Line data Source code
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 :
33 : typedef Vector<JSObject*, 4, JitAllocPolicy> ObjectVector;
34 : typedef Vector<TraceLoggerEvent, 0, SystemAllocPolicy> TraceLoggerEventVector;
35 :
36 : class JitCode : public gc::TenuredCell
37 : {
38 : protected:
39 : uint8_t* code_;
40 : ExecutablePool* pool_;
41 : uint32_t bufferSize_; // Total buffer size. Does not include headerSize_.
42 : uint32_t insnSize_; // Instruction stream size.
43 : uint32_t dataSize_; // Size of the read-only data area.
44 : uint32_t jumpRelocTableBytes_; // Size of the jump relocation table.
45 : uint32_t dataRelocTableBytes_; // Size of the data relocation table.
46 : uint8_t headerSize_ : 5; // Number of bytes allocated before codeStart.
47 : uint8_t kind_ : 3; // jit::CodeKind, for the memory reporters.
48 : bool invalidated_ : 1; // Whether the code object has been invalidated.
49 : // This is necessary to prevent GC tracing.
50 : bool hasBytecodeMap_ : 1; // Whether the code object has been registered with
51 : // native=>bytecode mapping tables.
52 :
53 : JitCode()
54 : : code_(nullptr),
55 : pool_(nullptr)
56 : { }
57 4499 : JitCode(uint8_t* code, uint32_t bufferSize, uint32_t headerSize, ExecutablePool* pool,
58 : CodeKind kind)
59 4499 : : code_(code),
60 : pool_(pool),
61 : bufferSize_(bufferSize),
62 : insnSize_(0),
63 : dataSize_(0),
64 : jumpRelocTableBytes_(0),
65 : dataRelocTableBytes_(0),
66 : headerSize_(headerSize),
67 : kind_(kind),
68 : invalidated_(false),
69 4499 : hasBytecodeMap_(false)
70 : {
71 4499 : MOZ_ASSERT(CodeKind(kind_) == kind);
72 4499 : MOZ_ASSERT(headerSize_ == headerSize);
73 4499 : }
74 :
75 9035 : uint32_t dataOffset() const {
76 9035 : return insnSize_;
77 : }
78 9035 : uint32_t jumpRelocTableOffset() const {
79 9035 : return dataOffset() + dataSize_;
80 : }
81 4501 : uint32_t dataRelocTableOffset() const {
82 4501 : return jumpRelocTableOffset() + jumpRelocTableBytes_;
83 : }
84 :
85 : public:
86 161702 : uint8_t* raw() const {
87 161702 : return code_;
88 : }
89 632 : uint8_t* rawEnd() const {
90 632 : return code_ + insnSize_;
91 : }
92 0 : bool containsNativePC(const void* addr) const {
93 0 : const uint8_t* addr_u8 = (const uint8_t*) addr;
94 0 : return raw() <= addr_u8 && addr_u8 < rawEnd();
95 : }
96 47748 : size_t instructionsSize() const {
97 47748 : return insnSize_;
98 : }
99 0 : size_t bufferSize() const {
100 0 : return bufferSize_;
101 : }
102 0 : size_t headerSize() const {
103 0 : return headerSize_;
104 : }
105 :
106 : void traceChildren(JSTracer* trc);
107 : void finalize(FreeOp* fop);
108 0 : void setInvalidated() {
109 0 : invalidated_ = true;
110 0 : }
111 :
112 632 : void setHasBytecodeMap() {
113 632 : hasBytecodeMap_ = true;
114 632 : }
115 :
116 : void togglePreBarriers(bool enabled, ReprotectCode reprotect);
117 :
118 : // If this JitCode object has been, effectively, corrupted due to
119 : // invalidation patching, then we have to remember this so we don't try and
120 : // trace relocation entries that may now be corrupt.
121 22 : bool invalidated() const {
122 22 : return !!invalidated_;
123 : }
124 :
125 7673 : template <typename T> T as() const {
126 7673 : return JS_DATA_TO_FUNC_PTR(T, raw());
127 : }
128 :
129 : void copyFrom(MacroAssembler& masm);
130 :
131 370 : static JitCode* FromExecutable(uint8_t* buffer) {
132 370 : JitCode* code = *(JitCode**)(buffer - sizeof(JitCode*));
133 370 : MOZ_ASSERT(code->raw() == buffer);
134 370 : return code;
135 : }
136 :
137 73 : static size_t offsetOfCode() {
138 73 : return offsetof(JitCode, code_);
139 : }
140 :
141 21 : uint8_t* jumpRelocTable() {
142 21 : return code_ + jumpRelocTableOffset();
143 : }
144 :
145 : // Allocates a new JitCode object which will be managed by the GC. If no
146 : // object can be allocated, nullptr is returned. On failure, |pool| is
147 : // automatically released, so the code may be freed.
148 : template <AllowGC allowGC>
149 : static JitCode* New(JSContext* cx, uint8_t* code, uint32_t bufferSize, uint32_t headerSize,
150 : ExecutablePool* pool, CodeKind kind);
151 :
152 : public:
153 : static const JS::TraceKind TraceKind = JS::TraceKind::JitCode;
154 : };
155 :
156 : class SnapshotWriter;
157 : class RecoverWriter;
158 : class SafepointWriter;
159 : class SafepointIndex;
160 : class OsiIndex;
161 : class IonIC;
162 : struct PatchableBackedgeInfo;
163 :
164 : // An IonScript attaches Ion-generated information to a JSScript.
165 : struct IonScript
166 : {
167 : private:
168 : // Code pointer containing the actual method.
169 : PreBarrieredJitCode method_;
170 :
171 : // Deoptimization table used by this method.
172 : PreBarrieredJitCode deoptTable_;
173 :
174 : // Entrypoint for OSR, or nullptr.
175 : jsbytecode* osrPc_;
176 :
177 : // Offset to OSR entrypoint from method_->raw(), or 0.
178 : uint32_t osrEntryOffset_;
179 :
180 : // Offset to entrypoint skipping type arg check from method_->raw().
181 : uint32_t skipArgCheckEntryOffset_;
182 :
183 : // Offset of the invalidation epilogue (which pushes this IonScript
184 : // and calls the invalidation thunk).
185 : uint32_t invalidateEpilogueOffset_;
186 :
187 : // The offset immediately after the IonScript immediate.
188 : // NOTE: technically a constant delta from
189 : // |invalidateEpilogueOffset_|, so we could hard-code this
190 : // per-platform if we want.
191 : uint32_t invalidateEpilogueDataOffset_;
192 :
193 : // Number of times this script bailed out without invalidation.
194 : uint32_t numBailouts_;
195 :
196 : // Flag set if IonScript was compiled with profiling enabled.
197 : bool hasProfilingInstrumentation_;
198 :
199 : // Flag for if this script is getting recompiled.
200 : uint32_t recompiling_;
201 :
202 : // Any kind of data needed by the runtime, these can be either cache
203 : // information or profiling info.
204 : uint32_t runtimeData_;
205 : uint32_t runtimeSize_;
206 :
207 : // State for polymorphic caches in the compiled code. All caches are stored
208 : // in the runtimeData buffer and indexed by the icIndex which gives a
209 : // relative offset in the runtimeData array.
210 : uint32_t icIndex_;
211 : uint32_t icEntries_;
212 :
213 : // Map code displacement to safepoint / OSI-patch-delta.
214 : uint32_t safepointIndexOffset_;
215 : uint32_t safepointIndexEntries_;
216 :
217 : // Offset to and length of the safepoint table in bytes.
218 : uint32_t safepointsStart_;
219 : uint32_t safepointsSize_;
220 :
221 : // Number of bytes this function reserves on the stack.
222 : uint32_t frameSlots_;
223 :
224 : // Number of bytes used passed in as formal arguments or |this|.
225 : uint32_t argumentSlots_;
226 :
227 : // Frame size is the value that can be added to the StackPointer along
228 : // with the frame prefix to get a valid JitFrameLayout.
229 : uint32_t frameSize_;
230 :
231 : // Table mapping bailout IDs to snapshot offsets.
232 : uint32_t bailoutTable_;
233 : uint32_t bailoutEntries_;
234 :
235 : // Map OSI-point displacement to snapshot.
236 : uint32_t osiIndexOffset_;
237 : uint32_t osiIndexEntries_;
238 :
239 : // Offset from the start of the code buffer to its snapshot buffer.
240 : uint32_t snapshots_;
241 : uint32_t snapshotsListSize_;
242 : uint32_t snapshotsRVATableSize_;
243 :
244 : // List of instructions needed to recover stack frames.
245 : uint32_t recovers_;
246 : uint32_t recoversSize_;
247 :
248 : // Constant table for constants stored in snapshots.
249 : uint32_t constantTable_;
250 : uint32_t constantEntries_;
251 :
252 : // List of patchable backedges which are threaded into the runtime's list.
253 : uint32_t backedgeList_;
254 : uint32_t backedgeEntries_;
255 :
256 : // List of entries to the shared stub.
257 : uint32_t sharedStubList_;
258 : uint32_t sharedStubEntries_;
259 :
260 : // Number of references from invalidation records.
261 : uint32_t invalidationCount_;
262 :
263 : // Identifier of the compilation which produced this code.
264 : RecompileInfo recompileInfo_;
265 :
266 : // The optimization level this script was compiled in.
267 : OptimizationLevel optimizationLevel_;
268 :
269 : // Number of times we tried to enter this script via OSR but failed due to
270 : // a LOOPENTRY pc other than osrPc_.
271 : uint32_t osrPcMismatchCounter_;
272 :
273 : // Allocated space for fallback stubs.
274 : FallbackICStubSpace fallbackStubSpace_;
275 :
276 : // TraceLogger events that are baked into the IonScript.
277 : TraceLoggerEventVector traceLoggerEvents_;
278 :
279 : private:
280 2608 : inline uint8_t* bottomBuffer() {
281 2608 : return reinterpret_cast<uint8_t*>(this);
282 : }
283 : inline const uint8_t* bottomBuffer() const {
284 : return reinterpret_cast<const uint8_t*>(this);
285 : }
286 :
287 : public:
288 :
289 0 : SnapshotOffset* bailoutTable() {
290 0 : return (SnapshotOffset*) &bottomBuffer()[bailoutTable_];
291 : }
292 15 : PreBarrieredValue* constants() {
293 15 : return (PreBarrieredValue*) &bottomBuffer()[constantTable_];
294 : }
295 840 : const SafepointIndex* safepointIndices() const {
296 840 : return const_cast<IonScript*>(this)->safepointIndices();
297 : }
298 844 : SafepointIndex* safepointIndices() {
299 844 : return (SafepointIndex*) &bottomBuffer()[safepointIndexOffset_];
300 : }
301 1680 : const OsiIndex* osiIndices() const {
302 1680 : return const_cast<IonScript*>(this)->osiIndices();
303 : }
304 1685 : OsiIndex* osiIndices() {
305 1685 : return (OsiIndex*) &bottomBuffer()[osiIndexOffset_];
306 : }
307 32 : uint32_t* icIndex() {
308 32 : return (uint32_t*) &bottomBuffer()[icIndex_];
309 : }
310 32 : uint8_t* runtimeData() {
311 32 : return &bottomBuffer()[runtimeData_];
312 : }
313 0 : PatchableBackedge* backedgeList() {
314 0 : return (PatchableBackedge*) &bottomBuffer()[backedgeList_];
315 : }
316 :
317 : private:
318 : void trace(JSTracer* trc);
319 :
320 : public:
321 : // Do not call directly, use IonScript::New. This is public for cx->new_.
322 : IonScript();
323 :
324 10 : ~IonScript() {
325 : // The contents of the fallback stub space are removed and freed
326 : // separately after the next minor GC. See IonScript::Destroy.
327 5 : MOZ_ASSERT(fallbackStubSpace_.isEmpty());
328 5 : }
329 :
330 : static IonScript* New(JSContext* cx, RecompileInfo recompileInfo,
331 : uint32_t frameSlots, uint32_t argumentSlots, uint32_t frameSize,
332 : size_t snapshotsListSize, size_t snapshotsRVATableSize,
333 : size_t recoversSize, size_t bailoutEntries,
334 : size_t constants, size_t safepointIndexEntries,
335 : size_t osiIndexEntries, size_t icEntries,
336 : size_t runtimeSize, size_t safepointsSize,
337 : size_t backedgeEntries, size_t sharedStubEntries,
338 : OptimizationLevel optimizationLevel);
339 : static void Trace(JSTracer* trc, IonScript* script);
340 : static void Destroy(FreeOp* fop, IonScript* script);
341 :
342 : static inline size_t offsetOfMethod() {
343 : return offsetof(IonScript, method_);
344 : }
345 : static inline size_t offsetOfOsrEntryOffset() {
346 : return offsetof(IonScript, osrEntryOffset_);
347 : }
348 : static inline size_t offsetOfSkipArgCheckEntryOffset() {
349 : return offsetof(IonScript, skipArgCheckEntryOffset_);
350 : }
351 368 : static inline size_t offsetOfInvalidationCount() {
352 368 : return offsetof(IonScript, invalidationCount_);
353 : }
354 6 : static inline size_t offsetOfRecompiling() {
355 6 : return offsetof(IonScript, recompiling_);
356 : }
357 :
358 : public:
359 58891 : JitCode* method() const {
360 58891 : return method_;
361 : }
362 5 : void setMethod(JitCode* code) {
363 5 : MOZ_ASSERT(!invalidated());
364 5 : method_ = code;
365 5 : }
366 5 : void setDeoptTable(JitCode* code) {
367 5 : deoptTable_ = code;
368 5 : }
369 5 : void setOsrPc(jsbytecode* osrPc) {
370 5 : osrPc_ = osrPc;
371 5 : }
372 4 : jsbytecode* osrPc() const {
373 4 : return osrPc_;
374 : }
375 5 : void setOsrEntryOffset(uint32_t offset) {
376 5 : MOZ_ASSERT(!osrEntryOffset_);
377 5 : osrEntryOffset_ = offset;
378 5 : }
379 1 : uint32_t osrEntryOffset() const {
380 1 : return osrEntryOffset_;
381 : }
382 5 : void setSkipArgCheckEntryOffset(uint32_t offset) {
383 5 : MOZ_ASSERT(!skipArgCheckEntryOffset_);
384 5 : skipArgCheckEntryOffset_ = offset;
385 5 : }
386 5 : uint32_t getSkipArgCheckEntryOffset() const {
387 5 : return skipArgCheckEntryOffset_;
388 : }
389 840 : bool containsCodeAddress(uint8_t* addr) const {
390 840 : return method()->raw() <= addr && addr <= method()->raw() + method()->instructionsSize();
391 : }
392 18480 : bool containsReturnAddress(uint8_t* addr) const {
393 : // This accounts for an off by one error caused by the return address of a
394 : // bailout sitting outside the range of the containing function.
395 18480 : return method()->raw() <= addr && addr <= method()->raw() + method()->instructionsSize();
396 : }
397 5 : void setInvalidationEpilogueOffset(uint32_t offset) {
398 5 : MOZ_ASSERT(!invalidateEpilogueOffset_);
399 5 : invalidateEpilogueOffset_ = offset;
400 5 : }
401 0 : uint32_t invalidateEpilogueOffset() const {
402 0 : MOZ_ASSERT(invalidateEpilogueOffset_);
403 0 : return invalidateEpilogueOffset_;
404 : }
405 5 : void setInvalidationEpilogueDataOffset(uint32_t offset) {
406 5 : MOZ_ASSERT(!invalidateEpilogueDataOffset_);
407 5 : invalidateEpilogueDataOffset_ = offset;
408 5 : }
409 0 : uint32_t invalidateEpilogueDataOffset() const {
410 0 : MOZ_ASSERT(invalidateEpilogueDataOffset_);
411 0 : return invalidateEpilogueDataOffset_;
412 : }
413 0 : void incNumBailouts() {
414 0 : numBailouts_++;
415 0 : }
416 35 : bool bailoutExpected() const {
417 35 : return numBailouts_ >= JitOptions.frequentBailoutThreshold;
418 : }
419 0 : void setHasProfilingInstrumentation() {
420 0 : hasProfilingInstrumentation_ = true;
421 0 : }
422 : void clearHasProfilingInstrumentation() {
423 : hasProfilingInstrumentation_ = false;
424 : }
425 1 : bool hasProfilingInstrumentation() const {
426 1 : return hasProfilingInstrumentation_;
427 : }
428 0 : MOZ_MUST_USE bool addTraceLoggerEvent(TraceLoggerEvent& event) {
429 0 : MOZ_ASSERT(event.hasTextId());
430 0 : return traceLoggerEvents_.append(Move(event));
431 : }
432 840 : const uint8_t* snapshots() const {
433 840 : return reinterpret_cast<const uint8_t*>(this) + snapshots_;
434 : }
435 840 : size_t snapshotsListSize() const {
436 840 : return snapshotsListSize_;
437 : }
438 840 : size_t snapshotsRVATableSize() const {
439 840 : return snapshotsRVATableSize_;
440 : }
441 840 : const uint8_t* recovers() const {
442 840 : return reinterpret_cast<const uint8_t*>(this) + recovers_;
443 : }
444 840 : size_t recoversSize() const {
445 840 : return recoversSize_;
446 : }
447 3360 : const uint8_t* safepoints() const {
448 3360 : return reinterpret_cast<const uint8_t*>(this) + safepointsStart_;
449 : }
450 1680 : size_t safepointsSize() const {
451 1680 : return safepointsSize_;
452 : }
453 0 : size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
454 0 : return mallocSizeOf(this);
455 : }
456 0 : PreBarrieredValue& getConstant(size_t index) {
457 0 : MOZ_ASSERT(index < numConstants());
458 0 : return constants()[index];
459 : }
460 0 : size_t numConstants() const {
461 0 : return constantEntries_;
462 : }
463 1680 : uint32_t frameSlots() const {
464 1680 : return frameSlots_;
465 : }
466 1680 : uint32_t argumentSlots() const {
467 1680 : return argumentSlots_;
468 : }
469 861 : uint32_t frameSize() const {
470 861 : return frameSize_;
471 : }
472 : SnapshotOffset bailoutToSnapshot(uint32_t bailoutId) {
473 : MOZ_ASSERT(bailoutId < bailoutEntries_);
474 : return bailoutTable()[bailoutId];
475 : }
476 : const SafepointIndex* getSafepointIndex(uint32_t disp) const;
477 840 : const SafepointIndex* getSafepointIndex(uint8_t* retAddr) const {
478 840 : MOZ_ASSERT(containsCodeAddress(retAddr));
479 840 : return getSafepointIndex(retAddr - method()->raw());
480 : }
481 : const OsiIndex* getOsiIndex(uint32_t disp) const;
482 : const OsiIndex* getOsiIndex(uint8_t* retAddr) const;
483 :
484 28 : IonIC& getICFromIndex(uint32_t index) {
485 28 : MOZ_ASSERT(index < icEntries_);
486 28 : uint32_t offset = icIndex()[index];
487 28 : return getIC(offset);
488 : }
489 28 : inline IonIC& getIC(uint32_t offset) {
490 28 : MOZ_ASSERT(offset < runtimeSize_);
491 28 : return *(IonIC*) &runtimeData()[offset];
492 : }
493 22 : size_t numICs() const {
494 22 : return icEntries_;
495 : }
496 0 : IonICEntry* sharedStubList() {
497 0 : return (IonICEntry*) &bottomBuffer()[sharedStubList_];
498 : }
499 0 : size_t numSharedStubs() const {
500 0 : return sharedStubEntries_;
501 : }
502 4 : size_t runtimeSize() const {
503 4 : return runtimeSize_;
504 : }
505 : void purgeICs(Zone* zone);
506 : void unlinkFromRuntime(FreeOp* fop);
507 : void copySnapshots(const SnapshotWriter* writer);
508 : void copyRecovers(const RecoverWriter* writer);
509 : void copyBailoutTable(const SnapshotOffset* table);
510 : void copyConstants(const Value* vp);
511 : void copySafepointIndices(const SafepointIndex* firstSafepointIndex, MacroAssembler& masm);
512 : void copyOsiIndices(const OsiIndex* firstOsiIndex, MacroAssembler& masm);
513 : void copyRuntimeData(const uint8_t* data);
514 : void copyICEntries(const uint32_t* caches, MacroAssembler& masm);
515 : void copySafepoints(const SafepointWriter* writer);
516 : void copyPatchableBackedges(JSContext* cx, JitCode* code,
517 : PatchableBackedgeInfo* backedges,
518 : MacroAssembler& masm);
519 :
520 51 : bool invalidated() const {
521 51 : return invalidationCount_ != 0;
522 : }
523 :
524 : // Invalidate the current compilation.
525 : void invalidate(JSContext* cx, bool resetUses, const char* reason);
526 :
527 0 : size_t invalidationCount() const {
528 0 : return invalidationCount_;
529 : }
530 0 : void incrementInvalidationCount() {
531 0 : invalidationCount_++;
532 0 : }
533 0 : void decrementInvalidationCount(FreeOp* fop) {
534 0 : MOZ_ASSERT(invalidationCount_);
535 0 : invalidationCount_--;
536 0 : if (!invalidationCount_)
537 0 : Destroy(fop, this);
538 0 : }
539 5 : const RecompileInfo& recompileInfo() const {
540 5 : return recompileInfo_;
541 : }
542 0 : RecompileInfo& recompileInfoRef() {
543 0 : return recompileInfo_;
544 : }
545 35 : OptimizationLevel optimizationLevel() const {
546 35 : return optimizationLevel_;
547 : }
548 0 : uint32_t incrOsrPcMismatchCounter() {
549 0 : return ++osrPcMismatchCounter_;
550 : }
551 0 : void resetOsrPcMismatchCounter() {
552 0 : osrPcMismatchCounter_ = 0;
553 0 : }
554 :
555 0 : void setRecompiling() {
556 0 : recompiling_ = true;
557 0 : }
558 :
559 0 : bool isRecompiling() const {
560 0 : return recompiling_;
561 : }
562 :
563 5 : void clearRecompiling() {
564 5 : recompiling_ = false;
565 5 : }
566 :
567 5 : FallbackICStubSpace* fallbackStubSpace() {
568 5 : return &fallbackStubSpace_;
569 : }
570 : void adoptFallbackStubs(FallbackICStubSpace* stubSpace);
571 : void purgeOptimizedStubs(Zone* zone);
572 :
573 : enum ShouldIncreaseAge {
574 : IncreaseAge = true,
575 : KeepAge = false
576 : };
577 :
578 : static void writeBarrierPre(Zone* zone, IonScript* ionScript);
579 : };
580 :
581 : // Execution information for a basic block which may persist after the
582 : // accompanying IonScript is destroyed, for use during profiling.
583 : struct IonBlockCounts
584 : {
585 : private:
586 : uint32_t id_;
587 :
588 : // Approximate bytecode in the outer (not inlined) script this block
589 : // was generated from.
590 : uint32_t offset_;
591 :
592 : // File and line of the inner script this block was generated from.
593 : char* description_;
594 :
595 : // ids for successors of this block.
596 : uint32_t numSuccessors_;
597 : uint32_t* successors_;
598 :
599 : // Hit count for this block.
600 : uint64_t hitCount_;
601 :
602 : // Text information about the code generated for this block.
603 : char* code_;
604 :
605 : public:
606 :
607 0 : MOZ_MUST_USE bool init(uint32_t id, uint32_t offset, char* description,
608 : uint32_t numSuccessors) {
609 0 : id_ = id;
610 0 : offset_ = offset;
611 0 : description_ = description;
612 0 : numSuccessors_ = numSuccessors;
613 0 : if (numSuccessors) {
614 0 : successors_ = js_pod_calloc<uint32_t>(numSuccessors);
615 0 : if (!successors_)
616 0 : return false;
617 : }
618 0 : return true;
619 : }
620 :
621 0 : void destroy() {
622 0 : js_free(description_);
623 0 : js_free(successors_);
624 0 : js_free(code_);
625 0 : }
626 :
627 0 : uint32_t id() const {
628 0 : return id_;
629 : }
630 :
631 0 : uint32_t offset() const {
632 0 : return offset_;
633 : }
634 :
635 0 : const char* description() const {
636 0 : return description_;
637 : }
638 :
639 0 : size_t numSuccessors() const {
640 0 : return numSuccessors_;
641 : }
642 :
643 0 : void setSuccessor(size_t i, uint32_t id) {
644 0 : MOZ_ASSERT(i < numSuccessors_);
645 0 : successors_[i] = id;
646 0 : }
647 :
648 0 : uint32_t successor(size_t i) const {
649 0 : MOZ_ASSERT(i < numSuccessors_);
650 0 : return successors_[i];
651 : }
652 :
653 0 : uint64_t* addressOfHitCount() {
654 0 : return &hitCount_;
655 : }
656 :
657 0 : uint64_t hitCount() const {
658 0 : return hitCount_;
659 : }
660 :
661 0 : void setCode(const char* code) {
662 0 : char* ncode = js_pod_malloc<char>(strlen(code) + 1);
663 0 : if (ncode) {
664 0 : strcpy(ncode, code);
665 0 : code_ = ncode;
666 : }
667 0 : }
668 :
669 0 : const char* code() const {
670 0 : return code_;
671 : }
672 : };
673 :
674 : // Execution information for a compiled script which may persist after the
675 : // IonScript is destroyed, for use during profiling.
676 : struct IonScriptCounts
677 : {
678 : private:
679 : // Any previous invalidated compilation(s) for the script.
680 : IonScriptCounts* previous_;
681 :
682 : // Information about basic blocks in this script.
683 : size_t numBlocks_;
684 : IonBlockCounts* blocks_;
685 :
686 : public:
687 :
688 0 : IonScriptCounts() {
689 0 : mozilla::PodZero(this);
690 0 : }
691 :
692 0 : ~IonScriptCounts() {
693 0 : for (size_t i = 0; i < numBlocks_; i++)
694 0 : blocks_[i].destroy();
695 0 : js_free(blocks_);
696 : // The list can be long in some corner cases (bug 1140084), so
697 : // unroll the recursion.
698 0 : IonScriptCounts* victims = previous_;
699 0 : while (victims) {
700 0 : IonScriptCounts* victim = victims;
701 0 : victims = victim->previous_;
702 0 : victim->previous_ = nullptr;
703 0 : js_delete(victim);
704 : }
705 0 : }
706 :
707 0 : MOZ_MUST_USE bool init(size_t numBlocks) {
708 0 : blocks_ = js_pod_calloc<IonBlockCounts>(numBlocks);
709 0 : if (!blocks_)
710 0 : return false;
711 :
712 0 : numBlocks_ = numBlocks;
713 0 : return true;
714 : }
715 :
716 0 : size_t numBlocks() const {
717 0 : return numBlocks_;
718 : }
719 :
720 0 : IonBlockCounts& block(size_t i) {
721 0 : MOZ_ASSERT(i < numBlocks_);
722 0 : return blocks_[i];
723 : }
724 :
725 0 : void setPrevious(IonScriptCounts* previous) {
726 0 : previous_ = previous;
727 0 : }
728 :
729 0 : IonScriptCounts* previous() const {
730 0 : return previous_;
731 : }
732 : };
733 :
734 : struct VMFunction;
735 :
736 : struct AutoFlushICache
737 : {
738 : private:
739 : #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
740 : uintptr_t start_;
741 : uintptr_t stop_;
742 : const char* name_;
743 : bool inhibit_;
744 : AutoFlushICache* prev_;
745 : #endif
746 :
747 : public:
748 : static void setRange(uintptr_t p, size_t len);
749 : static void flush(uintptr_t p, size_t len);
750 : static void setInhibit();
751 : ~AutoFlushICache();
752 : explicit AutoFlushICache(const char* nonce, bool inhibit=false);
753 : };
754 :
755 : } // namespace jit
756 :
757 : namespace gc {
758 :
759 : inline bool
760 : IsMarked(JSRuntime* rt, const jit::VMFunction*)
761 : {
762 : // VMFunction are only static objects which are used by WeakMaps as keys.
763 : // It is considered as a root object which is always marked.
764 : return true;
765 : }
766 :
767 : } // namespace gc
768 :
769 : } // namespace js
770 :
771 : // JS::ubi::Nodes can point to js::jit::JitCode instances; they're js::gc::Cell
772 : // instances with no associated compartment.
773 : namespace JS {
774 : namespace ubi {
775 : template<>
776 : class Concrete<js::jit::JitCode> : TracerConcrete<js::jit::JitCode> {
777 : protected:
778 0 : explicit Concrete(js::jit::JitCode *ptr) : TracerConcrete<js::jit::JitCode>(ptr) { }
779 :
780 : public:
781 0 : static void construct(void *storage, js::jit::JitCode *ptr) { new (storage) Concrete(ptr); }
782 :
783 0 : CoarseType coarseType() const final { return CoarseType::Script; }
784 :
785 0 : Size size(mozilla::MallocSizeOf mallocSizeOf) const override {
786 0 : Size size = js::gc::Arena::thingSize(get().asTenured().getAllocKind());
787 0 : size += get().bufferSize();
788 0 : size += get().headerSize();
789 0 : return size;
790 : }
791 :
792 0 : const char16_t* typeName() const override { return concreteTypeName; }
793 : static const char16_t concreteTypeName[];
794 : };
795 :
796 : } // namespace ubi
797 :
798 : template <>
799 : struct DeletePolicy<js::jit::IonScript>
800 : {
801 : explicit DeletePolicy(JSRuntime* rt) : rt_(rt) {}
802 : void operator()(const js::jit::IonScript* script);
803 :
804 : private:
805 : JSRuntime* rt_;
806 : };
807 :
808 : } // namespace JS
809 :
810 : #endif /* jit_IonCode_h */
|