WebKit Bugzilla
Attachment 370705 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-20190527223429.patch (text/plain), 48.23 KB, created by
Caio Lima
on 2019-05-27 13:34:30 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2019-05-27 13:34:30 PDT
Size:
48.23 KB
patch
obsolete
>Subversion Revision: 245779 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index df5adc4cc725fa461b2ac8974f772558f11a5455..d2ef3aa6210004e4a354b16dda91025bbaa3aecc 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,73 @@ >+2019-05-26 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-25 Tadeu Zagallo <tzagallo@apple.com> > > JITOperations getByVal should mark negative array indices as out-of-bounds >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index ac28dcdbb3a20a9266c99a027e340a7e11a60b80..80c33f7584fbc6b972218243aadbe97a7093a9e0 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -902,6 +902,27 @@ 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()) { >+ // We need to call `didFoldClobberWorld` here because this path is only possible >+ // when node->useKind is UntypedUse. In the case of BigIntUse, children will be >+ // cleared by `AbstractInterpreter::executeEffects`. >+ 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 38023fce2d22564f46d451a016f4a0cf23e2bdb2..bf9f55dc9ca2783039f0c7c94a79a8c24021db17 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -5125,12 +5125,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 72dbaab46134a35452f4b10fc364513303a087dc..c56d3ed7e7c6720fc4216ecea2878da1685d64a0 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -681,6 +681,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > case ValueMul: > case ValueDiv: > case ValueMod: >+ 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 5560e8e2393c985fdd79bf0e13b245a6dccf8168..8d8d6cd06f7947e42caebf950c6294cb74c8b785 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -380,6 +380,7 @@ bool doesGC(Graph& graph, Node* node) > case ValueMul: > case ValueDiv: > case ValueMod: >+ case ValuePow: > case ValueBitNot: > case ValueNegate: > #else >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index f929fe3fdfa5ee5d2580e010ea91a36f439c3bbc..aa177b9ebbdda8c576ca9183c990b50b8427dd76 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -108,6 +108,18 @@ 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)) { >@@ -589,15 +601,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 b2c0b41e3de7588b8804552d12f2be998e204c7f..4194c2a40898f6dcd8cb2e1c8724c2a79b8f8f0f 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) \ > macro(ValueMod, NodeResultJS | NodeMustGenerate) \ > \ > /* Add of values that always convers its inputs to strings. May have two or three kids. */\ >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index 25c4c090d6001e6bc11f40b646b9df676b6c0418..5cb276f3f19fcf81ebff3efdcd7be0153947e96b 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -548,6 +548,19 @@ EncodedJSValue JIT_OPERATION operationValueDiv(ExecState* exec, EncodedJSValue e > return binaryOp(exec, encodedOp1, encodedOp2, bigIntOp, numberOp, "Invalid mix of BigInt and other type in division operation."); > } > >+EncodedJSValue JIT_OPERATION operationValuePow(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) >+{ >+ auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* { >+ return JSBigInt::exponentiate(exec, left, right); >+ }; >+ >+ auto numberOp = [] (double left, double right) -> double { >+ return operationMathPow(left, right); >+ }; >+ >+ return binaryOp(exec, encodedOp1, encodedOp2, bigIntOp, numberOp, "Invalid mix of BigInt and other type in exponentiation operation."_s); >+} >+ > double JIT_OPERATION operationArithAbs(ExecState* exec, EncodedJSValue encodedOp1) > { > VM* vm = &exec->vm(); >@@ -1396,6 +1409,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 0ce007921d9b7bfd7051270f9617d8bd017c8d09..7ee6c355e2d39190805c610bda4ddb46f6f267e8 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.h >+++ b/Source/JavaScriptCore/dfg/DFGOperations.h >@@ -60,6 +60,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; >@@ -171,6 +172,7 @@ JSCell* JIT_OPERATION operationSubBigInt(ExecState*, JSCell* op1, JSCell* op2) W > JSCell* JIT_OPERATION operationMulBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationModBigInt(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 098af63e64ed9c047ab37a54e0b82b430715ded8..84d61de6748af73b19953c275d79dc84e423ae5d 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(); >@@ -1120,6 +1136,7 @@ private: > case ValueMul: > case ValueDiv: > case ValueMod: >+ case ValuePow: > case ArithAdd: > case ArithSub: > case ArithNegate: >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index 2bf682b56dda0c9b40ef6322888445a0d46b5770..72ca69a595a2cddb55171246454709a56a5c36d5 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -239,6 +239,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case ValueMul: > case ValueDiv: > case ValueMod: >+ case ValuePow: > case TryGetById: > case DeleteById: > case DeleteByVal: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index d0410b35d39017f80db5905ed492d3e33868bc5c..e5538f19360636fc5a43a3a29fe18f5437015c77 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -5796,6 +5796,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 d9ce5baf25f0c493215e6a65904ad4beced0a77d..9f1d893b87c15cea4559ed775b09941aa0101a3a 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -1359,6 +1359,7 @@ public: > void compileValueMod(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 db2d4649f691dbfee937bd5baf1d9a4aadd4bb7a..9d382cf616d9d32775be9750899d0c9ae853dd8b 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -2097,6 +2097,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 e9f467fe8d197021e50f60add3cdcb83cb2f4636..2d62faa8c33ac9499f503fdb240476db63a61e92 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2253,6 +2253,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 0aa5b09feed4c1531b553f80c289f37115524770..e3141e69f7f5ab821b1479459c655264f47b95bd 100644 >--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp >+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp >@@ -258,6 +258,7 @@ public: > case ValueMul: > case ValueDiv: > case ValueMod: >+ case ValuePow: > case ArithAdd: > case ArithSub: > case ArithMul: >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index c5d4f1824e9ab76892c9f0b7998aa0d22826b322..a22c117e44c8616e3de1222d704ccf9ca5cb2990 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -99,6 +99,7 @@ inline CapabilityLevel canCompile(Node* node) > case ValueMul: > case ValueDiv: > case ValueMod: >+ case ValuePow: > case StrCat: > case ArithAdd: > case ArithClz32: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index 5e28a1a232b1771b5a8291234f476cfb31b28f95..94c9658225a710dab803152da0249f63d390ffac 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -793,6 +793,9 @@ private: > case ArithAbs: > compileArithAbs(); > break; >+ case ValuePow: >+ compileValuePow(); >+ break; > case ArithPow: > compileArithPow(); > break; >@@ -2718,6 +2721,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 4e78a48d6d19eb9b06d3c9ed074e958112d08a7a..29b2022338aac3e88f2a33e2b8937a5832ad90e2 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -636,12 +636,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..4c0c1f9eaecab266d200afb54d2311279e358332 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -237,6 +237,95 @@ 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); >+ RETURN_IF_EXCEPTION(scope, 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); >+ RETURN_IF_EXCEPTION(scope, nullptr); >+ runningSquare = maybeResult; >+ if (n & 1) { >+ if (!result) >+ result = runningSquare; >+ else { >+ maybeResult = JSBigInt::multiply(exec, result, runningSquare); >+ RETURN_IF_EXCEPTION(scope, nullptr); >+ result = maybeResult; >+ } >+ } >+ } >+ >+ return result; >+} >+ > JSBigInt* JSBigInt::multiply(ExecState* exec, JSBigInt* x, JSBigInt* y) > { > VM& vm = exec->vm(); >@@ -1055,7 +1144,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 96d083c93a85dfc81c589526c3a439dbd8bd881a..d1444e0d31c9e2af777ac70cfa316415e5111586 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,20 @@ >+2019-05-26 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-25 Tadeu Zagallo <tzagallo@apple.com> > > JITOperations getByVal should mark negative array indices as out-of-bounds >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