diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/ftl/FTLLink.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/ftl/FTLLink.cpp')
-rw-r--r-- | Source/JavaScriptCore/ftl/FTLLink.cpp | 209 |
1 files changed, 97 insertions, 112 deletions
diff --git a/Source/JavaScriptCore/ftl/FTLLink.cpp b/Source/JavaScriptCore/ftl/FTLLink.cpp index 5b2bb67c7..85050d151 100644 --- a/Source/JavaScriptCore/ftl/FTLLink.cpp +++ b/Source/JavaScriptCore/ftl/FTLLink.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,145 +29,129 @@ #if ENABLE(FTL_JIT) #include "CCallHelpers.h" +#include "CallFrameInlines.h" #include "CodeBlockWithJITType.h" #include "DFGCommon.h" #include "FTLJITCode.h" #include "JITOperations.h" +#include "JITStubs.h" +#include "LLVMAPI.h" #include "LinkBuffer.h" -#include "JSCInlines.h" -#include "ProfilerCompilation.h" #include "VirtualRegister.h" namespace JSC { namespace FTL { using namespace DFG; +static void compileEntry(CCallHelpers& jit) +{ + jit.preserveReturnAddressAfterCall(GPRInfo::regT2); + jit.emitPutReturnPCToCallFrameHeader(GPRInfo::regT2); + jit.emitPutImmediateToCallFrameHeader(jit.codeBlock(), JSStack::CodeBlock); +} + void link(State& state) { - Graph& graph = state.graph; - CodeBlock* codeBlock = graph.m_codeBlock; - VM& vm = graph.m_vm; + CodeBlock* codeBlock = state.graph.m_codeBlock; - // B3 will create its own jump tables as needed. + // LLVM will create its own jump tables as needed. codeBlock->clearSwitchJumpTables(); - - state.jitCode->common.requiredRegisterCountForExit = graph.requiredRegisterCountForExit(); - if (!graph.m_plan.inlineCallFrames->isEmpty()) - state.jitCode->common.inlineCallFrames = graph.m_plan.inlineCallFrames; + state.jitCode->common.frameRegisterCount = state.graph.frameRegisterCount(); + state.jitCode->common.requiredRegisterCountForExit = state.graph.requiredRegisterCountForExit(); + + if (!state.graph.m_inlineCallFrames->isEmpty()) + state.jitCode->common.inlineCallFrames = std::move(state.graph.m_inlineCallFrames); - graph.registerFrozenValues(); - // Create the entrypoint. Note that we use this entrypoint totally differently // depending on whether we're doing OSR entry or not. - CCallHelpers jit(&vm, codeBlock); + // FIXME: Except for OSR entry, this is a total kludge - LLVM should just use our + // calling convention. + // https://bugs.webkit.org/show_bug.cgi?id=113621 + CCallHelpers jit(&state.graph.m_vm, codeBlock); - std::unique_ptr<LinkBuffer> linkBuffer; - - CCallHelpers::Address frame = CCallHelpers::Address( - CCallHelpers::stackPointerRegister, -static_cast<int32_t>(AssemblyHelpers::prologueStackPointerDelta())); + OwnPtr<LinkBuffer> linkBuffer; + CCallHelpers::Label arityCheck; + switch (state.graph.m_plan.mode) { + case FTLMode: { + compileEntry(jit); - if (Profiler::Compilation* compilation = graph.compilation()) { - compilation->addDescription( - Profiler::OriginStack(), - toCString("Generated FTL JIT code for ", CodeBlockWithJITType(codeBlock, JITCode::FTLJIT), ", instruction count = ", graph.m_codeBlock->instructionCount(), ":\n")); + // This part is only necessary for functions. We currently only compile functions. - graph.ensureDominators(); - graph.ensureNaturalLoops(); + CCallHelpers::Label fromArityCheck = jit.label(); - const char* prefix = " "; + // Plant a check that sufficient space is available in the JSStack. + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291 + jit.addPtr( + CCallHelpers::TrustedImm32(virtualRegisterForLocal(state.jitCode->common.requiredRegisterCountForExit).offset() * sizeof(Register)), + GPRInfo::callFrameRegister, GPRInfo::regT1); + CCallHelpers::Jump stackCheck = jit.branchPtr( + CCallHelpers::Above, + CCallHelpers::AbsoluteAddress(state.graph.m_vm.addressOfJSStackLimit()), + GPRInfo::regT1); + CCallHelpers::Label fromStackCheck = jit.label(); - DumpContext dumpContext; - StringPrintStream out; - Node* lastNode = 0; - for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); ++blockIndex) { - BasicBlock* block = graph.block(blockIndex); - if (!block) - continue; - - graph.dumpBlockHeader(out, prefix, block, Graph::DumpLivePhisOnly, &dumpContext); - compilation->addDescription(Profiler::OriginStack(), out.toCString()); - out.reset(); - - for (size_t nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { - Node* node = block->at(nodeIndex); - - Profiler::OriginStack stack; - - if (node->origin.semantic.isSet()) { - stack = Profiler::OriginStack( - *vm.m_perBytecodeProfiler, codeBlock, node->origin.semantic); - } - - if (graph.dumpCodeOrigin(out, prefix, lastNode, node, &dumpContext)) { - compilation->addDescription(stack, out.toCString()); - out.reset(); - } - - graph.dump(out, prefix, node, &dumpContext); - compilation->addDescription(stack, out.toCString()); - out.reset(); - - if (node->origin.semantic.isSet()) - lastNode = node; - } - } + jit.setupArgumentsExecState(); + jit.move( + CCallHelpers::TrustedImmPtr(reinterpret_cast<void*>(state.generatedFunction)), + GPRInfo::nonArgGPR0); + jit.call(GPRInfo::nonArgGPR0); + jit.emitGetReturnPCFromCallFrameHeaderPtr(GPRInfo::regT1); + jit.emitGetCallerFrameFromCallFrameHeaderPtr(GPRInfo::callFrameRegister); + jit.restoreReturnAddressBeforeReturn(GPRInfo::regT1); + jit.ret(); - dumpContext.dump(out, prefix); - compilation->addDescription(Profiler::OriginStack(), out.toCString()); - out.reset(); - - out.print(" Disassembly:\n"); - out.print(" <not implemented yet>\n"); - compilation->addDescription(Profiler::OriginStack(), out.toCString()); - out.reset(); + stackCheck.link(&jit); + jit.move(CCallHelpers::TrustedImmPtr(codeBlock), GPRInfo::argumentGPR1); + jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); + jit.store32( + CCallHelpers::TrustedImm32(CallFrame::Location::encodeAsBytecodeOffset(0)), + CCallHelpers::tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount))); + jit.storePtr(GPRInfo::callFrameRegister, &state.graph.m_vm.topCallFrame); + CCallHelpers::Call callStackCheck = jit.call(); +#if !ASSERT_DISABLED + // FIXME: need to make this call register with exception handling somehow. This is + // part of a bigger problem: FTL should be able to handle exceptions. + // https://bugs.webkit.org/show_bug.cgi?id=113622 + // Until then, use a JIT ASSERT. + jit.load64(state.graph.m_vm.addressOfException(), GPRInfo::regT0); + jit.jitAssertIsNull(GPRInfo::regT0); +#endif + jit.jump(fromStackCheck); - state.jitCode->common.compilation = compilation; - } - - switch (graph.m_plan.mode) { - case FTLMode: { - CCallHelpers::JumpList mainPathJumps; - + arityCheck = jit.label(); + compileEntry(jit); jit.load32( - frame.withOffset(sizeof(Register) * JSStack::ArgumentCount), + CCallHelpers::payloadFor(static_cast<VirtualRegister>(JSStack::ArgumentCount)), GPRInfo::regT1); - mainPathJumps.append(jit.branch32( + jit.branch32( CCallHelpers::AboveOrEqual, GPRInfo::regT1, - CCallHelpers::TrustedImm32(codeBlock->numParameters()))); - jit.emitFunctionPrologue(); + CCallHelpers::TrustedImm32(codeBlock->numParameters())) + .linkTo(fromArityCheck, &jit); jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); jit.store32( - CCallHelpers::TrustedImm32(CallSiteIndex(0).bits()), - CCallHelpers::tagFor(JSStack::ArgumentCount)); - jit.storePtr(GPRInfo::callFrameRegister, &vm.topCallFrame); + CCallHelpers::TrustedImm32(CallFrame::Location::encodeAsBytecodeOffset(0)), + CCallHelpers::tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount))); + jit.storePtr(GPRInfo::callFrameRegister, &state.graph.m_vm.topCallFrame); CCallHelpers::Call callArityCheck = jit.call(); #if !ASSERT_DISABLED // FIXME: need to make this call register with exception handling somehow. This is // part of a bigger problem: FTL should be able to handle exceptions. // https://bugs.webkit.org/show_bug.cgi?id=113622 // Until then, use a JIT ASSERT. - jit.load64(vm.addressOfException(), GPRInfo::regT1); + jit.load64(state.graph.m_vm.addressOfException(), GPRInfo::regT1); jit.jitAssertIsNull(GPRInfo::regT1); #endif - jit.move(GPRInfo::returnValueGPR, GPRInfo::argumentGPR0); - jit.emitFunctionEpilogue(); - mainPathJumps.append(jit.branchTest32(CCallHelpers::Zero, GPRInfo::argumentGPR0)); - jit.emitFunctionPrologue(); + if (GPRInfo::returnValueGPR != GPRInfo::regT0) + jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); + jit.branchTest32(CCallHelpers::Zero, GPRInfo::regT0).linkTo(fromArityCheck, &jit); CCallHelpers::Call callArityFixup = jit.call(); - jit.emitFunctionEpilogue(); - mainPathJumps.append(jit.jump()); - - linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail); - if (linkBuffer->didFailToAllocate()) { - state.allocationFailed = true; - return; - } + jit.jump(fromArityCheck); + + linkBuffer = adoptPtr(new LinkBuffer(state.graph.m_vm, &jit, codeBlock, JITCompilationMustSucceed)); + linkBuffer->link(callStackCheck, operationStackCheck); linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck); - linkBuffer->link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixupGenerator)).code().executableAddress())); - linkBuffer->link(mainPathJumps, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction))); - - state.jitCode->initializeAddressForCall(MacroAssemblerCodePtr(bitwise_cast<void*>(state.generatedFunction))); + linkBuffer->link(callArityFixup, FunctionPtr((state.graph.m_vm.getCTIStub(arityFixup)).code().executableAddress())); break; } @@ -175,19 +159,19 @@ void link(State& state) // We jump to here straight from DFG code, after having boxed up all of the // values into the scratch buffer. Everything should be good to go - at this // point we've even done the stack check. Basically we just have to make the - // call to the B3-generated code. - CCallHelpers::Label start = jit.label(); - jit.emitFunctionEpilogue(); - CCallHelpers::Jump mainPathJump = jit.jump(); + // call to the LLVM-generated code. + jit.setupArgumentsExecState(); + jit.move( + CCallHelpers::TrustedImmPtr(reinterpret_cast<void*>(state.generatedFunction)), + GPRInfo::nonArgGPR0); + jit.call(GPRInfo::nonArgGPR0); + jit.emitGetReturnPCFromCallFrameHeaderPtr(GPRInfo::regT1); + jit.emitGetCallerFrameFromCallFrameHeaderPtr(GPRInfo::callFrameRegister); + jit.restoreReturnAddressBeforeReturn(GPRInfo::regT1); + jit.ret(); - linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail); - if (linkBuffer->didFailToAllocate()) { - state.allocationFailed = true; - return; - } - linkBuffer->link(mainPathJump, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction))); - - state.jitCode->initializeAddressForCall(linkBuffer->locationOf(start)); + linkBuffer = adoptPtr(new LinkBuffer( + state.graph.m_vm, &jit, codeBlock, JITCompilationMustSucceed)); break; } @@ -196,8 +180,9 @@ void link(State& state) break; } - state.finalizer->entrypointLinkBuffer = WTFMove(linkBuffer); + state.finalizer->entrypointLinkBuffer = linkBuffer.release(); state.finalizer->function = state.generatedFunction; + state.finalizer->arityCheck = arityCheck; state.finalizer->jitCode = state.jitCode; } |