DFG and FTL should support op_call_eval
https://bugs.webkit.org/show_bug.cgi?id=159786
Reviewed by Saam Barati.
Source/JavaScriptCore:
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):
LayoutTests:
* 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):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@203364 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 6686f58..63c754d 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,101 @@
+2016-07-15 Filip Pizlo <fpizlo@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 <fpizlo@apple.com>
DFG should really support jneq_ptr
diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
index 981fb1d0..3a2bb05 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h
@@ -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: {
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index cb0d39d..2df9eb5 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -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;
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 9741315..5a425f0 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -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;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 433a6e7..18b4c32 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -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:
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
index 1a23482..b01b070 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp
@@ -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:
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index dcc62be..4cbbe1f 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -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:
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index 52f7ec4..4af7707 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -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:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index e0122d1..3d8bfb3 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -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:
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index fc238d8..7b89b7a 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -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;
diff --git a/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp b/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
index 4abf5d9..d441862 100644
--- a/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
+++ b/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp
@@ -136,10 +136,6 @@
out.print("TypedArrayByteOffsetLoc");
return;
- case VarInjectionWatchpointLoc:
- out.print("VarInjectionWatchpointLoc");
- return;
-
case StructureLoc:
out.print("StructureLoc");
return;
diff --git a/Source/JavaScriptCore/dfg/DFGHeapLocation.h b/Source/JavaScriptCore/dfg/DFGHeapLocation.h
index 06bc0ae..b0f7a99 100644
--- a/Source/JavaScriptCore/dfg/DFGHeapLocation.h
+++ b/Source/JavaScriptCore/dfg/DFGHeapLocation.h
@@ -57,7 +57,6 @@
SetterLoc,
StructureLoc,
TypedArrayByteOffsetLoc,
- VarInjectionWatchpointLoc,
StackLoc,
StackPayloadLoc
};
diff --git a/Source/JavaScriptCore/dfg/DFGMayExit.cpp b/Source/JavaScriptCore/dfg/DFGMayExit.cpp
index 570b10a..43bdc36 100644
--- a/Source/JavaScriptCore/dfg/DFGMayExit.cpp
+++ b/Source/JavaScriptCore/dfg/DFGMayExit.cpp
@@ -96,6 +96,7 @@
case Call:
case Construct:
case CallVarargs:
+ case CallEval:
case ConstructVarargs:
case CallForwardVarargs:
case ConstructForwardVarargs:
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index f2de2d0..560da4b 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -1423,6 +1423,7 @@
case TailCallInlinedCaller:
case Construct:
case CallVarargs:
+ case CallEval:
case TailCallVarargsInlinedCaller:
case ConstructVarargs:
case CallForwardVarargs:
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index b293898..44668ce 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -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) \
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
index 2beeb69..be768ad 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitCompiler.cpp
@@ -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();
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index a7c8d2a..5576e64 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -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:
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 0ae166f..c8bc603 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -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:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index d4b9dfd..4255b28 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -660,6 +660,7 @@
bool isEmulatedTail = false;
switch (node->op()) {
case Call:
+ case CallEval:
callType = CallLinkInfo::Call;
break;
case TailCall:
@@ -879,6 +880,49 @@
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;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index b585820..b489956 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -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);
- CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo();
+ 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;
diff --git a/Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp b/Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp
index 6c58d81..03c502f 100644
--- a/Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp
@@ -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()));
diff --git a/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp b/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp
index 63649a4..39e296a 100644
--- a/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp
@@ -97,10 +97,6 @@
}
break;
- case VarInjectionWatchpoint:
- addLazily(globalObject()->varInjectionWatchpoint());
- break;
-
default:
break;
}
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index 84757bb..253e38d 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -142,6 +142,7 @@
case TailCallInlinedCaller:
case Construct:
case CallVarargs:
+ case CallEval:
case TailCallVarargs:
case TailCallVarargsInlinedCaller:
case ConstructVarargs:
diff --git a/Source/JavaScriptCore/ftl/FTLCompile.cpp b/Source/JavaScriptCore/ftl/FTLCompile.cpp
index 705c594..5f8ae85 100644
--- a/Source/JavaScriptCore/ftl/FTLCompile.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCompile.cpp
@@ -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) {
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
index 1a233d9..2b8cf51 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
@@ -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 = m_node->loadVarargsData();
diff --git a/Source/JavaScriptCore/jit/AssemblyHelpers.cpp b/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
index f6fef50..5200cf5 100644
--- a/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
+++ b/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
@@ -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)
diff --git a/Source/JavaScriptCore/jit/AssemblyHelpers.h b/Source/JavaScriptCore/jit/AssemblyHelpers.h
index 73aa58d..8fe910d 100644
--- a/Source/JavaScriptCore/jit/AssemblyHelpers.h
+++ b/Source/JavaScriptCore/jit/AssemblyHelpers.h
@@ -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());
-#endif
move(srcRegs.payloadGPR(), destRegs.payloadGPR());
+#else
+ move(srcRegs.gpr(), destRegs.gpr());
+#endif
}
void moveValue(JSValue value, JSValueRegs regs)
@@ -1380,7 +1391,9 @@
functor(TypeofType::Undefined, true);
}
-
+
+ void emitDumbVirtualCall(CallLinkInfo*);
+
Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
void makeSpaceOnStackForCCall();
diff --git a/Source/JavaScriptCore/jit/JITCall.cpp b/Source/JavaScriptCore/jit/JITCall.cpp
index fdb0936..41e51798 100644
--- a/Source/JavaScriptCore/jit/JITCall.cpp
+++ b/Source/JavaScriptCore/jit/JITCall.cpp
@@ -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();
diff --git a/Source/JavaScriptCore/jit/JITCall32_64.cpp b/Source/JavaScriptCore/jit/JITCall32_64.cpp
index f39a723..c7b439c 100644
--- a/Source/JavaScriptCore/jit/JITCall32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITCall32_64.cpp
@@ -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);
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index 01de367..3297e1d 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -772,7 +772,7 @@
UNUSED_PARAM(exec);
execCallee->setCodeBlock(0);
-
+
if (!isHostFunction(execCallee->calleeAsValue(), globalFuncEval))
return JSValue::encode(JSValue());
diff --git a/Source/JavaScriptCore/tests/stress/exit-then-eval.js b/Source/JavaScriptCore/tests/stress/exit-then-eval.js
new file mode 100644
index 0000000..df3dacc
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/exit-then-eval.js
@@ -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;
diff --git a/Source/JavaScriptCore/tests/stress/force-exit-then-eval-dfg.js b/Source/JavaScriptCore/tests/stress/force-exit-then-eval-dfg.js
new file mode 100644
index 0000000..5798086
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/force-exit-then-eval-dfg.js
@@ -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;
+}
+
diff --git a/Source/JavaScriptCore/tests/stress/force-exit-then-eval.js b/Source/JavaScriptCore/tests/stress/force-exit-then-eval.js
new file mode 100644
index 0000000..b3fd93d
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/force-exit-then-eval.js
@@ -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;