Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (91224 => 91225)
--- trunk/Source/_javascript_Core/ChangeLog 2011-07-19 00:25:49 UTC (rev 91224)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-07-19 00:26:14 UTC (rev 91225)
@@ -1,5 +1,36 @@
2011-07-18 Gavin Barraclough <[email protected]>
+ https://bugs.webkit.org/show_bug.cgi?id=64760
+ DFG JIT - Should be able to compile program code.
+
+ Reviewed by Geoff Garen.
+
+ Add support for op_end, hooks to compile program code in Executable.cpp.
+
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ - Add support for op_end
+ * dfg/DFGJITCompiler.cpp:
+ (JSC::DFG::JITCompiler::compileEntry):
+ (JSC::DFG::JITCompiler::compileBody):
+ (JSC::DFG::JITCompiler::link):
+ - Added, separate out steps of compileFunction.
+ (JSC::DFG::JITCompiler::compile):
+ - Added, compile program code.
+ (JSC::DFG::JITCompiler::compileFunction):
+ - Sections separated out to helper functions.
+ * dfg/DFGJITCompiler.h:
+ (JSC::DFG::JITCompiler::JITCompiler):
+ - Added m_exceptionCheckCount.
+ * runtime/Executable.cpp:
+ (JSC::tryDFGCompile):
+ (JSC::tryDFGCompileFunction):
+ (JSC::ProgramExecutable::compileInternal):
+ (JSC::FunctionExecutable::compileForCallInternal):
+ - Renamed tryDFGCompile to tryDFGCompileFunction, added tryDFGCompile to compile program code.
+
+2011-07-18 Gavin Barraclough <[email protected]>
+
https://bugs.webkit.org/show_bug.cgi?id=64678
Fix bugs in Object.prototype this handling.
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (91224 => 91225)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2011-07-19 00:25:49 UTC (rev 91224)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2011-07-19 00:26:14 UTC (rev 91225)
@@ -1112,11 +1112,14 @@
LAST_OPCODE(op_loop_if_greatereq);
}
- case op_ret: {
+ case op_ret:
addToGraph(Return, get(currentInstruction[1].u.operand));
LAST_OPCODE(op_ret);
- }
+ case op_end:
+ addToGraph(Return, get(currentInstruction[1].u.operand));
+ LAST_OPCODE(op_end);
+
case op_call: {
NodeIndex call = addCall(interpreter, currentInstruction, Call);
aliases.recordCall(call);
Modified: trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp (91224 => 91225)
--- trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp 2011-07-19 00:25:49 UTC (rev 91224)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp 2011-07-19 00:26:14 UTC (rev 91225)
@@ -223,38 +223,21 @@
ASSERT(!(entriesIter != entriesEnd));
}
-void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck)
+void JITCompiler::compileEntry()
{
- // === Stage 1 - Function header code generation ===
- //
// This code currently matches the old JIT. In the function header we need to
// pop the return address (since we do not allow any recursion on the machine
// stack), and perform a fast register file check.
-
- // This is the main entry point, without performing an arity check.
// FIXME: https://bugs.webkit.org/show_bug.cgi?id=56292
// We'll need to convert the remaining cti_ style calls (specifically the register file
// check) which will be dependent on stack layout. (We'd need to account for this in
// both normal return code and when jumping to an exception handler).
preserveReturnAddressAfterCall(GPRInfo::regT2);
emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC);
- // If we needed to perform an arity check we will already have moved the return address,
- // so enter after this.
- Label fromArityCheck(this);
+}
- // Setup a pointer to the codeblock in the CallFrameHeader.
- emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock);
-
- // Plant a check that sufficient space is available in the RegisterFile.
- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291
- addPtr(Imm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);
- Jump registerFileCheck = branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), GPRInfo::regT1);
- // Return here after register file check.
- Label fromRegisterFileCheck = label();
-
-
- // === Stage 2 - Function body code generation ===
- //
+void JITCompiler::compileBody()
+{
// We generate the speculative code path, followed by the non-speculative
// code for the function. Next we need to link the two together, making
// bail-outs from the speculative path jump to the corresponding point on
@@ -304,24 +287,17 @@
nonSpeculative.compile(checkIterator);
}
- // === Stage 3 - Function footer code generation ===
- //
- // Generate code to lookup and jump to exception handlers, to perform the slow
- // register file check (if the fast one in the function header fails), and
- // generate the entry point with arity check.
-
// Iterate over the m_calls vector, checking for exception checks,
// and linking them to here.
- unsigned exceptionCheckCount = 0;
for (unsigned i = 0; i < m_calls.size(); ++i) {
Jump& exceptionCheck = m_calls[i].m_exceptionCheck;
if (exceptionCheck.isSet()) {
exceptionCheck.link(this);
- ++exceptionCheckCount;
+ ++m_exceptionCheckCount;
}
}
// If any exception checks were linked, generate code to lookup a handler.
- if (exceptionCheckCount) {
+ if (m_exceptionCheckCount) {
// lookupExceptionHandler is passed two arguments, exec (the CallFrame*), and
// an identifier for the operation that threw the exception, which we can use
// to look up handler information. The identifier we use is the return address
@@ -334,38 +310,11 @@
// and the address of the handler in returnValueGPR2.
jump(GPRInfo::returnValueGPR2);
}
+}
- // Generate the register file check; if the fast check in the function head fails,
- // we need to call out to a helper function to check whether more space is available.
- // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions).
- registerFileCheck.link(this);
- move(stackPointerRegister, GPRInfo::argumentGPR0);
- poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
- Call callRegisterFileCheck = call();
- jump(fromRegisterFileCheck);
-
- // The fast entry point into a function does not check the correct number of arguments
- // have been passed to the call (we only use the fast entry point where we can statically
- // determine the correct number of arguments have been passed, or have already checked).
- // In cases where an arity check is necessary, we enter here.
- // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions).
- Label arityCheck = label();
- preserveReturnAddressAfterCall(GPRInfo::regT2);
- emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC);
- branch32(Equal, GPRInfo::regT1, Imm32(m_codeBlock->m_numParameters)).linkTo(fromArityCheck, this);
- move(stackPointerRegister, GPRInfo::argumentGPR0);
- poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
- Call callArityCheck = call();
- move(GPRInfo::regT0, GPRInfo::callFrameRegister);
- jump(fromArityCheck);
-
-
- // === Stage 4 - Link ===
- //
+void JITCompiler::link(LinkBuffer& linkBuffer)
+{
// Link the code, populate data in CodeBlock data structures.
-
- LinkBuffer linkBuffer(*m_globalData, this, m_globalData->executableAllocator);
-
#if DFG_DEBUG_VERBOSE
fprintf(stderr, "JIT code start at %p\n", linkBuffer.debugAddress());
#endif
@@ -377,7 +326,7 @@
}
if (m_codeBlock->needsCallReturnIndices()) {
- m_codeBlock->callReturnIndexVector().reserveCapacity(exceptionCheckCount);
+ m_codeBlock->callReturnIndexVector().reserveCapacity(m_exceptionCheckCount);
for (unsigned i = 0; i < m_calls.size(); ++i) {
if (m_calls[i].m_handlesExceptions) {
unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_calls[i].m_call);
@@ -419,7 +368,76 @@
info.cachedPrototype.setLocation(linkBuffer.locationOf(m_methodGets[i].m_protoObj));
info.callReturnLocation = linkBuffer.locationOf(m_methodGets[i].m_slowCall);
}
+}
+
+void JITCompiler::compile(JITCode& entry)
+{
+ // Preserve the return address to the callframe.
+ compileEntry();
+ // Generate the body of the program.
+ compileBody();
+ // Link
+ LinkBuffer linkBuffer(*m_globalData, this, m_globalData->executableAllocator);
+ link(linkBuffer);
+ entry = JITCode(linkBuffer.finalizeCode(), JITCode::DFGJIT);
+}
+
+void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck)
+{
+ compileEntry();
+
+ // === Function header code generation ===
+ // This is the main entry point, without performing an arity check.
+ // If we needed to perform an arity check we will already have moved the return address,
+ // so enter after this.
+ Label fromArityCheck(this);
+ // Setup a pointer to the codeblock in the CallFrameHeader.
+ emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock);
+ // Plant a check that sufficient space is available in the RegisterFile.
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291
+ addPtr(Imm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1);
+ Jump registerFileCheck = branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), GPRInfo::regT1);
+ // Return here after register file check.
+ Label fromRegisterFileCheck = label();
+
+
+ // === Function body code generation ===
+ compileBody();
+
+ // === Function footer code generation ===
+ //
+ // Generate code to perform the slow register file check (if the fast one in
+ // the function header fails), and generate the entry point with arity check.
+ //
+ // Generate the register file check; if the fast check in the function head fails,
+ // we need to call out to a helper function to check whether more space is available.
+ // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions).
+ registerFileCheck.link(this);
+ move(stackPointerRegister, GPRInfo::argumentGPR0);
+ poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+ Call callRegisterFileCheck = call();
+ jump(fromRegisterFileCheck);
+ // The fast entry point into a function does not check the correct number of arguments
+ // have been passed to the call (we only use the fast entry point where we can statically
+ // determine the correct number of arguments have been passed, or have already checked).
+ // In cases where an arity check is necessary, we enter here.
+ // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions).
+ Label arityCheck = label();
+ preserveReturnAddressAfterCall(GPRInfo::regT2);
+ emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC);
+ branch32(Equal, GPRInfo::regT1, Imm32(m_codeBlock->m_numParameters)).linkTo(fromArityCheck, this);
+ move(stackPointerRegister, GPRInfo::argumentGPR0);
+ poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
+ Call callArityCheck = call();
+ move(GPRInfo::regT0, GPRInfo::callFrameRegister);
+ jump(fromArityCheck);
+
+
+ // === Link ===
+ LinkBuffer linkBuffer(*m_globalData, this, m_globalData->executableAllocator);
+ link(linkBuffer);
+
// FIXME: switch the register file check & arity check over to DFGOpertaion style calls, not JIT stubs.
linkBuffer.link(callRegisterFileCheck, cti_register_file_check);
linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck);
Modified: trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h (91224 => 91225)
--- trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h 2011-07-19 00:25:49 UTC (rev 91224)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h 2011-07-19 00:26:14 UTC (rev 91225)
@@ -110,9 +110,11 @@
: m_globalData(globalData)
, m_graph(dfg)
, m_codeBlock(codeBlock)
+ , m_exceptionCheckCount(0)
{
}
+ void compile(JITCode& entry);
void compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck);
// Accessors for properties.
@@ -279,6 +281,11 @@
}
private:
+ // Internal implementation to compile.
+ void compileEntry();
+ void compileBody();
+ void link(LinkBuffer&);
+
// These methods used in linking the speculative & non-speculative paths together.
void fillNumericToDouble(NodeIndex, FPRReg, GPRReg temporary);
void fillInt32ToInteger(NodeIndex, GPRReg);
@@ -296,7 +303,9 @@
CodeBlock* m_codeBlock;
// Vector of calls out from JIT code, including exception handler information.
+ // Count of the number of CallRecords with exception handlers.
Vector<CallRecord> m_calls;
+ unsigned m_exceptionCheckCount;
struct PropertyAccessRecord {
PropertyAccessRecord(Call functionCall, int8_t deltaCheckImmToCall, int8_t deltaCallToStructCheck, int8_t deltaCallToLoadOrStore, int8_t deltaCallToSlowCase, int8_t deltaCallToDone, int8_t baseGPR, int8_t valueGPR, int8_t scratchGPR)
Modified: trunk/Source/_javascript_Core/runtime/Executable.cpp (91224 => 91225)
--- trunk/Source/_javascript_Core/runtime/Executable.cpp 2011-07-19 00:25:49 UTC (rev 91224)
+++ trunk/Source/_javascript_Core/runtime/Executable.cpp 2011-07-19 00:26:14 UTC (rev 91225)
@@ -43,6 +43,51 @@
const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0 };
#if ENABLE(JIT)
+#if ENABLE(DFG_JIT)
+static bool tryDFGCompile(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode)
+{
+#if ENABLE(DFG_JIT_RESTRICTIONS)
+ // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets.
+ if (codeBlock->numberOfJumpTargets())
+ return false;
+#endif
+
+ JSGlobalData* globalData = &exec->globalData();
+ DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars);
+ if (!parse(dfg, globalData, codeBlock))
+ return false;
+
+ dfg.predictArgumentTypes(exec);
+
+ DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock);
+ dataFlowJIT.compile(jitCode);
+ return true;
+}
+
+static bool tryDFGCompileFunction(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck)
+{
+#if ENABLE(DFG_JIT_RESTRICTIONS)
+ // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets.
+ if (codeBlock->numberOfJumpTargets())
+ return false;
+#endif
+
+ JSGlobalData* globalData = &exec->globalData();
+ DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars);
+ if (!parse(dfg, globalData, codeBlock))
+ return false;
+
+ dfg.predictArgumentTypes(exec);
+
+ DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock);
+ dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck);
+ return true;
+}
+#else
+static bool tryDFGCompile(ExecState*, CodeBlock*, JITCode&) { return false; }
+static bool tryDFGCompileFunction(ExecState*, CodeBlock*, JITCode&, MacroAssemblerCodePtr&) { return false; }
+#endif
+
class ExecutableFinalizer : public WeakHandleOwner {
virtual void finalize(Handle<Unknown> handle, void*)
{
@@ -226,7 +271,9 @@
#if ENABLE(JIT)
if (exec->globalData().canUseJIT()) {
- m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get());
+ bool dfgCompiled = tryDFGCompile(exec, m_programCodeBlock.get(), m_jitCodeForCall);
+ if (!dfgCompiled)
+ m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get());
#if !ENABLE(OPCODE_SAMPLING)
if (!BytecodeGenerator::dumpsGeneratedCode())
m_programCodeBlock->discardBytecode();
@@ -258,36 +305,6 @@
#endif
}
-#if ENABLE(JIT)
-static bool tryDFGCompile(ExecState* exec, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck)
-{
- JSGlobalData* globalData = &exec->globalData();
-#if ENABLE(DFG_JIT)
-#if ENABLE(DFG_JIT_RESTRICTIONS)
- // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets.
- if (codeBlock->numberOfJumpTargets())
- return false;
-#endif
-
- DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars);
- if (!parse(dfg, globalData, codeBlock))
- return false;
-
- dfg.predictArgumentTypes(exec);
-
- DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock);
- dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck);
- return true;
-#else
- UNUSED_PARAM(globalData);
- UNUSED_PARAM(codeBlock);
- UNUSED_PARAM(jitCode);
- UNUSED_PARAM(jitCodeWithArityCheck);
- return false;
-#endif
-}
-#endif
-
void ProgramExecutable::visitChildren(SlotVisitor& visitor)
{
ASSERT_GC_OBJECT_INHERITS(this, &s_info);
@@ -332,7 +349,7 @@
#if ENABLE(JIT)
if (exec->globalData().canUseJIT()) {
- bool dfgCompiled = tryDFGCompile(exec, m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck);
+ bool dfgCompiled = tryDFGCompileFunction(exec, m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck);
if (!dfgCompiled)
m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck);