WebKit Bugzilla
Attachment 340808 Details for
Bug 182214
: [ESNext][BigInt] Implement "+" and "-" unary operation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-182214-20180520185724.patch (text/plain), 47.35 KB, created by
Caio Lima
on 2018-05-20 14:57:27 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2018-05-20 14:57:27 PDT
Size:
47.35 KB
patch
obsolete
>Subversion Revision: 232001 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 8228176e72b5a333221358c4f3bea8410ceaf0da..374482854768742371a9f389d4979e9a8f7abb71 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,86 @@ >+2018-05-20 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement "+" and "-" unary operation >+ https://bugs.webkit.org/show_bug.cgi?id=182214 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This Patch is implementing support to "-" unary operation on BigInt. >+ It is also changing the logic of ASTBuilder::makeNegateNode to >+ calculate BigInt literals with properly sign, avoiding >+ unecessary operation. It required a refactoring into >+ JSBigInt::parseInt to consider the sign as parameter. >+ >+ We are also introducing a new DFG Node called ValueNegate to handle BigInt negate >+ operations. With the introduction of BigInt, it is not true >+ that every negate operation returns a Number. As ArithNegate is a >+ node that considers its result is always a Number, like all other >+ Arith<Operation>, we decided to keep this consistency and use ValueNegate when >+ speculation indicates that the operand is a BigInt. >+ This design is following the same distinction between ArithAdd and >+ ValueAdd. Also, this new node will make simpler the introduction of >+ optimizations when we create speculation paths for BigInt in future >+ patches. >+ >+ In the case of "+" unary operation on BigInt, the current semantic we already have >+ is correctly, since it needs to throw TypeError because of ToNumber call[1]. >+ In such case, we are adding tests to verify other edge cases. >+ >+ [1] - https://tc39.github.io/proposal-bigint/#sec-unary-plus-operator >+ >+ * bytecompiler/BytecodeGenerator.cpp: >+ (JSC::BytecodeGenerator::addBigIntConstant): >+ * bytecompiler/BytecodeGenerator.h: >+ * bytecompiler/NodesCodegen.cpp: >+ (JSC::BigIntNode::jsValue const): >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::makeSafe): >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGDoesGC.cpp: >+ (JSC::DFG::doesGC): >+ * dfg/DFGFixupPhase.cpp: >+ (JSC::DFG::FixupPhase::fixupNode): >+ * dfg/DFGNode.h: >+ (JSC::DFG::Node::arithNodeFlags): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileValueNegate): >+ (JSC::DFG::SpeculativeJIT::compileArithNegate): >+ * dfg/DFGSpeculativeJIT.h: >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compileNode): >+ (JSC::FTL::DFG::LowerDFGToB3::compileValueNegate): >+ (JSC::FTL::DFG::LowerDFGToB3::compileArithNegate): >+ * jit/JITOperations.cpp: >+ * parser/ASTBuilder.h: >+ (JSC::ASTBuilder::createBigIntWithSign): >+ (JSC::ASTBuilder::createBigIntFromUnaryOperation): >+ (JSC::ASTBuilder::makeNegateNode): >+ * parser/NodeConstructors.h: >+ (JSC::BigIntNode::BigIntNode): >+ * parser/Nodes.h: >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::updateArithProfileForUnaryArithOp): >+ (JSC::SLOW_PATH_DECL): >+ * runtime/JSBigInt.cpp: >+ (JSC::JSBigInt::parseInt): >+ * runtime/JSBigInt.h: >+ * runtime/JSCJSValueInlines.h: >+ (JSC::JSValue::strictEqualSlowCaseInline): >+ > 2018-05-18 Filip Pizlo <fpizlo@apple.com> > > DFG should inline InstanceOf ICs >diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >index e199e8f1b41c1355366dc4884d53d6e333310549..edb5050625cccf7e46b3ef84aaf1e821cf4840e9 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >@@ -3150,11 +3150,12 @@ RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst) > return dst; > } > >-JSValue BytecodeGenerator::addBigIntConstant(const Identifier& identifier, uint8_t radix) >+JSValue BytecodeGenerator::addBigIntConstant(const Identifier& identifier, uint8_t radix, bool sign) > { >- return m_bigIntMap.ensure(BigIntMapEntry(identifier.impl(), radix), [&] { >+ return m_bigIntMap.ensure(BigIntMapEntry(identifier.impl(), radix, sign), [&] { > auto scope = DECLARE_CATCH_SCOPE(*vm()); >- JSBigInt* bigIntInMap = JSBigInt::parseInt(nullptr, *vm(), identifier.string(), radix); >+ auto parseIntSign = sign ? JSBigInt::ParseIntSign::Signed : JSBigInt::ParseIntSign::Unsigned; >+ JSBigInt* bigIntInMap = JSBigInt::parseInt(nullptr, *vm(), identifier.string(), radix, JSBigInt::ErrorParseMode::ThrowExceptions, parseIntSign); > // FIXME: [ESNext] Enables a way to throw an error on ByteCodeGenerator step > // https://bugs.webkit.org/show_bug.cgi?id=180139 > scope.assertNoException(); >diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >index 97828ca50efa8b652ddff6e482993081da5ebc80..a7cc165675418ccef6dbff749a6ab2a91746ab28 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >@@ -1024,7 +1024,7 @@ namespace JSC { > void allocateCalleeSaveSpace(); > void allocateAndEmitScope(); > >- using BigIntMapEntry = std::pair<UniquedStringImpl*, uint8_t>; >+ using BigIntMapEntry = std::tuple<UniquedStringImpl*, uint8_t, bool>; > > using NumberMap = HashMap<double, JSValue>; > using IdentifierStringMap = HashMap<UniquedStringImpl*, JSString*, IdentifierRepHash>; >@@ -1113,7 +1113,7 @@ namespace JSC { > > public: > JSString* addStringConstant(const Identifier&); >- JSValue addBigIntConstant(const Identifier&, uint8_t radix); >+ JSValue addBigIntConstant(const Identifier&, uint8_t radix, bool sign); > RegisterID* addTemplateObjectConstant(Ref<TemplateObjectDescriptor>&&); > > Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; } >diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >index a5fa525d216021b00d955ad9de63c11f336a58d1..3da1ab3a111185111712c7a856fe50d79641ca33 100644 >--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >@@ -124,7 +124,7 @@ JSValue StringNode::jsValue(BytecodeGenerator& generator) const > > JSValue BigIntNode::jsValue(BytecodeGenerator& generator) const > { >- return generator.addBigIntConstant(m_value, m_radix); >+ return generator.addBigIntConstant(m_value, m_radix, m_sign); > } > > // ------------------------------ NumberNode ---------------------------------- >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index c4c92dd3b48d8478cca78a982794f86538fb003c..c5382005d2abc5bb6aa0d8a844eec3d4a34cdef5 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -761,6 +761,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >+ case ValueNegate: { >+ clobberWorld(); >+ setTypeForNode(node, SpecBytecodeNumber | SpecBigInt); >+ break; >+ } >+ > case ArithNegate: { > JSValue child = forNode(node->child1()).value(); > switch (node->child1().useKind()) { >@@ -808,9 +814,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > forNode(node->child1()).m_type)); > break; > default: >- DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse, node->child1().useKind()); >- clobberWorld(); >- setNonCellTypeForNode(node, SpecBytecodeNumber); >+ RELEASE_ASSERT_NOT_REACHED(); > break; > } > break; >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index fa097f32c666ed3f33fdbc4bbe38c15442b4d6e1..d07ca9268d8d76bc2eb9529bba6b3689bab181b6 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -936,17 +936,19 @@ private: > node->mergeFlags(NodeMayHaveNonNumberResult); > break; > } >+ case ValueNegate: > case ArithNegate: { >- // We'd like to assert here that the arith profile for the result of negate never >- // sees a non-number, but we can't. It's true that negate never produces a non-number. >- // But sometimes we'll end up grabbing the wrong ArithProfile during OSR exit, and >- // profiling the wrong value, leading the ArithProfile to think it observed a non-number result. > if (arithProfile->lhsObservedType().sawNumber() || arithProfile->didObserveDouble()) > node->mergeFlags(NodeMayHaveDoubleResult); > if (arithProfile->didObserveNegZeroDouble() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero)) > node->mergeFlags(NodeMayNegZeroInBaseline); > if (arithProfile->didObserveInt32Overflow() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) > node->mergeFlags(NodeMayOverflowInt32InBaseline); >+ if (arithProfile->didObserveNonNumber()) { >+ // FIXME: We should add support to BigInt into speculation >+ // https://bugs.webkit.org/show_bug.cgi?id=182470 >+ node->mergeFlags(NodeMayHaveNonNumberResult); >+ } > break; > } > >@@ -4710,7 +4712,10 @@ void ByteCodeParser::parseBlock(unsigned limit) > > case op_negate: { > Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); >- set(VirtualRegister(currentInstruction[1].u.operand), makeSafe(addToGraph(ArithNegate, op1))); >+ if (op1->hasNumberResult()) >+ set(VirtualRegister(currentInstruction[1].u.operand), makeSafe(addToGraph(ArithNegate, op1))); >+ else >+ set(VirtualRegister(currentInstruction[1].u.operand), makeSafe(addToGraph(ValueNegate, op1))); > NEXT_OPCODE(op_negate); > } > >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index 3ea02a8548eb6ab951cacf08341d99aff3e9e675..9e890b867c0ab8c189539b785ef3935ac166aa95 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -626,6 +626,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > case InByVal: > case InById: > case HasOwnProperty: >+ case ValueNegate: > case ValueAdd: > case SetFunctionName: > case GetDynamicVar: >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index fdf2e77fe1fe5168c5e7e2a880812683df630144..e08d21ae4e123be93399d693512e6c561f9985b6 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -97,6 +97,7 @@ bool doesGC(Graph& graph, Node* node) > case ArithFRound: > case ArithUnary: > case ValueAdd: >+ case ValueNegate: > case TryGetById: > case GetById: > case GetByIdFlush: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index ecbb3d3b0f20d3d81183165f7f1376ef92abb59e..2dfceeac9c74792189b0affc000d93fdd506ced9 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -146,7 +146,45 @@ private: > } > break; > } >+ >+ case ValueNegate: { >+ if (node->child1()->shouldSpeculateInt32OrBoolean() && node->canSpeculateInt32(FixupPass)) { >+ node->setOp(ArithNegate); >+ fixIntOrBooleanEdge(node->child1()); >+ if (bytecodeCanTruncateInteger(node->arithNodeFlags())) >+ node->setArithMode(Arith::Unchecked); >+ else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) >+ node->setArithMode(Arith::CheckOverflow); >+ else >+ node->setArithMode(Arith::CheckOverflowAndNegativeZero); >+ node->setResult(NodeResultInt32); >+ node->clearFlags(NodeMustGenerate); >+ break; >+ } > >+ if (m_graph.unaryArithShouldSpeculateAnyInt(node, FixupPass)) { >+ node->setOp(ArithNegate); >+ fixEdge<Int52RepUse>(node->child1()); >+ if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) >+ node->setArithMode(Arith::CheckOverflow); >+ else >+ node->setArithMode(Arith::CheckOverflowAndNegativeZero); >+ node->setResult(NodeResultInt52); >+ node->clearFlags(NodeMustGenerate); >+ break; >+ } >+ if (node->child1()->shouldSpeculateNotCell()) { >+ node->setOp(ArithNegate); >+ fixDoubleOrBooleanEdge(node->child1()); >+ node->setResult(NodeResultDouble); >+ node->clearFlags(NodeMustGenerate); >+ } else { >+ fixEdge<UntypedUse>(node->child1()); >+ node->setResult(NodeResultJS); >+ } >+ break; >+ } >+ > case ValueAdd: { > if (attemptToMakeIntegerAdd(node)) { > node->setOp(ArithAdd); >@@ -257,12 +295,10 @@ private: > node->clearFlags(NodeMustGenerate); > break; > } >- if (node->child1()->shouldSpeculateNotCell()) { >- fixDoubleOrBooleanEdge(node->child1()); >- node->setResult(NodeResultDouble); >- node->clearFlags(NodeMustGenerate); >- } else >- fixEdge<UntypedUse>(node->child1()); >+ >+ fixDoubleOrBooleanEdge(node->child1()); >+ node->setResult(NodeResultDouble); >+ node->clearFlags(NodeMustGenerate); > break; > } > >diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h >index 6236309e62ee5ff53860b5dabbfe2b0b11d0af09..772546fdc2b994b21ba2621a92691f24e881cd34 100644 >--- a/Source/JavaScriptCore/dfg/DFGNode.h >+++ b/Source/JavaScriptCore/dfg/DFGNode.h >@@ -1107,7 +1107,7 @@ public: > NodeFlags arithNodeFlags() > { > NodeFlags result = m_flags & NodeArithFlagsMask; >- if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc || op() == DoubleAsInt32) >+ if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc || op() == DoubleAsInt32 || op() == ValueNegate) > return result; > return result & ~NodeBytecodeNeedsNegZero; > } >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index 531711bdab6ddc3855e419059bd77bb1abde254e..52b7bb9f82896ea46ffb129f5b49293d64eff316 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -162,6 +162,9 @@ namespace JSC { namespace DFG { > macro(ArithSqrt, NodeResultDouble | NodeMustGenerate) \ > macro(ArithUnary, NodeResultDouble | NodeMustGenerate) \ > \ >+ /* BigInt is a valid operand for negate operations */\ >+ macro(ValueNegate, NodeResultJS | NodeMustGenerate) \ >+ \ > /* Add of values may either be arithmetic, or result in string concatenation. */\ > macro(ValueAdd, NodeResultJS | NodeMustGenerate) \ > \ >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index 9c661f905aa47c20c58c1302740a3b22de4aa4a4..5279423f90636f8f225f4914c797c076f6f472fc 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -245,6 +245,7 @@ private: > break; > } > >+ case ValueNegate: > case ArithNegate: { > SpeculatedType prediction = node->child1()->prediction(); > if (prediction) { >@@ -256,6 +257,11 @@ private: > changed |= mergePrediction(speculatedDoubleTypeForPrediction(node->child1()->prediction())); > else { > changed |= mergePrediction(SpecInt32Only); >+ if (node->op() == ValueNegate && node->mayHaveNonNumberResult()) { >+ // FIXME: We should add support to BigInt into speculatio >+ // https://bugs.webkit.org/show_bug.cgi?id=18247 >+ changed |= mergePrediction(SpecBigInt); >+ } > if (node->mayHaveDoubleResult()) > changed |= mergePrediction(SpecBytecodeDouble); > } >@@ -1038,6 +1044,7 @@ private: > case GetLocal: > case SetLocal: > case UInt32ToNumber: >+ case ValueNegate: > case ValueAdd: > case ArithAdd: > case ArithSub: >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index d6d026c4269b3642551a268ad1563b82467e6d71..b35078fd7033586b4e3cf719da83a6cff0e3caaf 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -219,6 +219,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case ArithCeil: > case ArithTrunc: > case ArithUnary: >+ case ValueNegate: > case ValueAdd: > case TryGetById: > case DeleteById: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index 1d56d4657a783ddeebc62158fb297efa48ff0812..517c578d3254ea00a82b9b99ace60a5851829691 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -4470,6 +4470,18 @@ void SpeculativeJIT::compileArithSub(Node* node) > } > } > >+void SpeculativeJIT::compileValueNegate(Node* node) >+{ >+ CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic); >+ ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex); >+ Instruction* instruction = &baselineCodeBlock->instructions()[node->origin.semantic.bytecodeIndex]; >+ JITNegIC* negIC = m_jit.codeBlock()->addJITNegIC(arithProfile, instruction); >+ auto repatchingFunction = operationArithNegateOptimize; >+ auto nonRepatchingFunction = operationArithNegate; >+ bool needsScratchGPRReg = true; >+ compileMathIC(node, negIC, needsScratchGPRReg, repatchingFunction, nonRepatchingFunction); >+} >+ > void SpeculativeJIT::compileArithNegate(Node* node) > { > switch (node->child1().useKind()) { >@@ -4544,15 +4556,7 @@ void SpeculativeJIT::compileArithNegate(Node* node) > } > > default: { >- CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic); >- ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex); >- Instruction* instruction = &baselineCodeBlock->instructions()[node->origin.semantic.bytecodeIndex]; >- JITNegIC* negIC = m_jit.codeBlock()->addJITNegIC(arithProfile, instruction); >- auto repatchingFunction = operationArithNegateOptimize; >- auto nonRepatchingFunction = operationArithNegate; >- bool needsScratchGPRReg = true; >- compileMathIC(node, negIC, needsScratchGPRReg, repatchingFunction, nonRepatchingFunction); >- return; >+ RELEASE_ASSERT_NOT_REACHED(); > } > } > } >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >index 05a08ea14e718164a4effc9506e36b39e1cfff4b..8b0419417ca7da205629949e861c59f45db4bfc5 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -1348,6 +1348,7 @@ public: > void compileArithAbs(Node*); > void compileArithClz32(Node*); > void compileArithSub(Node*); >+ void compileValueNegate(Node*); > void compileArithNegate(Node*); > void compileArithMul(Node*); > void compileArithDiv(Node*); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index 272c57a6a88ac8a7cc1cc01b40b6552db4dde591..920a09a9f657c12d493097c36e8d1dd151107a0b 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -2015,6 +2015,10 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case ValueNegate: >+ compileValueNegate(node); >+ break; >+ > case ValueAdd: > compileValueAdd(node); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index 50f26453538a8c28025609f6c3615ee66946d8cc..e77f234485f4fce69aacbb794537cd92f9f7b45e 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2165,6 +2165,10 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case ValueNegate: >+ compileValueNegate(node); >+ break; >+ > case ValueAdd: > compileValueAdd(node); > break; >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index f1513bb999a9c3ee22ec019536159eec89b9be94..7b44b66eb621467acc348b422939b6b18ef516e0 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -86,6 +86,7 @@ inline CapabilityLevel canCompile(Node* node) > case GetGlobalVar: > case GetGlobalLexicalVariable: > case PutGlobalVariable: >+ case ValueNegate: > case ValueAdd: > case StrCat: > case ArithAdd: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index 911d62ad5427ab15a3fc5c3a2d754fbb9861a144..9747cd80a4d7c915ff092c8ba4aac37611a56a32 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -583,6 +583,9 @@ private: > case ToThis: > compileToThis(); > break; >+ case ValueNegate: >+ compileValueNegate(); >+ break; > case ValueAdd: > compileValueAdd(); > break; >@@ -2708,7 +2711,18 @@ private: > LValue result = vmCall(Double, m_out.operation(operationArithFRound), m_callFrame, argument); > setDouble(result); > } >- >+ >+ void compileValueNegate() >+ { >+ DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse); >+ CodeBlock* baselineCodeBlock = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic); >+ ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(m_node->origin.semantic.bytecodeIndex); >+ Instruction* instruction = &baselineCodeBlock->instructions()[m_node->origin.semantic.bytecodeIndex]; >+ auto repatchingFunction = operationArithNegateOptimize; >+ auto nonRepatchingFunction = operationArithNegate; >+ compileUnaryMathIC<JITNegGenerator>(arithProfile, instruction, repatchingFunction, nonRepatchingFunction); >+ } >+ > void compileArithNegate() > { > switch (m_node->child1().useKind()) { >@@ -2757,13 +2771,7 @@ private: > } > > default: >- DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse, m_node->child1().useKind()); >- CodeBlock* baselineCodeBlock = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic); >- ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(m_node->origin.semantic.bytecodeIndex); >- Instruction* instruction = &baselineCodeBlock->instructions()[m_node->origin.semantic.bytecodeIndex]; >- auto repatchingFunction = operationArithNegateOptimize; >- auto nonRepatchingFunction = operationArithNegate; >- compileUnaryMathIC<JITNegGenerator>(arithProfile, instruction, repatchingFunction, nonRepatchingFunction); >+ DFG_CRASH(m_graph, m_node, "Bad use kind"); > break; > } > } >diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp >index 76d72e29739b601053ef5230a7dd000b66efa4e1..49dc4060406c228d0e6273dd3935ae75994b5050 100644 >--- a/Source/JavaScriptCore/jit/JITOperations.cpp >+++ b/Source/JavaScriptCore/jit/JITOperations.cpp >@@ -2712,7 +2712,14 @@ ALWAYS_INLINE static EncodedJSValue unprofiledNegate(ExecState* exec, EncodedJSV > NativeCallFrameTracer tracer(&vm, exec); > > JSValue operand = JSValue::decode(encodedOperand); >- double number = operand.toNumber(exec); >+ >+ JSValue primValue = operand.toPrimitive(exec, PreferNumber); >+ RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ >+ if (primValue.isBigInt()) >+ return JSValue::encode(JSValue(JSBigInt::unaryMinus(vm, asBigInt(primValue)))); >+ >+ double number = primValue.toNumber(exec); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); > return JSValue::encode(jsNumber(-number)); > } >@@ -2725,9 +2732,19 @@ ALWAYS_INLINE static EncodedJSValue profiledNegate(ExecState* exec, EncodedJSVal > > JSValue operand = JSValue::decode(encodedOperand); > arithProfile.observeLHS(operand); >- double number = operand.toNumber(exec); >+ >+ JSValue primValue = operand.toPrimitive(exec); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ >+ if (primValue.isBigInt()) { >+ JSValue result = JSValue(JSBigInt::unaryMinus(vm, asBigInt(primValue))); >+ arithProfile.observeResult(result); >+ >+ return JSValue::encode(result); >+ } > >+ double number = primValue.toNumber(exec); >+ RETURN_IF_EXCEPTION(scope, encodedJSValue()); > JSValue result = jsNumber(-number); > arithProfile.observeResult(result); > return JSValue::encode(result); >@@ -2761,7 +2778,16 @@ EncodedJSValue JIT_OPERATION operationArithNegateProfiledOptimize(ExecState* exe > exec->codeBlock()->dumpMathICStats(); > #endif > >- double number = operand.toNumber(exec); >+ JSValue primValue = operand.toPrimitive(exec); >+ RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ >+ if (primValue.isBigInt()) { >+ JSValue result = JSValue(JSBigInt::unaryMinus(vm, asBigInt(primValue))); >+ arithProfile->observeResult(result); >+ return JSValue::encode(result); >+ } >+ >+ double number = primValue.toNumber(exec); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); > JSValue result = jsNumber(-number); > arithProfile->observeResult(result); >@@ -2784,7 +2810,15 @@ EncodedJSValue JIT_OPERATION operationArithNegateOptimize(ExecState* exec, Encod > exec->codeBlock()->dumpMathICStats(); > #endif > >- double number = operand.toNumber(exec); >+ JSValue primValue = operand.toPrimitive(exec); >+ RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ >+ if (primValue.isBigInt()) { >+ JSValue result = JSValue(JSBigInt::unaryMinus(vm, asBigInt(primValue))); >+ return JSValue::encode(result); >+ } >+ >+ double number = primValue.toNumber(exec); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); > return JSValue::encode(jsNumber(-number)); > } >diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h >index 5c6dd33198ca2f94505358cdf94b605c9be7e812..65ad1070fbb2203dc73c5fe73971c778471747a5 100644 >--- a/Source/JavaScriptCore/parser/ASTBuilder.h >+++ b/Source/JavaScriptCore/parser/ASTBuilder.h >@@ -1072,6 +1072,10 @@ private: > { > return new (m_parserArena) DoubleNode(location, d); > } >+ ExpressionNode* createBigIntWithSign(const JSTokenLocation& location, const Identifier& bigInt, uint8_t radix, bool sign) >+ { >+ return new (m_parserArena) BigIntNode(location, bigInt, radix, sign); >+ } > ExpressionNode* createNumberFromBinaryOperation(const JSTokenLocation& location, double value, const NumberNode& originalNodeA, const NumberNode& originalNodeB) > { > if (originalNodeA.isIntegerNode() && originalNodeB.isIntegerNode()) >@@ -1084,6 +1088,10 @@ private: > return createIntegerLikeNumber(location, value); > return createDoubleLikeNumber(location, value); > } >+ ExpressionNode* createBigIntFromUnaryOperation(const JSTokenLocation& location, bool sign, const BigIntNode& originalNode) >+ { >+ return createBigIntWithSign(location, originalNode.identifier(), originalNode.radix(), sign); >+ } > > void tryInferNameInPattern(DestructuringPattern pattern, ExpressionNode* defaultValue) > { >@@ -1156,6 +1164,11 @@ ExpressionNode* ASTBuilder::makeNegateNode(const JSTokenLocation& location, Expr > return createNumberFromUnaryOperation(location, -numberNode.value(), numberNode); > } > >+ if (n->isBigInt()) { >+ const BigIntNode& bigIntNode = static_cast<const BigIntNode&>(*n); >+ return createBigIntFromUnaryOperation(location, !bigIntNode.sign(), bigIntNode); >+ } >+ > return new (m_parserArena) NegateNode(location, n); > } > >diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h >index 5d77db19b762ef78414688edc71c89f9f7f6dff9..5e113f392b3cb2d0042f83469eedc2bceea8d91b 100644 >--- a/Source/JavaScriptCore/parser/NodeConstructors.h >+++ b/Source/JavaScriptCore/parser/NodeConstructors.h >@@ -97,6 +97,15 @@ namespace JSC { > : ConstantNode(location, ResultType::bigIntType()) > , m_value(value) > , m_radix(radix) >+ , m_sign(false) >+ { >+ } >+ >+ inline BigIntNode::BigIntNode(const JSTokenLocation& location, const Identifier& value, uint8_t radix, bool sign) >+ : ConstantNode(location, ResultType::bigIntType()) >+ , m_value(value) >+ , m_radix(radix) >+ , m_sign(sign) > { > } > >diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h >index 6c0f2dbd0c11adb42c0dec69e4d0dee1adc71cd1..4365637c882155b0ccca99c2fc2e5587740fc783 100644 >--- a/Source/JavaScriptCore/parser/Nodes.h >+++ b/Source/JavaScriptCore/parser/Nodes.h >@@ -345,14 +345,20 @@ namespace JSC { > class BigIntNode final : public ConstantNode { > public: > BigIntNode(const JSTokenLocation&, const Identifier&, uint8_t radix); >+ BigIntNode(const JSTokenLocation&, const Identifier&, uint8_t radix, bool sign); > const Identifier& value() { return m_value; } > >+ const Identifier& identifier() const { return m_value; } >+ uint8_t radix() const { return m_radix; } >+ bool sign() const { return m_sign; } >+ > private: > bool isBigInt() const final { return true; } > JSValue jsValue(BytecodeGenerator&) const final; > > const Identifier& m_value; > const uint8_t m_radix; >+ const bool m_sign; > }; > > class ThrowableExpressionData { >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >index 253db5e4aac6114e306f9d4f2094a4b7c3f1a574..861e25fbf7a32c26306902cb28720dcfde5e6782 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -367,26 +367,29 @@ static void updateArithProfileForUnaryArithOp(Instruction* pc, JSValue result, J > { > ArithProfile& profile = *bitwise_cast<ArithProfile*>(&pc[3].u.operand); > profile.observeLHS(operand); >- ASSERT(result.isNumber()); >- if (!result.isInt32()) { >- if (operand.isInt32()) >- profile.setObservedInt32Overflow(); >- >- double doubleVal = result.asNumber(); >- if (!doubleVal && std::signbit(doubleVal)) >- profile.setObservedNegZeroDouble(); >- else { >- profile.setObservedNonNegZeroDouble(); >- >- // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value. >- // Therefore, we will get a false positive if the result is that value. This is intentionally >- // done to simplify the checking algorithm. >- static const int64_t int52OverflowPoint = (1ll << 51); >- int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal)); >- if (int64Val >= int52OverflowPoint) >- profile.setObservedInt52Overflow(); >+ ASSERT(result.isNumber() || result.isBigInt()); >+ if (result.isNumber()) { >+ if (!result.isInt32()) { >+ if (operand.isInt32()) >+ profile.setObservedInt32Overflow(); >+ >+ double doubleVal = result.asNumber(); >+ if (!doubleVal && std::signbit(doubleVal)) >+ profile.setObservedNegZeroDouble(); >+ else { >+ profile.setObservedNonNegZeroDouble(); >+ >+ // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value. >+ // Therefore, we will get a false positive if the result is that value. This is intentionally >+ // done to simplify the checking algorithm. >+ static const int64_t int52OverflowPoint = (1ll << 51); >+ int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal)); >+ if (int64Val >= int52OverflowPoint) >+ profile.setObservedInt52Overflow(); >+ } > } >- } >+ } else >+ profile.setObservedNonNumber(); > } > #else > static void updateArithProfileForUnaryArithOp(Instruction*, JSValue, JSValue) { } >@@ -396,7 +399,18 @@ SLOW_PATH_DECL(slow_path_negate) > { > BEGIN(); > JSValue operand = OP_C(2).jsValue(); >- JSValue result = jsNumber(-operand.toNumber(exec)); >+ JSValue primValue = operand.toPrimitive(exec, PreferNumber); >+ CHECK_EXCEPTION(); >+ >+ if (primValue.isBigInt()) { >+ JSValue result = JSValue(JSBigInt::unaryMinus(exec->vm(), asBigInt(primValue))); >+ RETURN_WITH_PROFILING(result, { >+ updateArithProfileForUnaryArithOp(pc, result, operand); >+ }); >+ } >+ >+ JSValue result = jsNumber(-primValue.toNumber(exec)); >+ CHECK_EXCEPTION(); > RETURN_WITH_PROFILING(result, { > updateArithProfileForUnaryArithOp(pc, result, operand); > }); >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp >index 460775d248b998bc3e8b827b8b22757fd9d2dbc8..b08090c3ee6051a9dba7fd8ed866762a5508d6e8 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -215,11 +215,11 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, StringView s, ErrorParseMode pars > return parseInt(state, s.characters16(), s.length(), parserMode); > } > >-JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, StringView s, uint8_t radix, ErrorParseMode parserMode) >+JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, StringView s, uint8_t radix, ErrorParseMode parserMode, ParseIntSign sign) > { > if (s.is8Bit()) >- return parseInt(state, vm, s.characters8(), s.length(), 0, radix, parserMode, false); >- return parseInt(state, vm, s.characters16(), s.length(), 0, radix, parserMode, false); >+ return parseInt(state, vm, s.characters8(), s.length(), 0, radix, parserMode, sign, ParseIntMode::DisallowEmptyString); >+ return parseInt(state, vm, s.characters16(), s.length(), 0, radix, parserMode, sign, ParseIntMode::DisallowEmptyString); > } > > JSBigInt* JSBigInt::stringToBigInt(ExecState* state, StringView s) >@@ -1054,42 +1054,42 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, CharType* data, unsigned length, > // Check Radix from frist characters > if (static_cast<unsigned>(p) + 1 < static_cast<unsigned>(length) && data[p] == '0') { > if (isASCIIAlphaCaselessEqual(data[p + 1], 'b')) >- return parseInt(state, vm, data, length, p + 2, 2, errorParseMode, false); >+ return parseInt(state, vm, data, length, p + 2, 2, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString); > > if (isASCIIAlphaCaselessEqual(data[p + 1], 'x')) >- return parseInt(state, vm, data, length, p + 2, 16, errorParseMode, false); >+ return parseInt(state, vm, data, length, p + 2, 16, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString); > > if (isASCIIAlphaCaselessEqual(data[p + 1], 'o')) >- return parseInt(state, vm, data, length, p + 2, 8, errorParseMode, false); >+ return parseInt(state, vm, data, length, p + 2, 8, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString); > } > >- bool sign = false; >+ ParseIntSign sign = ParseIntSign::Unsigned; > if (p < length) { > if (data[p] == '+') > ++p; > else if (data[p] == '-') { >- sign = true; >+ sign = ParseIntSign::Signed; > ++p; > } > } > >- JSBigInt* result = parseInt(state, vm, data, length, p, 10, errorParseMode); >+ JSBigInt* result = parseInt(state, vm, data, length, p, 10, errorParseMode, sign); > > if (result && !result->isZero()) >- result->setSign(sign); >+ result->setSign(sign == ParseIntSign::Signed); > > return result; > } > > template <typename CharType> >-JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode errorParseMode, bool allowEmptyString) >+JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode errorParseMode, ParseIntSign sign, ParseIntMode parseMode) > { > ASSERT(length >= 0); > unsigned p = startIndex; > > auto scope = DECLARE_THROW_SCOPE(vm); > >- if (!allowEmptyString && startIndex == length) { >+ if (parseMode != ParseIntMode::AllowEmptyString && startIndex == length) { > ASSERT(state); > if (errorParseMode == ErrorParseMode::ThrowExceptions) > throwVMError(state, scope, createSyntaxError(state, "Failed to parse String to BigInt")); >@@ -1133,6 +1133,7 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, unsigned > result->inplaceMultiplyAdd(static_cast<Digit>(radix), static_cast<Digit>(digit)); > } > >+ result->setSign(sign == ParseIntSign::Signed ? true : false); > if (p == length) > return result->rightTrim(vm); > >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.h b/Source/JavaScriptCore/runtime/JSBigInt.h >index 67650fc2f368b58fdee550c677e2c628476b7200..533ff4a5cf503a1a11c01e253f7f56b166880193 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -72,13 +72,16 @@ public: > void setLength(unsigned length) { m_length = length; } > unsigned length() const { return m_length; } > >- enum ErrorParseMode { >+ enum class ErrorParseMode { > ThrowExceptions, > IgnoreExceptions > }; > >- static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix, ErrorParseMode = ThrowExceptions); >- static JSBigInt* parseInt(ExecState*, StringView, ErrorParseMode = ThrowExceptions); >+ enum class ParseIntMode { DisallowEmptyString, AllowEmptyString }; >+ enum class ParseIntSign { Unsigned, Signed }; >+ >+ static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix, ErrorParseMode = ErrorParseMode::ThrowExceptions, ParseIntSign = ParseIntSign::Unsigned); >+ static JSBigInt* parseInt(ExecState*, StringView, ErrorParseMode = ErrorParseMode::ThrowExceptions); > static JSBigInt* stringToBigInt(ExecState*, StringView); > > std::optional<uint8_t> singleDigitValueForString(); >@@ -156,7 +159,7 @@ private: > static JSBigInt* parseInt(ExecState*, CharType* data, unsigned length, ErrorParseMode); > > template <typename CharType> >- static JSBigInt* parseInt(ExecState*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode, bool allowEmptyString = true); >+ static JSBigInt* parseInt(ExecState*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode, ParseIntSign = ParseIntSign::Signed, ParseIntMode = ParseIntMode::AllowEmptyString); > > static JSBigInt* allocateFor(ExecState*, VM&, unsigned radix, unsigned charcount); > >diff --git a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >index 55b1218eaf3a7a99df13873a913feac81d17fc8a..2d46b8d04c9a2afb7213af71016c2194db094918 100644 >--- a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >+++ b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >@@ -1100,7 +1100,7 @@ ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v > if (v1.asCell()->isString() && v2.asCell()->isString()) > return asString(v1)->equal(exec, asString(v2)); > if (v1.isBigInt() && v2.isBigInt()) >- return JSBigInt::equals(asBigInt(v1.asCell()), asBigInt(v2.asCell())); >+ return JSBigInt::equals(asBigInt(v1), asBigInt(v2)); > return v1 == v2; > } > >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 72f9954fad476b4d3cd7c2a0def5544fcfe4b577..058ba3c15ee662dc7f4197b3353f6e2e9a48ad5c 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,14 @@ >+2018-05-20 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement "+" and "-" unary operation >+ https://bugs.webkit.org/show_bug.cgi?id=182214 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * stress/big-int-negate-basic.js: Added. >+ * stress/big-int-negate-jit.js: Added. >+ * stress/big-int-unary-plus.js: Added. >+ > 2018-05-19 Yusuke Suzuki <utatane.tea@gmail.com> > > [JSC] JSC should have consistent InById IC >diff --git a/JSTests/stress/big-int-negate-basic.js b/JSTests/stress/big-int-negate-basic.js >new file mode 100644 >index 0000000000000000000000000000000000000000..59ba3c4724dbf01089afd58360a1b5fa72c8b72f >--- /dev/null >+++ b/JSTests/stress/big-int-negate-basic.js >@@ -0,0 +1,71 @@ >+//@ runBigIntEnabled >+// Original tests from https://github.com/tc39/test262/blob/master/test/language/expressions/unary-minus/bigint.js >+ >+function assert(a, b, message) { >+ if (a !== b) >+ throw new Error(message); >+} >+ >+function assertNotEqual(a, b, message) { >+ if (a === b) >+ throw new Error(message); >+} >+ >+assert(-0n, 0n, "-0n === 0n"); >+assert(-(0n), 0n, "-(0n) === 0n"); >+assertNotEqual(-1n, 1n, "-1n !== 1n"); >+assert(-(1n), -1n, "-(1n) === -1n"); >+assertNotEqual(-(1n), 1n, "-(1n) !== 1n"); >+assert(-(-1n), 1n, "-(-1n) === 1n"); >+assertNotEqual(-(-1n), -1n, "-(-1n) !== -1n"); >+assert(- - 1n, 1n, "- - 1n === 1n"); >+assertNotEqual(- - 1n, -1n, "- - 1n !== -1n"); >+assert(-(0x1fffffffffffff01n), -0x1fffffffffffff01n, "-(0x1fffffffffffff01n) === -0x1fffffffffffff01n"); >+assertNotEqual(-(0x1fffffffffffff01n), 0x1fffffffffffff01n, "-(0x1fffffffffffff01n) !== 0x1fffffffffffff01n"); >+assertNotEqual(-(0x1fffffffffffff01n), -0x1fffffffffffff00n, "-(0x1fffffffffffff01n) !== -0x1fffffffffffff00n"); >+ >+// Non-primitive cases >+ >+assert(-Object(1n), -1n, "-Object(1n) === -1n"); >+assertNotEqual(-Object(1n), 1n, "-Object(1n) !== 1n"); >+assertNotEqual(-Object(1n), Object(-1n), "-Object(1n) !== Object(-1n)"); >+assert(-Object(-1n), 1n, "-Object(-1n) === 1n"); >+assertNotEqual(-Object(-1n), -1n, "-Object(-1n) !== -1n"); >+assertNotEqual(-Object(-1n), Object(1n), "-Object(-1n) !== Object(1n)"); >+ >+let obj = { >+ [Symbol.toPrimitive]: function() { >+ return 1n; >+ }, >+ valueOf: function() { >+ throw new Error("Should never be called"); >+ }, >+ toString: function() { >+ throw new Error("Should never be called"); >+ } >+}; >+assert(-obj, -1n, "@@toPrimitive not called properly"); >+ >+obj = { >+ valueOf: function() { >+ return 1n; >+ }, >+ toString: function() { >+ throw new Error("Should never be called"); >+ } >+} >+assert(-obj, -1n, "valueOf not called properly"); >+ >+obj = { >+ toString: function() { >+ return 1n; >+ } >+}; >+ >+assert(-obj, -1n, "-{toString: function() { return 1n; }} === -1n"); >+ >+let x = 1n; >+let y = -x; >+let z = -y; >+assert(x, z, "-(-x) !== z"); >+ >diff --git a/JSTests/stress/big-int-negate-jit.js b/JSTests/stress/big-int-negate-jit.js >new file mode 100644 >index 0000000000000000000000000000000000000000..ab497831c965e87436ab904078bedb0269b58ca0 >--- /dev/null >+++ b/JSTests/stress/big-int-negate-jit.js >@@ -0,0 +1,48 @@ >+//@ skip if not $jitTests >+//@ runBigIntEnabled >+ >+function assert(a, b) { >+ if (a !== b) >+ throw new Error("Bad!"); >+} >+ >+function negateBigInt(n) { >+ return -n; >+} >+noInline(negateBigInt); >+ >+for (let i = 0; i < 100000; i++) { >+ assert(negateBigInt(100n), -100n); >+ assert(negateBigInt(-0x1fffffffffffff01n), 0x1fffffffffffff01n); >+} >+ >+if (numberOfDFGCompiles(negateBigInt) > 1) >+ throw "Failed negateBigInt(). We should have compiled a single negate for the BigInt type."; >+ >+function negateBigIntSpecializedToInt(n) { >+ return -n; >+} >+noInline(negateBigIntSpecializedToInt); >+ >+for (let i = 0; i < 100000; i++) { >+ negateBigIntSpecializedToInt(100); >+} >+ >+assert(negateBigIntSpecializedToInt(100n), -100n); >+ >+// Testing case mixing int and BigInt speculations >+function mixedSpeculationNegateBigInt(n, arr) { >+ return -(-(-n)); >+} >+noInline(mixedSpeculationNegateBigInt); >+ >+for (let i = 0; i < 100000; i++) { >+ if (i % 2) >+ assert(mixedSpeculationNegateBigInt(100), -100); >+ else >+ assert(mixedSpeculationNegateBigInt(-0x1fffffffffffff01n), 0x1fffffffffffff01n); >+} >+ >+if (numberOfDFGCompiles(mixedSpeculationNegateBigInt) > 1) >+ throw "Failed negateBigInt(). We should have compiled a single negate for the BigInt type."; >+ >diff --git a/JSTests/stress/big-int-unary-plus.js b/JSTests/stress/big-int-unary-plus.js >new file mode 100644 >index 0000000000000000000000000000000000000000..4d4ac37b9e5373e6b18b91983cdd372e55396240 >--- /dev/null >+++ b/JSTests/stress/big-int-unary-plus.js >@@ -0,0 +1,51 @@ >+//@ runBigIntEnabled >+ >+function assert(a) { >+ if (!a) >+ throw new Error("Bad!") >+} >+ >+function assertTypeError(input) { >+ try { >+ let a = +input; >+ assert(false); >+ } catch(e) { >+ assert(e instanceof TypeError); >+ } >+} >+ >+assertTypeError(10n); >+assertTypeError(-10n); >+assertTypeError(Object(10n)); >+assertTypeError(Object(-10n)); >+ >+let obj = { >+ [Symbol.toPrimitive]: function() { >+ return 1n; >+ }, >+ valueOf: function() { >+ throw new Error("Should never be called"); >+ }, >+ toString: function() { >+ throw new Error("Should never be called"); >+ } >+}; >+assertTypeError(obj); >+ >+obj = { >+ valueOf: function() { >+ return 1n; >+ }, >+ toString: function() { >+ throw new Error("Should never be called"); >+ } >+}; >+assertTypeError(obj); >+ >+obj = { >+ toString: function() { >+ return 1n; >+ } >+}; >+assertTypeError(obj); >+
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
Flags:
ysuzuki
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 182214
:
332473
|
332485
|
332486
|
333018
|
333056
|
335475
|
337703
|
337718
|
338072
|
338075
|
338579
|
338956
|
339233
|
339241
|
339254
|
339646
|
340157
|
340263
|
340265
|
340270
|
340808
|
340812
|
341279
|
341440