js/src/jit/IonCaches.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/IonCaches.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1286 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef jit_IonCaches_h
    1.11 +#define jit_IonCaches_h
    1.12 +
    1.13 +#if defined(JS_CODEGEN_ARM)
    1.14 +# include "jit/arm/Assembler-arm.h"
    1.15 +#elif defined(JS_CODEGEN_MIPS)
    1.16 +# include "jit/mips/Assembler-mips.h"
    1.17 +#endif
    1.18 +#include "jit/Registers.h"
    1.19 +#include "jit/shared/Assembler-shared.h"
    1.20 +
    1.21 +namespace js {
    1.22 +
    1.23 +class LockedJSContext;
    1.24 +class TypedArrayObject;
    1.25 +
    1.26 +namespace jit {
    1.27 +
    1.28 +#define IONCACHE_KIND_LIST(_)                                   \
    1.29 +    _(GetProperty)                                              \
    1.30 +    _(SetProperty)                                              \
    1.31 +    _(GetElement)                                               \
    1.32 +    _(SetElement)                                               \
    1.33 +    _(BindName)                                                 \
    1.34 +    _(Name)                                                     \
    1.35 +    _(CallsiteClone)                                            \
    1.36 +    _(GetPropertyPar)                                           \
    1.37 +    _(GetElementPar)                                            \
    1.38 +    _(SetPropertyPar)                                           \
    1.39 +    _(SetElementPar)
    1.40 +
    1.41 +// Forward declarations of Cache kinds.
    1.42 +#define FORWARD_DECLARE(kind) class kind##IC;
    1.43 +IONCACHE_KIND_LIST(FORWARD_DECLARE)
    1.44 +#undef FORWARD_DECLARE
    1.45 +
    1.46 +class IonCacheVisitor
    1.47 +{
    1.48 +  public:
    1.49 +#define VISIT_INS(op)                                               \
    1.50 +    virtual bool visit##op##IC(CodeGenerator *codegen) {            \
    1.51 +        MOZ_ASSUME_UNREACHABLE("NYI: " #op "IC");                   \
    1.52 +    }
    1.53 +
    1.54 +    IONCACHE_KIND_LIST(VISIT_INS)
    1.55 +#undef VISIT_INS
    1.56 +};
    1.57 +
    1.58 +// Common shared temporary state needed during codegen between the different
    1.59 +// kinds of caches. Used by OutOfLineUpdateCache.
    1.60 +struct AddCacheState
    1.61 +{
    1.62 +    RepatchLabel repatchEntry;
    1.63 +    Register dispatchScratch;
    1.64 +};
    1.65 +
    1.66 +
    1.67 +// Common structure encoding the state of a polymorphic inline cache contained
    1.68 +// in the code for an IonScript. IonCaches are used for polymorphic operations
    1.69 +// where multiple implementations may be required.
    1.70 +//
    1.71 +// Roughly speaking, the cache initially jumps to an out of line fragment
    1.72 +// which invokes a cache function to perform the operation. The cache function
    1.73 +// may generate a stub to perform the operation in certain cases (e.g. a
    1.74 +// particular shape for an input object) and attach the stub to existing
    1.75 +// stubs, forming a daisy chain of tests for how to perform the operation in
    1.76 +// different circumstances. The details of how stubs are linked up as
    1.77 +// described in comments below for the classes RepatchIonCache and
    1.78 +// DispatchIonCache.
    1.79 +//
    1.80 +// Eventually, if too many stubs are generated the cache function may disable
    1.81 +// the cache, by generating a stub to make a call and perform the operation
    1.82 +// within the VM.
    1.83 +//
    1.84 +// While calls may be made to the cache function and other VM functions, the
    1.85 +// cache may still be treated as pure during optimization passes, such that
    1.86 +// LICM and GVN may be performed on operations around the cache as if the
    1.87 +// operation cannot reenter scripted code through an Invoke() or otherwise have
    1.88 +// unexpected behavior. This restricts the sorts of stubs which the cache can
    1.89 +// generate or the behaviors which called functions can have, and if a called
    1.90 +// function performs a possibly impure operation then the operation will be
    1.91 +// marked as such and the calling script will be recompiled.
    1.92 +//
    1.93 +// Similarly, despite the presence of functions and multiple stubs generated
    1.94 +// for a cache, the cache itself may be marked as idempotent and become hoisted
    1.95 +// or coalesced by LICM or GVN. This also constrains the stubs which can be
    1.96 +// generated for the cache.
    1.97 +//
    1.98 +// * IonCache usage
    1.99 +//
   1.100 +// IonCache is the base structure of an inline cache, which generates code stubs
   1.101 +// dynamically and attaches them to an IonScript.
   1.102 +//
   1.103 +// A cache must at least provide a static update function which will usualy have
   1.104 +// a JSContext*, followed by the cache index. The rest of the arguments of the
   1.105 +// update function are usualy corresponding to the register inputs of the cache,
   1.106 +// as it must perform the same operation as any of the stubs that it might
   1.107 +// produce. The update function call is handled by the visit function of
   1.108 +// CodeGenerator corresponding to this IC.
   1.109 +//
   1.110 +// The CodeGenerator visit function, as opposed to other visit functions, has
   1.111 +// two arguments. The first one is the OutOfLineUpdateCache which stores the LIR
   1.112 +// instruction. The second one is the IC object.  This function would be called
   1.113 +// once the IC is registered with the addCache function of CodeGeneratorShared.
   1.114 +//
   1.115 +// To register a cache, you must call the addCache function as follow:
   1.116 +//
   1.117 +//     MyCodeIC cache(inputReg1, inputValueReg2, outputReg);
   1.118 +//     if (!addCache(lir, allocateCache(cache)))
   1.119 +//         return false;
   1.120 +//
   1.121 +// Once the cache is allocated with the allocateCache function, any modification
   1.122 +// made to the cache would be ignored.
   1.123 +//
   1.124 +// The addCache function will produce a patchable jump at the location where
   1.125 +// it is called. This jump will execute generated stubs and fallback on the code
   1.126 +// of the visitMyCodeIC function if no stub match.
   1.127 +//
   1.128 +//   Warning: As the addCache function fallback on a VMCall, calls to
   1.129 +// addCache should not be in the same path as another VMCall or in the same
   1.130 +// path of another addCache as this is not supported by the invalidation
   1.131 +// procedure.
   1.132 +class IonCache
   1.133 +{
   1.134 +  public:
   1.135 +    class StubAttacher;
   1.136 +
   1.137 +    enum Kind {
   1.138 +#   define DEFINE_CACHEKINDS(ickind) Cache_##ickind,
   1.139 +        IONCACHE_KIND_LIST(DEFINE_CACHEKINDS)
   1.140 +#   undef DEFINE_CACHEKINDS
   1.141 +        Cache_Invalid
   1.142 +    };
   1.143 +
   1.144 +    // Cache testing and cast.
   1.145 +#   define CACHEKIND_CASTS(ickind)                                      \
   1.146 +    bool is##ickind() const {                                           \
   1.147 +        return kind() == Cache_##ickind;                                \
   1.148 +    }                                                                   \
   1.149 +    inline ickind##IC &to##ickind();                                    \
   1.150 +    inline const ickind##IC &to##ickind() const;
   1.151 +    IONCACHE_KIND_LIST(CACHEKIND_CASTS)
   1.152 +#   undef CACHEKIND_CASTS
   1.153 +
   1.154 +    virtual Kind kind() const = 0;
   1.155 +
   1.156 +    virtual bool accept(CodeGenerator *codegen, IonCacheVisitor *visitor) = 0;
   1.157 +
   1.158 +  public:
   1.159 +
   1.160 +    static const char *CacheName(Kind kind);
   1.161 +
   1.162 +  protected:
   1.163 +    bool pure_ : 1;
   1.164 +    bool idempotent_ : 1;
   1.165 +    bool disabled_ : 1;
   1.166 +    size_t stubCount_ : 5;
   1.167 +
   1.168 +    CodeLocationLabel fallbackLabel_;
   1.169 +
   1.170 +    // Location of this operation, nullptr for idempotent caches.
   1.171 +    JSScript *script_;
   1.172 +    jsbytecode *pc_;
   1.173 +
   1.174 +  private:
   1.175 +    static const size_t MAX_STUBS;
   1.176 +    void incrementStubCount() {
   1.177 +        // The IC should stop generating stubs before wrapping stubCount.
   1.178 +        stubCount_++;
   1.179 +        JS_ASSERT(stubCount_);
   1.180 +    }
   1.181 +
   1.182 +  public:
   1.183 +
   1.184 +    IonCache()
   1.185 +      : pure_(false),
   1.186 +        idempotent_(false),
   1.187 +        disabled_(false),
   1.188 +        stubCount_(0),
   1.189 +        fallbackLabel_(),
   1.190 +        script_(nullptr),
   1.191 +        pc_(nullptr)
   1.192 +    {
   1.193 +    }
   1.194 +
   1.195 +    virtual void disable();
   1.196 +    inline bool isDisabled() const {
   1.197 +        return disabled_;
   1.198 +    }
   1.199 +
   1.200 +    // Set the initial 'out-of-line' jump state of the cache. The fallbackLabel is
   1.201 +    // the location of the out-of-line update (slow) path.  This location will
   1.202 +    // be set to the exitJump of the last generated stub.
   1.203 +    void setFallbackLabel(CodeOffsetLabel fallbackLabel) {
   1.204 +        fallbackLabel_ = fallbackLabel;
   1.205 +    }
   1.206 +
   1.207 +    virtual void emitInitialJump(MacroAssembler &masm, AddCacheState &addState) = 0;
   1.208 +    virtual void bindInitialJump(MacroAssembler &masm, AddCacheState &addState) = 0;
   1.209 +    virtual void updateBaseAddress(JitCode *code, MacroAssembler &masm);
   1.210 +
   1.211 +    // Initialize the AddCacheState depending on the kind of cache, like
   1.212 +    // setting a scratch register. Defaults to doing nothing.
   1.213 +    virtual void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
   1.214 +
   1.215 +    // Reset the cache around garbage collection.
   1.216 +    virtual void reset();
   1.217 +
   1.218 +    // Destroy any extra resources the cache uses upon IonScript finalization.
   1.219 +    virtual void destroy();
   1.220 +
   1.221 +    bool canAttachStub() const {
   1.222 +        return stubCount_ < MAX_STUBS;
   1.223 +    }
   1.224 +    bool empty() const {
   1.225 +        return stubCount_ == 0;
   1.226 +    }
   1.227 +
   1.228 +    enum LinkStatus {
   1.229 +        LINK_ERROR,
   1.230 +        CACHE_FLUSHED,
   1.231 +        LINK_GOOD
   1.232 +    };
   1.233 +
   1.234 +    // Use the Linker to link the generated code and check if any
   1.235 +    // monitoring/allocation caused an invalidation of the running ion script,
   1.236 +    // this function returns CACHE_FLUSHED. In case of allocation issue this
   1.237 +    // function returns LINK_ERROR.
   1.238 +    LinkStatus linkCode(JSContext *cx, MacroAssembler &masm, IonScript *ion, JitCode **code);
   1.239 +    // Fixup variables and update jumps in the list of stubs.  Increment the
   1.240 +    // number of attached stubs accordingly.
   1.241 +    void attachStub(MacroAssembler &masm, StubAttacher &attacher, Handle<JitCode *> code);
   1.242 +
   1.243 +    // Combine both linkStub and attachStub into one function. In addition, it
   1.244 +    // produces a spew augmented with the attachKind string.
   1.245 +    bool linkAndAttachStub(JSContext *cx, MacroAssembler &masm, StubAttacher &attacher,
   1.246 +                           IonScript *ion, const char *attachKind);
   1.247 +
   1.248 +#ifdef DEBUG
   1.249 +    bool isAllocated() {
   1.250 +        return fallbackLabel_.isSet();
   1.251 +    }
   1.252 +#endif
   1.253 +
   1.254 +    bool pure() const {
   1.255 +        return pure_;
   1.256 +    }
   1.257 +    bool idempotent() const {
   1.258 +        return idempotent_;
   1.259 +    }
   1.260 +    void setIdempotent() {
   1.261 +        JS_ASSERT(!idempotent_);
   1.262 +        JS_ASSERT(!script_);
   1.263 +        JS_ASSERT(!pc_);
   1.264 +        idempotent_ = true;
   1.265 +    }
   1.266 +
   1.267 +    void setScriptedLocation(JSScript *script, jsbytecode *pc) {
   1.268 +        JS_ASSERT(!idempotent_);
   1.269 +        script_ = script;
   1.270 +        pc_ = pc;
   1.271 +    }
   1.272 +
   1.273 +    void getScriptedLocation(MutableHandleScript pscript, jsbytecode **ppc) const {
   1.274 +        pscript.set(script_);
   1.275 +        *ppc = pc_;
   1.276 +    }
   1.277 +
   1.278 +    jsbytecode *pc() const {
   1.279 +        JS_ASSERT(pc_);
   1.280 +        return pc_;
   1.281 +    }
   1.282 +};
   1.283 +
   1.284 +//
   1.285 +// Repatch caches initially generate a patchable jump to an out of line call
   1.286 +// to the cache function. Stubs are attached by appending: when attaching a
   1.287 +// new stub, we patch the any failure conditions in last generated stub to
   1.288 +// jump to the new stub. Failure conditions in the new stub jump to the cache
   1.289 +// function which may generate new stubs.
   1.290 +//
   1.291 +//        Control flow               Pointers
   1.292 +//      =======#                 ----.     .---->
   1.293 +//             #                     |     |
   1.294 +//             #======>              \-----/
   1.295 +//
   1.296 +// Initial state:
   1.297 +//
   1.298 +//  JIT Code
   1.299 +// +--------+   .---------------.
   1.300 +// |        |   |               |
   1.301 +// |========|   v +----------+  |
   1.302 +// |== IC ==|====>| Cache Fn |  |
   1.303 +// |========|     +----------+  |
   1.304 +// |        |<=#       #        |
   1.305 +// |        |  #=======#        |
   1.306 +// +--------+  Rejoin path      |
   1.307 +//     |________                |
   1.308 +//             |                |
   1.309 +//   Repatch   |                |
   1.310 +//     IC      |                |
   1.311 +//   Entry     |                |
   1.312 +// +------------+               |
   1.313 +// | lastJump_  |---------------/
   1.314 +// +------------+
   1.315 +// |    ...     |
   1.316 +// +------------+
   1.317 +//
   1.318 +// Attaching stubs:
   1.319 +//
   1.320 +//   Patch the jump pointed to by lastJump_ to jump to the new stub. Update
   1.321 +//   lastJump_ to be the new stub's failure jump. The failure jump of the new
   1.322 +//   stub goes to the fallback label, which is the cache function. In this
   1.323 +//   fashion, new stubs are _appended_ to the chain of stubs, as lastJump_
   1.324 +//   points to the _tail_ of the stub chain.
   1.325 +//
   1.326 +//  JIT Code
   1.327 +// +--------+ #=======================#
   1.328 +// |        | #                       v
   1.329 +// |========| #   +----------+     +------+
   1.330 +// |== IC ==|=#   | Cache Fn |<====| Stub |
   1.331 +// |========|     +----------+  ^  +------+
   1.332 +// |        |<=#      #         |     #
   1.333 +// |        |  #======#=========|=====#
   1.334 +// +--------+      Rejoin path  |
   1.335 +//     |________                |
   1.336 +//             |                |
   1.337 +//   Repatch   |                |
   1.338 +//     IC      |                |
   1.339 +//   Entry     |                |
   1.340 +// +------------+               |
   1.341 +// | lastJump_  |---------------/
   1.342 +// +------------+
   1.343 +// |    ...     |
   1.344 +// +------------+
   1.345 +//
   1.346 +class RepatchIonCache : public IonCache
   1.347 +{
   1.348 +  protected:
   1.349 +    class RepatchStubAppender;
   1.350 +
   1.351 +    CodeLocationJump initialJump_;
   1.352 +    CodeLocationJump lastJump_;
   1.353 +
   1.354 +    // Offset from the initial jump to the rejoin label.
   1.355 +#ifdef JS_CODEGEN_ARM
   1.356 +    static const size_t REJOIN_LABEL_OFFSET = 4;
   1.357 +#elif defined(JS_CODEGEN_MIPS)
   1.358 +    // The size of jump created by MacroAssemblerMIPSCompat::jumpWithPatch.
   1.359 +    static const size_t REJOIN_LABEL_OFFSET = 4 * sizeof(void *);
   1.360 +#else
   1.361 +    static const size_t REJOIN_LABEL_OFFSET = 0;
   1.362 +#endif
   1.363 +
   1.364 +    CodeLocationLabel rejoinLabel() const {
   1.365 +        uint8_t *ptr = initialJump_.raw();
   1.366 +#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
   1.367 +        uint32_t i = 0;
   1.368 +        while (i < REJOIN_LABEL_OFFSET)
   1.369 +            ptr = Assembler::nextInstruction(ptr, &i);
   1.370 +#endif
   1.371 +        return CodeLocationLabel(ptr);
   1.372 +    }
   1.373 +
   1.374 +  public:
   1.375 +    RepatchIonCache()
   1.376 +      : initialJump_(),
   1.377 +        lastJump_()
   1.378 +    {
   1.379 +    }
   1.380 +
   1.381 +    virtual void reset();
   1.382 +
   1.383 +    // Set the initial jump state of the cache. The initialJump is the inline
   1.384 +    // jump that will point to out-of-line code (such as the slow path, or
   1.385 +    // stubs), and the rejoinLabel is the position that all out-of-line paths
   1.386 +    // will rejoin to.
   1.387 +    void emitInitialJump(MacroAssembler &masm, AddCacheState &addState);
   1.388 +    void bindInitialJump(MacroAssembler &masm, AddCacheState &addState);
   1.389 +
   1.390 +    // Update the labels once the code is finalized.
   1.391 +    void updateBaseAddress(JitCode *code, MacroAssembler &masm);
   1.392 +};
   1.393 +
   1.394 +//
   1.395 +// Dispatch caches avoid patching already-running code. Instead, the jump to
   1.396 +// the stub chain is indirect by way of the firstStub_ pointer
   1.397 +// below. Initially the pointer points to the cache function which may attach
   1.398 +// new stubs. Stubs are attached by prepending: when attaching a new stub, we
   1.399 +// jump to the previous stub on failure conditions, then overwrite the
   1.400 +// firstStub_ pointer with the newly generated stub.
   1.401 +//
   1.402 +// This style does not patch the already executing instruction stream, does
   1.403 +// not need to worry about cache coherence of cached jump addresses, and does
   1.404 +// not have to worry about aligning the exit jumps to ensure atomic patching,
   1.405 +// at the expense of an extra memory read to load the very first stub.
   1.406 +//
   1.407 +// ICs that need to work in parallel execution need to be dispatch style.
   1.408 +//
   1.409 +//        Control flow               Pointers             Memory load
   1.410 +//      =======#                 ----.     .---->         ******
   1.411 +//             #                     |     |                   *
   1.412 +//             #======>              \-----/                   *******
   1.413 +//
   1.414 +// Initial state:
   1.415 +//
   1.416 +//    The first stub points to the cache function.
   1.417 +//
   1.418 +//  JIT Code
   1.419 +// +--------+                                 .-------.
   1.420 +// |        |                                 v       |
   1.421 +// |========|     +---------------+     +----------+  |
   1.422 +// |== IC ==|====>| Load and jump |====>| Cache Fn |  |
   1.423 +// |========|     +---------------+     +----------+  |
   1.424 +// |        |<=#           *                #         |
   1.425 +// |        |  #===========*================#         |
   1.426 +// +--------+       Rejoin * path                     |
   1.427 +//     |________           *                          |
   1.428 +//             |           *                          |
   1.429 +//   Dispatch  |           *                          |
   1.430 +//     IC    **|************                          |
   1.431 +//   Entry   * |                                      |
   1.432 +// +------------+                                     |
   1.433 +// | firstStub_ |-------------------------------------/
   1.434 +// +------------+
   1.435 +// |    ...     |
   1.436 +// +------------+
   1.437 +//
   1.438 +// Attaching stubs:
   1.439 +//
   1.440 +//   Assign the address of the new stub to firstStub_. The new stub jumps to
   1.441 +//   the old address held in firstStub_ on failure. Note that there is no
   1.442 +//   concept of a fallback label here, new stubs are _prepended_, as
   1.443 +//   firstStub_ always points to the _head_ of the stub chain.
   1.444 +//
   1.445 +//  JIT Code
   1.446 +// +--------+                        #=====================#   .-----.
   1.447 +// |        |                        #                     v   v     |
   1.448 +// |========|     +---------------+  #  +----------+     +------+    |
   1.449 +// |== IC ==|====>| Load and jump |==#  | Cache Fn |<====| Stub |    |
   1.450 +// |========|     +---------------+     +----------+     +------+    |
   1.451 +// |        |<=#           *                #                #       |
   1.452 +// |        |  #===========*================#================#       |
   1.453 +// +--------+       Rejoin * path                                    |
   1.454 +//     |________           *                                         |
   1.455 +//             |           *                                         |
   1.456 +//   Dispatch  |           *                                         |
   1.457 +//     IC    **|************                                         |
   1.458 +//   Entry   * |                                                     |
   1.459 +// +------------+                                                    |
   1.460 +// | firstStub_ |----------------------------------------------------/
   1.461 +// +------------+
   1.462 +// |    ...     |
   1.463 +// +------------+
   1.464 +//
   1.465 +class DispatchIonCache : public IonCache
   1.466 +{
   1.467 +  protected:
   1.468 +    class DispatchStubPrepender;
   1.469 +
   1.470 +    uint8_t *firstStub_;
   1.471 +    CodeLocationLabel rejoinLabel_;
   1.472 +    CodeOffsetLabel dispatchLabel_;
   1.473 +
   1.474 +  public:
   1.475 +    DispatchIonCache()
   1.476 +      : firstStub_(nullptr),
   1.477 +        rejoinLabel_(),
   1.478 +        dispatchLabel_()
   1.479 +    {
   1.480 +    }
   1.481 +
   1.482 +    virtual void reset();
   1.483 +    virtual void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
   1.484 +
   1.485 +    void emitInitialJump(MacroAssembler &masm, AddCacheState &addState);
   1.486 +    void bindInitialJump(MacroAssembler &masm, AddCacheState &addState);
   1.487 +
   1.488 +    // Fix up the first stub pointer once the code is finalized.
   1.489 +    void updateBaseAddress(JitCode *code, MacroAssembler &masm);
   1.490 +};
   1.491 +
   1.492 +// Define the cache kind and pre-declare data structures used for calling inline
   1.493 +// caches.
   1.494 +#define CACHE_HEADER(ickind)                                        \
   1.495 +    Kind kind() const {                                             \
   1.496 +        return IonCache::Cache_##ickind;                            \
   1.497 +    }                                                               \
   1.498 +                                                                    \
   1.499 +    bool accept(CodeGenerator *codegen, IonCacheVisitor *visitor) { \
   1.500 +        return visitor->visit##ickind##IC(codegen);                 \
   1.501 +    }                                                               \
   1.502 +                                                                    \
   1.503 +    static const VMFunction UpdateInfo;
   1.504 +
   1.505 +// Subclasses of IonCache for the various kinds of caches. These do not define
   1.506 +// new data members; all caches must be of the same size.
   1.507 +
   1.508 +// Helper for idempotent GetPropertyIC location tracking. Declared externally
   1.509 +// to be forward declarable.
   1.510 +//
   1.511 +// Since all the scripts stored in CacheLocations are guaranteed to have been
   1.512 +// Ion compiled, and are kept alive by function objects in jitcode, and since
   1.513 +// the CacheLocations only have the lifespan of the jitcode, there is no need
   1.514 +// to trace or mark any of the scripts. Since JSScripts are always allocated
   1.515 +// tenured, and never moved, we can keep raw pointers, and there is no need
   1.516 +// for HeapPtrScripts here.
   1.517 +struct CacheLocation {
   1.518 +    jsbytecode *pc;
   1.519 +    JSScript *script;
   1.520 +
   1.521 +    CacheLocation(jsbytecode *pcin, JSScript *scriptin)
   1.522 +        : pc(pcin), script(scriptin)
   1.523 +    { }
   1.524 +};
   1.525 +
   1.526 +class GetPropertyIC : public RepatchIonCache
   1.527 +{
   1.528 +  protected:
   1.529 +    // Registers live after the cache, excluding output registers. The initial
   1.530 +    // value of these registers must be preserved by the cache.
   1.531 +    RegisterSet liveRegs_;
   1.532 +
   1.533 +    Register object_;
   1.534 +    PropertyName *name_;
   1.535 +    TypedOrValueRegister output_;
   1.536 +
   1.537 +    // Only valid if idempotent
   1.538 +    size_t locationsIndex_;
   1.539 +    size_t numLocations_;
   1.540 +
   1.541 +    bool monitoredResult_ : 1;
   1.542 +    bool hasTypedArrayLengthStub_ : 1;
   1.543 +    bool hasStrictArgumentsLengthStub_ : 1;
   1.544 +    bool hasNormalArgumentsLengthStub_ : 1;
   1.545 +    bool hasGenericProxyStub_ : 1;
   1.546 +
   1.547 +  public:
   1.548 +    GetPropertyIC(RegisterSet liveRegs,
   1.549 +                  Register object, PropertyName *name,
   1.550 +                  TypedOrValueRegister output,
   1.551 +                  bool monitoredResult)
   1.552 +      : liveRegs_(liveRegs),
   1.553 +        object_(object),
   1.554 +        name_(name),
   1.555 +        output_(output),
   1.556 +        locationsIndex_(0),
   1.557 +        numLocations_(0),
   1.558 +        monitoredResult_(monitoredResult),
   1.559 +        hasTypedArrayLengthStub_(false),
   1.560 +        hasStrictArgumentsLengthStub_(false),
   1.561 +        hasNormalArgumentsLengthStub_(false),
   1.562 +        hasGenericProxyStub_(false)
   1.563 +    {
   1.564 +    }
   1.565 +
   1.566 +    CACHE_HEADER(GetProperty)
   1.567 +
   1.568 +    void reset();
   1.569 +
   1.570 +    Register object() const {
   1.571 +        return object_;
   1.572 +    }
   1.573 +    PropertyName *name() const {
   1.574 +        return name_;
   1.575 +    }
   1.576 +    TypedOrValueRegister output() const {
   1.577 +        return output_;
   1.578 +    }
   1.579 +    bool monitoredResult() const {
   1.580 +        return monitoredResult_;
   1.581 +    }
   1.582 +    bool hasTypedArrayLengthStub() const {
   1.583 +        return hasTypedArrayLengthStub_;
   1.584 +    }
   1.585 +    bool hasArgumentsLengthStub(bool strict) const {
   1.586 +        return strict ? hasStrictArgumentsLengthStub_ : hasNormalArgumentsLengthStub_;
   1.587 +    }
   1.588 +    bool hasGenericProxyStub() const {
   1.589 +        return hasGenericProxyStub_;
   1.590 +    }
   1.591 +
   1.592 +    void setLocationInfo(size_t locationsIndex, size_t numLocations) {
   1.593 +        JS_ASSERT(idempotent());
   1.594 +        JS_ASSERT(!numLocations_);
   1.595 +        JS_ASSERT(numLocations);
   1.596 +        locationsIndex_ = locationsIndex;
   1.597 +        numLocations_ = numLocations;
   1.598 +    }
   1.599 +    void getLocationInfo(uint32_t *index, uint32_t *num) const {
   1.600 +        JS_ASSERT(idempotent());
   1.601 +        *index = locationsIndex_;
   1.602 +        *num = numLocations_;
   1.603 +    }
   1.604 +
   1.605 +    enum NativeGetPropCacheability {
   1.606 +        CanAttachNone,
   1.607 +        CanAttachReadSlot,
   1.608 +        CanAttachArrayLength,
   1.609 +        CanAttachCallGetter
   1.610 +    };
   1.611 +
   1.612 +    // Helpers for CanAttachNativeGetProp
   1.613 +    typedef JSContext * Context;
   1.614 +    bool allowArrayLength(Context cx, HandleObject obj) const;
   1.615 +    bool allowGetters() const {
   1.616 +        return monitoredResult() && !idempotent();
   1.617 +    }
   1.618 +
   1.619 +    // Attach the proper stub, if possible
   1.620 +    bool tryAttachStub(JSContext *cx, IonScript *ion, HandleObject obj,
   1.621 +                       HandlePropertyName name, void *returnAddr, bool *emitted);
   1.622 +    bool tryAttachProxy(JSContext *cx, IonScript *ion, HandleObject obj,
   1.623 +                        HandlePropertyName name, void *returnAddr, bool *emitted);
   1.624 +    bool tryAttachGenericProxy(JSContext *cx, IonScript *ion, HandleObject obj,
   1.625 +                               HandlePropertyName name, void *returnAddr, bool *emitted);
   1.626 +    bool tryAttachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj,
   1.627 +                                   void *returnAddr, bool *emitted);
   1.628 +    bool tryAttachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
   1.629 +                                     HandlePropertyName name, bool resetNeeded,
   1.630 +                                     void *returnAddr, bool *emitted);
   1.631 +    bool tryAttachNative(JSContext *cx, IonScript *ion, HandleObject obj,
   1.632 +                         HandlePropertyName name, void *returnAddr, bool *emitted);
   1.633 +    bool tryAttachTypedArrayLength(JSContext *cx, IonScript *ion, HandleObject obj,
   1.634 +                                   HandlePropertyName name, bool *emitted);
   1.635 +
   1.636 +    bool tryAttachArgumentsLength(JSContext *cx, IonScript *ion, HandleObject obj,
   1.637 +                                  HandlePropertyName name, bool *emitted);
   1.638 +
   1.639 +    static bool update(JSContext *cx, size_t cacheIndex, HandleObject obj, MutableHandleValue vp);
   1.640 +};
   1.641 +
   1.642 +class SetPropertyIC : public RepatchIonCache
   1.643 +{
   1.644 +  protected:
   1.645 +    // Registers live after the cache, excluding output registers. The initial
   1.646 +    // value of these registers must be preserved by the cache.
   1.647 +    RegisterSet liveRegs_;
   1.648 +
   1.649 +    Register object_;
   1.650 +    PropertyName *name_;
   1.651 +    ConstantOrRegister value_;
   1.652 +    bool strict_;
   1.653 +    bool needsTypeBarrier_;
   1.654 +
   1.655 +    bool hasGenericProxyStub_;
   1.656 +
   1.657 +  public:
   1.658 +    SetPropertyIC(RegisterSet liveRegs, Register object, PropertyName *name,
   1.659 +                  ConstantOrRegister value, bool strict, bool needsTypeBarrier)
   1.660 +      : liveRegs_(liveRegs),
   1.661 +        object_(object),
   1.662 +        name_(name),
   1.663 +        value_(value),
   1.664 +        strict_(strict),
   1.665 +        needsTypeBarrier_(needsTypeBarrier),
   1.666 +        hasGenericProxyStub_(false)
   1.667 +    {
   1.668 +    }
   1.669 +
   1.670 +    CACHE_HEADER(SetProperty)
   1.671 +
   1.672 +    void reset();
   1.673 +
   1.674 +    Register object() const {
   1.675 +        return object_;
   1.676 +    }
   1.677 +    PropertyName *name() const {
   1.678 +        return name_;
   1.679 +    }
   1.680 +    ConstantOrRegister value() const {
   1.681 +        return value_;
   1.682 +    }
   1.683 +    bool strict() const {
   1.684 +        return strict_;
   1.685 +    }
   1.686 +    bool needsTypeBarrier() const {
   1.687 +        return needsTypeBarrier_;
   1.688 +    }
   1.689 +    bool hasGenericProxyStub() const {
   1.690 +        return hasGenericProxyStub_;
   1.691 +    }
   1.692 +
   1.693 +    enum NativeSetPropCacheability {
   1.694 +        CanAttachNone,
   1.695 +        CanAttachSetSlot,
   1.696 +        MaybeCanAttachAddSlot,
   1.697 +        CanAttachCallSetter
   1.698 +    };
   1.699 +
   1.700 +    bool attachSetSlot(JSContext *cx, IonScript *ion, HandleObject obj, HandleShape shape,
   1.701 +                       bool checkTypeset);
   1.702 +    bool attachCallSetter(JSContext *cx, IonScript *ion, HandleObject obj,
   1.703 +                          HandleObject holder, HandleShape shape, void *returnAddr);
   1.704 +    bool attachAddSlot(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldShape,
   1.705 +                       bool checkTypeset);
   1.706 +    bool attachGenericProxy(JSContext *cx, IonScript *ion, void *returnAddr);
   1.707 +    bool attachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj,
   1.708 +                                void *returnAddr);
   1.709 +    bool attachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
   1.710 +                                  void *returnAddr);
   1.711 +
   1.712 +    static bool
   1.713 +    update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue value);
   1.714 +};
   1.715 +
   1.716 +class GetElementIC : public RepatchIonCache
   1.717 +{
   1.718 +  protected:
   1.719 +    RegisterSet liveRegs_;
   1.720 +
   1.721 +    Register object_;
   1.722 +    ConstantOrRegister index_;
   1.723 +    TypedOrValueRegister output_;
   1.724 +
   1.725 +    bool monitoredResult_ : 1;
   1.726 +    bool allowDoubleResult_ : 1;
   1.727 +    bool hasDenseStub_ : 1;
   1.728 +    bool hasStrictArgumentsStub_ : 1;
   1.729 +    bool hasNormalArgumentsStub_ : 1;
   1.730 +
   1.731 +    size_t failedUpdates_;
   1.732 +
   1.733 +    static const size_t MAX_FAILED_UPDATES;
   1.734 +
   1.735 +  public:
   1.736 +    GetElementIC(RegisterSet liveRegs, Register object, ConstantOrRegister index,
   1.737 +                 TypedOrValueRegister output, bool monitoredResult, bool allowDoubleResult)
   1.738 +      : liveRegs_(liveRegs),
   1.739 +        object_(object),
   1.740 +        index_(index),
   1.741 +        output_(output),
   1.742 +        monitoredResult_(monitoredResult),
   1.743 +        allowDoubleResult_(allowDoubleResult),
   1.744 +        hasDenseStub_(false),
   1.745 +        hasStrictArgumentsStub_(false),
   1.746 +        hasNormalArgumentsStub_(false),
   1.747 +        failedUpdates_(0)
   1.748 +    {
   1.749 +    }
   1.750 +
   1.751 +    CACHE_HEADER(GetElement)
   1.752 +
   1.753 +    void reset();
   1.754 +
   1.755 +    Register object() const {
   1.756 +        return object_;
   1.757 +    }
   1.758 +    ConstantOrRegister index() const {
   1.759 +        return index_;
   1.760 +    }
   1.761 +    TypedOrValueRegister output() const {
   1.762 +        return output_;
   1.763 +    }
   1.764 +    bool monitoredResult() const {
   1.765 +        return monitoredResult_;
   1.766 +    }
   1.767 +    bool allowDoubleResult() const {
   1.768 +        return allowDoubleResult_;
   1.769 +    }
   1.770 +    bool hasDenseStub() const {
   1.771 +        return hasDenseStub_;
   1.772 +    }
   1.773 +    bool hasArgumentsStub(bool strict) const {
   1.774 +        return strict ? hasStrictArgumentsStub_ : hasNormalArgumentsStub_;
   1.775 +    }
   1.776 +    void setHasDenseStub() {
   1.777 +        JS_ASSERT(!hasDenseStub());
   1.778 +        hasDenseStub_ = true;
   1.779 +    }
   1.780 +
   1.781 +    // Helpers for CanAttachNativeGetProp
   1.782 +    typedef JSContext * Context;
   1.783 +    bool allowGetters() const { JS_ASSERT(!idempotent()); return true; }
   1.784 +    bool allowArrayLength(Context, HandleObject) const { return false; }
   1.785 +    bool canMonitorSingletonUndefinedSlot(HandleObject holder, HandleShape shape) const {
   1.786 +        return monitoredResult();
   1.787 +    }
   1.788 +
   1.789 +    static bool canAttachGetProp(JSObject *obj, const Value &idval, jsid id);
   1.790 +    static bool canAttachDenseElement(JSObject *obj, const Value &idval);
   1.791 +    static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval,
   1.792 +                                           TypedOrValueRegister output);
   1.793 +
   1.794 +    bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval,
   1.795 +                       HandlePropertyName name, void *returnAddr);
   1.796 +    bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
   1.797 +    bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
   1.798 +                                 const Value &idval);
   1.799 +    bool attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj);
   1.800 +
   1.801 +    static bool
   1.802 +    update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
   1.803 +           MutableHandleValue vp);
   1.804 +
   1.805 +    void incFailedUpdates() {
   1.806 +        failedUpdates_++;
   1.807 +    }
   1.808 +    void resetFailedUpdates() {
   1.809 +        failedUpdates_ = 0;
   1.810 +    }
   1.811 +    bool shouldDisable() const {
   1.812 +        return !canAttachStub() ||
   1.813 +               (stubCount_ == 0 && failedUpdates_ > MAX_FAILED_UPDATES);
   1.814 +    }
   1.815 +};
   1.816 +
   1.817 +class SetElementIC : public RepatchIonCache
   1.818 +{
   1.819 +  protected:
   1.820 +    Register object_;
   1.821 +    Register tempToUnboxIndex_;
   1.822 +    Register temp_;
   1.823 +    FloatRegister tempFloat_;
   1.824 +    ValueOperand index_;
   1.825 +    ConstantOrRegister value_;
   1.826 +    bool strict_;
   1.827 +    bool guardHoles_;
   1.828 +
   1.829 +    bool hasDenseStub_ : 1;
   1.830 +
   1.831 +  public:
   1.832 +    SetElementIC(Register object, Register tempToUnboxIndex, Register temp,
   1.833 +                 FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
   1.834 +                 bool strict, bool guardHoles)
   1.835 +      : object_(object),
   1.836 +        tempToUnboxIndex_(tempToUnboxIndex),
   1.837 +        temp_(temp),
   1.838 +        tempFloat_(tempFloat),
   1.839 +        index_(index),
   1.840 +        value_(value),
   1.841 +        strict_(strict),
   1.842 +        guardHoles_(guardHoles),
   1.843 +        hasDenseStub_(false)
   1.844 +    {
   1.845 +    }
   1.846 +
   1.847 +    CACHE_HEADER(SetElement)
   1.848 +
   1.849 +    void reset();
   1.850 +
   1.851 +    Register object() const {
   1.852 +        return object_;
   1.853 +    }
   1.854 +    Register tempToUnboxIndex() const {
   1.855 +        return tempToUnboxIndex_;
   1.856 +    }
   1.857 +    Register temp() const {
   1.858 +        return temp_;
   1.859 +    }
   1.860 +    FloatRegister tempFloat() const {
   1.861 +        return tempFloat_;
   1.862 +    }
   1.863 +    ValueOperand index() const {
   1.864 +        return index_;
   1.865 +    }
   1.866 +    ConstantOrRegister value() const {
   1.867 +        return value_;
   1.868 +    }
   1.869 +    bool strict() const {
   1.870 +        return strict_;
   1.871 +    }
   1.872 +    bool guardHoles() const {
   1.873 +        return guardHoles_;
   1.874 +    }
   1.875 +
   1.876 +    bool hasDenseStub() const {
   1.877 +        return hasDenseStub_;
   1.878 +    }
   1.879 +    void setHasDenseStub() {
   1.880 +        JS_ASSERT(!hasDenseStub());
   1.881 +        hasDenseStub_ = true;
   1.882 +    }
   1.883 +
   1.884 +    bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
   1.885 +    bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr);
   1.886 +
   1.887 +    static bool
   1.888 +    update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
   1.889 +           HandleValue value);
   1.890 +};
   1.891 +
   1.892 +class BindNameIC : public RepatchIonCache
   1.893 +{
   1.894 +  protected:
   1.895 +    Register scopeChain_;
   1.896 +    PropertyName *name_;
   1.897 +    Register output_;
   1.898 +
   1.899 +  public:
   1.900 +    BindNameIC(Register scopeChain, PropertyName *name, Register output)
   1.901 +      : scopeChain_(scopeChain),
   1.902 +        name_(name),
   1.903 +        output_(output)
   1.904 +    {
   1.905 +    }
   1.906 +
   1.907 +    CACHE_HEADER(BindName)
   1.908 +
   1.909 +    Register scopeChainReg() const {
   1.910 +        return scopeChain_;
   1.911 +    }
   1.912 +    HandlePropertyName name() const {
   1.913 +        return HandlePropertyName::fromMarkedLocation(&name_);
   1.914 +    }
   1.915 +    Register outputReg() const {
   1.916 +        return output_;
   1.917 +    }
   1.918 +
   1.919 +    bool attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain);
   1.920 +    bool attachNonGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain, JSObject *holder);
   1.921 +
   1.922 +    static JSObject *
   1.923 +    update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain);
   1.924 +};
   1.925 +
   1.926 +class NameIC : public RepatchIonCache
   1.927 +{
   1.928 +  protected:
   1.929 +    // Registers live after the cache, excluding output registers. The initial
   1.930 +    // value of these registers must be preserved by the cache.
   1.931 +    RegisterSet liveRegs_;
   1.932 +
   1.933 +    bool typeOf_;
   1.934 +    Register scopeChain_;
   1.935 +    PropertyName *name_;
   1.936 +    TypedOrValueRegister output_;
   1.937 +
   1.938 +  public:
   1.939 +    NameIC(RegisterSet liveRegs, bool typeOf,
   1.940 +           Register scopeChain, PropertyName *name,
   1.941 +           TypedOrValueRegister output)
   1.942 +      : liveRegs_(liveRegs),
   1.943 +        typeOf_(typeOf),
   1.944 +        scopeChain_(scopeChain),
   1.945 +        name_(name),
   1.946 +        output_(output)
   1.947 +    {
   1.948 +    }
   1.949 +
   1.950 +    CACHE_HEADER(Name)
   1.951 +
   1.952 +    Register scopeChainReg() const {
   1.953 +        return scopeChain_;
   1.954 +    }
   1.955 +    HandlePropertyName name() const {
   1.956 +        return HandlePropertyName::fromMarkedLocation(&name_);
   1.957 +    }
   1.958 +    TypedOrValueRegister outputReg() const {
   1.959 +        return output_;
   1.960 +    }
   1.961 +    bool isTypeOf() const {
   1.962 +        return typeOf_;
   1.963 +    }
   1.964 +
   1.965 +    bool attachReadSlot(JSContext *cx, IonScript *ion, HandleObject scopeChain,
   1.966 +                        HandleObject holderBase, HandleObject holder, HandleShape shape);
   1.967 +    bool attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
   1.968 +                          HandleShape shape, void *returnAddr);
   1.969 +
   1.970 +    static bool
   1.971 +    update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain, MutableHandleValue vp);
   1.972 +};
   1.973 +
   1.974 +class CallsiteCloneIC : public RepatchIonCache
   1.975 +{
   1.976 +  protected:
   1.977 +    Register callee_;
   1.978 +    Register output_;
   1.979 +    JSScript *callScript_;
   1.980 +    jsbytecode *callPc_;
   1.981 +
   1.982 +  public:
   1.983 +    CallsiteCloneIC(Register callee, JSScript *callScript, jsbytecode *callPc, Register output)
   1.984 +      : callee_(callee),
   1.985 +        output_(output),
   1.986 +        callScript_(callScript),
   1.987 +        callPc_(callPc)
   1.988 +    {
   1.989 +    }
   1.990 +
   1.991 +    CACHE_HEADER(CallsiteClone)
   1.992 +
   1.993 +    Register calleeReg() const {
   1.994 +        return callee_;
   1.995 +    }
   1.996 +    HandleScript callScript() const {
   1.997 +        return HandleScript::fromMarkedLocation(&callScript_);
   1.998 +    }
   1.999 +    jsbytecode *callPc() const {
  1.1000 +        return callPc_;
  1.1001 +    }
  1.1002 +    Register outputReg() const {
  1.1003 +        return output_;
  1.1004 +    }
  1.1005 +
  1.1006 +    bool attach(JSContext *cx, IonScript *ion, HandleFunction original, HandleFunction clone);
  1.1007 +
  1.1008 +    static JSObject *update(JSContext *cx, size_t cacheIndex, HandleObject callee);
  1.1009 +};
  1.1010 +
  1.1011 +class ParallelIonCache : public DispatchIonCache
  1.1012 +{
  1.1013 +  protected:
  1.1014 +    // A set of all objects that are stubbed. Used to detect duplicates in
  1.1015 +    // parallel execution.
  1.1016 +    ShapeSet *stubbedShapes_;
  1.1017 +
  1.1018 +    ParallelIonCache()
  1.1019 +      : stubbedShapes_(nullptr)
  1.1020 +    {
  1.1021 +    }
  1.1022 +
  1.1023 +    bool initStubbedShapes(JSContext *cx);
  1.1024 +
  1.1025 +  public:
  1.1026 +    void reset();
  1.1027 +    void destroy();
  1.1028 +
  1.1029 +    bool hasOrAddStubbedShape(LockedJSContext &cx, Shape *shape, bool *alreadyStubbed);
  1.1030 +};
  1.1031 +
  1.1032 +class GetPropertyParIC : public ParallelIonCache
  1.1033 +{
  1.1034 +  protected:
  1.1035 +    Register object_;
  1.1036 +    PropertyName *name_;
  1.1037 +    TypedOrValueRegister output_;
  1.1038 +    bool hasTypedArrayLengthStub_ : 1;
  1.1039 +
  1.1040 +   public:
  1.1041 +    GetPropertyParIC(Register object, PropertyName *name, TypedOrValueRegister output)
  1.1042 +      : object_(object),
  1.1043 +        name_(name),
  1.1044 +        output_(output),
  1.1045 +        hasTypedArrayLengthStub_(false)
  1.1046 +    {
  1.1047 +    }
  1.1048 +
  1.1049 +    CACHE_HEADER(GetPropertyPar)
  1.1050 +
  1.1051 +#ifdef JS_CODEGEN_X86
  1.1052 +    // x86 lacks a general purpose scratch register for dispatch caches and
  1.1053 +    // must be given one manually.
  1.1054 +    void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
  1.1055 +#endif
  1.1056 +
  1.1057 +    void reset();
  1.1058 +
  1.1059 +    Register object() const {
  1.1060 +        return object_;
  1.1061 +    }
  1.1062 +    PropertyName *name() const {
  1.1063 +        return name_;
  1.1064 +    }
  1.1065 +    TypedOrValueRegister output() const {
  1.1066 +        return output_;
  1.1067 +    }
  1.1068 +    bool hasTypedArrayLengthStub() const {
  1.1069 +        return hasTypedArrayLengthStub_;
  1.1070 +    }
  1.1071 +
  1.1072 +    // CanAttachNativeGetProp Helpers
  1.1073 +    typedef LockedJSContext & Context;
  1.1074 +    bool canMonitorSingletonUndefinedSlot(HandleObject, HandleShape) const { return true; }
  1.1075 +    bool allowGetters() const { return false; }
  1.1076 +    bool allowArrayLength(Context, HandleObject) const { return true; }
  1.1077 +
  1.1078 +    bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, JSObject *holder,
  1.1079 +                        Shape *shape);
  1.1080 +    bool attachArrayLength(LockedJSContext &cx, IonScript *ion, JSObject *obj);
  1.1081 +    bool attachTypedArrayLength(LockedJSContext &cx, IonScript *ion, JSObject *obj);
  1.1082 +
  1.1083 +    static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
  1.1084 +                       MutableHandleValue vp);
  1.1085 +};
  1.1086 +
  1.1087 +class GetElementParIC : public ParallelIonCache
  1.1088 +{
  1.1089 +  protected:
  1.1090 +    Register object_;
  1.1091 +    ConstantOrRegister index_;
  1.1092 +    TypedOrValueRegister output_;
  1.1093 +
  1.1094 +    bool monitoredResult_ : 1;
  1.1095 +    bool allowDoubleResult_ : 1;
  1.1096 +
  1.1097 +  public:
  1.1098 +    GetElementParIC(Register object, ConstantOrRegister index,
  1.1099 +                    TypedOrValueRegister output, bool monitoredResult, bool allowDoubleResult)
  1.1100 +      : object_(object),
  1.1101 +        index_(index),
  1.1102 +        output_(output),
  1.1103 +        monitoredResult_(monitoredResult),
  1.1104 +        allowDoubleResult_(allowDoubleResult)
  1.1105 +    {
  1.1106 +    }
  1.1107 +
  1.1108 +    CACHE_HEADER(GetElementPar)
  1.1109 +
  1.1110 +#ifdef JS_CODEGEN_X86
  1.1111 +    // x86 lacks a general purpose scratch register for dispatch caches and
  1.1112 +    // must be given one manually.
  1.1113 +    void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
  1.1114 +#endif
  1.1115 +
  1.1116 +    Register object() const {
  1.1117 +        return object_;
  1.1118 +    }
  1.1119 +    ConstantOrRegister index() const {
  1.1120 +        return index_;
  1.1121 +    }
  1.1122 +    TypedOrValueRegister output() const {
  1.1123 +        return output_;
  1.1124 +    }
  1.1125 +    bool monitoredResult() const {
  1.1126 +        return monitoredResult_;
  1.1127 +    }
  1.1128 +    bool allowDoubleResult() const {
  1.1129 +        return allowDoubleResult_;
  1.1130 +    }
  1.1131 +
  1.1132 +    // CanAttachNativeGetProp Helpers
  1.1133 +    typedef LockedJSContext & Context;
  1.1134 +    bool canMonitorSingletonUndefinedSlot(HandleObject, HandleShape) const { return true; }
  1.1135 +    bool allowGetters() const { return false; }
  1.1136 +    bool allowArrayLength(Context, HandleObject) const { return false; }
  1.1137 +
  1.1138 +    bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval,
  1.1139 +                        PropertyName *name, JSObject *holder, Shape *shape);
  1.1140 +    bool attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval);
  1.1141 +    bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, TypedArrayObject *tarr,
  1.1142 +                                 const Value &idval);
  1.1143 +
  1.1144 +    static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
  1.1145 +                       MutableHandleValue vp);
  1.1146 +
  1.1147 +};
  1.1148 +
  1.1149 +class SetPropertyParIC : public ParallelIonCache
  1.1150 +{
  1.1151 +  protected:
  1.1152 +    Register object_;
  1.1153 +    PropertyName *name_;
  1.1154 +    ConstantOrRegister value_;
  1.1155 +    bool strict_;
  1.1156 +    bool needsTypeBarrier_;
  1.1157 +
  1.1158 +  public:
  1.1159 +    SetPropertyParIC(Register object, PropertyName *name, ConstantOrRegister value,
  1.1160 +                     bool strict, bool needsTypeBarrier)
  1.1161 +      : object_(object),
  1.1162 +        name_(name),
  1.1163 +        value_(value),
  1.1164 +        strict_(strict),
  1.1165 +        needsTypeBarrier_(needsTypeBarrier)
  1.1166 +    {
  1.1167 +    }
  1.1168 +
  1.1169 +    CACHE_HEADER(SetPropertyPar)
  1.1170 +
  1.1171 +#ifdef JS_CODEGEN_X86
  1.1172 +    // x86 lacks a general purpose scratch register for dispatch caches and
  1.1173 +    // must be given one manually.
  1.1174 +    void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
  1.1175 +#endif
  1.1176 +
  1.1177 +    Register object() const {
  1.1178 +        return object_;
  1.1179 +    }
  1.1180 +    PropertyName *name() const {
  1.1181 +        return name_;
  1.1182 +    }
  1.1183 +    ConstantOrRegister value() const {
  1.1184 +        return value_;
  1.1185 +    }
  1.1186 +    bool strict() const {
  1.1187 +        return strict_;
  1.1188 +    }
  1.1189 +    bool needsTypeBarrier() const {
  1.1190 +        return needsTypeBarrier_;
  1.1191 +    }
  1.1192 +
  1.1193 +    bool attachSetSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *shape,
  1.1194 +                       bool checkTypeset);
  1.1195 +    bool attachAddSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *oldShape,
  1.1196 +                       bool checkTypeset);
  1.1197 +
  1.1198 +    static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
  1.1199 +                       HandleValue value);
  1.1200 +};
  1.1201 +
  1.1202 +class SetElementParIC : public ParallelIonCache
  1.1203 +{
  1.1204 +  protected:
  1.1205 +    Register object_;
  1.1206 +    Register tempToUnboxIndex_;
  1.1207 +    Register temp_;
  1.1208 +    FloatRegister tempFloat_;
  1.1209 +    ValueOperand index_;
  1.1210 +    ConstantOrRegister value_;
  1.1211 +    bool strict_;
  1.1212 +    bool guardHoles_;
  1.1213 +
  1.1214 +  public:
  1.1215 +    SetElementParIC(Register object, Register tempToUnboxIndex, Register temp,
  1.1216 +                    FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
  1.1217 +                    bool strict, bool guardHoles)
  1.1218 +      : object_(object),
  1.1219 +        tempToUnboxIndex_(tempToUnboxIndex),
  1.1220 +        temp_(temp),
  1.1221 +        tempFloat_(tempFloat),
  1.1222 +        index_(index),
  1.1223 +        value_(value),
  1.1224 +        strict_(strict),
  1.1225 +        guardHoles_(guardHoles)
  1.1226 +    {
  1.1227 +    }
  1.1228 +
  1.1229 +    CACHE_HEADER(SetElementPar)
  1.1230 +
  1.1231 +#ifdef JS_CODEGEN_X86
  1.1232 +    // x86 lacks a general purpose scratch register for dispatch caches and
  1.1233 +    // must be given one manually.
  1.1234 +    void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
  1.1235 +#endif
  1.1236 +
  1.1237 +    Register object() const {
  1.1238 +        return object_;
  1.1239 +    }
  1.1240 +    Register tempToUnboxIndex() const {
  1.1241 +        return tempToUnboxIndex_;
  1.1242 +    }
  1.1243 +    Register temp() const {
  1.1244 +        return temp_;
  1.1245 +    }
  1.1246 +    FloatRegister tempFloat() const {
  1.1247 +        return tempFloat_;
  1.1248 +    }
  1.1249 +    ValueOperand index() const {
  1.1250 +        return index_;
  1.1251 +    }
  1.1252 +    ConstantOrRegister value() const {
  1.1253 +        return value_;
  1.1254 +    }
  1.1255 +    bool strict() const {
  1.1256 +        return strict_;
  1.1257 +    }
  1.1258 +    bool guardHoles() const {
  1.1259 +        return guardHoles_;
  1.1260 +    }
  1.1261 +
  1.1262 +    bool attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval);
  1.1263 +    bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, TypedArrayObject *tarr);
  1.1264 +
  1.1265 +    static bool update(ForkJoinContext *cx, size_t cacheIndex, HandleObject obj,
  1.1266 +                       HandleValue idval, HandleValue value);
  1.1267 +};
  1.1268 +
  1.1269 +#undef CACHE_HEADER
  1.1270 +
  1.1271 +// Implement cache casts now that the compiler can see the inheritance.
  1.1272 +#define CACHE_CASTS(ickind)                                             \
  1.1273 +    ickind##IC &IonCache::to##ickind()                                  \
  1.1274 +    {                                                                   \
  1.1275 +        JS_ASSERT(is##ickind());                                        \
  1.1276 +        return *static_cast<ickind##IC *>(this);                        \
  1.1277 +    }                                                                   \
  1.1278 +    const ickind##IC &IonCache::to##ickind() const                      \
  1.1279 +    {                                                                   \
  1.1280 +        JS_ASSERT(is##ickind());                                        \
  1.1281 +        return *static_cast<const ickind##IC *>(this);                  \
  1.1282 +    }
  1.1283 +IONCACHE_KIND_LIST(CACHE_CASTS)
  1.1284 +#undef OPCODE_CASTS
  1.1285 +
  1.1286 +} // namespace jit
  1.1287 +} // namespace js
  1.1288 +
  1.1289 +#endif /* jit_IonCaches_h */

mercurial