Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 #ifndef jit_IonCaches_h
8 #define jit_IonCaches_h
10 #if defined(JS_CODEGEN_ARM)
11 # include "jit/arm/Assembler-arm.h"
12 #elif defined(JS_CODEGEN_MIPS)
13 # include "jit/mips/Assembler-mips.h"
14 #endif
15 #include "jit/Registers.h"
16 #include "jit/shared/Assembler-shared.h"
18 namespace js {
20 class LockedJSContext;
21 class TypedArrayObject;
23 namespace jit {
25 #define IONCACHE_KIND_LIST(_) \
26 _(GetProperty) \
27 _(SetProperty) \
28 _(GetElement) \
29 _(SetElement) \
30 _(BindName) \
31 _(Name) \
32 _(CallsiteClone) \
33 _(GetPropertyPar) \
34 _(GetElementPar) \
35 _(SetPropertyPar) \
36 _(SetElementPar)
38 // Forward declarations of Cache kinds.
39 #define FORWARD_DECLARE(kind) class kind##IC;
40 IONCACHE_KIND_LIST(FORWARD_DECLARE)
41 #undef FORWARD_DECLARE
43 class IonCacheVisitor
44 {
45 public:
46 #define VISIT_INS(op) \
47 virtual bool visit##op##IC(CodeGenerator *codegen) { \
48 MOZ_ASSUME_UNREACHABLE("NYI: " #op "IC"); \
49 }
51 IONCACHE_KIND_LIST(VISIT_INS)
52 #undef VISIT_INS
53 };
55 // Common shared temporary state needed during codegen between the different
56 // kinds of caches. Used by OutOfLineUpdateCache.
57 struct AddCacheState
58 {
59 RepatchLabel repatchEntry;
60 Register dispatchScratch;
61 };
64 // Common structure encoding the state of a polymorphic inline cache contained
65 // in the code for an IonScript. IonCaches are used for polymorphic operations
66 // where multiple implementations may be required.
67 //
68 // Roughly speaking, the cache initially jumps to an out of line fragment
69 // which invokes a cache function to perform the operation. The cache function
70 // may generate a stub to perform the operation in certain cases (e.g. a
71 // particular shape for an input object) and attach the stub to existing
72 // stubs, forming a daisy chain of tests for how to perform the operation in
73 // different circumstances. The details of how stubs are linked up as
74 // described in comments below for the classes RepatchIonCache and
75 // DispatchIonCache.
76 //
77 // Eventually, if too many stubs are generated the cache function may disable
78 // the cache, by generating a stub to make a call and perform the operation
79 // within the VM.
80 //
81 // While calls may be made to the cache function and other VM functions, the
82 // cache may still be treated as pure during optimization passes, such that
83 // LICM and GVN may be performed on operations around the cache as if the
84 // operation cannot reenter scripted code through an Invoke() or otherwise have
85 // unexpected behavior. This restricts the sorts of stubs which the cache can
86 // generate or the behaviors which called functions can have, and if a called
87 // function performs a possibly impure operation then the operation will be
88 // marked as such and the calling script will be recompiled.
89 //
90 // Similarly, despite the presence of functions and multiple stubs generated
91 // for a cache, the cache itself may be marked as idempotent and become hoisted
92 // or coalesced by LICM or GVN. This also constrains the stubs which can be
93 // generated for the cache.
94 //
95 // * IonCache usage
96 //
97 // IonCache is the base structure of an inline cache, which generates code stubs
98 // dynamically and attaches them to an IonScript.
99 //
100 // A cache must at least provide a static update function which will usualy have
101 // a JSContext*, followed by the cache index. The rest of the arguments of the
102 // update function are usualy corresponding to the register inputs of the cache,
103 // as it must perform the same operation as any of the stubs that it might
104 // produce. The update function call is handled by the visit function of
105 // CodeGenerator corresponding to this IC.
106 //
107 // The CodeGenerator visit function, as opposed to other visit functions, has
108 // two arguments. The first one is the OutOfLineUpdateCache which stores the LIR
109 // instruction. The second one is the IC object. This function would be called
110 // once the IC is registered with the addCache function of CodeGeneratorShared.
111 //
112 // To register a cache, you must call the addCache function as follow:
113 //
114 // MyCodeIC cache(inputReg1, inputValueReg2, outputReg);
115 // if (!addCache(lir, allocateCache(cache)))
116 // return false;
117 //
118 // Once the cache is allocated with the allocateCache function, any modification
119 // made to the cache would be ignored.
120 //
121 // The addCache function will produce a patchable jump at the location where
122 // it is called. This jump will execute generated stubs and fallback on the code
123 // of the visitMyCodeIC function if no stub match.
124 //
125 // Warning: As the addCache function fallback on a VMCall, calls to
126 // addCache should not be in the same path as another VMCall or in the same
127 // path of another addCache as this is not supported by the invalidation
128 // procedure.
129 class IonCache
130 {
131 public:
132 class StubAttacher;
134 enum Kind {
135 # define DEFINE_CACHEKINDS(ickind) Cache_##ickind,
136 IONCACHE_KIND_LIST(DEFINE_CACHEKINDS)
137 # undef DEFINE_CACHEKINDS
138 Cache_Invalid
139 };
141 // Cache testing and cast.
142 # define CACHEKIND_CASTS(ickind) \
143 bool is##ickind() const { \
144 return kind() == Cache_##ickind; \
145 } \
146 inline ickind##IC &to##ickind(); \
147 inline const ickind##IC &to##ickind() const;
148 IONCACHE_KIND_LIST(CACHEKIND_CASTS)
149 # undef CACHEKIND_CASTS
151 virtual Kind kind() const = 0;
153 virtual bool accept(CodeGenerator *codegen, IonCacheVisitor *visitor) = 0;
155 public:
157 static const char *CacheName(Kind kind);
159 protected:
160 bool pure_ : 1;
161 bool idempotent_ : 1;
162 bool disabled_ : 1;
163 size_t stubCount_ : 5;
165 CodeLocationLabel fallbackLabel_;
167 // Location of this operation, nullptr for idempotent caches.
168 JSScript *script_;
169 jsbytecode *pc_;
171 private:
172 static const size_t MAX_STUBS;
173 void incrementStubCount() {
174 // The IC should stop generating stubs before wrapping stubCount.
175 stubCount_++;
176 JS_ASSERT(stubCount_);
177 }
179 public:
181 IonCache()
182 : pure_(false),
183 idempotent_(false),
184 disabled_(false),
185 stubCount_(0),
186 fallbackLabel_(),
187 script_(nullptr),
188 pc_(nullptr)
189 {
190 }
192 virtual void disable();
193 inline bool isDisabled() const {
194 return disabled_;
195 }
197 // Set the initial 'out-of-line' jump state of the cache. The fallbackLabel is
198 // the location of the out-of-line update (slow) path. This location will
199 // be set to the exitJump of the last generated stub.
200 void setFallbackLabel(CodeOffsetLabel fallbackLabel) {
201 fallbackLabel_ = fallbackLabel;
202 }
204 virtual void emitInitialJump(MacroAssembler &masm, AddCacheState &addState) = 0;
205 virtual void bindInitialJump(MacroAssembler &masm, AddCacheState &addState) = 0;
206 virtual void updateBaseAddress(JitCode *code, MacroAssembler &masm);
208 // Initialize the AddCacheState depending on the kind of cache, like
209 // setting a scratch register. Defaults to doing nothing.
210 virtual void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
212 // Reset the cache around garbage collection.
213 virtual void reset();
215 // Destroy any extra resources the cache uses upon IonScript finalization.
216 virtual void destroy();
218 bool canAttachStub() const {
219 return stubCount_ < MAX_STUBS;
220 }
221 bool empty() const {
222 return stubCount_ == 0;
223 }
225 enum LinkStatus {
226 LINK_ERROR,
227 CACHE_FLUSHED,
228 LINK_GOOD
229 };
231 // Use the Linker to link the generated code and check if any
232 // monitoring/allocation caused an invalidation of the running ion script,
233 // this function returns CACHE_FLUSHED. In case of allocation issue this
234 // function returns LINK_ERROR.
235 LinkStatus linkCode(JSContext *cx, MacroAssembler &masm, IonScript *ion, JitCode **code);
236 // Fixup variables and update jumps in the list of stubs. Increment the
237 // number of attached stubs accordingly.
238 void attachStub(MacroAssembler &masm, StubAttacher &attacher, Handle<JitCode *> code);
240 // Combine both linkStub and attachStub into one function. In addition, it
241 // produces a spew augmented with the attachKind string.
242 bool linkAndAttachStub(JSContext *cx, MacroAssembler &masm, StubAttacher &attacher,
243 IonScript *ion, const char *attachKind);
245 #ifdef DEBUG
246 bool isAllocated() {
247 return fallbackLabel_.isSet();
248 }
249 #endif
251 bool pure() const {
252 return pure_;
253 }
254 bool idempotent() const {
255 return idempotent_;
256 }
257 void setIdempotent() {
258 JS_ASSERT(!idempotent_);
259 JS_ASSERT(!script_);
260 JS_ASSERT(!pc_);
261 idempotent_ = true;
262 }
264 void setScriptedLocation(JSScript *script, jsbytecode *pc) {
265 JS_ASSERT(!idempotent_);
266 script_ = script;
267 pc_ = pc;
268 }
270 void getScriptedLocation(MutableHandleScript pscript, jsbytecode **ppc) const {
271 pscript.set(script_);
272 *ppc = pc_;
273 }
275 jsbytecode *pc() const {
276 JS_ASSERT(pc_);
277 return pc_;
278 }
279 };
281 //
282 // Repatch caches initially generate a patchable jump to an out of line call
283 // to the cache function. Stubs are attached by appending: when attaching a
284 // new stub, we patch the any failure conditions in last generated stub to
285 // jump to the new stub. Failure conditions in the new stub jump to the cache
286 // function which may generate new stubs.
287 //
288 // Control flow Pointers
289 // =======# ----. .---->
290 // # | |
291 // #======> \-----/
292 //
293 // Initial state:
294 //
295 // JIT Code
296 // +--------+ .---------------.
297 // | | | |
298 // |========| v +----------+ |
299 // |== IC ==|====>| Cache Fn | |
300 // |========| +----------+ |
301 // | |<=# # |
302 // | | #=======# |
303 // +--------+ Rejoin path |
304 // |________ |
305 // | |
306 // Repatch | |
307 // IC | |
308 // Entry | |
309 // +------------+ |
310 // | lastJump_ |---------------/
311 // +------------+
312 // | ... |
313 // +------------+
314 //
315 // Attaching stubs:
316 //
317 // Patch the jump pointed to by lastJump_ to jump to the new stub. Update
318 // lastJump_ to be the new stub's failure jump. The failure jump of the new
319 // stub goes to the fallback label, which is the cache function. In this
320 // fashion, new stubs are _appended_ to the chain of stubs, as lastJump_
321 // points to the _tail_ of the stub chain.
322 //
323 // JIT Code
324 // +--------+ #=======================#
325 // | | # v
326 // |========| # +----------+ +------+
327 // |== IC ==|=# | Cache Fn |<====| Stub |
328 // |========| +----------+ ^ +------+
329 // | |<=# # | #
330 // | | #======#=========|=====#
331 // +--------+ Rejoin path |
332 // |________ |
333 // | |
334 // Repatch | |
335 // IC | |
336 // Entry | |
337 // +------------+ |
338 // | lastJump_ |---------------/
339 // +------------+
340 // | ... |
341 // +------------+
342 //
343 class RepatchIonCache : public IonCache
344 {
345 protected:
346 class RepatchStubAppender;
348 CodeLocationJump initialJump_;
349 CodeLocationJump lastJump_;
351 // Offset from the initial jump to the rejoin label.
352 #ifdef JS_CODEGEN_ARM
353 static const size_t REJOIN_LABEL_OFFSET = 4;
354 #elif defined(JS_CODEGEN_MIPS)
355 // The size of jump created by MacroAssemblerMIPSCompat::jumpWithPatch.
356 static const size_t REJOIN_LABEL_OFFSET = 4 * sizeof(void *);
357 #else
358 static const size_t REJOIN_LABEL_OFFSET = 0;
359 #endif
361 CodeLocationLabel rejoinLabel() const {
362 uint8_t *ptr = initialJump_.raw();
363 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
364 uint32_t i = 0;
365 while (i < REJOIN_LABEL_OFFSET)
366 ptr = Assembler::nextInstruction(ptr, &i);
367 #endif
368 return CodeLocationLabel(ptr);
369 }
371 public:
372 RepatchIonCache()
373 : initialJump_(),
374 lastJump_()
375 {
376 }
378 virtual void reset();
380 // Set the initial jump state of the cache. The initialJump is the inline
381 // jump that will point to out-of-line code (such as the slow path, or
382 // stubs), and the rejoinLabel is the position that all out-of-line paths
383 // will rejoin to.
384 void emitInitialJump(MacroAssembler &masm, AddCacheState &addState);
385 void bindInitialJump(MacroAssembler &masm, AddCacheState &addState);
387 // Update the labels once the code is finalized.
388 void updateBaseAddress(JitCode *code, MacroAssembler &masm);
389 };
391 //
392 // Dispatch caches avoid patching already-running code. Instead, the jump to
393 // the stub chain is indirect by way of the firstStub_ pointer
394 // below. Initially the pointer points to the cache function which may attach
395 // new stubs. Stubs are attached by prepending: when attaching a new stub, we
396 // jump to the previous stub on failure conditions, then overwrite the
397 // firstStub_ pointer with the newly generated stub.
398 //
399 // This style does not patch the already executing instruction stream, does
400 // not need to worry about cache coherence of cached jump addresses, and does
401 // not have to worry about aligning the exit jumps to ensure atomic patching,
402 // at the expense of an extra memory read to load the very first stub.
403 //
404 // ICs that need to work in parallel execution need to be dispatch style.
405 //
406 // Control flow Pointers Memory load
407 // =======# ----. .----> ******
408 // # | | *
409 // #======> \-----/ *******
410 //
411 // Initial state:
412 //
413 // The first stub points to the cache function.
414 //
415 // JIT Code
416 // +--------+ .-------.
417 // | | v |
418 // |========| +---------------+ +----------+ |
419 // |== IC ==|====>| Load and jump |====>| Cache Fn | |
420 // |========| +---------------+ +----------+ |
421 // | |<=# * # |
422 // | | #===========*================# |
423 // +--------+ Rejoin * path |
424 // |________ * |
425 // | * |
426 // Dispatch | * |
427 // IC **|************ |
428 // Entry * | |
429 // +------------+ |
430 // | firstStub_ |-------------------------------------/
431 // +------------+
432 // | ... |
433 // +------------+
434 //
435 // Attaching stubs:
436 //
437 // Assign the address of the new stub to firstStub_. The new stub jumps to
438 // the old address held in firstStub_ on failure. Note that there is no
439 // concept of a fallback label here, new stubs are _prepended_, as
440 // firstStub_ always points to the _head_ of the stub chain.
441 //
442 // JIT Code
443 // +--------+ #=====================# .-----.
444 // | | # v v |
445 // |========| +---------------+ # +----------+ +------+ |
446 // |== IC ==|====>| Load and jump |==# | Cache Fn |<====| Stub | |
447 // |========| +---------------+ +----------+ +------+ |
448 // | |<=# * # # |
449 // | | #===========*================#================# |
450 // +--------+ Rejoin * path |
451 // |________ * |
452 // | * |
453 // Dispatch | * |
454 // IC **|************ |
455 // Entry * | |
456 // +------------+ |
457 // | firstStub_ |----------------------------------------------------/
458 // +------------+
459 // | ... |
460 // +------------+
461 //
462 class DispatchIonCache : public IonCache
463 {
464 protected:
465 class DispatchStubPrepender;
467 uint8_t *firstStub_;
468 CodeLocationLabel rejoinLabel_;
469 CodeOffsetLabel dispatchLabel_;
471 public:
472 DispatchIonCache()
473 : firstStub_(nullptr),
474 rejoinLabel_(),
475 dispatchLabel_()
476 {
477 }
479 virtual void reset();
480 virtual void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
482 void emitInitialJump(MacroAssembler &masm, AddCacheState &addState);
483 void bindInitialJump(MacroAssembler &masm, AddCacheState &addState);
485 // Fix up the first stub pointer once the code is finalized.
486 void updateBaseAddress(JitCode *code, MacroAssembler &masm);
487 };
489 // Define the cache kind and pre-declare data structures used for calling inline
490 // caches.
491 #define CACHE_HEADER(ickind) \
492 Kind kind() const { \
493 return IonCache::Cache_##ickind; \
494 } \
495 \
496 bool accept(CodeGenerator *codegen, IonCacheVisitor *visitor) { \
497 return visitor->visit##ickind##IC(codegen); \
498 } \
499 \
500 static const VMFunction UpdateInfo;
502 // Subclasses of IonCache for the various kinds of caches. These do not define
503 // new data members; all caches must be of the same size.
505 // Helper for idempotent GetPropertyIC location tracking. Declared externally
506 // to be forward declarable.
507 //
508 // Since all the scripts stored in CacheLocations are guaranteed to have been
509 // Ion compiled, and are kept alive by function objects in jitcode, and since
510 // the CacheLocations only have the lifespan of the jitcode, there is no need
511 // to trace or mark any of the scripts. Since JSScripts are always allocated
512 // tenured, and never moved, we can keep raw pointers, and there is no need
513 // for HeapPtrScripts here.
514 struct CacheLocation {
515 jsbytecode *pc;
516 JSScript *script;
518 CacheLocation(jsbytecode *pcin, JSScript *scriptin)
519 : pc(pcin), script(scriptin)
520 { }
521 };
523 class GetPropertyIC : public RepatchIonCache
524 {
525 protected:
526 // Registers live after the cache, excluding output registers. The initial
527 // value of these registers must be preserved by the cache.
528 RegisterSet liveRegs_;
530 Register object_;
531 PropertyName *name_;
532 TypedOrValueRegister output_;
534 // Only valid if idempotent
535 size_t locationsIndex_;
536 size_t numLocations_;
538 bool monitoredResult_ : 1;
539 bool hasTypedArrayLengthStub_ : 1;
540 bool hasStrictArgumentsLengthStub_ : 1;
541 bool hasNormalArgumentsLengthStub_ : 1;
542 bool hasGenericProxyStub_ : 1;
544 public:
545 GetPropertyIC(RegisterSet liveRegs,
546 Register object, PropertyName *name,
547 TypedOrValueRegister output,
548 bool monitoredResult)
549 : liveRegs_(liveRegs),
550 object_(object),
551 name_(name),
552 output_(output),
553 locationsIndex_(0),
554 numLocations_(0),
555 monitoredResult_(monitoredResult),
556 hasTypedArrayLengthStub_(false),
557 hasStrictArgumentsLengthStub_(false),
558 hasNormalArgumentsLengthStub_(false),
559 hasGenericProxyStub_(false)
560 {
561 }
563 CACHE_HEADER(GetProperty)
565 void reset();
567 Register object() const {
568 return object_;
569 }
570 PropertyName *name() const {
571 return name_;
572 }
573 TypedOrValueRegister output() const {
574 return output_;
575 }
576 bool monitoredResult() const {
577 return monitoredResult_;
578 }
579 bool hasTypedArrayLengthStub() const {
580 return hasTypedArrayLengthStub_;
581 }
582 bool hasArgumentsLengthStub(bool strict) const {
583 return strict ? hasStrictArgumentsLengthStub_ : hasNormalArgumentsLengthStub_;
584 }
585 bool hasGenericProxyStub() const {
586 return hasGenericProxyStub_;
587 }
589 void setLocationInfo(size_t locationsIndex, size_t numLocations) {
590 JS_ASSERT(idempotent());
591 JS_ASSERT(!numLocations_);
592 JS_ASSERT(numLocations);
593 locationsIndex_ = locationsIndex;
594 numLocations_ = numLocations;
595 }
596 void getLocationInfo(uint32_t *index, uint32_t *num) const {
597 JS_ASSERT(idempotent());
598 *index = locationsIndex_;
599 *num = numLocations_;
600 }
602 enum NativeGetPropCacheability {
603 CanAttachNone,
604 CanAttachReadSlot,
605 CanAttachArrayLength,
606 CanAttachCallGetter
607 };
609 // Helpers for CanAttachNativeGetProp
610 typedef JSContext * Context;
611 bool allowArrayLength(Context cx, HandleObject obj) const;
612 bool allowGetters() const {
613 return monitoredResult() && !idempotent();
614 }
616 // Attach the proper stub, if possible
617 bool tryAttachStub(JSContext *cx, IonScript *ion, HandleObject obj,
618 HandlePropertyName name, void *returnAddr, bool *emitted);
619 bool tryAttachProxy(JSContext *cx, IonScript *ion, HandleObject obj,
620 HandlePropertyName name, void *returnAddr, bool *emitted);
621 bool tryAttachGenericProxy(JSContext *cx, IonScript *ion, HandleObject obj,
622 HandlePropertyName name, void *returnAddr, bool *emitted);
623 bool tryAttachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj,
624 void *returnAddr, bool *emitted);
625 bool tryAttachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
626 HandlePropertyName name, bool resetNeeded,
627 void *returnAddr, bool *emitted);
628 bool tryAttachNative(JSContext *cx, IonScript *ion, HandleObject obj,
629 HandlePropertyName name, void *returnAddr, bool *emitted);
630 bool tryAttachTypedArrayLength(JSContext *cx, IonScript *ion, HandleObject obj,
631 HandlePropertyName name, bool *emitted);
633 bool tryAttachArgumentsLength(JSContext *cx, IonScript *ion, HandleObject obj,
634 HandlePropertyName name, bool *emitted);
636 static bool update(JSContext *cx, size_t cacheIndex, HandleObject obj, MutableHandleValue vp);
637 };
639 class SetPropertyIC : public RepatchIonCache
640 {
641 protected:
642 // Registers live after the cache, excluding output registers. The initial
643 // value of these registers must be preserved by the cache.
644 RegisterSet liveRegs_;
646 Register object_;
647 PropertyName *name_;
648 ConstantOrRegister value_;
649 bool strict_;
650 bool needsTypeBarrier_;
652 bool hasGenericProxyStub_;
654 public:
655 SetPropertyIC(RegisterSet liveRegs, Register object, PropertyName *name,
656 ConstantOrRegister value, bool strict, bool needsTypeBarrier)
657 : liveRegs_(liveRegs),
658 object_(object),
659 name_(name),
660 value_(value),
661 strict_(strict),
662 needsTypeBarrier_(needsTypeBarrier),
663 hasGenericProxyStub_(false)
664 {
665 }
667 CACHE_HEADER(SetProperty)
669 void reset();
671 Register object() const {
672 return object_;
673 }
674 PropertyName *name() const {
675 return name_;
676 }
677 ConstantOrRegister value() const {
678 return value_;
679 }
680 bool strict() const {
681 return strict_;
682 }
683 bool needsTypeBarrier() const {
684 return needsTypeBarrier_;
685 }
686 bool hasGenericProxyStub() const {
687 return hasGenericProxyStub_;
688 }
690 enum NativeSetPropCacheability {
691 CanAttachNone,
692 CanAttachSetSlot,
693 MaybeCanAttachAddSlot,
694 CanAttachCallSetter
695 };
697 bool attachSetSlot(JSContext *cx, IonScript *ion, HandleObject obj, HandleShape shape,
698 bool checkTypeset);
699 bool attachCallSetter(JSContext *cx, IonScript *ion, HandleObject obj,
700 HandleObject holder, HandleShape shape, void *returnAddr);
701 bool attachAddSlot(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldShape,
702 bool checkTypeset);
703 bool attachGenericProxy(JSContext *cx, IonScript *ion, void *returnAddr);
704 bool attachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj,
705 void *returnAddr);
706 bool attachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
707 void *returnAddr);
709 static bool
710 update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue value);
711 };
713 class GetElementIC : public RepatchIonCache
714 {
715 protected:
716 RegisterSet liveRegs_;
718 Register object_;
719 ConstantOrRegister index_;
720 TypedOrValueRegister output_;
722 bool monitoredResult_ : 1;
723 bool allowDoubleResult_ : 1;
724 bool hasDenseStub_ : 1;
725 bool hasStrictArgumentsStub_ : 1;
726 bool hasNormalArgumentsStub_ : 1;
728 size_t failedUpdates_;
730 static const size_t MAX_FAILED_UPDATES;
732 public:
733 GetElementIC(RegisterSet liveRegs, Register object, ConstantOrRegister index,
734 TypedOrValueRegister output, bool monitoredResult, bool allowDoubleResult)
735 : liveRegs_(liveRegs),
736 object_(object),
737 index_(index),
738 output_(output),
739 monitoredResult_(monitoredResult),
740 allowDoubleResult_(allowDoubleResult),
741 hasDenseStub_(false),
742 hasStrictArgumentsStub_(false),
743 hasNormalArgumentsStub_(false),
744 failedUpdates_(0)
745 {
746 }
748 CACHE_HEADER(GetElement)
750 void reset();
752 Register object() const {
753 return object_;
754 }
755 ConstantOrRegister index() const {
756 return index_;
757 }
758 TypedOrValueRegister output() const {
759 return output_;
760 }
761 bool monitoredResult() const {
762 return monitoredResult_;
763 }
764 bool allowDoubleResult() const {
765 return allowDoubleResult_;
766 }
767 bool hasDenseStub() const {
768 return hasDenseStub_;
769 }
770 bool hasArgumentsStub(bool strict) const {
771 return strict ? hasStrictArgumentsStub_ : hasNormalArgumentsStub_;
772 }
773 void setHasDenseStub() {
774 JS_ASSERT(!hasDenseStub());
775 hasDenseStub_ = true;
776 }
778 // Helpers for CanAttachNativeGetProp
779 typedef JSContext * Context;
780 bool allowGetters() const { JS_ASSERT(!idempotent()); return true; }
781 bool allowArrayLength(Context, HandleObject) const { return false; }
782 bool canMonitorSingletonUndefinedSlot(HandleObject holder, HandleShape shape) const {
783 return monitoredResult();
784 }
786 static bool canAttachGetProp(JSObject *obj, const Value &idval, jsid id);
787 static bool canAttachDenseElement(JSObject *obj, const Value &idval);
788 static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval,
789 TypedOrValueRegister output);
791 bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval,
792 HandlePropertyName name, void *returnAddr);
793 bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
794 bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
795 const Value &idval);
796 bool attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj);
798 static bool
799 update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
800 MutableHandleValue vp);
802 void incFailedUpdates() {
803 failedUpdates_++;
804 }
805 void resetFailedUpdates() {
806 failedUpdates_ = 0;
807 }
808 bool shouldDisable() const {
809 return !canAttachStub() ||
810 (stubCount_ == 0 && failedUpdates_ > MAX_FAILED_UPDATES);
811 }
812 };
814 class SetElementIC : public RepatchIonCache
815 {
816 protected:
817 Register object_;
818 Register tempToUnboxIndex_;
819 Register temp_;
820 FloatRegister tempFloat_;
821 ValueOperand index_;
822 ConstantOrRegister value_;
823 bool strict_;
824 bool guardHoles_;
826 bool hasDenseStub_ : 1;
828 public:
829 SetElementIC(Register object, Register tempToUnboxIndex, Register temp,
830 FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
831 bool strict, bool guardHoles)
832 : object_(object),
833 tempToUnboxIndex_(tempToUnboxIndex),
834 temp_(temp),
835 tempFloat_(tempFloat),
836 index_(index),
837 value_(value),
838 strict_(strict),
839 guardHoles_(guardHoles),
840 hasDenseStub_(false)
841 {
842 }
844 CACHE_HEADER(SetElement)
846 void reset();
848 Register object() const {
849 return object_;
850 }
851 Register tempToUnboxIndex() const {
852 return tempToUnboxIndex_;
853 }
854 Register temp() const {
855 return temp_;
856 }
857 FloatRegister tempFloat() const {
858 return tempFloat_;
859 }
860 ValueOperand index() const {
861 return index_;
862 }
863 ConstantOrRegister value() const {
864 return value_;
865 }
866 bool strict() const {
867 return strict_;
868 }
869 bool guardHoles() const {
870 return guardHoles_;
871 }
873 bool hasDenseStub() const {
874 return hasDenseStub_;
875 }
876 void setHasDenseStub() {
877 JS_ASSERT(!hasDenseStub());
878 hasDenseStub_ = true;
879 }
881 bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
882 bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr);
884 static bool
885 update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
886 HandleValue value);
887 };
889 class BindNameIC : public RepatchIonCache
890 {
891 protected:
892 Register scopeChain_;
893 PropertyName *name_;
894 Register output_;
896 public:
897 BindNameIC(Register scopeChain, PropertyName *name, Register output)
898 : scopeChain_(scopeChain),
899 name_(name),
900 output_(output)
901 {
902 }
904 CACHE_HEADER(BindName)
906 Register scopeChainReg() const {
907 return scopeChain_;
908 }
909 HandlePropertyName name() const {
910 return HandlePropertyName::fromMarkedLocation(&name_);
911 }
912 Register outputReg() const {
913 return output_;
914 }
916 bool attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain);
917 bool attachNonGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain, JSObject *holder);
919 static JSObject *
920 update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain);
921 };
923 class NameIC : public RepatchIonCache
924 {
925 protected:
926 // Registers live after the cache, excluding output registers. The initial
927 // value of these registers must be preserved by the cache.
928 RegisterSet liveRegs_;
930 bool typeOf_;
931 Register scopeChain_;
932 PropertyName *name_;
933 TypedOrValueRegister output_;
935 public:
936 NameIC(RegisterSet liveRegs, bool typeOf,
937 Register scopeChain, PropertyName *name,
938 TypedOrValueRegister output)
939 : liveRegs_(liveRegs),
940 typeOf_(typeOf),
941 scopeChain_(scopeChain),
942 name_(name),
943 output_(output)
944 {
945 }
947 CACHE_HEADER(Name)
949 Register scopeChainReg() const {
950 return scopeChain_;
951 }
952 HandlePropertyName name() const {
953 return HandlePropertyName::fromMarkedLocation(&name_);
954 }
955 TypedOrValueRegister outputReg() const {
956 return output_;
957 }
958 bool isTypeOf() const {
959 return typeOf_;
960 }
962 bool attachReadSlot(JSContext *cx, IonScript *ion, HandleObject scopeChain,
963 HandleObject holderBase, HandleObject holder, HandleShape shape);
964 bool attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
965 HandleShape shape, void *returnAddr);
967 static bool
968 update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain, MutableHandleValue vp);
969 };
971 class CallsiteCloneIC : public RepatchIonCache
972 {
973 protected:
974 Register callee_;
975 Register output_;
976 JSScript *callScript_;
977 jsbytecode *callPc_;
979 public:
980 CallsiteCloneIC(Register callee, JSScript *callScript, jsbytecode *callPc, Register output)
981 : callee_(callee),
982 output_(output),
983 callScript_(callScript),
984 callPc_(callPc)
985 {
986 }
988 CACHE_HEADER(CallsiteClone)
990 Register calleeReg() const {
991 return callee_;
992 }
993 HandleScript callScript() const {
994 return HandleScript::fromMarkedLocation(&callScript_);
995 }
996 jsbytecode *callPc() const {
997 return callPc_;
998 }
999 Register outputReg() const {
1000 return output_;
1001 }
1003 bool attach(JSContext *cx, IonScript *ion, HandleFunction original, HandleFunction clone);
1005 static JSObject *update(JSContext *cx, size_t cacheIndex, HandleObject callee);
1006 };
1008 class ParallelIonCache : public DispatchIonCache
1009 {
1010 protected:
1011 // A set of all objects that are stubbed. Used to detect duplicates in
1012 // parallel execution.
1013 ShapeSet *stubbedShapes_;
1015 ParallelIonCache()
1016 : stubbedShapes_(nullptr)
1017 {
1018 }
1020 bool initStubbedShapes(JSContext *cx);
1022 public:
1023 void reset();
1024 void destroy();
1026 bool hasOrAddStubbedShape(LockedJSContext &cx, Shape *shape, bool *alreadyStubbed);
1027 };
1029 class GetPropertyParIC : public ParallelIonCache
1030 {
1031 protected:
1032 Register object_;
1033 PropertyName *name_;
1034 TypedOrValueRegister output_;
1035 bool hasTypedArrayLengthStub_ : 1;
1037 public:
1038 GetPropertyParIC(Register object, PropertyName *name, TypedOrValueRegister output)
1039 : object_(object),
1040 name_(name),
1041 output_(output),
1042 hasTypedArrayLengthStub_(false)
1043 {
1044 }
1046 CACHE_HEADER(GetPropertyPar)
1048 #ifdef JS_CODEGEN_X86
1049 // x86 lacks a general purpose scratch register for dispatch caches and
1050 // must be given one manually.
1051 void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
1052 #endif
1054 void reset();
1056 Register object() const {
1057 return object_;
1058 }
1059 PropertyName *name() const {
1060 return name_;
1061 }
1062 TypedOrValueRegister output() const {
1063 return output_;
1064 }
1065 bool hasTypedArrayLengthStub() const {
1066 return hasTypedArrayLengthStub_;
1067 }
1069 // CanAttachNativeGetProp Helpers
1070 typedef LockedJSContext & Context;
1071 bool canMonitorSingletonUndefinedSlot(HandleObject, HandleShape) const { return true; }
1072 bool allowGetters() const { return false; }
1073 bool allowArrayLength(Context, HandleObject) const { return true; }
1075 bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, JSObject *holder,
1076 Shape *shape);
1077 bool attachArrayLength(LockedJSContext &cx, IonScript *ion, JSObject *obj);
1078 bool attachTypedArrayLength(LockedJSContext &cx, IonScript *ion, JSObject *obj);
1080 static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
1081 MutableHandleValue vp);
1082 };
1084 class GetElementParIC : public ParallelIonCache
1085 {
1086 protected:
1087 Register object_;
1088 ConstantOrRegister index_;
1089 TypedOrValueRegister output_;
1091 bool monitoredResult_ : 1;
1092 bool allowDoubleResult_ : 1;
1094 public:
1095 GetElementParIC(Register object, ConstantOrRegister index,
1096 TypedOrValueRegister output, bool monitoredResult, bool allowDoubleResult)
1097 : object_(object),
1098 index_(index),
1099 output_(output),
1100 monitoredResult_(monitoredResult),
1101 allowDoubleResult_(allowDoubleResult)
1102 {
1103 }
1105 CACHE_HEADER(GetElementPar)
1107 #ifdef JS_CODEGEN_X86
1108 // x86 lacks a general purpose scratch register for dispatch caches and
1109 // must be given one manually.
1110 void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
1111 #endif
1113 Register object() const {
1114 return object_;
1115 }
1116 ConstantOrRegister index() const {
1117 return index_;
1118 }
1119 TypedOrValueRegister output() const {
1120 return output_;
1121 }
1122 bool monitoredResult() const {
1123 return monitoredResult_;
1124 }
1125 bool allowDoubleResult() const {
1126 return allowDoubleResult_;
1127 }
1129 // CanAttachNativeGetProp Helpers
1130 typedef LockedJSContext & Context;
1131 bool canMonitorSingletonUndefinedSlot(HandleObject, HandleShape) const { return true; }
1132 bool allowGetters() const { return false; }
1133 bool allowArrayLength(Context, HandleObject) const { return false; }
1135 bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval,
1136 PropertyName *name, JSObject *holder, Shape *shape);
1137 bool attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval);
1138 bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, TypedArrayObject *tarr,
1139 const Value &idval);
1141 static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
1142 MutableHandleValue vp);
1144 };
1146 class SetPropertyParIC : public ParallelIonCache
1147 {
1148 protected:
1149 Register object_;
1150 PropertyName *name_;
1151 ConstantOrRegister value_;
1152 bool strict_;
1153 bool needsTypeBarrier_;
1155 public:
1156 SetPropertyParIC(Register object, PropertyName *name, ConstantOrRegister value,
1157 bool strict, bool needsTypeBarrier)
1158 : object_(object),
1159 name_(name),
1160 value_(value),
1161 strict_(strict),
1162 needsTypeBarrier_(needsTypeBarrier)
1163 {
1164 }
1166 CACHE_HEADER(SetPropertyPar)
1168 #ifdef JS_CODEGEN_X86
1169 // x86 lacks a general purpose scratch register for dispatch caches and
1170 // must be given one manually.
1171 void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
1172 #endif
1174 Register object() const {
1175 return object_;
1176 }
1177 PropertyName *name() const {
1178 return name_;
1179 }
1180 ConstantOrRegister value() const {
1181 return value_;
1182 }
1183 bool strict() const {
1184 return strict_;
1185 }
1186 bool needsTypeBarrier() const {
1187 return needsTypeBarrier_;
1188 }
1190 bool attachSetSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *shape,
1191 bool checkTypeset);
1192 bool attachAddSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *oldShape,
1193 bool checkTypeset);
1195 static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
1196 HandleValue value);
1197 };
1199 class SetElementParIC : public ParallelIonCache
1200 {
1201 protected:
1202 Register object_;
1203 Register tempToUnboxIndex_;
1204 Register temp_;
1205 FloatRegister tempFloat_;
1206 ValueOperand index_;
1207 ConstantOrRegister value_;
1208 bool strict_;
1209 bool guardHoles_;
1211 public:
1212 SetElementParIC(Register object, Register tempToUnboxIndex, Register temp,
1213 FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
1214 bool strict, bool guardHoles)
1215 : object_(object),
1216 tempToUnboxIndex_(tempToUnboxIndex),
1217 temp_(temp),
1218 tempFloat_(tempFloat),
1219 index_(index),
1220 value_(value),
1221 strict_(strict),
1222 guardHoles_(guardHoles)
1223 {
1224 }
1226 CACHE_HEADER(SetElementPar)
1228 #ifdef JS_CODEGEN_X86
1229 // x86 lacks a general purpose scratch register for dispatch caches and
1230 // must be given one manually.
1231 void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
1232 #endif
1234 Register object() const {
1235 return object_;
1236 }
1237 Register tempToUnboxIndex() const {
1238 return tempToUnboxIndex_;
1239 }
1240 Register temp() const {
1241 return temp_;
1242 }
1243 FloatRegister tempFloat() const {
1244 return tempFloat_;
1245 }
1246 ValueOperand index() const {
1247 return index_;
1248 }
1249 ConstantOrRegister value() const {
1250 return value_;
1251 }
1252 bool strict() const {
1253 return strict_;
1254 }
1255 bool guardHoles() const {
1256 return guardHoles_;
1257 }
1259 bool attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval);
1260 bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, TypedArrayObject *tarr);
1262 static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
1263 HandleValue idval, HandleValue value);
1264 };
1266 #undef CACHE_HEADER
1268 // Implement cache casts now that the compiler can see the inheritance.
1269 #define CACHE_CASTS(ickind) \
1270 ickind##IC &IonCache::to##ickind() \
1271 { \
1272 JS_ASSERT(is##ickind()); \
1273 return *static_cast<ickind##IC *>(this); \
1274 } \
1275 const ickind##IC &IonCache::to##ickind() const \
1276 { \
1277 JS_ASSERT(is##ickind()); \
1278 return *static_cast<const ickind##IC *>(this); \
1279 }
1280 IONCACHE_KIND_LIST(CACHE_CASTS)
1281 #undef OPCODE_CASTS
1283 } // namespace jit
1284 } // namespace js
1286 #endif /* jit_IonCaches_h */