WebKit Bugzilla
Attachment 360103 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-20190125100828.patch (text/plain), 43.99 KB, created by
Caio Lima
on 2019-01-25 04:08:31 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2019-01-25 04:08:31 PST
Size:
43.99 KB
patch
obsolete
>Subversion Revision: 240431 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 43d6ca8a878c42c4bfdc9c125148eac349d7c7c1..60947eea1887b86697a3e106997ece720426371c 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,50 @@ >+2019-01-24 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): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGDoesGC.cpp: >+ (JSC::DFG::doesGC): >+ * 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): >+ * runtime/JSBigInt.cpp: >+ (JSC::JSBigInt::exponentiate): >+ * runtime/JSBigInt.h: >+ > 2019-01-24 Carlos Garcia Campos <cgarcia@igalia.com> > > [GLIB] Expose JavaScriptCore options in GLib public API >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index 7581a1a7746e9870e79f92e2178fbd2c9759226d..c601bee73e83dc361eb26998f7d0c754cb70b9cc 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -856,7 +856,25 @@ 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()) { >+ 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 b1dc25b1b878f0b5d4f4d41d41df1fdad92362a4..9c0f889b459371272b5854108588358b2e7ac274 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -5060,12 +5060,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 7e9b0d8969aceaa0fca1039b0bcc746beb7b9533..360c54a7fb92e7015854eb3e2c41273feebd340c 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -670,6 +670,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 5418127a228e307aa9dd0ca063afde43c529dc2f..cb6d71fba14b252b7dbdb9f265e57dcec4cf524b 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -382,6 +382,7 @@ bool doesGC(Graph& graph, Node* node) > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValuePow: > return true; > > case GetIndexedPropertyStorage: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index d2d4fbfb44b35715358ca71e46f1ed20c68e2be2..029cc191e55fb68456752a20f3d21241a2502ecd 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)) { >@@ -561,15 +573,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 bd3bfe2fd40d2d0bd3b1d307a43a122935284e43..ccc3942bb6151c5050e4dd150a8477d25ffb4896 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -176,6 +176,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 d4a0a7aeee88bee483cb4af518097108535a1338..edbeadd50729f2ce330212c99a570850893c51da 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -542,6 +542,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 38c116a54f91a615b81c15112148f25f94adb1ef..bfb498c43daf0543e0a06c5de207cd5b7e3189d9 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 operationBitOrBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationAddBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index c2afe5b378add7ae4d1e9bd4fd8320ae27687065..97da8a8b1bc2a6ba3da7da134a331b30302dc117 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 883f79988bd6a4a4c2735173bc5c598c5a77666d..3d128778bbdf290bcea1389adf4790dd47c92969 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -236,6 +236,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 2e8663a3315b9422cb9d19d470069b8064502940..d16890a7d45a28ae92031feac6db60fa5d8d62e0 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -5793,6 +5793,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 8ed85f6311f14a940530e2f146288ab612b10b3d..9c15f765ed030ba0e7bf07f0f1811a4dc5105f2f 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -1362,6 +1362,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 4dfe9c92321d753d178148f4ed35f8973f3e6f52..e0734fb26058f09ee64264e432a5ff57146814c6 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -2086,6 +2086,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 7f9e381b755d264ca75e3e7dcaca80c8741dde66..186ac09b37df757d503a419a47aab701d8615a4e 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2238,6 +2238,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 abd1ab2f512c35677cad4f4c95fdd5fb94ec15ce..6a9d7c6452e13526229e3b5011cfcf1f8e56dfe7 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 1ff0c337da8c95ce94c56f8ebe3a9b6a4e4dab15..f2c2980b9cb1f16e6d3f63d81181a2fbb884d8cf 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -96,6 +96,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 ae1fa909136f74647c4cea289da0a8fa6d3faa04..77b62e5267d3faa22c25f92a016005faed58dd5b 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -629,6 +629,9 @@ private: > case ArithAbs: > compileArithAbs(); > break; >+ case ValuePow: >+ compileValuePow(); >+ break; > case ArithPow: > compileArithPow(); > break; >@@ -2525,6 +2528,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 bbbadab67fdf6fcad4cac0664cdc8e60bf5e4b2e..ff5a1576b8d58b6883985fea4b8e8a5cbf3e793b 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -643,12 +643,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 2bcaa9b6762d252f0b31ee1a8949cdd83746800e..dbd0504b0ce6c0a432d1113c62eff82fa513a096 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(); >@@ -1049,7 +1142,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 dbbf63ded1c8cbd48ea7b9fcb5b0e8515b5fea9d..9882e4a9bc73eee59bd20e6c9e17abc4ee52653e 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 4dc67e70fca078c469ddef58f68b6b44e32e9653..e443fe2bc32aa46d9b4a459517dc7260ebe7ed37 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,18 @@ >+2019-01-24 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-to-primitive.js: Added. >+ * stress/big-int-exp-type-error.js: Added. >+ * stress/big-int-exp-wrapped-value.js: Added. >+ > 2019-01-23 Yusuke Suzuki <ysuzuki@apple.com> > > [DFG] AvailabilityMap::pruneByLiveness should make non-live operands Availability::unavailable instead of Availability() >diff --git a/JSTests/stress/big-int-exp-basic.js b/JSTests/stress/big-int-exp-basic.js >new file mode 100644 >index 0000000000000000000000000000000000000000..8844ff297283311f8a078cb88b3c5f1111a1b212 >--- /dev/null >+++ b/JSTests/stress/big-int-exp-basic.js >@@ -0,0 +1,82 @@ >+//@ runBigIntEnabled >+ >+// Copyright (C) 2017 Robin Templeton. All rights reserved. >+// This code is governed by the BSD license found in the LICENSE file. >+ >+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-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"); >+
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