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 */