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.

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

mercurial