Diff
Modified: trunk/LayoutTests/ChangeLog (203363 => 203364)
--- trunk/LayoutTests/ChangeLog 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/LayoutTests/ChangeLog 2016-07-18 19:32:34 UTC (rev 203364)
@@ -1,3 +1,25 @@
+2016-07-15 Filip Pizlo <fpi...@apple.com>
+
+ DFG and FTL should support op_call_eval
+ https://bugs.webkit.org/show_bug.cgi?id=159786
+
+ Reviewed by Saam Barati.
+
+ * js/regress/eval-compute-expected.txt: Added.
+ * js/regress/eval-compute.html: Added.
+ * js/regress/eval-not-eval-compute-args-expected.txt: Added.
+ * js/regress/eval-not-eval-compute-args.html: Added.
+ * js/regress/eval-not-eval-compute-expected.txt: Added.
+ * js/regress/eval-not-eval-compute.html: Added.
+ * js/regress/script-tests/eval-compute.js: Added.
+ (foo):
+ * js/regress/script-tests/eval-not-eval-compute-args.js: Added.
+ (foo):
+ (i.result.foo):
+ * js/regress/script-tests/eval-not-eval-compute.js: Added.
+ (foo):
+ (i.result.foo):
+
2016-07-12 Filip Pizlo <fpi...@apple.com>
DFG should really support jneq_ptr
Added: trunk/LayoutTests/js/regress/eval-compute-expected.txt (0 => 203364)
--- trunk/LayoutTests/js/regress/eval-compute-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/eval-compute-expected.txt 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,10 @@
+JSRegress/eval-compute
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/regress/eval-compute.html (0 => 203364)
--- trunk/LayoutTests/js/regress/eval-compute.html (rev 0)
+++ trunk/LayoutTests/js/regress/eval-compute.html 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/regress/eval-not-eval-compute-args-expected.txt (0 => 203364)
--- trunk/LayoutTests/js/regress/eval-not-eval-compute-args-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/eval-not-eval-compute-args-expected.txt 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,10 @@
+JSRegress/eval-not-eval-compute-args
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/regress/eval-not-eval-compute-args.html (0 => 203364)
--- trunk/LayoutTests/js/regress/eval-not-eval-compute-args.html (rev 0)
+++ trunk/LayoutTests/js/regress/eval-not-eval-compute-args.html 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/regress/eval-not-eval-compute-expected.txt (0 => 203364)
--- trunk/LayoutTests/js/regress/eval-not-eval-compute-expected.txt (rev 0)
+++ trunk/LayoutTests/js/regress/eval-not-eval-compute-expected.txt 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,10 @@
+JSRegress/eval-not-eval-compute
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/regress/eval-not-eval-compute.html (0 => 203364)
--- trunk/LayoutTests/js/regress/eval-not-eval-compute.html (rev 0)
+++ trunk/LayoutTests/js/regress/eval-not-eval-compute.html 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/js/regress/script-tests/eval-compute.js (0 => 203364)
--- trunk/LayoutTests/js/regress/script-tests/eval-compute.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/eval-compute.js 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,16 @@
+function foo(string) {
+ var x = 42;
+ var result = eval(string);
+ for (var i = 0; i < 100000; ++i)
+ result++;
+ return result;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 200; ++i) {
+ var result = foo("x + " + i);
+ if (result != 42 + i + 100000)
+ throw "Error: bad result: " + result;
+}
+
Added: trunk/LayoutTests/js/regress/script-tests/eval-not-eval-compute-args.js (0 => 203364)
--- trunk/LayoutTests/js/regress/script-tests/eval-not-eval-compute-args.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/eval-not-eval-compute-args.js 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,16 @@
+function foo(eval, a, b, c) {
+ var x = 42;
+ var result = eval(a, b, c);
+ for (var i = 0; i < 100000; ++i)
+ result++;
+ return result;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 200; ++i) {
+ var result = foo(function(a, b, c) { return a + b + c; }, 42, i, 0);
+ if (result != 42 + i + 100000)
+ throw "Error: bad result: " + result;
+}
+
Added: trunk/LayoutTests/js/regress/script-tests/eval-not-eval-compute.js (0 => 203364)
--- trunk/LayoutTests/js/regress/script-tests/eval-not-eval-compute.js (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/eval-not-eval-compute.js 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,16 @@
+function foo(eval, string) {
+ var x = 42;
+ var result = eval(string);
+ for (var i = 0; i < 100000; ++i)
+ result++;
+ return result;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 200; ++i) {
+ var result = foo(function() { return 42 + i; }, "x + " + i);
+ if (result != 42 + i + 100000)
+ throw "Error: bad result: " + result;
+}
+
Modified: trunk/Source/_javascript_Core/ChangeLog (203363 => 203364)
--- trunk/Source/_javascript_Core/ChangeLog 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-07-18 19:32:34 UTC (rev 203364)
@@ -1,3 +1,101 @@
+2016-07-15 Filip Pizlo <fpi...@apple.com>
+
+ DFG and FTL should support op_call_eval
+ https://bugs.webkit.org/show_bug.cgi?id=159786
+
+ Reviewed by Saam Barati.
+
+ This adds support for op_call_eval in DFG and FTL by brute force:
+
+ - There is now a CallEval() node type, which compiles exactly the same way that we do in
+ baseline.
+
+ - We teach the DFG and bytecode liveness that the scope register and 'this' are read by
+ CallEval()/op_call_eval.
+
+ We can compile eval quite well, except that right now we cannot inline functions that use
+ eval. It would be nice to do that, but the payoff is probably smaller. "Don't inline users
+ of eval" may even be an OK inlining heuristic. Not inlining users of eval allows me to
+ reuse the baseline implementation, which is really great. Otherwise, I'd have to get rid
+ of things like the rogue reads of scope register and 'this'.
+
+ The goal here is to produce speed-ups for code that has functions that do both eval and
+ some computational stuff. Obviously, we're not producing any benefit for the eval itself.
+ But now the other stuff in a function that uses eval will get to participate in
+ optimization.
+
+ This is a huge speed-up on microbenchmarks.
+
+ * bytecode/BytecodeUseDef.h:
+ (JSC::computeUsesForBytecodeOffset):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::printCallOp):
+ (JSC::CodeBlock::dumpBytecode):
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::setLocal):
+ (JSC::DFG::ByteCodeParser::setArgument):
+ (JSC::DFG::ByteCodeParser::flush):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::needsScopeRegister):
+ (JSC::DFG::Graph::needsFlushedThis):
+ * dfg/DFGHeapLocation.cpp:
+ (WTF::printInternal):
+ * dfg/DFGHeapLocation.h:
+ * dfg/DFGMayExit.cpp:
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasHeapPrediction):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGOSRExitCompiler.cpp:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGStackLayoutPhase.cpp:
+ (JSC::DFG::StackLayoutPhase::run):
+ * dfg/DFGWatchpointCollectionPhase.cpp:
+ (JSC::DFG::WatchpointCollectionPhase::handle):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLCompile.cpp:
+ (JSC::FTL::compile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileCallOrConstructVarargs):
+ (JSC::FTL::DFG::LowerDFGToB3::compileCallEval):
+ (JSC::FTL::DFG::LowerDFGToB3::compileLoadVarargs):
+ * jit/AssemblyHelpers.cpp:
+ (JSC::AssemblyHelpers::restoreCalleeSavesFromVMEntryFrameCalleeSavesBuffer):
+ (JSC::AssemblyHelpers::emitDumbVirtualCall):
+ * jit/AssemblyHelpers.h:
+ (JSC::AssemblyHelpers::emitTypeOf):
+ * jit/JITCall.cpp:
+ (JSC::JIT::compileCallEvalSlowCase):
+ * jit/JITCall32_64.cpp:
+ (JSC::JIT::compileCallEvalSlowCase):
+ * jit/JITOperations.cpp:
+ * tests/stress/exit-then-eval.js: Added.
+ (foo):
+ * tests/stress/force-exit-then-eval-dfg.js: Added.
+ (foo):
+ * tests/stress/force-exit-then-eval.js: Added.
+ (foo):
+
2016-07-12 Filip Pizlo <fpi...@apple.com>
DFG should really support jneq_ptr
Modified: trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h (203363 => 203364)
--- trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h 2016-07-18 19:32:34 UTC (rev 203364)
@@ -282,6 +282,8 @@
int lastArg = registerOffset + CallFrame::thisArgumentOffset();
for (int i = 0; i < argCount; i++)
functor(codeBlock, instruction, opcodeID, lastArg + i);
+ if (opcodeID == op_call_eval)
+ functor(codeBlock, instruction, opcodeID, codeBlock->scopeRegister().offset());
return;
}
case op_save: {
Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -529,7 +529,8 @@
int argCount = (++it)->u.operand;
int registerOffset = (++it)->u.operand;
printLocationAndOp(out, exec, location, it, op);
- out.printf("%s, %s, %d, %d", registerName(dst).data(), registerName(func).data(), argCount, registerOffset);
+ out.print(registerName(dst), ", ", registerName(func), ", ", argCount, ", ", registerOffset);
+ out.print(" (this at ", virtualRegisterForArgument(0, -registerOffset), ")");
if (cacheDumpMode == DumpCaches) {
LLIntCallLinkInfo* callLinkInfo = it[1].u.callLinkInfo;
if (callLinkInfo->lastSeenCallee) {
@@ -609,6 +610,7 @@
static_cast<unsigned long>(instructions().size()),
static_cast<unsigned long>(instructions().size() * sizeof(Instruction)),
m_numParameters, m_numCalleeLocals, m_numVars);
+ out.print("; scope at ", scopeRegister());
out.printf("\n");
StubInfoMap stubInfos;
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-07-18 19:32:34 UTC (rev 203364)
@@ -2801,7 +2801,6 @@
forNode(node).setType(m_graph, SpecObject);
break;
- case VarInjectionWatchpoint:
case PutGlobalVariable:
case NotifyWrite:
break;
@@ -2847,6 +2846,7 @@
case ConstructVarargs:
case ConstructForwardVarargs:
case TailCallForwardVarargsInlinedCaller:
+ case CallEval:
clobberWorld(node->origin.semantic, clobberLimit);
forNode(node).makeHeapTop();
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -455,7 +455,7 @@
ArgumentPosition* argumentPosition = findArgumentPositionForLocal(operand);
if (argumentPosition)
flushDirect(operand, argumentPosition);
- else if (m_hasDebuggerEnabled && operand == m_codeBlock->scopeRegister())
+ else if (m_graph.needsScopeRegister() && operand == m_codeBlock->scopeRegister())
flush(operand);
}
@@ -511,10 +511,12 @@
// Always flush arguments, except for 'this'. If 'this' is created by us,
// then make sure that it's never unboxed.
- if (argument) {
+ if (argument || m_graph.needsFlushedThis()) {
if (setMode != ImmediateNakedSet)
flushDirect(operand);
- } else if (m_codeBlock->specializationKind() == CodeForConstruct)
+ }
+
+ if (!argument && m_codeBlock->specializationKind() == CodeForConstruct)
variableAccessData->mergeShouldNeverUnbox(true);
variableAccessData->mergeStructureCheckHoistingFailed(
@@ -604,7 +606,9 @@
numArguments = inlineStackEntry->m_codeBlock->numParameters();
for (unsigned argument = numArguments; argument-- > 1;)
flushDirect(inlineStackEntry->remapOperand(virtualRegisterForArgument(argument)));
- if (m_hasDebuggerEnabled)
+ if (!inlineStackEntry->m_inlineCallFrame && m_graph.needsFlushedThis())
+ flushDirect(virtualRegisterForArgument(0));
+ if (m_graph.needsScopeRegister())
flush(m_codeBlock->scopeRegister());
}
@@ -4564,6 +4568,15 @@
NEXT_OPCODE(op_construct_varargs);
}
+ case op_call_eval: {
+ int result = currentInstruction[1].u.operand;
+ int callee = currentInstruction[2].u.operand;
+ int argumentCountIncludingThis = currentInstruction[3].u.operand;
+ int registerOffset = -currentInstruction[4].u.operand;
+ addCall(result, CallEval, OpInfo(), get(VirtualRegister(callee)), argumentCountIncludingThis, registerOffset, getPrediction());
+ NEXT_OPCODE(op_call_eval);
+ }
+
case op_jneq_ptr: {
Special::Pointer specialPointer = currentInstruction[2].u.specialPointer;
ASSERT(pointerIsCell(specialPointer));
@@ -4596,7 +4609,7 @@
// get_from_scope and put_to_scope depend on this watchpoint forcing OSR exit, so they don't add their own watchpoints.
if (needsVarInjectionChecks(resolveType))
- addToGraph(VarInjectionWatchpoint);
+ m_graph.watchpoints().addLazily(m_inlineStackTop->m_codeBlock->globalObject()->varInjectionWatchpoint());
switch (resolveType) {
case GlobalProperty:
Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -244,6 +244,7 @@
case op_new_regexp:
case op_switch_string: // Don't inline because we don't want to copy string tables in the concurrent JIT.
+ case op_call_eval:
return CanCompile;
default:
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-07-18 19:32:34 UTC (rev 203364)
@@ -431,11 +431,6 @@
write(HeapObjectCount);
return;
- case VarInjectionWatchpoint:
- read(MiscFields);
- def(HeapLocation(VarInjectionWatchpointLoc, MiscFields), LazyNode(node));
- return;
-
case IsObjectOrNull:
read(MiscFields);
def(HeapLocation(IsObjectOrNullLoc, MiscFields, node->child1()), LazyNode(node));
@@ -484,6 +479,14 @@
write(Heap);
return;
+ case CallEval:
+ ASSERT(!node->origin.semantic.inlineCallFrame);
+ read(AbstractHeap(Stack, graph.m_codeBlock->scopeRegister()));
+ read(AbstractHeap(Stack, virtualRegisterForArgument(0)));
+ read(World);
+ write(Heap);
+ return;
+
case TailCall:
case TailCallVarargs:
case TailCallForwardVarargs:
Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -127,7 +127,6 @@
case GetGlobalVar:
case GetGlobalLexicalVariable:
case PutGlobalVariable:
- case VarInjectionWatchpoint:
case CheckCell:
case CheckNotEmpty:
case CheckIdent:
@@ -144,6 +143,7 @@
case TailCallInlinedCaller:
case Construct:
case CallVarargs:
+ case CallEval:
case TailCallVarargsInlinedCaller:
case ConstructVarargs:
case LoadVarargs:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -1535,12 +1535,12 @@
case GetGlobalVar:
case GetGlobalLexicalVariable:
case NotifyWrite:
- case VarInjectionWatchpoint:
case Call:
case CheckTypeInfoFlags:
case TailCallInlinedCaller:
case Construct:
case CallVarargs:
+ case CallEval:
case TailCallVarargsInlinedCaller:
case ConstructVarargs:
case CallForwardVarargs:
Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGGraph.h 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h 2016-07-18 19:32:34 UTC (rev 203364)
@@ -813,6 +813,9 @@
// because it queries the m_hasExceptionHandlers boolean whose value
// is only fully determined after bytcode parsing.
bool willCatchExceptionInMachineFrame(CodeOrigin, CodeOrigin& opCatchOriginOut, HandlerInfo*& catchHandlerOut);
+
+ bool needsScopeRegister() const { return m_hasDebuggerEnabled || m_codeBlock->usesEval(); }
+ bool needsFlushedThis() const { return m_codeBlock->usesEval(); }
VM& m_vm;
Plan& m_plan;
Modified: trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -136,10 +136,6 @@
out.print("TypedArrayByteOffsetLoc");
return;
- case VarInjectionWatchpointLoc:
- out.print("VarInjectionWatchpointLoc");
- return;
-
case StructureLoc:
out.print("StructureLoc");
return;
Modified: trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h 2016-07-18 19:32:34 UTC (rev 203364)
@@ -57,7 +57,6 @@
SetterLoc,
StructureLoc,
TypedArrayByteOffsetLoc,
- VarInjectionWatchpointLoc,
StackLoc,
StackPayloadLoc
};
Modified: trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -96,6 +96,7 @@
case Call:
case Construct:
case CallVarargs:
+ case CallEval:
case ConstructVarargs:
case CallForwardVarargs:
case ConstructForwardVarargs:
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2016-07-18 19:32:34 UTC (rev 203364)
@@ -1423,6 +1423,7 @@
case TailCallInlinedCaller:
case Construct:
case CallVarargs:
+ case CallEval:
case TailCallVarargsInlinedCaller:
case ConstructVarargs:
case CallForwardVarargs:
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2016-07-18 19:32:34 UTC (rev 203364)
@@ -232,7 +232,6 @@
macro(GetDynamicVar, NodeResultJS | NodeMustGenerate) \
macro(PutDynamicVar, NodeMustGenerate) \
macro(NotifyWrite, NodeMustGenerate) \
- macro(VarInjectionWatchpoint, NodeMustGenerate) \
macro(GetRegExpObjectLastIndex, NodeResultJS) \
macro(SetRegExpObjectLastIndex, NodeMustGenerate) \
macro(RecordRegExpCachedResult, NodeMustGenerate | NodeHasVarArgs) \
@@ -277,6 +276,7 @@
macro(TailCallInlinedCaller, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
macro(TailCallVarargsInlinedCaller, NodeResultJS | NodeMustGenerate) \
macro(TailCallForwardVarargsInlinedCaller, NodeResultJS | NodeMustGenerate) \
+ macro(CallEval, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
\
/* Shadow Chicken */\
macro(LogShadowChickenPrologue, NodeMustGenerate) \
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitCompiler.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2013, 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -153,9 +153,10 @@
// So, we must restore our call frame and stack pointer.
jit.restoreCalleeSavesFromVMEntryFrameCalleeSavesBuffer();
jit.loadPtr(vm->addressOfCallFrameForCatch(), GPRInfo::callFrameRegister);
- jit.addPtr(CCallHelpers::TrustedImm32(codeBlock->stackPointerOffset() * sizeof(Register)),
- GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
}
+ jit.addPtr(
+ CCallHelpers::TrustedImm32(codeBlock->stackPointerOffset() * sizeof(Register)),
+ GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
jit.jitAssertHasValidCallFrame();
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -704,6 +704,7 @@
case TailCallInlinedCaller:
case Construct:
case CallVarargs:
+ case CallEval:
case TailCallVarargsInlinedCaller:
case ConstructVarargs:
case CallForwardVarargs:
@@ -1047,7 +1048,6 @@
case CheckIdent:
case CheckBadCell:
case PutStructure:
- case VarInjectionWatchpoint:
case Phantom:
case Check:
case PutGlobalVariable:
Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2016-07-18 19:32:34 UTC (rev 203364)
@@ -222,7 +222,6 @@
case GetGlobalVar:
case GetGlobalLexicalVariable:
case PutGlobalVariable:
- case VarInjectionWatchpoint:
case CheckCell:
case CheckBadCell:
case CheckNotEmpty:
@@ -240,6 +239,7 @@
case TailCallInlinedCaller:
case Construct:
case CallVarargs:
+ case CallEval:
case TailCallVarargsInlinedCaller:
case TailCallForwardVarargsInlinedCaller:
case ConstructVarargs:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -660,6 +660,7 @@
bool isEmulatedTail = false;
switch (node->op()) {
case Call:
+ case CallEval:
callType = CallLinkInfo::Call;
break;
case TailCall:
@@ -879,7 +880,50 @@
m_jit.emitStoreCallSiteIndex(callSite);
CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo();
+ info->setUpCall(callType, node->origin.semantic, calleePayloadGPR);
+
+ auto setResultAndResetStack = [&] () {
+ m_jit.setupResults(resultPayloadGPR, resultTagGPR);
+ jsValueResult(resultTagGPR, resultPayloadGPR, node, DataFormatJS, UseChildrenCalledExplicitly);
+ // After the calls are done, we need to reestablish our stack
+ // pointer. We rely on this for varargs calls, calls with arity
+ // mismatch (the callframe is slided) and tail calls.
+ m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
+ };
+
+ if (node->op() == CallEval) {
+ // We want to call operationCallEval but we don't want to overwrite the parameter area in
+ // which we have created a prototypical eval call frame. This means that we have to
+ // subtract stack to make room for the call. Lucky for us, at this point we have the whole
+ // register file to ourselves.
+
+ m_jit.addPtr(TrustedImm32(-static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))), JITCompiler::stackPointerRegister, GPRInfo::regT0);
+ m_jit.storePtr(GPRInfo::callFrameRegister, JITCompiler::Address(GPRInfo::regT0, CallFrame::callerFrameOffset()));
+
+ // Now we need to make room for:
+ // - The caller frame and PC of a call to operationCallEval.
+ // - Potentially two arguments on the stack.
+ unsigned requiredBytes = sizeof(CallerFrameAndPC) + sizeof(ExecState*) * 2;
+ requiredBytes = WTF::roundUpToMultipleOf(stackAlignmentBytes(), requiredBytes);
+ m_jit.subPtr(TrustedImm32(requiredBytes), JITCompiler::stackPointerRegister);
+ m_jit.setupArgumentsWithExecState(GPRInfo::regT0);
+ prepareForExternalCall();
+ m_jit.appendCall(operationCallEval);
+ m_jit.exceptionCheck();
+ JITCompiler::Jump done = m_jit.branch32(JITCompiler::NotEqual, GPRInfo::returnValueGPR2, TrustedImm32(JSValue::EmptyValueTag));
+
+ // This is the part where we meant to make a normal call. Oops.
+ m_jit.addPtr(TrustedImm32(requiredBytes), JITCompiler::stackPointerRegister);
+ m_jit.load32(JITCompiler::calleeFrameSlot(CallFrameSlot::callee).withOffset(PayloadOffset), GPRInfo::regT0);
+ m_jit.load32(JITCompiler::calleeFrameSlot(CallFrameSlot::callee).withOffset(TagOffset), GPRInfo::regT1);
+ m_jit.emitDumbVirtualCall(info);
+
+ done.link(&m_jit);
+ setResultAndResetStack();
+ return;
+ }
+
slowPath.append(m_jit.branchIfNotCell(JSValueRegs(calleeTagGPR, calleePayloadGPR)));
slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
@@ -929,17 +973,9 @@
if (isTail)
m_jit.abortWithReason(JITDidReturnFromTailCall);
- else {
- m_jit.setupResults(resultPayloadGPR, resultTagGPR);
+ else
+ setResultAndResetStack();
- jsValueResult(resultTagGPR, resultPayloadGPR, node, DataFormatJS, UseChildrenCalledExplicitly);
- // After the calls are done, we need to reestablish our stack
- // pointer. We rely on this for varargs calls, calls with arity
- // mismatch (the callframe is slided) and tail calls.
- m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
- }
-
- info->setUpCall(callType, node->origin.semantic, calleePayloadGPR);
m_jit.addJSCall(fastCall, slowCall, targetToCheck, info);
}
@@ -4591,11 +4627,6 @@
break;
}
- case VarInjectionWatchpoint: {
- noResult(node);
- break;
- }
-
case CheckTypeInfoFlags: {
compileCheckTypeInfoFlags(node);
break;
@@ -4803,6 +4834,7 @@
case TailCallForwardVarargs:
case TailCallForwardVarargsInlinedCaller:
case ConstructForwardVarargs:
+ case CallEval:
emitCall(node);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -635,6 +635,7 @@
bool isEmulatedTail = false;
switch (node->op()) {
case Call:
+ case CallEval:
callType = CallLinkInfo::Call;
break;
case TailCall:
@@ -838,8 +839,53 @@
CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(dynamicOrigin, m_stream->size());
m_jit.emitStoreCallSiteIndex(callSite);
+ auto setResultAndResetStack = [&] () {
+ GPRFlushedCallResult result(this);
+ GPRReg resultGPR = result.gpr();
+ m_jit.move(GPRInfo::returnValueGPR, resultGPR);
+
+ jsValueResult(resultGPR, m_currentNode, DataFormatJS, UseChildrenCalledExplicitly);
+
+ // After the calls are done, we need to reestablish our stack
+ // pointer. We rely on this for varargs calls, calls with arity
+ // mismatch (the callframe is slided) and tail calls.
+ m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
+ };
+
CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo();
+ callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR);
+ if (node->op() == CallEval) {
+ // We want to call operationCallEval but we don't want to overwrite the parameter area in
+ // which we have created a prototypical eval call frame. This means that we have to
+ // subtract stack to make room for the call. Lucky for us, at this point we have the whole
+ // register file to ourselves.
+
+ m_jit.addPtr(TrustedImm32(-static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))), JITCompiler::stackPointerRegister, GPRInfo::regT0);
+ m_jit.storePtr(GPRInfo::callFrameRegister, JITCompiler::Address(GPRInfo::regT0, CallFrame::callerFrameOffset()));
+
+ // Now we need to make room for:
+ // - The caller frame and PC of a call to operationCallEval.
+ // - Potentially two arguments on the stack.
+ unsigned requiredBytes = sizeof(CallerFrameAndPC) + sizeof(ExecState*) * 2;
+ requiredBytes = WTF::roundUpToMultipleOf(stackAlignmentBytes(), requiredBytes);
+ m_jit.subPtr(TrustedImm32(requiredBytes), JITCompiler::stackPointerRegister);
+ m_jit.setupArgumentsWithExecState(GPRInfo::regT0);
+ prepareForExternalCall();
+ m_jit.appendCall(operationCallEval);
+ m_jit.exceptionCheck();
+ JITCompiler::Jump done = m_jit.branchTest64(JITCompiler::NonZero, GPRInfo::returnValueGPR);
+
+ // This is the part where we meant to make a normal call. Oops.
+ m_jit.addPtr(TrustedImm32(requiredBytes), JITCompiler::stackPointerRegister);
+ m_jit.load64(JITCompiler::calleeFrameSlot(CallFrameSlot::callee), GPRInfo::regT0);
+ m_jit.emitDumbVirtualCall(callLinkInfo);
+
+ done.link(&m_jit);
+ setResultAndResetStack();
+ return;
+ }
+
JITCompiler::DataLabelPtr targetToCheck;
JITCompiler::Jump slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(0));
@@ -877,20 +923,9 @@
if (isTail)
m_jit.abortWithReason(JITDidReturnFromTailCall);
- else {
- GPRFlushedCallResult result(this);
- GPRReg resultGPR = result.gpr();
- m_jit.move(GPRInfo::returnValueGPR, resultGPR);
+ else
+ setResultAndResetStack();
- jsValueResult(resultGPR, m_currentNode, DataFormatJS, UseChildrenCalledExplicitly);
-
- // After the calls are done, we need to reestablish our stack
- // pointer. We rely on this for varargs calls, calls with arity
- // mismatch (the callframe is slided) and tail calls.
- m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
- }
-
- callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR);
m_jit.addJSCall(fastCall, slowCall, targetToCheck, callLinkInfo);
}
@@ -4506,11 +4541,6 @@
break;
}
- case VarInjectionWatchpoint: {
- noResult(node);
- break;
- }
-
case CheckTypeInfoFlags: {
compileCheckTypeInfoFlags(node);
break;
@@ -4721,6 +4751,7 @@
case ConstructForwardVarargs:
case TailCallForwardVarargs:
case TailCallForwardVarargsInlinedCaller:
+ case CallEval:
emitCall(node);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGStackLayoutPhase.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGStackLayoutPhase.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGStackLayoutPhase.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -173,7 +173,7 @@
data->machineLocal = assign(allocation, data->local);
}
- if (LIKELY(!m_graph.hasDebuggerEnabled()))
+ if (!m_graph.needsScopeRegister())
codeBlock()->setScopeRegister(VirtualRegister());
else
codeBlock()->setScopeRegister(assign(allocation, codeBlock()->scopeRegister()));
Modified: trunk/Source/_javascript_Core/dfg/DFGWatchpointCollectionPhase.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/dfg/DFGWatchpointCollectionPhase.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/dfg/DFGWatchpointCollectionPhase.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -97,10 +97,6 @@
}
break;
- case VarInjectionWatchpoint:
- addLazily(globalObject()->varInjectionWatchpoint());
- break;
-
default:
break;
}
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -142,6 +142,7 @@
case TailCallInlinedCaller:
case Construct:
case CallVarargs:
+ case CallEval:
case TailCallVarargs:
case TailCallVarargsInlinedCaller:
case ConstructVarargs:
Modified: trunk/Source/_javascript_Core/ftl/FTLCompile.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/ftl/FTLCompile.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/ftl/FTLCompile.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -105,7 +105,10 @@
}
- if (graph.hasDebuggerEnabled())
+ // Note that the scope register could be invalid here if the original code had CallEval but it
+ // got killed. That's because it takes the CallEval to cause the scope register to be kept alive
+ // unless the debugger is also enabled.
+ if (graph.needsScopeRegister() && codeBlock->scopeRegister().isValid())
codeBlock->setScopeRegister(codeBlock->scopeRegister() + localsOffset);
for (OSRExitDescriptor& descriptor : state.jitCode->osrExitDescriptors) {
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -843,6 +843,9 @@
case ConstructForwardVarargs:
compileCallOrConstructVarargs();
break;
+ case CallEval:
+ compileCallEval();
+ break;
case LoadVarargs:
compileLoadVarargs();
break;
@@ -5543,6 +5546,90 @@
}
}
+ void compileCallEval()
+ {
+ Node* node = m_node;
+ unsigned numArgs = node->numChildren() - 1;
+
+ LValue jsCallee = lowJSValue(m_graph.varArgChild(node, 0));
+
+ unsigned frameSize = CallFrame::headerSizeInRegisters + numArgs;
+ unsigned alignedFrameSize = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), frameSize);
+
+ m_proc.requestCallArgAreaSize(alignedFrameSize);
+
+ Vector<ConstrainedValue> arguments;
+ arguments.append(ConstrainedValue(jsCallee, ValueRep::reg(GPRInfo::regT0)));
+
+ auto addArgument = [&] (LValue value, VirtualRegister reg, int offset) {
+ intptr_t offsetFromSP =
+ (reg.offset() - CallerFrameAndPC::sizeInRegisters) * sizeof(EncodedJSValue) + offset;
+ arguments.append(ConstrainedValue(value, ValueRep::stackArgument(offsetFromSP)));
+ };
+
+ addArgument(jsCallee, VirtualRegister(CallFrameSlot::callee), 0);
+ addArgument(m_out.constInt32(numArgs), VirtualRegister(CallFrameSlot::argumentCount), PayloadOffset);
+ for (unsigned i = 0; i < numArgs; ++i)
+ addArgument(lowJSValue(m_graph.varArgChild(node, 1 + i)), virtualRegisterForArgument(i), 0);
+
+ PatchpointValue* patchpoint = m_out.patchpoint(Int64);
+ patchpoint->appendVector(arguments);
+
+ RefPtr<PatchpointExceptionHandle> exceptionHandle = preparePatchpointForExceptions(patchpoint);
+
+ patchpoint->append(m_tagMask, ValueRep::reg(GPRInfo::tagMaskRegister));
+ patchpoint->append(m_tagTypeNumber, ValueRep::reg(GPRInfo::tagTypeNumberRegister));
+ patchpoint->clobber(RegisterSet::macroScratchRegisters());
+ patchpoint->clobberLate(RegisterSet::volatileRegistersForJSCall());
+ patchpoint->resultConstraint = ValueRep::reg(GPRInfo::returnValueGPR);
+
+ CodeOrigin codeOrigin = codeOriginDescriptionOfCallSite();
+ State* state = &m_ftlState;
+ patchpoint->setGenerator(
+ [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+ AllowMacroScratchRegisterUsage allowScratch(jit);
+ CallSiteIndex callSiteIndex = state->jitCode->common.addUniqueCallSiteIndex(codeOrigin);
+
+ Box<CCallHelpers::JumpList> exceptions = exceptionHandle->scheduleExitCreation(params)->jumps(jit);
+
+ exceptionHandle->scheduleExitCreationForUnwind(params, callSiteIndex);
+
+ jit.store32(
+ CCallHelpers::TrustedImm32(callSiteIndex.bits()),
+ CCallHelpers::tagFor(VirtualRegister(CallFrameSlot::argumentCount)));
+
+ CallLinkInfo* callLinkInfo = jit.codeBlock()->addCallLinkInfo();
+ callLinkInfo->setUpCall(CallLinkInfo::Call, node->origin.semantic, GPRInfo::regT0);
+
+ jit.addPtr(CCallHelpers::TrustedImm32(-static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))), CCallHelpers::stackPointerRegister, GPRInfo::regT1);
+ jit.storePtr(GPRInfo::callFrameRegister, CCallHelpers::Address(GPRInfo::regT1, CallFrame::callerFrameOffset()));
+
+ // Now we need to make room for:
+ // - The caller frame and PC for a call to operationCallEval.
+ // - Potentially two arguments on the stack.
+ unsigned requiredBytes = sizeof(CallerFrameAndPC) + sizeof(ExecState*) * 2;
+ requiredBytes = WTF::roundUpToMultipleOf(stackAlignmentBytes(), requiredBytes);
+ jit.subPtr(CCallHelpers::TrustedImm32(requiredBytes), CCallHelpers::stackPointerRegister);
+ jit.setupArgumentsWithExecState(GPRInfo::regT1);
+ jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(operationCallEval)), GPRInfo::nonPreservedNonArgumentGPR);
+ jit.call(GPRInfo::nonPreservedNonArgumentGPR);
+ exceptions->append(jit.emitExceptionCheck(AssemblyHelpers::NormalExceptionCheck, AssemblyHelpers::FarJumpWidth));
+
+ CCallHelpers::Jump done = jit.branchTest64(CCallHelpers::NonZero, GPRInfo::returnValueGPR);
+
+ jit.addPtr(CCallHelpers::TrustedImm32(requiredBytes), CCallHelpers::stackPointerRegister);
+ jit.load64(CCallHelpers::calleeFrameSlot(CallFrameSlot::callee), GPRInfo::regT0);
+ jit.emitDumbVirtualCall(callLinkInfo);
+
+ done.link(&jit);
+ jit.addPtr(
+ CCallHelpers::TrustedImm32(-params.proc().frameSize()),
+ GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister);
+ });
+
+ setJSValue(patchpoint);
+ }
+
void compileLoadVarargs()
{
LoadVarargsData* data = ""
Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -30,6 +30,7 @@
#include "JITOperations.h"
#include "JSCInlines.h"
+#include "LinkBuffer.h"
namespace JSC {
@@ -613,6 +614,18 @@
#endif
}
+void AssemblyHelpers::emitDumbVirtualCall(CallLinkInfo* info)
+{
+ move(TrustedImmPtr(info), GPRInfo::regT2);
+ Call call = nearCall();
+ addLinkTask(
+ [=] (LinkBuffer& linkBuffer) {
+ MacroAssemblerCodeRef virtualThunk = virtualThunkFor(&linkBuffer.vm(), *info);
+ info->setSlowStub(createJITStubRoutine(virtualThunk, linkBuffer.vm(), nullptr, true));
+ linkBuffer.link(call, CodeLocationLabel(virtualThunk.code()));
+ });
+}
+
} // namespace JSC
#endif // ENABLE(JIT)
Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (203363 => 203364)
--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2016-07-18 19:32:34 UTC (rev 203364)
@@ -165,9 +165,20 @@
void moveValueRegs(JSValueRegs srcRegs, JSValueRegs destRegs)
{
#if USE(JSVALUE32_64)
+ if (destRegs.tagGPR() == srcRegs.payloadGPR()) {
+ if (destRegs.payloadGPR() == srcRegs.tagGPR()) {
+ swap(srcRegs.payloadGPR(), srcRegs.tagGPR());
+ return;
+ }
+ move(srcRegs.payloadGPR(), destRegs.payloadGPR());
+ move(srcRegs.tagGPR(), destRegs.tagGPR());
+ return;
+ }
move(srcRegs.tagGPR(), destRegs.tagGPR());
+ move(srcRegs.payloadGPR(), destRegs.payloadGPR());
+#else
+ move(srcRegs.gpr(), destRegs.gpr());
#endif
- move(srcRegs.payloadGPR(), destRegs.payloadGPR());
}
void moveValue(JSValue value, JSValueRegs regs)
@@ -1380,7 +1391,9 @@
functor(TypeofType::Undefined, true);
}
-
+
+ void emitDumbVirtualCall(CallLinkInfo*);
+
Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
void makeSpaceOnStackForCCall();
Modified: trunk/Source/_javascript_Core/jit/JITCall.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/jit/JITCall.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/jit/JITCall.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2013-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -124,14 +124,7 @@
addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister);
load64(Address(stackPointerRegister, sizeof(Register) * CallFrameSlot::callee - sizeof(CallerFrameAndPC)), regT0);
- move(TrustedImmPtr(info), regT2);
- Call call = emitNakedCall();
- addLinkTask(
- [=] (LinkBuffer& linkBuffer) {
- MacroAssemblerCodeRef virtualThunk = virtualThunkFor(m_vm, *info);
- info->setSlowStub(createJITStubRoutine(virtualThunk, *m_vm, nullptr, true));
- linkBuffer.link(call, CodeLocationLabel(virtualThunk.code()));
- });
+ emitDumbVirtualCall(info);
addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
checkStackPointerAlignment();
Modified: trunk/Source/_javascript_Core/jit/JITCall32_64.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/jit/JITCall32_64.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/jit/JITCall32_64.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -214,8 +214,6 @@
addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister);
- loadPtr(Address(stackPointerRegister, sizeof(Register) * CallFrameSlot::callee - sizeof(CallerFrameAndPC)), regT0);
- loadPtr(Address(stackPointerRegister, sizeof(Register) * CallFrameSlot::callee - sizeof(CallerFrameAndPC)), regT1);
move(TrustedImmPtr(info), regT2);
emitLoad(CallFrameSlot::callee, regT1, regT0);
Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (203363 => 203364)
--- trunk/Source/_javascript_Core/jit/JITOperations.cpp 2016-07-18 19:23:41 UTC (rev 203363)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp 2016-07-18 19:32:34 UTC (rev 203364)
@@ -772,7 +772,7 @@
UNUSED_PARAM(exec);
execCallee->setCodeBlock(0);
-
+
if (!isHostFunction(execCallee->calleeAsValue(), globalFuncEval))
return JSValue::encode(JSValue());
Added: trunk/Source/_javascript_Core/tests/stress/exit-then-eval.js (0 => 203364)
--- trunk/Source/_javascript_Core/tests/stress/exit-then-eval.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/exit-then-eval.js 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,17 @@
+function foo(a, b, string)
+{
+ var x = a + b;
+ return eval(string);
+}
+
+noInline(foo);
+
+for (var i = 0; i < 100000; ++i) {
+ var result = foo(1, 2, "x + 1");
+ if (result != 1 + 2 + 1)
+ throw "Error: bad result in loop: " + result;
+}
+
+var result = foo(2000000000, 2000000000, "x - 1");
+if (result != 2000000000 + 2000000000 - 1)
+ throw "Error: bad result at end: " + result;
Added: trunk/Source/_javascript_Core/tests/stress/force-exit-then-eval-dfg.js (0 => 203364)
--- trunk/Source/_javascript_Core/tests/stress/force-exit-then-eval-dfg.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/force-exit-then-eval-dfg.js 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,14 @@
+function foo(a, b, string)
+{
+ OSRExit();
+ return eval(string);
+}
+
+noInline(foo);
+
+for (var i = 0; i < 100000; ++i) {
+ var result = foo(1, 2, "a + b + 1");
+ if (result != 1 + 2 + 1)
+ throw "Error: bad result in loop: " + result;
+}
+
Added: trunk/Source/_javascript_Core/tests/stress/force-exit-then-eval.js (0 => 203364)
--- trunk/Source/_javascript_Core/tests/stress/force-exit-then-eval.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/force-exit-then-eval.js 2016-07-18 19:32:34 UTC (rev 203364)
@@ -0,0 +1,23 @@
+var flag = true;
+flag = false;
+
+function foo(a, b, string)
+{
+ var x = a + b;
+ if (flag)
+ return eval(string);
+ return 42;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 100000; ++i) {
+ var result = foo(1, 2, "x + 1");
+ if (result != 42)
+ throw "Error: bad result in loop: " + result;
+}
+
+flag = true;
+var result = foo(1, 2, "x - 1");
+if (result != 1 + 2 - 1)
+ throw "Error: bad result at end: " + result;