|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef jit_IonLinker_h |
|
8 #define jit_IonLinker_h |
|
9 |
|
10 #include "jscntxt.h" |
|
11 #include "jscompartment.h" |
|
12 #include "jsgc.h" |
|
13 |
|
14 #include "assembler/jit/ExecutableAllocator.h" |
|
15 #include "jit/IonCode.h" |
|
16 #include "jit/IonMacroAssembler.h" |
|
17 #include "jit/JitCompartment.h" |
|
18 |
|
19 namespace js { |
|
20 namespace jit { |
|
21 |
|
22 class Linker |
|
23 { |
|
24 MacroAssembler &masm; |
|
25 |
|
26 JitCode *fail(JSContext *cx) { |
|
27 js_ReportOutOfMemory(cx); |
|
28 return nullptr; |
|
29 } |
|
30 |
|
31 template <AllowGC allowGC> |
|
32 JitCode *newCode(JSContext *cx, JSC::ExecutableAllocator *execAlloc, JSC::CodeKind kind) { |
|
33 JS_ASSERT(kind == JSC::ION_CODE || |
|
34 kind == JSC::BASELINE_CODE || |
|
35 kind == JSC::OTHER_CODE); |
|
36 JS_ASSERT(masm.numAsmJSAbsoluteLinks() == 0); |
|
37 |
|
38 gc::AutoSuppressGC suppressGC(cx); |
|
39 if (masm.oom()) |
|
40 return fail(cx); |
|
41 |
|
42 JSC::ExecutablePool *pool; |
|
43 size_t bytesNeeded = masm.bytesNeeded() + sizeof(JitCode *) + CodeAlignment; |
|
44 if (bytesNeeded >= MAX_BUFFER_SIZE) |
|
45 return fail(cx); |
|
46 |
|
47 // ExecutableAllocator requires bytesNeeded to be word-size aligned. |
|
48 bytesNeeded = AlignBytes(bytesNeeded, sizeof(void *)); |
|
49 |
|
50 uint8_t *result = (uint8_t *)execAlloc->alloc(bytesNeeded, &pool, kind); |
|
51 if (!result) |
|
52 return fail(cx); |
|
53 |
|
54 // The JitCode pointer will be stored right before the code buffer. |
|
55 uint8_t *codeStart = result + sizeof(JitCode *); |
|
56 |
|
57 // Bump the code up to a nice alignment. |
|
58 codeStart = (uint8_t *)AlignBytes((uintptr_t)codeStart, CodeAlignment); |
|
59 uint32_t headerSize = codeStart - result; |
|
60 JitCode *code = JitCode::New<allowGC>(cx, codeStart, bytesNeeded - headerSize, |
|
61 headerSize, pool, kind); |
|
62 if (!code) |
|
63 return nullptr; |
|
64 if (masm.oom()) |
|
65 return fail(cx); |
|
66 code->copyFrom(masm); |
|
67 masm.link(code); |
|
68 #ifdef JSGC_GENERATIONAL |
|
69 if (masm.embedsNurseryPointers()) |
|
70 cx->runtime()->gcStoreBuffer.putWholeCell(code); |
|
71 #endif |
|
72 return code; |
|
73 } |
|
74 |
|
75 public: |
|
76 Linker(MacroAssembler &masm) |
|
77 : masm(masm) |
|
78 { |
|
79 masm.finish(); |
|
80 } |
|
81 |
|
82 template <AllowGC allowGC> |
|
83 JitCode *newCode(JSContext *cx, JSC::CodeKind kind) { |
|
84 return newCode<allowGC>(cx, cx->runtime()->jitRuntime()->execAlloc(), kind); |
|
85 } |
|
86 |
|
87 JitCode *newCodeForIonScript(JSContext *cx) { |
|
88 #ifdef JS_CODEGEN_ARM |
|
89 // ARM does not yet use implicit interrupt checks, see bug 864220. |
|
90 return newCode<CanGC>(cx, JSC::ION_CODE); |
|
91 #else |
|
92 // The caller must lock the runtime against interrupt requests, as the |
|
93 // thread requesting an interrupt may use the executable allocator below. |
|
94 JS_ASSERT(cx->runtime()->currentThreadOwnsInterruptLock()); |
|
95 |
|
96 JSC::ExecutableAllocator *alloc = cx->runtime()->jitRuntime()->getIonAlloc(cx); |
|
97 if (!alloc) |
|
98 return nullptr; |
|
99 |
|
100 return newCode<CanGC>(cx, alloc, JSC::ION_CODE); |
|
101 #endif |
|
102 } |
|
103 }; |
|
104 |
|
105 } // namespace jit |
|
106 } // namespace js |
|
107 |
|
108 #endif /* jit_IonLinker_h */ |