Bug 1885489 - Part 5: Add SnapshotIterator::readInt32(). r=iain
[gecko.git] / js / src / jit / InterpreterEntryTrampoline.cpp
blob2e662af559c44072275e3e026a2824133042f2a3
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
7 #include "jit/InterpreterEntryTrampoline.h"
8 #include "jit/JitRuntime.h"
9 #include "jit/Linker.h"
10 #include "vm/Interpreter.h"
12 #include "gc/Marking-inl.h"
13 #include "jit/MacroAssembler-inl.h"
15 using namespace js;
16 using namespace js::jit;
18 void js::ClearInterpreterEntryMap(JSRuntime* runtime) {
19 if (runtime->hasJitRuntime() &&
20 runtime->jitRuntime()->hasInterpreterEntryMap()) {
21 runtime->jitRuntime()->getInterpreterEntryMap()->clear();
25 void EntryTrampolineMap::traceTrampolineCode(JSTracer* trc) {
26 for (jit::EntryTrampolineMap::Enum e(*this); !e.empty(); e.popFront()) {
27 EntryTrampoline& trampoline = e.front().value();
28 trampoline.trace(trc);
32 void EntryTrampolineMap::updateScriptsAfterMovingGC(void) {
33 for (jit::EntryTrampolineMap::Enum e(*this); !e.empty(); e.popFront()) {
34 BaseScript* script = e.front().key();
35 if (IsForwarded(script)) {
36 script = Forwarded(script);
37 e.rekeyFront(script);
42 #ifdef JSGC_HASH_TABLE_CHECKS
43 void EntryTrampoline::checkTrampolineAfterMovingGC() {
44 JitCode* trampoline = entryTrampoline_;
45 CheckGCThingAfterMovingGC(trampoline);
48 void EntryTrampolineMap::checkScriptsAfterMovingGC() {
49 for (jit::EntryTrampolineMap::Enum r(*this); !r.empty(); r.popFront()) {
50 BaseScript* script = r.front().key();
51 CheckGCThingAfterMovingGC(script);
52 r.front().value().checkTrampolineAfterMovingGC();
53 auto ptr = lookup(script);
54 MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
57 #endif
59 void JitRuntime::generateBaselineInterpreterEntryTrampoline(
60 MacroAssembler& masm) {
61 AutoCreatedBy acb(masm,
62 "JitRuntime::generateBaselineInterpreterEntryTrampoline");
64 #ifdef JS_USE_LINK_REGISTER
65 masm.pushReturnAddress();
66 #endif
67 masm.push(FramePointer);
68 masm.moveStackPtrTo(FramePointer);
70 AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
71 Register nargs = regs.takeAny();
72 Register callee = regs.takeAny();
73 Register scratch = regs.takeAny();
75 // Load callee token and keep it in a register as it will be used often
76 Address calleeTokenAddr(
77 FramePointer, BaselineInterpreterEntryFrameLayout::offsetOfCalleeToken());
78 masm.loadPtr(calleeTokenAddr, callee);
80 // Load argc into nargs.
81 masm.loadNumActualArgs(FramePointer, nargs);
83 Label notFunction;
85 // Check if calleetoken is script or function
86 masm.branchTestPtr(Assembler::NonZero, callee, Imm32(CalleeTokenScriptBit),
87 &notFunction);
89 // CalleeToken is a function, load |nformals| into scratch
90 masm.movePtr(callee, scratch);
91 masm.andPtr(Imm32(uint32_t(CalleeTokenMask)), scratch);
92 masm.loadFunctionArgCount(scratch, scratch);
94 // Take max(nformals, argc).
95 Label noUnderflow;
96 masm.branch32(Assembler::AboveOrEqual, nargs, scratch, &noUnderflow);
97 { masm.movePtr(scratch, nargs); }
98 masm.bind(&noUnderflow);
100 // Add 1 to nargs if constructing.
101 static_assert(
102 CalleeToken_FunctionConstructing == 1,
103 "Ensure that we can use the constructing bit to count the value");
104 masm.movePtr(callee, scratch);
105 masm.and32(Imm32(uint32_t(CalleeToken_FunctionConstructing)), scratch);
106 masm.addPtr(scratch, nargs);
108 masm.bind(&notFunction);
110 // Align stack
111 masm.alignJitStackBasedOnNArgs(nargs, /*countIncludesThis = */ false);
113 // Point argPtr to the topmost argument.
114 static_assert(sizeof(Value) == 8,
115 "Using TimesEight for scale of sizeof(Value).");
116 BaseIndex topPtrAddr(FramePointer, nargs, TimesEight,
117 sizeof(BaselineInterpreterEntryFrameLayout));
118 Register argPtr = nargs;
119 masm.computeEffectiveAddress(topPtrAddr, argPtr);
121 // Load the end address into scratch, which is the callee token.
122 masm.computeEffectiveAddress(calleeTokenAddr, scratch);
124 // Copy |this|+arguments
125 Label loop;
126 masm.bind(&loop);
128 masm.pushValue(Address(argPtr, 0));
129 masm.subPtr(Imm32(sizeof(Value)), argPtr);
130 masm.branchPtr(Assembler::Above, argPtr, scratch, &loop);
133 // Copy callee token
134 masm.push(callee);
136 // Save a new descriptor using BaselineInterpreterEntry frame type.
137 masm.loadNumActualArgs(FramePointer, scratch);
138 masm.pushFrameDescriptorForJitCall(FrameType::BaselineInterpreterEntry,
139 scratch, scratch);
141 // Call into baseline interpreter
142 uint8_t* blinterpAddr = baselineInterpreter().codeRaw();
143 masm.assertStackAlignment(JitStackAlignment, 2 * sizeof(uintptr_t));
144 masm.call(ImmPtr(blinterpAddr));
146 masm.moveToStackPtr(FramePointer);
147 masm.pop(FramePointer);
148 masm.ret();
151 void JitRuntime::generateInterpreterEntryTrampoline(MacroAssembler& masm) {
152 AutoCreatedBy acb(masm, "JitRuntime::generateInterpreterEntryTrampoline");
154 // If BLI is disabled, we don't need an offset.
155 if (IsBaselineInterpreterEnabled()) {
156 uint32_t offset = startTrampolineCode(masm);
157 if (!vmInterpreterEntryOffset_) {
158 vmInterpreterEntryOffset_ = offset;
162 #ifdef JS_CODEGEN_ARM64
163 // Use the normal stack pointer for the initial pushes.
164 masm.SetStackPointer64(sp);
166 // Push lr and fp together to maintain 16-byte alignment.
167 masm.push(lr, FramePointer);
168 masm.moveStackPtrTo(FramePointer);
170 // Save the PSP register (r28), and a scratch (r19).
171 masm.push(r19, r28);
173 // Setup the PSP so we can use callWithABI below.
174 masm.SetStackPointer64(PseudoStackPointer64);
175 masm.initPseudoStackPtr();
177 Register arg0 = IntArgReg0;
178 Register arg1 = IntArgReg1;
179 Register scratch = r19;
180 #elif defined(JS_CODEGEN_X86)
181 masm.push(FramePointer);
182 masm.moveStackPtrTo(FramePointer);
184 AllocatableRegisterSet regs(RegisterSet::Volatile());
185 Register arg0 = regs.takeAnyGeneral();
186 Register arg1 = regs.takeAnyGeneral();
187 Register scratch = regs.takeAnyGeneral();
189 // First two arguments are passed on the stack in 32-bit.
190 Address cxAddr(FramePointer, 2 * sizeof(void*));
191 Address stateAddr(FramePointer, 3 * sizeof(void*));
192 masm.loadPtr(cxAddr, arg0);
193 masm.loadPtr(stateAddr, arg1);
194 #else
195 masm.push(FramePointer);
196 masm.moveStackPtrTo(FramePointer);
198 AllocatableRegisterSet regs(RegisterSet::Volatile());
199 regs.take(IntArgReg0);
200 regs.take(IntArgReg1);
201 Register arg0 = IntArgReg0;
202 Register arg1 = IntArgReg1;
203 Register scratch = regs.takeAnyGeneral();
204 #endif
206 using Fn = bool (*)(JSContext* cx, js::RunState& state);
207 masm.setupUnalignedABICall(scratch);
208 masm.passABIArg(arg0); // cx
209 masm.passABIArg(arg1); // state
210 masm.callWithABI<Fn, Interpret>(
211 ABIType::General, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
213 #ifdef JS_CODEGEN_ARM64
214 masm.syncStackPtr();
215 masm.SetStackPointer64(sp);
217 // Restore r28 and r19.
218 masm.pop(r28, r19);
220 // Restore old fp and pop lr for return.
221 masm.pop(FramePointer, lr);
222 masm.abiret();
224 // Reset stack pointer.
225 masm.SetStackPointer64(PseudoStackPointer64);
226 #else
227 masm.moveToStackPtr(FramePointer);
228 masm.pop(FramePointer);
229 masm.ret();
230 #endif
233 JitCode* JitRuntime::generateEntryTrampolineForScript(JSContext* cx,
234 JSScript* script) {
235 if (JitSpewEnabled(JitSpew_Codegen)) {
236 UniqueChars funName;
237 if (script->function() && script->function()->fullDisplayAtom()) {
238 funName =
239 AtomToPrintableString(cx, script->function()->fullDisplayAtom());
242 JitSpew(JitSpew_Codegen,
243 "# Emitting Interpreter Entry Trampoline for %s (%s:%u:%u)",
244 funName ? funName.get() : "*", script->filename(), script->lineno(),
245 script->column().oneOriginValue());
248 TempAllocator temp(&cx->tempLifoAlloc());
249 JitContext jctx(cx);
250 StackMacroAssembler masm(cx, temp);
251 AutoCreatedBy acb(masm, "JitRuntime::generateEntryTrampolineForScript");
252 PerfSpewerRangeRecorder rangeRecorder(masm);
254 if (IsBaselineInterpreterEnabled()) {
255 generateBaselineInterpreterEntryTrampoline(masm);
256 rangeRecorder.recordOffset("BaselineInterpreter", cx, script);
259 generateInterpreterEntryTrampoline(masm);
260 rangeRecorder.recordOffset("Interpreter", cx, script);
262 Linker linker(masm);
263 JitCode* code = linker.newCode(cx, CodeKind::Other);
264 if (!code) {
265 return nullptr;
267 rangeRecorder.collectRangesForJitCode(code);
268 JitSpew(JitSpew_Codegen, "# code = %p", code->raw());
269 return code;