js/src/jit/BaselineJIT.h

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:f8097811d172
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_BaselineJIT_h
8 #define jit_BaselineJIT_h
9
10 #ifdef JS_ION
11
12 #include "mozilla/MemoryReporting.h"
13
14 #include "jscntxt.h"
15 #include "jscompartment.h"
16
17 #include "ds/LifoAlloc.h"
18 #include "jit/Bailouts.h"
19 #include "jit/IonCode.h"
20 #include "jit/IonMacroAssembler.h"
21
22 namespace js {
23 namespace jit {
24
25 class StackValue;
26 class ICEntry;
27 class ICStub;
28
29 class PCMappingSlotInfo
30 {
31 uint8_t slotInfo_;
32
33 public:
34 // SlotInfo encoding:
35 // Bits 0 & 1: number of slots at top of stack which are unsynced.
36 // Bits 2 & 3: SlotLocation of top slot value (only relevant if numUnsynced > 0).
37 // Bits 3 & 4: SlotLocation of next slot value (only relevant if numUnsynced > 1).
38 enum SlotLocation { SlotInR0 = 0, SlotInR1 = 1, SlotIgnore = 3 };
39
40 PCMappingSlotInfo()
41 : slotInfo_(0)
42 { }
43
44 explicit PCMappingSlotInfo(uint8_t slotInfo)
45 : slotInfo_(slotInfo)
46 { }
47
48 static inline bool ValidSlotLocation(SlotLocation loc) {
49 return (loc == SlotInR0) || (loc == SlotInR1) || (loc == SlotIgnore);
50 }
51
52 static SlotLocation ToSlotLocation(const StackValue *stackVal);
53
54 inline static PCMappingSlotInfo MakeSlotInfo() { return PCMappingSlotInfo(0); }
55
56 inline static PCMappingSlotInfo MakeSlotInfo(SlotLocation topSlotLoc) {
57 JS_ASSERT(ValidSlotLocation(topSlotLoc));
58 return PCMappingSlotInfo(1 | (topSlotLoc << 2));
59 }
60
61 inline static PCMappingSlotInfo MakeSlotInfo(SlotLocation topSlotLoc, SlotLocation nextSlotLoc) {
62 JS_ASSERT(ValidSlotLocation(topSlotLoc));
63 JS_ASSERT(ValidSlotLocation(nextSlotLoc));
64 return PCMappingSlotInfo(2 | (topSlotLoc << 2) | (nextSlotLoc) << 4);
65 }
66
67 inline unsigned numUnsynced() const {
68 return slotInfo_ & 0x3;
69 }
70 inline SlotLocation topSlotLocation() const {
71 return static_cast<SlotLocation>((slotInfo_ >> 2) & 0x3);
72 }
73 inline SlotLocation nextSlotLocation() const {
74 return static_cast<SlotLocation>((slotInfo_ >> 4) & 0x3);
75 }
76 inline uint8_t toByte() const {
77 return slotInfo_;
78 }
79 };
80
81 // A CompactBuffer is used to store native code offsets (relative to the
82 // previous pc) and PCMappingSlotInfo bytes. To allow binary search into this
83 // table, we maintain a second table of "index" entries. Every X ops, the
84 // compiler will add an index entry, so that from the index entry to the
85 // actual native code offset, we have to iterate at most X times.
86 struct PCMappingIndexEntry
87 {
88 // jsbytecode offset.
89 uint32_t pcOffset;
90
91 // Native code offset.
92 uint32_t nativeOffset;
93
94 // Offset in the CompactBuffer where data for pcOffset starts.
95 uint32_t bufferOffset;
96 };
97
98 struct BaselineScript
99 {
100 public:
101 static const uint32_t MAX_JSSCRIPT_LENGTH = 0x0fffffffu;
102
103 // Limit the locals on a given script so that stack check on baseline frames
104 // doesn't overflow a uint32_t value.
105 // (MAX_JSSCRIPT_SLOTS * sizeof(Value)) must fit within a uint32_t.
106 static const uint32_t MAX_JSSCRIPT_SLOTS = 0xffffu;
107
108 private:
109 // Code pointer containing the actual method.
110 HeapPtr<JitCode> method_;
111
112 // For heavyweight scripts, template objects to use for the call object and
113 // decl env object (linked via the call object's enclosing scope).
114 HeapPtrObject templateScope_;
115
116 // Allocated space for fallback stubs.
117 FallbackICStubSpace fallbackStubSpace_;
118
119 // Native code offset right before the scope chain is initialized.
120 uint32_t prologueOffset_;
121
122 // Native code offset right before the frame is popped and the method
123 // returned from.
124 uint32_t epilogueOffset_;
125
126 // The offsets for the toggledJump instructions for SPS update ICs.
127 #ifdef DEBUG
128 mozilla::DebugOnly<bool> spsOn_;
129 #endif
130 uint32_t spsPushToggleOffset_;
131
132 // Native code offsets right after the debug prologue VM call returns, or
133 // would have returned. This offset is recorded even when debug mode is
134 // off to aid on-stack debug mode recompilation.
135 //
136 // We don't need one for the debug epilogue because that always happens
137 // right before the epilogue, so we just use the epilogue offset.
138 uint32_t postDebugPrologueOffset_;
139
140 public:
141 enum Flag {
142 // Flag set by JSScript::argumentsOptimizationFailed. Similar to
143 // JSScript::needsArgsObj_, but can be read from JIT code.
144 NEEDS_ARGS_OBJ = 1 << 0,
145
146 // Flag set when discarding JIT code, to indicate this script is
147 // on the stack and should not be discarded.
148 ACTIVE = 1 << 1,
149
150 // Flag set when the script contains any writes to its on-stack
151 // (rather than call object stored) arguments.
152 MODIFIES_ARGUMENTS = 1 << 2,
153
154 // Flag set when compiled for use for debug mode. Handles various
155 // Debugger hooks and compiles toggled calls for traps.
156 DEBUG_MODE = 1 << 3
157 };
158
159 private:
160 uint32_t flags_;
161
162 private:
163 void trace(JSTracer *trc);
164
165 uint32_t icEntriesOffset_;
166 uint32_t icEntries_;
167
168 uint32_t pcMappingIndexOffset_;
169 uint32_t pcMappingIndexEntries_;
170
171 uint32_t pcMappingOffset_;
172 uint32_t pcMappingSize_;
173
174 // List mapping indexes of bytecode type sets to the offset of the opcode
175 // they correspond to, for use by TypeScript::BytecodeTypes.
176 uint32_t bytecodeTypeMapOffset_;
177
178 public:
179 // Do not call directly, use BaselineScript::New. This is public for cx->new_.
180 BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
181 uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset);
182
183 static BaselineScript *New(JSContext *cx, uint32_t prologueOffset,
184 uint32_t epilogueOffset, uint32_t postDebugPrologueOffset,
185 uint32_t spsPushToggleOffset, size_t icEntries,
186 size_t pcMappingIndexEntries, size_t pcMappingSize,
187 size_t bytecodeTypeMapEntries);
188 static void Trace(JSTracer *trc, BaselineScript *script);
189 static void Destroy(FreeOp *fop, BaselineScript *script);
190
191 void purgeOptimizedStubs(Zone *zone);
192
193 static inline size_t offsetOfMethod() {
194 return offsetof(BaselineScript, method_);
195 }
196
197 void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t *data,
198 size_t *fallbackStubs) const {
199 *data += mallocSizeOf(this);
200
201 // |data| already includes the ICStubSpace itself, so use
202 // sizeOfExcludingThis.
203 *fallbackStubs += fallbackStubSpace_.sizeOfExcludingThis(mallocSizeOf);
204 }
205
206 bool active() const {
207 return flags_ & ACTIVE;
208 }
209 void setActive() {
210 flags_ |= ACTIVE;
211 }
212 void resetActive() {
213 flags_ &= ~ACTIVE;
214 }
215
216 void setNeedsArgsObj() {
217 flags_ |= NEEDS_ARGS_OBJ;
218 }
219
220 void setModifiesArguments() {
221 flags_ |= MODIFIES_ARGUMENTS;
222 }
223 bool modifiesArguments() {
224 return flags_ & MODIFIES_ARGUMENTS;
225 }
226
227 void setDebugMode() {
228 flags_ |= DEBUG_MODE;
229 }
230 bool debugMode() const {
231 return flags_ & DEBUG_MODE;
232 }
233
234 uint32_t prologueOffset() const {
235 return prologueOffset_;
236 }
237 uint8_t *prologueEntryAddr() const {
238 return method_->raw() + prologueOffset_;
239 }
240
241 uint32_t epilogueOffset() const {
242 return epilogueOffset_;
243 }
244 uint8_t *epilogueEntryAddr() const {
245 return method_->raw() + epilogueOffset_;
246 }
247
248 uint32_t postDebugPrologueOffset() const {
249 return postDebugPrologueOffset_;
250 }
251 uint8_t *postDebugPrologueAddr() const {
252 return method_->raw() + postDebugPrologueOffset_;
253 }
254
255 ICEntry *icEntryList() {
256 return (ICEntry *)(reinterpret_cast<uint8_t *>(this) + icEntriesOffset_);
257 }
258 PCMappingIndexEntry *pcMappingIndexEntryList() {
259 return (PCMappingIndexEntry *)(reinterpret_cast<uint8_t *>(this) + pcMappingIndexOffset_);
260 }
261 uint8_t *pcMappingData() {
262 return reinterpret_cast<uint8_t *>(this) + pcMappingOffset_;
263 }
264 FallbackICStubSpace *fallbackStubSpace() {
265 return &fallbackStubSpace_;
266 }
267
268 JitCode *method() const {
269 return method_;
270 }
271 void setMethod(JitCode *code) {
272 JS_ASSERT(!method_);
273 method_ = code;
274 }
275
276 JSObject *templateScope() const {
277 return templateScope_;
278 }
279 void setTemplateScope(JSObject *templateScope) {
280 JS_ASSERT(!templateScope_);
281 templateScope_ = templateScope;
282 }
283
284 void toggleBarriers(bool enabled) {
285 method()->togglePreBarriers(enabled);
286 }
287
288 bool containsCodeAddress(uint8_t *addr) const {
289 return method()->raw() <= addr && addr <= method()->raw() + method()->instructionsSize();
290 }
291
292 ICEntry &icEntry(size_t index);
293 ICEntry *maybeICEntryFromReturnOffset(CodeOffsetLabel returnOffset);
294 ICEntry &icEntryFromReturnOffset(CodeOffsetLabel returnOffset);
295 ICEntry &icEntryFromPCOffset(uint32_t pcOffset);
296 ICEntry &icEntryForDebugModeRecompileFromPCOffset(uint32_t pcOffset);
297 ICEntry &icEntryFromPCOffset(uint32_t pcOffset, ICEntry *prevLookedUpEntry);
298 ICEntry *maybeICEntryFromReturnAddress(uint8_t *returnAddr);
299 ICEntry &icEntryFromReturnAddress(uint8_t *returnAddr);
300 uint8_t *returnAddressForIC(const ICEntry &ent);
301
302 size_t numICEntries() const {
303 return icEntries_;
304 }
305
306 void copyICEntries(JSScript *script, const ICEntry *entries, MacroAssembler &masm);
307 void adoptFallbackStubs(FallbackICStubSpace *stubSpace);
308
309 PCMappingIndexEntry &pcMappingIndexEntry(size_t index);
310 CompactBufferReader pcMappingReader(size_t indexEntry);
311
312 size_t numPCMappingIndexEntries() const {
313 return pcMappingIndexEntries_;
314 }
315
316 void copyPCMappingIndexEntries(const PCMappingIndexEntry *entries);
317
318 void copyPCMappingEntries(const CompactBufferWriter &entries);
319 uint8_t *nativeCodeForPC(JSScript *script, jsbytecode *pc, PCMappingSlotInfo *slotInfo = nullptr);
320 jsbytecode *pcForReturnOffset(JSScript *script, uint32_t nativeOffset);
321 jsbytecode *pcForReturnAddress(JSScript *script, uint8_t *nativeAddress);
322
323 // Toggle debug traps (used for breakpoints and step mode) in the script.
324 // If |pc| is nullptr, toggle traps for all ops in the script. Else, only
325 // toggle traps at |pc|.
326 void toggleDebugTraps(JSScript *script, jsbytecode *pc);
327
328 void toggleSPS(bool enable);
329
330 void noteAccessedGetter(uint32_t pcOffset);
331 void noteArrayWriteHole(uint32_t pcOffset);
332
333 static size_t offsetOfFlags() {
334 return offsetof(BaselineScript, flags_);
335 }
336
337 static void writeBarrierPre(Zone *zone, BaselineScript *script);
338
339 uint32_t *bytecodeTypeMap() {
340 JS_ASSERT(bytecodeTypeMapOffset_);
341 return reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(this) + bytecodeTypeMapOffset_);
342 }
343 };
344
345 inline bool
346 IsBaselineEnabled(JSContext *cx)
347 {
348 return cx->runtime()->options().baseline();
349 }
350
351 MethodStatus
352 CanEnterBaselineMethod(JSContext *cx, RunState &state);
353
354 MethodStatus
355 CanEnterBaselineAtBranch(JSContext *cx, InterpreterFrame *fp, bool newType);
356
357 IonExecStatus
358 EnterBaselineMethod(JSContext *cx, RunState &state);
359
360 IonExecStatus
361 EnterBaselineAtBranch(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc);
362
363 void
364 FinishDiscardBaselineScript(FreeOp *fop, JSScript *script);
365
366 void
367 AddSizeOfBaselineData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf, size_t *data,
368 size_t *fallbackStubs);
369
370 void
371 ToggleBaselineSPS(JSRuntime *runtime, bool enable);
372
373 struct BaselineBailoutInfo
374 {
375 // Pointer into the current C stack, where overwriting will start.
376 uint8_t *incomingStack;
377
378 // The top and bottom heapspace addresses of the reconstructed stack
379 // which will be copied to the bottom.
380 uint8_t *copyStackTop;
381 uint8_t *copyStackBottom;
382
383 // Fields to store the top-of-stack baseline values that are held
384 // in registers. The setR0 and setR1 fields are flags indicating
385 // whether each one is initialized.
386 uint32_t setR0;
387 Value valueR0;
388 uint32_t setR1;
389 Value valueR1;
390
391 // The value of the frame pointer register on resume.
392 void *resumeFramePtr;
393
394 // The native code address to resume into.
395 void *resumeAddr;
396
397 // If resuming into a TypeMonitor IC chain, this field holds the
398 // address of the first stub in that chain. If this field is
399 // set, then the actual jitcode resumed into is the jitcode for
400 // the first stub, not the resumeAddr above. The resumeAddr
401 // above, in this case, is pushed onto the stack so that the
402 // TypeMonitor chain can tail-return into the main jitcode when done.
403 ICStub *monitorStub;
404
405 // Number of baseline frames to push on the stack.
406 uint32_t numFrames;
407
408 // The bailout kind.
409 BailoutKind bailoutKind;
410 };
411
412 uint32_t
413 BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter,
414 bool invalidate, BaselineBailoutInfo **bailoutInfo,
415 const ExceptionBailoutInfo *exceptionInfo = nullptr);
416
417 // Mark baseline scripts on the stack as active, so that they are not discarded
418 // during GC.
419 void
420 MarkActiveBaselineScripts(Zone *zone);
421
422 MethodStatus
423 BaselineCompile(JSContext *cx, JSScript *script);
424
425 } // namespace jit
426 } // namespace js
427
428 #endif // JS_ION
429
430 #endif /* jit_BaselineJIT_h */

mercurial