]> git.saurik.com Git - apple/javascriptcore.git/blob - ftl/FTLCompile.cpp
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / ftl / FTLCompile.cpp
1 /*
2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "FTLCompile.h"
28
29 #if ENABLE(FTL_JIT)
30
31 #include "CodeBlockWithJITType.h"
32 #include "CCallHelpers.h"
33 #include "DFGCommon.h"
34 #include "DFGGraphSafepoint.h"
35 #include "DataView.h"
36 #include "Disassembler.h"
37 #include "FTLExitThunkGenerator.h"
38 #include "FTLInlineCacheSize.h"
39 #include "FTLJITCode.h"
40 #include "FTLThunks.h"
41 #include "FTLUnwindInfo.h"
42 #include "JITStubs.h"
43 #include "LLVMAPI.h"
44 #include "LinkBuffer.h"
45 #include "RepatchBuffer.h"
46
47 namespace JSC { namespace FTL {
48
49 using namespace DFG;
50
51 static uint8_t* mmAllocateCodeSection(
52 void* opaqueState, uintptr_t size, unsigned alignment, unsigned, const char* sectionName)
53 {
54 State& state = *static_cast<State*>(opaqueState);
55
56 RELEASE_ASSERT(alignment <= jitAllocationGranule);
57
58 RefPtr<ExecutableMemoryHandle> result =
59 state.graph.m_vm.executableAllocator.allocate(
60 state.graph.m_vm, size, state.graph.m_codeBlock, JITCompilationMustSucceed);
61
62 // LLVM used to put __compact_unwind in a code section. We keep this here defensively,
63 // for clients that use older LLVMs.
64 if (!strcmp(sectionName, "__compact_unwind")) {
65 state.compactUnwind = result->start();
66 state.compactUnwindSize = result->sizeInBytes();
67 }
68
69 state.jitCode->addHandle(result);
70 state.codeSectionNames.append(sectionName);
71
72 return static_cast<uint8_t*>(result->start());
73 }
74
75 static uint8_t* mmAllocateDataSection(
76 void* opaqueState, uintptr_t size, unsigned alignment, unsigned sectionID,
77 const char* sectionName, LLVMBool isReadOnly)
78 {
79 UNUSED_PARAM(sectionID);
80 UNUSED_PARAM(isReadOnly);
81
82 // Allocate the GOT in the code section to make it reachable for all code.
83 if (!strcmp(sectionName, "__got"))
84 return mmAllocateCodeSection(opaqueState, size, alignment, sectionID, sectionName);
85
86 State& state = *static_cast<State*>(opaqueState);
87
88 RefPtr<DataSection> section = adoptRef(new DataSection(size, alignment));
89
90 if (!strcmp(sectionName, "__llvm_stackmaps"))
91 state.stackmapsSection = section;
92 else {
93 state.jitCode->addDataSection(section);
94 state.dataSectionNames.append(sectionName);
95 if (!strcmp(sectionName, "__compact_unwind")) {
96 state.compactUnwind = section->base();
97 state.compactUnwindSize = size;
98 }
99 }
100
101 return bitwise_cast<uint8_t*>(section->base());
102 }
103
104 static LLVMBool mmApplyPermissions(void*, char**)
105 {
106 return false;
107 }
108
109 static void mmDestroy(void*)
110 {
111 }
112
113 static void dumpDataSection(DataSection* section, const char* prefix)
114 {
115 for (unsigned j = 0; j < section->size() / sizeof(int64_t); ++j) {
116 char buf[32];
117 int64_t* wordPointer = static_cast<int64_t*>(section->base()) + j;
118 snprintf(buf, sizeof(buf), "0x%lx", static_cast<unsigned long>(bitwise_cast<uintptr_t>(wordPointer)));
119 dataLogF("%s%16s: 0x%016llx\n", prefix, buf, static_cast<long long>(*wordPointer));
120 }
121 }
122
123 template<typename DescriptorType>
124 void generateICFastPath(
125 State& state, CodeBlock* codeBlock, GeneratedFunction generatedFunction,
126 StackMaps::RecordMap& recordMap, DescriptorType& ic, size_t sizeOfIC)
127 {
128 VM& vm = state.graph.m_vm;
129
130 StackMaps::RecordMap::iterator iter = recordMap.find(ic.stackmapID());
131 if (iter == recordMap.end()) {
132 // It was optimized out.
133 return;
134 }
135
136 Vector<StackMaps::Record>& records = iter->value;
137
138 RELEASE_ASSERT(records.size() == ic.m_generators.size());
139
140 for (unsigned i = records.size(); i--;) {
141 StackMaps::Record& record = records[i];
142 auto generator = ic.m_generators[i];
143
144 CCallHelpers fastPathJIT(&vm, codeBlock);
145 generator.generateFastPath(fastPathJIT);
146
147 char* startOfIC =
148 bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
149
150 LinkBuffer linkBuffer(vm, fastPathJIT, startOfIC, sizeOfIC);
151 // Note: we could handle the !isValid() case. We just don't appear to have a
152 // reason to do so, yet.
153 RELEASE_ASSERT(linkBuffer.isValid());
154
155 MacroAssembler::AssemblerType_T::fillNops(
156 startOfIC + linkBuffer.size(), sizeOfIC - linkBuffer.size());
157
158 state.finalizer->sideCodeLinkBuffer->link(
159 ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC));
160
161 linkBuffer.link(
162 generator.slowPathJump(),
163 state.finalizer->sideCodeLinkBuffer->locationOf(generator.slowPathBegin()));
164
165 generator.finalize(linkBuffer, *state.finalizer->sideCodeLinkBuffer);
166 }
167 }
168
169 static RegisterSet usedRegistersFor(const StackMaps::Record& record)
170 {
171 if (Options::assumeAllRegsInFTLICAreLive())
172 return RegisterSet::allRegisters();
173 return RegisterSet(record.usedRegisterSet(), RegisterSet::calleeSaveRegisters());
174 }
175
176 static void fixFunctionBasedOnStackMaps(
177 State& state, CodeBlock* codeBlock, JITCode* jitCode, GeneratedFunction generatedFunction,
178 StackMaps::RecordMap& recordMap, bool didSeeUnwindInfo)
179 {
180 Graph& graph = state.graph;
181 VM& vm = graph.m_vm;
182 StackMaps stackmaps = jitCode->stackmaps;
183
184 StackMaps::RecordMap::iterator iter = recordMap.find(state.capturedStackmapID);
185 RELEASE_ASSERT(iter != recordMap.end());
186 RELEASE_ASSERT(iter->value.size() == 1);
187 RELEASE_ASSERT(iter->value[0].locations.size() == 1);
188 Location capturedLocation =
189 Location::forStackmaps(&jitCode->stackmaps, iter->value[0].locations[0]);
190 RELEASE_ASSERT(capturedLocation.kind() == Location::Register);
191 RELEASE_ASSERT(capturedLocation.gpr() == GPRInfo::callFrameRegister);
192 RELEASE_ASSERT(!(capturedLocation.addend() % sizeof(Register)));
193 int32_t localsOffset = capturedLocation.addend() / sizeof(Register) + graph.m_nextMachineLocal;
194
195 for (unsigned i = graph.m_inlineVariableData.size(); i--;) {
196 InlineCallFrame* inlineCallFrame = graph.m_inlineVariableData[i].inlineCallFrame;
197
198 if (inlineCallFrame->argumentsRegister.isValid()) {
199 inlineCallFrame->argumentsRegister = VirtualRegister(
200 inlineCallFrame->argumentsRegister.offset() + localsOffset);
201 }
202
203 for (unsigned argument = inlineCallFrame->arguments.size(); argument-- > 1;) {
204 inlineCallFrame->arguments[argument] =
205 inlineCallFrame->arguments[argument].withLocalsOffset(localsOffset);
206 }
207
208 if (inlineCallFrame->isClosureCall) {
209 inlineCallFrame->calleeRecovery =
210 inlineCallFrame->calleeRecovery.withLocalsOffset(localsOffset);
211 }
212 }
213
214 if (codeBlock->usesArguments()) {
215 codeBlock->setArgumentsRegister(
216 VirtualRegister(codeBlock->argumentsRegister().offset() + localsOffset));
217 }
218
219 MacroAssembler::Label stackOverflowException;
220
221 {
222 CCallHelpers checkJIT(&vm, codeBlock);
223
224 // At this point it's perfectly fair to just blow away all state and restore the
225 // JS JIT view of the universe.
226 checkJIT.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
227
228 MacroAssembler::Label exceptionContinueArg1Set = checkJIT.label();
229 checkJIT.move(MacroAssembler::TrustedImm64(TagTypeNumber), GPRInfo::tagTypeNumberRegister);
230 checkJIT.move(MacroAssembler::TrustedImm64(TagMask), GPRInfo::tagMaskRegister);
231
232 checkJIT.move(MacroAssembler::TrustedImmPtr(&vm), GPRInfo::argumentGPR0);
233 MacroAssembler::Call call = checkJIT.call();
234 checkJIT.jumpToExceptionHandler();
235
236 stackOverflowException = checkJIT.label();
237 checkJIT.emitGetCallerFrameFromCallFrameHeaderPtr(GPRInfo::argumentGPR1);
238 checkJIT.jump(exceptionContinueArg1Set);
239
240 OwnPtr<LinkBuffer> linkBuffer = adoptPtr(new LinkBuffer(
241 vm, checkJIT, codeBlock, JITCompilationMustSucceed));
242 linkBuffer->link(call, FunctionPtr(lookupExceptionHandler));
243
244 state.finalizer->handleExceptionsLinkBuffer = linkBuffer.release();
245 }
246
247 ExitThunkGenerator exitThunkGenerator(state);
248 exitThunkGenerator.emitThunks();
249 if (exitThunkGenerator.didThings()) {
250 RELEASE_ASSERT(state.finalizer->osrExit.size());
251 RELEASE_ASSERT(didSeeUnwindInfo);
252
253 OwnPtr<LinkBuffer> linkBuffer = adoptPtr(new LinkBuffer(
254 vm, exitThunkGenerator, codeBlock, JITCompilationMustSucceed));
255
256 RELEASE_ASSERT(state.finalizer->osrExit.size() == state.jitCode->osrExit.size());
257
258 for (unsigned i = 0; i < state.jitCode->osrExit.size(); ++i) {
259 OSRExitCompilationInfo& info = state.finalizer->osrExit[i];
260 OSRExit& exit = jitCode->osrExit[i];
261
262 if (verboseCompilationEnabled())
263 dataLog("Handling OSR stackmap #", exit.m_stackmapID, " for ", exit.m_codeOrigin, "\n");
264
265 iter = recordMap.find(exit.m_stackmapID);
266 if (iter == recordMap.end()) {
267 // It was optimized out.
268 continue;
269 }
270
271 info.m_thunkAddress = linkBuffer->locationOf(info.m_thunkLabel);
272 exit.m_patchableCodeOffset = linkBuffer->offsetOf(info.m_thunkJump);
273
274 for (unsigned j = exit.m_values.size(); j--;) {
275 ExitValue value = exit.m_values[j];
276 if (!value.isInJSStackSomehow())
277 continue;
278 if (!value.virtualRegister().isLocal())
279 continue;
280 exit.m_values[j] = value.withVirtualRegister(
281 VirtualRegister(value.virtualRegister().offset() + localsOffset));
282 }
283
284 if (verboseCompilationEnabled()) {
285 DumpContext context;
286 dataLog(" Exit values: ", inContext(exit.m_values, &context), "\n");
287 }
288 }
289
290 state.finalizer->exitThunksLinkBuffer = linkBuffer.release();
291 }
292
293 if (!state.getByIds.isEmpty() || !state.putByIds.isEmpty()) {
294 CCallHelpers slowPathJIT(&vm, codeBlock);
295
296 CCallHelpers::JumpList exceptionTarget;
297
298 for (unsigned i = state.getByIds.size(); i--;) {
299 GetByIdDescriptor& getById = state.getByIds[i];
300
301 if (verboseCompilationEnabled())
302 dataLog("Handling GetById stackmap #", getById.stackmapID(), "\n");
303
304 iter = recordMap.find(getById.stackmapID());
305 if (iter == recordMap.end()) {
306 // It was optimized out.
307 continue;
308 }
309
310 for (unsigned i = 0; i < iter->value.size(); ++i) {
311 StackMaps::Record& record = iter->value[i];
312
313 RegisterSet usedRegisters = usedRegistersFor(record);
314
315 GPRReg result = record.locations[0].directGPR();
316 GPRReg base = record.locations[1].directGPR();
317
318 JITGetByIdGenerator gen(
319 codeBlock, getById.codeOrigin(), usedRegisters, JSValueRegs(base),
320 JSValueRegs(result), NeedToSpill);
321
322 MacroAssembler::Label begin = slowPathJIT.label();
323
324 MacroAssembler::Call call = callOperation(
325 state, usedRegisters, slowPathJIT, getById.codeOrigin(), &exceptionTarget,
326 operationGetByIdOptimize, result, gen.stubInfo(), base, getById.uid());
327
328 gen.reportSlowPathCall(begin, call);
329
330 getById.m_slowPathDone.append(slowPathJIT.jump());
331 getById.m_generators.append(gen);
332 }
333 }
334
335 for (unsigned i = state.putByIds.size(); i--;) {
336 PutByIdDescriptor& putById = state.putByIds[i];
337
338 if (verboseCompilationEnabled())
339 dataLog("Handling PutById stackmap #", putById.stackmapID(), "\n");
340
341 iter = recordMap.find(putById.stackmapID());
342 if (iter == recordMap.end()) {
343 // It was optimized out.
344 continue;
345 }
346
347 for (unsigned i = 0; i < iter->value.size(); ++i) {
348 StackMaps::Record& record = iter->value[i];
349
350 RegisterSet usedRegisters = usedRegistersFor(record);
351
352 GPRReg base = record.locations[0].directGPR();
353 GPRReg value = record.locations[1].directGPR();
354
355 JITPutByIdGenerator gen(
356 codeBlock, putById.codeOrigin(), usedRegisters, JSValueRegs(base),
357 JSValueRegs(value), GPRInfo::patchpointScratchRegister, NeedToSpill,
358 putById.ecmaMode(), putById.putKind());
359
360 MacroAssembler::Label begin = slowPathJIT.label();
361
362 MacroAssembler::Call call = callOperation(
363 state, usedRegisters, slowPathJIT, putById.codeOrigin(), &exceptionTarget,
364 gen.slowPathFunction(), gen.stubInfo(), value, base, putById.uid());
365
366 gen.reportSlowPathCall(begin, call);
367
368 putById.m_slowPathDone.append(slowPathJIT.jump());
369 putById.m_generators.append(gen);
370 }
371 }
372
373 exceptionTarget.link(&slowPathJIT);
374 MacroAssembler::Jump exceptionJump = slowPathJIT.jump();
375
376 state.finalizer->sideCodeLinkBuffer = adoptPtr(
377 new LinkBuffer(vm, slowPathJIT, codeBlock, JITCompilationMustSucceed));
378 state.finalizer->sideCodeLinkBuffer->link(
379 exceptionJump, state.finalizer->handleExceptionsLinkBuffer->entrypoint());
380
381 for (unsigned i = state.getByIds.size(); i--;) {
382 generateICFastPath(
383 state, codeBlock, generatedFunction, recordMap, state.getByIds[i],
384 sizeOfGetById());
385 }
386 for (unsigned i = state.putByIds.size(); i--;) {
387 generateICFastPath(
388 state, codeBlock, generatedFunction, recordMap, state.putByIds[i],
389 sizeOfPutById());
390 }
391 }
392
393 // Handling JS calls is weird: we need to ensure that we sort them by the PC in LLVM
394 // generated code. That implies first pruning the ones that LLVM didn't generate.
395 Vector<JSCall> oldCalls = state.jsCalls;
396 state.jsCalls.resize(0);
397 for (unsigned i = 0; i < oldCalls.size(); ++i) {
398 JSCall& call = oldCalls[i];
399
400 StackMaps::RecordMap::iterator iter = recordMap.find(call.stackmapID());
401 if (iter == recordMap.end())
402 continue;
403
404 for (unsigned j = 0; j < iter->value.size(); ++j) {
405 JSCall copy = call;
406 copy.m_instructionOffset = iter->value[j].instructionOffset;
407 state.jsCalls.append(copy);
408 }
409 }
410
411 std::sort(state.jsCalls.begin(), state.jsCalls.end());
412
413 for (unsigned i = state.jsCalls.size(); i--;) {
414 JSCall& call = state.jsCalls[i];
415
416 CCallHelpers fastPathJIT(&vm, codeBlock);
417 call.emit(fastPathJIT);
418
419 char* startOfIC = bitwise_cast<char*>(generatedFunction) + call.m_instructionOffset;
420
421 LinkBuffer linkBuffer(vm, fastPathJIT, startOfIC, sizeOfCall());
422 if (!linkBuffer.isValid()) {
423 dataLog("Failed to insert inline cache for call because we thought the size would be ", sizeOfCall(), " but it ended up being ", fastPathJIT.m_assembler.codeSize(), " prior to compaction.\n");
424 RELEASE_ASSERT_NOT_REACHED();
425 }
426
427 MacroAssembler::AssemblerType_T::fillNops(
428 startOfIC + linkBuffer.size(), sizeOfCall() - linkBuffer.size());
429
430 call.link(vm, linkBuffer);
431 }
432
433 RepatchBuffer repatchBuffer(codeBlock);
434
435 iter = recordMap.find(state.handleStackOverflowExceptionStackmapID);
436 // It's sort of remotely possible that we won't have an in-band exception handling
437 // path, for some kinds of functions.
438 if (iter != recordMap.end()) {
439 for (unsigned i = iter->value.size(); i--;) {
440 StackMaps::Record& record = iter->value[i];
441
442 CodeLocationLabel source = CodeLocationLabel(
443 bitwise_cast<char*>(generatedFunction) + record.instructionOffset);
444
445 RELEASE_ASSERT(stackOverflowException.isSet());
446
447 repatchBuffer.replaceWithJump(source, state.finalizer->handleExceptionsLinkBuffer->locationOf(stackOverflowException));
448 }
449 }
450
451 iter = recordMap.find(state.handleExceptionStackmapID);
452 // It's sort of remotely possible that we won't have an in-band exception handling
453 // path, for some kinds of functions.
454 if (iter != recordMap.end()) {
455 for (unsigned i = iter->value.size(); i--;) {
456 StackMaps::Record& record = iter->value[i];
457
458 CodeLocationLabel source = CodeLocationLabel(
459 bitwise_cast<char*>(generatedFunction) + record.instructionOffset);
460
461 repatchBuffer.replaceWithJump(source, state.finalizer->handleExceptionsLinkBuffer->entrypoint());
462 }
463 }
464
465 for (unsigned exitIndex = 0; exitIndex < jitCode->osrExit.size(); ++exitIndex) {
466 OSRExitCompilationInfo& info = state.finalizer->osrExit[exitIndex];
467 OSRExit& exit = jitCode->osrExit[exitIndex];
468 iter = recordMap.find(exit.m_stackmapID);
469
470 Vector<const void*> codeAddresses;
471
472 if (iter != recordMap.end()) {
473 for (unsigned i = iter->value.size(); i--;) {
474 StackMaps::Record& record = iter->value[i];
475
476 CodeLocationLabel source = CodeLocationLabel(
477 bitwise_cast<char*>(generatedFunction) + record.instructionOffset);
478
479 codeAddresses.append(bitwise_cast<char*>(generatedFunction) + record.instructionOffset + MacroAssembler::maxJumpReplacementSize());
480
481 if (info.m_isInvalidationPoint)
482 jitCode->common.jumpReplacements.append(JumpReplacement(source, info.m_thunkAddress));
483 else
484 repatchBuffer.replaceWithJump(source, info.m_thunkAddress);
485 }
486 }
487
488 if (graph.compilation())
489 graph.compilation()->addOSRExitSite(codeAddresses);
490 }
491 }
492
493 void compile(State& state, Safepoint::Result& safepointResult)
494 {
495 char* error = 0;
496
497 {
498 GraphSafepoint safepoint(state.graph, safepointResult);
499
500 LLVMMCJITCompilerOptions options;
501 llvm->InitializeMCJITCompilerOptions(&options, sizeof(options));
502 options.OptLevel = Options::llvmBackendOptimizationLevel();
503 options.NoFramePointerElim = true;
504 if (Options::useLLVMSmallCodeModel())
505 options.CodeModel = LLVMCodeModelSmall;
506 options.EnableFastISel = Options::enableLLVMFastISel();
507 options.MCJMM = llvm->CreateSimpleMCJITMemoryManager(
508 &state, mmAllocateCodeSection, mmAllocateDataSection, mmApplyPermissions, mmDestroy);
509
510 LLVMExecutionEngineRef engine;
511
512 if (isARM64())
513 llvm->SetTarget(state.module, "arm64-apple-ios");
514
515 if (llvm->CreateMCJITCompilerForModule(&engine, state.module, &options, sizeof(options), &error)) {
516 dataLog("FATAL: Could not create LLVM execution engine: ", error, "\n");
517 CRASH();
518 }
519
520 LLVMPassManagerRef functionPasses = 0;
521 LLVMPassManagerRef modulePasses;
522
523 if (Options::llvmSimpleOpt()) {
524 modulePasses = llvm->CreatePassManager();
525 llvm->AddTargetData(llvm->GetExecutionEngineTargetData(engine), modulePasses);
526 llvm->AddPromoteMemoryToRegisterPass(modulePasses);
527 llvm->AddConstantPropagationPass(modulePasses);
528 llvm->AddInstructionCombiningPass(modulePasses);
529 llvm->AddTypeBasedAliasAnalysisPass(modulePasses);
530 llvm->AddBasicAliasAnalysisPass(modulePasses);
531 llvm->AddGVNPass(modulePasses);
532 llvm->AddCFGSimplificationPass(modulePasses);
533 llvm->AddDeadStoreEliminationPass(modulePasses);
534 llvm->RunPassManager(modulePasses, state.module);
535 } else {
536 LLVMPassManagerBuilderRef passBuilder = llvm->PassManagerBuilderCreate();
537 llvm->PassManagerBuilderSetOptLevel(passBuilder, Options::llvmOptimizationLevel());
538 llvm->PassManagerBuilderSetSizeLevel(passBuilder, Options::llvmSizeLevel());
539
540 functionPasses = llvm->CreateFunctionPassManagerForModule(state.module);
541 modulePasses = llvm->CreatePassManager();
542
543 llvm->AddTargetData(llvm->GetExecutionEngineTargetData(engine), modulePasses);
544
545 llvm->PassManagerBuilderPopulateFunctionPassManager(passBuilder, functionPasses);
546 llvm->PassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
547
548 llvm->PassManagerBuilderDispose(passBuilder);
549
550 llvm->InitializeFunctionPassManager(functionPasses);
551 for (LValue function = llvm->GetFirstFunction(state.module); function; function = llvm->GetNextFunction(function))
552 llvm->RunFunctionPassManager(functionPasses, function);
553 llvm->FinalizeFunctionPassManager(functionPasses);
554
555 llvm->RunPassManager(modulePasses, state.module);
556 }
557
558 if (shouldShowDisassembly() || verboseCompilationEnabled())
559 state.dumpState("after optimization");
560
561 // FIXME: Need to add support for the case where JIT memory allocation failed.
562 // https://bugs.webkit.org/show_bug.cgi?id=113620
563 state.generatedFunction = reinterpret_cast<GeneratedFunction>(llvm->GetPointerToGlobal(engine, state.function));
564 if (functionPasses)
565 llvm->DisposePassManager(functionPasses);
566 llvm->DisposePassManager(modulePasses);
567 llvm->DisposeExecutionEngine(engine);
568 }
569 if (safepointResult.didGetCancelled())
570 return;
571 RELEASE_ASSERT(!state.graph.m_vm.heap.isCollecting());
572
573 if (shouldShowDisassembly()) {
574 for (unsigned i = 0; i < state.jitCode->handles().size(); ++i) {
575 ExecutableMemoryHandle* handle = state.jitCode->handles()[i].get();
576 dataLog(
577 "Generated LLVM code for ",
578 CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT),
579 " #", i, ", ", state.codeSectionNames[i], ":\n");
580 disassemble(
581 MacroAssemblerCodePtr(handle->start()), handle->sizeInBytes(),
582 " ", WTF::dataFile(), LLVMSubset);
583 }
584
585 for (unsigned i = 0; i < state.jitCode->dataSections().size(); ++i) {
586 DataSection* section = state.jitCode->dataSections()[i].get();
587 dataLog(
588 "Generated LLVM data section for ",
589 CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT),
590 " #", i, ", ", state.dataSectionNames[i], ":\n");
591 dumpDataSection(section, " ");
592 }
593 }
594
595 bool didSeeUnwindInfo = state.jitCode->unwindInfo.parse(
596 state.compactUnwind, state.compactUnwindSize, state.generatedFunction);
597 if (shouldShowDisassembly()) {
598 dataLog("Unwind info for ", CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT), ":\n");
599 if (didSeeUnwindInfo)
600 dataLog(" ", state.jitCode->unwindInfo, "\n");
601 else
602 dataLog(" <no unwind info>\n");
603 }
604
605 if (state.stackmapsSection && state.stackmapsSection->size()) {
606 if (shouldShowDisassembly()) {
607 dataLog(
608 "Generated LLVM stackmaps section for ",
609 CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT), ":\n");
610 dataLog(" Raw data:\n");
611 dumpDataSection(state.stackmapsSection.get(), " ");
612 }
613
614 RefPtr<DataView> stackmapsData = DataView::create(
615 ArrayBuffer::create(state.stackmapsSection->base(), state.stackmapsSection->size()));
616 state.jitCode->stackmaps.parse(stackmapsData.get());
617
618 if (shouldShowDisassembly()) {
619 dataLog(" Structured data:\n");
620 state.jitCode->stackmaps.dumpMultiline(WTF::dataFile(), " ");
621 }
622
623 StackMaps::RecordMap recordMap = state.jitCode->stackmaps.computeRecordMap();
624 fixFunctionBasedOnStackMaps(
625 state, state.graph.m_codeBlock, state.jitCode.get(), state.generatedFunction,
626 recordMap, didSeeUnwindInfo);
627
628 if (shouldShowDisassembly()) {
629 for (unsigned i = 0; i < state.jitCode->handles().size(); ++i) {
630 if (state.codeSectionNames[i] != "__text")
631 continue;
632
633 ExecutableMemoryHandle* handle = state.jitCode->handles()[i].get();
634 dataLog(
635 "Generated LLVM code after stackmap-based fix-up for ",
636 CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT),
637 " in ", state.graph.m_plan.mode, " #", i, ", ",
638 state.codeSectionNames[i], ":\n");
639 disassemble(
640 MacroAssemblerCodePtr(handle->start()), handle->sizeInBytes(),
641 " ", WTF::dataFile(), LLVMSubset);
642 }
643 }
644 }
645
646 state.module = 0; // We no longer own the module.
647 }
648
649 } } // namespace JSC::FTL
650
651 #endif // ENABLE(FTL_JIT)
652