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_IonCode_h
8 #define jit_IonCode_h
9
10 #include "mozilla/Atomics.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "mozilla/PodOperations.h"
13
14 #include "jstypes.h"
15
16 #include "gc/Heap.h"
17 #include "jit/ExecutableAllocator.h"
18 #include "jit/ICStubSpace.h"
19 #include "jit/IonOptimizationLevels.h"
20 #include "jit/IonTypes.h"
21 #include "js/UbiNode.h"
22 #include "vm/TraceLogging.h"
23 #include "vm/TypeInference.h"
24
25 namespace js {
26 namespace jit {
27
28 class MacroAssembler;
29 class PatchableBackedge;
30 class IonBuilder;
31 class IonICEntry;
32 class JitCode;
33
34 typedef Vector<JSObject*, 4, JitAllocPolicy> ObjectVector;
35 typedef Vector<TraceLoggerEvent, 0, SystemAllocPolicy> TraceLoggerEventVector;
36
37 // Header at start of raw code buffer
38 struct JitCodeHeader {
39 // Link back to corresponding gcthing
40 JitCode* jitCode_;
41
42 // !!! NOTE !!!
43 // If we are running on AMD Bobcat, insert a NOP-slide at end of the JitCode
44 // header so we can try to recover when the CPU screws up the branch landing
45 // site. See Bug 1281759.
46 void* nops_;
47
48 void init(JitCode* jitCode);
49
FromExecutableJitCodeHeader50 static JitCodeHeader* FromExecutable(uint8_t* buffer) {
51 return (JitCodeHeader*)(buffer - sizeof(JitCodeHeader));
52 }
53 };
54
55 class JitCode : public gc::TenuredCell {
56 protected:
57 uint8_t* code_;
58 ExecutablePool* pool_;
59 uint32_t bufferSize_; // Total buffer size. Does not include headerSize_.
60 uint32_t insnSize_; // Instruction stream size.
61 uint32_t dataSize_; // Size of the read-only data area.
62 uint32_t jumpRelocTableBytes_; // Size of the jump relocation table.
63 uint32_t dataRelocTableBytes_; // Size of the data relocation table.
64 uint8_t headerSize_ : 5; // Number of bytes allocated before codeStart.
65 uint8_t kind_ : 3; // jit::CodeKind, for the memory reporters.
66 bool invalidated_ : 1; // Whether the code object has been invalidated.
67 // This is necessary to prevent GC tracing.
68 bool hasBytecodeMap_ : 1; // Whether the code object has been registered with
69 // native=>bytecode mapping tables.
70
JitCode()71 JitCode() : code_(nullptr), pool_(nullptr) {}
JitCode(uint8_t * code,uint32_t bufferSize,uint32_t headerSize,ExecutablePool * pool,CodeKind kind)72 JitCode(uint8_t* code, uint32_t bufferSize, uint32_t headerSize,
73 ExecutablePool* pool, CodeKind kind)
74 : code_(code),
75 pool_(pool),
76 bufferSize_(bufferSize),
77 insnSize_(0),
78 dataSize_(0),
79 jumpRelocTableBytes_(0),
80 dataRelocTableBytes_(0),
81 headerSize_(headerSize),
82 kind_(uint8_t(kind)),
83 invalidated_(false),
84 hasBytecodeMap_(false) {
85 MOZ_ASSERT(CodeKind(kind_) == kind);
86 MOZ_ASSERT(headerSize_ == headerSize);
87 }
88
dataOffset()89 uint32_t dataOffset() const { return insnSize_; }
jumpRelocTableOffset()90 uint32_t jumpRelocTableOffset() const { return dataOffset() + dataSize_; }
dataRelocTableOffset()91 uint32_t dataRelocTableOffset() const {
92 return jumpRelocTableOffset() + jumpRelocTableBytes_;
93 }
94
95 public:
raw()96 uint8_t* raw() const { return code_; }
rawEnd()97 uint8_t* rawEnd() const { return code_ + insnSize_; }
containsNativePC(const void * addr)98 bool containsNativePC(const void* addr) const {
99 const uint8_t* addr_u8 = (const uint8_t*)addr;
100 return raw() <= addr_u8 && addr_u8 < rawEnd();
101 }
instructionsSize()102 size_t instructionsSize() const { return insnSize_; }
bufferSize()103 size_t bufferSize() const { return bufferSize_; }
headerSize()104 size_t headerSize() const { return headerSize_; }
105
106 void traceChildren(JSTracer* trc);
107 void finalize(FreeOp* fop);
setInvalidated()108 void setInvalidated() { invalidated_ = true; }
109
setHasBytecodeMap()110 void setHasBytecodeMap() { hasBytecodeMap_ = true; }
111
112 void togglePreBarriers(bool enabled, ReprotectCode reprotect);
113
114 // If this JitCode object has been, effectively, corrupted due to
115 // invalidation patching, then we have to remember this so we don't try and
116 // trace relocation entries that may now be corrupt.
invalidated()117 bool invalidated() const { return !!invalidated_; }
118
119 template <typename T>
as()120 T as() const {
121 return JS_DATA_TO_FUNC_PTR(T, raw());
122 }
123
124 void copyFrom(MacroAssembler& masm);
125
FromExecutable(uint8_t * buffer)126 static JitCode* FromExecutable(uint8_t* buffer) {
127 JitCode* code = JitCodeHeader::FromExecutable(buffer)->jitCode_;
128 MOZ_ASSERT(code->raw() == buffer);
129 return code;
130 }
131
offsetOfCode()132 static size_t offsetOfCode() { return offsetof(JitCode, code_); }
133
jumpRelocTable()134 uint8_t* jumpRelocTable() { return code_ + jumpRelocTableOffset(); }
135
136 // Allocates a new JitCode object which will be managed by the GC. If no
137 // object can be allocated, nullptr is returned. On failure, |pool| is
138 // automatically released, so the code may be freed.
139 template <AllowGC allowGC>
140 static JitCode* New(JSContext* cx, uint8_t* code, uint32_t bufferSize,
141 uint32_t headerSize, ExecutablePool* pool, CodeKind kind);
142
143 public:
144 static const JS::TraceKind TraceKind = JS::TraceKind::JitCode;
145 };
146
147 class SnapshotWriter;
148 class RecoverWriter;
149 class SafepointWriter;
150 class SafepointIndex;
151 class OsiIndex;
152 class IonIC;
153 struct PatchableBackedgeInfo;
154
155 // An IonScript attaches Ion-generated information to a JSScript.
156 struct IonScript {
157 private:
158 // Code pointer containing the actual method.
159 PreBarrieredJitCode method_;
160
161 // Entrypoint for OSR, or nullptr.
162 jsbytecode* osrPc_;
163
164 // Offset to OSR entrypoint from method_->raw(), or 0.
165 uint32_t osrEntryOffset_;
166
167 // Offset to entrypoint skipping type arg check from method_->raw().
168 uint32_t skipArgCheckEntryOffset_;
169
170 // Offset of the invalidation epilogue (which pushes this IonScript
171 // and calls the invalidation thunk).
172 uint32_t invalidateEpilogueOffset_;
173
174 // The offset immediately after the IonScript immediate.
175 // NOTE: technically a constant delta from
176 // |invalidateEpilogueOffset_|, so we could hard-code this
177 // per-platform if we want.
178 uint32_t invalidateEpilogueDataOffset_;
179
180 // Number of times this script bailed out without invalidation.
181 uint32_t numBailouts_;
182
183 // Flag set if IonScript was compiled with profiling enabled.
184 bool hasProfilingInstrumentation_;
185
186 // Flag for if this script is getting recompiled.
187 uint32_t recompiling_;
188
189 // Any kind of data needed by the runtime, these can be either cache
190 // information or profiling info.
191 uint32_t runtimeData_;
192 uint32_t runtimeSize_;
193
194 // State for polymorphic caches in the compiled code. All caches are stored
195 // in the runtimeData buffer and indexed by the icIndex which gives a
196 // relative offset in the runtimeData array.
197 uint32_t icIndex_;
198 uint32_t icEntries_;
199
200 // Map code displacement to safepoint / OSI-patch-delta.
201 uint32_t safepointIndexOffset_;
202 uint32_t safepointIndexEntries_;
203
204 // Offset to and length of the safepoint table in bytes.
205 uint32_t safepointsStart_;
206 uint32_t safepointsSize_;
207
208 // Number of bytes this function reserves on the stack.
209 uint32_t frameSlots_;
210
211 // Number of bytes used passed in as formal arguments or |this|.
212 uint32_t argumentSlots_;
213
214 // Frame size is the value that can be added to the StackPointer along
215 // with the frame prefix to get a valid JitFrameLayout.
216 uint32_t frameSize_;
217
218 // Table mapping bailout IDs to snapshot offsets.
219 uint32_t bailoutTable_;
220 uint32_t bailoutEntries_;
221
222 // Map OSI-point displacement to snapshot.
223 uint32_t osiIndexOffset_;
224 uint32_t osiIndexEntries_;
225
226 // Offset from the start of the code buffer to its snapshot buffer.
227 uint32_t snapshots_;
228 uint32_t snapshotsListSize_;
229 uint32_t snapshotsRVATableSize_;
230
231 // List of instructions needed to recover stack frames.
232 uint32_t recovers_;
233 uint32_t recoversSize_;
234
235 // Constant table for constants stored in snapshots.
236 uint32_t constantTable_;
237 uint32_t constantEntries_;
238
239 // List of patchable backedges which are threaded into the runtime's list.
240 uint32_t backedgeList_;
241 uint32_t backedgeEntries_;
242
243 // List of entries to the shared stub.
244 uint32_t sharedStubList_;
245 uint32_t sharedStubEntries_;
246
247 // Number of references from invalidation records.
248 uint32_t invalidationCount_;
249
250 // Identifier of the compilation which produced this code.
251 RecompileInfo recompileInfo_;
252
253 // The optimization level this script was compiled in.
254 OptimizationLevel optimizationLevel_;
255
256 // Number of times we tried to enter this script via OSR but failed due to
257 // a LOOPENTRY pc other than osrPc_.
258 uint32_t osrPcMismatchCounter_;
259
260 // Allocated space for fallback stubs.
261 FallbackICStubSpace fallbackStubSpace_;
262
263 // TraceLogger events that are baked into the IonScript.
264 TraceLoggerEventVector traceLoggerEvents_;
265
266 private:
bottomBufferIonScript267 inline uint8_t* bottomBuffer() { return reinterpret_cast<uint8_t*>(this); }
bottomBufferIonScript268 inline const uint8_t* bottomBuffer() const {
269 return reinterpret_cast<const uint8_t*>(this);
270 }
271
272 public:
bailoutTableIonScript273 SnapshotOffset* bailoutTable() {
274 return (SnapshotOffset*)&bottomBuffer()[bailoutTable_];
275 }
constantsIonScript276 PreBarrieredValue* constants() {
277 return (PreBarrieredValue*)&bottomBuffer()[constantTable_];
278 }
safepointIndicesIonScript279 const SafepointIndex* safepointIndices() const {
280 return const_cast<IonScript*>(this)->safepointIndices();
281 }
safepointIndicesIonScript282 SafepointIndex* safepointIndices() {
283 return (SafepointIndex*)&bottomBuffer()[safepointIndexOffset_];
284 }
osiIndicesIonScript285 const OsiIndex* osiIndices() const {
286 return const_cast<IonScript*>(this)->osiIndices();
287 }
osiIndicesIonScript288 OsiIndex* osiIndices() { return (OsiIndex*)&bottomBuffer()[osiIndexOffset_]; }
icIndexIonScript289 uint32_t* icIndex() { return (uint32_t*)&bottomBuffer()[icIndex_]; }
runtimeDataIonScript290 uint8_t* runtimeData() { return &bottomBuffer()[runtimeData_]; }
backedgeListIonScript291 PatchableBackedge* backedgeList() {
292 return (PatchableBackedge*)&bottomBuffer()[backedgeList_];
293 }
294
295 private:
296 void trace(JSTracer* trc);
297
298 public:
299 // Do not call directly, use IonScript::New. This is public for cx->new_.
300 IonScript();
301
~IonScriptIonScript302 ~IonScript() {
303 // The contents of the fallback stub space are removed and freed
304 // separately after the next minor GC. See IonScript::Destroy.
305 MOZ_ASSERT(fallbackStubSpace_.isEmpty());
306 }
307
308 static IonScript* New(JSContext* cx, RecompileInfo recompileInfo,
309 uint32_t frameSlots, uint32_t argumentSlots,
310 uint32_t frameSize, size_t snapshotsListSize,
311 size_t snapshotsRVATableSize, size_t recoversSize,
312 size_t bailoutEntries, size_t constants,
313 size_t safepointIndexEntries, size_t osiIndexEntries,
314 size_t icEntries, size_t runtimeSize,
315 size_t safepointsSize, size_t backedgeEntries,
316 size_t sharedStubEntries,
317 OptimizationLevel optimizationLevel);
318 static void Trace(JSTracer* trc, IonScript* script);
319 static void Destroy(FreeOp* fop, IonScript* script);
320
offsetOfMethodIonScript321 static inline size_t offsetOfMethod() { return offsetof(IonScript, method_); }
offsetOfOsrEntryOffsetIonScript322 static inline size_t offsetOfOsrEntryOffset() {
323 return offsetof(IonScript, osrEntryOffset_);
324 }
offsetOfSkipArgCheckEntryOffsetIonScript325 static inline size_t offsetOfSkipArgCheckEntryOffset() {
326 return offsetof(IonScript, skipArgCheckEntryOffset_);
327 }
offsetOfInvalidationCountIonScript328 static inline size_t offsetOfInvalidationCount() {
329 return offsetof(IonScript, invalidationCount_);
330 }
offsetOfRecompilingIonScript331 static inline size_t offsetOfRecompiling() {
332 return offsetof(IonScript, recompiling_);
333 }
334
335 public:
methodIonScript336 JitCode* method() const { return method_; }
setMethodIonScript337 void setMethod(JitCode* code) {
338 MOZ_ASSERT(!invalidated());
339 method_ = code;
340 }
setOsrPcIonScript341 void setOsrPc(jsbytecode* osrPc) { osrPc_ = osrPc; }
osrPcIonScript342 jsbytecode* osrPc() const { return osrPc_; }
setOsrEntryOffsetIonScript343 void setOsrEntryOffset(uint32_t offset) {
344 MOZ_ASSERT(!osrEntryOffset_);
345 osrEntryOffset_ = offset;
346 }
osrEntryOffsetIonScript347 uint32_t osrEntryOffset() const { return osrEntryOffset_; }
setSkipArgCheckEntryOffsetIonScript348 void setSkipArgCheckEntryOffset(uint32_t offset) {
349 MOZ_ASSERT(!skipArgCheckEntryOffset_);
350 skipArgCheckEntryOffset_ = offset;
351 }
getSkipArgCheckEntryOffsetIonScript352 uint32_t getSkipArgCheckEntryOffset() const {
353 return skipArgCheckEntryOffset_;
354 }
containsCodeAddressIonScript355 bool containsCodeAddress(uint8_t* addr) const {
356 return method()->raw() <= addr &&
357 addr <= method()->raw() + method()->instructionsSize();
358 }
containsReturnAddressIonScript359 bool containsReturnAddress(uint8_t* addr) const {
360 // This accounts for an off by one error caused by the return address of a
361 // bailout sitting outside the range of the containing function.
362 return method()->raw() <= addr &&
363 addr <= method()->raw() + method()->instructionsSize();
364 }
setInvalidationEpilogueOffsetIonScript365 void setInvalidationEpilogueOffset(uint32_t offset) {
366 MOZ_ASSERT(!invalidateEpilogueOffset_);
367 invalidateEpilogueOffset_ = offset;
368 }
invalidateEpilogueOffsetIonScript369 uint32_t invalidateEpilogueOffset() const {
370 MOZ_ASSERT(invalidateEpilogueOffset_);
371 return invalidateEpilogueOffset_;
372 }
setInvalidationEpilogueDataOffsetIonScript373 void setInvalidationEpilogueDataOffset(uint32_t offset) {
374 MOZ_ASSERT(!invalidateEpilogueDataOffset_);
375 invalidateEpilogueDataOffset_ = offset;
376 }
invalidateEpilogueDataOffsetIonScript377 uint32_t invalidateEpilogueDataOffset() const {
378 MOZ_ASSERT(invalidateEpilogueDataOffset_);
379 return invalidateEpilogueDataOffset_;
380 }
incNumBailoutsIonScript381 void incNumBailouts() { numBailouts_++; }
bailoutExpectedIonScript382 bool bailoutExpected() const {
383 return numBailouts_ >= JitOptions.frequentBailoutThreshold;
384 }
setHasProfilingInstrumentationIonScript385 void setHasProfilingInstrumentation() { hasProfilingInstrumentation_ = true; }
clearHasProfilingInstrumentationIonScript386 void clearHasProfilingInstrumentation() {
387 hasProfilingInstrumentation_ = false;
388 }
hasProfilingInstrumentationIonScript389 bool hasProfilingInstrumentation() const {
390 return hasProfilingInstrumentation_;
391 }
addTraceLoggerEventIonScript392 MOZ_MUST_USE bool addTraceLoggerEvent(TraceLoggerEvent& event) {
393 MOZ_ASSERT(event.hasTextId());
394 return traceLoggerEvents_.append(mozilla::Move(event));
395 }
snapshotsIonScript396 const uint8_t* snapshots() const {
397 return reinterpret_cast<const uint8_t*>(this) + snapshots_;
398 }
snapshotsListSizeIonScript399 size_t snapshotsListSize() const { return snapshotsListSize_; }
snapshotsRVATableSizeIonScript400 size_t snapshotsRVATableSize() const { return snapshotsRVATableSize_; }
recoversIonScript401 const uint8_t* recovers() const {
402 return reinterpret_cast<const uint8_t*>(this) + recovers_;
403 }
recoversSizeIonScript404 size_t recoversSize() const { return recoversSize_; }
safepointsIonScript405 const uint8_t* safepoints() const {
406 return reinterpret_cast<const uint8_t*>(this) + safepointsStart_;
407 }
safepointsSizeIonScript408 size_t safepointsSize() const { return safepointsSize_; }
sizeOfIncludingThisIonScript409 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
410 return mallocSizeOf(this);
411 }
getConstantIonScript412 PreBarrieredValue& getConstant(size_t index) {
413 MOZ_ASSERT(index < numConstants());
414 return constants()[index];
415 }
numConstantsIonScript416 size_t numConstants() const { return constantEntries_; }
frameSlotsIonScript417 uint32_t frameSlots() const { return frameSlots_; }
argumentSlotsIonScript418 uint32_t argumentSlots() const { return argumentSlots_; }
frameSizeIonScript419 uint32_t frameSize() const { return frameSize_; }
bailoutToSnapshotIonScript420 SnapshotOffset bailoutToSnapshot(uint32_t bailoutId) {
421 MOZ_ASSERT(bailoutId < bailoutEntries_);
422 return bailoutTable()[bailoutId];
423 }
424 const SafepointIndex* getSafepointIndex(uint32_t disp) const;
getSafepointIndexIonScript425 const SafepointIndex* getSafepointIndex(uint8_t* retAddr) const {
426 MOZ_ASSERT(containsCodeAddress(retAddr));
427 return getSafepointIndex(retAddr - method()->raw());
428 }
429 const OsiIndex* getOsiIndex(uint32_t disp) const;
430 const OsiIndex* getOsiIndex(uint8_t* retAddr) const;
431
getICFromIndexIonScript432 IonIC& getICFromIndex(uint32_t index) {
433 MOZ_ASSERT(index < icEntries_);
434 uint32_t offset = icIndex()[index];
435 return getIC(offset);
436 }
getICIonScript437 inline IonIC& getIC(uint32_t offset) {
438 MOZ_ASSERT(offset < runtimeSize_);
439 return *(IonIC*)&runtimeData()[offset];
440 }
numICsIonScript441 size_t numICs() const { return icEntries_; }
sharedStubListIonScript442 IonICEntry* sharedStubList() {
443 return (IonICEntry*)&bottomBuffer()[sharedStubList_];
444 }
numSharedStubsIonScript445 size_t numSharedStubs() const { return sharedStubEntries_; }
runtimeSizeIonScript446 size_t runtimeSize() const { return runtimeSize_; }
447 void purgeICs(Zone* zone);
448 void unlinkFromRuntime(FreeOp* fop);
449 void copySnapshots(const SnapshotWriter* writer);
450 void copyRecovers(const RecoverWriter* writer);
451 void copyBailoutTable(const SnapshotOffset* table);
452 void copyConstants(const Value* vp);
453 void copySafepointIndices(const SafepointIndex* firstSafepointIndex);
454 void copyOsiIndices(const OsiIndex* firstOsiIndex);
455 void copyRuntimeData(const uint8_t* data);
456 void copyICEntries(const uint32_t* caches, MacroAssembler& masm);
457 void copySafepoints(const SafepointWriter* writer);
458 void copyPatchableBackedges(JSContext* cx, JitCode* code,
459 PatchableBackedgeInfo* backedges,
460 MacroAssembler& masm);
461
invalidatedIonScript462 bool invalidated() const { return invalidationCount_ != 0; }
463
464 // Invalidate the current compilation.
465 void invalidate(JSContext* cx, bool resetUses, const char* reason);
466
invalidationCountIonScript467 size_t invalidationCount() const { return invalidationCount_; }
incrementInvalidationCountIonScript468 void incrementInvalidationCount() { invalidationCount_++; }
decrementInvalidationCountIonScript469 void decrementInvalidationCount(FreeOp* fop) {
470 MOZ_ASSERT(invalidationCount_);
471 invalidationCount_--;
472 if (!invalidationCount_) Destroy(fop, this);
473 }
recompileInfoIonScript474 const RecompileInfo& recompileInfo() const { return recompileInfo_; }
recompileInfoRefIonScript475 RecompileInfo& recompileInfoRef() { return recompileInfo_; }
optimizationLevelIonScript476 OptimizationLevel optimizationLevel() const { return optimizationLevel_; }
incrOsrPcMismatchCounterIonScript477 uint32_t incrOsrPcMismatchCounter() { return ++osrPcMismatchCounter_; }
resetOsrPcMismatchCounterIonScript478 void resetOsrPcMismatchCounter() { osrPcMismatchCounter_ = 0; }
479
setRecompilingIonScript480 void setRecompiling() { recompiling_ = true; }
481
isRecompilingIonScript482 bool isRecompiling() const { return recompiling_; }
483
clearRecompilingIonScript484 void clearRecompiling() { recompiling_ = false; }
485
fallbackStubSpaceIonScript486 FallbackICStubSpace* fallbackStubSpace() { return &fallbackStubSpace_; }
487 void adoptFallbackStubs(FallbackICStubSpace* stubSpace);
488 void purgeOptimizedStubs(Zone* zone);
489
490 enum ShouldIncreaseAge { IncreaseAge = true, KeepAge = false };
491
492 static void writeBarrierPre(Zone* zone, IonScript* ionScript);
493 };
494
495 // Execution information for a basic block which may persist after the
496 // accompanying IonScript is destroyed, for use during profiling.
497 struct IonBlockCounts {
498 private:
499 uint32_t id_;
500
501 // Approximate bytecode in the outer (not inlined) script this block
502 // was generated from.
503 uint32_t offset_;
504
505 // File and line of the inner script this block was generated from.
506 char* description_;
507
508 // ids for successors of this block.
509 uint32_t numSuccessors_;
510 uint32_t* successors_;
511
512 // Hit count for this block.
513 uint64_t hitCount_;
514
515 // Text information about the code generated for this block.
516 char* code_;
517
518 public:
initIonBlockCounts519 MOZ_MUST_USE bool init(uint32_t id, uint32_t offset, char* description,
520 uint32_t numSuccessors) {
521 id_ = id;
522 offset_ = offset;
523 description_ = description;
524 numSuccessors_ = numSuccessors;
525 if (numSuccessors) {
526 successors_ = js_pod_calloc<uint32_t>(numSuccessors);
527 if (!successors_) return false;
528 }
529 return true;
530 }
531
destroyIonBlockCounts532 void destroy() {
533 js_free(description_);
534 js_free(successors_);
535 js_free(code_);
536 }
537
idIonBlockCounts538 uint32_t id() const { return id_; }
539
offsetIonBlockCounts540 uint32_t offset() const { return offset_; }
541
descriptionIonBlockCounts542 const char* description() const { return description_; }
543
numSuccessorsIonBlockCounts544 size_t numSuccessors() const { return numSuccessors_; }
545
setSuccessorIonBlockCounts546 void setSuccessor(size_t i, uint32_t id) {
547 MOZ_ASSERT(i < numSuccessors_);
548 successors_[i] = id;
549 }
550
successorIonBlockCounts551 uint32_t successor(size_t i) const {
552 MOZ_ASSERT(i < numSuccessors_);
553 return successors_[i];
554 }
555
addressOfHitCountIonBlockCounts556 uint64_t* addressOfHitCount() { return &hitCount_; }
557
hitCountIonBlockCounts558 uint64_t hitCount() const { return hitCount_; }
559
setCodeIonBlockCounts560 void setCode(const char* code) {
561 char* ncode = js_pod_malloc<char>(strlen(code) + 1);
562 if (ncode) {
563 strcpy(ncode, code);
564 code_ = ncode;
565 }
566 }
567
codeIonBlockCounts568 const char* code() const { return code_; }
569
sizeOfExcludingThisIonBlockCounts570 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
571 return mallocSizeOf(description_) + mallocSizeOf(successors_) +
572 mallocSizeOf(code_);
573 }
574 };
575
576 // Execution information for a compiled script which may persist after the
577 // IonScript is destroyed, for use during profiling.
578 struct IonScriptCounts {
579 private:
580 // Any previous invalidated compilation(s) for the script.
581 IonScriptCounts* previous_;
582
583 // Information about basic blocks in this script.
584 size_t numBlocks_;
585 IonBlockCounts* blocks_;
586
587 public:
IonScriptCountsIonScriptCounts588 IonScriptCounts() { mozilla::PodZero(this); }
589
~IonScriptCountsIonScriptCounts590 ~IonScriptCounts() {
591 for (size_t i = 0; i < numBlocks_; i++) blocks_[i].destroy();
592 js_free(blocks_);
593 // The list can be long in some corner cases (bug 1140084), so
594 // unroll the recursion.
595 IonScriptCounts* victims = previous_;
596 while (victims) {
597 IonScriptCounts* victim = victims;
598 victims = victim->previous_;
599 victim->previous_ = nullptr;
600 js_delete(victim);
601 }
602 }
603
initIonScriptCounts604 MOZ_MUST_USE bool init(size_t numBlocks) {
605 blocks_ = js_pod_calloc<IonBlockCounts>(numBlocks);
606 if (!blocks_) return false;
607
608 numBlocks_ = numBlocks;
609 return true;
610 }
611
numBlocksIonScriptCounts612 size_t numBlocks() const { return numBlocks_; }
613
blockIonScriptCounts614 IonBlockCounts& block(size_t i) {
615 MOZ_ASSERT(i < numBlocks_);
616 return blocks_[i];
617 }
618
setPreviousIonScriptCounts619 void setPrevious(IonScriptCounts* previous) { previous_ = previous; }
620
previousIonScriptCounts621 IonScriptCounts* previous() const { return previous_; }
622
sizeOfIncludingThisIonScriptCounts623 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
624 size_t size = 0;
625 auto currCounts = this;
626 while (currCounts) {
627 const IonScriptCounts* currCount = currCounts;
628 currCounts = currCount->previous_;
629 size += currCount->sizeOfOneIncludingThis(mallocSizeOf);
630 }
631 return size;
632 }
633
sizeOfOneIncludingThisIonScriptCounts634 size_t sizeOfOneIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
635 size_t size = mallocSizeOf(this) + mallocSizeOf(blocks_);
636 for (size_t i = 0; i < numBlocks_; i++)
637 blocks_[i].sizeOfExcludingThis(mallocSizeOf);
638 return size;
639 }
640 };
641
642 struct VMFunction;
643
644 struct AutoFlushICache {
645 private:
646 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
647 defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
648 uintptr_t start_;
649 uintptr_t stop_;
650 #ifdef JS_JITSPEW
651 const char* name_;
652 #endif
653 bool inhibit_;
654 AutoFlushICache* prev_;
655 #endif
656
657 public:
658 static void setRange(uintptr_t p, size_t len);
659 static void flush(uintptr_t p, size_t len);
660 static void setInhibit();
661 ~AutoFlushICache();
662 explicit AutoFlushICache(const char* nonce, bool inhibit = false);
663 };
664
665 } // namespace jit
666
667 namespace gc {
668
IsMarked(JSRuntime * rt,const jit::VMFunction *)669 inline bool IsMarked(JSRuntime* rt, const jit::VMFunction*) {
670 // VMFunction are only static objects which are used by WeakMaps as keys.
671 // It is considered as a root object which is always marked.
672 return true;
673 }
674
675 } // namespace gc
676
677 } // namespace js
678
679 // JS::ubi::Nodes can point to js::jit::JitCode instances; they're js::gc::Cell
680 // instances with no associated compartment.
681 namespace JS {
682 namespace ubi {
683 template <>
684 class Concrete<js::jit::JitCode> : TracerConcrete<js::jit::JitCode> {
685 protected:
Concrete(js::jit::JitCode * ptr)686 explicit Concrete(js::jit::JitCode* ptr)
687 : TracerConcrete<js::jit::JitCode>(ptr) {}
688
689 public:
construct(void * storage,js::jit::JitCode * ptr)690 static void construct(void* storage, js::jit::JitCode* ptr) {
691 new (storage) Concrete(ptr);
692 }
693
coarseType()694 CoarseType coarseType() const final { return CoarseType::Script; }
695
size(mozilla::MallocSizeOf mallocSizeOf)696 Size size(mozilla::MallocSizeOf mallocSizeOf) const override {
697 Size size = js::gc::Arena::thingSize(get().asTenured().getAllocKind());
698 size += get().bufferSize();
699 size += get().headerSize();
700 return size;
701 }
702
typeName()703 const char16_t* typeName() const override { return concreteTypeName; }
704 static const char16_t concreteTypeName[];
705 };
706
707 } // namespace ubi
708
709 template <>
710 struct DeletePolicy<js::jit::IonScript> {
711 explicit DeletePolicy(JSRuntime* rt) : rt_(rt) {}
712 void operator()(const js::jit::IonScript* script);
713
714 private:
715 JSRuntime* rt_;
716 };
717
718 } // namespace JS
719
720 #endif /* jit_IonCode_h */
721