Bug 1294650 - Install shim 'qipcap' dlls into the Firefox folder to circumvent dll injection by the 3rd party Websense product. r=aklotz a=ritu
CLOSED TREE
MozReview-Commit-ID: 11qJbfim7Lm
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"jit/SharedIC.h"#include"mozilla/Casting.h"#include"mozilla/DebugOnly.h"#include"mozilla/IntegerPrintfMacros.h"#include"mozilla/SizePrintfMacros.h"#include"mozilla/Sprintf.h"#include"jslibmath.h"#include"jstypes.h"#include"gc/Policy.h"#include"jit/BaselineCacheIR.h"#include"jit/BaselineDebugModeOSR.h"#include"jit/BaselineIC.h"#include"jit/JitSpewer.h"#include"jit/Linker.h"#include"jit/SharedICHelpers.h"#ifdef JS_ION_PERF# include "jit/PerfSpewer.h"#endif#include"jit/VMFunctions.h"#include"vm/Interpreter.h"#include"jit/MacroAssembler-inl.h"#include"vm/Interpreter-inl.h"usingmozilla::BitwiseCast;usingmozilla::DebugOnly;namespacejs{namespacejit{#ifdef JS_JITSPEWvoidFallbackICSpew(JSContext*cx,ICFallbackStub*stub,constchar*fmt,...){if(JitSpewEnabled(JitSpew_BaselineICFallback)){RootedScriptscript(cx,GetTopJitJSScript(cx));jsbytecode*pc=stub->icEntry()->pc(script);charfmtbuf[100];va_listargs;va_start(args,fmt);(void)VsprintfLiteral(fmtbuf,fmt,args);va_end(args);JitSpew(JitSpew_BaselineICFallback,"Fallback hit for (%s:%"PRIuSIZE") (pc=%"PRIuSIZE",line=%d,uses=%d,stubs=%"PRIuSIZE"): %s",script->filename(),script->lineno(),script->pcToOffset(pc),PCToLineNumber(script,pc),script->getWarmUpCount(),stub->numOptimizedStubs(),fmtbuf);}}voidTypeFallbackICSpew(JSContext*cx,ICTypeMonitor_Fallback*stub,constchar*fmt,...){if(JitSpewEnabled(JitSpew_BaselineICFallback)){RootedScriptscript(cx,GetTopJitJSScript(cx));jsbytecode*pc=stub->icEntry()->pc(script);charfmtbuf[100];va_listargs;va_start(args,fmt);(void)VsprintfLiteral(fmtbuf,fmt,args);va_end(args);JitSpew(JitSpew_BaselineICFallback,"Type monitor fallback hit for (%s:%"PRIuSIZE") (pc=%"PRIuSIZE",line=%d,uses=%d,stubs=%d): %s",script->filename(),script->lineno(),script->pcToOffset(pc),PCToLineNumber(script,pc),script->getWarmUpCount(),(int)stub->numOptimizedMonitorStubs(),fmtbuf);}}#endif // JS_JITSPEWICFallbackStub*ICEntry::fallbackStub()const{returnfirstStub()->getChainFallback();}voidIonICEntry::trace(JSTracer*trc){TraceManuallyBarrieredEdge(trc,&script_,"IonICEntry::script_");traceEntry(trc);}voidBaselineICEntry::trace(JSTracer*trc){traceEntry(trc);}voidICEntry::traceEntry(JSTracer*trc){if(!hasStub())return;for(ICStub*stub=firstStub();stub;stub=stub->next())stub->trace(trc);}ICStubConstIterator&ICStubConstIterator::operator++(){MOZ_ASSERT(currentStub_!=nullptr);currentStub_=currentStub_->next();return*this;}ICStubIterator::ICStubIterator(ICFallbackStub*fallbackStub,boolend):icEntry_(fallbackStub->icEntry()),fallbackStub_(fallbackStub),previousStub_(nullptr),currentStub_(end?fallbackStub:icEntry_->firstStub()),unlinked_(false){}ICStubIterator&ICStubIterator::operator++(){MOZ_ASSERT(currentStub_->next()!=nullptr);if(!unlinked_)previousStub_=currentStub_;currentStub_=currentStub_->next();unlinked_=false;return*this;}voidICStubIterator::unlink(JSContext*cx){MOZ_ASSERT(currentStub_->next()!=nullptr);MOZ_ASSERT(currentStub_!=fallbackStub_);MOZ_ASSERT(!unlinked_);fallbackStub_->unlinkStub(cx->zone(),previousStub_,currentStub_);// Mark the current iterator position as unlinked, so operator++ works properly.unlinked_=true;}voidICStub::markCode(JSTracer*trc,constchar*name){JitCode*stubJitCode=jitCode();TraceManuallyBarrieredEdge(trc,&stubJitCode,name);}voidICStub::updateCode(JitCode*code){// Write barrier on the old code.JitCode::writeBarrierPre(jitCode());stubCode_=code->raw();}/* static */voidICStub::trace(JSTracer*trc){markCode(trc,"shared-stub-jitcode");// If the stub is a monitored fallback stub, then mark the monitor ICs hanging// off of that stub. We don't need to worry about the regular monitored stubs,// because the regular monitored stubs will always have a monitored fallback stub// that references the same stub chain.if(isMonitoredFallback()){ICTypeMonitor_Fallback*lastMonStub=toMonitoredFallbackStub()->fallbackMonitorStub();for(ICStubConstIteratoriter(lastMonStub->firstMonitorStub());!iter.atEnd();iter++){MOZ_ASSERT_IF(iter->next()==nullptr,*iter==lastMonStub);iter->trace(trc);}}if(isUpdated()){for(ICStubConstIteratoriter(toUpdatedStub()->firstUpdateStub());!iter.atEnd();iter++){MOZ_ASSERT_IF(iter->next()==nullptr,iter->isTypeUpdate_Fallback());iter->trace(trc);}}switch(kind()){caseICStub::Call_Scripted:{ICCall_Scripted*callStub=toCall_Scripted();TraceEdge(trc,&callStub->callee(),"baseline-callscripted-callee");TraceNullableEdge(trc,&callStub->templateObject(),"baseline-callscripted-template");break;}caseICStub::Call_Native:{ICCall_Native*callStub=toCall_Native();TraceEdge(trc,&callStub->callee(),"baseline-callnative-callee");TraceNullableEdge(trc,&callStub->templateObject(),"baseline-callnative-template");break;}caseICStub::Call_ClassHook:{ICCall_ClassHook*callStub=toCall_ClassHook();TraceNullableEdge(trc,&callStub->templateObject(),"baseline-callclasshook-template");break;}caseICStub::Call_StringSplit:{ICCall_StringSplit*callStub=toCall_StringSplit();TraceEdge(trc,&callStub->templateObject(),"baseline-callstringsplit-template");TraceEdge(trc,&callStub->expectedSep(),"baseline-callstringsplit-sep");TraceEdge(trc,&callStub->expectedStr(),"baseline-callstringsplit-str");break;}caseICStub::GetElem_NativeSlotName:caseICStub::GetElem_NativeSlotSymbol:caseICStub::GetElem_UnboxedPropertyName:{ICGetElemNativeStub*getElemStub=static_cast<ICGetElemNativeStub*>(this);getElemStub->receiverGuard().trace(trc);if(getElemStub->isSymbol()){ICGetElem_NativeSlot<JS::Symbol*>*typedGetElemStub=toGetElem_NativeSlotSymbol();TraceEdge(trc,&typedGetElemStub->key(),"baseline-getelem-native-key");}else{ICGetElemNativeSlotStub<PropertyName*>*typedGetElemStub=reinterpret_cast<ICGetElemNativeSlotStub<PropertyName*>*>(this);TraceEdge(trc,&typedGetElemStub->key(),"baseline-getelem-native-key");}break;}caseICStub::GetElem_NativePrototypeSlotName:caseICStub::GetElem_NativePrototypeSlotSymbol:{ICGetElemNativeStub*getElemStub=static_cast<ICGetElemNativeStub*>(this);getElemStub->receiverGuard().trace(trc);if(getElemStub->isSymbol()){ICGetElem_NativePrototypeSlot<JS::Symbol*>*typedGetElemStub=toGetElem_NativePrototypeSlotSymbol();TraceEdge(trc,&typedGetElemStub->key(),"baseline-getelem-nativeproto-key");TraceEdge(trc,&typedGetElemStub->holder(),"baseline-getelem-nativeproto-holder");TraceEdge(trc,&typedGetElemStub->holderShape(),"baseline-getelem-nativeproto-holdershape");}else{ICGetElem_NativePrototypeSlot<PropertyName*>*typedGetElemStub=toGetElem_NativePrototypeSlotName();TraceEdge(trc,&typedGetElemStub->key(),"baseline-getelem-nativeproto-key");TraceEdge(trc,&typedGetElemStub->holder(),"baseline-getelem-nativeproto-holder");TraceEdge(trc,&typedGetElemStub->holderShape(),"baseline-getelem-nativeproto-holdershape");}break;}caseICStub::GetElem_NativePrototypeCallNativeName:caseICStub::GetElem_NativePrototypeCallNativeSymbol:caseICStub::GetElem_NativePrototypeCallScriptedName:caseICStub::GetElem_NativePrototypeCallScriptedSymbol:{ICGetElemNativeStub*getElemStub=static_cast<ICGetElemNativeStub*>(this);getElemStub->receiverGuard().trace(trc);if(getElemStub->isSymbol()){ICGetElemNativePrototypeCallStub<JS::Symbol*>*callStub=reinterpret_cast<ICGetElemNativePrototypeCallStub<JS::Symbol*>*>(this);TraceEdge(trc,&callStub->key(),"baseline-getelem-nativeprotocall-key");TraceEdge(trc,&callStub->getter(),"baseline-getelem-nativeprotocall-getter");TraceEdge(trc,&callStub->holder(),"baseline-getelem-nativeprotocall-holder");TraceEdge(trc,&callStub->holderShape(),"baseline-getelem-nativeprotocall-holdershape");}else{ICGetElemNativePrototypeCallStub<PropertyName*>*callStub=reinterpret_cast<ICGetElemNativePrototypeCallStub<PropertyName*>*>(this);TraceEdge(trc,&callStub->key(),"baseline-getelem-nativeprotocall-key");TraceEdge(trc,&callStub->getter(),"baseline-getelem-nativeprotocall-getter");TraceEdge(trc,&callStub->holder(),"baseline-getelem-nativeprotocall-holder");TraceEdge(trc,&callStub->holderShape(),"baseline-getelem-nativeprotocall-holdershape");}break;}caseICStub::GetElem_Dense:{ICGetElem_Dense*getElemStub=toGetElem_Dense();TraceEdge(trc,&getElemStub->shape(),"baseline-getelem-dense-shape");break;}caseICStub::GetElem_UnboxedArray:{ICGetElem_UnboxedArray*getElemStub=toGetElem_UnboxedArray();TraceEdge(trc,&getElemStub->group(),"baseline-getelem-unboxed-array-group");break;}caseICStub::GetElem_TypedArray:{ICGetElem_TypedArray*getElemStub=toGetElem_TypedArray();TraceEdge(trc,&getElemStub->shape(),"baseline-getelem-typedarray-shape");break;}caseICStub::SetElem_DenseOrUnboxedArray:{ICSetElem_DenseOrUnboxedArray*setElemStub=toSetElem_DenseOrUnboxedArray();TraceNullableEdge(trc,&setElemStub->shape(),"baseline-getelem-dense-shape");TraceEdge(trc,&setElemStub->group(),"baseline-setelem-dense-group");break;}caseICStub::SetElem_DenseOrUnboxedArrayAdd:{ICSetElem_DenseOrUnboxedArrayAdd*setElemStub=toSetElem_DenseOrUnboxedArrayAdd();TraceEdge(trc,&setElemStub->group(),"baseline-setelem-denseadd-group");JS_STATIC_ASSERT(ICSetElem_DenseOrUnboxedArrayAdd::MAX_PROTO_CHAIN_DEPTH==4);switch(setElemStub->protoChainDepth()){case0:setElemStub->toImpl<0>()->traceShapes(trc);break;case1:setElemStub->toImpl<1>()->traceShapes(trc);break;case2:setElemStub->toImpl<2>()->traceShapes(trc);break;case3:setElemStub->toImpl<3>()->traceShapes(trc);break;case4:setElemStub->toImpl<4>()->traceShapes(trc);break;default:MOZ_CRASH("Invalid proto stub.");}break;}caseICStub::SetElem_TypedArray:{ICSetElem_TypedArray*setElemStub=toSetElem_TypedArray();TraceEdge(trc,&setElemStub->shape(),"baseline-setelem-typedarray-shape");break;}caseICStub::TypeMonitor_SingleObject:{ICTypeMonitor_SingleObject*monitorStub=toTypeMonitor_SingleObject();TraceEdge(trc,&monitorStub->object(),"baseline-monitor-singleton");break;}caseICStub::TypeMonitor_ObjectGroup:{ICTypeMonitor_ObjectGroup*monitorStub=toTypeMonitor_ObjectGroup();TraceEdge(trc,&monitorStub->group(),"baseline-monitor-group");break;}caseICStub::TypeUpdate_SingleObject:{ICTypeUpdate_SingleObject*updateStub=toTypeUpdate_SingleObject();TraceEdge(trc,&updateStub->object(),"baseline-update-singleton");break;}caseICStub::TypeUpdate_ObjectGroup:{ICTypeUpdate_ObjectGroup*updateStub=toTypeUpdate_ObjectGroup();TraceEdge(trc,&updateStub->group(),"baseline-update-group");break;}caseICStub::In_Native:{ICIn_Native*inStub=toIn_Native();TraceEdge(trc,&inStub->shape(),"baseline-innative-stub-shape");TraceEdge(trc,&inStub->name(),"baseline-innative-stub-name");break;}caseICStub::In_NativePrototype:{ICIn_NativePrototype*inStub=toIn_NativePrototype();TraceEdge(trc,&inStub->shape(),"baseline-innativeproto-stub-shape");TraceEdge(trc,&inStub->name(),"baseline-innativeproto-stub-name");TraceEdge(trc,&inStub->holder(),"baseline-innativeproto-stub-holder");TraceEdge(trc,&inStub->holderShape(),"baseline-innativeproto-stub-holdershape");break;}caseICStub::In_NativeDoesNotExist:{ICIn_NativeDoesNotExist*inStub=toIn_NativeDoesNotExist();TraceEdge(trc,&inStub->name(),"baseline-innativedoesnotexist-stub-name");JS_STATIC_ASSERT(ICIn_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH==8);switch(inStub->protoChainDepth()){case0:inStub->toImpl<0>()->traceShapes(trc);break;case1:inStub->toImpl<1>()->traceShapes(trc);break;case2:inStub->toImpl<2>()->traceShapes(trc);break;case3:inStub->toImpl<3>()->traceShapes(trc);break;case4:inStub->toImpl<4>()->traceShapes(trc);break;case5:inStub->toImpl<5>()->traceShapes(trc);break;case6:inStub->toImpl<6>()->traceShapes(trc);break;case7:inStub->toImpl<7>()->traceShapes(trc);break;case8:inStub->toImpl<8>()->traceShapes(trc);break;default:MOZ_CRASH("Invalid proto stub.");}break;}caseICStub::In_Dense:{ICIn_Dense*inStub=toIn_Dense();TraceEdge(trc,&inStub->shape(),"baseline-in-dense-shape");break;}caseICStub::GetName_Global:{ICGetName_Global*globalStub=toGetName_Global();globalStub->receiverGuard().trace(trc);TraceEdge(trc,&globalStub->holder(),"baseline-global-stub-holder");TraceEdge(trc,&globalStub->holderShape(),"baseline-global-stub-holdershape");TraceEdge(trc,&globalStub->globalShape(),"baseline-global-stub-globalshape");break;}caseICStub::GetName_Env0:static_cast<ICGetName_Env<0>*>(this)->traceEnvironments(trc);break;caseICStub::GetName_Env1:static_cast<ICGetName_Env<1>*>(this)->traceEnvironments(trc);break;caseICStub::GetName_Env2:static_cast<ICGetName_Env<2>*>(this)->traceEnvironments(trc);break;caseICStub::GetName_Env3:static_cast<ICGetName_Env<3>*>(this)->traceEnvironments(trc);break;caseICStub::GetName_Env4:static_cast<ICGetName_Env<4>*>(this)->traceEnvironments(trc);break;caseICStub::GetName_Env5:static_cast<ICGetName_Env<5>*>(this)->traceEnvironments(trc);break;caseICStub::GetName_Env6:static_cast<ICGetName_Env<6>*>(this)->traceEnvironments(trc);break;caseICStub::GetIntrinsic_Constant:{ICGetIntrinsic_Constant*constantStub=toGetIntrinsic_Constant();TraceEdge(trc,&constantStub->value(),"baseline-getintrinsic-constant-value");break;}caseICStub::GetProp_Primitive:{ICGetProp_Primitive*propStub=toGetProp_Primitive();TraceEdge(trc,&propStub->protoShape(),"baseline-getprop-primitive-stub-shape");break;}caseICStub::GetProp_CallDOMProxyNative:caseICStub::GetProp_CallDOMProxyWithGenerationNative:{ICGetPropCallDOMProxyNativeStub*propStub;if(kind()==ICStub::GetProp_CallDOMProxyNative)propStub=toGetProp_CallDOMProxyNative();elsepropStub=toGetProp_CallDOMProxyWithGenerationNative();propStub->receiverGuard().trace(trc);TraceNullableEdge(trc,&propStub->expandoShape(),"baseline-getproplistbasenative-stub-expandoshape");TraceEdge(trc,&propStub->holder(),"baseline-getproplistbasenative-stub-holder");TraceEdge(trc,&propStub->holderShape(),"baseline-getproplistbasenative-stub-holdershape");TraceEdge(trc,&propStub->getter(),"baseline-getproplistbasenative-stub-getter");break;}caseICStub::GetProp_DOMProxyShadowed:{ICGetProp_DOMProxyShadowed*propStub=toGetProp_DOMProxyShadowed();TraceEdge(trc,&propStub->shape(),"baseline-getproplistbaseshadowed-stub-shape");TraceEdge(trc,&propStub->name(),"baseline-getproplistbaseshadowed-stub-name");break;}caseICStub::GetProp_CallScripted:{ICGetProp_CallScripted*callStub=toGetProp_CallScripted();callStub->receiverGuard().trace(trc);TraceEdge(trc,&callStub->holder(),"baseline-getpropcallscripted-stub-holder");TraceEdge(trc,&callStub->holderShape(),"baseline-getpropcallscripted-stub-holdershape");TraceEdge(trc,&callStub->getter(),"baseline-getpropcallscripted-stub-getter");break;}caseICStub::GetProp_CallNative:{ICGetProp_CallNative*callStub=toGetProp_CallNative();callStub->receiverGuard().trace(trc);TraceEdge(trc,&callStub->holder(),"baseline-getpropcallnative-stub-holder");TraceEdge(trc,&callStub->holderShape(),"baseline-getpropcallnative-stub-holdershape");TraceEdge(trc,&callStub->getter(),"baseline-getpropcallnative-stub-getter");break;}caseICStub::GetProp_CallNativeGlobal:{ICGetProp_CallNativeGlobal*callStub=toGetProp_CallNativeGlobal();callStub->receiverGuard().trace(trc);TraceEdge(trc,&callStub->holder(),"baseline-getpropcallnativeglobal-stub-holder");TraceEdge(trc,&callStub->holderShape(),"baseline-getpropcallnativeglobal-stub-holdershape");TraceEdge(trc,&callStub->globalShape(),"baseline-getpropcallnativeglobal-stub-globalshape");TraceEdge(trc,&callStub->getter(),"baseline-getpropcallnativeglobal-stub-getter");break;}caseICStub::SetProp_Native:{ICSetProp_Native*propStub=toSetProp_Native();TraceEdge(trc,&propStub->shape(),"baseline-setpropnative-stub-shape");TraceEdge(trc,&propStub->group(),"baseline-setpropnative-stub-group");break;}caseICStub::SetProp_NativeAdd:{ICSetProp_NativeAdd*propStub=toSetProp_NativeAdd();TraceEdge(trc,&propStub->group(),"baseline-setpropnativeadd-stub-group");TraceEdge(trc,&propStub->newShape(),"baseline-setpropnativeadd-stub-newshape");TraceNullableEdge(trc,&propStub->newGroup(),"baseline-setpropnativeadd-stub-new-group");JS_STATIC_ASSERT(ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH==4);switch(propStub->protoChainDepth()){case0:propStub->toImpl<0>()->traceShapes(trc);break;case1:propStub->toImpl<1>()->traceShapes(trc);break;case2:propStub->toImpl<2>()->traceShapes(trc);break;case3:propStub->toImpl<3>()->traceShapes(trc);break;case4:propStub->toImpl<4>()->traceShapes(trc);break;default:MOZ_CRASH("Invalid proto stub.");}break;}caseICStub::SetProp_Unboxed:{ICSetProp_Unboxed*propStub=toSetProp_Unboxed();TraceEdge(trc,&propStub->group(),"baseline-setprop-unboxed-stub-group");break;}caseICStub::SetProp_TypedObject:{ICSetProp_TypedObject*propStub=toSetProp_TypedObject();TraceEdge(trc,&propStub->shape(),"baseline-setprop-typedobject-stub-shape");TraceEdge(trc,&propStub->group(),"baseline-setprop-typedobject-stub-group");break;}caseICStub::SetProp_CallScripted:{ICSetProp_CallScripted*callStub=toSetProp_CallScripted();callStub->receiverGuard().trace(trc);TraceEdge(trc,&callStub->holder(),"baseline-setpropcallscripted-stub-holder");TraceEdge(trc,&callStub->holderShape(),"baseline-setpropcallscripted-stub-holdershape");TraceEdge(trc,&callStub->setter(),"baseline-setpropcallscripted-stub-setter");break;}caseICStub::SetProp_CallNative:{ICSetProp_CallNative*callStub=toSetProp_CallNative();callStub->receiverGuard().trace(trc);TraceEdge(trc,&callStub->holder(),"baseline-setpropcallnative-stub-holder");TraceEdge(trc,&callStub->holderShape(),"baseline-setpropcallnative-stub-holdershape");TraceEdge(trc,&callStub->setter(),"baseline-setpropcallnative-stub-setter");break;}caseICStub::InstanceOf_Function:{ICInstanceOf_Function*instanceofStub=toInstanceOf_Function();TraceEdge(trc,&instanceofStub->shape(),"baseline-instanceof-fun-shape");TraceEdge(trc,&instanceofStub->prototypeObject(),"baseline-instanceof-fun-prototype");break;}caseICStub::NewArray_Fallback:{ICNewArray_Fallback*stub=toNewArray_Fallback();TraceNullableEdge(trc,&stub->templateObject(),"baseline-newarray-template");TraceEdge(trc,&stub->templateGroup(),"baseline-newarray-template-group");break;}caseICStub::NewObject_Fallback:{ICNewObject_Fallback*stub=toNewObject_Fallback();TraceNullableEdge(trc,&stub->templateObject(),"baseline-newobject-template");break;}caseICStub::Rest_Fallback:{ICRest_Fallback*stub=toRest_Fallback();TraceEdge(trc,&stub->templateObject(),"baseline-rest-template");break;}caseICStub::CacheIR_Monitored:TraceBaselineCacheIRStub(trc,this,toCacheIR_Monitored()->stubInfo());break;default:break;}}voidICFallbackStub::unlinkStub(Zone*zone,ICStub*prev,ICStub*stub){MOZ_ASSERT(stub->next());// If stub is the last optimized stub, update lastStubPtrAddr.if(stub->next()==this){MOZ_ASSERT(lastStubPtrAddr_==stub->addressOfNext());if(prev)lastStubPtrAddr_=prev->addressOfNext();elselastStubPtrAddr_=icEntry()->addressOfFirstStub();*lastStubPtrAddr_=this;}else{if(prev){MOZ_ASSERT(prev->next()==stub);prev->setNext(stub->next());}else{MOZ_ASSERT(icEntry()->firstStub()==stub);icEntry()->setFirstStub(stub->next());}}MOZ_ASSERT(numOptimizedStubs_>0);numOptimizedStubs_--;if(zone->needsIncrementalBarrier()){// We are removing edges from ICStub to gcthings. Perform one final trace// of the stub for incremental GC, as it must know about those edges.stub->trace(zone->barrierTracer());}if(ICStub::CanMakeCalls(stub->kind())&&stub->isMonitored()){// This stub can make calls so we can return to it if it's on the stack.// We just have to reset its firstMonitorStub_ field to avoid a stale// pointer when purgeOptimizedStubs destroys all optimized monitor// stubs (unlinked stubs won't be updated).ICTypeMonitor_Fallback*monitorFallback=toMonitoredFallbackStub()->fallbackMonitorStub();stub->toMonitoredStub()->resetFirstMonitorStub(monitorFallback);}#ifdef DEBUG// Poison stub code to ensure we don't call this stub again. However, if this// stub can make calls, a pointer to it may be stored in a stub frame on the// stack, so we can't touch the stubCode_ or GC will crash when marking this// pointer.if(!ICStub::CanMakeCalls(stub->kind()))stub->stubCode_=(uint8_t*)0xbad;#endif}voidICFallbackStub::unlinkStubsWithKind(JSContext*cx,ICStub::Kindkind){for(ICStubIteratoriter=beginChain();!iter.atEnd();iter++){if(iter->kind()==kind)iter.unlink(cx);}}voidICTypeMonitor_Fallback::resetMonitorStubChain(Zone*zone){if(zone->needsIncrementalBarrier()){// We are removing edges from monitored stubs to gcthings (JitCode).// Perform one final trace of all monitor stubs for incremental GC,// as it must know about those edges.for(ICStub*s=firstMonitorStub_;!s->isTypeMonitor_Fallback();s=s->next())s->trace(zone->barrierTracer());}firstMonitorStub_=this;numOptimizedMonitorStubs_=0;if(hasFallbackStub_){lastMonitorStubPtrAddr_=nullptr;// Reset firstMonitorStub_ field of all monitored stubs.for(ICStubConstIteratoriter=mainFallbackStub_->beginChainConst();!iter.atEnd();iter++){if(!iter->isMonitored())continue;iter->toMonitoredStub()->resetFirstMonitorStub(this);}}else{icEntry_->setFirstStub(this);lastMonitorStubPtrAddr_=icEntry_->addressOfFirstStub();}}ICMonitoredStub::ICMonitoredStub(Kindkind,JitCode*stubCode,ICStub*firstMonitorStub):ICStub(kind,ICStub::Monitored,stubCode),firstMonitorStub_(firstMonitorStub){// In order to silence Coverity - null pointer dereference checkerMOZ_ASSERT(firstMonitorStub_);// If the first monitored stub is a ICTypeMonitor_Fallback stub, then// double check that _its_ firstMonitorStub is the same as this one.MOZ_ASSERT_IF(firstMonitorStub_->isTypeMonitor_Fallback(),firstMonitorStub_->toTypeMonitor_Fallback()->firstMonitorStub()==firstMonitorStub_);}boolICMonitoredFallbackStub::initMonitoringChain(JSContext*cx,ICStubSpace*space,ICStubCompiler::Engineengine){MOZ_ASSERT(fallbackMonitorStub_==nullptr);ICTypeMonitor_Fallback::Compilercompiler(cx,engine,this);ICTypeMonitor_Fallback*stub=compiler.getStub(space);if(!stub)returnfalse;fallbackMonitorStub_=stub;returntrue;}boolICMonitoredFallbackStub::addMonitorStubForValue(JSContext*cx,SharedStubInfo*stub,HandleValueval){returnfallbackMonitorStub_->addMonitorStubForValue(cx,stub,val);}boolICUpdatedStub::initUpdatingChain(JSContext*cx,ICStubSpace*space){MOZ_ASSERT(firstUpdateStub_==nullptr);ICTypeUpdate_Fallback::Compilercompiler(cx);ICTypeUpdate_Fallback*stub=compiler.getStub(space);if(!stub)returnfalse;firstUpdateStub_=stub;returntrue;}JitCode*ICStubCompiler::getStubCode(){JitCompartment*comp=cx->compartment()->jitCompartment();// Check for existing cached stubcode.uint32_tstubKey=getKey();JitCode*stubCode=comp->getStubCode(stubKey);if(stubCode)returnstubCode;// Compile new stubcode.JitContextjctx(cx,nullptr);MacroAssemblermasm;#ifndef JS_USE_LINK_REGISTER// The first value contains the return addres,// which we pull into ICTailCallReg for tail calls.masm.adjustFrame(sizeof(intptr_t));#endif#ifdef JS_CODEGEN_ARMmasm.setSecondScratchReg(BaselineSecondScratchReg);#endifif(!generateStubCode(masm))returnnullptr;Linkerlinker(masm);AutoFlushICacheafc("getStubCode");Rooted<JitCode*>newStubCode(cx,linker.newCode<CanGC>(cx,BASELINE_CODE));if(!newStubCode)returnnullptr;// All barriers are emitted off-by-default, enable them if needed.if(cx->zone()->needsIncrementalBarrier())newStubCode->togglePreBarriers(true,DontReprotect);// Cache newly compiled stubcode.if(!comp->putStubCode(cx,stubKey,newStubCode))returnnullptr;// After generating code, run postGenerateStubCode(). We must not fail// after this point.postGenerateStubCode(masm,newStubCode);MOZ_ASSERT(entersStubFrame_==ICStub::CanMakeCalls(kind));MOZ_ASSERT(!inStubFrame_);#ifdef JS_ION_PERFwritePerfSpewerJitCodeProfile(newStubCode,"BaselineIC");#endifreturnnewStubCode;}boolICStubCompiler::tailCallVM(constVMFunction&fun,MacroAssembler&masm){JitCode*code=cx->runtime()->jitRuntime()->getVMWrapper(fun);if(!code)returnfalse;MOZ_ASSERT(fun.expectTailCall==TailCall);uint32_targSize=fun.explicitStackSlots()*sizeof(void*);if(engine_==Engine::Baseline){EmitBaselineTailCallVM(code,masm,argSize);}else{uint32_tstackSize=argSize+fun.extraValuesToPop*sizeof(Value);EmitIonTailCallVM(code,masm,stackSize);}returntrue;}boolICStubCompiler::callVM(constVMFunction&fun,MacroAssembler&masm){MOZ_ASSERT(inStubFrame_);JitCode*code=cx->runtime()->jitRuntime()->getVMWrapper(fun);if(!code)returnfalse;MOZ_ASSERT(fun.expectTailCall==NonTailCall);if(engine_==Engine::Baseline)EmitBaselineCallVM(code,masm);elseEmitIonCallVM(code,fun.explicitStackSlots(),masm);returntrue;}boolICStubCompiler::callTypeUpdateIC(MacroAssembler&masm,uint32_tobjectOffset){JitCode*code=cx->runtime()->jitRuntime()->getVMWrapper(DoTypeUpdateFallbackInfo);if(!code)returnfalse;EmitCallTypeUpdateIC(masm,code,objectOffset);returntrue;}voidICStubCompiler::enterStubFrame(MacroAssembler&masm,Registerscratch){if(engine_==Engine::Baseline){EmitBaselineEnterStubFrame(masm,scratch);#ifdef DEBUGframePushedAtEnterStubFrame_=masm.framePushed();#endif}else{EmitIonEnterStubFrame(masm,scratch);}MOZ_ASSERT(!inStubFrame_);inStubFrame_=true;#ifdef DEBUGentersStubFrame_=true;#endif}voidICStubCompiler::leaveStubFrame(MacroAssembler&masm,boolcalledIntoIon){MOZ_ASSERT(entersStubFrame_&&inStubFrame_);inStubFrame_=false;if(engine_==Engine::Baseline){#ifdef DEBUGmasm.setFramePushed(framePushedAtEnterStubFrame_);if(calledIntoIon)masm.adjustFrame(sizeof(intptr_t));// Calls into ion have this extra.#endifEmitBaselineLeaveStubFrame(masm,calledIntoIon);}else{EmitIonLeaveStubFrame(masm);}}voidICStubCompiler::pushStubPayload(MacroAssembler&masm,Registerscratch){if(engine_==Engine::IonMonkey){masm.push(Imm32(0));return;}if(inStubFrame_){masm.loadPtr(Address(BaselineFrameReg,0),scratch);masm.pushBaselineFramePtr(scratch,scratch);}else{masm.pushBaselineFramePtr(BaselineFrameReg,scratch);}}voidICStubCompiler::PushStubPayload(MacroAssembler&masm,Registerscratch){pushStubPayload(masm,scratch);masm.adjustFrame(sizeof(intptr_t));}voidICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler&masm,Registerobj,ValueOperandval,Registerscratch,LiveGeneralRegisterSetsaveRegs){LabelskipBarrier;masm.branchPtrInNurseryChunk(Assembler::Equal,obj,scratch,&skipBarrier);masm.branchValueIsNurseryObject(Assembler::NotEqual,val,scratch,&skipBarrier);// void PostWriteBarrier(JSRuntime* rt, JSObject* obj);#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)saveRegs.add(ICTailCallReg);#endifsaveRegs.set()=GeneralRegisterSet::Intersect(saveRegs.set(),GeneralRegisterSet::Volatile());masm.PushRegsInMask(saveRegs);masm.setupUnalignedABICall(scratch);masm.movePtr(ImmPtr(cx->runtime()),scratch);masm.passABIArg(scratch);masm.passABIArg(obj);masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*,PostWriteBarrier));masm.PopRegsInMask(saveRegs);masm.bind(&skipBarrier);}SharedStubInfo::SharedStubInfo(JSContext*cx,void*payload,ICEntry*icEntry):maybeFrame_(nullptr),outerScript_(cx),innerScript_(cx),icEntry_(icEntry){if(payload){maybeFrame_=(BaselineFrame*)payload;outerScript_=maybeFrame_->script();innerScript_=maybeFrame_->script();}else{IonICEntry*entry=(IonICEntry*)icEntry;innerScript_=entry->script();// outerScript_ is initialized lazily.}}HandleScriptSharedStubInfo::outerScript(JSContext*cx){if(!outerScript_){js::jit::JitActivationIteratoriter(cx->runtime());JitFrameIteratorit(iter);MOZ_ASSERT(it.isExitFrame());++it;MOZ_ASSERT(it.isIonJS());outerScript_=it.script();MOZ_ASSERT(!it.ionScript()->invalidated());}returnouterScript_;}//// BinaryArith_Fallback//staticboolDoBinaryArithFallback(JSContext*cx,void*payload,ICBinaryArith_Fallback*stub_,HandleValuelhs,HandleValuerhs,MutableHandleValueret){SharedStubInfoinfo(cx,payload,stub_->icEntry());ICStubCompiler::Engineengine=info.engine();// This fallback stub may trigger debug mode toggling.DebugModeOSRVolatileStub<ICBinaryArith_Fallback*>stub(engine,info.maybeFrame(),stub_);jsbytecode*pc=info.pc();JSOpop=JSOp(*pc);FallbackICSpew(cx,stub,"BinaryArith(%s,%d,%d)",CodeName[op],int(lhs.isDouble()?JSVAL_TYPE_DOUBLE:lhs.extractNonDoubleType()),int(rhs.isDouble()?JSVAL_TYPE_DOUBLE:rhs.extractNonDoubleType()));// Don't pass lhs/rhs directly, we need the original values when// generating stubs.RootedValuelhsCopy(cx,lhs);RootedValuerhsCopy(cx,rhs);// Perform the compare operation.switch(op){caseJSOP_ADD:// Do an add.if(!AddValues(cx,&lhsCopy,&rhsCopy,ret))returnfalse;break;caseJSOP_SUB:if(!SubValues(cx,&lhsCopy,&rhsCopy,ret))returnfalse;break;caseJSOP_MUL:if(!MulValues(cx,&lhsCopy,&rhsCopy,ret))returnfalse;break;caseJSOP_DIV:if(!DivValues(cx,&lhsCopy,&rhsCopy,ret))returnfalse;break;caseJSOP_MOD:if(!ModValues(cx,&lhsCopy,&rhsCopy,ret))returnfalse;break;caseJSOP_POW:if(!math_pow_handle(cx,lhsCopy,rhsCopy,ret))returnfalse;break;caseJSOP_BITOR:{int32_tresult;if(!BitOr(cx,lhs,rhs,&result))returnfalse;ret.setInt32(result);break;}caseJSOP_BITXOR:{int32_tresult;if(!BitXor(cx,lhs,rhs,&result))returnfalse;ret.setInt32(result);break;}caseJSOP_BITAND:{int32_tresult;if(!BitAnd(cx,lhs,rhs,&result))returnfalse;ret.setInt32(result);break;}caseJSOP_LSH:{int32_tresult;if(!BitLsh(cx,lhs,rhs,&result))returnfalse;ret.setInt32(result);break;}caseJSOP_RSH:{int32_tresult;if(!BitRsh(cx,lhs,rhs,&result))returnfalse;ret.setInt32(result);break;}caseJSOP_URSH:{if(!UrshOperation(cx,lhs,rhs,ret))returnfalse;break;}default:MOZ_CRASH("Unhandled baseline arith op");}// Check if debug mode toggling made the stub invalid.if(stub.invalid())returntrue;if(ret.isDouble())stub->setSawDoubleResult();// Check to see if a new stub should be generated.if(stub->numOptimizedStubs()>=ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS){stub->noteUnoptimizableOperands();returntrue;}// Handle string concat.if(op==JSOP_ADD){if(lhs.isString()&&rhs.isString()){JitSpew(JitSpew_BaselineIC," Generating %s(String, String) stub",CodeName[op]);MOZ_ASSERT(ret.isString());ICBinaryArith_StringConcat::Compilercompiler(cx,engine);ICStub*strcatStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!strcatStub)returnfalse;stub->addNewStub(strcatStub);returntrue;}if((lhs.isString()&&rhs.isObject())||(lhs.isObject()&&rhs.isString())){JitSpew(JitSpew_BaselineIC," Generating %s(%s, %s) stub",CodeName[op],lhs.isString()?"String":"Object",lhs.isString()?"Object":"String");MOZ_ASSERT(ret.isString());ICBinaryArith_StringObjectConcat::Compilercompiler(cx,engine,lhs.isString());ICStub*strcatStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!strcatStub)returnfalse;stub->addNewStub(strcatStub);returntrue;}}if(((lhs.isBoolean()&&(rhs.isBoolean()||rhs.isInt32()))||(rhs.isBoolean()&&(lhs.isBoolean()||lhs.isInt32())))&&(op==JSOP_ADD||op==JSOP_SUB||op==JSOP_BITOR||op==JSOP_BITAND||op==JSOP_BITXOR)){JitSpew(JitSpew_BaselineIC," Generating %s(%s, %s) stub",CodeName[op],lhs.isBoolean()?"Boolean":"Int32",rhs.isBoolean()?"Boolean":"Int32");ICBinaryArith_BooleanWithInt32::Compilercompiler(cx,op,engine,lhs.isBoolean(),rhs.isBoolean());ICStub*arithStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!arithStub)returnfalse;stub->addNewStub(arithStub);returntrue;}// Handle only int32 or double.if(!lhs.isNumber()||!rhs.isNumber()){stub->noteUnoptimizableOperands();returntrue;}MOZ_ASSERT(ret.isNumber());if(lhs.isDouble()||rhs.isDouble()||ret.isDouble()){if(!cx->runtime()->jitSupportsFloatingPoint)returntrue;switch(op){caseJSOP_ADD:caseJSOP_SUB:caseJSOP_MUL:caseJSOP_DIV:caseJSOP_MOD:{// Unlink int32 stubs, it's faster to always use the double stub.stub->unlinkStubsWithKind(cx,ICStub::BinaryArith_Int32);JitSpew(JitSpew_BaselineIC," Generating %s(Double, Double) stub",CodeName[op]);ICBinaryArith_Double::Compilercompiler(cx,op,engine);ICStub*doubleStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!doubleStub)returnfalse;stub->addNewStub(doubleStub);returntrue;}default:break;}}if(lhs.isInt32()&&rhs.isInt32()&&op!=JSOP_POW){boolallowDouble=ret.isDouble();if(allowDouble)stub->unlinkStubsWithKind(cx,ICStub::BinaryArith_Int32);JitSpew(JitSpew_BaselineIC," Generating %s(Int32, Int32%s) stub",CodeName[op],allowDouble?" => Double":"");ICBinaryArith_Int32::CompilercompilerInt32(cx,op,engine,allowDouble);ICStub*int32Stub=compilerInt32.getStub(compilerInt32.getStubSpace(info.outerScript(cx)));if(!int32Stub)returnfalse;stub->addNewStub(int32Stub);returntrue;}// Handle Double <BITOP> Int32 or Int32 <BITOP> Double case.if(((lhs.isDouble()&&rhs.isInt32())||(lhs.isInt32()&&rhs.isDouble()))&&ret.isInt32()){switch(op){caseJSOP_BITOR:caseJSOP_BITXOR:caseJSOP_BITAND:{JitSpew(JitSpew_BaselineIC," Generating %s(%s, %s) stub",CodeName[op],lhs.isDouble()?"Double":"Int32",lhs.isDouble()?"Int32":"Double");ICBinaryArith_DoubleWithInt32::Compilercompiler(cx,op,engine,lhs.isDouble());ICStub*optStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!optStub)returnfalse;stub->addNewStub(optStub);returntrue;}default:break;}}stub->noteUnoptimizableOperands();returntrue;}typedefbool(*DoBinaryArithFallbackFn)(JSContext*,void*,ICBinaryArith_Fallback*,HandleValue,HandleValue,MutableHandleValue);staticconstVMFunctionDoBinaryArithFallbackInfo=FunctionInfo<DoBinaryArithFallbackFn>(DoBinaryArithFallback,"DoBinaryArithFallback",TailCall,PopValues(2));boolICBinaryArith_Fallback::Compiler::generateStubCode(MacroAssembler&masm){MOZ_ASSERT(R0==JSReturnOperand);// Restore the tail call register.EmitRestoreTailCallReg(masm);// Ensure stack is fully synced for the expression decompiler.masm.pushValue(R0);masm.pushValue(R1);// Push arguments.masm.pushValue(R1);masm.pushValue(R0);masm.push(ICStubReg);pushStubPayload(masm,R0.scratchReg());returntailCallVM(DoBinaryArithFallbackInfo,masm);}staticboolDoConcatStrings(JSContext*cx,HandleStringlhs,HandleStringrhs,MutableHandleValueres){JSString*result=ConcatStrings<CanGC>(cx,lhs,rhs);if(!result)returnfalse;res.setString(result);returntrue;}typedefbool(*DoConcatStringsFn)(JSContext*,HandleString,HandleString,MutableHandleValue);staticconstVMFunctionDoConcatStringsInfo=FunctionInfo<DoConcatStringsFn>(DoConcatStrings,"DoConcatStrings",TailCall);boolICBinaryArith_StringConcat::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;masm.branchTestString(Assembler::NotEqual,R0,&failure);masm.branchTestString(Assembler::NotEqual,R1,&failure);// Restore the tail call register.EmitRestoreTailCallReg(masm);masm.unboxString(R0,R0.scratchReg());masm.unboxString(R1,R1.scratchReg());masm.push(R1.scratchReg());masm.push(R0.scratchReg());if(!tailCallVM(DoConcatStringsInfo,masm))returnfalse;// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}staticJSString*ConvertObjectToStringForConcat(JSContext*cx,HandleValueobj){MOZ_ASSERT(obj.isObject());RootedValuerootedObj(cx,obj);if(!ToPrimitive(cx,&rootedObj))returnnullptr;returnToString<CanGC>(cx,rootedObj);}staticboolDoConcatStringObject(JSContext*cx,boollhsIsString,HandleValuelhs,HandleValuerhs,MutableHandleValueres){JSString*lstr=nullptr;JSString*rstr=nullptr;if(lhsIsString){// Convert rhs first.MOZ_ASSERT(lhs.isString()&&rhs.isObject());rstr=ConvertObjectToStringForConcat(cx,rhs);if(!rstr)returnfalse;// lhs is already string.lstr=lhs.toString();}else{MOZ_ASSERT(rhs.isString()&&lhs.isObject());// Convert lhs first.lstr=ConvertObjectToStringForConcat(cx,lhs);if(!lstr)returnfalse;// rhs is already string.rstr=rhs.toString();}JSString*str=ConcatStrings<NoGC>(cx,lstr,rstr);if(!str){RootedStringnlstr(cx,lstr),nrstr(cx,rstr);str=ConcatStrings<CanGC>(cx,nlstr,nrstr);if(!str)returnfalse;}// Technically, we need to call TypeScript::MonitorString for this PC, however// it was called when this stub was attached so it's OK.res.setString(str);returntrue;}typedefbool(*DoConcatStringObjectFn)(JSContext*,boollhsIsString,HandleValue,HandleValue,MutableHandleValue);staticconstVMFunctionDoConcatStringObjectInfo=FunctionInfo<DoConcatStringObjectFn>(DoConcatStringObject,"DoConcatStringObject",TailCall,PopValues(2));boolICBinaryArith_StringObjectConcat::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;if(lhsIsString_){masm.branchTestString(Assembler::NotEqual,R0,&failure);masm.branchTestObject(Assembler::NotEqual,R1,&failure);}else{masm.branchTestObject(Assembler::NotEqual,R0,&failure);masm.branchTestString(Assembler::NotEqual,R1,&failure);}// Restore the tail call register.EmitRestoreTailCallReg(masm);// Sync for the decompiler.masm.pushValue(R0);masm.pushValue(R1);// Push arguments.masm.pushValue(R1);masm.pushValue(R0);masm.push(Imm32(lhsIsString_));if(!tailCallVM(DoConcatStringObjectInfo,masm))returnfalse;// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}boolICBinaryArith_Double::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;masm.ensureDouble(R0,FloatReg0,&failure);masm.ensureDouble(R1,FloatReg1,&failure);switch(op){caseJSOP_ADD:masm.addDouble(FloatReg1,FloatReg0);break;caseJSOP_SUB:masm.subDouble(FloatReg1,FloatReg0);break;caseJSOP_MUL:masm.mulDouble(FloatReg1,FloatReg0);break;caseJSOP_DIV:masm.divDouble(FloatReg1,FloatReg0);break;caseJSOP_MOD:masm.setupUnalignedABICall(R0.scratchReg());masm.passABIArg(FloatReg0,MoveOp::DOUBLE);masm.passABIArg(FloatReg1,MoveOp::DOUBLE);masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*,NumberMod),MoveOp::DOUBLE);MOZ_ASSERT(ReturnDoubleReg==FloatReg0);break;default:MOZ_CRASH("Unexpected op");}masm.boxDouble(FloatReg0,R0);EmitReturnFromIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}boolICBinaryArith_BooleanWithInt32::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;if(lhsIsBool_)masm.branchTestBoolean(Assembler::NotEqual,R0,&failure);elsemasm.branchTestInt32(Assembler::NotEqual,R0,&failure);if(rhsIsBool_)masm.branchTestBoolean(Assembler::NotEqual,R1,&failure);elsemasm.branchTestInt32(Assembler::NotEqual,R1,&failure);RegisterlhsReg=lhsIsBool_?masm.extractBoolean(R0,ExtractTemp0):masm.extractInt32(R0,ExtractTemp0);RegisterrhsReg=rhsIsBool_?masm.extractBoolean(R1,ExtractTemp1):masm.extractInt32(R1,ExtractTemp1);MOZ_ASSERT(op_==JSOP_ADD||op_==JSOP_SUB||op_==JSOP_BITOR||op_==JSOP_BITXOR||op_==JSOP_BITAND);switch(op_){caseJSOP_ADD:{LabelfixOverflow;masm.branchAdd32(Assembler::Overflow,rhsReg,lhsReg,&fixOverflow);masm.tagValue(JSVAL_TYPE_INT32,lhsReg,R0);EmitReturnFromIC(masm);masm.bind(&fixOverflow);masm.sub32(rhsReg,lhsReg);// Proceed to failure below.break;}caseJSOP_SUB:{LabelfixOverflow;masm.branchSub32(Assembler::Overflow,rhsReg,lhsReg,&fixOverflow);masm.tagValue(JSVAL_TYPE_INT32,lhsReg,R0);EmitReturnFromIC(masm);masm.bind(&fixOverflow);masm.add32(rhsReg,lhsReg);// Proceed to failure below.break;}caseJSOP_BITOR:{masm.orPtr(rhsReg,lhsReg);masm.tagValue(JSVAL_TYPE_INT32,lhsReg,R0);EmitReturnFromIC(masm);break;}caseJSOP_BITXOR:{masm.xorPtr(rhsReg,lhsReg);masm.tagValue(JSVAL_TYPE_INT32,lhsReg,R0);EmitReturnFromIC(masm);break;}caseJSOP_BITAND:{masm.andPtr(rhsReg,lhsReg);masm.tagValue(JSVAL_TYPE_INT32,lhsReg,R0);EmitReturnFromIC(masm);break;}default:MOZ_CRASH("Unhandled op for BinaryArith_BooleanWithInt32.");}// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}boolICBinaryArith_DoubleWithInt32::Compiler::generateStubCode(MacroAssembler&masm){MOZ_ASSERT(op==JSOP_BITOR||op==JSOP_BITAND||op==JSOP_BITXOR);Labelfailure;RegisterintReg;RegisterscratchReg;if(lhsIsDouble_){masm.branchTestDouble(Assembler::NotEqual,R0,&failure);masm.branchTestInt32(Assembler::NotEqual,R1,&failure);intReg=masm.extractInt32(R1,ExtractTemp0);masm.unboxDouble(R0,FloatReg0);scratchReg=R0.scratchReg();}else{masm.branchTestInt32(Assembler::NotEqual,R0,&failure);masm.branchTestDouble(Assembler::NotEqual,R1,&failure);intReg=masm.extractInt32(R0,ExtractTemp0);masm.unboxDouble(R1,FloatReg0);scratchReg=R1.scratchReg();}// Truncate the double to an int32.{LabeldoneTruncate;LabeltruncateABICall;masm.branchTruncateDoubleMaybeModUint32(FloatReg0,scratchReg,&truncateABICall);masm.jump(&doneTruncate);masm.bind(&truncateABICall);masm.push(intReg);masm.setupUnalignedABICall(scratchReg);masm.passABIArg(FloatReg0,MoveOp::DOUBLE);masm.callWithABI(mozilla::BitwiseCast<void*,int32_t(*)(double)>(JS::ToInt32));masm.storeCallWordResult(scratchReg);masm.pop(intReg);masm.bind(&doneTruncate);}RegisterintReg2=scratchReg;// All handled ops commute, so no need to worry about ordering.switch(op){caseJSOP_BITOR:masm.orPtr(intReg,intReg2);break;caseJSOP_BITXOR:masm.xorPtr(intReg,intReg2);break;caseJSOP_BITAND:masm.andPtr(intReg,intReg2);break;default:MOZ_CRASH("Unhandled op for BinaryArith_DoubleWithInt32.");}masm.tagValue(JSVAL_TYPE_INT32,intReg2,R0);EmitReturnFromIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}//// UnaryArith_Fallback//staticboolDoUnaryArithFallback(JSContext*cx,void*payload,ICUnaryArith_Fallback*stub_,HandleValueval,MutableHandleValueres){SharedStubInfoinfo(cx,payload,stub_->icEntry());ICStubCompiler::Engineengine=info.engine();HandleScriptscript=info.innerScript();// This fallback stub may trigger debug mode toggling.DebugModeOSRVolatileStub<ICUnaryArith_Fallback*>stub(engine,info.maybeFrame(),stub_);jsbytecode*pc=info.pc();JSOpop=JSOp(*pc);FallbackICSpew(cx,stub,"UnaryArith(%s)",CodeName[op]);switch(op){caseJSOP_BITNOT:{int32_tresult;if(!BitNot(cx,val,&result))returnfalse;res.setInt32(result);break;}caseJSOP_NEG:if(!NegOperation(cx,script,pc,val,res))returnfalse;break;default:MOZ_CRASH("Unexpected op");}// Check if debug mode toggling made the stub invalid.if(stub.invalid())returntrue;if(res.isDouble())stub->setSawDoubleResult();if(stub->numOptimizedStubs()>=ICUnaryArith_Fallback::MAX_OPTIMIZED_STUBS){// TODO: Discard/replace stubs.returntrue;}if(val.isInt32()&&res.isInt32()){JitSpew(JitSpew_BaselineIC," Generating %s(Int32 => Int32) stub",CodeName[op]);ICUnaryArith_Int32::Compilercompiler(cx,op,engine);ICStub*int32Stub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!int32Stub)returnfalse;stub->addNewStub(int32Stub);returntrue;}if(val.isNumber()&&res.isNumber()&&cx->runtime()->jitSupportsFloatingPoint){JitSpew(JitSpew_BaselineIC," Generating %s(Number => Number) stub",CodeName[op]);// Unlink int32 stubs, the double stub handles both cases and TI specializes for both.stub->unlinkStubsWithKind(cx,ICStub::UnaryArith_Int32);ICUnaryArith_Double::Compilercompiler(cx,op,engine);ICStub*doubleStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!doubleStub)returnfalse;stub->addNewStub(doubleStub);returntrue;}returntrue;}typedefbool(*DoUnaryArithFallbackFn)(JSContext*,void*,ICUnaryArith_Fallback*,HandleValue,MutableHandleValue);staticconstVMFunctionDoUnaryArithFallbackInfo=FunctionInfo<DoUnaryArithFallbackFn>(DoUnaryArithFallback,"DoUnaryArithFallback",TailCall,PopValues(1));boolICUnaryArith_Fallback::Compiler::generateStubCode(MacroAssembler&masm){MOZ_ASSERT(R0==JSReturnOperand);// Restore the tail call register.EmitRestoreTailCallReg(masm);// Ensure stack is fully synced for the expression decompiler.masm.pushValue(R0);// Push arguments.masm.pushValue(R0);masm.push(ICStubReg);pushStubPayload(masm,R0.scratchReg());returntailCallVM(DoUnaryArithFallbackInfo,masm);}boolICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;masm.ensureDouble(R0,FloatReg0,&failure);MOZ_ASSERT(op==JSOP_NEG||op==JSOP_BITNOT);if(op==JSOP_NEG){masm.negateDouble(FloatReg0);masm.boxDouble(FloatReg0,R0);}else{// Truncate the double to an int32.RegisterscratchReg=R1.scratchReg();LabeldoneTruncate;LabeltruncateABICall;masm.branchTruncateDoubleMaybeModUint32(FloatReg0,scratchReg,&truncateABICall);masm.jump(&doneTruncate);masm.bind(&truncateABICall);masm.setupUnalignedABICall(scratchReg);masm.passABIArg(FloatReg0,MoveOp::DOUBLE);masm.callWithABI(BitwiseCast<void*,int32_t(*)(double)>(JS::ToInt32));masm.storeCallWordResult(scratchReg);masm.bind(&doneTruncate);masm.not32(scratchReg);masm.tagValue(JSVAL_TYPE_INT32,scratchReg,R0);}EmitReturnFromIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}//// Compare_Fallback//staticboolDoCompareFallback(JSContext*cx,void*payload,ICCompare_Fallback*stub_,HandleValuelhs,HandleValuerhs,MutableHandleValueret){SharedStubInfoinfo(cx,payload,stub_->icEntry());ICStubCompiler::Engineengine=info.engine();// This fallback stub may trigger debug mode toggling.DebugModeOSRVolatileStub<ICCompare_Fallback*>stub(engine,info.maybeFrame(),stub_);jsbytecode*pc=info.pc();JSOpop=JSOp(*pc);FallbackICSpew(cx,stub,"Compare(%s)",CodeName[op]);// Case operations in a CONDSWITCH are performing strict equality.if(op==JSOP_CASE)op=JSOP_STRICTEQ;// Don't pass lhs/rhs directly, we need the original values when// generating stubs.RootedValuelhsCopy(cx,lhs);RootedValuerhsCopy(cx,rhs);// Perform the compare operation.boolout;switch(op){caseJSOP_LT:if(!LessThan(cx,&lhsCopy,&rhsCopy,&out))returnfalse;break;caseJSOP_LE:if(!LessThanOrEqual(cx,&lhsCopy,&rhsCopy,&out))returnfalse;break;caseJSOP_GT:if(!GreaterThan(cx,&lhsCopy,&rhsCopy,&out))returnfalse;break;caseJSOP_GE:if(!GreaterThanOrEqual(cx,&lhsCopy,&rhsCopy,&out))returnfalse;break;caseJSOP_EQ:if(!LooselyEqual<true>(cx,&lhsCopy,&rhsCopy,&out))returnfalse;break;caseJSOP_NE:if(!LooselyEqual<false>(cx,&lhsCopy,&rhsCopy,&out))returnfalse;break;caseJSOP_STRICTEQ:if(!StrictlyEqual<true>(cx,&lhsCopy,&rhsCopy,&out))returnfalse;break;caseJSOP_STRICTNE:if(!StrictlyEqual<false>(cx,&lhsCopy,&rhsCopy,&out))returnfalse;break;default:MOZ_ASSERT_UNREACHABLE("Unhandled baseline compare op");returnfalse;}ret.setBoolean(out);// Check if debug mode toggling made the stub invalid.if(stub.invalid())returntrue;// Check to see if a new stub should be generated.if(stub->numOptimizedStubs()>=ICCompare_Fallback::MAX_OPTIMIZED_STUBS){// TODO: Discard all stubs in this IC and replace with inert megamorphic stub.// But for now we just bail.returntrue;}// Try to generate new stubs.if(lhs.isInt32()&&rhs.isInt32()){JitSpew(JitSpew_BaselineIC," Generating %s(Int32, Int32) stub",CodeName[op]);ICCompare_Int32::Compilercompiler(cx,op,engine);ICStub*int32Stub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!int32Stub)returnfalse;stub->addNewStub(int32Stub);returntrue;}if(!cx->runtime()->jitSupportsFloatingPoint&&(lhs.isNumber()||rhs.isNumber()))returntrue;if(lhs.isNumber()&&rhs.isNumber()){JitSpew(JitSpew_BaselineIC," Generating %s(Number, Number) stub",CodeName[op]);// Unlink int32 stubs, it's faster to always use the double stub.stub->unlinkStubsWithKind(cx,ICStub::Compare_Int32);ICCompare_Double::Compilercompiler(cx,op,engine);ICStub*doubleStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!doubleStub)returnfalse;stub->addNewStub(doubleStub);returntrue;}if((lhs.isNumber()&&rhs.isUndefined())||(lhs.isUndefined()&&rhs.isNumber())){JitSpew(JitSpew_BaselineIC," Generating %s(%s, %s) stub",CodeName[op],rhs.isUndefined()?"Number":"Undefined",rhs.isUndefined()?"Undefined":"Number");ICCompare_NumberWithUndefined::Compilercompiler(cx,op,engine,lhs.isUndefined());ICStub*doubleStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!doubleStub)returnfalse;stub->addNewStub(doubleStub);returntrue;}if(lhs.isBoolean()&&rhs.isBoolean()){JitSpew(JitSpew_BaselineIC," Generating %s(Boolean, Boolean) stub",CodeName[op]);ICCompare_Boolean::Compilercompiler(cx,op,engine);ICStub*booleanStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!booleanStub)returnfalse;stub->addNewStub(booleanStub);returntrue;}if((lhs.isBoolean()&&rhs.isInt32())||(lhs.isInt32()&&rhs.isBoolean())){JitSpew(JitSpew_BaselineIC," Generating %s(%s, %s) stub",CodeName[op],rhs.isInt32()?"Boolean":"Int32",rhs.isInt32()?"Int32":"Boolean");ICCompare_Int32WithBoolean::Compilercompiler(cx,op,engine,lhs.isInt32());ICStub*optStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!optStub)returnfalse;stub->addNewStub(optStub);returntrue;}if(IsEqualityOp(op)){if(lhs.isString()&&rhs.isString()&&!stub->hasStub(ICStub::Compare_String)){JitSpew(JitSpew_BaselineIC," Generating %s(String, String) stub",CodeName[op]);ICCompare_String::Compilercompiler(cx,op,engine);ICStub*stringStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!stringStub)returnfalse;stub->addNewStub(stringStub);returntrue;}if(lhs.isObject()&&rhs.isObject()){MOZ_ASSERT(!stub->hasStub(ICStub::Compare_Object));JitSpew(JitSpew_BaselineIC," Generating %s(Object, Object) stub",CodeName[op]);ICCompare_Object::Compilercompiler(cx,op,engine);ICStub*objectStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!objectStub)returnfalse;stub->addNewStub(objectStub);returntrue;}if((lhs.isObject()||lhs.isNull()||lhs.isUndefined())&&(rhs.isObject()||rhs.isNull()||rhs.isUndefined())&&!stub->hasStub(ICStub::Compare_ObjectWithUndefined)){JitSpew(JitSpew_BaselineIC," Generating %s(Obj/Null/Undef, Obj/Null/Undef) stub",CodeName[op]);boollhsIsUndefined=lhs.isNull()||lhs.isUndefined();boolcompareWithNull=lhs.isNull()||rhs.isNull();ICCompare_ObjectWithUndefined::Compilercompiler(cx,op,engine,lhsIsUndefined,compareWithNull);ICStub*objectStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!objectStub)returnfalse;stub->addNewStub(objectStub);returntrue;}}stub->noteUnoptimizableAccess();returntrue;}typedefbool(*DoCompareFallbackFn)(JSContext*,void*,ICCompare_Fallback*,HandleValue,HandleValue,MutableHandleValue);staticconstVMFunctionDoCompareFallbackInfo=FunctionInfo<DoCompareFallbackFn>(DoCompareFallback,"DoCompareFallback",TailCall,PopValues(2));boolICCompare_Fallback::Compiler::generateStubCode(MacroAssembler&masm){MOZ_ASSERT(R0==JSReturnOperand);// Restore the tail call register.EmitRestoreTailCallReg(masm);// Ensure stack is fully synced for the expression decompiler.masm.pushValue(R0);masm.pushValue(R1);// Push arguments.masm.pushValue(R1);masm.pushValue(R0);masm.push(ICStubReg);pushStubPayload(masm,R0.scratchReg());returntailCallVM(DoCompareFallbackInfo,masm);}//// Compare_String//boolICCompare_String::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;masm.branchTestString(Assembler::NotEqual,R0,&failure);masm.branchTestString(Assembler::NotEqual,R1,&failure);MOZ_ASSERT(IsEqualityOp(op));Registerleft=masm.extractString(R0,ExtractTemp0);Registerright=masm.extractString(R1,ExtractTemp1);AllocatableGeneralRegisterSetregs(availableGeneralRegs(2));RegisterscratchReg=regs.takeAny();masm.compareStrings(op,left,right,scratchReg,&failure);masm.tagValue(JSVAL_TYPE_BOOLEAN,scratchReg,R0);EmitReturnFromIC(masm);masm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}//// Compare_Boolean//boolICCompare_Boolean::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;masm.branchTestBoolean(Assembler::NotEqual,R0,&failure);masm.branchTestBoolean(Assembler::NotEqual,R1,&failure);Registerleft=masm.extractInt32(R0,ExtractTemp0);Registerright=masm.extractInt32(R1,ExtractTemp1);// Compare payload regs of R0 and R1.Assembler::Conditioncond=JSOpToCondition(op,/* signed = */true);masm.cmp32Set(cond,left,right,left);// Box the result and returnmasm.tagValue(JSVAL_TYPE_BOOLEAN,left,R0);EmitReturnFromIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}//// Compare_NumberWithUndefined//boolICCompare_NumberWithUndefined::Compiler::generateStubCode(MacroAssembler&masm){ValueOperandnumberOperand,undefinedOperand;if(lhsIsUndefined){numberOperand=R1;undefinedOperand=R0;}else{numberOperand=R0;undefinedOperand=R1;}Labelfailure;masm.branchTestNumber(Assembler::NotEqual,numberOperand,&failure);masm.branchTestUndefined(Assembler::NotEqual,undefinedOperand,&failure);// Comparing a number with undefined will always be true for NE/STRICTNE,// and always be false for other compare ops.masm.moveValue(BooleanValue(op==JSOP_NE||op==JSOP_STRICTNE),R0);EmitReturnFromIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}//// Compare_Object//boolICCompare_Object::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;masm.branchTestObject(Assembler::NotEqual,R0,&failure);masm.branchTestObject(Assembler::NotEqual,R1,&failure);MOZ_ASSERT(IsEqualityOp(op));Registerleft=masm.extractObject(R0,ExtractTemp0);Registerright=masm.extractObject(R1,ExtractTemp1);LabelifTrue;masm.branchPtr(JSOpToCondition(op,/* signed = */true),left,right,&ifTrue);masm.moveValue(BooleanValue(false),R0);EmitReturnFromIC(masm);masm.bind(&ifTrue);masm.moveValue(BooleanValue(true),R0);EmitReturnFromIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}//// Compare_ObjectWithUndefined//boolICCompare_ObjectWithUndefined::Compiler::generateStubCode(MacroAssembler&masm){MOZ_ASSERT(IsEqualityOp(op));ValueOperandobjectOperand,undefinedOperand;if(lhsIsUndefined){objectOperand=R1;undefinedOperand=R0;}else{objectOperand=R0;undefinedOperand=R1;}Labelfailure;if(compareWithNull)masm.branchTestNull(Assembler::NotEqual,undefinedOperand,&failure);elsemasm.branchTestUndefined(Assembler::NotEqual,undefinedOperand,&failure);LabelnotObject;masm.branchTestObject(Assembler::NotEqual,objectOperand,¬Object);if(op==JSOP_STRICTEQ||op==JSOP_STRICTNE){// obj !== undefined for all objects.masm.moveValue(BooleanValue(op==JSOP_STRICTNE),R0);EmitReturnFromIC(masm);}else{// obj != undefined only where !obj->getClass()->emulatesUndefined()LabelemulatesUndefined;Registerobj=masm.extractObject(objectOperand,ExtractTemp0);masm.loadPtr(Address(obj,JSObject::offsetOfGroup()),obj);masm.loadPtr(Address(obj,ObjectGroup::offsetOfClasp()),obj);masm.branchTest32(Assembler::NonZero,Address(obj,Class::offsetOfFlags()),Imm32(JSCLASS_EMULATES_UNDEFINED),&emulatesUndefined);masm.moveValue(BooleanValue(op==JSOP_NE),R0);EmitReturnFromIC(masm);masm.bind(&emulatesUndefined);masm.moveValue(BooleanValue(op==JSOP_EQ),R0);EmitReturnFromIC(masm);}masm.bind(¬Object);// Also support null == null or undefined == undefined comparisons.if(compareWithNull)masm.branchTestNull(Assembler::NotEqual,objectOperand,&failure);elsemasm.branchTestUndefined(Assembler::NotEqual,objectOperand,&failure);masm.moveValue(BooleanValue(op==JSOP_STRICTEQ||op==JSOP_EQ),R0);EmitReturnFromIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}//// Compare_Int32WithBoolean//boolICCompare_Int32WithBoolean::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;ValueOperandint32Val;ValueOperandboolVal;if(lhsIsInt32_){int32Val=R0;boolVal=R1;}else{boolVal=R0;int32Val=R1;}masm.branchTestBoolean(Assembler::NotEqual,boolVal,&failure);masm.branchTestInt32(Assembler::NotEqual,int32Val,&failure);if(op_==JSOP_STRICTEQ||op_==JSOP_STRICTNE){// Ints and booleans are never strictly equal, always strictly not equal.masm.moveValue(BooleanValue(op_==JSOP_STRICTNE),R0);EmitReturnFromIC(masm);}else{RegisterboolReg=masm.extractBoolean(boolVal,ExtractTemp0);Registerint32Reg=masm.extractInt32(int32Val,ExtractTemp1);// Compare payload regs of R0 and R1.Assembler::Conditioncond=JSOpToCondition(op_,/* signed = */true);masm.cmp32Set(cond,(lhsIsInt32_?int32Reg:boolReg),(lhsIsInt32_?boolReg:int32Reg),R0.scratchReg());// Box the result and returnmasm.tagValue(JSVAL_TYPE_BOOLEAN,R0.scratchReg(),R0);EmitReturnFromIC(masm);}// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}//// GetProp_Fallback//staticboolTryAttachMagicArgumentsGetPropStub(JSContext*cx,SharedStubInfo*info,ICGetProp_Fallback*stub,HandlePropertyNamename,HandleValueval,HandleValueres,bool*attached){MOZ_ASSERT(!*attached);if(!val.isMagic(JS_OPTIMIZED_ARGUMENTS))returntrue;// Try handling arguments.callee on optimized arguments.if(name==cx->names().callee){MOZ_ASSERT(info->script()->hasMappedArgsObj());JitSpew(JitSpew_BaselineIC," Generating GetProp(MagicArgs.callee) stub");// Unlike ICGetProp_ArgumentsLength, only magic argument stubs are// supported at the moment.ICStub*monitorStub=stub->fallbackMonitorStub()->firstMonitorStub();ICGetProp_ArgumentsCallee::Compilercompiler(cx,info->engine(),monitorStub);ICStub*newStub=compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));if(!newStub)returnfalse;stub->addNewStub(newStub);*attached=true;returntrue;}returntrue;}staticboolTryAttachLengthStub(JSContext*cx,SharedStubInfo*info,ICGetProp_Fallback*stub,HandleValueval,HandleValueres,bool*attached){MOZ_ASSERT(!*attached);if(val.isString()){MOZ_ASSERT(res.isInt32());JitSpew(JitSpew_BaselineIC," Generating GetProp(String.length) stub");ICGetProp_StringLength::Compilercompiler(cx,info->engine());ICStub*newStub=compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));if(!newStub)returnfalse;*attached=true;stub->addNewStub(newStub);returntrue;}if(val.isMagic(JS_OPTIMIZED_ARGUMENTS)&&res.isInt32()){JitSpew(JitSpew_BaselineIC," Generating GetProp(MagicArgs.length) stub");ICGetProp_ArgumentsLength::Compilercompiler(cx,info->engine(),ICGetProp_ArgumentsLength::Magic);ICStub*newStub=compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));if(!newStub)returnfalse;*attached=true;stub->addNewStub(newStub);returntrue;}returntrue;}staticboolUpdateExistingGenerationalDOMProxyStub(ICGetProp_Fallback*stub,HandleObjectobj){ValueexpandoSlot=GetProxyExtra(obj,GetDOMProxyExpandoSlot());MOZ_ASSERT(!expandoSlot.isObject()&&!expandoSlot.isUndefined());ExpandoAndGeneration*expandoAndGeneration=(ExpandoAndGeneration*)expandoSlot.toPrivate();for(ICStubConstIteratoriter=stub->beginChainConst();!iter.atEnd();iter++){if(iter->isGetProp_CallDOMProxyWithGenerationNative()){ICGetProp_CallDOMProxyWithGenerationNative*updateStub=iter->toGetProp_CallDOMProxyWithGenerationNative();if(updateStub->expandoAndGeneration()==expandoAndGeneration){// Update generationuint64_tgeneration=expandoAndGeneration->generation;JitSpew(JitSpew_BaselineIC," Updating existing stub with generation, old value: %i, ""new value: %"PRIu64"",updateStub->generation(),generation);updateStub->setGeneration(generation);returntrue;}}}returnfalse;}// Return whether obj is in some PreliminaryObjectArray and has a structure// that might change in the future.boolIsPreliminaryObject(JSObject*obj){if(obj->isSingleton())returnfalse;TypeNewScript*newScript=obj->group()->newScript();if(newScript&&!newScript->analyzed())returntrue;if(obj->group()->maybePreliminaryObjects())returntrue;returnfalse;}voidStripPreliminaryObjectStubs(JSContext*cx,ICFallbackStub*stub){// Before the new script properties analysis has been performed on a type,// all instances of that type have the maximum number of fixed slots.// Afterwards, the objects (even the preliminary ones) might be changed// to reduce the number of fixed slots they have. If we generate stubs for// both the old and new number of fixed slots, the stub will look// polymorphic to IonBuilder when it is actually monomorphic. To avoid// this, strip out any stubs for preliminary objects before attaching a new// stub which isn't on a preliminary object.for(ICStubIteratoriter=stub->beginChain();!iter.atEnd();iter++){if(iter->isCacheIR_Monitored()&&iter->toCacheIR_Monitored()->hasPreliminaryObject())iter.unlink(cx);elseif(iter->isSetProp_Native()&&iter->toSetProp_Native()->hasPreliminaryObject())iter.unlink(cx);}}JSObject*GetDOMProxyProto(JSObject*obj){MOZ_ASSERT(IsCacheableDOMProxy(obj));returnobj->staticPrototype();}// Look up a property's shape on an object, being careful never to do any effectful// operations. This procedure not yielding a shape should not be taken as a lack of// existence of the property on the object.boolEffectlesslyLookupProperty(JSContext*cx,HandleObjectobj,HandleIdid,MutableHandleObjectholder,MutableHandleShapeshape,bool*checkDOMProxy,DOMProxyShadowsResult*shadowsResult,bool*domProxyHasGeneration){shape.set(nullptr);holder.set(nullptr);if(checkDOMProxy){*checkDOMProxy=false;*shadowsResult=ShadowCheckFailed;}// Check for list base if asked to.RootedObjectcheckObj(cx,obj);if(checkDOMProxy&&IsCacheableDOMProxy(obj)){MOZ_ASSERT(domProxyHasGeneration);MOZ_ASSERT(shadowsResult);*checkDOMProxy=true;if(obj->hasUncacheableProto())returntrue;*shadowsResult=GetDOMProxyShadowsCheck()(cx,obj,id);if(*shadowsResult==ShadowCheckFailed)returnfalse;if(DOMProxyIsShadowing(*shadowsResult)){holder.set(obj);returntrue;}*domProxyHasGeneration=(*shadowsResult==DoesntShadowUnique);checkObj=GetDOMProxyProto(obj);if(!checkObj)returntrue;}if(LookupPropertyPure(cx,checkObj,id,holder.address(),shape.address()))returntrue;holder.set(nullptr);shape.set(nullptr);returntrue;}boolIsCacheableProtoChain(JSObject*obj,JSObject*holder,boolisDOMProxy){MOZ_ASSERT_IF(isDOMProxy,IsCacheableDOMProxy(obj));if(!isDOMProxy&&!obj->isNative()){if(obj==holder)returnfalse;if(!obj->is<UnboxedPlainObject>()&&!obj->is<UnboxedArrayObject>()&&!obj->is<TypedObject>()){returnfalse;}}JSObject*cur=obj;while(cur!=holder){// We cannot assume that we find the holder object on the prototype// chain and must check for null proto. The prototype chain can be// altered during the lookupProperty call.MOZ_ASSERT(!cur->hasDynamicPrototype());// Don't handle objects which require a prototype guard. This should// be uncommon so handling it is likely not worth the complexity.if(cur->hasUncacheableProto())returnfalse;JSObject*proto=cur->staticPrototype();if(!proto||!proto->isNative())returnfalse;cur=proto;}returntrue;}boolIsCacheableGetPropReadSlot(JSObject*obj,JSObject*holder,Shape*shape,boolisDOMProxy){if(!shape||!IsCacheableProtoChain(obj,holder,isDOMProxy))returnfalse;if(!shape->hasSlot()||!shape->hasDefaultGetter())returnfalse;returntrue;}voidGetFixedOrDynamicSlotOffset(Shape*shape,bool*isFixed,uint32_t*offset){MOZ_ASSERT(isFixed);MOZ_ASSERT(offset);*isFixed=shape->slot()<shape->numFixedSlots();*offset=*isFixed?NativeObject::getFixedSlotOffset(shape->slot()):(shape->slot()-shape->numFixedSlots())*sizeof(Value);}boolIsCacheableGetPropCall(JSContext*cx,JSObject*obj,JSObject*holder,Shape*shape,bool*isScripted,bool*isTemporarilyUnoptimizable,boolisDOMProxy){MOZ_ASSERT(isScripted);if(!shape||!IsCacheableProtoChain(obj,holder,isDOMProxy))returnfalse;if(shape->hasSlot()||shape->hasDefaultGetter())returnfalse;if(!shape->hasGetterValue())returnfalse;if(!shape->getterValue().isObject()||!shape->getterObject()->is<JSFunction>())returnfalse;JSFunction*func=&shape->getterObject()->as<JSFunction>();if(IsWindow(obj)){if(!func->isNative())returnfalse;if(!func->jitInfo()||func->jitInfo()->needsOuterizedThisObject())returnfalse;}if(func->isNative()){*isScripted=false;returntrue;}if(!func->hasJITCode()){*isTemporarilyUnoptimizable=true;returnfalse;}*isScripted=true;returntrue;}// Try to update all existing GetProp/GetName getter call stubs that match the// given holder in place with a new shape and getter. fallbackStub can be// either an ICGetProp_Fallback or an ICGetName_Fallback.//// If 'getter' is an own property, holder == receiver must be true.boolUpdateExistingGetPropCallStubs(ICFallbackStub*fallbackStub,ICStub::Kindkind,HandleNativeObjectholder,HandleObjectreceiver,HandleFunctiongetter){MOZ_ASSERT(kind==ICStub::GetProp_CallScripted||kind==ICStub::GetProp_CallNative||kind==ICStub::GetProp_CallNativeGlobal);MOZ_ASSERT(fallbackStub->isGetName_Fallback()||fallbackStub->isGetProp_Fallback());MOZ_ASSERT(holder);MOZ_ASSERT(receiver);boolisOwnGetter=(holder==receiver);boolfoundMatchingStub=false;ReceiverGuardreceiverGuard(receiver);for(ICStubConstIteratoriter=fallbackStub->beginChainConst();!iter.atEnd();iter++){if(iter->kind()==kind){ICGetPropCallGetter*getPropStub=static_cast<ICGetPropCallGetter*>(*iter);if(getPropStub->holder()==holder&&getPropStub->isOwnGetter()==isOwnGetter){// If this is an own getter, update the receiver guard as well,// since that's the shape we'll be guarding on. Furthermore,// isOwnGetter() relies on holderShape_ and receiverGuard_ being// the same shape.if(isOwnGetter)getPropStub->receiverGuard().update(receiverGuard);MOZ_ASSERT(getPropStub->holderShape()!=holder->lastProperty()||!getPropStub->receiverGuard().matches(receiverGuard)||getPropStub->toGetProp_CallNativeGlobal()->globalShape()!=receiver->as<LexicalEnvironmentObject>().global().lastProperty(),"Why didn't we end up using this stub?");// We want to update the holder shape to match the new one no// matter what, even if the receiver shape is different.getPropStub->holderShape()=holder->lastProperty();// Make sure to update the getter, since a shape change might// have changed which getter we want to use.getPropStub->getter()=getter;if(getPropStub->isGetProp_CallNativeGlobal()){ICGetProp_CallNativeGlobal*globalStub=getPropStub->toGetProp_CallNativeGlobal();globalStub->globalShape()=receiver->as<LexicalEnvironmentObject>().global().lastProperty();}if(getPropStub->receiverGuard().matches(receiverGuard))foundMatchingStub=true;}}}returnfoundMatchingStub;}staticboolTryAttachNativeGetAccessorPropStub(JSContext*cx,SharedStubInfo*info,ICGetProp_Fallback*stub,HandlePropertyNamename,HandleValueval,HandleValueres,bool*attached,bool*isTemporarilyUnoptimizable){MOZ_ASSERT(!*attached);MOZ_ASSERT(!*isTemporarilyUnoptimizable);if(!val.isObject())returntrue;RootedObjectobj(cx,&val.toObject());boolisDOMProxy;booldomProxyHasGeneration;DOMProxyShadowsResultdomProxyShadowsResult;RootedShapeshape(cx);RootedObjectholder(cx);RootedIdid(cx,NameToId(name));if(!EffectlesslyLookupProperty(cx,obj,id,&holder,&shape,&isDOMProxy,&domProxyShadowsResult,&domProxyHasGeneration)){returnfalse;}ICStub*monitorStub=stub->fallbackMonitorStub()->firstMonitorStub();boolisScripted=false;boolcacheableCall=IsCacheableGetPropCall(cx,obj,holder,shape,&isScripted,isTemporarilyUnoptimizable,isDOMProxy);// Try handling scripted getters.if(cacheableCall&&isScripted&&!isDOMProxy&&info->engine()==ICStubCompiler::Engine::Baseline){RootedFunctioncallee(cx,&shape->getterObject()->as<JSFunction>());MOZ_ASSERT(callee->hasScript());if(UpdateExistingGetPropCallStubs(stub,ICStub::GetProp_CallScripted,holder.as<NativeObject>(),obj,callee)){*attached=true;returntrue;}JitSpew(JitSpew_BaselineIC," Generating GetProp(NativeObj/ScriptedGetter %s:%"PRIuSIZE") stub",callee->nonLazyScript()->filename(),callee->nonLazyScript()->lineno());ICGetProp_CallScripted::Compilercompiler(cx,monitorStub,obj,holder,callee,info->pcOffset());ICStub*newStub=compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));if(!newStub)returnfalse;stub->addNewStub(newStub);*attached=true;returntrue;}// If it's a shadowed listbase proxy property, attach stub to call Proxy::get instead.if(isDOMProxy&&DOMProxyIsShadowing(domProxyShadowsResult)){MOZ_ASSERT(obj==holder);JitSpew(JitSpew_BaselineIC," Generating GetProp(DOMProxyProxy) stub");Rooted<ProxyObject*>proxy(cx,&obj->as<ProxyObject>());ICGetProp_DOMProxyShadowed::Compilercompiler(cx,info->engine(),monitorStub,proxy,name,info->pcOffset());ICStub*newStub=compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));if(!newStub)returnfalse;stub->addNewStub(newStub);*attached=true;returntrue;}constClass*outerClass=nullptr;if(!isDOMProxy&&!obj->isNative()){outerClass=obj->getClass();if(!IsWindowProxy(obj))returntrue;// This must be a WindowProxy for the current Window/global. Else it'd// be a cross-compartment wrapper and IsWindowProxy returns false for// those.MOZ_ASSERT(ToWindowIfWindowProxy(obj)==cx->global());obj=cx->global();if(!EffectlesslyLookupProperty(cx,obj,id,&holder,&shape,&isDOMProxy,&domProxyShadowsResult,&domProxyHasGeneration)){returnfalse;}cacheableCall=IsCacheableGetPropCall(cx,obj,holder,shape,&isScripted,isTemporarilyUnoptimizable,isDOMProxy);}// Try handling JSNative getters.if(!cacheableCall||isScripted)returntrue;if(!shape||!shape->hasGetterValue()||!shape->getterValue().isObject()||!shape->getterObject()->is<JSFunction>()){returntrue;}RootedFunctioncallee(cx,&shape->getterObject()->as<JSFunction>());MOZ_ASSERT(callee->isNative());if(outerClass&&(!callee->jitInfo()||callee->jitInfo()->needsOuterizedThisObject()))returntrue;JitSpew(JitSpew_BaselineIC," Generating GetProp(%s%s/NativeGetter %p) stub",isDOMProxy?"DOMProxyObj":"NativeObj",isDOMProxy&&domProxyHasGeneration?"WithGeneration":"",callee->native());ICStub*newStub=nullptr;if(isDOMProxy){MOZ_ASSERT(obj!=holder);ICStub::Kindkind;if(domProxyHasGeneration){if(UpdateExistingGenerationalDOMProxyStub(stub,obj)){*attached=true;returntrue;}kind=ICStub::GetProp_CallDOMProxyWithGenerationNative;}else{kind=ICStub::GetProp_CallDOMProxyNative;}Rooted<ProxyObject*>proxy(cx,&obj->as<ProxyObject>());ICGetPropCallDOMProxyNativeCompilercompiler(cx,kind,info->engine(),monitorStub,proxy,holder,callee,info->pcOffset());newStub=compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));}else{if(UpdateExistingGetPropCallStubs(stub,ICStub::GetProp_CallNative,holder.as<NativeObject>(),obj,callee)){*attached=true;returntrue;}ICGetPropCallNativeCompilercompiler(cx,ICStub::GetProp_CallNative,info->engine(),monitorStub,obj,holder,callee,info->pcOffset(),outerClass);newStub=compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));}if(!newStub)returnfalse;stub->addNewStub(newStub);*attached=true;returntrue;}staticboolTryAttachPrimitiveGetPropStub(JSContext*cx,SharedStubInfo*info,ICGetProp_Fallback*stub,HandlePropertyNamename,HandleValueval,HandleValueres,bool*attached){MOZ_ASSERT(!*attached);JSValueTypeprimitiveType;RootedNativeObjectproto(cx);Rooted<GlobalObject*>global(cx,&info->script()->global());if(val.isString()){primitiveType=JSVAL_TYPE_STRING;proto=GlobalObject::getOrCreateStringPrototype(cx,global);}elseif(val.isSymbol()){primitiveType=JSVAL_TYPE_SYMBOL;proto=GlobalObject::getOrCreateSymbolPrototype(cx,global);}elseif(val.isNumber()){primitiveType=JSVAL_TYPE_DOUBLE;proto=GlobalObject::getOrCreateNumberPrototype(cx,global);}else{MOZ_ASSERT(val.isBoolean());primitiveType=JSVAL_TYPE_BOOLEAN;proto=GlobalObject::getOrCreateBooleanPrototype(cx,global);}if(!proto)returnfalse;// Instantiate this property, for use during Ion compilation.RootedIdid(cx,NameToId(name));if(IsIonEnabled(cx))EnsureTrackPropertyTypes(cx,proto,id);// For now, only look for properties directly set on the prototype.RootedShapeshape(cx,proto->lookup(cx,id));if(!shape||!shape->hasSlot()||!shape->hasDefaultGetter())returntrue;boolisFixedSlot;uint32_toffset;GetFixedOrDynamicSlotOffset(shape,&isFixedSlot,&offset);ICStub*monitorStub=stub->fallbackMonitorStub()->firstMonitorStub();JitSpew(JitSpew_BaselineIC," Generating GetProp_Primitive stub");ICGetProp_Primitive::Compilercompiler(cx,info->engine(),monitorStub,primitiveType,proto,isFixedSlot,offset);ICStub*newStub=compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));if(!newStub)returnfalse;stub->addNewStub(newStub);*attached=true;returntrue;}boolCheckHasNoSuchProperty(JSContext*cx,JSObject*obj,PropertyName*name,JSObject**lastProto,size_t*protoChainDepthOut){size_tdepth=0;JSObject*curObj=obj;while(curObj){if(curObj->isNative()){// Don't handle proto chains with resolve hooks.if(ClassMayResolveId(cx->names(),curObj->getClass(),NameToId(name),curObj))returnfalse;if(curObj->as<NativeObject>().contains(cx,NameToId(name)))returnfalse;if(curObj->getClass()->getGetProperty())returnfalse;}elseif(curObj!=obj){// Non-native objects are only handled as the original receiver.returnfalse;}elseif(curObj->is<UnboxedPlainObject>()){if(curObj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx,NameToId(name)))returnfalse;}elseif(curObj->is<UnboxedArrayObject>()){if(name==cx->names().length)returnfalse;}elseif(curObj->is<TypedObject>()){if(curObj->as<TypedObject>().typeDescr().hasProperty(cx->names(),NameToId(name)))returnfalse;}else{returnfalse;}JSObject*proto=curObj->staticPrototype();if(!proto)break;curObj=proto;depth++;}if(lastProto)*lastProto=curObj;if(protoChainDepthOut)*protoChainDepthOut=depth;returntrue;}staticboolComputeGetPropResult(JSContext*cx,BaselineFrame*frame,JSOpop,HandlePropertyNamename,MutableHandleValueval,MutableHandleValueres){// Handle arguments.length and arguments.callee on optimized arguments, as// it is not an object.if(frame&&val.isMagic(JS_OPTIMIZED_ARGUMENTS)&&IsOptimizedArguments(frame,val)){if(op==JSOP_LENGTH){res.setInt32(frame->numActualArgs());}else{MOZ_ASSERT(name==cx->names().callee);MOZ_ASSERT(frame->script()->hasMappedArgsObj());res.setObject(*frame->callee());}}else{if(op==JSOP_GETXPROP){RootedObjectobj(cx,&val.toObject());RootedIdid(cx,NameToId(name));if(!GetPropertyForNameLookup(cx,obj,id,res))returnfalse;}else{MOZ_ASSERT(op==JSOP_GETPROP||op==JSOP_CALLPROP||op==JSOP_LENGTH);if(!GetProperty(cx,val,name,res))returnfalse;}}returntrue;}staticboolDoGetPropFallback(JSContext*cx,void*payload,ICGetProp_Fallback*stub_,MutableHandleValueval,MutableHandleValueres){SharedStubInfoinfo(cx,payload,stub_->icEntry());ICStubCompiler::Engineengine=info.engine();HandleScriptscript=info.innerScript();// This fallback stub may trigger debug mode toggling.DebugModeOSRVolatileStub<ICGetProp_Fallback*>stub(engine,info.maybeFrame(),stub_);jsbytecode*pc=info.pc();JSOpop=JSOp(*pc);FallbackICSpew(cx,stub,"GetProp(%s)",CodeName[op]);MOZ_ASSERT(op==JSOP_GETPROP||op==JSOP_CALLPROP||op==JSOP_LENGTH||op==JSOP_GETXPROP);// Grab our old shape before it goes away.RootedShapeoldShape(cx);if(val.isObject())oldShape=val.toObject().maybeShape();boolattached=false;// There are some reasons we can fail to attach a stub that are temporary.// We want to avoid calling noteUnoptimizableAccess() if the reason we// failed to attach a stub is one of those temporary reasons, since we might// end up attaching a stub for the exact same access later.boolisTemporarilyUnoptimizable=false;RootedPropertyNamename(cx,script->getName(pc));// After the Genericstub was added, we should never reach the Fallbackstub again.MOZ_ASSERT(!stub->hasStub(ICStub::GetProp_Generic));if(stub->numOptimizedStubs()>=ICGetProp_Fallback::MAX_OPTIMIZED_STUBS&&!stub.invalid()){// Discard all stubs in this IC and replace with generic getprop stub.for(ICStubIteratoriter=stub->beginChain();!iter.atEnd();iter++)iter.unlink(cx);ICGetProp_Generic::Compilercompiler(cx,engine,stub->fallbackMonitorStub()->firstMonitorStub());ICStub*newStub=compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));if(!newStub)returnfalse;stub->addNewStub(newStub);attached=true;}if(!attached&&!JitOptions.disableCacheIR){mozilla::Maybe<CacheIRWriter>writer;GetPropIRGeneratorgen(cx,pc,val,name,res);if(!gen.tryAttachStub(writer))returnfalse;if(gen.emitted()){ICStub*newStub=AttachBaselineCacheIRStub(cx,writer.ref(),CacheKind::GetProp,stub);if(newStub){JitSpew(JitSpew_BaselineIC," Attached CacheIR stub");attached=true;if(gen.shouldNotePreliminaryObjectStub())newStub->toCacheIR_Monitored()->notePreliminaryObject();elseif(gen.shouldUnlinkPreliminaryObjectStubs())StripPreliminaryObjectStubs(cx,stub);}}}if(!attached&&!stub.invalid()&&!TryAttachNativeGetAccessorPropStub(cx,&info,stub,name,val,res,&attached,&isTemporarilyUnoptimizable)){returnfalse;}if(!ComputeGetPropResult(cx,info.maybeFrame(),op,name,val,res))returnfalse;TypeScript::Monitor(cx,script,pc,res);// Check if debug mode toggling made the stub invalid.if(stub.invalid())returntrue;// Add a type monitor stub for the resulting value.if(!stub->addMonitorStubForValue(cx,&info,res))returnfalse;if(attached)returntrue;if(op==JSOP_LENGTH){if(!TryAttachLengthStub(cx,&info,stub,val,res,&attached))returnfalse;if(attached)returntrue;}if(!TryAttachMagicArgumentsGetPropStub(cx,&info,stub,name,val,res,&attached))returnfalse;if(attached)returntrue;if(val.isString()||val.isNumber()||val.isBoolean()){if(!TryAttachPrimitiveGetPropStub(cx,&info,stub,name,val,res,&attached))returnfalse;if(attached)returntrue;}MOZ_ASSERT(!attached);if(!isTemporarilyUnoptimizable)stub->noteUnoptimizableAccess();returntrue;}typedefbool(*DoGetPropFallbackFn)(JSContext*,void*,ICGetProp_Fallback*,MutableHandleValue,MutableHandleValue);staticconstVMFunctionDoGetPropFallbackInfo=FunctionInfo<DoGetPropFallbackFn>(DoGetPropFallback,"DoGetPropFallback",TailCall,PopValues(1));boolICGetProp_Fallback::Compiler::generateStubCode(MacroAssembler&masm){MOZ_ASSERT(R0==JSReturnOperand);EmitRestoreTailCallReg(masm);// Ensure stack is fully synced for the expression decompiler.masm.pushValue(R0);// Push arguments.masm.pushValue(R0);masm.push(ICStubReg);pushStubPayload(masm,R0.scratchReg());if(!tailCallVM(DoGetPropFallbackInfo,masm))returnfalse;// Even though the fallback frame doesn't enter a stub frame, the CallScripted// frame that we are emulating does. Again, we lie.#ifdef DEBUGEmitRepushTailCallReg(masm);enterStubFrame(masm,R0.scratchReg());#elseinStubFrame_=true;#endif// What follows is bailout for inlined scripted getters.// The return address pointed to by the baseline stack points here.returnOffset_=masm.currentOffset();leaveStubFrame(masm,true);// When we get here, ICStubReg contains the ICGetProp_Fallback stub,// which we can't use to enter the TypeMonitor IC, because it's a MonitoredFallbackStub// instead of a MonitoredStub. So, we cheat.masm.loadPtr(Address(ICStubReg,ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()),ICStubReg);EmitEnterTypeMonitorIC(masm,ICTypeMonitor_Fallback::offsetOfFirstMonitorStub());returntrue;}voidICGetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler&masm,Handle<JitCode*>code){if(engine_==Engine::Baseline){void*address=code->raw()+returnOffset_;cx->compartment()->jitCompartment()->initBaselineGetPropReturnAddr(address);}}boolICGetProp_StringLength::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;masm.branchTestString(Assembler::NotEqual,R0,&failure);// Unbox string and load its length.Registerstring=masm.extractString(R0,ExtractTemp0);masm.loadStringLength(string,string);masm.tagValue(JSVAL_TYPE_INT32,string,R0);EmitReturnFromIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}boolICGetProp_Primitive::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;switch(primitiveType_){caseJSVAL_TYPE_STRING:masm.branchTestString(Assembler::NotEqual,R0,&failure);break;caseJSVAL_TYPE_SYMBOL:masm.branchTestSymbol(Assembler::NotEqual,R0,&failure);break;caseJSVAL_TYPE_DOUBLE:// Also used for int32.masm.branchTestNumber(Assembler::NotEqual,R0,&failure);break;caseJSVAL_TYPE_BOOLEAN:masm.branchTestBoolean(Assembler::NotEqual,R0,&failure);break;default:MOZ_CRASH("unexpected type");}AllocatableGeneralRegisterSetregs(availableGeneralRegs(1));RegisterholderReg=regs.takeAny();RegisterscratchReg=regs.takeAny();// Verify the shape of the prototype.masm.movePtr(ImmGCPtr(prototype_.get()),holderReg);AddressshapeAddr(ICStubReg,ICGetProp_Primitive::offsetOfProtoShape());masm.loadPtr(Address(holderReg,ShapedObject::offsetOfShape()),scratchReg);masm.branchPtr(Assembler::NotEqual,shapeAddr,scratchReg,&failure);if(!isFixedSlot_)masm.loadPtr(Address(holderReg,NativeObject::offsetOfSlots()),holderReg);masm.load32(Address(ICStubReg,ICGetProp_Primitive::offsetOfOffset()),scratchReg);masm.loadValue(BaseIndex(holderReg,scratchReg,TimesOne),R0);// Enter type monitor IC to type-check result.EmitEnterTypeMonitorIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}ICGetPropNativeStub*ICGetPropNativeCompiler::getStub(ICStubSpace*space){ReceiverGuardguard(obj_);switch(kind){caseICStub::GetName_Global:{MOZ_ASSERT(obj_!=holder_);Shape*holderShape=holder_->as<NativeObject>().lastProperty();Shape*globalShape=obj_->as<LexicalEnvironmentObject>().global().lastProperty();returnnewStub<ICGetName_Global>(space,getStubCode(),firstMonitorStub_,guard,offset_,holder_,holderShape,globalShape);}default:MOZ_CRASH("Bad stub kind");}}voidGuardReceiverObject(MacroAssembler&masm,ReceiverGuardguard,Registerobject,Registerscratch,size_treceiverGuardOffset,Label*failure){AddressgroupAddress(ICStubReg,receiverGuardOffset+HeapReceiverGuard::offsetOfGroup());AddressshapeAddress(ICStubReg,receiverGuardOffset+HeapReceiverGuard::offsetOfShape());AddressexpandoAddress(object,UnboxedPlainObject::offsetOfExpando());if(guard.group){masm.loadPtr(groupAddress,scratch);masm.branchTestObjGroup(Assembler::NotEqual,object,scratch,failure);if(guard.group->clasp()==&UnboxedPlainObject::class_&&!guard.shape){// Guard the unboxed object has no expando object.masm.branchPtr(Assembler::NotEqual,expandoAddress,ImmWord(0),failure);}}if(guard.shape){masm.loadPtr(shapeAddress,scratch);if(guard.group&&guard.group->clasp()==&UnboxedPlainObject::class_){// Guard the unboxed object has a matching expando object.masm.branchPtr(Assembler::Equal,expandoAddress,ImmWord(0),failure);Labeldone;masm.push(object);masm.loadPtr(expandoAddress,object);masm.branchTestObjShape(Assembler::Equal,object,scratch,&done);masm.pop(object);masm.jump(failure);masm.bind(&done);masm.pop(object);}else{masm.branchTestObjShape(Assembler::NotEqual,object,scratch,failure);}}}staticvoidGuardGlobalObject(MacroAssembler&masm,HandleObjectholder,RegisterglobalLexicalReg,RegisterholderReg,Registerscratch,size_tglobalShapeOffset,Label*failure){if(holder->is<GlobalObject>())return;masm.extractObject(Address(globalLexicalReg,EnvironmentObject::offsetOfEnclosingEnvironment()),holderReg);masm.loadPtr(Address(ICStubReg,globalShapeOffset),scratch);masm.branchTestObjShape(Assembler::NotEqual,holderReg,scratch,failure);}boolICGetPropNativeCompiler::generateStubCode(MacroAssembler&masm){Labelfailure;AllocatableGeneralRegisterSetregs(availableGeneralRegs(0));RegisterobjReg=InvalidReg;if(inputDefinitelyObject_){objReg=R0.scratchReg();}else{regs.take(R0);// Guard input is an object and unbox.masm.branchTestObject(Assembler::NotEqual,R0,&failure);objReg=masm.extractObject(R0,ExtractTemp0);}regs.takeUnchecked(objReg);Registerscratch=regs.takeAnyExcluding(ICTailCallReg);// Shape/group guard.GuardReceiverObject(masm,ReceiverGuard(obj_),objReg,scratch,ICGetPropNativeStub::offsetOfReceiverGuard(),&failure);MOZ_ASSERT(obj_!=holder_);MOZ_ASSERT(kind==ICStub::GetName_Global);RegisterholderReg=regs.takeAny();// If we are generating a non-lexical GETGNAME stub, we must also// guard on the shape of the GlobalObject.MOZ_ASSERT(obj_->is<LexicalEnvironmentObject>()&&obj_->as<LexicalEnvironmentObject>().isGlobal());GuardGlobalObject(masm,holder_,objReg,holderReg,scratch,ICGetName_Global::offsetOfGlobalShape(),&failure);// Shape guard holder.masm.loadPtr(Address(ICStubReg,ICGetName_Global::offsetOfHolder()),holderReg);masm.loadPtr(Address(ICStubReg,ICGetName_Global::offsetOfHolderShape()),scratch);masm.branchTestObjShape(Assembler::NotEqual,holderReg,scratch,&failure);if(!isFixedSlot_){// Don't overwrite actual holderReg if we need to load a dynamic slots object.// May need to preserve object for noSuchMethod check later.RegisternextHolder=regs.takeAny();masm.loadPtr(Address(holderReg,NativeObject::offsetOfSlots()),nextHolder);holderReg=nextHolder;}masm.load32(Address(ICStubReg,ICGetPropNativeStub::offsetOfOffset()),scratch);BaseIndexresult(holderReg,scratch,TimesOne);masm.loadValue(result,R0);// Enter type monitor IC to type-check result.EmitEnterTypeMonitorIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}boolGetProtoShapes(JSObject*obj,size_tprotoChainDepth,MutableHandle<ShapeVector>shapes){JSObject*curProto=obj->staticPrototype();for(size_ti=0;i<protoChainDepth;i++){if(!shapes.append(curProto->as<NativeObject>().lastProperty()))returnfalse;curProto=curProto->staticPrototype();}MOZ_ASSERT(!curProto,"longer prototype chain encountered than this stub permits!");returntrue;}boolICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler&masm){MOZ_ASSERT(engine_==Engine::Baseline);Labelfailure;LabelfailureLeaveStubFrame;AllocatableGeneralRegisterSetregs(availableGeneralRegs(1));Registerscratch=regs.takeAnyExcluding(ICTailCallReg);// Guard input is an object.masm.branchTestObject(Assembler::NotEqual,R0,&failure);// Unbox and shape guard.RegisterobjReg=masm.extractObject(R0,ExtractTemp0);GuardReceiverObject(masm,ReceiverGuard(receiver_),objReg,scratch,ICGetProp_CallScripted::offsetOfReceiverGuard(),&failure);if(receiver_!=holder_){RegisterholderReg=regs.takeAny();masm.loadPtr(Address(ICStubReg,ICGetProp_CallScripted::offsetOfHolder()),holderReg);masm.loadPtr(Address(ICStubReg,ICGetProp_CallScripted::offsetOfHolderShape()),scratch);masm.branchTestObjShape(Assembler::NotEqual,holderReg,scratch,&failure);regs.add(holderReg);}// Push a stub frame so that we can perform a non-tail call.enterStubFrame(masm,scratch);// Load callee function and code. To ensure that |code| doesn't end up being// ArgumentsRectifierReg, if it's available we assign it to |callee| instead.Registercallee;if(regs.has(ArgumentsRectifierReg)){callee=ArgumentsRectifierReg;regs.take(callee);}else{callee=regs.takeAny();}Registercode=regs.takeAny();masm.loadPtr(Address(ICStubReg,ICGetProp_CallScripted::offsetOfGetter()),callee);masm.branchIfFunctionHasNoScript(callee,&failureLeaveStubFrame);masm.loadPtr(Address(callee,JSFunction::offsetOfNativeOrScript()),code);masm.loadBaselineOrIonRaw(code,code,&failureLeaveStubFrame);// Align the stack such that the JitFrameLayout is aligned on// JitStackAlignment.masm.alignJitStackBasedOnNArgs(0);// Getter is called with 0 arguments, just |obj| as thisv.// Note that we use Push, not push, so that callJit will align the stack// properly on ARM.masm.Push(R0);EmitBaselineCreateStubFrameDescriptor(masm,scratch,JitFrameLayout::Size());masm.Push(Imm32(0));// ActualArgc is 0masm.Push(callee);masm.Push(scratch);// Handle arguments underflow.LabelnoUnderflow;masm.load16ZeroExtend(Address(callee,JSFunction::offsetOfNargs()),scratch);masm.branch32(Assembler::Equal,scratch,Imm32(0),&noUnderflow);{// Call the arguments rectifier.MOZ_ASSERT(ArgumentsRectifierReg!=code);JitCode*argumentsRectifier=cx->runtime()->jitRuntime()->getArgumentsRectifier();masm.movePtr(ImmGCPtr(argumentsRectifier),code);masm.loadPtr(Address(code,JitCode::offsetOfCode()),code);masm.movePtr(ImmWord(0),ArgumentsRectifierReg);}masm.bind(&noUnderflow);masm.callJit(code);leaveStubFrame(masm,true);// Enter type monitor IC to type-check result.EmitEnterTypeMonitorIC(masm);// Leave stub frame and go to next stub.masm.bind(&failureLeaveStubFrame);inStubFrame_=true;leaveStubFrame(masm,false);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}//// VM function to help call native getters.//boolDoCallNativeGetter(JSContext*cx,HandleFunctioncallee,HandleObjectobj,MutableHandleValueresult){MOZ_ASSERT(callee->isNative());JSNativenatfun=callee->native();JS::AutoValueArray<2>vp(cx);vp[0].setObject(*callee.get());vp[1].setObject(*obj.get());if(!natfun(cx,0,vp.begin()))returnfalse;result.set(vp[0]);returntrue;}typedefbool(*DoCallNativeGetterFn)(JSContext*,HandleFunction,HandleObject,MutableHandleValue);staticconstVMFunctionDoCallNativeGetterInfo=FunctionInfo<DoCallNativeGetterFn>(DoCallNativeGetter,"DoCallNativeGetter");boolICGetPropCallNativeCompiler::generateStubCode(MacroAssembler&masm){Labelfailure;AllocatableGeneralRegisterSetregs(availableGeneralRegs(1));RegisterobjReg=InvalidReg;MOZ_ASSERT(!(inputDefinitelyObject_&&outerClass_));if(inputDefinitelyObject_){objReg=R0.scratchReg();}else{// Guard input is an object and unbox.masm.branchTestObject(Assembler::NotEqual,R0,&failure);objReg=masm.extractObject(R0,ExtractTemp0);if(outerClass_){Registertmp=regs.takeAny();masm.branchTestObjClass(Assembler::NotEqual,objReg,tmp,outerClass_,&failure);masm.movePtr(ImmGCPtr(cx->global()),objReg);regs.add(tmp);}}Registerscratch=regs.takeAnyExcluding(ICTailCallReg);// Shape guard.GuardReceiverObject(masm,ReceiverGuard(receiver_),objReg,scratch,ICGetPropCallGetter::offsetOfReceiverGuard(),&failure);if(receiver_!=holder_){RegisterholderReg=regs.takeAny();// If we are generating a non-lexical GETGNAME stub, we must also// guard on the shape of the GlobalObject.if(kind==ICStub::GetProp_CallNativeGlobal){MOZ_ASSERT(receiver_->is<LexicalEnvironmentObject>()&&receiver_->as<LexicalEnvironmentObject>().isGlobal());GuardGlobalObject(masm,holder_,objReg,holderReg,scratch,ICGetProp_CallNativeGlobal::offsetOfGlobalShape(),&failure);}masm.loadPtr(Address(ICStubReg,ICGetPropCallGetter::offsetOfHolder()),holderReg);masm.loadPtr(Address(ICStubReg,ICGetPropCallGetter::offsetOfHolderShape()),scratch);masm.branchTestObjShape(Assembler::NotEqual,holderReg,scratch,&failure);regs.add(holderReg);}// Box and push obj onto baseline frame stack for decompilerif(engine_==Engine::Baseline){if(inputDefinitelyObject_)masm.tagValue(JSVAL_TYPE_OBJECT,objReg,R0);EmitStowICValues(masm,1);if(inputDefinitelyObject_)objReg=masm.extractObject(R0,ExtractTemp0);}// Push a stub frame so that we can perform a non-tail call.enterStubFrame(masm,scratch);// Load callee function.Registercallee=regs.takeAny();masm.loadPtr(Address(ICStubReg,ICGetPropCallGetter::offsetOfGetter()),callee);// If we're calling a getter on the global, inline the logic for the// 'this' hook on the global lexical scope and manually push the global.if(kind==ICStub::GetProp_CallNativeGlobal)masm.extractObject(Address(objReg,EnvironmentObject::offsetOfEnclosingEnvironment()),objReg);// Push args for vm call.masm.Push(objReg);masm.Push(callee);regs.add(R0);if(!callVM(DoCallNativeGetterInfo,masm))returnfalse;leaveStubFrame(masm);if(engine_==Engine::Baseline)EmitUnstowICValues(masm,1,/* discard = */true);// Enter type monitor IC to type-check result.EmitEnterTypeMonitorIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}ICStub*ICGetPropCallNativeCompiler::getStub(ICStubSpace*space){ReceiverGuardguard(receiver_);Shape*holderShape=holder_->as<NativeObject>().lastProperty();switch(kind){caseICStub::GetProp_CallNative:returnnewStub<ICGetProp_CallNative>(space,getStubCode(),firstMonitorStub_,guard,holder_,holderShape,getter_,pcOffset_);caseICStub::GetProp_CallNativeGlobal:{Shape*globalShape=receiver_->as<LexicalEnvironmentObject>().global().lastProperty();returnnewStub<ICGetProp_CallNativeGlobal>(space,getStubCode(),firstMonitorStub_,guard,holder_,holderShape,globalShape,getter_,pcOffset_);}default:MOZ_CRASH("Bad stub kind");}}// Callers are expected to have already guarded on the shape of the// object, which guarantees the object is a DOM proxy.voidCheckDOMProxyExpandoDoesNotShadow(JSContext*cx,MacroAssembler&masm,Registerobject,constAddress&checkExpandoShapeAddr,Address*expandoAndGenerationAddr,Address*generationAddr,Registerscratch,AllocatableGeneralRegisterSet&domProxyRegSet,Label*checkFailed){// Guard that the object does not have expando properties, or has an expando// which is known to not have the desired property.// For the remaining code, we need to reserve some registers to load a value.// This is ugly, but unavoidable.ValueOperandtempVal=domProxyRegSet.takeAnyValue();masm.pushValue(tempVal);LabelfailDOMProxyCheck;LabeldomProxyOk;masm.loadPtr(Address(object,ProxyObject::offsetOfValues()),scratch);AddressexpandoAddr(scratch,ProxyObject::offsetOfExtraSlotInValues(GetDOMProxyExpandoSlot()));if(expandoAndGenerationAddr){MOZ_ASSERT(generationAddr);masm.loadPtr(*expandoAndGenerationAddr,tempVal.scratchReg());masm.branchPrivatePtr(Assembler::NotEqual,expandoAddr,tempVal.scratchReg(),&failDOMProxyCheck);masm.branch64(Assembler::NotEqual,Address(tempVal.scratchReg(),ExpandoAndGeneration::offsetOfGeneration()),*generationAddr,scratch,&failDOMProxyCheck);masm.loadValue(Address(tempVal.scratchReg(),0),tempVal);}else{masm.loadValue(expandoAddr,tempVal);}// If the incoming object does not have an expando object then we're sure we're not// shadowing.masm.branchTestUndefined(Assembler::Equal,tempVal,&domProxyOk);// The reference object used to generate this check may not have had an// expando object at all, in which case the presence of a non-undefined// expando value in the incoming object is automatically a failure.masm.loadPtr(checkExpandoShapeAddr,scratch);masm.branchPtr(Assembler::Equal,scratch,ImmPtr(nullptr),&failDOMProxyCheck);// Otherwise, ensure that the incoming object has an object for its expando value and that// the shape matches.masm.branchTestObject(Assembler::NotEqual,tempVal,&failDOMProxyCheck);RegisterobjReg=masm.extractObject(tempVal,tempVal.scratchReg());masm.branchTestObjShape(Assembler::Equal,objReg,scratch,&domProxyOk);// Failure case: restore the tempVal registers and jump to failures.masm.bind(&failDOMProxyCheck);masm.popValue(tempVal);masm.jump(checkFailed);// Success case: restore the tempval and proceed.masm.bind(&domProxyOk);masm.popValue(tempVal);}boolICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler&masm,Address*expandoAndGenerationAddr,Address*generationAddr){Labelfailure;AllocatableGeneralRegisterSetregs(availableGeneralRegs(1));Registerscratch=regs.takeAnyExcluding(ICTailCallReg);// Guard input is an object.masm.branchTestObject(Assembler::NotEqual,R0,&failure);// Unbox.RegisterobjReg=masm.extractObject(R0,ExtractTemp0);// Shape guard.staticconstsize_treceiverShapeOffset=ICGetProp_CallDOMProxyNative::offsetOfReceiverGuard()+HeapReceiverGuard::offsetOfShape();masm.loadPtr(Address(ICStubReg,receiverShapeOffset),scratch);masm.branchTestObjShape(Assembler::NotEqual,objReg,scratch,&failure);// Guard that our expando object hasn't started shadowing this property.{AllocatableGeneralRegisterSetdomProxyRegSet(GeneralRegisterSet::All());domProxyRegSet.take(ICStubReg);domProxyRegSet.take(objReg);domProxyRegSet.take(scratch);AddressexpandoShapeAddr(ICStubReg,ICGetProp_CallDOMProxyNative::offsetOfExpandoShape());CheckDOMProxyExpandoDoesNotShadow(cx,masm,objReg,expandoShapeAddr,expandoAndGenerationAddr,generationAddr,scratch,domProxyRegSet,&failure);}RegisterholderReg=regs.takeAny();masm.loadPtr(Address(ICStubReg,ICGetProp_CallDOMProxyNative::offsetOfHolder()),holderReg);masm.loadPtr(Address(ICStubReg,ICGetProp_CallDOMProxyNative::offsetOfHolderShape()),scratch);masm.branchTestObjShape(Assembler::NotEqual,holderReg,scratch,&failure);regs.add(holderReg);// Push a stub frame so that we can perform a non-tail call.enterStubFrame(masm,scratch);// Load callee function.Registercallee=regs.takeAny();masm.loadPtr(Address(ICStubReg,ICGetProp_CallDOMProxyNative::offsetOfGetter()),callee);// Push args for vm call.masm.Push(objReg);masm.Push(callee);// Don't have to preserve R0 anymore.regs.add(R0);if(!callVM(DoCallNativeGetterInfo,masm))returnfalse;leaveStubFrame(masm);// Enter type monitor IC to type-check result.EmitEnterTypeMonitorIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}boolICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler&masm){if(kind==ICStub::GetProp_CallDOMProxyNative)returngenerateStubCode(masm,nullptr,nullptr);AddressinternalStructAddress(ICStubReg,ICGetProp_CallDOMProxyWithGenerationNative::offsetOfInternalStruct());AddressgenerationAddress(ICStubReg,ICGetProp_CallDOMProxyWithGenerationNative::offsetOfGeneration());returngenerateStubCode(masm,&internalStructAddress,&generationAddress);}ICStub*ICGetPropCallDOMProxyNativeCompiler::getStub(ICStubSpace*space){RootedShapeshape(cx,proxy_->maybeShape());RootedShapeholderShape(cx,holder_->as<NativeObject>().lastProperty());ValueexpandoSlot=GetProxyExtra(proxy_,GetDOMProxyExpandoSlot());RootedShapeexpandoShape(cx,nullptr);ExpandoAndGeneration*expandoAndGeneration;uint64_tgeneration;ValueexpandoVal;if(kind==ICStub::GetProp_CallDOMProxyNative){expandoVal=expandoSlot;expandoAndGeneration=nullptr;// initialize to silence GCC warninggeneration=0;// initialize to silence GCC warning}else{MOZ_ASSERT(kind==ICStub::GetProp_CallDOMProxyWithGenerationNative);MOZ_ASSERT(!expandoSlot.isObject()&&!expandoSlot.isUndefined());expandoAndGeneration=(ExpandoAndGeneration*)expandoSlot.toPrivate();expandoVal=expandoAndGeneration->expando;generation=expandoAndGeneration->generation;}if(expandoVal.isObject())expandoShape=expandoVal.toObject().as<NativeObject>().lastProperty();if(kind==ICStub::GetProp_CallDOMProxyNative){returnnewStub<ICGetProp_CallDOMProxyNative>(space,getStubCode(),firstMonitorStub_,shape,expandoShape,holder_,holderShape,getter_,pcOffset_);}returnnewStub<ICGetProp_CallDOMProxyWithGenerationNative>(space,getStubCode(),firstMonitorStub_,shape,expandoAndGeneration,generation,expandoShape,holder_,holderShape,getter_,pcOffset_);}ICStub*ICGetProp_DOMProxyShadowed::Compiler::getStub(ICStubSpace*space){RootedShapeshape(cx,proxy_->maybeShape());returnNew<ICGetProp_DOMProxyShadowed>(cx,space,getStubCode(),firstMonitorStub_,shape,proxy_->handler(),name_,pcOffset_);}staticboolProxyGet(JSContext*cx,HandleObjectproxy,HandlePropertyNamename,MutableHandleValuevp){RootedValuereceiver(cx,ObjectValue(*proxy));RootedIdid(cx,NameToId(name));returnProxy::get(cx,proxy,receiver,id,vp);}typedefbool(*ProxyGetFn)(JSContext*cx,HandleObjectproxy,HandlePropertyNamename,MutableHandleValuevp);staticconstVMFunctionProxyGetInfo=FunctionInfo<ProxyGetFn>(ProxyGet,"ProxyGet");boolICGetProp_DOMProxyShadowed::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;AllocatableGeneralRegisterSetregs(availableGeneralRegs(1));// Need to reserve a scratch register, but the scratch register should not be// ICTailCallReg, because it's used for |enterStubFrame| which needs a// non-ICTailCallReg scratch reg.Registerscratch=regs.takeAnyExcluding(ICTailCallReg);// Guard input is an object.masm.branchTestObject(Assembler::NotEqual,R0,&failure);// Unbox.RegisterobjReg=masm.extractObject(R0,ExtractTemp0);// Shape guard.masm.loadPtr(Address(ICStubReg,ICGetProp_DOMProxyShadowed::offsetOfShape()),scratch);masm.branchTestObjShape(Assembler::NotEqual,objReg,scratch,&failure);// No need to do any more guards; it's safe to call ProxyGet even// if we've since stopped shadowing.// Call ProxyGet(JSContext* cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp);// Push a stub frame so that we can perform a non-tail call.enterStubFrame(masm,scratch);// Push property name and proxy object.masm.loadPtr(Address(ICStubReg,ICGetProp_DOMProxyShadowed::offsetOfName()),scratch);masm.Push(scratch);masm.Push(objReg);// Don't have to preserve R0 anymore.regs.add(R0);if(!callVM(ProxyGetInfo,masm))returnfalse;leaveStubFrame(masm);// Enter type monitor IC to type-check result.EmitEnterTypeMonitorIC(masm);// Failure case - jump to next stubmasm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}boolICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler&masm){MOZ_ASSERT(which_==ICGetProp_ArgumentsLength::Magic);Labelfailure;// Ensure that this is lazy arguments.masm.branchTestMagicValue(Assembler::NotEqual,R0,JS_OPTIMIZED_ARGUMENTS,&failure);// Ensure that frame has not loaded different arguments object since.masm.branchTest32(Assembler::NonZero,Address(BaselineFrameReg,BaselineFrame::reverseOffsetOfFlags()),Imm32(BaselineFrame::HAS_ARGS_OBJ),&failure);AddressactualArgs(BaselineFrameReg,BaselineFrame::offsetOfNumActualArgs());masm.loadPtr(actualArgs,R0.scratchReg());masm.tagValue(JSVAL_TYPE_INT32,R0.scratchReg(),R0);EmitReturnFromIC(masm);masm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}ICGetProp_ArgumentsCallee::ICGetProp_ArgumentsCallee(JitCode*stubCode,ICStub*firstMonitorStub):ICMonitoredStub(GetProp_ArgumentsCallee,stubCode,firstMonitorStub){}boolICGetProp_ArgumentsCallee::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;// Ensure that this is lazy arguments.masm.branchTestMagicValue(Assembler::NotEqual,R0,JS_OPTIMIZED_ARGUMENTS,&failure);// Ensure that frame has not loaded different arguments object since.masm.branchTest32(Assembler::NonZero,Address(BaselineFrameReg,BaselineFrame::reverseOffsetOfFlags()),Imm32(BaselineFrame::HAS_ARGS_OBJ),&failure);Addresscallee(BaselineFrameReg,BaselineFrame::offsetOfCalleeToken());masm.loadFunctionFromCalleeToken(callee,R0.scratchReg());masm.tagValue(JSVAL_TYPE_OBJECT,R0.scratchReg(),R0);EmitEnterTypeMonitorIC(masm);masm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}/* static */ICGetProp_Generic*ICGetProp_Generic::Clone(JSContext*cx,ICStubSpace*space,ICStub*firstMonitorStub,ICGetProp_Generic&other){returnNew<ICGetProp_Generic>(cx,space,other.jitCode(),firstMonitorStub);}staticboolDoGetPropGeneric(JSContext*cx,void*payload,ICGetProp_Generic*stub,MutableHandleValueval,MutableHandleValueres){ICFallbackStub*fallback=stub->getChainFallback();SharedStubInfoinfo(cx,payload,fallback->icEntry());HandleScriptscript=info.innerScript();jsbytecode*pc=info.pc();JSOpop=JSOp(*pc);RootedPropertyNamename(cx,script->getName(pc));returnComputeGetPropResult(cx,info.maybeFrame(),op,name,val,res);}typedefbool(*DoGetPropGenericFn)(JSContext*,void*,ICGetProp_Generic*,MutableHandleValue,MutableHandleValue);staticconstVMFunctionDoGetPropGenericInfo=FunctionInfo<DoGetPropGenericFn>(DoGetPropGeneric,"DoGetPropGeneric");boolICGetProp_Generic::Compiler::generateStubCode(MacroAssembler&masm){AllocatableGeneralRegisterSetregs(availableGeneralRegs(1));Registerscratch=regs.takeAnyExcluding(ICTailCallReg);// Sync for the decompiler.if(engine_==Engine::Baseline)EmitStowICValues(masm,1);enterStubFrame(masm,scratch);// Push arguments.masm.Push(R0);masm.Push(ICStubReg);PushStubPayload(masm,R0.scratchReg());if(!callVM(DoGetPropGenericInfo,masm))returnfalse;leaveStubFrame(masm);if(engine_==Engine::Baseline)EmitUnstowICValues(masm,1,/* discard = */true);EmitEnterTypeMonitorIC(masm);returntrue;}voidCheckForTypedObjectWithDetachedStorage(JSContext*cx,MacroAssembler&masm,Label*failure){// All stubs manipulating typed objects must check the compartment-wide// flag indicating whether their underlying storage might be detached, to// bail out if needed.int32_t*address=&cx->compartment()->detachedTypedObjects;masm.branch32(Assembler::NotEqual,AbsoluteAddress(address),Imm32(0),failure);}voidLoadTypedThingData(MacroAssembler&masm,TypedThingLayoutlayout,Registerobj,Registerresult){switch(layout){caseLayout_TypedArray:masm.loadPtr(Address(obj,TypedArrayObject::dataOffset()),result);break;caseLayout_OutlineTypedObject:masm.loadPtr(Address(obj,OutlineTypedObject::offsetOfData()),result);break;caseLayout_InlineTypedObject:masm.computeEffectiveAddress(Address(obj,InlineTypedObject::offsetOfDataStart()),result);break;default:MOZ_CRASH();}}voidBaselineScript::noteAccessedGetter(uint32_tpcOffset){ICEntry&entry=icEntryFromPCOffset(pcOffset);ICFallbackStub*stub=entry.fallbackStub();if(stub->isGetProp_Fallback())stub->toGetProp_Fallback()->noteAccessedGetter();}ICGetProp_Primitive::ICGetProp_Primitive(JitCode*stubCode,ICStub*firstMonitorStub,JSValueTypeprimitiveType,Shape*protoShape,uint32_toffset):ICMonitoredStub(GetProp_Primitive,stubCode,firstMonitorStub),protoShape_(protoShape),offset_(offset){extra_=uint16_t(primitiveType);MOZ_ASSERT(JSValueType(extra_)==primitiveType);}ICGetPropNativeStub::ICGetPropNativeStub(ICStub::Kindkind,JitCode*stubCode,ICStub*firstMonitorStub,ReceiverGuardguard,uint32_toffset):ICMonitoredStub(kind,stubCode,firstMonitorStub),receiverGuard_(guard),offset_(offset){}ICGetPropNativePrototypeStub::ICGetPropNativePrototypeStub(ICStub::Kindkind,JitCode*stubCode,ICStub*firstMonitorStub,ReceiverGuardguard,uint32_toffset,JSObject*holder,Shape*holderShape):ICGetPropNativeStub(kind,stubCode,firstMonitorStub,guard,offset),holder_(holder),holderShape_(holderShape){}ICGetPropCallGetter::ICGetPropCallGetter(Kindkind,JitCode*stubCode,ICStub*firstMonitorStub,ReceiverGuardreceiverGuard,JSObject*holder,Shape*holderShape,JSFunction*getter,uint32_tpcOffset):ICMonitoredStub(kind,stubCode,firstMonitorStub),receiverGuard_(receiverGuard),holder_(holder),holderShape_(holderShape),getter_(getter),pcOffset_(pcOffset){MOZ_ASSERT(kind==ICStub::GetProp_CallScripted||kind==ICStub::GetProp_CallNative||kind==ICStub::GetProp_CallNativeGlobal||kind==ICStub::GetProp_CallDOMProxyNative||kind==ICStub::GetProp_CallDOMProxyWithGenerationNative);}/* static */ICGetProp_CallScripted*ICGetProp_CallScripted::Clone(JSContext*cx,ICStubSpace*space,ICStub*firstMonitorStub,ICGetProp_CallScripted&other){returnNew<ICGetProp_CallScripted>(cx,space,other.jitCode(),firstMonitorStub,other.receiverGuard(),other.holder_,other.holderShape_,other.getter_,other.pcOffset_);}/* static */ICGetProp_CallNative*ICGetProp_CallNative::Clone(JSContext*cx,ICStubSpace*space,ICStub*firstMonitorStub,ICGetProp_CallNative&other){returnNew<ICGetProp_CallNative>(cx,space,other.jitCode(),firstMonitorStub,other.receiverGuard(),other.holder_,other.holderShape_,other.getter_,other.pcOffset_);}/* static */ICGetProp_CallNativeGlobal*ICGetProp_CallNativeGlobal::Clone(JSContext*cx,ICStubSpace*space,ICStub*firstMonitorStub,ICGetProp_CallNativeGlobal&other){returnNew<ICGetProp_CallNativeGlobal>(cx,space,other.jitCode(),firstMonitorStub,other.receiverGuard(),other.holder_,other.holderShape_,other.globalShape_,other.getter_,other.pcOffset_);}ICGetPropCallDOMProxyNativeStub::ICGetPropCallDOMProxyNativeStub(Kindkind,JitCode*stubCode,ICStub*firstMonitorStub,Shape*shape,Shape*expandoShape,JSObject*holder,Shape*holderShape,JSFunction*getter,uint32_tpcOffset):ICGetPropCallGetter(kind,stubCode,firstMonitorStub,ReceiverGuard(nullptr,shape),holder,holderShape,getter,pcOffset),expandoShape_(expandoShape){}ICGetPropCallDOMProxyNativeCompiler::ICGetPropCallDOMProxyNativeCompiler(JSContext*cx,ICStub::Kindkind,ICStubCompiler::Engineengine,ICStub*firstMonitorStub,Handle<ProxyObject*>proxy,HandleObjectholder,HandleFunctiongetter,uint32_tpcOffset):ICStubCompiler(cx,kind,engine),firstMonitorStub_(firstMonitorStub),proxy_(cx,proxy),holder_(cx,holder),getter_(cx,getter),pcOffset_(pcOffset){MOZ_ASSERT(kind==ICStub::GetProp_CallDOMProxyNative||kind==ICStub::GetProp_CallDOMProxyWithGenerationNative);MOZ_ASSERT(proxy_->handler()->family()==GetDOMProxyHandlerFamily());}/* static */ICGetProp_CallDOMProxyNative*ICGetProp_CallDOMProxyNative::Clone(JSContext*cx,ICStubSpace*space,ICStub*firstMonitorStub,ICGetProp_CallDOMProxyNative&other){returnNew<ICGetProp_CallDOMProxyNative>(cx,space,other.jitCode(),firstMonitorStub,other.receiverGuard_.shape(),other.expandoShape_,other.holder_,other.holderShape_,other.getter_,other.pcOffset_);}/* static */ICGetProp_CallDOMProxyWithGenerationNative*ICGetProp_CallDOMProxyWithGenerationNative::Clone(JSContext*cx,ICStubSpace*space,ICStub*firstMonitorStub,ICGetProp_CallDOMProxyWithGenerationNative&other){returnNew<ICGetProp_CallDOMProxyWithGenerationNative>(cx,space,other.jitCode(),firstMonitorStub,other.receiverGuard_.shape(),other.expandoAndGeneration_,other.generation_,other.expandoShape_,other.holder_,other.holderShape_,other.getter_,other.pcOffset_);}ICGetProp_DOMProxyShadowed::ICGetProp_DOMProxyShadowed(JitCode*stubCode,ICStub*firstMonitorStub,Shape*shape,constBaseProxyHandler*proxyHandler,PropertyName*name,uint32_tpcOffset):ICMonitoredStub(ICStub::GetProp_DOMProxyShadowed,stubCode,firstMonitorStub),shape_(shape),proxyHandler_(proxyHandler),name_(name),pcOffset_(pcOffset){}/* static */ICGetProp_DOMProxyShadowed*ICGetProp_DOMProxyShadowed::Clone(JSContext*cx,ICStubSpace*space,ICStub*firstMonitorStub,ICGetProp_DOMProxyShadowed&other){returnNew<ICGetProp_DOMProxyShadowed>(cx,space,other.jitCode(),firstMonitorStub,other.shape_,other.proxyHandler_,other.name_,other.pcOffset_);}//// TypeMonitor_Fallback//boolICTypeMonitor_Fallback::addMonitorStubForValue(JSContext*cx,SharedStubInfo*info,HandleValueval){boolwasDetachedMonitorChain=lastMonitorStubPtrAddr_==nullptr;MOZ_ASSERT_IF(wasDetachedMonitorChain,numOptimizedMonitorStubs_==0);if(numOptimizedMonitorStubs_>=MAX_OPTIMIZED_STUBS){// TODO: if the TypeSet becomes unknown or has the AnyObject type,// replace stubs with a single stub to handle these.returntrue;}if(val.isPrimitive()){if(val.isMagic(JS_UNINITIALIZED_LEXICAL))returntrue;MOZ_ASSERT(!val.isMagic());JSValueTypetype=val.isDouble()?JSVAL_TYPE_DOUBLE:val.extractNonDoubleType();// Check for existing TypeMonitor stub.ICTypeMonitor_PrimitiveSet*existingStub=nullptr;for(ICStubConstIteratoriter(firstMonitorStub());!iter.atEnd();iter++){if(iter->isTypeMonitor_PrimitiveSet()){existingStub=iter->toTypeMonitor_PrimitiveSet();if(existingStub->containsType(type))returntrue;}}ICTypeMonitor_PrimitiveSet::Compilercompiler(cx,info->engine(),existingStub,type);ICStub*stub=existingStub?compiler.updateStub():compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));if(!stub){ReportOutOfMemory(cx);returnfalse;}JitSpew(JitSpew_BaselineIC," %s TypeMonitor stub %p for primitive type %d",existingStub?"Modified existing":"Created new",stub,type);if(!existingStub){MOZ_ASSERT(!hasStub(TypeMonitor_PrimitiveSet));addOptimizedMonitorStub(stub);}}elseif(val.toObject().isSingleton()){RootedObjectobj(cx,&val.toObject());// Check for existing TypeMonitor stub.for(ICStubConstIteratoriter(firstMonitorStub());!iter.atEnd();iter++){if(iter->isTypeMonitor_SingleObject()&&iter->toTypeMonitor_SingleObject()->object()==obj){returntrue;}}ICTypeMonitor_SingleObject::Compilercompiler(cx,obj);ICStub*stub=compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));if(!stub){ReportOutOfMemory(cx);returnfalse;}JitSpew(JitSpew_BaselineIC," Added TypeMonitor stub %p for singleton %p",stub,obj.get());addOptimizedMonitorStub(stub);}else{RootedObjectGroupgroup(cx,val.toObject().group());// Check for existing TypeMonitor stub.for(ICStubConstIteratoriter(firstMonitorStub());!iter.atEnd();iter++){if(iter->isTypeMonitor_ObjectGroup()&&iter->toTypeMonitor_ObjectGroup()->group()==group){returntrue;}}ICTypeMonitor_ObjectGroup::Compilercompiler(cx,group);ICStub*stub=compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));if(!stub){ReportOutOfMemory(cx);returnfalse;}JitSpew(JitSpew_BaselineIC," Added TypeMonitor stub %p for ObjectGroup %p",stub,group.get());addOptimizedMonitorStub(stub);}boolfirstMonitorStubAdded=wasDetachedMonitorChain&&(numOptimizedMonitorStubs_>0);if(firstMonitorStubAdded){// Was an empty monitor chain before, but a new stub was added. This is the// only time that any main stubs' firstMonitorStub fields need to be updated to// refer to the newly added monitor stub.ICStub*firstStub=mainFallbackStub_->icEntry()->firstStub();for(ICStubConstIteratoriter(firstStub);!iter.atEnd();iter++){// Non-monitored stubs are used if the result has always the same type,// e.g. a StringLength stub will always return int32.if(!iter->isMonitored())continue;// Since we just added the first optimized monitoring stub, any// existing main stub's |firstMonitorStub| MUST be pointing to the fallback// monitor stub (i.e. this stub).MOZ_ASSERT(iter->toMonitoredStub()->firstMonitorStub()==this);iter->toMonitoredStub()->updateFirstMonitorStub(firstMonitorStub_);}}returntrue;}staticboolDoTypeMonitorFallback(JSContext*cx,void*payload,ICTypeMonitor_Fallback*stub,HandleValuevalue,MutableHandleValueres){SharedStubInfoinfo(cx,payload,stub->icEntry());HandleScriptscript=info.innerScript();jsbytecode*pc=stub->icEntry()->pc(script);TypeFallbackICSpew(cx,stub,"TypeMonitor");if(value.isMagic()){// It's possible that we arrived here from bailing out of Ion, and that// Ion proved that the value is dead and optimized out. In such cases,// do nothing. However, it's also possible that we have an uninitialized// this, in which case we should not look for other magic values.if(value.whyMagic()==JS_OPTIMIZED_OUT){MOZ_ASSERT(!stub->monitorsThis());res.set(value);returntrue;}// In derived class constructors (including nested arrows/eval), the// |this| argument or GETALIASEDVAR can return the magic TDZ value.MOZ_ASSERT(value.isMagic(JS_UNINITIALIZED_LEXICAL));MOZ_ASSERT(info.frame()->isFunctionFrame()||info.frame()->isEvalFrame());MOZ_ASSERT(stub->monitorsThis()||*GetNextPc(pc)==JSOP_CHECKTHIS||*GetNextPc(pc)==JSOP_CHECKRETURN);}uint32_targument;if(stub->monitorsThis()){MOZ_ASSERT(pc==script->code());if(value.isMagic(JS_UNINITIALIZED_LEXICAL))TypeScript::SetThis(cx,script,TypeSet::UnknownType());elseTypeScript::SetThis(cx,script,value);}elseif(stub->monitorsArgument(&argument)){MOZ_ASSERT(pc==script->code());MOZ_ASSERT(!value.isMagic(JS_UNINITIALIZED_LEXICAL));TypeScript::SetArgument(cx,script,argument,value);}else{if(value.isMagic(JS_UNINITIALIZED_LEXICAL))TypeScript::Monitor(cx,script,pc,TypeSet::UnknownType());elseTypeScript::Monitor(cx,script,pc,value);}if(!stub->invalid()&&!stub->addMonitorStubForValue(cx,&info,value))returnfalse;// Copy input value to res.res.set(value);returntrue;}typedefbool(*DoTypeMonitorFallbackFn)(JSContext*,void*,ICTypeMonitor_Fallback*,HandleValue,MutableHandleValue);staticconstVMFunctionDoTypeMonitorFallbackInfo=FunctionInfo<DoTypeMonitorFallbackFn>(DoTypeMonitorFallback,"DoTypeMonitorFallback",TailCall);boolICTypeMonitor_Fallback::Compiler::generateStubCode(MacroAssembler&masm){MOZ_ASSERT(R0==JSReturnOperand);// Restore the tail call register.EmitRestoreTailCallReg(masm);masm.pushValue(R0);masm.push(ICStubReg);pushStubPayload(masm,R0.scratchReg());returntailCallVM(DoTypeMonitorFallbackInfo,masm);}boolICTypeMonitor_PrimitiveSet::Compiler::generateStubCode(MacroAssembler&masm){Labelsuccess;if((flags_&TypeToFlag(JSVAL_TYPE_INT32))&&!(flags_&TypeToFlag(JSVAL_TYPE_DOUBLE)))masm.branchTestInt32(Assembler::Equal,R0,&success);if(flags_&TypeToFlag(JSVAL_TYPE_DOUBLE))masm.branchTestNumber(Assembler::Equal,R0,&success);if(flags_&TypeToFlag(JSVAL_TYPE_UNDEFINED))masm.branchTestUndefined(Assembler::Equal,R0,&success);if(flags_&TypeToFlag(JSVAL_TYPE_BOOLEAN))masm.branchTestBoolean(Assembler::Equal,R0,&success);if(flags_&TypeToFlag(JSVAL_TYPE_STRING))masm.branchTestString(Assembler::Equal,R0,&success);if(flags_&TypeToFlag(JSVAL_TYPE_SYMBOL))masm.branchTestSymbol(Assembler::Equal,R0,&success);// Currently, we will never generate primitive stub checks for object. However,// when we do get to the point where we want to collapse our monitor chains of// objects and singletons down (when they get too long) to a generic "any object"// in coordination with the typeset doing the same thing, this will need to// be re-enabled./* if (flags_ & TypeToFlag(JSVAL_TYPE_OBJECT)) masm.branchTestObject(Assembler::Equal, R0, &success); */MOZ_ASSERT(!(flags_&TypeToFlag(JSVAL_TYPE_OBJECT)));if(flags_&TypeToFlag(JSVAL_TYPE_NULL))masm.branchTestNull(Assembler::Equal,R0,&success);EmitStubGuardFailure(masm);masm.bind(&success);EmitReturnFromIC(masm);returntrue;}staticvoidMaybeWorkAroundAmdBug(MacroAssembler&masm){// Attempt to work around an AMD bug (see bug 1034706 and bug 1281759), by// inserting 32-bytes of NOPs.#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)if(CPUInfo::NeedAmdBugWorkaround()){masm.nop(9);masm.nop(9);masm.nop(9);masm.nop(5);}#endif}boolICTypeMonitor_SingleObject::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;masm.branchTestObject(Assembler::NotEqual,R0,&failure);MaybeWorkAroundAmdBug(masm);// Guard on the object's identity.Registerobj=masm.extractObject(R0,ExtractTemp0);AddressexpectedObject(ICStubReg,ICTypeMonitor_SingleObject::offsetOfObject());masm.branchPtr(Assembler::NotEqual,expectedObject,obj,&failure);MaybeWorkAroundAmdBug(masm);EmitReturnFromIC(masm);MaybeWorkAroundAmdBug(masm);masm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}boolICTypeMonitor_ObjectGroup::Compiler::generateStubCode(MacroAssembler&masm){Labelfailure;masm.branchTestObject(Assembler::NotEqual,R0,&failure);MaybeWorkAroundAmdBug(masm);// Guard on the object's ObjectGroup.Registerobj=masm.extractObject(R0,ExtractTemp0);masm.loadPtr(Address(obj,JSObject::offsetOfGroup()),R1.scratchReg());AddressexpectedGroup(ICStubReg,ICTypeMonitor_ObjectGroup::offsetOfGroup());masm.branchPtr(Assembler::NotEqual,expectedGroup,R1.scratchReg(),&failure);MaybeWorkAroundAmdBug(masm);EmitReturnFromIC(masm);MaybeWorkAroundAmdBug(masm);masm.bind(&failure);EmitStubGuardFailure(masm);returntrue;}boolICUpdatedStub::addUpdateStubForValue(JSContext*cx,HandleScriptouterScript,HandleObjectobj,HandleIdid,HandleValueval){if(numOptimizedStubs_>=MAX_OPTIMIZED_STUBS){// TODO: if the TypeSet becomes unknown or has the AnyObject type,// replace stubs with a single stub to handle these.returntrue;}EnsureTrackPropertyTypes(cx,obj,id);// Make sure that undefined values are explicitly included in the property// types for an object if generating a stub to write an undefined value.if(val.isUndefined()&&CanHaveEmptyPropertyTypesForOwnProperty(obj))AddTypePropertyId(cx,obj,id,val);if(val.isPrimitive()){JSValueTypetype=val.isDouble()?JSVAL_TYPE_DOUBLE:val.extractNonDoubleType();// Check for existing TypeUpdate stub.ICTypeUpdate_PrimitiveSet*existingStub=nullptr;for(ICStubConstIteratoriter(firstUpdateStub_);!iter.atEnd();iter++){if(iter->isTypeUpdate_PrimitiveSet()){existingStub=iter->toTypeUpdate_PrimitiveSet();if(existingStub->containsType(type))returntrue;}}ICTypeUpdate_PrimitiveSet::Compilercompiler(cx,existingStub,type);ICStub*stub=existingStub?compiler.updateStub():compiler.getStub(compiler.getStubSpace(outerScript));if(!stub)returnfalse;if(!existingStub){MOZ_ASSERT(!hasTypeUpdateStub(TypeUpdate_PrimitiveSet));addOptimizedUpdateStub(stub);}JitSpew(JitSpew_BaselineIC," %s TypeUpdate stub %p for primitive type %d",existingStub?"Modified existing":"Created new",stub,type);}elseif(val.toObject().isSingleton()){RootedObjectobj(cx,&val.toObject());// Check for existing TypeUpdate stub.for(ICStubConstIteratoriter(firstUpdateStub_);!iter.atEnd();iter++){if(iter->isTypeUpdate_SingleObject()&&iter->toTypeUpdate_SingleObject()->object()==obj){returntrue;}}ICTypeUpdate_SingleObject::Compilercompiler(cx,obj);ICStub*stub=compiler.getStub(compiler.getStubSpace(outerScript));if(!stub)returnfalse;JitSpew(JitSpew_BaselineIC," Added TypeUpdate stub %p for singleton %p",stub,obj.get());addOptimizedUpdateStub(stub);}else{RootedObjectGroupgroup(cx,val.toObject().group());// Check for existing TypeUpdate stub.for(ICStubConstIteratoriter(firstUpdateStub_);!iter.atEnd();iter++){if(iter->isTypeUpdate_ObjectGroup()&&iter->toTypeUpdate_ObjectGroup()->group()==group){returntrue;}}ICTypeUpdate_ObjectGroup::Compilercompiler(cx,group);ICStub*stub=compiler.getStub(compiler.getStubSpace(outerScript));if(!stub)returnfalse;JitSpew(JitSpew_BaselineIC," Added TypeUpdate stub %p for ObjectGroup %p",stub,group.get());addOptimizedUpdateStub(stub);}returntrue;}//// NewArray_Fallback//staticboolDoNewArray(JSContext*cx,void*payload,ICNewArray_Fallback*stub,uint32_tlength,MutableHandleValueres){SharedStubInfoinfo(cx,payload,stub->icEntry());FallbackICSpew(cx,stub,"NewArray");RootedObjectobj(cx);if(stub->templateObject()){RootedObjecttemplateObject(cx,stub->templateObject());obj=NewArrayOperationWithTemplate(cx,templateObject);if(!obj)returnfalse;}else{HandleScriptscript=info.script();jsbytecode*pc=info.pc();obj=NewArrayOperation(cx,script,pc,length);if(!obj)returnfalse;if(obj&&!obj->isSingleton()&&!obj->group()->maybePreliminaryObjects()){JSObject*templateObject=NewArrayOperation(cx,script,pc,length,TenuredObject);if(!templateObject)returnfalse;stub->setTemplateObject(templateObject);}}res.setObject(*obj);returntrue;}typedefbool(*DoNewArrayFn)(JSContext*,void*,ICNewArray_Fallback*,uint32_t,MutableHandleValue);staticconstVMFunctionDoNewArrayInfo=FunctionInfo<DoNewArrayFn>(DoNewArray,"DoNewArray",TailCall);boolICNewArray_Fallback::Compiler::generateStubCode(MacroAssembler&masm){EmitRestoreTailCallReg(masm);masm.push(R0.scratchReg());// lengthmasm.push(ICStubReg);// stub.pushStubPayload(masm,R0.scratchReg());returntailCallVM(DoNewArrayInfo,masm);}//// NewObject_Fallback//// Unlike typical baseline IC stubs, the code for NewObject_WithTemplate is// specialized for the template object being allocated.staticJitCode*GenerateNewObjectWithTemplateCode(JSContext*cx,JSObject*templateObject){JitContextjctx(cx,nullptr);MacroAssemblermasm;#ifdef JS_CODEGEN_ARMmasm.setSecondScratchReg(BaselineSecondScratchReg);#endifLabelfailure;RegisterobjReg=R0.scratchReg();RegistertempReg=R1.scratchReg();masm.movePtr(ImmGCPtr(templateObject->group()),tempReg);masm.branchTest32(Assembler::NonZero,Address(tempReg,ObjectGroup::offsetOfFlags()),Imm32(OBJECT_FLAG_PRE_TENURE),&failure);masm.branchPtr(Assembler::NotEqual,AbsoluteAddress(cx->compartment()->addressOfMetadataBuilder()),ImmWord(0),&failure);masm.createGCObject(objReg,tempReg,templateObject,gc::DefaultHeap,&failure);masm.tagValue(JSVAL_TYPE_OBJECT,objReg,R0);EmitReturnFromIC(masm);masm.bind(&failure);EmitStubGuardFailure(masm);Linkerlinker(masm);AutoFlushICacheafc("GenerateNewObjectWithTemplateCode");returnlinker.newCode<CanGC>(cx,BASELINE_CODE);}staticboolDoNewObject(JSContext*cx,void*payload,ICNewObject_Fallback*stub,MutableHandleValueres){SharedStubInfoinfo(cx,payload,stub->icEntry());FallbackICSpew(cx,stub,"NewObject");RootedObjectobj(cx);RootedObjecttemplateObject(cx,stub->templateObject());if(templateObject){MOZ_ASSERT(!templateObject->group()->maybePreliminaryObjects());obj=NewObjectOperationWithTemplate(cx,templateObject);}else{HandleScriptscript=info.script();jsbytecode*pc=info.pc();obj=NewObjectOperation(cx,script,pc);if(obj&&!obj->isSingleton()&&!obj->group()->maybePreliminaryObjects()){JSObject*templateObject=NewObjectOperation(cx,script,pc,TenuredObject);if(!templateObject)returnfalse;if(!stub->invalid()&&(templateObject->is<UnboxedPlainObject>()||!templateObject->as<PlainObject>().hasDynamicSlots())){JitCode*code=GenerateNewObjectWithTemplateCode(cx,templateObject);if(!code)returnfalse;ICStubSpace*space=ICStubCompiler::StubSpaceForKind(ICStub::NewObject_WithTemplate,script,ICStubCompiler::Engine::Baseline);ICStub*templateStub=ICStub::New<ICNewObject_WithTemplate>(cx,space,code);if(!templateStub)returnfalse;stub->addNewStub(templateStub);}stub->setTemplateObject(templateObject);}}if(!obj)returnfalse;res.setObject(*obj);returntrue;}typedefbool(*DoNewObjectFn)(JSContext*,void*,ICNewObject_Fallback*,MutableHandleValue);staticconstVMFunctionDoNewObjectInfo=FunctionInfo<DoNewObjectFn>(DoNewObject,"DoNewObject",TailCall);boolICNewObject_Fallback::Compiler::generateStubCode(MacroAssembler&masm){EmitRestoreTailCallReg(masm);masm.push(ICStubReg);// stub.pushStubPayload(masm,R0.scratchReg());returntailCallVM(DoNewObjectInfo,masm);}}// namespace jit}// namespace js