WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-182214-20180203011425.patch (text/plain), 45.12 KB, created by
Caio Lima
on 2018-02-02 16:14:27 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2018-02-02 16:14:27 PST
Size:
45.12 KB
patch
obsolete
>Subversion Revision: 228024 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 21522186d431d622cc75ba78ff2e94e7bf6caf0e..7198d93e26da3d729ca56f68c0d1a02a04556562 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,90 @@ >+2018-02-02 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 always is 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 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 >+ >+ * bytecode/SpeculatedType.h: >+ (JSC::isCellOtherSpeculation): >+ * 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/DFGBackwardsPropagationPhase.cpp: >+ (JSC::DFG::BackwardsPropagationPhase::propagate): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::makeSafe): >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGConstantFoldingPhase.cpp: >+ (JSC::DFG::ConstantFoldingPhase::foldConstants): >+ * 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): >+ * 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): >+ * 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): >+ (JSC::JSBigInt::copy): >+ (JSC::JSBigInt::unaryMinus): >+ * runtime/JSBigInt.h: >+ > 2018-02-02 Mark Lam <mark.lam@apple.com> > > More ARM64_32 fixes. >diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h >index 2db85da99fcb5787150d69f9bf3ddc1db98cdf47..4f81ae73f8e2614d13df19b85f21d3cd8030084d 100644 >--- a/Source/JavaScriptCore/bytecode/SpeculatedType.h >+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h >@@ -296,6 +296,11 @@ inline bool isStringObjectSpeculation(SpeculatedType value) > return value == SpecStringObject; > } > >+inline bool isCellOtherSpeculation(SpeculatedType value) >+{ >+ return value == SpecCellOther; >+} >+ > inline bool isStringOrStringObjectSpeculation(SpeculatedType value) > { > return !!value && !(value & ~(SpecString | SpecStringObject)); >diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >index 92b58429a0f478607a5e6035d7552061ef91ff40..ca8b5dc6fa2c9c40ba1aae12127fa0c5ec71fbca 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >@@ -3110,11 +3110,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, 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 14db70685f5fe5935d3f0aba9c6af265010f47bf..f29d5efef522d2ff3f7e1a7edcd103713f742abc 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >@@ -1003,7 +1003,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>; >@@ -1092,7 +1092,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* addTemplateRegistryKeyConstant(Ref<TemplateRegistryKey>&&); > > Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; } >diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >index f8c1b7f2c4f5e6946cfc5dad0b448b7cc5602972..a5f02533963413427c253f4a57d2dc562ecf6217 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 837bec4bc6aecf850f2a689653a1629e53b36cfa..43667cf1ec87b470604f9d7e4872999381bb23ca 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -716,6 +716,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >+ case ValueNegate: { >+ clobberWorld(node->origin.semantic, clobberLimit); >+ forNode(node).setType(m_graph, SpecBytecodeNumber | SpecCellOther); >+ break; >+ } >+ > case ArithNegate: { > JSValue child = forNode(node->child1()).value(); > switch (node->child1().useKind()) { >diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >index 3d2be8cff2cd95e697d47daa91db7c3ee0b6c13e..5113d6296c2acdd5b4b619a726d933e87c26955b 100644 >--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >@@ -302,7 +302,7 @@ private: > node->child2()->mergeFlags(flags); > break; > } >- >+ > case ArithNegate: { > flags &= ~NodeBytecodeUsesAsOther; > >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index fd66009ff33d6fa7cff0c1464b429b4e78bdfed3..2e610bb72c95506f9b6f6292775ff1eeccf58051 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -938,6 +938,7 @@ 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. >@@ -4667,7 +4668,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 b82aa0d71150692189aee33f405224842a00ebd8..c2664f197251b0a88ba17e13423d0f652e3220d8 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -636,6 +636,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > case ToPrimitive: > case In: > case HasOwnProperty: >+ case ValueNegate: > case ValueAdd: > case SetFunctionName: > case GetDynamicVar: >diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >index 7217c9c4c60b7c23820bfd030fa96cce63b16881..879e2fbcaae6294e14e35084847ee996eba60838 100644 >--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >@@ -146,14 +146,14 @@ private: > JSValue child2Constant = m_state.forNode(node->child2().node()).value(); > > // FIXME: Revisit this condition when introducing BigInt to JSC. >- auto isNonStringCellConstant = [] (JSValue value) { >- return value && value.isCell() && !value.isString(); >+ auto isNonStringOrBigIntCellConstant = [] (JSValue value) { >+ return value && value.isCell() && !value.isString() && !value.isBigInt(); > }; > >- if (isNonStringCellConstant(child1Constant)) { >+ if (isNonStringOrBigIntCellConstant(child1Constant)) { > node->convertToCompareEqPtr(m_graph.freezeStrong(child1Constant.asCell()), node->child2()); > changed = true; >- } else if (isNonStringCellConstant(child2Constant)) { >+ } else if (isNonStringOrBigIntCellConstant(child2Constant)) { > node->convertToCompareEqPtr(m_graph.freezeStrong(child2Constant.asCell()), node->child1()); > changed = true; > } >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index 0c496c8d262ea936cdc2f1466e08c1b1899e41c8..5df09ae6261dc4411f13b176931b435ba25ba0ec 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -96,6 +96,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 058b50b37831d07c44db9970e3f047d78834af7b..b1be4d9d90f3b88b0d6ecd4dcc0c8762e7b37bda 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); >diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h >index 75c46476911a0dd59fc51f4cdda14d5a9747699a..d4de166974db43fcbd76932bda8d96585c09be27 100644 >--- a/Source/JavaScriptCore/dfg/DFGNode.h >+++ b/Source/JavaScriptCore/dfg/DFGNode.h >@@ -1087,7 +1087,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 335a493cd9c5eaad81246e6f8d7349276628feb8..7b53174e53ed0ee1388b4cb1c5844da23ce5867f 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -160,6 +160,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 de4428b72d851837c3c049057cd7f1056208bd89..a287f1ea4f3e09eaedfbac2415b3168752601880 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -178,6 +178,26 @@ private: > break; > } > >+ case ValueNegate: { >+ SpeculatedType prediction = node->child1()->prediction(); >+ if (prediction) { >+ if (isInt32OrBooleanSpeculation(prediction) && node->canSpeculateInt32(m_pass)) >+ changed |= mergePrediction(SpecInt32Only); >+ else if (m_graph.unaryArithShouldSpeculateAnyInt(node, m_pass)) >+ changed |= mergePrediction(SpecInt52Only); >+ else if (isBytecodeNumberSpeculation(prediction)) >+ changed |= mergePrediction(speculatedDoubleTypeForPrediction(node->child1()->prediction())); >+ else { >+ changed |= mergePrediction(SpecInt32Only); >+ if (isCellOrOtherSpeculation(prediction)) >+ changed |= mergePrediction(SpecCellOther); >+ if (node->mayHaveDoubleResult()) >+ changed |= mergePrediction(SpecBytecodeDouble); >+ } >+ } >+ break; >+ } >+ > case ValueAdd: { > SpeculatedType left = node->child1()->prediction(); > SpeculatedType right = node->child2()->prediction(); >@@ -1025,6 +1045,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 7a10fbe2e3fcebfebca2910303c02005c166b986..9538e4100ce3254eeaf17956ac286d7c8a664304 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -217,6 +217,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) > 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 4b180390f01178ecf4456244bdabd4d3bb3fa89e..2bf10823fbce6588f46bfbbdced4ff6c6b6eff6f 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -4463,6 +4463,17 @@ void SpeculativeJIT::compileArithSub(Node* node) > } > } > >+void SpeculativeJIT::compileValueNegate(Node* node) >+{ >+ ArithProfile* arithProfile = m_jit.graph().baselineCodeBlockFor(node->origin.semantic)->arithProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex); >+ JITNegIC* negIC = m_jit.codeBlock()->addJITNegIC(arithProfile); >+ auto repatchingFunction = operationArithNegateOptimize; >+ auto nonRepatchingFunction = operationArithNegate; >+ bool needsScratchGPRReg = true; >+ compileMathIC(node, negIC, needsScratchGPRReg, repatchingFunction, nonRepatchingFunction); >+ return; >+} >+ > void SpeculativeJIT::compileArithNegate(Node* node) > { > switch (node->child1().useKind()) { >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >index f2b46cb8ada29398ad7df2c48b7de30327393b80..5e2f5a0489a0364bfa228b698171704bf9bf290a 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -3046,6 +3046,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 cdb015386d4ca0d9d99960cadb83dc40d8babc67..6901341b280a8d3fb89c4ca74656d0d30edc7d7e 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -2321,6 +2321,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 d8b3cd6dbefa5ba1a1ebe3f7d50b5c50e5354ace..859df0be9689ed35ddf9026936c0650063141bef 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2467,6 +2467,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 1aaa20df1aa40c9c59739b6637ac8aeac687cd20..72131ac59087f83e4fab924ad762b0dc617b8480 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -85,6 +85,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 cdabee403f529d1250613aed03c9706094ff0f86..b8f3989b19c18ddbf34c9935f830a592ec7a3c55 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -579,6 +579,9 @@ private: > case ToThis: > compileToThis(); > break; >+ case ValueNegate: >+ compileValueNegate(); >+ break; > case ValueAdd: > compileValueAdd(); > break; >@@ -2674,7 +2677,16 @@ 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); >+ ArithProfile* arithProfile = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic)->arithProfileForBytecodeOffset(m_node->origin.semantic.bytecodeIndex); >+ auto repatchingFunction = operationArithNegateOptimize; >+ auto nonRepatchingFunction = operationArithNegate; >+ compileUnaryMathIC<JITNegGenerator>(arithProfile, repatchingFunction, nonRepatchingFunction); >+ } >+ > void compileArithNegate() > { > switch (m_node->child1().useKind()) { >diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp >index 057c108526ec7b766ea8207aaf30b316c5282852..c32071dfe1811a5bb8051a3d5f74c9db7fc20891 100644 >--- a/Source/JavaScriptCore/jit/JITOperations.cpp >+++ b/Source/JavaScriptCore/jit/JITOperations.cpp >@@ -2584,8 +2584,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(exec, asBigInt(primValue.asCell())))); >+ >+ double number = primValue.toNumber(exec); > return JSValue::encode(jsNumber(-number)); > } > >@@ -2597,9 +2603,18 @@ 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(exec, asBigInt(primValue.asCell()))); >+ arithProfile.observeResult(result); > >+ return JSValue::encode(result); >+ } >+ >+ double number = primValue.toNumber(exec); > JSValue result = jsNumber(-number); > arithProfile.observeResult(result); > return JSValue::encode(result); >@@ -2633,8 +2648,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(exec, asBigInt(primValue.asCell()))); >+ arithProfile->observeResult(result); >+ return JSValue::encode(result); >+ } >+ >+ double number = primValue.toNumber(exec); > JSValue result = jsNumber(-number); > arithProfile->observeResult(result); > return JSValue::encode(result); >@@ -2656,8 +2679,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(exec, asBigInt(primValue.asCell()))); >+ return JSValue::encode(result); >+ } >+ >+ double number = primValue.toNumber(exec); > return JSValue::encode(jsNumber(-number)); > } > >diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h >index 861f0cf706f040b3188537a9afeea11b8be332de..346859c05ada52e37b962e5336b4d047b68c5507 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 0a0797e58e26b9010401be1a0ed5e3d1985a8441..14825f26c4e6d36d92fc34e6a68d59de671a81c5 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 32a60ea546a652281385397d189263041b8e40a1..92ec6da0c7ff588c0d445f2d33fb0f79906f7641 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 0cb7a3a82cf7eed2a70b818e0c7b194dd7aca0b6..1071b7554a8b37c4d9cbecf9f64b0e629ead0153 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -371,26 +371,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) { } >@@ -400,7 +403,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); >+ if (UNLIKELY(throwScope.exception())) >+ RETURN(JSValue()); >+ >+ if (primValue.isBigInt()) { >+ JSValue result = JSValue(JSBigInt::unaryMinus(exec, asBigInt(primValue.asCell()))); >+ RETURN_WITH_PROFILING(result, { >+ updateArithProfileForUnaryArithOp(pc, result, operand); >+ }); >+ } >+ >+ JSValue result = jsNumber(-primValue.toNumber(exec)); > RETURN_WITH_PROFILING(result, { > updateArithProfileForUnaryArithOp(pc, result, operand); > }); >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp >index c51c8b210d93c17f96400efe77daa672a259a6d3..29f941ad031e2d10aaa2a50e93ceea8685067a43 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -216,11 +216,11 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, StringView s) > return parseInt(state, s.characters16(), s.length()); > } > >-JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, StringView s, uint8_t radix) >+JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, StringView s, uint8_t radix, ParseIntSign sign) > { > if (s.is8Bit()) >- return parseInt(state, vm, s.characters8(), s.length(), 0, radix, false); >- return parseInt(state, vm, s.characters16(), s.length(), 0, radix, false); >+ return parseInt(state, vm, s.characters8(), s.length(), 0, radix, sign, DisallowEmptyString); >+ return parseInt(state, vm, s.characters16(), s.length(), 0, radix, sign, DisallowEmptyString); > } > > String JSBigInt::toString(ExecState& state, int radix) >@@ -246,6 +246,28 @@ void JSBigInt::inplaceMultiplyAdd(uintptr_t factor, uintptr_t summand) > internalMultiplyAdd(this, factor, summand, length(), this); > } > >+JSBigInt* JSBigInt::copy(ExecState* state, JSBigInt* x) >+{ >+ ASSERT(!x->isZero()); >+ >+ VM& vm = state->vm(); >+ JSBigInt* result = JSBigInt::createWithLength(vm, x->length()); >+ for (int i = 0; i < x->length(); i++) >+ result->setDigit(i, x->digit(i)); >+ result->setSign(x->sign()); >+ return result; >+} >+ >+JSBigInt* JSBigInt::unaryMinus(ExecState* state, JSBigInt* x) >+{ >+ if (x->isZero()) >+ return x; >+ >+ JSBigInt* result = copy(state, x); >+ result->setSign(!x->sign()); >+ return result; >+} >+ > #if USE(JSVALUE32_64) > #define HAVE_TWO_DIGIT 1 > typedef uint64_t TwoDigit; >@@ -719,7 +741,7 @@ size_t JSBigInt::offsetOfData() > } > > template <typename CharType> >-JSBigInt* JSBigInt::parseInt(ExecState* state, CharType* data, int length) >+JSBigInt* JSBigInt::parseInt(ExecState* state, CharType* data, int length) > { > VM& vm = state->vm(); > >@@ -730,42 +752,37 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, CharType* data, int 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, false); >+ return parseInt(state, vm, data, length, p + 2, 2, Unsigned, DisallowEmptyString); > > if (isASCIIAlphaCaselessEqual(data[p + 1], 'x')) >- return parseInt(state, vm, data, length, p + 2, 16, false); >+ return parseInt(state, vm, data, length, p + 2, 16, Unsigned, DisallowEmptyString); > > if (isASCIIAlphaCaselessEqual(data[p + 1], 'o')) >- return parseInt(state, vm, data, length, p + 2, 8, false); >+ return parseInt(state, vm, data, length, p + 2, 8, Unsigned, DisallowEmptyString); > } > >- bool sign = false; >+ ParseIntSign sign = Unsigned; > if (p < length) { > if (data[p] == '+') > ++p; > else if (data[p] == '-') { >- sign = true; >+ sign = Signed; > ++p; > } > } > >- JSBigInt* result = parseInt(state, vm, data, length, p, 10); >- >- if (result && !result->isZero()) >- result->setSign(sign); >- >- return result; >+ return parseInt(state, vm, data, length, p, 10, sign); > } > > template <typename CharType> >-JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, int length, int startIndex, int radix, bool allowEmptyString) >+JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, int length, int startIndex, int radix, ParseIntSign sign, ParseIntMode parseMode) > { > ASSERT(length >= 0); > int p = startIndex; > > auto scope = DECLARE_THROW_SCOPE(vm); > >- if (!allowEmptyString && startIndex == length) { >+ if (parseMode != ParseIntMode::AllowEmptyString && startIndex == length) { > ASSERT(state); > throwVMError(state, scope, createSyntaxError(state, "Failed to parse String to BigInt")); > return nullptr; >@@ -808,6 +825,7 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, int lengt > 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 d4aa86b5440729af679cc31fee6443d92979362a..e70b5ce1698b004024535fdd3a75c9ad193b5e8a 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -72,7 +72,10 @@ public: > void setLength(int length) { m_length = length; } > int length() const { return m_length; } > >- static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix); >+ enum ParseIntMode { DisallowEmptyString, AllowEmptyString }; >+ enum ParseIntSign { Unsigned, Signed }; >+ >+ static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix, ParseIntSign = Unsigned); > static JSBigInt* parseInt(ExecState*, StringView); > > std::optional<uint8_t> singleDigitValueForString(); >@@ -85,6 +88,8 @@ public: > > JSObject* toObject(ExecState*, JSGlobalObject*) const; > >+ static JSBigInt* unaryMinus(ExecState*, JSBigInt* x); >+ > private: > using Digit = uintptr_t; > static constexpr const int bitsPerByte = 8; >@@ -119,10 +124,12 @@ private: > static JSBigInt* parseInt(ExecState*, CharType* data, int length); > > template <typename CharType> >- static JSBigInt* parseInt(ExecState*, VM&, CharType* data, int length, int startIndex, int radix, bool allowEmptyString = true); >+ static JSBigInt* parseInt(ExecState*, VM&, CharType* data, int length, int startIndex, int radix, ParseIntSign = Signed, ParseIntMode = AllowEmptyString); > > static JSBigInt* allocateFor(ExecState*, VM&, int radix, int charcount); > >+ static JSBigInt* copy(ExecState*, JSBigInt*); >+ > JSBigInt* rightTrim(VM&); > > void inplaceMultiplyAdd(Digit multiplier, Digit part); >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 04a1b21e7ff6194efbd6378dbff9c0539c44389e..7af7601a51c23dcd97d029a50e92e446813a29f8 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,14 @@ >+2018-02-02 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-02-02 Guillaume Emont <guijemont@igalia.com> > > JSTests: Skip mozilla/js1_5/Array/regress-157652.js on all memory limited platforms >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..0053f5fb201ab3fe92dfb588814f5669d838027a >--- /dev/null >+++ b/JSTests/stress/big-int-negate-jit.js >@@ -0,0 +1,31 @@ >+//@ 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); >+ >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
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