js/src/jit/IonCaches.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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_;
  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
  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)
  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
  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)
  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_;
  1059     PropertyName *name() const {
  1060         return name_;
  1062     TypedOrValueRegister output() const {
  1063         return output_;
  1065     bool hasTypedArrayLengthStub() const {
  1066         return hasTypedArrayLengthStub_;
  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
  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)
  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_;
  1116     ConstantOrRegister index() const {
  1117         return index_;
  1119     TypedOrValueRegister output() const {
  1120         return output_;
  1122     bool monitoredResult() const {
  1123         return monitoredResult_;
  1125     bool allowDoubleResult() const {
  1126         return allowDoubleResult_;
  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
  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)
  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_;
  1177     PropertyName *name() const {
  1178         return name_;
  1180     ConstantOrRegister value() const {
  1181         return value_;
  1183     bool strict() const {
  1184         return strict_;
  1186     bool needsTypeBarrier() const {
  1187         return needsTypeBarrier_;
  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
  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)
  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_;
  1237     Register tempToUnboxIndex() const {
  1238         return tempToUnboxIndex_;
  1240     Register temp() const {
  1241         return temp_;
  1243     FloatRegister tempFloat() const {
  1244         return tempFloat_;
  1246     ValueOperand index() const {
  1247         return index_;
  1249     ConstantOrRegister value() const {
  1250         return value_;
  1252     bool strict() const {
  1253         return strict_;
  1255     bool guardHoles() const {
  1256         return guardHoles_;
  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);                  \
  1280 IONCACHE_KIND_LIST(CACHE_CASTS)
  1281 #undef OPCODE_CASTS
  1283 } // namespace jit
  1284 } // namespace js
  1286 #endif /* jit_IonCaches_h */

mercurial