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_JitRealm_h
8 : #define jit_JitRealm_h
9 :
10 : #include "mozilla/Array.h"
11 : #include "mozilla/DebugOnly.h"
12 : #include "mozilla/MemoryReporting.h"
13 :
14 : #include <utility>
15 :
16 : #include "builtin/TypedObject.h"
17 : #include "jit/CompileInfo.h"
18 : #include "jit/ICStubSpace.h"
19 : #include "jit/IonCode.h"
20 : #include "jit/IonControlFlow.h"
21 : #include "jit/JitFrames.h"
22 : #include "jit/shared/Assembler-shared.h"
23 : #include "js/GCHashTable.h"
24 : #include "js/Value.h"
25 : #include "vm/Stack.h"
26 :
27 : namespace js {
28 : namespace jit {
29 :
30 : class FrameSizeClass;
31 :
32 195 : struct EnterJitData
33 : {
34 : explicit EnterJitData(JSContext* cx)
35 195 : : envChain(cx),
36 585 : result(cx)
37 : {}
38 :
39 : uint8_t* jitcode;
40 : InterpreterFrame* osrFrame;
41 :
42 : void* calleeToken;
43 :
44 : Value* maxArgv;
45 : unsigned maxArgc;
46 : unsigned numActualArgs;
47 : unsigned osrNumStackValues;
48 :
49 : RootedObject envChain;
50 : RootedValue result;
51 :
52 : bool constructing;
53 : };
54 :
55 : typedef void (*EnterJitCode)(void* code, unsigned argc, Value* argv, InterpreterFrame* fp,
56 : CalleeToken calleeToken, JSObject* envChain,
57 : size_t numStackValues, Value* vp);
58 :
59 : class JitcodeGlobalTable;
60 :
61 : class JitRuntime
62 : {
63 : private:
64 : friend class JitRealm;
65 :
66 : // Executable allocator for all code except wasm code.
67 : MainThreadData<ExecutableAllocator> execAlloc_;
68 :
69 : MainThreadData<uint64_t> nextCompilationId_;
70 :
71 : // Shared exception-handler tail.
72 : ExclusiveAccessLockWriteOnceData<uint32_t> exceptionTailOffset_;
73 :
74 : // Shared post-bailout-handler tail.
75 : ExclusiveAccessLockWriteOnceData<uint32_t> bailoutTailOffset_;
76 :
77 : // Shared profiler exit frame tail.
78 : ExclusiveAccessLockWriteOnceData<uint32_t> profilerExitFrameTailOffset_;
79 :
80 : // Trampoline for entering JIT code.
81 : ExclusiveAccessLockWriteOnceData<uint32_t> enterJITOffset_;
82 :
83 : // Vector mapping frame class sizes to bailout tables.
84 : struct BailoutTable {
85 : uint32_t startOffset;
86 : uint32_t size;
87 : BailoutTable(uint32_t startOffset, uint32_t size)
88 : : startOffset(startOffset), size(size)
89 : {}
90 : };
91 : typedef Vector<BailoutTable, 4, SystemAllocPolicy> BailoutTableVector;
92 : ExclusiveAccessLockWriteOnceData<BailoutTableVector> bailoutTables_;
93 :
94 : // Generic bailout table; used if the bailout table overflows.
95 : ExclusiveAccessLockWriteOnceData<uint32_t> bailoutHandlerOffset_;
96 :
97 : // Argument-rectifying thunk, in the case of insufficient arguments passed
98 : // to a function call site.
99 : ExclusiveAccessLockWriteOnceData<uint32_t> argumentsRectifierOffset_;
100 : ExclusiveAccessLockWriteOnceData<uint32_t> argumentsRectifierReturnOffset_;
101 :
102 : // Thunk that invalides an (Ion compiled) caller on the Ion stack.
103 : ExclusiveAccessLockWriteOnceData<uint32_t> invalidatorOffset_;
104 :
105 : // Thunk that calls the GC pre barrier.
106 : ExclusiveAccessLockWriteOnceData<uint32_t> valuePreBarrierOffset_;
107 : ExclusiveAccessLockWriteOnceData<uint32_t> stringPreBarrierOffset_;
108 : ExclusiveAccessLockWriteOnceData<uint32_t> objectPreBarrierOffset_;
109 : ExclusiveAccessLockWriteOnceData<uint32_t> shapePreBarrierOffset_;
110 : ExclusiveAccessLockWriteOnceData<uint32_t> objectGroupPreBarrierOffset_;
111 :
112 : // Thunk to call malloc/free.
113 : ExclusiveAccessLockWriteOnceData<uint32_t> mallocStubOffset_;
114 : ExclusiveAccessLockWriteOnceData<uint32_t> freeStubOffset_;
115 :
116 : // Thunk called to finish compilation of an IonScript.
117 : ExclusiveAccessLockWriteOnceData<uint32_t> lazyLinkStubOffset_;
118 :
119 : // Thunk to enter the interpreter from JIT code.
120 : ExclusiveAccessLockWriteOnceData<uint32_t> interpreterStubOffset_;
121 :
122 : // Thunk used by the debugger for breakpoint and step mode.
123 : ExclusiveAccessLockWriteOnceData<JitCode*> debugTrapHandler_;
124 :
125 : // Thunk used to fix up on-stack recompile of baseline scripts.
126 : ExclusiveAccessLockWriteOnceData<JitCode*> baselineDebugModeOSRHandler_;
127 : ExclusiveAccessLockWriteOnceData<void*> baselineDebugModeOSRHandlerNoFrameRegPopAddr_;
128 :
129 : // Code for trampolines and VMFunction wrappers.
130 : ExclusiveAccessLockWriteOnceData<JitCode*> trampolineCode_;
131 :
132 : // Map VMFunction addresses to the offset of the wrapper in
133 : // trampolineCode_.
134 : using VMWrapperMap = HashMap<const VMFunction*, uint32_t, VMFunction>;
135 : ExclusiveAccessLockWriteOnceData<VMWrapperMap*> functionWrappers_;
136 :
137 : // Global table of jitcode native address => bytecode address mappings.
138 : UnprotectedData<JitcodeGlobalTable*> jitcodeGlobalTable_;
139 :
140 : #ifdef DEBUG
141 : // The number of possible bailing places encounters before forcefully bailing
142 : // in that place. Zero means inactive.
143 : MainThreadData<uint32_t> ionBailAfter_;
144 : #endif
145 :
146 : // Number of Ion compilations which were finished off thread and are
147 : // waiting to be lazily linked. This is only set while holding the helper
148 : // thread state lock, but may be read from at other times.
149 : mozilla::Atomic<size_t> numFinishedBuilders_;
150 :
151 : // List of Ion compilation waiting to get linked.
152 : using IonBuilderList = mozilla::LinkedList<js::jit::IonBuilder>;
153 : MainThreadData<IonBuilderList> ionLazyLinkList_;
154 : MainThreadData<size_t> ionLazyLinkListSize_;
155 :
156 : private:
157 : void generateLazyLinkStub(MacroAssembler& masm);
158 : void generateInterpreterStub(MacroAssembler& masm);
159 : void generateProfilerExitFrameTailStub(MacroAssembler& masm, Label* profilerExitTail);
160 : void generateExceptionTailStub(MacroAssembler& masm, void* handler, Label* profilerExitTail);
161 : void generateBailoutTailStub(MacroAssembler& masm, Label* bailoutTail);
162 : void generateEnterJIT(JSContext* cx, MacroAssembler& masm);
163 : void generateArgumentsRectifier(MacroAssembler& masm);
164 : BailoutTable generateBailoutTable(MacroAssembler& masm, Label* bailoutTail, uint32_t frameClass);
165 : void generateBailoutHandler(MacroAssembler& masm, Label* bailoutTail);
166 : void generateInvalidator(MacroAssembler& masm, Label* bailoutTail);
167 : uint32_t generatePreBarrier(JSContext* cx, MacroAssembler& masm, MIRType type);
168 : void generateMallocStub(MacroAssembler& masm);
169 : void generateFreeStub(MacroAssembler& masm);
170 : JitCode* generateDebugTrapHandler(JSContext* cx);
171 : JitCode* generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrameRegPopOffsetOut);
172 : bool generateVMWrapper(JSContext* cx, MacroAssembler& masm, const VMFunction& f);
173 :
174 : bool generateTLEventVM(MacroAssembler& masm, const VMFunction& f, bool enter);
175 :
176 : inline bool generateTLEnterVM(MacroAssembler& masm, const VMFunction& f) {
177 908 : return generateTLEventVM(masm, f, /* enter = */ true);
178 : }
179 : inline bool generateTLExitVM(MacroAssembler& masm, const VMFunction& f) {
180 908 : return generateTLEventVM(masm, f, /* enter = */ false);
181 : }
182 :
183 : uint32_t startTrampolineCode(MacroAssembler& masm);
184 :
185 0 : TrampolinePtr trampolineCode(uint32_t offset) const {
186 0 : MOZ_ASSERT(offset > 0);
187 84634 : MOZ_ASSERT(offset < trampolineCode_->instructionsSize());
188 84634 : return TrampolinePtr(trampolineCode_->raw() + offset);
189 : }
190 :
191 : public:
192 : JitRuntime();
193 : ~JitRuntime();
194 : MOZ_MUST_USE bool initialize(JSContext* cx, js::AutoLockForExclusiveAccess& lock);
195 :
196 : static void Trace(JSTracer* trc, js::AutoLockForExclusiveAccess& lock);
197 : static void TraceJitcodeGlobalTableForMinorGC(JSTracer* trc);
198 : static MOZ_MUST_USE bool MarkJitcodeGlobalTableIteratively(GCMarker* marker);
199 : static void SweepJitcodeGlobalTable(JSRuntime* rt);
200 :
201 : ExecutableAllocator& execAlloc() {
202 2809 : return execAlloc_.ref();
203 : }
204 :
205 : IonCompilationId nextCompilationId() {
206 135 : return IonCompilationId(nextCompilationId_++);
207 : }
208 :
209 : TrampolinePtr getVMWrapper(const VMFunction& f) const;
210 : JitCode* debugTrapHandler(JSContext* cx);
211 : JitCode* getBaselineDebugModeOSRHandler(JSContext* cx);
212 : void* getBaselineDebugModeOSRHandlerAddress(JSContext* cx, bool popFrameReg);
213 :
214 : TrampolinePtr getGenericBailoutHandler() const {
215 96 : return trampolineCode(bailoutHandlerOffset_);
216 : }
217 :
218 : TrampolinePtr getExceptionTail() const {
219 172 : return trampolineCode(exceptionTailOffset_);
220 : }
221 :
222 : TrampolinePtr getBailoutTail() const {
223 0 : return trampolineCode(bailoutTailOffset_);
224 : }
225 :
226 : TrampolinePtr getProfilerExitFrameTail() const {
227 1628 : return trampolineCode(profilerExitFrameTailOffset_);
228 : }
229 :
230 : TrampolinePtr getBailoutTable(const FrameSizeClass& frameClass) const;
231 : uint32_t getBailoutTableSize(const FrameSizeClass& frameClass) const;
232 :
233 : TrampolinePtr getArgumentsRectifier() const {
234 2242 : return trampolineCode(argumentsRectifierOffset_);
235 : }
236 :
237 : TrampolinePtr getArgumentsRectifierReturnAddr() const {
238 0 : return trampolineCode(argumentsRectifierReturnOffset_);
239 : }
240 :
241 : TrampolinePtr getInvalidationThunk() const {
242 96 : return trampolineCode(invalidatorOffset_);
243 : }
244 :
245 : EnterJitCode enterJit() const {
246 46986 : return JS_DATA_TO_FUNC_PTR(EnterJitCode, trampolineCode(enterJITOffset_).value);
247 : }
248 :
249 957 : TrampolinePtr preBarrier(MIRType type) const {
250 0 : switch (type) {
251 : case MIRType::Value:
252 0 : return trampolineCode(valuePreBarrierOffset_);
253 : case MIRType::String:
254 0 : return trampolineCode(stringPreBarrierOffset_);
255 : case MIRType::Object:
256 0 : return trampolineCode(objectPreBarrierOffset_);
257 : case MIRType::Shape:
258 0 : return trampolineCode(shapePreBarrierOffset_);
259 : case MIRType::ObjectGroup:
260 10 : return trampolineCode(objectGroupPreBarrierOffset_);
261 0 : default: MOZ_CRASH();
262 : }
263 : }
264 :
265 : TrampolinePtr mallocStub() const {
266 0 : return trampolineCode(mallocStubOffset_);
267 : }
268 :
269 : TrampolinePtr freeStub() const {
270 24 : return trampolineCode(freeStubOffset_);
271 : }
272 :
273 : TrampolinePtr lazyLinkStub() const {
274 94 : return trampolineCode(lazyLinkStubOffset_);
275 : }
276 : TrampolinePtr interpreterStub() const {
277 30964 : return trampolineCode(interpreterStubOffset_);
278 : }
279 :
280 : bool hasJitcodeGlobalTable() const {
281 1706 : return jitcodeGlobalTable_ != nullptr;
282 : }
283 :
284 0 : JitcodeGlobalTable* getJitcodeGlobalTable() {
285 853 : MOZ_ASSERT(hasJitcodeGlobalTable());
286 1706 : return jitcodeGlobalTable_;
287 : }
288 :
289 : bool isProfilerInstrumentationEnabled(JSRuntime* rt) {
290 977 : return rt->geckoProfiler().enabled();
291 : }
292 :
293 : bool isOptimizationTrackingEnabled(JSRuntime* rt) {
294 76 : return isProfilerInstrumentationEnabled(rt);
295 : }
296 :
297 : #ifdef DEBUG
298 1134 : void* addressOfIonBailAfter() { return &ionBailAfter_; }
299 :
300 : // Set after how many bailing places we should forcefully bail.
301 : // Zero disables this feature.
302 : void setIonBailAfter(uint32_t after) {
303 0 : ionBailAfter_ = after;
304 : }
305 : #endif
306 :
307 : size_t numFinishedBuilders() const {
308 196 : return numFinishedBuilders_;
309 : }
310 : mozilla::Atomic<size_t>& numFinishedBuildersRef(const AutoLockHelperThreadState& locked) {
311 : return numFinishedBuilders_;
312 : }
313 :
314 : IonBuilderList& ionLazyLinkList(JSRuntime* rt);
315 :
316 : size_t ionLazyLinkListSize() const {
317 94 : return ionLazyLinkListSize_;
318 : }
319 :
320 : void ionLazyLinkListRemove(JSRuntime* rt, js::jit::IonBuilder* builder);
321 : void ionLazyLinkListAdd(JSRuntime* rt, js::jit::IonBuilder* builder);
322 : };
323 :
324 : enum class CacheKind : uint8_t;
325 : class CacheIRStubInfo;
326 :
327 : enum class ICStubEngine : uint8_t {
328 : // Baseline IC, see SharedIC.h and BaselineIC.h.
329 : Baseline = 0,
330 :
331 : // Ion IC that reuses Baseline IC code, see SharedIC.h.
332 : IonSharedIC,
333 :
334 : // Ion IC, see IonIC.h.
335 : IonIC
336 : };
337 :
338 1305 : struct CacheIRStubKey : public DefaultHasher<CacheIRStubKey> {
339 : struct Lookup {
340 : CacheKind kind;
341 : ICStubEngine engine;
342 : const uint8_t* code;
343 : uint32_t length;
344 :
345 : Lookup(CacheKind kind, ICStubEngine engine, const uint8_t* code, uint32_t length)
346 11687 : : kind(kind), engine(engine), code(code), length(length)
347 : {}
348 : };
349 :
350 : static HashNumber hash(const Lookup& l);
351 : static bool match(const CacheIRStubKey& entry, const Lookup& l);
352 :
353 : UniquePtr<CacheIRStubInfo, JS::FreePolicy> stubInfo;
354 :
355 844 : explicit CacheIRStubKey(CacheIRStubInfo* info) : stubInfo(info) {}
356 1708 : CacheIRStubKey(CacheIRStubKey&& other) : stubInfo(std::move(other.stubInfo)) { }
357 :
358 : void operator=(CacheIRStubKey&& other) {
359 0 : stubInfo = std::move(other.stubInfo);
360 : }
361 : };
362 :
363 : template<typename Key>
364 : struct IcStubCodeMapGCPolicy
365 : {
366 : static bool needsSweep(Key*, ReadBarrieredJitCode* value) {
367 0 : return IsAboutToBeFinalized(value);
368 : }
369 : };
370 :
371 50 : class JitZone
372 : {
373 : // Allocated space for optimized baseline stubs.
374 : OptimizedICStubSpace optimizedStubSpace_;
375 : // Allocated space for cached cfg.
376 : CFGSpace cfgSpace_;
377 :
378 : // Set of CacheIRStubInfo instances used by Ion stubs in this Zone.
379 : using IonCacheIRStubInfoSet = HashSet<CacheIRStubKey, CacheIRStubKey, SystemAllocPolicy>;
380 : IonCacheIRStubInfoSet ionCacheIRStubInfoSet_;
381 :
382 : // Map CacheIRStubKey to shared JitCode objects.
383 : using BaselineCacheIRStubCodeMap = GCHashMap<CacheIRStubKey,
384 : ReadBarrieredJitCode,
385 : CacheIRStubKey,
386 : SystemAllocPolicy,
387 : IcStubCodeMapGCPolicy<CacheIRStubKey>>;
388 : BaselineCacheIRStubCodeMap baselineCacheIRStubCodes_;
389 :
390 : public:
391 : MOZ_MUST_USE bool init(JSContext* cx);
392 : void sweep();
393 :
394 : void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
395 : size_t* jitZone,
396 : size_t* baselineStubsOptimized,
397 : size_t* cachedCFG) const;
398 :
399 : OptimizedICStubSpace* optimizedStubSpace() {
400 24944 : return &optimizedStubSpace_;
401 : }
402 : CFGSpace* cfgSpace() {
403 : return &cfgSpace_;
404 : }
405 :
406 0 : JitCode* getBaselineCacheIRStubCode(const CacheIRStubKey::Lookup& key,
407 : CacheIRStubInfo** stubInfo) {
408 0 : auto p = baselineCacheIRStubCodes_.lookup(key);
409 0 : if (p) {
410 21530 : *stubInfo = p->key().stubInfo.get();
411 0 : return p->value();
412 : }
413 379 : *stubInfo = nullptr;
414 0 : return nullptr;
415 : }
416 379 : MOZ_MUST_USE bool putBaselineCacheIRStubCode(const CacheIRStubKey::Lookup& lookup,
417 : CacheIRStubKey& key,
418 : JitCode* stubCode)
419 : {
420 0 : auto p = baselineCacheIRStubCodes_.lookupForAdd(lookup);
421 379 : MOZ_ASSERT(!p);
422 758 : return baselineCacheIRStubCodes_.add(p, std::move(key), stubCode);
423 : }
424 :
425 543 : CacheIRStubInfo* getIonCacheIRStubInfo(const CacheIRStubKey::Lookup& key) {
426 0 : if (!ionCacheIRStubInfoSet_.initialized())
427 : return nullptr;
428 1084 : IonCacheIRStubInfoSet::Ptr p = ionCacheIRStubInfoSet_.lookup(key);
429 0 : return p ? p->stubInfo.get() : nullptr;
430 : }
431 43 : MOZ_MUST_USE bool putIonCacheIRStubInfo(const CacheIRStubKey::Lookup& lookup,
432 : CacheIRStubKey& key)
433 : {
434 0 : if (!ionCacheIRStubInfoSet_.initialized() && !ionCacheIRStubInfoSet_.init())
435 : return false;
436 0 : IonCacheIRStubInfoSet::AddPtr p = ionCacheIRStubInfoSet_.lookupForAdd(lookup);
437 43 : MOZ_ASSERT(!p);
438 86 : return ionCacheIRStubInfoSet_.add(p, std::move(key));
439 : }
440 : void purgeIonCacheIRStubInfo() {
441 0 : ionCacheIRStubInfoSet_.finish();
442 : }
443 : };
444 :
445 : enum class BailoutReturnStub {
446 : GetProp,
447 : GetPropSuper,
448 : SetProp,
449 : Call,
450 : New,
451 : Count
452 : };
453 :
454 : class JitRealm
455 : {
456 : friend class JitActivation;
457 :
458 : // Map ICStub keys to ICStub shared code objects.
459 : using ICStubCodeMap = GCHashMap<uint32_t,
460 : ReadBarrieredJitCode,
461 : DefaultHasher<uint32_t>,
462 : ZoneAllocPolicy,
463 : IcStubCodeMapGCPolicy<uint32_t>>;
464 : ICStubCodeMap* stubCodes_;
465 :
466 : // Keep track of offset into various baseline stubs' code at return
467 : // point from called script.
468 : struct BailoutReturnStubInfo
469 : {
470 : void* addr;
471 : uint32_t key;
472 :
473 135 : BailoutReturnStubInfo() : addr(nullptr), key(0) { }
474 : BailoutReturnStubInfo(void* addr_, uint32_t key_) : addr(addr_), key(key_) { }
475 : };
476 : mozilla::EnumeratedArray<BailoutReturnStub,
477 : BailoutReturnStub::Count,
478 : BailoutReturnStubInfo> bailoutReturnStubInfo_;
479 :
480 : // The JitRealm stores stubs to concatenate strings inline and perform
481 : // RegExp calls inline. These bake in zone and realm specific pointers
482 : // and can't be stored in JitRuntime.
483 : //
484 : // These are weak pointers, but they can by accessed during off-thread Ion
485 : // compilation and therefore can't use the usual read barrier. Instead, we
486 : // record which stubs have been read and perform the appropriate barriers in
487 : // CodeGenerator::link().
488 :
489 : enum StubIndex : uint32_t
490 : {
491 : StringConcat = 0,
492 : RegExpMatcher,
493 : RegExpSearcher,
494 : RegExpTester,
495 : Count
496 : };
497 :
498 : mozilla::EnumeratedArray<StubIndex, StubIndex::Count, ReadBarrieredJitCode> stubs_;
499 :
500 : // The same approach is taken for SIMD template objects.
501 :
502 : mozilla::EnumeratedArray<SimdType, SimdType::Count, ReadBarrieredObject> simdTemplateObjects_;
503 :
504 : JitCode* generateStringConcatStub(JSContext* cx);
505 : JitCode* generateRegExpMatcherStub(JSContext* cx);
506 : JitCode* generateRegExpSearcherStub(JSContext* cx);
507 : JitCode* generateRegExpTesterStub(JSContext* cx);
508 :
509 0 : JitCode* getStubNoBarrier(StubIndex stub, uint32_t* requiredBarriersOut) const {
510 0 : MOZ_ASSERT(CurrentThreadIsIonCompiling());
511 54 : *requiredBarriersOut |= 1 << uint32_t(stub);
512 108 : return stubs_[stub].unbarrieredGet();
513 : }
514 :
515 : public:
516 0 : JSObject* getSimdTemplateObjectFor(JSContext* cx, Handle<SimdTypeDescr*> descr) {
517 0 : ReadBarrieredObject& tpl = simdTemplateObjects_[descr->type()];
518 0 : if (!tpl)
519 0 : tpl.set(TypedObject::createZeroed(cx, descr, gc::TenuredHeap));
520 0 : return tpl.get();
521 : }
522 :
523 0 : JSObject* maybeGetSimdTemplateObjectFor(SimdType type) const {
524 : // This function is used by Eager Simd Unbox phase which can run
525 : // off-thread, so we cannot use the usual read barrier. For more
526 : // information, see the comment above
527 : // CodeGenerator::simdRefreshTemplatesDuringLink_.
528 :
529 0 : MOZ_ASSERT(CurrentThreadIsIonCompiling());
530 0 : return simdTemplateObjects_[type].unbarrieredGet();
531 : }
532 :
533 0 : JitCode* getStubCode(uint32_t key) {
534 0 : ICStubCodeMap::Ptr p = stubCodes_->lookup(key);
535 54719 : if (p)
536 107947 : return p->value();
537 : return nullptr;
538 : }
539 0 : MOZ_MUST_USE bool putStubCode(JSContext* cx, uint32_t key, Handle<JitCode*> stubCode) {
540 0 : MOZ_ASSERT(stubCode);
541 0 : if (!stubCodes_->putNew(key, stubCode.get())) {
542 0 : ReportOutOfMemory(cx);
543 0 : return false;
544 : }
545 : return true;
546 : }
547 0 : void initBailoutReturnAddr(void* addr, uint32_t key, BailoutReturnStub kind) {
548 0 : MOZ_ASSERT(bailoutReturnStubInfo_[kind].addr == nullptr);
549 0 : bailoutReturnStubInfo_[kind] = BailoutReturnStubInfo { addr, key };
550 0 : }
551 0 : void* bailoutReturnAddr(BailoutReturnStub kind) {
552 2 : MOZ_ASSERT(bailoutReturnStubInfo_[kind].addr);
553 2 : return bailoutReturnStubInfo_[kind].addr;
554 : }
555 :
556 : JitRealm();
557 : ~JitRealm();
558 :
559 : MOZ_MUST_USE bool initialize(JSContext* cx);
560 :
561 : // Initialize code stubs only used by Ion, not Baseline.
562 52 : MOZ_MUST_USE bool ensureIonStubsExist(JSContext* cx) {
563 0 : if (stubs_[StringConcat])
564 : return true;
565 5 : stubs_[StringConcat] = generateStringConcatStub(cx);
566 3 : return stubs_[StringConcat];
567 : }
568 :
569 : void sweep(JS::Realm* realm);
570 :
571 0 : void discardStubs() {
572 0 : for (ReadBarrieredJitCode& stubRef : stubs_)
573 0 : stubRef = nullptr;
574 0 : }
575 :
576 : JitCode* stringConcatStubNoBarrier(uint32_t* requiredBarriersOut) const {
577 48 : return getStubNoBarrier(StringConcat, requiredBarriersOut);
578 : }
579 :
580 : JitCode* regExpMatcherStubNoBarrier(uint32_t* requiredBarriersOut) const {
581 1 : return getStubNoBarrier(RegExpMatcher, requiredBarriersOut);
582 : }
583 :
584 8 : MOZ_MUST_USE bool ensureRegExpMatcherStubExists(JSContext* cx) {
585 0 : if (stubs_[RegExpMatcher])
586 : return true;
587 5 : stubs_[RegExpMatcher] = generateRegExpMatcherStub(cx);
588 3 : return stubs_[RegExpMatcher];
589 : }
590 :
591 : JitCode* regExpSearcherStubNoBarrier(uint32_t* requiredBarriersOut) const {
592 1 : return getStubNoBarrier(RegExpSearcher, requiredBarriersOut);
593 : }
594 :
595 1 : MOZ_MUST_USE bool ensureRegExpSearcherStubExists(JSContext* cx) {
596 0 : if (stubs_[RegExpSearcher])
597 : return true;
598 5 : stubs_[RegExpSearcher] = generateRegExpSearcherStub(cx);
599 3 : return stubs_[RegExpSearcher];
600 : }
601 :
602 : JitCode* regExpTesterStubNoBarrier(uint32_t* requiredBarriersOut) const {
603 4 : return getStubNoBarrier(RegExpTester, requiredBarriersOut);
604 : }
605 :
606 8 : MOZ_MUST_USE bool ensureRegExpTesterStubExists(JSContext* cx) {
607 0 : if (stubs_[RegExpTester])
608 : return true;
609 5 : stubs_[RegExpTester] = generateRegExpTesterStub(cx);
610 3 : return stubs_[RegExpTester];
611 : }
612 :
613 : // Perform the necessary read barriers on stubs and SIMD template object
614 : // described by the bitmasks passed in. This function can only be called
615 : // from the main thread.
616 : //
617 : // The stub and template object pointers must still be valid by the time
618 : // these methods are called. This is arranged by cancelling off-thread Ion
619 : // compilation at the start of GC and at the start of sweeping.
620 : void performStubReadBarriers(uint32_t stubsToBarrier) const;
621 : void performSIMDTemplateReadBarriers(uint32_t simdTemplatesToBarrier) const;
622 :
623 : size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
624 :
625 : bool stringsCanBeInNursery;
626 : };
627 :
628 : // Called from Zone::discardJitCode().
629 : void InvalidateAll(FreeOp* fop, JS::Zone* zone);
630 : void FinishInvalidation(FreeOp* fop, JSScript* script);
631 :
632 : // On windows systems, really large frames need to be incrementally touched.
633 : // The following constant defines the minimum increment of the touch.
634 : #ifdef XP_WIN
635 : const unsigned WINDOWS_BIG_FRAME_TOUCH_INCREMENT = 4096 - 1;
636 : #endif
637 :
638 : // If NON_WRITABLE_JIT_CODE is enabled, this class will ensure
639 : // JIT code is writable (has RW permissions) in its scope.
640 : // Otherwise it's a no-op.
641 : class MOZ_STACK_CLASS AutoWritableJitCode
642 : {
643 : JSRuntime* rt_;
644 : void* addr_;
645 : size_t size_;
646 :
647 : public:
648 2815 : AutoWritableJitCode(JSRuntime* rt, void* addr, size_t size)
649 0 : : rt_(rt), addr_(addr), size_(size)
650 : {
651 1 : rt_->toggleAutoWritableJitCodeActive(true);
652 0 : if (!ExecutableAllocator::makeWritable(addr_, size_))
653 0 : MOZ_CRASH();
654 0 : }
655 0 : AutoWritableJitCode(void* addr, size_t size)
656 0 : : AutoWritableJitCode(TlsContext.get()->runtime(), addr, size)
657 0 : {}
658 0 : explicit AutoWritableJitCode(JitCode* code)
659 0 : : AutoWritableJitCode(code->runtimeFromMainThread(), code->raw(), code->bufferSize())
660 0 : {}
661 1 : ~AutoWritableJitCode() {
662 0 : if (!ExecutableAllocator::makeExecutable(addr_, size_))
663 0 : MOZ_CRASH();
664 2815 : rt_->toggleAutoWritableJitCodeActive(false);
665 2815 : }
666 : };
667 :
668 0 : class MOZ_STACK_CLASS MaybeAutoWritableJitCode
669 : {
670 : mozilla::Maybe<AutoWritableJitCode> awjc_;
671 :
672 : public:
673 : MaybeAutoWritableJitCode(void* addr, size_t size, ReprotectCode reprotect) {
674 : if (reprotect)
675 : awjc_.emplace(addr, size);
676 : }
677 0 : MaybeAutoWritableJitCode(JitCode* code, ReprotectCode reprotect) {
678 : if (reprotect)
679 : awjc_.emplace(code);
680 : }
681 : };
682 :
683 : } // namespace jit
684 : } // namespace js
685 :
686 : #endif /* jit_JitRealm_h */
|