WebKit Bugzilla
Attachment 369121 Details for
Bug 190799
: [ESNext][BigInt] Implement support for "**"
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-190799-20190506103407.patch (text/plain), 48.58 KB, created by
Caio Lima
on 2019-05-06 06:34:10 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2019-05-06 06:34:10 PDT
Size:
48.58 KB
patch
obsolete
>Subversion Revision: 244907 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index c05005e6603b8f6563045eda392a959d85d413b3..9bc3e9d092e968ef8d34a0ea807da8fc2d6fe838 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,73 @@ >+2019-05-06 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement support for "**" >+ https://bugs.webkit.org/show_bug.cgi?id=190799 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ We are introducing support for BigInt into "**" operator. This Patch >+ also includes changes into DFG, introducing a new node "ValuePow" that >+ is responsible to handle UntypedUse and BigIntUse. >+ >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ >+ ValuePow(Untyped, Untyped) still can propagate constant if AI proves >+ it. We are doing so if AI proves rhs and lhs as numbers. >+ >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ >+ When compiling op_pow, we first verify if rhs and lhs can be any Int >+ or number. If this happen, we emit ArithPow, otherwise we fallback to >+ ValuePow and rely on fixup to convert it to ArithPow if possible. >+ >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ >+ We only clobberize world if ValuePow is UntypedUse. Otherwise, we can >+ properly support CSE. >+ >+ * dfg/DFGDoesGC.cpp: >+ (JSC::DFG::doesGC): >+ >+ JSBigInt::exponentiate allocates JSBigInts to perform calculation and >+ it can trigger GC. ValuePow(UntypedUse) can trigger GC because it can >+ execute user code. >+ >+ * dfg/DFGFixupPhase.cpp: >+ (JSC::DFG::FixupPhase::fixupArithPow): >+ (JSC::DFG::FixupPhase::fixupNode): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileValuePow): >+ * dfg/DFGSpeculativeJIT.h: >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGValidate.cpp: >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compileNode): >+ (JSC::FTL::DFG::LowerDFGToB3::compileValuePow): >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::SLOW_PATH_DECL): >+ >+ We are adding proper support to BigInt on op_pow. The specification >+ defines that we can only apply pow when both operands have the same >+ type after calling ToNumeric(). >+ >+ * runtime/JSBigInt.cpp: >+ (JSC::JSBigInt::exponentiate): >+ * runtime/JSBigInt.h: >+ > 2019-05-03 Commit Queue <commit-queue@webkit.org> > > Unreviewed, rolling out r244881. >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index 74d82ea8c5f16b68328d45ff0414d0da356535d9..4a395531e67647a5654a785624639def7f15c47a 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -850,7 +850,26 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > } > break; > } >- >+ >+ case ValuePow: { >+ JSValue childX = forNode(node->child1()).value(); >+ JSValue childY = forNode(node->child2()).value(); >+ if (childX && childY && childX.isNumber() && childY.isNumber()) { >+ if (!node->isBinaryUseKind(BigIntUse)) >+ didFoldClobberWorld(); >+ setConstant(node, jsDoubleNumber(operationMathPow(childX.asNumber(), childY.asNumber()))); >+ break; >+ } >+ >+ if (node->binaryUseKind() == BigIntUse) >+ setTypeForNode(node, SpecBigInt); >+ else { >+ clobberWorld(); >+ setTypeForNode(node, SpecBytecodeNumber | SpecBigInt); >+ } >+ break; >+ } >+ > case ValueMul: { > if (node->binaryUseKind() == BigIntUse) > setTypeForNode(node, SpecBigInt); >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index 06fb181d3d71755422deb55d0e67384ec4307359..1c3c567ad5d3942f378a389c2d08abb4ffcb7987 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -5109,12 +5109,13 @@ void ByteCodeParser::parseBlock(unsigned limit) > } > > case op_pow: { >- // FIXME: ArithPow(Untyped, Untyped) should be supported as the same to ArithMul, ArithSub etc. >- // https://bugs.webkit.org/show_bug.cgi?id=160012 > auto bytecode = currentInstruction->as<OpPow>(); > Node* op1 = get(bytecode.m_lhs); > Node* op2 = get(bytecode.m_rhs); >- set(bytecode.m_dst, addToGraph(ArithPow, op1, op2)); >+ if (op1->hasNumberOrAnyIntResult() && op2->hasNumberOrAnyIntResult()) >+ set(bytecode.m_dst, addToGraph(ArithPow, op1, op2)); >+ else >+ set(bytecode.m_dst, addToGraph(ValuePow, op1, op2)); > NEXT_OPCODE(op_pow); > } > >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index b1598d48fe30e21a6b0310be1089eba8609227a0..b166aa0f71eb0be7d491be7b9cc1dc68e2c729c0 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -680,6 +680,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValuePow: > if (node->isBinaryUseKind(BigIntUse)) { > def(PureValue(node)); > return; >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index 10991a5576005976cc140ea65b9bd494134997e3..14b9a8003bc8547db617b3f0faaedb3ed3b20a36 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -379,6 +379,7 @@ bool doesGC(Graph& graph, Node* node) > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValuePow: > case ValueBitNot: > case ValueNegate: > #else >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index a0cd01aa34dd75b338adf7d1f48df6e73668be0d..5eab9d033ff13ca8d4211a2925969226ad9f0332 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -75,6 +75,18 @@ public: > } > > private: >+ void fixupArithPow(Node* node) >+ { >+ if (node->child2()->shouldSpeculateInt32OrBooleanForArithmetic()) { >+ fixDoubleOrBooleanEdge(node->child1()); >+ fixIntOrBooleanEdge(node->child2()); >+ return; >+ } >+ >+ fixDoubleOrBooleanEdge(node->child1()); >+ fixDoubleOrBooleanEdge(node->child2()); >+ } >+ > void fixupArithDiv(Node* node, Edge& leftChild, Edge& rightChild) > { > if (m_graph.binaryArithShouldSpeculateInt32(node, FixupPass)) { >@@ -574,15 +586,30 @@ private: > break; > } > >- case ArithPow: { >- if (node->child2()->shouldSpeculateInt32OrBooleanForArithmetic()) { >- fixDoubleOrBooleanEdge(node->child1()); >- fixIntOrBooleanEdge(node->child2()); >+ case ValuePow: { >+ if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) { >+ fixEdge<BigIntUse>(node->child1()); >+ fixEdge<BigIntUse>(node->child2()); >+ node->clearFlags(NodeMustGenerate); > break; > } > >- fixDoubleOrBooleanEdge(node->child1()); >- fixDoubleOrBooleanEdge(node->child2()); >+ if (Node::shouldSpeculateUntypedForArithmetic(node->child1().node(), node->child2().node())) { >+ fixEdge<UntypedUse>(node->child1()); >+ fixEdge<UntypedUse>(node->child2()); >+ break; >+ } >+ >+ node->setOp(ArithPow); >+ node->clearFlags(NodeMustGenerate); >+ node->setResult(NodeResultDouble); >+ >+ fixupArithPow(node); >+ break; >+ } >+ >+ case ArithPow: { >+ fixupArithPow(node); > break; > } > >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index 7f67872b7bd07ab77c44cc725b04b5ecbf4efb64..6cdc991480ad0cc8027d22e42f50587ad9785c65 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -179,6 +179,7 @@ namespace JSC { namespace DFG { > macro(ValueSub, NodeResultJS | NodeMustGenerate) \ > macro(ValueMul, NodeResultJS | NodeMustGenerate) \ > macro(ValueDiv, NodeResultJS | NodeMustGenerate) \ >+ macro(ValuePow, NodeResultJS | NodeMustGenerate) \ > \ > /* Add of values that always convers its inputs to strings. May have two or three kids. */\ > macro(StrCat, NodeResultJS | NodeMustGenerate) \ >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index fea350da028fe031092d780ee6989c81ebfa0312..2853103c372cbf704ba54aaa45a62415c95c6765 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -526,6 +526,34 @@ EncodedJSValue JIT_OPERATION operationValueDiv(ExecState* exec, EncodedJSValue e > return JSValue::encode(jsNumber(a / b)); > } > >+EncodedJSValue JIT_OPERATION operationValuePow(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) >+{ >+ VM* vm = &exec->vm(); >+ NativeCallFrameTracer tracer(vm, exec); >+ auto scope = DECLARE_THROW_SCOPE(*vm); >+ >+ JSValue op1 = JSValue::decode(encodedOp1); >+ JSValue op2 = JSValue::decode(encodedOp2); >+ >+ auto leftNumeric = op1.toNumeric(exec); >+ RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ auto rightNumeric = op2.toNumeric(exec); >+ RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) >+ RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::exponentiate(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)))); >+ >+ return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in exponentiation operation."); >+ } >+ >+ scope.release(); >+ >+ double a = WTF::get<double>(leftNumeric); >+ double b = WTF::get<double>(rightNumeric); >+ return JSValue::encode(jsNumber(operationMathPow(a, b))); >+} >+ > double JIT_OPERATION operationArithAbs(ExecState* exec, EncodedJSValue encodedOp1) > { > VM* vm = &exec->vm(); >@@ -1363,6 +1391,17 @@ JSCell* JIT_OPERATION operationDivBigInt(ExecState* exec, JSCell* op1, JSCell* o > return JSBigInt::divide(exec, leftOperand, rightOperand); > } > >+JSCell* JIT_OPERATION operationPowBigInt(ExecState* exec, JSCell* op1, JSCell* op2) >+{ >+ VM* vm = &exec->vm(); >+ NativeCallFrameTracer tracer(vm, exec); >+ >+ JSBigInt* leftOperand = jsCast<JSBigInt*>(op1); >+ JSBigInt* rightOperand = jsCast<JSBigInt*>(op2); >+ >+ return JSBigInt::exponentiate(exec, leftOperand, rightOperand); >+} >+ > JSCell* JIT_OPERATION operationBitAndBigInt(ExecState* exec, JSCell* op1, JSCell* op2) > { > VM* vm = &exec->vm(); >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h >index 949e39a9b8634cd71cadab20cbf90dcfa4d8a7c1..2d0b0cbba7d9965509395e01ed694996e953c343 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.h >+++ b/Source/JavaScriptCore/dfg/DFGOperations.h >@@ -59,6 +59,7 @@ EncodedJSValue JIT_OPERATION operationValueBitRShift(ExecState*, EncodedJSValue > EncodedJSValue JIT_OPERATION operationValueBitURShift(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; > EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; > EncodedJSValue JIT_OPERATION operationValueDiv(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; >+EncodedJSValue JIT_OPERATION operationValuePow(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL; > double JIT_OPERATION operationArithAbs(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL; > uint32_t JIT_OPERATION operationArithClz32(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL; > double JIT_OPERATION operationArithFRound(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL; >@@ -169,6 +170,7 @@ size_t JIT_OPERATION operationCompareStrictEqCell(ExecState*, JSCell* op1, JSCel > JSCell* JIT_OPERATION operationSubBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationMulBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationDivBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; >+JSCell* JIT_OPERATION operationPowBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationBitAndBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationBitNotBigInt(ExecState*, JSCell* op1) WTF_INTERNAL; > JSCell* JIT_OPERATION operationBitOrBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index 6e3fb25d81b8b8df5e01b9f8fd3ada9e9059519f..7efc0fa0b158ee4e2825792bff30c66cbf711a2e 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -277,6 +277,22 @@ private: > break; > } > >+ case ValuePow: { >+ SpeculatedType left = node->child1()->prediction(); >+ SpeculatedType right = node->child2()->prediction(); >+ >+ if (left && right) { >+ if (node->child1()->shouldSpeculateBigInt() && node->child2()->shouldSpeculateBigInt()) >+ changed |= mergePrediction(SpecBigInt); >+ else if (isFullNumberOrBooleanSpeculationExpectingDefined(left) >+ && isFullNumberOrBooleanSpeculationExpectingDefined(right)) >+ setPrediction(SpecBytecodeDouble); >+ else >+ setPrediction(SpecBytecodeDouble | SpecBigInt); >+ } >+ break; >+ } >+ > case ValueNegate: > case ArithNegate: { > SpeculatedType prediction = node->child1()->prediction(); >@@ -1117,6 +1133,7 @@ private: > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValuePow: > case ArithAdd: > case ArithSub: > case ArithNegate: >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index 992bcf8a9b27bf10a6ec68c4cc6016fd7bfc0d5a..41a02d3d2b82145bd65622918887851d27f67359 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -238,6 +238,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValuePow: > case TryGetById: > case DeleteById: > case DeleteByVal: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index 3c0390725e83572eba1b6297603f0c30f583d917..7b47f0c3da18c1a967e9cf6fac3c2d6366566db3 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -5749,6 +5749,47 @@ static MacroAssembler::Jump compileArithPowIntegerFastPath(JITCompiler& assemble > return skipSlowPath; > } > >+void SpeculativeJIT::compileValuePow(Node* node) >+{ >+ Edge& leftChild = node->child1(); >+ Edge& rightChild = node->child2(); >+ >+ if (node->binaryUseKind() == BigIntUse) { >+ SpeculateCellOperand left(this, leftChild); >+ SpeculateCellOperand right(this, rightChild); >+ GPRReg leftGPR = left.gpr(); >+ GPRReg rightGPR = right.gpr(); >+ >+ speculateBigInt(leftChild, leftGPR); >+ speculateBigInt(rightChild, rightGPR); >+ >+ flushRegisters(); >+ GPRFlushedCallResult result(this); >+ GPRReg resultGPR = result.gpr(); >+ >+ callOperation(operationPowBigInt, resultGPR, leftGPR, rightGPR); >+ >+ m_jit.exceptionCheck(); >+ cellResult(resultGPR, node); >+ return; >+ } >+ >+ DFG_ASSERT(m_jit.graph(), node, node->binaryUseKind() == UntypedUse, node->binaryUseKind()); >+ >+ JSValueOperand left(this, leftChild); >+ JSValueOperand right(this, rightChild); >+ JSValueRegs leftRegs = left.jsValueRegs(); >+ JSValueRegs rightRegs = right.jsValueRegs(); >+ >+ flushRegisters(); >+ JSValueRegsFlushedCallResult result(this); >+ JSValueRegs resultRegs = result.regs(); >+ callOperation(operationValuePow, resultRegs, leftRegs, rightRegs); >+ m_jit.exceptionCheck(); >+ >+ jsValueResult(resultRegs, node); >+} >+ > void SpeculativeJIT::compileArithPow(Node* node) > { > if (node->child2().useKind() == Int32Use) { >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >index e65de38b0bb1becead325f552f4685c7ffa0f314..d84c07282ae5f5c4638996758bc773773f25bedd 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -1358,6 +1358,7 @@ public: > void compileArithFRound(Node*); > void compileArithMod(Node*); > void compileArithPow(Node*); >+ void compileValuePow(Node*); > void compileArithRounding(Node*); > void compileArithRandom(Node*); > void compileArithUnary(Node*); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index 1e3374553a8c7bfa02e782aa1b72da7b151dddfa..cfc029186a4634ef9dc1dbc5b8a7b16971bfd59b 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -2092,6 +2092,11 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case ValuePow: { >+ compileValuePow(node); >+ break; >+ } >+ > case ArithPow: { > compileArithPow(node); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index f009e6b08b3f0c97ad91f8c303a6e2a0172ecca5..d399f1abfa7cd2fca6e62c5c2c9a97b3e4ed5b1d 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2248,6 +2248,10 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case ValuePow: >+ compileValuePow(node); >+ break; >+ > case ArithPow: > compileArithPow(node); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGValidate.cpp b/Source/JavaScriptCore/dfg/DFGValidate.cpp >index 04dfdcb7d683cb243d72e84d65d178b432cababd..5f28cb607f32bb47b6aff372c06499b5699bbc56 100644 >--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp >+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp >@@ -257,6 +257,7 @@ public: > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValuePow: > case ArithAdd: > case ArithSub: > case ArithMul: >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index 316ab8deeee7477aed83ff75e207023dd491bea4..4d48c7e044a00f443d5b807500a764aed07cc3f1 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -98,6 +98,7 @@ inline CapabilityLevel canCompile(Node* node) > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValuePow: > case StrCat: > case ArithAdd: > case ArithClz32: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index c2564d317b11c99e67bf3743431a18973727da6c..298d1ba45daafc4078b55f9df6af42eeb75dbfd7 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -790,6 +790,9 @@ private: > case ArithAbs: > compileArithAbs(); > break; >+ case ValuePow: >+ compileValuePow(); >+ break; > case ArithPow: > compileArithPow(); > break; >@@ -2693,6 +2696,23 @@ private: > setDouble(result); > } > >+ void compileValuePow() >+ { >+ if (m_node->isBinaryUseKind(BigIntUse)) { >+ LValue base = lowBigInt(m_node->child1()); >+ LValue exponent = lowBigInt(m_node->child2()); >+ >+ LValue result = vmCall(pointerType(), m_out.operation(operationPowBigInt), m_callFrame, base, exponent); >+ setJSValue(result); >+ return; >+ } >+ >+ LValue base = lowJSValue(m_node->child1()); >+ LValue exponent = lowJSValue(m_node->child2()); >+ LValue result = vmCall(Int64, m_out.operation(operationValuePow), m_callFrame, base, exponent); >+ setJSValue(result); >+ } >+ > void compileArithPow() > { > if (m_node->child2().useKind() == Int32Use) >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >index 8544188836fe689cd8a67d2bff437252173cf5be..5dabfd80824a0c5d053bdb10964004b7a59c7a75 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -635,12 +635,26 @@ SLOW_PATH_DECL(slow_path_pow) > { > BEGIN(); > auto bytecode = pc->as<OpPow>(); >- double a = GET_C(bytecode.m_lhs).jsValue().toNumber(exec); >- if (UNLIKELY(throwScope.exception())) >- RETURN(JSValue()); >- double b = GET_C(bytecode.m_rhs).jsValue().toNumber(exec); >- if (UNLIKELY(throwScope.exception())) >- RETURN(JSValue()); >+ JSValue left = GET_C(bytecode.m_lhs).jsValue(); >+ JSValue right = GET_C(bytecode.m_rhs).jsValue(); >+ auto leftNumeric = left.toNumeric(exec); >+ CHECK_EXCEPTION(); >+ auto rightNumeric = right.toNumeric(exec); >+ CHECK_EXCEPTION(); >+ >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >+ JSBigInt* result = JSBigInt::exponentiate(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); >+ CHECK_EXCEPTION(); >+ RETURN(result); >+ } >+ >+ THROW(createTypeError(exec, "Invalid mix of BigInt and other type in exponentiation operation.")); >+ } >+ >+ double a = WTF::get<double>(leftNumeric); >+ double b = WTF::get<double>(rightNumeric); >+ > RETURN(jsNumber(operationMathPow(a, b))); > } > >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp >index 7e3ccb48bb22e60769fa5515fc215b94ab757a9d..c498438fbf8fa7fee3ea09bd3425f6c267806536 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -237,6 +237,99 @@ void JSBigInt::inplaceMultiplyAdd(Digit factor, Digit summand) > internalMultiplyAdd(this, factor, summand, length(), this); > } > >+JSBigInt* JSBigInt::exponentiate(ExecState* exec, JSBigInt* base, JSBigInt* exponent) >+{ >+ VM& vm = exec->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ if (exponent->sign()) { >+ throwRangeError(exec, scope, "Negative exponent is not allowed"_s); >+ return nullptr; >+ } >+ >+ // 2. If base is 0n and exponent is 0n, return 1n. >+ if (exponent->isZero()) >+ return JSBigInt::createFrom(vm, 1); >+ >+ // 3. Return a BigInt representing the mathematical value of base raised >+ // to the power exponent. >+ if (base->isZero()) >+ return base; >+ >+ if (base->length() == 1 && base->digit(0) == 1) { >+ // (-1) ** even_number == 1. >+ if (base->sign() && !(exponent->digit(0) & 1)) >+ return JSBigInt::unaryMinus(vm, base); >+ >+ // (-1) ** odd_number == -1; 1 ** anything == 1. >+ return base; >+ } >+ >+ // For all bases >= 2, very large exponents would lead to unrepresentable >+ // results. >+ static_assert(maxLengthBits < std::numeric_limits<Digit>::max(), "maxLengthBits needs to be less than digit::max()"); >+ if (exponent->length() > 1) { >+ throwRangeError(exec, scope, "BigInt generated from this operation is too big"_s); >+ return nullptr; >+ } >+ >+ Digit expValue = exponent->digit(0); >+ if (expValue == 1) >+ return base; >+ if (expValue >= maxLengthBits) { >+ throwRangeError(exec, scope, "BigInt generated from this operation is too big"_s); >+ return nullptr; >+ } >+ >+ static_assert(maxLengthBits <= maxInt, "maxLengthBits needs to be <= maxInt"); >+ int n = static_cast<int>(expValue); >+ if (base->length() == 1 && base->digit(0) == 2) { >+ // Fast path for 2^n. >+ int neededDigits = 1 + (n / digitBits); >+ JSBigInt* result = JSBigInt::tryCreateWithLength(exec, neededDigits); >+ if (!result) >+ return nullptr; >+ >+ result->initialize(InitializationType::WithZero); >+ // All bits are zero. Now set the n-th bit. >+ Digit msd = static_cast<Digit>(1) << (n % digitBits); >+ result->setDigit(neededDigits - 1, msd); >+ // Result is negative for odd powers of -2n. >+ if (base->sign()) >+ result->setSign(static_cast<bool>(n & 1)); >+ >+ return result; >+ } >+ >+ JSBigInt* result = nullptr; >+ JSBigInt* runningSquare = base; >+ >+ // This implicitly sets the result's sign correctly. >+ if (n & 1) >+ result = base; >+ >+ n >>= 1; >+ for (; n; n >>= 1) { >+ JSBigInt* maybeResult = JSBigInt::multiply(exec, runningSquare, runningSquare); >+ if (!maybeResult) >+ return nullptr; >+ >+ runningSquare = maybeResult; >+ if (n & 1) { >+ if (!result) >+ result = runningSquare; >+ else { >+ maybeResult = JSBigInt::multiply(exec, result, runningSquare); >+ if (!maybeResult) >+ return nullptr; >+ result = maybeResult; >+ } >+ } >+ } >+ >+ return result; >+} >+ > JSBigInt* JSBigInt::multiply(ExecState* exec, JSBigInt* x, JSBigInt* y) > { > VM& vm = exec->vm(); >@@ -1055,7 +1148,7 @@ void JSBigInt::absoluteDivWithBigIntDivisor(ExecState* exec, JSBigInt* dividend, > } > } > >-// Returns whether (factor1 * factor2) > (high << kDigitBits) + low. >+// Returns whether (factor1 * factor2) > (high << digitBits) + low. > inline bool JSBigInt::productGreaterThan(Digit factor1, Digit factor2, Digit high, Digit low) > { > Digit resultHigh; >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.h b/Source/JavaScriptCore/runtime/JSBigInt.h >index 5cc9e09d4cbe22a9ef2a6190287330220376def1..414ed3ca0bb100cd5344f32fc8fb38650eca5999 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -111,6 +111,8 @@ public: > JSObject* toObject(ExecState*, JSGlobalObject*) const; > inline bool toBoolean() const { return !isZero(); } > >+ static JSBigInt* exponentiate(ExecState*, JSBigInt* base, JSBigInt* exponent); >+ > static JSBigInt* multiply(ExecState*, JSBigInt* x, JSBigInt* y); > > ComparisonResult static compareToDouble(JSBigInt* x, double y); >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 37b413a12d5abd87da0cccc770619be5ccd2f496..1b911d516fed5b20e680dacc20b1f818f3ea59bb 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,20 @@ >+2019-05-06 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement support for "**" >+ https://bugs.webkit.org/show_bug.cgi?id=190799 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * stress/big-int-exp-basic.js: Added. >+ * stress/big-int-exp-jit-osr.js: Added. >+ * stress/big-int-exp-jit-untyped.js: Added. >+ * stress/big-int-exp-jit.js: Added. >+ * stress/big-int-exp-negative-exponent.js: Added. >+ * stress/big-int-exp-to-primitive.js: Added. >+ * stress/big-int-exp-type-error.js: Added. >+ * stress/big-int-exp-wrapped-value.js: Added. >+ * stress/value-pow-ai-rule.js: Added. >+ > 2019-05-02 Michael Saboff <msaboff@apple.com> > > Unreviewed rollout of r244862. >diff --git a/JSTests/stress/big-int-exp-basic.js b/JSTests/stress/big-int-exp-basic.js >new file mode 100644 >index 0000000000000000000000000000000000000000..c815964a183cb4470fb8ed298ce9d6f0b7ce0e65 >--- /dev/null >+++ b/JSTests/stress/big-int-exp-basic.js >@@ -0,0 +1,111 @@ >+//@ runBigIntEnabled >+ >+// Copyright (C) 2017 Josh Wolfe. All rights reserved. >+// This code is governed by the BSD license below. >+// >+// The << Software identified by reference to the Ecma Standard* ("Software)">> is protected by copyright and is being >+// made available under the "BSD License", included below. This Software may be subject to third party rights (rights >+// from parties other than Ecma International), including patent rights, and no licenses under such third party rights >+// are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA >+// CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR >+// INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS*. >+// >+// Copyright (C) 2012-2013 Ecma International >+// All rights reserved. >+// >+// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the >+// following conditions are met: >+// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following >+// disclaimer. >+// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the >+// following disclaimer in the documentation and/or other materials provided with the distribution. >+// 3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from >+// this software without specific prior written permission. >+// >+// THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT >+// SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING >+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH >+// DAMAGE. >+// >+// * Ecma International Standards hereafter means Ecma International Standards as well as Ecma Technical Reports >+ >+var assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+assert.sameValue( >+ 0x123n ** 0x123n, >+ 0x37AA7FAA38F2F6026AABEFE979EA730BA9EA4CB99E2E3F645D515D3BBE2D84BCD89F8A034BADF3E3DC0CF417258371B31F4555DC0883DA96760AB157DB7DFFF5E3E97A3EAAB8328B2B178060B5A5E4C4DD8BC8D66B7F4D9F0E0B1AC3A566FDE0A15EBF8DBDBD0565C5FBDB7C123CF250E271DF5C38BC6746A1327F09C7FB4B96E0EDA45C429799CA80B1DB039692C70DFFE4E66F1D9CAB4270863B09A7918F774D686F685F560FEDC6B7B85CB45DE5EEEF6A5FE2FC8B5037FB421204641909347C91F2DC252F49B8F310E867E56D1CA2E81EE9A3AA568682C7B8B41D709A2E7F8D9A8D8C56D6BE78B6CA8365E362B81A64974C315FB8FA50CED4F7944F28FA3ECA77B8BCB56DC69814328F891E6065D108EEE7B8E695038090CCA10C0E68DD7A36CFAA1C26CDFEC369FBn, >+ 'The result of (0x123n ** 0x123n) is 0x37AA7FAA38F2F6026AABEFE979EA730BA9EA4CB99E2E3F645D515D3BBE2D84BCD89F8A034BADF3E3DC0CF417258371B31F4555DC0883DA96760AB157DB7DFFF5E3E97A3EAAB8328B2B178060B5A5E4C4DD8BC8D66B7F4D9F0E0B1AC3A566FDE0A15EBF8DBDBD0565C5FBDB7C123CF250E271DF5C38BC6746A1327F09C7FB4B96E0EDA45C429799CA80B1DB039692C70DFFE4E66F1D9CAB4270863B09A7918F774D686F685F560FEDC6B7B85CB45DE5EEEF6A5FE2FC8B5037FB421204641909347C91F2DC252F49B8F310E867E56D1CA2E81EE9A3AA568682C7B8B41D709A2E7F8D9A8D8C56D6BE78B6CA8365E362B81A64974C315FB8FA50CED4F7944F28FA3ECA77B8BCB56DC69814328F891E6065D108EEE7B8E695038090CCA10C0E68DD7A36CFAA1C26CDFEC369FBn' >+); >+ >+assert.sameValue( >+ 0x123n ** 0xFFn, >+ 0x8D5BB75861377EC967BF78FDF39CE51696FBD34722999943F8865938772B517167CD5ED775A78987F5106831F4978E0709032B26ED8F13F814699DB8AB3ACD5CF631F2D8B8B706FCF5EF441AAEE745A795EC5CB86A5E8D87D09F648EFC557B98F73E750FEC9AED061D47806F269CCCDFB6D513912A82AE79B171D76AF6D926BC4F4C4DA43A6EFB4D9D1672E356CC1F74A29AF80D53A8F27592F6191AB9B3D57FA2C435CB2CE8F18A3B3448F88F4BAD3606A9878DA9528B569BADAC0C1EC0B1A2B06CD4C64DEEC940807DFD05C56E3E17ADB1A88EDAF0D67C87C1F871BFB5C47CAE8365FE33538317EE2DF4EE52636CE1BDA9E41C7DA72826E4C097A53BD73D8D697E10D28Bn, >+ 'The result of (0x123n ** 0xFFn) is 0x8D5BB75861377EC967BF78FDF39CE51696FBD34722999943F8865938772B517167CD5ED775A78987F5106831F4978E0709032B26ED8F13F814699DB8AB3ACD5CF631F2D8B8B706FCF5EF441AAEE745A795EC5CB86A5E8D87D09F648EFC557B98F73E750FEC9AED061D47806F269CCCDFB6D513912A82AE79B171D76AF6D926BC4F4C4DA43A6EFB4D9D1672E356CC1F74A29AF80D53A8F27592F6191AB9B3D57FA2C435CB2CE8F18A3B3448F88F4BAD3606A9878DA9528B569BADAC0C1EC0B1A2B06CD4C64DEEC940807DFD05C56E3E17ADB1A88EDAF0D67C87C1F871BFB5C47CAE8365FE33538317EE2DF4EE52636CE1BDA9E41C7DA72826E4C097A53BD73D8D697E10D28Bn' >+); >+ >+assert.sameValue(0x123n ** 0x3n, 0x178027Bn, 'The result of (0x123n ** 0x3n) is 0x178027Bn'); >+assert.sameValue(0x123n ** 0x2n, 0x14AC9n, 'The result of (0x123n ** 0x2n) is 0x14AC9n'); >+assert.sameValue(0x123n ** 0x1n, 0x123n, 'The result of (0x123n ** 0x1n) is 0x123n'); >+ >+assert.sameValue( >+ 0xFFn ** 0x123n, >+ 0x51F5CA2E1A36F5FF1ED3D393D76FBC3612B38EB64E00EDAC5E95ADE0D16D0B044C8E9F2B77B3F31AF9159F482205541E9D3BE9D248FF39CE6524874EBCA60E06302E8B505D11EEEEE869C7F801A82B9739C197E6D63A1EB2D29B5AD5EED4773C762106E9F66BFCB6C11450218973C69DED3FE51FF881AD0430675BF54320513EA766117C50C554E86E22A5ACFD8047D5470B4FCBCB9EFC86196CA77C58F1BEB09F76160D641B82E2481BEDAE089207D49FE0FB7DE14B6C4BC82E9C58140746AC8E74C3353AAF5F9CF47ED1F87C52F463C053DB63CD08CC9866EBA274D39B6B357ADADAD4D210167EF7363453D42BC225D90070336861F2D259489D78B7F04B05FE65E29151ADD2B8F4D318011988550CE590DBA4C868AC65AA325051DF613D6C2E22FFn, >+ 'The result of (0xFFn ** 0x123n) is 0x51F5CA2E1A36F5FF1ED3D393D76FBC3612B38EB64E00EDAC5E95ADE0D16D0B044C8E9F2B77B3F31AF9159F482205541E9D3BE9D248FF39CE6524874EBCA60E06302E8B505D11EEEEE869C7F801A82B9739C197E6D63A1EB2D29B5AD5EED4773C762106E9F66BFCB6C11450218973C69DED3FE51FF881AD0430675BF54320513EA766117C50C554E86E22A5ACFD8047D5470B4FCBCB9EFC86196CA77C58F1BEB09F76160D641B82E2481BEDAE089207D49FE0FB7DE14B6C4BC82E9C58140746AC8E74C3353AAF5F9CF47ED1F87C52F463C053DB63CD08CC9866EBA274D39B6B357ADADAD4D210167EF7363453D42BC225D90070336861F2D259489D78B7F04B05FE65E29151ADD2B8F4D318011988550CE590DBA4C868AC65AA325051DF613D6C2E22FFn' >+); >+ >+assert.sameValue( >+ 0xFFn ** 0xFFn, >+ 0x5E5C8B0EB95AB08F9D37EF127FC01BD0E33DE52647528396D78D5F8DA31989E67814F6BBA1FB0F0207010FF5F2347B19D5F6598FC91BF5A88F77DAA3D7B382FEC484F3D205C06A34445384C0E7AB0D883788C68C012CB433055EDDA746A48409444EA91147273B79FC3EABB70ECA552AF650C234BB01ED404427F17CDDDD71D08E39EF9C3982E3CE44E670456AA8154C1FDBD9C35947F494636A425C69BF89E9C75AD3B7A0A559AF0F5DA9947C8DEBA64417310713B23E7EF4DE50BB2A3E90BC2AC3DA5201CCA8D6E5DFEA887C4F7A4E92175D9F88BD2779B57F9EB35BE7528F965A06DA0AC41DCB3A34F1D8AB7D8FEE620A94FAA42C395997756B007FFEFFn, >+ 'The result of (0xFFn ** 0xFFn) is 0x5E5C8B0EB95AB08F9D37EF127FC01BD0E33DE52647528396D78D5F8DA31989E67814F6BBA1FB0F0207010FF5F2347B19D5F6598FC91BF5A88F77DAA3D7B382FEC484F3D205C06A34445384C0E7AB0D883788C68C012CB433055EDDA746A48409444EA91147273B79FC3EABB70ECA552AF650C234BB01ED404427F17CDDDD71D08E39EF9C3982E3CE44E670456AA8154C1FDBD9C35947F494636A425C69BF89E9C75AD3B7A0A559AF0F5DA9947C8DEBA64417310713B23E7EF4DE50BB2A3E90BC2AC3DA5201CCA8D6E5DFEA887C4F7A4E92175D9F88BD2779B57F9EB35BE7528F965A06DA0AC41DCB3A34F1D8AB7D8FEE620A94FAA42C395997756B007FFEFFn' >+); >+ >+assert.sameValue(0xFFn ** 0x3n, 0xFD02FFn, 'The result of (0xFFn ** 0x3n) is 0xFD02FFn'); >+assert.sameValue(0xFFn ** 0x2n, 0xFE01n, 'The result of (0xFFn ** 0x2n) is 0xFE01n'); >+assert.sameValue(0xFFn ** 0x1n, 0xFFn, 'The result of (0xFFn ** 0x1n) is 0xFFn'); >+ >+assert.sameValue( >+ 0x3n ** 0x123n, >+ 0x25609213623D7D6219085CF49D306450BF6519835586C19D3A4F3A2C5F35B44A300C8A76E11708B5495B9C3EE756BBF19E3FD15CE625D3C0539Bn, >+ 'The result of (0x3n ** 0x123n) is 0x25609213623D7D6219085CF49D306450BF6519835586C19D3A4F3A2C5F35B44A300C8A76E11708B5495B9C3EE756BBF19E3FD15CE625D3C0539Bn' >+); >+ >+assert.sameValue( >+ 0x3n ** 0xFFn, >+ 0x11F1B08E87EC42C5D83C3218FC83C41DCFD9F4428F4F92AF1AAA80AA46162B1F71E981273601F4AD1DD4709B5ACA650265A6ABn, >+ 'The result of (0x3n ** 0xFFn) is 0x11F1B08E87EC42C5D83C3218FC83C41DCFD9F4428F4F92AF1AAA80AA46162B1F71E981273601F4AD1DD4709B5ACA650265A6ABn' >+); >+ >+assert.sameValue(0x3n ** 0x3n, 0x1Bn, 'The result of (0x3n ** 0x3n) is 0x1Bn'); >+assert.sameValue(0x3n ** 0x2n, 0x9n, 'The result of (0x3n ** 0x2n) is 0x9n'); >+assert.sameValue(0x3n ** 0x1n, 0x3n, 'The result of (0x3n ** 0x1n) is 0x3n'); >+ >+assert.sameValue( >+ 0x2n ** 0x123n, >+ 0x8000000000000000000000000000000000000000000000000000000000000000000000000n, >+ 'The result of (0x2n ** 0x123n) is 0x8000000000000000000000000000000000000000000000000000000000000000000000000n' >+); >+ >+assert.sameValue( >+ 0x2n ** 0xFFn, >+ 0x8000000000000000000000000000000000000000000000000000000000000000n, >+ 'The result of (0x2n ** 0xFFn) is 0x8000000000000000000000000000000000000000000000000000000000000000n' >+); >+ >+assert.sameValue(0x2n ** 0x3n, 0x8n, 'The result of (0x2n ** 0x3n) is 0x8n'); >+assert.sameValue(0x2n ** 0x2n, 0x4n, 'The result of (0x2n ** 0x2n) is 0x4n'); >+assert.sameValue(0x2n ** 0x1n, 0x2n, 'The result of (0x2n ** 0x1n) is 0x2n'); >+assert.sameValue(0x1n ** 0x123n, 0x1n, 'The result of (0x1n ** 0x123n) is 0x1n'); >+assert.sameValue(0x1n ** 0xFFn, 0x1n, 'The result of (0x1n ** 0xFFn) is 0x1n'); >+assert.sameValue(0x1n ** 0x3n, 0x1n, 'The result of (0x1n ** 0x3n) is 0x1n'); >+assert.sameValue(0x1n ** 0x2n, 0x1n, 'The result of (0x1n ** 0x2n) is 0x1n'); >+assert.sameValue(0x1n ** 0x1n, 0x1n, 'The result of (0x1n ** 0x1n) is 0x1n'); >+assert.sameValue(0n ** 0n, 1n, 'The result of (0n ** 0n) is 1n'); >+ >diff --git a/JSTests/stress/big-int-exp-jit-osr.js b/JSTests/stress/big-int-exp-jit-osr.js >new file mode 100644 >index 0000000000000000000000000000000000000000..ea8efbb70d0b658db07ac1b3f33e696936e067a7 >--- /dev/null >+++ b/JSTests/stress/big-int-exp-jit-osr.js >@@ -0,0 +1,25 @@ >+//@ runBigIntEnabled >+ >+let assert = { >+ sameValue: function(i, e, m) { >+ if (i !== e) >+ throw new Error(m); >+ } >+} >+ >+function bigIntExp(x, y) { >+ return x ** y; >+} >+noInline(bigIntExp); >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntExp(3n, 10n); >+ assert.sameValue(r, 59049n, 3n + " ** " + 10n + " = " + r); >+} >+ >+let r = bigIntExp(3, 10); >+assert.sameValue(r, 59049, 3 + " ** " + 10 + " = " + r); >+ >+r = bigIntExp("3", "10"); >+assert.sameValue(r, 59049, "'" + 3 + "' ** '" + 10 + "' = " + r); >+ >diff --git a/JSTests/stress/big-int-exp-jit-untyped.js b/JSTests/stress/big-int-exp-jit-untyped.js >new file mode 100644 >index 0000000000000000000000000000000000000000..c94483e411de4d83d6c7c664ce4882da2ea2cd1f >--- /dev/null >+++ b/JSTests/stress/big-int-exp-jit-untyped.js >@@ -0,0 +1,39 @@ >+//@ runBigIntEnabled >+ >+let assert = { >+ sameValue: function(i, e, m) { >+ if (i !== e) >+ throw new Error(m); >+ } >+} >+ >+function bigIntExp(x, y) { >+ return x ** y; >+} >+noInline(bigIntExp); >+ >+let o = {valueOf: () => 10n}; >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntExp(3n, o); >+ assert.sameValue(r, 59049n, 3n + " ** {valueOf: () => 10n} = " + r); >+} >+ >+o2 = {valueOf: () => 3n}; >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntExp(o2, o); >+ assert.sameValue(r, 59049n, "{valueOf: () => 3n} ** {valueOf: () => 10n} = " + r); >+} >+ >+o = Object(10n); >+let r = bigIntExp(3n, o); >+assert.sameValue(r, 59049n, 3n + " ** Object(10n) = " + r); >+ >+o2 = Object(3n); >+r = bigIntExp(o2, o); >+assert.sameValue(r, 59049n, "Object(3n) ** Object(10n) = " + r); >+ >+r = bigIntExp(3, 3); >+assert.sameValue(r, 27, "3 ** 3 = " + r); >+ >diff --git a/JSTests/stress/big-int-exp-jit.js b/JSTests/stress/big-int-exp-jit.js >new file mode 100644 >index 0000000000000000000000000000000000000000..dc9d31d57f7dedb2c618bcdd2c1dad6217005500 >--- /dev/null >+++ b/JSTests/stress/big-int-exp-jit.js >@@ -0,0 +1,19 @@ >+//@ runBigIntEnabled >+ >+let assert = { >+ sameValue: function(i, e, m) { >+ if (i !== e) >+ throw new Error(m); >+ } >+} >+ >+function bigIntExp(x, y) { >+ return x ** y; >+} >+noInline(bigIntExp); >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntExp(3n, 10n); >+ assert.sameValue(r, 59049n, 3n + " ** " + 10n + " = " + r); >+} >+ >diff --git a/JSTests/stress/big-int-exp-negative-exponent.js b/JSTests/stress/big-int-exp-negative-exponent.js >new file mode 100644 >index 0000000000000000000000000000000000000000..c6779f33fae47d7cb5f1e9c7f8a0bf7026bc7fff >--- /dev/null >+++ b/JSTests/stress/big-int-exp-negative-exponent.js >@@ -0,0 +1,21 @@ >+//@ runBigIntEnabled >+ >+function assert(a, message) { >+ if (!a) >+ throw new Error(message); >+} >+ >+function assertThrowRangeError(a, b) { >+ try { >+ let n = a ** b; >+ assert(false, "Should throw RangeError, but executed without exception"); >+ } catch (e) { >+ assert(e instanceof RangeError, "Expected RangeError, got: " + e); >+ } >+} >+ >+assertThrowRangeError(1n, -1n); >+assertThrowRangeError(0n, -1n); >+assertThrowRangeError(-1n, -1n); >+assertThrowRangeError(1n, -100000000000000000n); >+ >diff --git a/JSTests/stress/big-int-exp-to-primitive.js b/JSTests/stress/big-int-exp-to-primitive.js >new file mode 100644 >index 0000000000000000000000000000000000000000..e0b83f349b909ffca9e7751115d7f563da2c721e >--- /dev/null >+++ b/JSTests/stress/big-int-exp-to-primitive.js >@@ -0,0 +1,34 @@ >+//@ runBigIntEnabled >+ >+function assert(a) { >+ if (!a) >+ throw new Error("Bad assertion"); >+} >+ >+assert.sameValue = function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+} >+ >+function testExp(x, y, z) { >+ assert.sameValue(x ** y, z, x + " * " + y + " = " + z); >+} >+ >+let o = { >+ [Symbol.toPrimitive]: function () { return 15n; } >+} >+ >+testExp(15n, o, 437893890380859375n); >+ >+o.valueOf = function () { >+ throw new Error("Should never execute it"); >+}; >+ >+testExp(22n, o, 136880068015412051968n); >+ >+o.toString = function () { >+ throw new Error("Should never execute it"); >+}; >+ >+testExp(103n, o, 1557967416600764580522382952407n); >+ >diff --git a/JSTests/stress/big-int-exp-type-error.js b/JSTests/stress/big-int-exp-type-error.js >new file mode 100644 >index 0000000000000000000000000000000000000000..8c2b94b2ab137bc2b4d70976c430dee92ea0234b >--- /dev/null >+++ b/JSTests/stress/big-int-exp-type-error.js >@@ -0,0 +1,106 @@ >+//@ runBigIntEnabled >+ >+function assert(a, message) { >+ if (!a) >+ throw new Error(message); >+} >+ >+function assertThrowTypeError(a, b, message) { >+ try { >+ let n = a ** b; >+ assert(false, message + ": Should throw TypeError, but executed without exception"); >+ } catch (e) { >+ assert(e instanceof TypeError, message + ": expected TypeError, got: " + e); >+ } >+} >+ >+assertThrowTypeError(30n, "foo", "BigInt ** String"); >+assertThrowTypeError("bar", 18757382984821n, "String ** BigInt"); >+assertThrowTypeError(30n, Symbol("foo"), "BigInt ** Symbol"); >+assertThrowTypeError(Symbol("bar"), 18757382984821n, "Symbol ** BigInt"); >+assertThrowTypeError(30n, 3320, "BigInt ** Int32"); >+assertThrowTypeError(33256, 18757382984821n, "Int32 ** BigInt"); >+assertThrowTypeError(30n, 0.543, "BigInt ** Double"); >+assertThrowTypeError(230.19293, 18757382984821n, "Double ** BigInt"); >+assertThrowTypeError(30n, NaN, "BigInt ** NaN"); >+assertThrowTypeError(NaN, 18757382984821n, "NaN ** BigInt"); >+assertThrowTypeError(30n, NaN, "BigInt ** NaN"); >+assertThrowTypeError(NaN, 18757382984821n, "NaN ** BigInt"); >+assertThrowTypeError(30n, +Infinity, "BigInt ** NaN"); >+assertThrowTypeError(+Infinity, 18757382984821n, "NaN ** BigInt"); >+assertThrowTypeError(30n, -Infinity, "BigInt ** -Infinity"); >+assertThrowTypeError(-Infinity, 18757382984821n, "-Infinity ** BigInt"); >+assertThrowTypeError(30n, null, "BigInt ** null"); >+assertThrowTypeError(null, 18757382984821n, "null ** BigInt"); >+assertThrowTypeError(30n, undefined, "BigInt ** undefined"); >+assertThrowTypeError(undefined, 18757382984821n, "undefined ** BigInt"); >+assertThrowTypeError(30n, true, "BigInt ** true"); >+assertThrowTypeError(true, 18757382984821n, "true ** BigInt"); >+assertThrowTypeError(30n, false, "BigInt ** false"); >+assertThrowTypeError(false, 18757382984821n, "false ** BigInt"); >+ >+// Error when returning from object >+ >+let o = { >+ valueOf: function () { return Symbol("Foo"); } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt ** Object.valueOf returning Symbol"); >+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Symbol ** BigInt"); >+ >+o = { >+ valueOf: function () { return 33256; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt ** Object.valueOf returning Int32"); >+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Int32 ** BigInt"); >+ >+o = { >+ valueOf: function () { return 0.453; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt ** Object.valueOf returning Double"); >+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Double ** BigInt"); >+ >+o = { >+ toString: function () { return Symbol("Foo"); } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt ** Object.toString returning Symbol"); >+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Symbol ** BigInt"); >+ >+o = { >+ toString: function () { return 33256; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt ** Object.toString returning Int32"); >+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Int32 ** BigInt"); >+ >+o = { >+ toString: function () { return 0.453; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt ** Object.toString returning Double"); >+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Double ** BigInt"); >+ >+o = { >+ [Symbol.toPrimitive]: function () { return Symbol("Foo"); } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt ** Object.@@toPrimitive returning Symbol"); >+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Symbol ** BigInt"); >+ >+o = { >+ [Symbol.toPrimitive]: function () { return 33256; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt ** Object.@@toPrimitive returning Int32"); >+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Int32 ** BigInt"); >+ >+o = { >+ [Symbol.toPrimitive]: function () { return 0.453; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt ** Object.@@toPrimitive returning Double"); >+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Double ** BigInt"); >+ >diff --git a/JSTests/stress/big-int-exp-wrapped-value.js b/JSTests/stress/big-int-exp-wrapped-value.js >new file mode 100644 >index 0000000000000000000000000000000000000000..5a9a1810a629dfd46d70d70f4401937cab5e72b0 >--- /dev/null >+++ b/JSTests/stress/big-int-exp-wrapped-value.js >@@ -0,0 +1,36 @@ >+//@ runBigIntEnabled >+ >+assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+function testExp(x, y, z, message) { >+ assert.sameValue(x ** y, z, message); >+} >+ >+testExp(Object(2n), 1n, 2n, "ToPrimitive: unbox object with internal slot"); >+ >+let o = { >+ [Symbol.toPrimitive]: function() { >+ return 2n; >+ } >+}; >+testExp(o, 1n, 2n, "ToPrimitive: @@toPrimitive"); >+ >+o = { >+ valueOf: function() { >+ return 2n; >+ } >+}; >+testExp(o, 1n, 2n, "ToPrimitive: valueOf"); >+ >+o = { >+ toString: function() { >+ return 2n; >+ } >+} >+testExp(o, 1n, 2n, "ToPrimitive: toString"); >+ >diff --git a/JSTests/stress/value-pow-ai-rule.js b/JSTests/stress/value-pow-ai-rule.js >new file mode 100644 >index 0000000000000000000000000000000000000000..ed48265fa8800675933e39b0e8b835a0a82b8209 >--- /dev/null >+++ b/JSTests/stress/value-pow-ai-rule.js >@@ -0,0 +1,20 @@ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Expected: " + e + " bug got: " + a); >+} >+ >+let predicate = true; >+function foo(a) { >+ let v = a; >+ if (predicate) >+ v = 10; >+ >+ let c = v ** 5; >+ return c; >+} >+noInline(foo); >+ >+for (let i = 0; i < 10000; i++) { >+ assert(foo("10"), 100000); >+} >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 190799
:
358509
|
358518
|
358520
|
360053
|
360103
|
360105
|
362260
|
364248
|
369121
|
370657
|
370705
|
371195