diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/ftl/FTLLink.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/ftl/FTLLink.cpp')
-rw-r--r-- | Source/JavaScriptCore/ftl/FTLLink.cpp | 229 |
1 files changed, 124 insertions, 105 deletions
diff --git a/Source/JavaScriptCore/ftl/FTLLink.cpp b/Source/JavaScriptCore/ftl/FTLLink.cpp index 85050d151..d11b2a9b6 100644 --- a/Source/JavaScriptCore/ftl/FTLLink.cpp +++ b/Source/JavaScriptCore/ftl/FTLLink.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2014 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,129 +29,149 @@ #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) { - CodeBlock* codeBlock = state.graph.m_codeBlock; + Graph& graph = state.graph; + CodeBlock* codeBlock = graph.m_codeBlock; + VM& vm = graph.m_vm; - // LLVM will create its own jump tables as needed. + // B3 will create its own jump tables as needed. codeBlock->clearSwitchJumpTables(); + + state.jitCode->common.requiredRegisterCountForExit = graph.requiredRegisterCountForExit(); - 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); + if (!graph.m_plan.inlineCallFrames->isEmpty()) + state.jitCode->common.inlineCallFrames = graph.m_plan.inlineCallFrames; + graph.registerFrozenValues(); + // Create the entrypoint. Note that we use this entrypoint totally differently // depending on whether we're doing OSR entry or not. - // 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); + CCallHelpers jit(&vm, codeBlock); - OwnPtr<LinkBuffer> linkBuffer; - CCallHelpers::Label arityCheck; - switch (state.graph.m_plan.mode) { - case FTLMode: { - compileEntry(jit); + std::unique_ptr<LinkBuffer> linkBuffer; + + CCallHelpers::Address frame = CCallHelpers::Address( + CCallHelpers::stackPointerRegister, -static_cast<int32_t>(AssemblyHelpers::prologueStackPointerDelta())); - // This part is only necessary for functions. We currently only compile functions. + 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")); - CCallHelpers::Label fromArityCheck = jit.label(); + graph.ensureDominators(); + graph.ensureNaturalLoops(); - // 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(); + const char* prefix = " "; - 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 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; + } + } - 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); + 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(); - arityCheck = jit.label(); - compileEntry(jit); + state.jitCode->common.compilation = compilation; + } + + switch (graph.m_plan.mode) { + case FTLMode: { + CCallHelpers::JumpList mainPathJumps; + jit.load32( - CCallHelpers::payloadFor(static_cast<VirtualRegister>(JSStack::ArgumentCount)), + frame.withOffset(sizeof(Register) * CallFrameSlot::argumentCount), GPRInfo::regT1); - jit.branch32( + mainPathJumps.append(jit.branch32( CCallHelpers::AboveOrEqual, GPRInfo::regT1, - CCallHelpers::TrustedImm32(codeBlock->numParameters())) - .linkTo(fromArityCheck, &jit); + CCallHelpers::TrustedImm32(codeBlock->numParameters()))); + jit.emitFunctionPrologue(); 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); + jit.storePtr(GPRInfo::callFrameRegister, &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(state.graph.m_vm.addressOfException(), GPRInfo::regT1); - jit.jitAssertIsNull(GPRInfo::regT1); -#endif - if (GPRInfo::returnValueGPR != GPRInfo::regT0) - jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); - jit.branchTest32(CCallHelpers::Zero, GPRInfo::regT0).linkTo(fromArityCheck, &jit); + + auto noException = jit.branch32(CCallHelpers::GreaterThanOrEqual, GPRInfo::returnValueGPR, CCallHelpers::TrustedImm32(0)); + jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(); + jit.move(CCallHelpers::TrustedImmPtr(jit.vm()), GPRInfo::argumentGPR0); + jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1); + CCallHelpers::Call callLookupExceptionHandlerFromCallerFrame = jit.call(); + jit.jumpToExceptionHandler(); + noException.link(&jit); + + if (!ASSERT_DISABLED) { + jit.load64(vm.addressOfException(), GPRInfo::regT1); + jit.jitAssertIsNull(GPRInfo::regT1); + } + + jit.move(GPRInfo::returnValueGPR, GPRInfo::argumentGPR0); + jit.emitFunctionEpilogue(); + mainPathJumps.append(jit.branchTest32(CCallHelpers::Zero, GPRInfo::argumentGPR0)); + jit.emitFunctionPrologue(); CCallHelpers::Call callArityFixup = jit.call(); - jit.jump(fromArityCheck); - - linkBuffer = adoptPtr(new LinkBuffer(state.graph.m_vm, &jit, codeBlock, JITCompilationMustSucceed)); - linkBuffer->link(callStackCheck, operationStackCheck); + jit.emitFunctionEpilogue(); + mainPathJumps.append(jit.jump()); + + linkBuffer = std::make_unique<LinkBuffer>(vm, jit, codeBlock, JITCompilationCanFail); + if (linkBuffer->didFailToAllocate()) { + state.allocationFailed = true; + return; + } linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck); - linkBuffer->link(callArityFixup, FunctionPtr((state.graph.m_vm.getCTIStub(arityFixup)).code().executableAddress())); + linkBuffer->link(callLookupExceptionHandlerFromCallerFrame, lookupExceptionHandlerFromCallerFrame); + 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))); break; } @@ -159,19 +179,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 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(); + // call to the B3-generated code. + CCallHelpers::Label start = jit.label(); + jit.emitFunctionEpilogue(); + CCallHelpers::Jump mainPathJump = jit.jump(); - linkBuffer = adoptPtr(new LinkBuffer( - state.graph.m_vm, &jit, codeBlock, JITCompilationMustSucceed)); + 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)); break; } @@ -180,9 +200,8 @@ void link(State& state) break; } - state.finalizer->entrypointLinkBuffer = linkBuffer.release(); + state.finalizer->entrypointLinkBuffer = WTFMove(linkBuffer); state.finalizer->function = state.generatedFunction; - state.finalizer->arityCheck = arityCheck; state.finalizer->jitCode = state.jitCode; } |