WebKit Bugzilla
Attachment 359035 Details for
Bug 193240
: [ESNext][BigInt] Add support for op_inc
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP - Patch
bug-193240-20190114122904.patch (text/plain), 63.71 KB, created by
Caio Lima
on 2019-01-14 07:29:07 PST
(
hide
)
Description:
WIP - Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2019-01-14 07:29:07 PST
Size:
63.71 KB
patch
obsolete
>Subversion Revision: 239923 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index df789492e590f3dfa3f17ecf18bd2e2555334e42..14ebc6de8c6c09d7c3f42175b4c76a6893b6302f 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,96 @@ >+2019-01-14 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Add support for op_inc >+ https://bugs.webkit.org/show_bug.cgi?id=193240 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ We are introducing BigInt support for op_inc, including prefix nd >+ postfix operators. To make this happen according to spec, we alto >+ introduced a new OpCode called to_numeric, that is follows the same >+ semantics of "ToNumeric". This operation can result into BigInt or >+ Number and is used by postfix increment semantics. >+ We also added a new DFG node to handle increment on DFG and FTL >+ properly. This node is named ValueInc and we handle only BigIntUse >+ cases and during FixupPhase, when we fixup operand to Int/Number, we >+ then replace such node with ArithAdd(op, 1). >+ >+ * bytecode/BytecodeList.rb: >+ * bytecode/BytecodeUseDef.h: >+ (JSC::computeUsesForBytecodeOffset): >+ (JSC::computeDefsForBytecodeOffset): >+ * bytecode/CodeBlock.cpp: >+ (JSC::CodeBlock::finishCreation): >+ * bytecode/Opcode.h: >+ (JSC::padOpcodeName): >+ * bytecompiler/BytecodeGenerator.cpp: >+ (JSC::BytecodeGenerator::emitToNumeric): >+ * bytecompiler/BytecodeGenerator.h: >+ * bytecompiler/NodesCodegen.cpp: >+ (JSC::emitPostIncOrDec): >+ * 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/DFGCapabilities.cpp: >+ (JSC::DFG::capabilityLevel): >+ * 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): >+ (JSC::DFG::FixupPhase::fixupToNumeric): >+ * dfg/DFGGraph.h: >+ (JSC::DFG::Graph::incSpeculationMode): >+ (JSC::DFG::Graph::shouldSpeculateAnyIntForAdd): >+ (JSC::DFG::Graph::usesAsNumbers): >+ (JSC::DFG::Graph::incShouldSpeculateAnyInt): >+ (JSC::DFG::Graph::addShouldSpeculateAnyInt): >+ * dfg/DFGNode.h: >+ (JSC::DFG::Node::hasHeapPrediction): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileValueInc): >+ * 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::compileValueInc): >+ (JSC::FTL::DFG::LowerDFGToB3::compileToNumeric): >+ * jit/JIT.cpp: >+ (JSC::JIT::privateCompileMainPass): >+ (JSC::JIT::privateCompileSlowCases): >+ * jit/JIT.h: >+ * jit/JITOpcodes.cpp: >+ (JSC::JIT::emit_op_to_numeric): >+ * jit/JITOpcodes32_64.cpp: >+ (JSC::JIT::emit_op_to_numeric): >+ * llint/LowLevelInterpreter.asm: >+ * llint/LowLevelInterpreter32_64.asm: >+ * llint/LowLevelInterpreter64.asm: >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::SLOW_PATH_DECL): >+ * runtime/CommonSlowPaths.h: >+ * runtime/JSBigInt.cpp: >+ (JSC::JSBigInt::increment): >+ * runtime/JSBigInt.h: >+ > 2019-01-12 Timothy Hatcher <timothy@apple.com> > > Have prefers-color-scheme: light always match on macOS versions before Mojave. >diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.rb b/Source/JavaScriptCore/bytecode/BytecodeList.rb >index 3c8b312e69a25cff115dc33e2586e27809566f89..a4591a97eda1036948c17236ad960c629f877590 100644 >--- a/Source/JavaScriptCore/bytecode/BytecodeList.rb >+++ b/Source/JavaScriptCore/bytecode/BytecodeList.rb >@@ -327,6 +327,15 @@ op :to_number, > profile: ValueProfile, > } > >+op :to_numeric, >+ args: { >+ dst: VirtualRegister, >+ operand: VirtualRegister, >+ }, >+ metadata: { >+ profile: ValueProfile, >+ } >+ > op :negate, > args: { > dst: VirtualRegister, >diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h >index bba02b116b166bd9928e35fb6fe41e17cd8c0031..c662b5dd773837484508a9b21db83c5b0cfbea88 100644 >--- a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h >+++ b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h >@@ -175,6 +175,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, const Ins > USES(OpIsObjectOrNull, operand) > USES(OpIsCellWithType, operand) > USES(OpIsFunction, operand) >+ USES(OpToNumeric, operand) > USES(OpToNumber, operand) > USES(OpToString, operand) > USES(OpToObject, operand) >@@ -413,6 +414,7 @@ void computeDefsForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, const Ins > DEFS(OpIsFunction, dst) > DEFS(OpInById, dst) > DEFS(OpInByVal, dst) >+ DEFS(OpToNumeric, dst) > DEFS(OpToNumber, dst) > DEFS(OpToString, dst) > DEFS(OpToObject, dst) >diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp >index 315c46e4e7c4dea3082af59893e957de08bd112d..62e9c71555321b66e817948d10b2e3d233539ec1 100644 >--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp >+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp >@@ -563,6 +563,7 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink > LINK(OpGetByIdDirect, profile) > LINK(OpGetByValWithThis, profile) > LINK(OpGetFromArguments, profile) >+ LINK(OpToNumeric, profile) > LINK(OpToNumber, profile) > LINK(OpToObject, profile) > LINK(OpGetArgument, profile) >diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h >index 1f39b7f9d9c32008edaeeaee64b5297691da28a5..f5b0fbea01a3f3fe9fdfc2ef190730d04135f65e 100644 >--- a/Source/JavaScriptCore/bytecode/Opcode.h >+++ b/Source/JavaScriptCore/bytecode/Opcode.h >@@ -98,6 +98,7 @@ IGNORE_WARNINGS_END > macro(OpGetByIdDirect) \ > macro(OpGetByValWithThis) \ > macro(OpGetFromArguments) \ >+ macro(OpToNumeric) \ > macro(OpToNumber) \ > macro(OpToObject) \ > macro(OpGetArgument) \ >diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >index a13894261d4b8d1df53a92f97f83859eddeaab09..3d7b5a5a08a077c6b3f0a9e81bec88a2773c34a3 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >@@ -1677,6 +1677,11 @@ RegisterID* BytecodeGenerator::emitToObject(RegisterID* dst, RegisterID* src, co > return dst; > } > >+RegisterID* BytecodeGenerator::emitToNumeric(RegisterID* dst, RegisterID* src) >+{ >+ return emitUnaryOp<OpToNumeric>(dst, src); >+} >+ > RegisterID* BytecodeGenerator::emitToNumber(RegisterID* dst, RegisterID* src) > { > return emitUnaryOp<OpToNumber>(dst, src); >diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >index 6ad716eebd28fad7ca02affeb344026eedb94376..b999fb31194363451658a35701a5bb80c3beda3e 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >@@ -736,6 +736,7 @@ namespace JSC { > RegisterID* moveLinkTimeConstant(RegisterID* dst, LinkTimeConstant); > RegisterID* moveEmptyValue(RegisterID* dst); > >+ RegisterID* emitToNumeric(RegisterID* dst, RegisterID* src); > RegisterID* emitToNumber(RegisterID* dst, RegisterID* src); > RegisterID* emitToString(RegisterID* dst, RegisterID* src); > RegisterID* emitToObject(RegisterID* dst, RegisterID* src, const Identifier& message); >diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >index 90b6d49bb9954d2e6b8c75f531b6eeddb958bf9f..31e073f4ca20c6c825c74122184245e8c3b136de 100644 >--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >@@ -1543,8 +1543,8 @@ static RegisterID* emitIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst > static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) > { > if (dst == srcDst) >- return generator.emitToNumber(generator.finalDestination(dst), srcDst); >- RefPtr<RegisterID> tmp = generator.emitToNumber(generator.tempDestination(dst), srcDst); >+ return generator.emitToNumeric(generator.finalDestination(dst), srcDst); >+ RefPtr<RegisterID> tmp = generator.emitToNumeric(generator.tempDestination(dst), srcDst); > emitIncOrDec(generator, srcDst, oper); > return generator.move(dst, tmp.get()); > } >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index 2c55ac3e330630b516b3f5dc26f172436ac3d9b5..81a642b631823fbb57502d35bef8b9e4080e4190 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -610,6 +610,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > forNode(node).fixTypeForRepresentation(m_graph, node); > break; > } >+ >+ case ValueInc: { >+ DFG_ASSERT(m_graph, node, node->child1().useKind() == BigIntUse); >+ setTypeForNode(node, SpecBigInt); >+ break; >+ } > > case ValueSub: > case ValueAdd: { >@@ -2387,6 +2393,20 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >+ case ToNumeric: { >+ JSValue childConst = forNode(node->child1()).value(); >+ if (childConst && childConst.isNumber()) { >+ didFoldClobberWorld(); >+ setConstant(node, childConst); >+ break; >+ } >+ >+ ASSERT(node->child1().useKind() == UntypedUse); >+ clobberWorld(); >+ setTypeForNode(node, SpecBigInt | SpecBytecodeNumber); >+ break; >+ } >+ > case ToNumber: { > JSValue childConst = forNode(node->child1()).value(); > if (childConst && childConst.isNumber()) { >diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >index 05c86ed1eb05f129ed4d00206d31e4e1f25d6159..a4a7ec4ae11333b8d1826419bc85ba537794dac0 100644 >--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >@@ -281,6 +281,19 @@ private: > break; > } > >+ case ValueInc: { >+ if (node->child1()->hasNumericResult() || node->child1()->hasNumberResult()) >+ flags &= ~NodeBytecodeUsesAsOther; >+ if (isNotNegZero(node->child1().node())) >+ flags &= ~NodeBytecodeNeedsNegZero; >+ if (!isWithinPowerOfTwo<32>(node->child1())) >+ flags |= NodeBytecodeUsesAsNumber; >+ if (!m_allowNestedOverflowingAdditions) >+ flags |= NodeBytecodeUsesAsNumber; >+ node->child1()->mergeFlags(flags); >+ break; >+ } >+ > case ArithAdd: { > flags &= ~NodeBytecodeUsesAsOther; > if (isNotNegZero(node->child1().node()) || isNotNegZero(node->child2().node())) >@@ -392,6 +405,7 @@ private: > break; > } > >+ case ToNumeric: > case ToPrimitive: > case ToNumber: { > node->child1()->mergeFlags(flags); >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index cfc583a0826835ec4048cdbd2ac7130907fbffa4..2e3e2fea2a33fa8d180e385dad03065d7db4c9c5 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -991,6 +991,7 @@ private: > case ArithAdd: > case ArithSub: > case ValueAdd: >+ case ValueInc: > case ArithMod: // for ArithMod "MayOverflow" means we tried to divide by zero, or we saw double. > node->mergeFlags(NodeMayOverflowInt32InBaseline); > break; >@@ -5005,7 +5006,10 @@ void ByteCodeParser::parseBlock(unsigned limit) > case op_inc: { > auto bytecode = currentInstruction->as<OpInc>(); > Node* op = get(bytecode.srcDst); >- set(bytecode.srcDst, makeSafe(addToGraph(ArithAdd, op, addToGraph(JSConstant, OpInfo(m_constantOne))))); >+ if (op->hasNumberResult()) >+ set(bytecode.srcDst, makeSafe(addToGraph(ArithAdd, op, addToGraph(JSConstant, OpInfo(m_constantOne))))); >+ else >+ set(bytecode.srcDst, makeSafe(addToGraph(ValueInc, op))); > NEXT_OPCODE(op_inc); > } > >@@ -6745,6 +6749,14 @@ void ByteCodeParser::parseBlock(unsigned limit) > set(bytecode.dst, addToGraph(ToNumber, OpInfo(0), OpInfo(prediction), value)); > NEXT_OPCODE(op_to_number); > } >+ >+ case op_to_numeric: { >+ auto bytecode = currentInstruction->as<OpToNumeric>(); >+ SpeculatedType prediction = getPrediction(); >+ Node* value = get(bytecode.operand); >+ set(bytecode.dst, addToGraph(ToNumeric, OpInfo(0), OpInfo(prediction), value)); >+ NEXT_OPCODE(op_to_numeric); >+ } > > case op_to_string: { > auto bytecode = currentInstruction->as<OpToString>(); >diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp >index 405336384266cfc66ee437ed3c5180c97daa5e00..a3eb45cd98d5598766b550684d64546201fec616 100644 >--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp >+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp >@@ -233,6 +233,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, const I > case op_jneq_ptr: > case op_typeof: > case op_to_number: >+ case op_to_numeric: > case op_to_string: > case op_to_object: > case op_switch_imm: >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index 58ec03035053a8d9e31aff33ccedf46ebc049331..66f737ae4fced9bc951c16d3abe41116bb6cca84 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -658,6 +658,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > case GetDirectPname: > case InstanceOfCustom: > case ToNumber: >+ case ToNumeric: > case NumberToStringWithRadix: > case CreateThis: > case InstanceOf: >@@ -667,6 +668,15 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > write(Heap); > return; > >+ case ValueInc: >+ if (node->child1().useKind() == BigIntUse) { >+ def(PureValue(node)); >+ return; >+ } >+ read(World); >+ write(Heap); >+ return; >+ > case ValueBitAnd: > case ValueBitXor: > case ValueBitOr: >diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >index 23bd7b92b0a180711ca97b8e37503164ef8da932..a310cc07d2248a2d5c6ab1997b15ec4a595299ab 100644 >--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >@@ -785,6 +785,17 @@ private: > break; > } > >+ case ToNumeric: { >+ auto childType = m_state.forNode(node->child1()).m_type; >+ if (((childType & SpecBytecodeNumber) && (childType & ~SpecBytecodeNumber)) >+ || ((childType & SpecBigInt) && (childType & ~SpecBigInt))) >+ break; >+ >+ node->convertToIdentity(); >+ changed = true; >+ break; >+ } >+ > case ToNumber: { > if (m_state.forNode(node->child1()).m_type & ~SpecBytecodeNumber) > break; >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index 4f79af6c4cc5c1d9a9581e712441ad703994cb2d..13addf6cf5de42cc408270de1ba15235895a708f 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -105,6 +105,7 @@ bool doesGC(Graph& graph, Node* node) > case ValueMul: > case ValueNegate: > case ValueDiv: >+ case ValueInc: > case TryGetById: > case GetById: > case GetByIdFlush: >@@ -199,6 +200,7 @@ bool doesGC(Graph& graph, Node* node) > case ToPrimitive: > case ToNumber: > case ToString: >+ case ToNumeric: > case CallStringConstructor: > case NumberToStringWithRadix: > case NumberToStringWithValidRadixConstant: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index e6bac2df2ae6e36df3966be95353bbd1b1b69825..abded1d5cd04b465494ccf1efa423d643fe241f7 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -409,6 +409,30 @@ private: > break; > } > >+ case ValueInc: { >+ if (node->child1()->shouldSpeculateBigInt()) { >+ fixEdge<BigIntUse>(node->child1()); >+ break; >+ } >+ >+ JSValue value = jsNumber(1); >+ node->setOp(ArithAdd); >+ Node* oneConstantNode = m_insertionSet.insertNode( >+ m_indexInBlock, SpecBoolInt32, JSConstant, >+ m_currentNode->origin, OpInfo(m_graph.freeze(value))); >+ node->child2() = Edge(oneConstantNode, UntypedUse); >+ node->setResult(NodeResultNumber); >+ >+ // now we fixup ArithAdd >+ if (attemptToMakeIntegerAdd(node)) >+ break; >+ fixDoubleOrBooleanEdge(node->child1()); >+ fixDoubleOrBooleanEdge(node->child2()); >+ node->setResult(NodeResultDouble); >+ >+ break; >+ } >+ > case ArithAdd: > case ArithSub: { > // FIXME: Clear ArithSub's NodeMustGenerate when ArithMode is unchecked >@@ -1278,6 +1302,11 @@ private: > break; > } > >+ case ToNumeric: { >+ fixupToNumeric(node); >+ break; >+ } >+ > case ToNumber: { > fixupToNumber(node); > break; >@@ -2791,6 +2820,18 @@ private: > fixEdge<UntypedUse>(node->child1()); > node->setResult(NodeResultJS); > } >+ >+ void fixupToNumeric(Node* node) >+ { >+ // If the prediction of the child is BigInt, we attempt to convert ToNumeric to Identity. >+ if (node->child1()->shouldSpeculateBigInt()) { >+ fixEdge<BigIntUse>(node->child1()); >+ node->convertToIdentity(); >+ return; >+ } >+ >+ fixupToNumber(node); >+ } > > void fixupToObject(Node* node) > { >diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h >index 2551f661904a8c41e0997563907215afd4017a0f..d40c1f912942b9173d0d6dec96c959e2b0baabab 100644 >--- a/Source/JavaScriptCore/dfg/DFGGraph.h >+++ b/Source/JavaScriptCore/dfg/DFGGraph.h >@@ -271,6 +271,15 @@ public: > pass); > } > >+ AddSpeculationMode incSpeculationMode(Node* node, PredictionPass pass) >+ { >+ if (!node->child1()->shouldSpeculateInt32OrBooleanForArithmetic()) >+ return DontSpeculateInt32; >+ >+ RareCaseProfilingSource source = node->sourceFor(pass); >+ return node->canSpeculateInt32(source) ? SpeculateInt32 : DontSpeculateInt32; >+ } >+ > AddSpeculationMode addSpeculationMode(Node* add, PredictionPass pass) > { > if (add->op() == ValueAdd) >@@ -284,6 +293,54 @@ public: > return addSpeculationMode(add, pass) != DontSpeculateInt32; > } > >+ bool shouldSpeculateAnyIntForAdd(Node* node) >+ { >+ auto isAnyIntSpeculationForAdd = [](SpeculatedType value) { >+ return !!value && (value & (SpecAnyInt | SpecAnyIntAsDouble)) == value; >+ }; >+ >+ // When DoubleConstant node appears, it means that users explicitly write a constant in their code with double form instead of integer form (1.0 instead of 1). >+ // In that case, we should honor this decision: using it as integer is not appropriate. >+ if (node->op() == DoubleConstant) >+ return false; >+ return isAnyIntSpeculationForAdd(node->prediction()); >+ }; >+ >+ bool usesAsNumbers(Node* node) >+ { >+ NodeFlags flags = node->flags() & NodeBytecodeBackPropMask; >+ if (!flags) >+ return false; >+ return (flags & (NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex)) == flags; >+ }; >+ >+ bool incShouldSpeculateAnyInt(Node* node) >+ { >+ if (!enableInt52()) >+ return false; >+ >+ Node* srcNode = node->child1().node(); >+ >+ if (hasExitSite(node, Int52Overflow)) >+ return false; >+ >+ if (!srcNode->shouldSpeculateAnyInt()) >+ return false; >+ >+ auto usesAsNumbers = [](Node* node) { >+ NodeFlags flags = node->flags() & NodeBytecodeBackPropMask; >+ if (!flags) >+ return false; >+ return (flags & (NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex)) == flags; >+ }; >+ >+ // Wrapping Int52 to Value is also not so cheap. Thus, we allow Int52 addition only when the node is used as number. >+ if (!usesAsNumbers(node)) >+ return false; >+ >+ return shouldSpeculateAnyIntForAdd(srcNode); >+ } >+ > bool addShouldSpeculateAnyInt(Node* add) > { > if (!enableInt52()) >@@ -298,18 +355,6 @@ public: > if (Node::shouldSpeculateAnyInt(left, right)) > return true; > >- auto shouldSpeculateAnyIntForAdd = [](Node* node) { >- auto isAnyIntSpeculationForAdd = [](SpeculatedType value) { >- return !!value && (value & (SpecAnyInt | SpecAnyIntAsDouble)) == value; >- }; >- >- // When DoubleConstant node appears, it means that users explicitly write a constant in their code with double form instead of integer form (1.0 instead of 1). >- // In that case, we should honor this decision: using it as integer is not appropriate. >- if (node->op() == DoubleConstant) >- return false; >- return isAnyIntSpeculationForAdd(node->prediction()); >- }; >- > // Allow AnyInt ArithAdd only when the one side of the binary operation should be speculated AnyInt. It is a bit conservative > // decision. This is because Double to Int52 conversion is not so cheap. Frequent back-and-forth conversions between Double and Int52 > // rather hurt the performance. If the one side of the operation is already Int52, the cost for constructing ArithAdd becomes >@@ -318,13 +363,6 @@ public: > if (!left->shouldSpeculateAnyInt() && !right->shouldSpeculateAnyInt()) > return false; > >- auto usesAsNumbers = [](Node* node) { >- NodeFlags flags = node->flags() & NodeBytecodeBackPropMask; >- if (!flags) >- return false; >- return (flags & (NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex)) == flags; >- }; >- > // Wrapping Int52 to Value is also not so cheap. Thus, we allow Int52 addition only when the node is used as number. > if (!usesAsNumbers(add)) > return false; >diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h >index b8014755c7bcb50914ed39d61a53d94aca86021e..206d49945cf0561341312952825063ad8a4cb9a4 100644 >--- a/Source/JavaScriptCore/dfg/DFGNode.h >+++ b/Source/JavaScriptCore/dfg/DFGNode.h >@@ -1683,6 +1683,7 @@ public: > case GetGlobalLexicalVariable: > case StringReplace: > case StringReplaceRegExp: >+ case ToNumeric: > case ToNumber: > case ToObject: > case CallObjectConstructor: >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index ded0e2680b8e82018c3d4868335b4d03e4ac8fd2..a228570deaab252775d1df772e643a3d41aec7ed 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -169,6 +169,7 @@ namespace JSC { namespace DFG { > \ > /* BigInt is a valid operand for negate operations */\ > macro(ValueNegate, NodeResultJS | NodeMustGenerate) \ >+ macro(ValueInc, NodeResultJS) \ > \ > /* Add of values may either be arithmetic, or result in string concatenation. */\ > macro(ValueAdd, NodeResultJS | NodeMustGenerate) \ >@@ -381,6 +382,7 @@ namespace JSC { namespace DFG { > macro(ToPrimitive, NodeResultJS | NodeMustGenerate) \ > macro(ToString, NodeResultJS | NodeMustGenerate) \ > macro(ToNumber, NodeResultJS | NodeMustGenerate) \ >+ macro(ToNumeric, NodeResultJS | NodeMustGenerate) \ > macro(ToObject, NodeResultJS | NodeMustGenerate) \ > macro(CallObjectConstructor, NodeResultJS) \ > macro(CallStringConstructor, NodeResultJS | NodeMustGenerate) \ >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index dfced10bf264f41040c0d47e3854dcb0dc91c999..dfac8a60607a390a129897518bc34234d75c96c7 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -1409,6 +1409,16 @@ JSCell* JIT_OPERATION operationBitXorBigInt(ExecState* exec, JSCell* op1, JSCell > return JSBigInt::bitwiseXor(exec, leftOperand, rightOperand); > } > >+JSCell* JIT_OPERATION operationIncrementBigInt(ExecState* exec, JSCell* op1) >+{ >+ VM* vm = &exec->vm(); >+ NativeCallFrameTracer tracer(vm, exec); >+ >+ JSBigInt* srcOperand = jsCast<JSBigInt*>(op1); >+ >+ return JSBigInt::increment(exec, srcOperand); >+} >+ > size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, JSCell* op1, JSCell* op2) > { > VM* vm = &exec->vm(); >@@ -1433,6 +1443,18 @@ EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValu > return JSValue::encode(JSValue::decode(value).toPrimitive(exec)); > } > >+EncodedJSValue JIT_OPERATION operationToNumeric(ExecState* exec, EncodedJSValue value) >+{ >+ VM* vm = &exec->vm(); >+ NativeCallFrameTracer tracer(vm, exec); >+ >+ auto resultNumeric = JSValue::decode(value).toNumeric(exec); >+ if (WTF::holds_alternative<JSBigInt*>(resultNumeric)) >+ return JSValue::encode(WTF::get<JSBigInt*>(resultNumeric)); >+ >+ return JSValue::encode(jsNumber(WTF::get<double>(resultNumeric))); >+} >+ > EncodedJSValue JIT_OPERATION operationToNumber(ExecState* exec, EncodedJSValue value) > { > VM* vm = &exec->vm(); >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h >index 8b76f4d6bf37401de2c4a97c1c3205527cc63951..0e7f069fa173ead4f9960bfbfccc2a0f0cdd88da 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.h >+++ b/Source/JavaScriptCore/dfg/DFGOperations.h >@@ -80,6 +80,7 @@ EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState*, JSString*, i > EncodedJSValue JIT_OPERATION operationGetByValObjectString(ExecState*, JSCell*, JSCell* string) WTF_INTERNAL; > EncodedJSValue JIT_OPERATION operationGetByValObjectSymbol(ExecState*, JSCell*, JSCell* symbol) WTF_INTERNAL; > EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL; >+EncodedJSValue JIT_OPERATION operationToNumeric(ExecState*, EncodedJSValue) WTF_INTERNAL; > EncodedJSValue JIT_OPERATION operationToNumber(ExecState*, EncodedJSValue) WTF_INTERNAL; > EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL; > EncodedJSValue JIT_OPERATION operationGetPrototypeOf(ExecState*, EncodedJSValue) WTF_INTERNAL; >@@ -173,6 +174,7 @@ JSCell* JIT_OPERATION operationBitAndBigInt(ExecState*, JSCell* op1, JSCell* op2 > JSCell* JIT_OPERATION operationBitOrBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationAddBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationBitXorBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; >+JSCell* JIT_OPERATION operationIncrementBigInt(ExecState*, JSCell* op1) WTF_INTERNAL; > size_t JIT_OPERATION operationSameValue(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL; > JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState*, Structure*, JSScope*, SymbolTable*, EncodedJSValue); > JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState*, Structure*, uint32_t length, uint32_t minCapacity); >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index a5869b3c24334bd7d135a28e721d2af43cd00acc..8d7199ad06d0373474e8fb8e55f0ae01c5793214 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -210,6 +210,28 @@ private: > break; > } > >+ case ValueInc: { >+ SpeculatedType srcSpeculation = node->child1()->prediction(); >+ if (srcSpeculation) { >+ if (isBigIntSpeculation(srcSpeculation)) >+ changed |= mergePrediction(SpecBigInt); >+ else if (m_graph.incSpeculationMode(node, m_pass) != DontSpeculateInt32) >+ changed |= mergePrediction(SpecInt32Only); >+ else if (m_graph.incShouldSpeculateAnyInt(node)) >+ changed |= mergePrediction(SpecInt52Only); >+ else if (isFullNumberOrBooleanSpeculation(srcSpeculation)) >+ changed |= mergePrediction(speculatedDoubleTypeForPredictions(srcSpeculation, SpecBoolInt32)); >+ else { >+ changed |= mergePrediction(SpecInt32Only); >+ if (srcSpeculation & SpecBytecodeDouble) >+ changed |= mergePrediction(SpecBytecodeDouble); >+ if (srcSpeculation & SpecBigInt) >+ changed |= mergePrediction(SpecBigInt); >+ } >+ } >+ break; >+ } >+ > case ArithAdd: { > SpeculatedType left = node->child1()->prediction(); > SpeculatedType right = node->child2()->prediction(); >@@ -805,6 +827,7 @@ private: > case GetFromArguments: > case LoadKeyFromMapBucket: > case LoadValueFromMapBucket: >+ case ToNumeric: > case ToNumber: > case ToObject: > case CallObjectConstructor: >@@ -1147,6 +1170,7 @@ private: > case AtomicsOr: > case AtomicsStore: > case AtomicsSub: >+ case ValueInc: > case AtomicsXor: { > m_dependentNodes.append(m_currentNode); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index 48444a1409c49a188c5b0b926a27137824548909..9e539644278583d62aa09719308833f104483595 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -236,6 +236,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValueInc: > case TryGetById: > case DeleteById: > case DeleteByVal: >@@ -342,6 +343,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case ToPrimitive: > case ToString: > case ToNumber: >+ case ToNumeric: > case ToObject: > case NumberToStringWithRadix: > case NumberToStringWithValidRadixConstant: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index 61269bc37971b21a11ef69de5365f7f7d99fd6ef..0423d04293a742a110e28108da392f02cac8fdc5 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -4228,6 +4228,23 @@ void SpeculativeJIT::compileToObjectOrCallObjectConstructor(Node* node) > cellResult(resultGPR, node); > } > >+void SpeculativeJIT::compileValueInc(Node* node) >+{ >+ ASSERT(node->child1().useKind() == BigIntUse); >+ SpeculateCellOperand srcOperand(this, node->child1()); >+ GPRReg srcGPR = srcOperand.gpr(); >+ >+ speculateBigInt(node->child1(), srcGPR); >+ >+ flushRegisters(); >+ GPRFlushedCallResult result(this); >+ GPRReg resultGPR = result.gpr(); >+ callOperation(operationIncrementBigInt, resultGPR, srcGPR); >+ m_jit.exceptionCheck(); >+ cellResult(resultGPR, node); >+ >+} >+ > void SpeculativeJIT::compileArithAdd(Node* node) > { > switch (node->binaryUseKind()) { >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >index 28369106eb5fabf0e72d005a56c01fc2d06a5825..d02654ead84333cc1a6b6e68882d06704ff16a3d 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -1345,6 +1345,7 @@ public: > template <typename Generator, typename RepatchingFunction, typename NonRepatchingFunction> > void compileMathIC(Node*, JITUnaryMathIC<Generator>*, bool needsScratchGPRReg, RepatchingFunction, NonRepatchingFunction); > >+ void compileValueInc(Node*); > void compileArithDoubleUnaryOp(Node*, double (*doubleFunction)(double), double (*operation)(ExecState*, EncodedJSValue)); > void compileValueAdd(Node*); > void compileValueSub(Node*); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index c299bccd61322c2ebbe8136447f34d15f6b97545..2e6637418458bf086b75bf572738dd1a08db00f0 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -2026,6 +2026,10 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case ValueInc: >+ compileValueInc(node); >+ break; >+ > case ValueNegate: > compileValueNegate(node); > break; >@@ -3057,6 +3061,54 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case ToNumeric: { >+ JSValueOperand argument(this, node->child1()); >+ GPRTemporary resultTag(this, Reuse, argument, TagWord); >+ GPRTemporary resultPayload(this, Reuse, argument, PayloadWord); >+ >+ GPRReg argumentPayloadGPR = argument.payloadGPR(); >+ GPRReg argumentTagGPR = argument.tagGPR(); >+ JSValueRegs argumentRegs = argument.jsValueRegs(); >+ JSValueRegs resultRegs(resultTag.gpr(), resultPayload.gpr()); >+ >+ argument.use(); >+ >+ if (!(m_state.forNode(node->child1()).m_type & (SpecBytecodeNumber | SpecBigInt))) { >+ flushRegisters(); >+ callOperation(operationToNumeric, resultRegs, argumentRegs); >+ m_jit.exceptionCheck(); >+ } else { >+ MacroAssembler::Jump notNumber; >+ MacroAssembler::JumpList done; >+ MacroAssembler::JumpList slowPath; >+ { >+ GPRTemporary scratch(this); >+ notNumber = m_jit.branchIfNotNumber(argument.jsValueRegs(), scratch.gpr()); >+ } >+ m_jit.move(argumentTagGPR, resultRegs.tagGPR()); >+ m_jit.move(argumentPayloadGPR, resultRegs.payloadGPR()); >+ done.append(m_jit.jump()); >+ >+ notNumber.link(&m_jit); >+ slowPath.append(m_jit.branchIfNotCell(argument.jsValueRegs())); >+ slowPath.append(m_jit.branchIfNotBigInt(argument.jsValueRegs().payloadGPR())); >+ m_jit.move(argumentTagGPR, resultRegs.tagGPR()); >+ m_jit.move(argumentPayloadGPR, resultRegs.payloadGPR()); >+ done.append(m_jit.jump()); >+ >+ slowPath.link(&m_jit); >+ silentSpillAllRegisters(resultRegs); >+ callOperation(operationToNumeric, resultRegs, argumentRegs); >+ silentFillAllRegisters(); >+ m_jit.exceptionCheck(); >+ >+ done.link(&m_jit); >+ } >+ >+ jsValueResult(resultRegs.tagGPR(), resultRegs.payloadGPR(), node, UseChildrenCalledExplicitly); >+ break; >+ } >+ > case ToNumber: { > JSValueOperand argument(this, node->child1()); > GPRTemporary resultTag(this, Reuse, argument, TagWord); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index 32e08c99f465f006c19731bd2bb0a02b4c1488ba..e951d6421c5215ec6eaf910b084efe975bb9a661 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2185,6 +2185,10 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case ValueInc: >+ compileValueInc(node); >+ break; >+ > case ArithAdd: > compileArithAdd(node); > break; >@@ -3307,6 +3311,45 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case ToNumeric: { >+ JSValueOperand argument(this, node->child1()); >+ GPRTemporary result(this, Reuse, argument); >+ >+ GPRReg argumentGPR = argument.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ >+ argument.use(); >+ >+ if (!(m_state.forNode(node->child1()).m_type & (SpecBytecodeNumber | SpecBigInt))) { >+ flushRegisters(); >+ callOperation(operationToNumber, resultGPR, argumentGPR); >+ m_jit.exceptionCheck(); >+ } else { >+ MacroAssembler::JumpList done; >+ MacroAssembler::JumpList slowPath; >+ MacroAssembler::Jump notNumber = m_jit.branchIfNotNumber(argumentGPR); >+ m_jit.move(argumentGPR, resultGPR); >+ done.append(m_jit.jump()); >+ >+ notNumber.link(&m_jit); >+ slowPath.append(m_jit.branchIfNotCell(argumentGPR)); >+ slowPath.append(m_jit.branchIfNotBigInt(argumentGPR)); >+ m_jit.move(argumentGPR, resultGPR); >+ done.append(m_jit.jump()); >+ >+ slowPath.link(&m_jit); >+ silentSpillAllRegisters(resultGPR); >+ callOperation(operationToNumeric, resultGPR, argumentGPR); >+ silentFillAllRegisters(); >+ m_jit.exceptionCheck(); >+ >+ done.link(&m_jit); >+ } >+ >+ jsValueResult(resultGPR, node, UseChildrenCalledExplicitly); >+ break; >+ } >+ > case ToNumber: { > JSValueOperand argument(this, node->child1()); > GPRTemporary result(this, Reuse, argument); >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index 7db5b56d326ddad666ec69cfa4d8d186d224ff4a..5ba27d7bbe0dc4370f6ea839141b6999d9e37817 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -96,6 +96,7 @@ inline CapabilityLevel canCompile(Node* node) > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValueInc: > case StrCat: > case ArithAdd: > case ArithClz32: >@@ -195,6 +196,7 @@ inline CapabilityLevel canCompile(Node* node) > case SetCallee: > case GetArgumentCountIncludingThis: > case SetArgumentCountIncludingThis: >+ case ToNumeric: > case ToNumber: > case ToString: > case ToObject: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index 73836a8aad901e4324a7eea8e40e1ad9368d5137..f30627d1ca9ae3c9244be66a3063be03ede6bbc7 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -603,6 +603,9 @@ private: > case StrCat: > compileStrCat(); > break; >+ case ValueInc: >+ compileValueInc(); >+ break; > case ArithAdd: > case ArithSub: > compileArithAddOrSub(); >@@ -914,6 +917,9 @@ private: > case NukeStructureAndSetButterfly: > compileNukeStructureAndSetButterfly(); > break; >+ case ToNumeric: >+ compileToNumeric(); >+ break; > case ToNumber: > compileToNumber(); > break; >@@ -2141,6 +2147,15 @@ private: > setJSValue(result); > } > >+ void compileValueInc() >+ { >+ ASSERT(m_node->child1().useKind() == BigIntUse); >+ LValue srcOp = lowBigInt(m_node->child1()); >+ >+ LValue result = vmCall(pointerType(), m_out.operation(operationIncrementBigInt), m_callFrame, srcOp); >+ setJSValue(result); >+ } >+ > void compileArithAddOrSub() > { > bool isSub = m_node->op() == ArithSub; >@@ -6292,6 +6307,38 @@ private: > nukeStructureAndSetButterfly(lowStorage(m_node->child2()), lowCell(m_node->child1())); > } > >+ void compileToNumeric() >+ { >+ LValue value = lowJSValue(m_node->child1()); >+ >+ if (!(abstractValue(m_node->child1()).m_type & (SpecBytecodeNumber | SpecBigInt))) >+ setJSValue(vmCall(Int64, m_out.operation(operationToNumeric), m_callFrame, value)); >+ else { >+ LBasicBlock notNumber = m_out.newBlock(); >+ LBasicBlock isCell = m_out.newBlock(); >+ LBasicBlock notBigInt = m_out.newBlock(); >+ LBasicBlock continuation = m_out.newBlock(); >+ >+ ValueFromBlock fastResult = m_out.anchor(value); >+ m_out.branch(isNumber(value, provenType(m_node->child1())), unsure(continuation), unsure(notNumber)); >+ >+ // notNumber case. >+ LBasicBlock lastNext = m_out.appendTo(notNumber, isCell); >+ m_out.branch(this->isCell(value, provenType(m_node->child1())), unsure(isCell), unsure(notBigInt)); >+ >+ m_out.appendTo(isCell, notBigInt); >+ m_out.branch(isBigInt(value, provenType(m_node->child1())), unsure(continuation), unsure(notBigInt)); >+ >+ m_out.appendTo(notBigInt, continuation); >+ ValueFromBlock slowResult = m_out.anchor(vmCall(Int64, m_out.operation(operationToNumeric), m_callFrame, value)); >+ m_out.jump(continuation); >+ >+ // continuation case. >+ m_out.appendTo(continuation, lastNext); >+ setJSValue(m_out.phi(Int64, fastResult, slowResult)); >+ } >+ } >+ > void compileToNumber() > { > LValue value = lowJSValue(m_node->child1()); >diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp >index 5d6e07773dcbef5272d57151115a3d4dcfd168a2..e6b007f8c873ddfe6a217559bc7b52bd7a167f30 100644 >--- a/Source/JavaScriptCore/jit/JIT.cpp >+++ b/Source/JavaScriptCore/jit/JIT.cpp >@@ -431,6 +431,7 @@ void JIT::privateCompileMainPass() > DEFINE_OP(op_switch_imm) > DEFINE_OP(op_switch_string) > DEFINE_OP(op_throw) >+ DEFINE_OP(op_to_numeric) > DEFINE_OP(op_to_number) > DEFINE_OP(op_to_string) > DEFINE_OP(op_to_object) >@@ -574,6 +575,7 @@ void JIT::privateCompileSlowCases() > DEFINE_SLOWCASE_SLOW_OP(create_this) > DEFINE_SLOWCASE_SLOW_OP(to_this) > DEFINE_SLOWCASE_SLOW_OP(to_primitive) >+ DEFINE_SLOWCASE_SLOW_OP(to_numeric) > DEFINE_SLOWCASE_SLOW_OP(to_number) > DEFINE_SLOWCASE_SLOW_OP(to_string) > DEFINE_SLOWCASE_SLOW_OP(to_object) >diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h >index 6c9d3bb41b0931a99fd7ba6b6b0f2cfc354004a0..15f6743a9fd140f4318c6a0dd5d80eaf5d63d1d4 100644 >--- a/Source/JavaScriptCore/jit/JIT.h >+++ b/Source/JavaScriptCore/jit/JIT.h >@@ -620,6 +620,7 @@ namespace JSC { > void emit_op_switch_string(const Instruction*); > void emit_op_tear_off_arguments(const Instruction*); > void emit_op_throw(const Instruction*); >+ void emit_op_to_numeric(const Instruction*); > void emit_op_to_number(const Instruction*); > void emit_op_to_string(const Instruction*); > void emit_op_to_object(const Instruction*); >diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp >index 6ec0749ac2246bd052d72084a7e5e5d16972128b..951692c678fdfc920c0c216508b6c17dcd00ee52 100644 >--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp >+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp >@@ -622,6 +622,22 @@ void JIT::emitSlow_op_jnstricteq(const Instruction* currentInstruction, Vector<S > emitJumpSlowToHot(branchTest32(Zero, returnValueGPR), target); > } > >+void JIT::emit_op_to_numeric(const Instruction* currentInstruction) >+{ >+ auto bytecode = currentInstruction->as<OpToNumeric>(); >+ int dstVReg = bytecode.dst.offset(); >+ int srcVReg = bytecode.operand.offset(); >+ emitGetVirtualRegister(srcVReg, regT0); >+ >+ addSlowCase(branchIfNotNumber(regT0)); >+ addSlowCase(branchIfNotCell(regT0)); >+ addSlowCase(branchIfNotBigInt(regT0)); >+ >+ emitValueProfilingSite(bytecode.metadata(m_codeBlock)); >+ if (srcVReg != dstVReg) >+ emitPutVirtualRegister(dstVReg); >+} >+ > void JIT::emit_op_to_number(const Instruction* currentInstruction) > { > auto bytecode = currentInstruction->as<OpToNumber>(); >diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp >index acdc007b06b7d44be3a394923f9b7bbb17acdccd..f96cabd1823e46984e9f91485b05ccb303e8af55 100644 >--- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp >+++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp >@@ -797,6 +797,30 @@ void JIT::emit_op_throw(const Instruction* currentInstruction) > jumpToExceptionHandler(*vm()); > } > >+void JIT::emit_op_to_numeric(const Instruction* currentInstruction) >+{ >+ auto bytecode = currentInstruction->as<OpToNumeric>(); >+ int dst = bytecode.dst.offset(); >+ int src = bytecode.operand.offset(); >+ >+ emitLoad(src, regT1, regT0); >+ >+ JumpList isNumber; >+ isNumber.append(branchIfInt32(regT1)); >+ Jump isNotNumber = branch32(AboveOrEqual, regT1, TrustedImm32(JSValue::LowestTag)); >+ isNumber.append(jump()); >+ >+ isNotNumber.link(this); >+ addSlowCase(branchIfNotCell(regT1)); >+ addSlowCase(branchIfNotBigInt(regT0)); >+ >+ isNumber.link(this); >+ >+ emitValueProfilingSite(bytecode.metadata(m_codeBlock)); >+ if (src != dst) >+ emitStore(dst, regT1, regT0); >+} >+ > void JIT::emit_op_to_number(const Instruction* currentInstruction) > { > auto bytecode = currentInstruction->as<OpToNumber>(); >diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm >index ec2a32e833d626e788f42ea029a6fb6670160841..c4bcf3ec45f8eb145681a7b66d76f9b8acb2ee06 100644 >--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm >+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm >@@ -451,6 +451,7 @@ const CopyOnWrite = constexpr CopyOnWrite > const StringType = constexpr StringType > const SymbolType = constexpr SymbolType > const ObjectType = constexpr ObjectType >+const BigIntType = constexpr BigIntType > const FinalObjectType = constexpr FinalObjectType > const JSFunctionType = constexpr JSFunctionType > const ArrayType = constexpr ArrayType >diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm >index a505a557aa6dc4b6ed7b034a67d34b60956d8c6f..d4e35ae4eaf5dba3b7eebdd496c2ea2dd4af5aca 100644 >--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm >+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm >@@ -948,6 +948,24 @@ macro preOp(name, op, operation) > end > > >+llintOpWithProfile(op_to_numeric, OpToNumeric, macro (size, get, dispatch, return) >+ get(operand, t0) >+ loadConstantOrVariable(size, t0, t2, t3) >+ bieq t2, Int32Tag, .opToNumericIsInt >+ biaeq t2, LowestTag, .isNotNumber >+.opToNumericIsInt: >+ return(t2, t3) >+ >+.isNotNumber: >+ bineq t2, CellTag, .opToNumericSlow >+ bbneq JSCell::m_type[t3], BigIntType, .opToNumericSlow >+ return(t2, t3) >+ >+.opToNumericSlow: >+ callSlowPath(_slow_path_to_numeric) >+ dispatch() >+end) >+ > llintOpWithProfile(op_to_number, OpToNumber, macro (size, get, dispatch, return) > get(operand, t0) > loadConstantOrVariable(size, t0, t2, t3) >diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >index 412b5c60185a2366c05c6b3d271a322fa73ffca9..d28385953a07db536f9aecb7435a4cd655e6d63a 100644 >--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >@@ -885,6 +885,24 @@ macro preOp(name, op, arithmeticOperation) > end) > end > >+llintOpWithProfile(op_to_numeric, OpToNumeric, macro (size, get, dispatch, return) >+ get(operand, t0) >+ loadConstantOrVariable(size, t0, t2) >+ bqaeq t2, tagTypeNumber, .opToNumericIsImmediate >+ btqz t2, tagTypeNumber, .isNotNumber >+.opToNumericIsImmediate: >+ return(t2) >+ >+.isNotNumber: >+ btqnz t0, tagMask, .opToNumericSlow >+ bbneq JSCell::m_type[t0], BigIntType, .opToNumericSlow >+ return(t0) >+ >+.opToNumericSlow: >+ callSlowPath(_slow_path_to_numeric) >+ dispatch() >+end) >+ > llintOpWithProfile(op_to_number, OpToNumber, macro (size, get, dispatch, return) > get(operand, t0) > loadConstantOrVariable(size, t0, t2) >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >index 3118b315a8cb8c5df2218d823381886cef582819..ae561f46e03e32f9aa81fe8017542546e0f3bbd3 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -377,7 +377,14 @@ SLOW_PATH_DECL(slow_path_inc) > { > BEGIN(); > auto bytecode = pc->as<OpInc>(); >- RETURN_WITH_PROFILING_CUSTOM(bytecode.srcDst, jsNumber(GET(bytecode.srcDst).jsValue().toNumber(exec) + 1), { }); >+ auto srcNumeric = GET(bytecode.srcDst).jsValue().toNumeric(exec); >+ if (WTF::holds_alternative<JSBigInt*>(srcNumeric)) { >+ JSBigInt* result = JSBigInt::increment(exec, WTF::get<JSBigInt*>(srcNumeric)); >+ CHECK_EXCEPTION(); >+ RETURN_WITH_PROFILING_CUSTOM(bytecode.srcDst, JSValue(result), { }); >+ } >+ >+ RETURN_WITH_PROFILING_CUSTOM(bytecode.srcDst, jsNumber(WTF::get<double>(srcNumeric) + 1), { }); > } > > SLOW_PATH_DECL(slow_path_dec) >@@ -487,6 +494,17 @@ static void updateArithProfileForBinaryArithOp(ExecState* exec, const Instructio > static void updateArithProfileForBinaryArithOp(ExecState*, const Instruction*, JSValue, JSValue, JSValue) { } > #endif > >+SLOW_PATH_DECL(slow_path_to_numeric) >+{ >+ BEGIN(); >+ auto bytecode = pc->as<OpToNumeric>(); >+ JSValue argument = GET_C(bytecode.operand).jsValue(); >+ auto numericResult = argument.toNumeric(exec); >+ if (WTF::holds_alternative<JSBigInt*>(numericResult)) >+ RETURN_PROFILED(JSValue(WTF::get<JSBigInt*>(numericResult))); >+ RETURN_PROFILED(jsNumber(WTF::get<double>(numericResult))); >+} >+ > SLOW_PATH_DECL(slow_path_to_number) > { > BEGIN(); >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h >index 68ef05b3efd0d58e021e3d386b807ac41663733d..a5a8a2908c515196a00cf51bdd19f92a16a06e1d 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h >@@ -315,6 +315,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_greater); > SLOW_PATH_HIDDEN_DECL(slow_path_greatereq); > SLOW_PATH_HIDDEN_DECL(slow_path_inc); > SLOW_PATH_HIDDEN_DECL(slow_path_dec); >+SLOW_PATH_HIDDEN_DECL(slow_path_to_numeric); > SLOW_PATH_HIDDEN_DECL(slow_path_to_number); > SLOW_PATH_HIDDEN_DECL(slow_path_to_string); > SLOW_PATH_HIDDEN_DECL(slow_path_to_object); >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp >index ca531636b781e869ea78f76d25b5e4aead416185..2666e1725724f4086cc0c74040ca2c21c39215d4 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -352,6 +352,24 @@ JSBigInt* JSBigInt::remainder(ExecState* exec, JSBigInt* x, JSBigInt* y) > return remainder->rightTrim(vm); > } > >+JSBigInt* JSBigInt::increment(ExecState* exec, JSBigInt* x) >+{ >+ VM& vm = exec->vm(); >+ if (x->sign()) { >+ if (x->length() == 1 && x->digit(0) == 1) >+ return JSBigInt::createZero(vm); >+ >+ JSBigInt* result = absoluteSubOne(exec, x, x->length()); >+ if (!result) >+ return nullptr; >+ >+ result->setSign(true); >+ return result; >+ } >+ >+ return absoluteAddOne(exec, x, SignOption::Unsigned); >+} >+ > JSBigInt* JSBigInt::add(ExecState* exec, JSBigInt* x, JSBigInt* y) > { > VM& vm = exec->vm(); >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.h b/Source/JavaScriptCore/runtime/JSBigInt.h >index 2b3bf9307d8dbbb1107533ed830347bcdd4a610b..e2053d0cf890f24925aed67f72fd17bd195c11a8 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -114,6 +114,8 @@ public: > > ComparisonResult static compareToDouble(JSBigInt* x, double y); > >+ static JSBigInt* increment(ExecState*, JSBigInt* x); >+ > static JSBigInt* add(ExecState*, JSBigInt* x, JSBigInt* y); > static JSBigInt* sub(ExecState*, JSBigInt* x, JSBigInt* y); > static JSBigInt* divide(ExecState*, JSBigInt* x, JSBigInt* y); >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index a915dfe21c0791fda1190e0cc6d8d00048b1205e..3e6bbebb59ffe14f34f4e18f478466774e4a3703 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,19 @@ >+2019-01-14 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Add support for op_inc >+ https://bugs.webkit.org/show_bug.cgi?id=193240 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * stress/big-int-increment-jit-osr.js: Added. >+ * stress/big-int-increment-jit.js: Added. >+ * stress/big-int-increment-wrapped-value.js: Added. >+ * stress/big-int-postfix-increment-basic.js: Added. >+ * stress/big-int-prefix-increment-basic.js: Added. >+ * stress/inc-int52-overflow.js: Added. >+ * stress/to-numeric-observable-operand.js: Added. >+ * stress/value-inc-number-and-big-int-observation.js: Added. >+ > 2019-01-11 Saam barati <sbarati@apple.com> > > DFG combined liveness can be wrong for terminal basic blocks >diff --git a/JSTests/stress/big-int-increment-jit-osr.js b/JSTests/stress/big-int-increment-jit-osr.js >new file mode 100644 >index 0000000000000000000000000000000000000000..554f0017e01b48ec770959ac357b66549d5f2ed8 >--- /dev/null >+++ b/JSTests/stress/big-int-increment-jit-osr.js >@@ -0,0 +1,25 @@ >+//@ runBigIntEnabled >+ >+let assert = { >+ sameValue: function(i, e, m) { >+ if (i !== e) >+ throw new Error(m); >+ } >+} >+ >+function bigIntInc(x) { >+ return x++; >+} >+noInline(bigIntInc); >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntInc(3012n); >+ assert.sameValue(r, 3012n, 3012n + "++ = " + r); >+} >+ >+let r = bigIntInc(3); >+assert.sameValue(r, 3, 3 + "++ = " + r); >+ >+r = bigIntInc("3"); >+assert.sameValue(r, 3, 3 + "++ = " + r); >+ >diff --git a/JSTests/stress/big-int-increment-jit.js b/JSTests/stress/big-int-increment-jit.js >new file mode 100644 >index 0000000000000000000000000000000000000000..e4a9a7e10df23ccd132607f4743c289978333792 >--- /dev/null >+++ b/JSTests/stress/big-int-increment-jit.js >@@ -0,0 +1,19 @@ >+//@ runBigIntEnabled >+ >+let assert = { >+ sameValue: function(i, e, m) { >+ if (i !== e) >+ throw new Error(m); >+ } >+} >+ >+function bigIntInc(x) { >+ return x++; >+} >+noInline(bigIntInc); >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntInc(3n); >+ assert.sameValue(r, 3n, 3n + "++ = " + r); >+} >+ >diff --git a/JSTests/stress/big-int-increment-wrapped-value.js b/JSTests/stress/big-int-increment-wrapped-value.js >new file mode 100644 >index 0000000000000000000000000000000000000000..ca48131451ba212460b3ac06ee9865f18b4216a4 >--- /dev/null >+++ b/JSTests/stress/big-int-increment-wrapped-value.js >@@ -0,0 +1,36 @@ >+//@ runBigIntEnabled >+ >+assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+function testInc(x, z, message) { >+ assert.sameValue(++x, z, message); >+} >+ >+testInc(Object(2n), 3n, "ToPrimitive: unbox object with internal slot"); >+ >+let o = { >+ [Symbol.toPrimitive]: function() { >+ return 2n; >+ } >+}; >+testInc(o, 3n, "ToPrimitive: @@toPrimitive"); >+ >+o = { >+ valueOf: function() { >+ return 2n; >+ } >+}; >+testInc(o, 3n, "ToPrimitive: valueOf"); >+ >+o = { >+ toString: function() { >+ return 2n; >+ } >+} >+testInc(o, 3n, "ToPrimitive: toString"); >+ >diff --git a/JSTests/stress/big-int-postfix-increment-basic.js b/JSTests/stress/big-int-postfix-increment-basic.js >new file mode 100644 >index 0000000000000000000000000000000000000000..ec8db5e3dc76bf74d04d5f6bab7641025a85b94f >--- /dev/null >+++ b/JSTests/stress/big-int-postfix-increment-basic.js >@@ -0,0 +1,60 @@ >+//@ runBigIntEnabled >+ >+// Copyright (C) 2017 Josh Wolfe. All rights reserved. >+// This code is governed by the BSD license. >+ >+var assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+var x = 0n; >+assert.sameValue(x++, 0n, "var x = 0n; x++ === 0n"); >+assert.sameValue(x, 1n, "var x = 0n; x++; x === 1n"); >+ >+var x = -1n; >+assert.sameValue(x++, -1n, "var x = -1n; x++ === -1n"); >+assert.sameValue(x, 0n, "var x = -1n; x++; x === 0n"); >+ >+var x = 123456n; >+assert.sameValue(x++, 123456n, "var x = 123456n; x++ === 123456n"); >+assert.sameValue(x, 123457n, "var x = 123456n; x++; x === 123457n"); >+ >+var x = -123457n; >+assert.sameValue(x++, -123457n, "var x = -123457n; x++ === -123457n"); >+assert.sameValue(x, -123456n, "var x = -123457n; x++; x === -123456n"); >+ >+var x = 0x1fffffffffffff00n; >+assert.sameValue(x++, 0x1fffffffffffff00n, "var x = 0x1fffffffffffff00n; x++ === 0x1fffffffffffff00n"); >+assert.sameValue(x, 0x1fffffffffffff01n, "var x = 0x1fffffffffffff00n; x++; x === 0x1fffffffffffff01n"); >+ >+var x = -0x1fffffffffffff01n; >+assert.sameValue(x++, -0x1fffffffffffff01n, "var x = -0x1fffffffffffff01n; x++ === -0x1fffffffffffff01n"); >+assert.sameValue(x, -0x1fffffffffffff00n, "var x = -0x1fffffffffffff01n; x++; x === -0x1fffffffffffff00n"); >+ >+var x = {y:0n}; >+assert.sameValue(x.y++, 0n, "var x = {y:0n}; x.y++ === 0n"); >+assert.sameValue(x.y, 1n, "var x = {y:0n}; x.y++; x.y === 1n"); >+ >+var x = {y:{z:0n}}; >+assert.sameValue(x.y.z++, 0n, "var x = {y:{z:0n}}; x.y.z++ === 0n"); >+assert.sameValue(x.y.z, 1n, "var x = {y:{z:0n}}; x.y.z++; x.y.z === 1n"); >+ >+var x = [0n]; >+assert.sameValue(x[0]++, 0n, "var x = [0n]; x[0]++ === 0n"); >+assert.sameValue(x[0], 1n, "var x = [0n]; x[0]++; x[0] === 1n"); >+ >+var x = [null, [null, null, 0n]]; >+assert.sameValue(x[1][2]++, 0n, "var x = [null, [null, null, 0n]]; x[1][2]++ === 0n"); >+assert.sameValue(x[1][2], 1n, "var x = [null, [null, null, 0n]]; x[1][2]++; x[1][2] === 1n"); >+ >+var x = {y:[0n]}; >+assert.sameValue(x.y[0]++, 0n, "var x = {y:[0n]}; x.y[0]++ === 0n"); >+assert.sameValue(x.y[0], 1n, "var x = {y:[0n]}; x.y[0]++; x.y[0] === 1n"); >+ >+var x = [{z:0n}]; >+assert.sameValue(x[0].z++, 0n, "var x = [{z:0n}]; x[0].z++ === 0n"); >+assert.sameValue(x[0].z, 1n, "var x = [{z:0n}]; x[0].z++; x[0].z === 1n"); >+ >diff --git a/JSTests/stress/big-int-prefix-increment-basic.js b/JSTests/stress/big-int-prefix-increment-basic.js >new file mode 100644 >index 0000000000000000000000000000000000000000..5bb5fa13801e08719404899c0e79cc7e72ab7503 >--- /dev/null >+++ b/JSTests/stress/big-int-prefix-increment-basic.js >@@ -0,0 +1,60 @@ >+//@ runBigIntEnabled >+ >+// Copyright (C) 2017 Josh Wolfe. All rights reserved. >+// This code is governed by the BSD license. >+ >+var assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+var x = 0n; >+assert.sameValue(++x, 1n, "var x = 0n; ++x === 1n"); >+assert.sameValue(x, 1n, "var x = 0n; ++x; x === 1n"); >+ >+var x = -1n; >+assert.sameValue(++x, 0n, "var x = -1n; ++x === 0n"); >+assert.sameValue(x, 0n, "var x = -1n; ++x; x === 0n"); >+ >+var x = 123456n; >+assert.sameValue(++x, 123457n, "var x = 123456n; ++x === 123457n"); >+assert.sameValue(x, 123457n, "var x = 123456n; ++x; x === 123457n"); >+ >+var x = -123457n; >+assert.sameValue(++x, -123456n, "var x = -123457n; ++x === -123456n"); >+assert.sameValue(x, -123456n, "var x = -123457n; ++x; x === -123456n"); >+ >+var x = 0x1fffffffffffff00n; >+assert.sameValue(++x, 0x1fffffffffffff01n, "var x = 0x1fffffffffffff00n; ++x === 0x1fffffffffffff01n"); >+assert.sameValue(x, 0x1fffffffffffff01n, "var x = 0x1fffffffffffff00n; ++x; x === 0x1fffffffffffff01n"); >+ >+var x = -0x1fffffffffffff01n; >+assert.sameValue(++x, -0x1fffffffffffff00n, "var x = -0x1fffffffffffff01n; ++x === -0x1fffffffffffff00n"); >+assert.sameValue(x, -0x1fffffffffffff00n, "var x = -0x1fffffffffffff01n; ++x; x === -0x1fffffffffffff00n"); >+ >+var x = {y:0n}; >+assert.sameValue(++x.y, 1n, "var x = {y:0n}; ++x.y === 1n"); >+assert.sameValue(x.y, 1n, "var x = {y:0n}; ++x.y; x.y === 1n"); >+ >+var x = {y:{z:0n}}; >+assert.sameValue(++x.y.z, 1n, "var x = {y:{z:0n}}; ++x.y.z === 1n"); >+assert.sameValue(x.y.z, 1n, "var x = {y:{z:0n}}; ++x.y.z; x.y.z === 1n"); >+ >+var x = [0n]; >+assert.sameValue(++x[0], 1n, "var x = [0n]; ++x[0] === 1n"); >+assert.sameValue(x[0], 1n, "var x = [0n]; ++x[0]; x[0] === 1n"); >+ >+var x = [null, [null, null, 0n]]; >+assert.sameValue(++x[1][2], 1n, "var x = [null, [null, null, 0n]]; ++x[1][2] === 1n"); >+assert.sameValue(x[1][2], 1n, "var x = [null, [null, null, 0n]]; ++x[1][2]; x[1][2] === 1n"); >+ >+var x = {y:[0n]}; >+assert.sameValue(++x.y[0], 1n, "var x = {y:[0n]}; ++x.y[0] === 1n"); >+assert.sameValue(x.y[0], 1n, "var x = {y:[0n]}; ++x.y[0]; x.y[0] === 1n"); >+ >+var x = [{z:0n}]; >+assert.sameValue(++x[0].z, 1n, "var x = [{z:0n}]; ++x[0].z === 1n"); >+assert.sameValue(x[0].z, 1n, "var x = [{z:0n}]; ++x[0].z; x[0].z === 1n"); >+ >diff --git a/JSTests/stress/inc-int52-overflow.js b/JSTests/stress/inc-int52-overflow.js >new file mode 100644 >index 0000000000000000000000000000000000000000..e5ea96a19e7c7828cc4ea2dece868e2fb62ec24d >--- /dev/null >+++ b/JSTests/stress/inc-int52-overflow.js >@@ -0,0 +1,26 @@ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Expected: " + e + " but got: " + a); >+} >+ >+function inc(a) { >+ var y = a; >+ var z = y * 2; >+ if (z) { >+ z += y; >+ z += y; >+ z += y; >+ z += 1; >+ } >+ return z++; >+} >+noInline(inc); >+ >+for (var i = 0; i < 100000; i++) >+ inc(1000000000); >+ >+inc(375299968947541); >+ >+for (var i = 0; i < 100000; i++) >+ inc(1000000000); >+ >diff --git a/JSTests/stress/to-numeric-observable-operand.js b/JSTests/stress/to-numeric-observable-operand.js >new file mode 100644 >index 0000000000000000000000000000000000000000..e18f1a5ab331de0b81ce5c8acec1d7df2f754047 >--- /dev/null >+++ b/JSTests/stress/to-numeric-observable-operand.js >@@ -0,0 +1,23 @@ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Expected: " + e + " but got: " + a); >+} >+ >+function inc(a) { >+ return a++; >+} >+noInline(inc); >+ >+var c = 0; >+ >+var o = { >+ valueOf: () => { >+ c++; >+ return 3; >+ } >+}; >+for (var i = 0; i < 100000; i++) >+ inc(o); >+ >+assert(c, 200000); >+ >diff --git a/JSTests/stress/value-inc-number-and-big-int-observation.js b/JSTests/stress/value-inc-number-and-big-int-observation.js >new file mode 100644 >index 0000000000000000000000000000000000000000..7cef714c3c0eff955da96189423de0413f4110e5 >--- /dev/null >+++ b/JSTests/stress/value-inc-number-and-big-int-observation.js >@@ -0,0 +1,23 @@ >+//@ runBigIntEnabled >+ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Expected: " + e + " but got: " + a); >+} >+ >+function inc(a) { >+ return a++; >+} >+noInline(inc); >+ >+for (var i = 0; i < 100000; i++) >+ assert(inc(41), 41); >+ >+assert(inc(41n), 41n); >+ >+for (var i = 0; i < 100000; i++) { >+ assert(inc(11), 11); >+ assert(inc(0xfffffffffffffffffffff00000000000000000n), 0xfffffffffffffffffffff00000000000000000n); >+} >+ >+
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 193240
:
358966
|
358968
|
359025
|
359035
|
382769
|
383081
|
383101
|
383164
|
383165
|
383526
|
383645
|
383768
|
383813
|
383818
|
383913
|
383914
|
383934