From 96b54f3e75d58183a3581334aaf643d120276a94 Mon Sep 17 00:00:00 2001 From: Kannan Vijayan Date: Tue, 12 Nov 2013 14:20:34 -0500 Subject: [PATCH] Bug 912303 - Added noSuchMethod support to baseline CALLPROP/CALLELEM stubs. r=efaust --- js/src/jit/BaselineIC.cpp | 261 +++++++++++++++++++++++--- js/src/jit/BaselineIC.h | 72 +++++-- js/src/jit/arm/BaselineHelpers-arm.h | 2 +- js/src/jit/arm/MacroAssembler-arm.cpp | 50 ++++- js/src/jit/arm/MacroAssembler-arm.h | 6 + js/src/jit/x64/BaselineHelpers-x64.h | 2 +- js/src/jit/x64/MacroAssembler-x64.h | 50 ++++- js/src/jit/x86/BaselineHelpers-x86.h | 2 +- js/src/jit/x86/MacroAssembler-x86.h | 12 ++ 9 files changed, 413 insertions(+), 44 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 339c5560b71d..3dd8bb375bd8 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -3487,6 +3487,18 @@ IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *sh return true; } +static bool +LookupNoSuchMethodHandler(JSContext *cx, HandleObject obj, HandleValue id, + MutableHandleValue result) +{ + return OnUnknownMethod(cx, obj, id, result); +} + +typedef bool (*LookupNoSuchMethodHandlerFn)(JSContext *, HandleObject, HandleValue, + MutableHandleValue); +static const VMFunction LookupNoSuchMethodHandlerInfo = + FunctionInfo(LookupNoSuchMethodHandler); + static bool GetElemNativeStubExists(ICGetElem_Fallback *stub, HandleObject obj, HandleObject holder, HandlePropertyName propName, bool needsAtomize) @@ -3668,6 +3680,7 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt RootedPropertyName propName(cx, JSID_TO_ATOM(id)->asPropertyName()); bool needsAtomize = !key.toString()->isAtom(); + bool isCallElem = (JSOp(*pc) == JSOP_CALLELEM); RootedShape shape(cx); RootedObject holder(cx); @@ -3698,8 +3711,8 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt ICGetElemNativeStub::AccessType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot : ICGetElemNativeStub::DynamicSlot; - ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, propName, acctype, - needsAtomize, offset); + ICGetElemNativeCompiler compiler(cx, kind, isCallElem, monitorStub, obj, holder, propName, + acctype, needsAtomize, offset); ICStub *newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; @@ -3712,6 +3725,13 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt if (IsCacheableGetPropCall(cx, obj, holder, shape, &getterIsScripted, /*isDOMProxy=*/false)) { RootedFunction getter(cx, &shape->getterObject()->as()); +#if JS_HAS_NO_SUCH_METHOD + // It's unlikely that a getter function will be used in callelem locations. + // Just don't attach stubs in that case to avoid issues with __noSuchMethod__ handling. + if (isCallElem) + return true; +#endif + // If a suitable stub already exists, nothing else to do. if (GetElemNativeStubExists(stub, obj, holder, propName, needsAtomize)) return true; @@ -3744,7 +3764,7 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt ? ICGetElemNativeStub::ScriptedGetter : ICGetElemNativeStub::NativeGetter; ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, propName, acctype, - needsAtomize, getter, pc - script->code); + needsAtomize, getter, pc - script->code, isCallElem); ICStub *newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; @@ -3769,10 +3789,14 @@ static bool TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetElem_Fallback *stub, HandleValue lhs, HandleValue rhs, HandleValue res) { + bool isCallElem = (JSOp(*pc) == JSOP_CALLELEM); + // Check for String[i] => Char accesses. if (lhs.isString() && rhs.isInt32() && res.isString() && !stub->hasStub(ICStub::GetElem_String)) { + // NoSuchMethod handling doesn't apply to string targets. + IonSpew(IonSpew_BaselineIC, " Generating GetElem(String[Int32]) stub"); ICGetElem_String::Compiler compiler(cx); ICStub *stringStub = compiler.getStub(compiler.getStubSpace(script)); @@ -3786,9 +3810,13 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl if (lhs.isMagic(JS_OPTIMIZED_ARGUMENTS) && rhs.isInt32() && !ArgumentsGetElemStubExists(stub, ICGetElem_Arguments::Magic)) { + // Any script with a CALLPROP on arguments (arguments.foo()) + // should not have optimized arguments. + JS_ASSERT(!isCallElem); + IonSpew(IonSpew_BaselineIC, " Generating GetElem(MagicArgs[Int32]) stub"); ICGetElem_Arguments::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(), - ICGetElem_Arguments::Magic); + ICGetElem_Arguments::Magic, false); ICStub *argsStub = compiler.getStub(compiler.getStubSpace(script)); if (!argsStub) return false; @@ -3810,7 +3838,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl if (!ArgumentsGetElemStubExists(stub, which)) { IonSpew(IonSpew_BaselineIC, " Generating GetElem(ArgsObj[Int32]) stub"); ICGetElem_Arguments::Compiler compiler( - cx, stub->fallbackMonitorStub()->firstMonitorStub(), which); + cx, stub->fallbackMonitorStub()->firstMonitorStub(), which, isCallElem); ICStub *argsStub = compiler.getStub(compiler.getStubSpace(script)); if (!argsStub) return false; @@ -3825,7 +3853,7 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl if (rhs.isInt32() && rhs.toInt32() >= 0) { IonSpew(IonSpew_BaselineIC, " Generating GetElem(Native[Int32] dense) stub"); ICGetElem_Dense::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(), - obj->lastProperty()); + obj->lastProperty(), isCallElem); ICStub *denseStub = compiler.getStub(compiler.getStubSpace(script)); if (!denseStub) return false; @@ -3845,6 +3873,12 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICGetEl if (obj->is() && rhs.isInt32() && res.isNumber() && !TypedArrayGetElemStubExists(stub, obj)) { + // Don't attach CALLELEM stubs for accesses on typed array expected to yield numbers. +#if JS_HAS_NO_SUCH_METHOD + if (isCallElem) + return true; +#endif + Rooted tarr(cx, &obj->as()); if (!cx->runtime()->jitSupportsFloatingPoint && TypedArrayRequiresFloatingPoint(tarr)) return true; @@ -4211,16 +4245,58 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler &masm) if (acctype_ == ICGetElemNativeStub::DynamicSlot || acctype_ == ICGetElemNativeStub::FixedSlot) { - // Load from object. - if (acctype_ == ICGetElemNativeStub::DynamicSlot) - masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), holderReg); - masm.load32(Address(BaselineStubReg, ICGetElemNativeSlotStub::offsetOfOffset()), scratchReg); - masm.loadValue(BaseIndex(holderReg, scratchReg, TimesOne), R0); + // Load from object. + if (acctype_ == ICGetElemNativeStub::DynamicSlot) + masm.addPtr(Address(holderReg, JSObject::offsetOfSlots()), scratchReg); + else + masm.addPtr(holderReg, scratchReg); + + Address valAddr(scratchReg, 0); + + // Check if __noSuchMethod__ needs to be called. +#if JS_HAS_NO_SUCH_METHOD + if (isCallElem_) { + Label afterNoSuchMethod; + Label skipNoSuchMethod; + + masm.branchTestUndefined(Assembler::NotEqual, valAddr, &skipNoSuchMethod); + + GeneralRegisterSet regs = availableGeneralRegs(0); + regs.takeUnchecked(objReg); + regs.take(R1); + Register scratch = regs.takeAnyExcluding(BaselineTailCallReg); + if (popR1) + masm.pop(R1.scratchReg()); + enterStubFrame(masm, scratch); + + masm.pushValue(R1); + masm.push(objReg); + if (!callVM(LookupNoSuchMethodHandlerInfo, masm)) + return false; + + leaveStubFrame(masm); + // Result is already in R0 + masm.jump(&afterNoSuchMethod); + masm.bind(&skipNoSuchMethod); + + if (popR1) + masm.pop(R1.scratchReg()); + masm.loadValue(valAddr, R0); + masm.bind(&afterNoSuchMethod); + } else { + masm.loadValue(valAddr, R0); + if (popR1) + masm.addPtr(ImmWord(sizeof(size_t)), BaselineStackReg); + } +#else + masm.loadValue(valAddr, R0); if (popR1) masm.addPtr(ImmWord(sizeof(size_t)), BaselineStackReg); +#endif + } else { JS_ASSERT(acctype_ == ICGetElemNativeStub::NativeGetter || acctype_ == ICGetElemNativeStub::ScriptedGetter); @@ -4355,7 +4431,45 @@ ICGetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm) JS_STATIC_ASSERT(sizeof(Value) == 8); BaseIndex element(scratchReg, key, TimesEight); masm.branchTestMagic(Assembler::Equal, element, &failure); + + // Check if __noSuchMethod__ should be called. +#if JS_HAS_NO_SUCH_METHOD + entersStubFrame_ = true; + if (isCallElem_) { + Label afterNoSuchMethod; + Label skipNoSuchMethod; + regs = availableGeneralRegs(0); + regs.takeUnchecked(obj); + regs.take(R1); + + masm.pushValue(R1); + masm.loadValue(element, R1); + masm.branchTestUndefined(Assembler::NotEqual, R1, &skipNoSuchMethod); + + // Call __noSuchMethod__ checker. Object pointer is in objReg. + scratchReg = regs.takeAnyExcluding(BaselineTailCallReg); + enterStubFrame(masm, scratchReg); + + // propName (R1) already pushed above. + masm.push(obj); + if (!callVM(LookupNoSuchMethodHandlerInfo, masm)) + return false; + + leaveStubFrame(masm); + // Result is already in R0 + masm.jump(&afterNoSuchMethod); + masm.bind(&skipNoSuchMethod); + + masm.moveValue(R1, R0); + masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg); // pop previously pushed propName (R1) + masm.bind(&afterNoSuchMethod); + } else { + masm.loadValue(element, R0); + } +#else + // Load value from element location. masm.loadValue(element, R0); +#endif // Enter type monitor IC to type-check result. EmitEnterTypeMonitorIC(masm); @@ -4414,8 +4528,16 @@ ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm) bool ICGetElem_Arguments::Compiler::generateStubCode(MacroAssembler &masm) { + // Variatns of GetElem_Arguments can enter stub frames if entered in CallProp + // context when noSuchMethod support is on. +#if JS_HAS_NO_SUCH_METHOD + entersStubFrame_ = true; +#endif + Label failure; if (which_ == ICGetElem_Arguments::Magic) { + JS_ASSERT(!isCallElem_); + // Ensure that this is a magic arguments value. masm.branchTestMagicValue(Assembler::NotEqual, R0, JS_OPTIMIZED_ARGUMENTS, &failure); @@ -4516,15 +4638,47 @@ ICGetElem_Arguments::Compiler::generateStubCode(MacroAssembler &masm) masm.addPtr(Imm32(ArgumentsData::offsetOfArgs()), argData); regs.add(scratchReg); regs.add(tempReg); - regs.add(argData); ValueOperand tempVal = regs.takeAnyValue(); masm.loadValue(BaseIndex(argData, idxReg, ScaleFromElemWidth(sizeof(Value))), tempVal); // Makesure that this is not a FORWARD_TO_CALL_SLOT magic value. masm.branchTestMagic(Assembler::Equal, tempVal, &failureReconstructInputs); - // Everything checked out, return value. +#if JS_HAS_NO_SUCH_METHOD + if (isCallElem_) { + Label afterNoSuchMethod; + Label skipNoSuchMethod; + + masm.branchTestUndefined(Assembler::NotEqual, tempVal, &skipNoSuchMethod); + + // Call __noSuchMethod__ checker. Object pointer is in objReg. + regs = availableGeneralRegs(0); + // R1 and objReg are guaranteed not to overlap. + regs.takeUnchecked(objReg); + regs.take(R1); + masm.tagValue(JSVAL_TYPE_INT32, idxReg, R1); + scratchReg = regs.takeAnyExcluding(BaselineTailCallReg); + enterStubFrame(masm, scratchReg); + + masm.pushValue(R1); + masm.push(objReg); + if (!callVM(LookupNoSuchMethodHandlerInfo, masm)) + return false; + + leaveStubFrame(masm); + // Result is already in R0 + masm.jump(&afterNoSuchMethod); + masm.bind(&skipNoSuchMethod); + + masm.moveValue(tempVal, R0); + masm.bind(&afterNoSuchMethod); + } else { + masm.moveValue(tempVal, R0); + } +#else + // Copy value from temp to R0. masm.moveValue(tempVal, R0); +#endif // Type-check result EmitEnterTypeMonitorIC(masm); @@ -5818,6 +5972,8 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, if (!isDOMProxy && !obj->isNative()) return true; + bool isCallProp = (JSOp(*pc) == JSOP_CALLPROP); + ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub(); if (!isDOMProxy && IsCacheableGetPropReadSlot(obj, holder, shape)) { bool isFixedSlot; @@ -5834,7 +5990,8 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, IonSpew(IonSpew_BaselineIC, " Generating GetProp(%s %s) stub", isDOMProxy ? "DOMProxy" : "Native", (obj == holder) ? "direct" : "prototype"); - ICGetPropNativeCompiler compiler(cx, kind, monitorStub, obj, holder, isFixedSlot, offset); + ICGetPropNativeCompiler compiler(cx, kind, isCallProp, monitorStub, obj, holder, + name, isFixedSlot, offset); ICStub *newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; @@ -5849,6 +6006,14 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, // Try handling scripted getters. if (cacheableCall && isScripted && !isDOMProxy) { +#if JS_HAS_NO_SUCH_METHOD + // It's hard to keep the original object alive through a call, and it's unlikely + // that a getter will be used to generate functions for calling in CALLPROP locations. + // Just don't attach stubs in that case. + if (isCallProp) + return true; +#endif + RootedFunction callee(cx, &shape->getterObject()->as()); JS_ASSERT(obj != holder); JS_ASSERT(callee->hasScript()); @@ -5869,6 +6034,14 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, // Try handling JSNative getters. if (cacheableCall && !isScripted) { +#if JS_HAS_NO_SUCH_METHOD + // It's unlikely that a getter function will be used to generate functions for calling + // in CALLPROP locations. Just don't attach stubs in that case to avoid issues with + // __noSuchMethod__ handling. + if (isCallProp) + return true; +#endif + RootedFunction callee(cx, &shape->getterObject()->as()); JS_ASSERT(obj != holder); JS_ASSERT(callee->isNative()); @@ -5909,6 +6082,10 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, // If it's a shadowed listbase proxy property, attach stub to call Proxy::get instead. if (isDOMProxy && domProxyShadowsResult == Shadows) { JS_ASSERT(obj == holder); +#if JS_HAS_NO_SUCH_METHOD + if (isCallProp) + return true; +#endif IonSpew(IonSpew_BaselineIC, " Generating GetProp(DOMProxyProxy) stub"); Rooted proxy(cx, &obj->as()); @@ -5926,9 +6103,9 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, } static bool -TryAttachStringGetPropStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub, - HandlePropertyName name, HandleValue val, HandleValue res, - bool *attached) +TryAttachStringGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, + ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val, + HandleValue res, bool *attached) { JS_ASSERT(!*attached); JS_ASSERT(val.isString()); @@ -6038,7 +6215,7 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub, return true; if (val.isString()) { - if (!TryAttachStringGetPropStub(cx, script, stub, name, val, res, &attached)) + if (!TryAttachStringGetPropStub(cx, script, pc, stub, name, val, res, &attached)) return false; if (attached) return true; @@ -6219,7 +6396,7 @@ ICGetPropNativeCompiler::generateStubCode(MacroAssembler &masm) // Guard input is an object. masm.branchTestObject(Assembler::NotEqual, R0, &failure); - Register scratch = regs.takeAny(); + Register scratch = regs.takeAnyExcluding(BaselineTailCallReg); // Unbox and shape guard. Register objReg = masm.extractObject(R0, ExtractTemp0); @@ -6239,11 +6416,51 @@ ICGetPropNativeCompiler::generateStubCode(MacroAssembler &masm) masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure); } - if (!isFixedSlot_) - masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), holderReg); + 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. + Register nextHolder = regs.takeAny(); + masm.loadPtr(Address(holderReg, JSObject::offsetOfSlots()), nextHolder); + holderReg = nextHolder; + } masm.load32(Address(BaselineStubReg, ICGetPropNativeStub::offsetOfOffset()), scratch); - masm.loadValue(BaseIndex(holderReg, scratch, TimesOne), R0); + BaseIndex result(holderReg, scratch, TimesOne); + +#if JS_HAS_NO_SUCH_METHOD + entersStubFrame_ = true; + if (isCallProp_) { + // Check for __noSuchMethod__ invocation. + Label afterNoSuchMethod; + Label skipNoSuchMethod; + + masm.push(objReg); + masm.loadValue(result, R0); + masm.branchTestUndefined(Assembler::NotEqual, R0, &skipNoSuchMethod); + + masm.pop(objReg); + enterStubFrame(masm, scratch); + + masm.movePtr(ImmGCPtr(propName_.get()), R1.scratchReg()); + masm.tagValue(JSVAL_TYPE_STRING, R1.scratchReg(), R1); + masm.pushValue(R1); + masm.push(objReg); + if (!callVM(LookupNoSuchMethodHandlerInfo, masm)) + return false; + + leaveStubFrame(masm); + masm.jump(&afterNoSuchMethod); + masm.bind(&skipNoSuchMethod); + + // Pop pushed objReg. + masm.addPtr(Imm32(sizeof(void *)), BaselineStackReg); + masm.bind(&afterNoSuchMethod); + } else { + masm.loadValue(result, R0); + } +#else + masm.loadValue(result, R0); +#endif // Enter type monitor IC to type-check result. EmitEnterTypeMonitorIC(masm); diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 308ecea725f4..1e96b8178365 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -754,6 +754,12 @@ class ICStub // pushed during the bailout. case GetProp_Fallback: case SetProp_Fallback: +#if JS_HAS_NO_SUCH_METHOD + case GetElem_Dense: + case GetElem_Arguments: + case GetProp_NativePrototype: + case GetProp_Native: +#endif return true; default: return false; @@ -3110,6 +3116,7 @@ class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCal // Compiler for GetElem_NativeSlot and GetElem_NativePrototypeSlot stubs. class ICGetElemNativeCompiler : public ICStubCompiler { + bool isCallElem_; ICStub *firstMonitorStub_; HandleObject obj_; HandleObject holder_; @@ -3126,16 +3133,24 @@ class ICGetElemNativeCompiler : public ICStubCompiler protected: virtual int32_t getKey() const { +#if JS_HAS_NO_SUCH_METHOD + return static_cast(kind) | + (static_cast(isCallElem_) << 16) | + (static_cast(needsAtomize_) << 17) | + (static_cast(acctype_) << 18); +#else return static_cast(kind) | (static_cast(needsAtomize_) << 16) | (static_cast(acctype_) << 17); +#endif } public: - ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub, - HandleObject obj, HandleObject holder, HandlePropertyName name, - ICGetElemNativeStub::AccessType acctype, bool needsAtomize, - uint32_t offset) + ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, bool isCallElem, + ICStub *firstMonitorStub, HandleObject obj, HandleObject holder, + HandlePropertyName name, ICGetElemNativeStub::AccessType acctype, + bool needsAtomize, uint32_t offset) : ICStubCompiler(cx, kind), + isCallElem_(isCallElem), firstMonitorStub_(firstMonitorStub), obj_(obj), holder_(holder), @@ -3150,8 +3165,9 @@ class ICGetElemNativeCompiler : public ICStubCompiler ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub, HandleObject obj, HandleObject holder, HandlePropertyName name, ICGetElemNativeStub::AccessType acctype, bool needsAtomize, - HandleFunction getter, uint32_t pcOffset) + HandleFunction getter, uint32_t pcOffset, bool isCallElem) : ICStubCompiler(cx, kind), + isCallElem_(false), firstMonitorStub_(firstMonitorStub), obj_(obj), holder_(holder), @@ -3255,15 +3271,25 @@ class ICGetElem_Dense : public ICMonitoredStub class Compiler : public ICStubCompiler { ICStub *firstMonitorStub_; RootedShape shape_; + bool isCallElem_; protected: bool generateStubCode(MacroAssembler &masm); + virtual int32_t getKey() const { +#if JS_HAS_NO_SUCH_METHOD + return static_cast(kind) | (static_cast(isCallElem_) << 16); +#else + return static_cast(kind); +#endif + } + public: - Compiler(JSContext *cx, ICStub *firstMonitorStub, Shape *shape) + Compiler(JSContext *cx, ICStub *firstMonitorStub, Shape *shape, bool isCallElem) : ICStubCompiler(cx, ICStub::GetElem_Dense), firstMonitorStub_(firstMonitorStub), - shape_(cx, shape) + shape_(cx, shape), + isCallElem_(isCallElem) {} ICStub *getStub(ICStubSpace *space) { @@ -3351,19 +3377,27 @@ class ICGetElem_Arguments : public ICMonitoredStub class Compiler : public ICStubCompiler { ICStub *firstMonitorStub_; Which which_; + bool isCallElem_; protected: bool generateStubCode(MacroAssembler &masm); virtual int32_t getKey() const { +#if JS_HAS_NO_SUCH_METHOD + return static_cast(kind) | + static_cast(isCallElem_ << 16) | + (static_cast(which_) << 17); +#else return static_cast(kind) | (static_cast(which_) << 16); +#endif } public: - Compiler(JSContext *cx, ICStub *firstMonitorStub, Which which) + Compiler(JSContext *cx, ICStub *firstMonitorStub, Which which, bool isCallElem) : ICStubCompiler(cx, ICStub::GetElem_Arguments), firstMonitorStub_(firstMonitorStub), - which_(which) + which_(which), + isCallElem_(isCallElem) {} ICStub *getStub(ICStubSpace *space) { @@ -4253,9 +4287,11 @@ class ICGetProp_NativePrototype : public ICGetPropNativeStub // Compiler for GetProp_Native and GetProp_NativePrototype stubs. class ICGetPropNativeCompiler : public ICStubCompiler { + bool isCallProp_; ICStub *firstMonitorStub_; HandleObject obj_; HandleObject holder_; + HandlePropertyName propName_; bool isFixedSlot_; uint32_t offset_; @@ -4263,17 +4299,25 @@ class ICGetPropNativeCompiler : public ICStubCompiler protected: virtual int32_t getKey() const { +#if JS_HAS_NO_SUCH_METHOD + return static_cast(kind) | + (static_cast(isCallProp_) << 16) | + (static_cast(isFixedSlot_) << 17); +#else return static_cast(kind) | (static_cast(isFixedSlot_) << 16); +#endif } public: - ICGetPropNativeCompiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub, - HandleObject obj, HandleObject holder, bool isFixedSlot, - uint32_t offset) + ICGetPropNativeCompiler(JSContext *cx, ICStub::Kind kind, bool isCallProp, + ICStub *firstMonitorStub, HandleObject obj, HandleObject holder, + HandlePropertyName propName, bool isFixedSlot, uint32_t offset) : ICStubCompiler(cx, kind), + isCallProp_(isCallProp), firstMonitorStub_(firstMonitorStub), obj_(obj), holder_(holder), + propName_(propName), isFixedSlot_(isFixedSlot), offset_(offset) {} @@ -4355,8 +4399,8 @@ class ICGetPropCallGetter : public ICMonitoredStub uint32_t pcOffset_; public: - Compiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub, HandleObject obj, - HandleObject holder, HandleFunction getter, uint32_t pcOffset) + Compiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub, + HandleObject obj, HandleObject holder, HandleFunction getter, uint32_t pcOffset) : ICStubCompiler(cx, kind), firstMonitorStub_(firstMonitorStub), obj_(cx, obj), diff --git a/js/src/jit/arm/BaselineHelpers-arm.h b/js/src/jit/arm/BaselineHelpers-arm.h index aa9907483b63..9e418973c383 100644 --- a/js/src/jit/arm/BaselineHelpers-arm.h +++ b/js/src/jit/arm/BaselineHelpers-arm.h @@ -205,7 +205,7 @@ EmitUnstowICValues(MacroAssembler &masm, int values) masm.popValue(R0); break; case 2: - // Untow R0 and R1 + // Unstow R0 and R1 masm.popValue(R1); masm.popValue(R0); break; diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index bb4089e3996a..0cbab9b30cc5 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -2689,13 +2689,61 @@ MacroAssemblerARMCompat::testInt32(Assembler::Condition cond, const Address &add } Assembler::Condition -MacroAssemblerARMCompat::testDouble(Assembler::Condition cond, const Address &address) +MacroAssemblerARMCompat::testDouble(Condition cond, const Address &address) { JS_ASSERT(cond == Equal || cond == NotEqual); extractTag(address, ScratchRegister); return testDouble(cond, ScratchRegister); } +Assembler::Condition +MacroAssemblerARMCompat::testBoolean(Condition cond, const Address &address) +{ + JS_ASSERT(cond == Equal || cond == NotEqual); + extractTag(address, ScratchRegister); + return testBoolean(cond, ScratchRegister); +} + +Assembler::Condition +MacroAssemblerARMCompat::testNull(Condition cond, const Address &address) +{ + JS_ASSERT(cond == Equal || cond == NotEqual); + extractTag(address, ScratchRegister); + return testNull(cond, ScratchRegister); +} + +Assembler::Condition +MacroAssemblerARMCompat::testUndefined(Condition cond, const Address &address) +{ + JS_ASSERT(cond == Equal || cond == NotEqual); + extractTag(address, ScratchRegister); + return testUndefined(cond, ScratchRegister); +} + +Assembler::Condition +MacroAssemblerARMCompat::testString(Condition cond, const Address &address) +{ + JS_ASSERT(cond == Equal || cond == NotEqual); + extractTag(address, ScratchRegister); + return testString(cond, ScratchRegister); +} + +Assembler::Condition +MacroAssemblerARMCompat::testObject(Condition cond, const Address &address) +{ + JS_ASSERT(cond == Equal || cond == NotEqual); + extractTag(address, ScratchRegister); + return testObject(cond, ScratchRegister); +} + +Assembler::Condition +MacroAssemblerARMCompat::testNumber(Condition cond, const Address &address) +{ + JS_ASSERT(cond == Equal || cond == NotEqual); + extractTag(address, ScratchRegister); + return testNumber(cond, ScratchRegister); +} + Assembler::Condition MacroAssemblerARMCompat::testDouble(Condition cond, const Register &tag) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 064fc8639f4d..3b5a21dfab95 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -728,6 +728,12 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM Condition testMagic(Condition cond, const Address &address); Condition testInt32(Condition cond, const Address &address); Condition testDouble(Condition cond, const Address &address); + Condition testBoolean(Condition cond, const Address &address); + Condition testNull(Condition cond, const Address &address); + Condition testUndefined(Condition cond, const Address &address); + Condition testString(Condition cond, const Address &address); + Condition testObject(Condition cond, const Address &address); + Condition testNumber(Condition cond, const Address &address); Condition testUndefined(Condition cond, const BaseIndex &src); Condition testNull(Condition cond, const BaseIndex &src); diff --git a/js/src/jit/x64/BaselineHelpers-x64.h b/js/src/jit/x64/BaselineHelpers-x64.h index 0716a0482393..70dfd5f53e94 100644 --- a/js/src/jit/x64/BaselineHelpers-x64.h +++ b/js/src/jit/x64/BaselineHelpers-x64.h @@ -193,7 +193,7 @@ EmitUnstowICValues(MacroAssembler &masm, int values) masm.push(BaselineTailCallReg); break; case 2: - // Untow R0 and R1 + // Unstow R0 and R1 masm.pop(BaselineTailCallReg); masm.popValue(R1); masm.popValue(R0); diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 081a8f1d9a8f..53ccd2ac0a63 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -356,6 +356,48 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared splitTag(src, ScratchReg); return testGCThing(cond, ScratchReg); } + Condition testPrimitive(Condition cond, const ValueOperand &src) { + splitTag(src, ScratchReg); + return testPrimitive(cond, ScratchReg); + } + + + Condition testUndefined(Condition cond, const Address &src) { + splitTag(src, ScratchReg); + return testUndefined(cond, ScratchReg); + } + Condition testInt32(Condition cond, const Address &src) { + splitTag(src, ScratchReg); + return testInt32(cond, ScratchReg); + } + Condition testBoolean(Condition cond, const Address &src) { + splitTag(src, ScratchReg); + return testBoolean(cond, ScratchReg); + } + Condition testDouble(Condition cond, const Address &src) { + splitTag(src, ScratchReg); + return testDouble(cond, ScratchReg); + } + Condition testNumber(Condition cond, const Address &src) { + splitTag(src, ScratchReg); + return testNumber(cond, ScratchReg); + } + Condition testNull(Condition cond, const Address &src) { + splitTag(src, ScratchReg); + return testNull(cond, ScratchReg); + } + Condition testString(Condition cond, const Address &src) { + splitTag(src, ScratchReg); + return testString(cond, ScratchReg); + } + Condition testObject(Condition cond, const Address &src) { + splitTag(src, ScratchReg); + return testObject(cond, ScratchReg); + } + Condition testPrimitive(Condition cond, const Address &src) { + splitTag(src, ScratchReg); + return testPrimitive(cond, ScratchReg); + } Condition testGCThing(Condition cond, const Address &src) { splitTag(src, ScratchReg); return testGCThing(cond, ScratchReg); @@ -364,10 +406,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared splitTag(src, ScratchReg); return testMagic(cond, ScratchReg); } - Condition testPrimitive(Condition cond, const ValueOperand &src) { - splitTag(src, ScratchReg); - return testPrimitive(cond, ScratchReg); - } Condition testUndefined(Condition cond, const BaseIndex &src) { @@ -773,6 +811,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED)))); j(cond, label); } + void branchTestUndefined(Condition cond, const Address &address, Label *label) { + JS_ASSERT(cond == Equal || cond == NotEqual); + branchTestUndefined(cond, Operand(address), label); + } void branchTestInt32(Condition cond, const Operand &operand, Label *label) { JS_ASSERT(cond == Equal || cond == NotEqual); cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32)))); diff --git a/js/src/jit/x86/BaselineHelpers-x86.h b/js/src/jit/x86/BaselineHelpers-x86.h index 1b073f29ab8b..dc3ccc65086f 100644 --- a/js/src/jit/x86/BaselineHelpers-x86.h +++ b/js/src/jit/x86/BaselineHelpers-x86.h @@ -199,7 +199,7 @@ EmitUnstowICValues(MacroAssembler &masm, int values) masm.push(BaselineTailCallReg); break; case 2: - // Untow R0 and R1 + // Unstow R0 and R1 masm.pop(BaselineTailCallReg); masm.popValue(R1); masm.popValue(R0); diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index b13516f4cc2c..ce5f4a219afa 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -357,6 +357,18 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared JS_ASSERT(cond == Equal || cond == NotEqual); return testDouble(cond, Operand(address)); } + + + Condition testUndefined(Condition cond, const Operand &operand) { + JS_ASSERT(cond == Equal || cond == NotEqual); + cmpl(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED)); + return cond; + } + Condition testUndefined(Condition cond, const Address &addr) { + return testUndefined(cond, Operand(addr)); + } + + Condition testUndefined(Condition cond, const ValueOperand &value) { return testUndefined(cond, value.typeReg()); }