mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 21:35:39 +00:00
Bug 912303 - Added noSuchMethod support to baseline CALLPROP/CALLELEM stubs. r=efaust
This commit is contained in:
parent
3f7a45bcdc
commit
96b54f3e75
@ -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<LookupNoSuchMethodHandlerFn>(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<JSFunction>());
|
||||
|
||||
#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<TypedArrayObject>() && 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<TypedArrayObject*> tarr(cx, &obj->as<TypedArrayObject>());
|
||||
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<JSFunction>());
|
||||
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<JSFunction>());
|
||||
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<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
|
||||
@ -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);
|
||||
|
@ -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<int32_t>(kind) |
|
||||
(static_cast<int32_t>(isCallElem_) << 16) |
|
||||
(static_cast<int32_t>(needsAtomize_) << 17) |
|
||||
(static_cast<int32_t>(acctype_) << 18);
|
||||
#else
|
||||
return static_cast<int32_t>(kind) | (static_cast<int32_t>(needsAtomize_) << 16) |
|
||||
(static_cast<int32_t>(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<int32_t>(kind) | (static_cast<int32_t>(isCallElem_) << 16);
|
||||
#else
|
||||
return static_cast<int32_t>(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<int32_t>(kind) |
|
||||
static_cast<int32_t>(isCallElem_ << 16) |
|
||||
(static_cast<int32_t>(which_) << 17);
|
||||
#else
|
||||
return static_cast<int32_t>(kind) | (static_cast<int32_t>(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<int32_t>(kind) |
|
||||
(static_cast<int32_t>(isCallProp_) << 16) |
|
||||
(static_cast<int32_t>(isFixedSlot_) << 17);
|
||||
#else
|
||||
return static_cast<int32_t>(kind) | (static_cast<int32_t>(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),
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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))));
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user