Bug 856829 - Add optimized stubs for GetProp-getter and SetProp-setter calling JSNative targets. r=jandem

This commit is contained in:
Kannan Vijayan 2013-04-03 13:47:58 +02:00
Родитель 833d84e579
Коммит f851cf4a9e
2 изменённых файлов: 533 добавлений и 94 удалений

Просмотреть файл

@ -310,6 +310,14 @@ ICStub::trace(JSTracer *trc)
MarkObject(trc, &callStub->getter(), "baseline-getpropcallscripted-stub-getter"); MarkObject(trc, &callStub->getter(), "baseline-getpropcallscripted-stub-getter");
break; break;
} }
case ICStub::GetProp_CallNative: {
ICGetProp_CallNative *callStub = toGetProp_CallNative();
MarkShape(trc, &callStub->shape(), "baseline-getpropcallnative-stub-shape");
MarkObject(trc, &callStub->holder(), "baseline-getpropcallnative-stub-holder");
MarkShape(trc, &callStub->holderShape(), "baseline-getpropcallnative-stub-holdershape");
MarkObject(trc, &callStub->getter(), "baseline-getpropcallnative-stub-getter");
break;
}
case ICStub::SetProp_Native: { case ICStub::SetProp_Native: {
ICSetProp_Native *propStub = toSetProp_Native(); ICSetProp_Native *propStub = toSetProp_Native();
MarkShape(trc, &propStub->shape(), "baseline-setpropnative-stub-shape"); MarkShape(trc, &propStub->shape(), "baseline-setpropnative-stub-shape");
@ -339,6 +347,14 @@ ICStub::trace(JSTracer *trc)
MarkObject(trc, &callStub->setter(), "baseline-setpropcallscripted-stub-setter"); MarkObject(trc, &callStub->setter(), "baseline-setpropcallscripted-stub-setter");
break; break;
} }
case ICStub::SetProp_CallNative: {
ICSetProp_CallNative *callStub = toSetProp_CallNative();
MarkShape(trc, &callStub->shape(), "baseline-setpropcallnative-stub-shape");
MarkObject(trc, &callStub->holder(), "baseline-setpropcallnative-stub-holder");
MarkShape(trc, &callStub->holderShape(), "baseline-setpropcallnative-stub-holdershape");
MarkObject(trc, &callStub->setter(), "baseline-setpropcallnative-stub-setter");
break;
}
default: default:
break; break;
} }
@ -579,7 +595,8 @@ ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, La
// This should only be called from the following stubs. // This should only be called from the following stubs.
JS_ASSERT(kind == ICStub::Call_Scripted || kind == ICStub::Call_AnyScripted || JS_ASSERT(kind == ICStub::Call_Scripted || kind == ICStub::Call_AnyScripted ||
kind == ICStub::Call_Native || kind == ICStub::GetProp_CallScripted || kind == ICStub::Call_Native || kind == ICStub::GetProp_CallScripted ||
kind == ICStub::SetProp_CallScripted); kind == ICStub::GetProp_CallNative || kind == ICStub::SetProp_CallScripted ||
kind == ICStub::SetProp_CallNative);
// Guard on bit in frame that indicates if the SPS frame was pushed in the first // Guard on bit in frame that indicates if the SPS frame was pushed in the first
// place. This code is expected to be called from within a stub that has already // place. This code is expected to be called from within a stub that has already
@ -3031,8 +3048,10 @@ IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, Shape *shape)
} }
static bool static bool
IsCacheableGetPropCallScripted(JSObject *obj, JSObject *holder, Shape *shape) IsCacheableGetPropCall(JSObject *obj, JSObject *holder, Shape *shape, bool *isScripted)
{ {
JS_ASSERT(isScripted);
// Currently we only optimize getter calls for getters bound on prototypes. // Currently we only optimize getter calls for getters bound on prototypes.
if (obj == holder) if (obj == holder)
return false; return false;
@ -3043,15 +3062,27 @@ IsCacheableGetPropCallScripted(JSObject *obj, JSObject *holder, Shape *shape)
if (shape->hasSlot() || shape->hasDefaultGetter()) if (shape->hasSlot() || shape->hasDefaultGetter())
return false; return false;
if (!shape->hasGetterValue() || !shape->getterObject()->isFunction()) if (!shape->hasGetterValue())
return false;
if (!shape->getterValue().isObject() || !shape->getterObject()->isFunction())
return false; return false;
JSFunction *func = shape->getterObject()->toFunction(); JSFunction *func = shape->getterObject()->toFunction();
if (func->isNative()) {
*isScripted = false;
return true;
}
if (!func->hasScript()) if (!func->hasScript())
return false; return false;
JSScript *script = func->nonLazyScript(); JSScript *script = func->nonLazyScript();
return script->hasIonScript() || script->hasBaselineScript(); if (!script->hasIonScript() && !script->hasBaselineScript())
return false;
*isScripted = true;
return true;
} }
static bool static bool
@ -3132,8 +3163,10 @@ IsCacheableSetPropAddSlot(JSContext *cx, HandleObject obj, HandleShape oldShape,
} }
static bool static bool
IsCacheableSetPropCallScripted(JSObject *obj, JSObject *holder, Shape *shape) IsCacheableSetPropCall(JSObject *obj, JSObject *holder, Shape *shape, bool *isScripted)
{ {
JS_ASSERT(isScripted);
// Currently we only optimize setter calls for setters bound on prototypes. // Currently we only optimize setter calls for setters bound on prototypes.
if (obj == holder) if (obj == holder)
return false; return false;
@ -3144,15 +3177,27 @@ IsCacheableSetPropCallScripted(JSObject *obj, JSObject *holder, Shape *shape)
if (shape->hasSlot() || shape->hasDefaultSetter()) if (shape->hasSlot() || shape->hasDefaultSetter())
return false; return false;
if (!shape->hasSetterValue() || !shape->setterObject()->isFunction()) if (!shape->hasSetterValue())
return false;
if (!shape->setterValue().isObject() || !shape->setterObject()->isFunction())
return false; return false;
JSFunction *func = shape->setterObject()->toFunction(); JSFunction *func = shape->setterObject()->toFunction();
if (func->isNative()) {
*isScripted = false;
return true;
}
if (!func->hasScript()) if (!func->hasScript())
return false; return false;
JSScript *script = func->nonLazyScript(); JSScript *script = func->nonLazyScript();
return script->hasIonScript() || script->hasBaselineScript(); if (!script->hasIonScript() && !script->hasBaselineScript())
return false;
*isScripted = true;
return true;
} }
static bool static bool
@ -4711,14 +4756,16 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
return true; return true;
} }
// Only handle CallGetter stubs on prototypes for now, not direct getters. bool isScripted = false;
if (IsCacheableGetPropCallScripted(obj, holder, shape)) { bool cacheableCall = IsCacheableGetPropCall(obj, holder, shape, &isScripted);
// Try handling scripted getters.
if (cacheableCall && isScripted) {
RootedFunction callee(cx, shape->getterObject()->toFunction()); RootedFunction callee(cx, shape->getterObject()->toFunction());
JS_ASSERT(obj != holder); JS_ASSERT(obj != holder);
JS_ASSERT(callee->hasScript()); JS_ASSERT(callee->hasScript());
IonSpew(IonSpew_BaselineIC, " Generating GetProp(Native %s Getter %s:%d) stub", IonSpew(IonSpew_BaselineIC, " Generating GetProp(NativeObj/ScriptedGetter %s:%d) stub",
(obj == holder) ? "direct" : "prototype",
callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno); callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno);
ICGetProp_CallScripted::Compiler compiler(cx, monitorStub, obj, holder, callee, ICGetProp_CallScripted::Compiler compiler(cx, monitorStub, obj, holder, callee,
@ -4732,6 +4779,26 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
return true; return true;
} }
// Try handling JSNative getters.
if (cacheableCall && !isScripted) {
RootedFunction callee(cx, shape->getterObject()->toFunction());
JS_ASSERT(obj != holder);
JS_ASSERT(callee->isNative());
IonSpew(IonSpew_BaselineIC, " Generating GetProp(NativeObj/NativeGetter %p) stub",
callee->native());
ICGetProp_CallNative::Compiler compiler(cx, monitorStub, obj, holder, callee,
pc - script->code);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
*attached = true;
return true;
}
return true; return true;
} }
@ -5137,6 +5204,99 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
return true; return true;
} }
static bool
DoCallNativeGetter(JSContext *cx, HandleFunction callee, HandleObject obj,
MutableHandleValue result)
{
JS_ASSERT(callee->isNative());
JSNative natfun = callee->native();
Value vp[2] = { ObjectValue(*callee.get()), ObjectValue(*obj.get()) };
AutoValueArray rootVp(cx, vp, 2);
if (!natfun(cx, 0, vp))
return false;
result.set(vp[0]);
return true;
}
typedef bool (*DoCallNativeGetterFn)(JSContext *, HandleFunction, HandleObject, MutableHandleValue);
static const VMFunction DoCallNativeGetterInfo =
FunctionInfo<DoCallNativeGetterFn>(DoCallNativeGetter);
bool
ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
{
Label failure;
GeneralRegisterSet regs(availableGeneralRegs(1));
Register scratch;
if (regs.has(BaselineTailCallReg)) {
regs.take(BaselineTailCallReg);
scratch = regs.takeAny();
regs.add(BaselineTailCallReg);
} else {
scratch = regs.takeAny();
}
// Guard input is an object.
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
// Unbox and shape guard.
Register objReg = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallNative::offsetOfShape()), scratch);
masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
Register holderReg = regs.takeAny();
masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallNative::offsetOfHolder()), holderReg);
masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallNative::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.
Register callee = regs.takeAny();
masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallNative::offsetOfGetter()), callee);
// Push args for vm call.
masm.push(objReg);
masm.push(callee);
// Don't to preserve R0 anymore.
regs.add(R0);
// If needed, update SPS Profiler frame entry.
{
Label skipProfilerUpdate;
Register scratch = regs.takeAny();
Register pcIdx = regs.takeAny();
// Check if profiling is enabled.
guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
// Update profiling entry before leaving function.
masm.load32(Address(BaselineStubReg, ICGetProp_CallNative::offsetOfPCOffset()), pcIdx);
masm.spsUpdatePCIdx(&cx->runtime->spsProfiler, pcIdx, scratch);
masm.bind(&skipProfilerUpdate);
regs.add(scratch);
regs.add(pcIdx);
}
if (!callVM(DoCallNativeGetterInfo, masm))
return false;
leaveStubFrame(masm);
// Enter type monitor IC to type-check result.
EmitEnterTypeMonitorIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
// //
// SetProp_Fallback // SetProp_Fallback
// //
@ -5198,13 +5358,16 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
return true; return true;
} }
if (IsCacheableSetPropCallScripted(obj, holder, shape)) { bool isScripted = false;
bool cacheableCall = IsCacheableSetPropCall(obj, holder, shape, &isScripted);
// Try handling scripted setters.
if (cacheableCall && isScripted) {
RootedFunction callee(cx, shape->setterObject()->toFunction()); RootedFunction callee(cx, shape->setterObject()->toFunction());
JS_ASSERT(obj != holder); JS_ASSERT(obj != holder);
JS_ASSERT(callee->hasScript()); JS_ASSERT(callee->hasScript());
IonSpew(IonSpew_BaselineIC, " Generating SetProp(Native %s Setter %s:%d) stub", IonSpew(IonSpew_BaselineIC, " Generating SetProp(NativeObj/ScriptedSetter %s:%d) stub",
(obj == holder) ? "direct" : "prototype",
callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno); callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno);
ICSetProp_CallScripted::Compiler compiler(cx, obj, holder, callee, pc - script->code); ICSetProp_CallScripted::Compiler compiler(cx, obj, holder, callee, pc - script->code);
@ -5217,6 +5380,25 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetPr
return true; return true;
} }
// Try handling JSNative setters.
if (cacheableCall && !isScripted) {
RootedFunction callee(cx, shape->setterObject()->toFunction());
JS_ASSERT(obj != holder);
JS_ASSERT(callee->isNative());
IonSpew(IonSpew_BaselineIC, " Generating SetProp(NativeObj/NativeSetter %p) stub",
callee->native());
ICSetProp_CallNative::Compiler compiler(cx, obj, holder, callee, pc - script->code);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
*attached = true;
return true;
}
return true; return true;
} }
@ -5587,6 +5769,110 @@ ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
return true; return true;
} }
static bool
DoCallNativeSetter(JSContext *cx, HandleFunction callee, HandleObject obj, HandleValue val)
{
JS_ASSERT(callee->isNative());
JSNative natfun = callee->native();
Value vp[3] = { ObjectValue(*callee.get()), ObjectValue(*obj.get()), val };
AutoValueArray rootVp(cx, vp, 3);
return natfun(cx, 1, vp);
}
typedef bool (*DoCallNativeSetterFn)(JSContext *, HandleFunction, HandleObject, HandleValue);
static const VMFunction DoCallNativeSetterInfo =
FunctionInfo<DoCallNativeSetterFn>(DoCallNativeSetter);
bool
ICSetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
{
Label failure;
Label failureUnstow;
// Guard input is an object.
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
// Stow R0 and R1 to free up registers.
EmitStowICValues(masm, 2);
GeneralRegisterSet regs(availableGeneralRegs(1));
Register scratch;
if (regs.has(BaselineTailCallReg)) {
regs.take(BaselineTailCallReg);
scratch = regs.takeAny();
regs.add(BaselineTailCallReg);
} else {
scratch = regs.takeAny();
}
// Unbox and shape guard.
Register objReg = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfShape()), scratch);
masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failureUnstow);
Register holderReg = regs.takeAny();
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfHolder()), holderReg);
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfHolderShape()), scratch);
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failureUnstow);
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.
Register callee = regs.takeAny();
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfSetter()), callee);
// To Push R1, read it off of the stowed values on stack.
// Stack: [ ..., R0, R1, ..STUBFRAME-HEADER.. ]
masm.movePtr(BaselineStackReg, scratch);
masm.pushValue(Address(scratch, STUB_FRAME_SIZE));
masm.push(objReg);
masm.push(callee);
// Don't need to preserve R0 anymore.
regs.add(R0);
// If needed, update SPS Profiler frame entry.
{
Label skipProfilerUpdate;
Register scratch = regs.takeAny();
Register pcIdx = regs.takeAny();
// Check if profiling is enabled.
guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
// Update profiling entry before leaving function.
masm.load32(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfPCOffset()), pcIdx);
masm.spsUpdatePCIdx(&cx->runtime->spsProfiler, pcIdx, scratch);
masm.bind(&skipProfilerUpdate);
regs.add(scratch);
regs.add(pcIdx);
}
if (!callVM(DoCallNativeSetterInfo, masm))
return false;
leaveStubFrame(masm);
// Do not care about return value from function. The original RHS should be returned
// as the result of this operation.
EmitUnstowICValues(masm, 2);
masm.moveValue(R1, R0);
EmitReturnFromIC(masm);
// Unstow R0 and R1
masm.bind(&failureUnstow);
EmitUnstowICValues(masm, 2);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
// //
// Call_Fallback // Call_Fallback
// //

Просмотреть файл

@ -362,11 +362,13 @@ class ICEntry
_(GetProp_Native) \ _(GetProp_Native) \
_(GetProp_NativePrototype) \ _(GetProp_NativePrototype) \
_(GetProp_CallScripted) \ _(GetProp_CallScripted) \
_(GetProp_CallNative) \
\ \
_(SetProp_Fallback) \ _(SetProp_Fallback) \
_(SetProp_Native) \ _(SetProp_Native) \
_(SetProp_NativeAdd) \ _(SetProp_NativeAdd) \
_(SetProp_CallScripted) \ _(SetProp_CallScripted) \
_(SetProp_CallNative) \
\ \
_(TableSwitch) \ _(TableSwitch) \
\ \
@ -721,7 +723,9 @@ class ICStub
case Call_Fallback: case Call_Fallback:
case UseCount_Fallback: case UseCount_Fallback:
case GetProp_CallScripted: case GetProp_CallScripted:
case GetProp_CallNative:
case SetProp_CallScripted: case SetProp_CallScripted:
case SetProp_CallNative:
return true; return true;
default: default:
return false; return false;
@ -4005,8 +4009,8 @@ class ICGetPropNativeCompiler : public ICStubCompiler
} }
}; };
// Stub for calling a scripted getter on a native object. // Stub for calling a getter (native or scripted) on a native object.
class ICGetProp_CallScripted : public ICMonitoredStub class ICGetPropCallGetter : public ICMonitoredStub
{ {
friend class ICStubSpace; friend class ICStubSpace;
@ -4024,15 +4028,83 @@ class ICGetProp_CallScripted : public ICMonitoredStub
// PC offset of call // PC offset of call
uint32_t pcOffset_; uint32_t pcOffset_;
ICGetProp_CallScripted(IonCode *stubCode, ICStub *firstMonitorStub, ICGetPropCallGetter(Kind kind, IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandleObject holder, HandleShape holderShape, HandleShape shape, HandleObject holder, HandleShape holderShape,
HandleFunction getter, uint32_t pcOffset) HandleFunction getter, uint32_t pcOffset)
: ICMonitoredStub(GetProp_CallScripted, stubCode, firstMonitorStub), : ICMonitoredStub(kind, stubCode, firstMonitorStub),
shape_(shape), shape_(shape),
holder_(holder), holder_(holder),
holderShape_(holderShape), holderShape_(holderShape),
getter_(getter), getter_(getter),
pcOffset_(pcOffset) pcOffset_(pcOffset)
{
JS_ASSERT(kind == ICStub::GetProp_CallScripted || kind == ICStub::GetProp_CallNative);
}
public:
HeapPtrShape &shape() {
return shape_;
}
HeapPtrObject &holder() {
return holder_;
}
HeapPtrShape &holderShape() {
return holderShape_;
}
HeapPtrFunction &getter() {
return getter_;
}
static size_t offsetOfShape() {
return offsetof(ICGetPropCallGetter, shape_);
}
static size_t offsetOfHolder() {
return offsetof(ICGetPropCallGetter, holder_);
}
static size_t offsetOfHolderShape() {
return offsetof(ICGetPropCallGetter, holderShape_);
}
static size_t offsetOfGetter() {
return offsetof(ICGetPropCallGetter, getter_);
}
static size_t offsetOfPCOffset() {
return offsetof(ICGetPropCallGetter, pcOffset_);
}
class Compiler : public ICStubCompiler {
protected:
ICStub *firstMonitorStub_;
RootedObject obj_;
RootedObject holder_;
RootedFunction getter_;
uint32_t pcOffset_;
public:
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),
holder_(cx, holder),
getter_(cx, getter),
pcOffset_(pcOffset)
{
JS_ASSERT(kind == ICStub::GetProp_CallScripted || kind == ICStub::GetProp_CallNative);
}
};
};
// Stub for calling a scripted getter on a native object.
class ICGetProp_CallScripted : public ICGetPropCallGetter
{
friend class ICStubSpace;
protected:
ICGetProp_CallScripted(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandleObject holder, HandleShape holderShape,
HandleFunction getter, uint32_t pcOffset)
: ICGetPropCallGetter(GetProp_CallScripted, stubCode, firstMonitorStub,
shape, holder, holderShape, getter, pcOffset)
{} {}
public: public:
@ -4048,53 +4120,15 @@ class ICGetProp_CallScripted : public ICMonitoredStub
pcOffset); pcOffset);
} }
HeapPtrShape &shape() { class Compiler : public ICGetPropCallGetter::Compiler {
return shape_; protected:
}
HeapPtrObject &holder() {
return holder_;
}
HeapPtrShape &holderShape() {
return holderShape_;
}
HeapPtrFunction &getter() {
return getter_;
}
static size_t offsetOfShape() {
return offsetof(ICGetProp_CallScripted, shape_);
}
static size_t offsetOfHolder() {
return offsetof(ICGetProp_CallScripted, holder_);
}
static size_t offsetOfHolderShape() {
return offsetof(ICGetProp_CallScripted, holderShape_);
}
static size_t offsetOfGetter() {
return offsetof(ICGetProp_CallScripted, getter_);
}
static size_t offsetOfPCOffset() {
return offsetof(ICGetProp_CallScripted, pcOffset_);
}
class Compiler : public ICStubCompiler {
ICStub *firstMonitorStub_;
RootedObject obj_;
RootedObject holder_;
RootedFunction getter_;
uint32_t pcOffset_;
bool generateStubCode(MacroAssembler &masm); bool generateStubCode(MacroAssembler &masm);
public: public:
Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj, Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj,
HandleObject holder, HandleFunction getter, uint32_t pcOffset) HandleObject holder, HandleFunction getter, uint32_t pcOffset)
: ICStubCompiler(cx, ICStub::GetProp_CallScripted), : ICGetPropCallGetter::Compiler(cx, ICStub::GetProp_CallScripted, firstMonitorStub,
firstMonitorStub_(firstMonitorStub), obj, holder, getter, pcOffset)
obj_(cx, obj),
holder_(cx, holder),
getter_(cx, getter),
pcOffset_(pcOffset)
{} {}
ICStub *getStub(ICStubSpace *space) { ICStub *getStub(ICStubSpace *space) {
@ -4106,6 +4140,52 @@ class ICGetProp_CallScripted : public ICMonitoredStub
}; };
}; };
// Stub for calling a native getter on a native object.
class ICGetProp_CallNative : public ICGetPropCallGetter
{
friend class ICStubSpace;
protected:
ICGetProp_CallNative(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandleObject holder, HandleShape holderShape,
HandleFunction getter, uint32_t pcOffset)
: ICGetPropCallGetter(GetProp_CallNative, stubCode, firstMonitorStub,
shape, holder, holderShape, getter, pcOffset)
{}
public:
static inline ICGetProp_CallNative *New(
ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
HandleShape shape, HandleObject holder, HandleShape holderShape,
HandleFunction getter, uint32_t pcOffset)
{
if (!code)
return NULL;
return space->allocate<ICGetProp_CallNative>(code, firstMonitorStub,
shape, holder, holderShape, getter,
pcOffset);
}
class Compiler : public ICGetPropCallGetter::Compiler {
protected:
bool generateStubCode(MacroAssembler &masm);
public:
Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj,
HandleObject holder, HandleFunction getter, uint32_t pcOffset)
: ICGetPropCallGetter::Compiler(cx, ICStub::GetProp_CallNative, firstMonitorStub,
obj, holder, getter, pcOffset)
{}
ICStub *getStub(ICStubSpace *space) {
RootedShape shape(cx, obj_->lastProperty());
RootedShape holderShape(cx, holder_->lastProperty());
return ICGetProp_CallNative::New(space, getStubCode(), firstMonitorStub_, shape,
holder_, holderShape, getter_, pcOffset_);
}
};
};
// SetProp // SetProp
// JSOP_SETPROP // JSOP_SETPROP
// JSOP_SETNAME // JSOP_SETNAME
@ -4356,8 +4436,8 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler {
ICUpdatedStub *getStub(ICStubSpace *space); ICUpdatedStub *getStub(ICStubSpace *space);
}; };
// Stub for calling a scripted setter on a native object. // Base stub for calling a setters on a native object.
class ICSetProp_CallScripted : public ICStub class ICSetPropCallSetter : public ICStub
{ {
friend class ICStubSpace; friend class ICStubSpace;
@ -4375,28 +4455,19 @@ class ICSetProp_CallScripted : public ICStub
// PC of call, for profiler // PC of call, for profiler
uint32_t pcOffset_; uint32_t pcOffset_;
ICSetProp_CallScripted(IonCode *stubCode, HandleShape shape, HandleObject holder, ICSetPropCallSetter(Kind kind, IonCode *stubCode, HandleShape shape, HandleObject holder,
HandleShape holderShape, HandleFunction setter, uint32_t pcOffset) HandleShape holderShape, HandleFunction setter, uint32_t pcOffset)
: ICStub(SetProp_CallScripted, stubCode), : ICStub(kind, stubCode),
shape_(shape), shape_(shape),
holder_(holder), holder_(holder),
holderShape_(holderShape), holderShape_(holderShape),
setter_(setter), setter_(setter),
pcOffset_(pcOffset) pcOffset_(pcOffset)
{}
public:
static inline ICSetProp_CallScripted *New(ICStubSpace *space, IonCode *code,
HandleShape shape, HandleObject holder,
HandleShape holderShape, HandleFunction setter,
uint32_t pcOffset)
{ {
if (!code) JS_ASSERT(kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative);
return NULL;
return space->allocate<ICSetProp_CallScripted>(code, shape, holder, holderShape, setter,
pcOffset);
} }
public:
HeapPtrShape &shape() { HeapPtrShape &shape() {
return shape_; return shape_;
} }
@ -4411,37 +4482,75 @@ class ICSetProp_CallScripted : public ICStub
} }
static size_t offsetOfShape() { static size_t offsetOfShape() {
return offsetof(ICSetProp_CallScripted, shape_); return offsetof(ICSetPropCallSetter, shape_);
} }
static size_t offsetOfHolder() { static size_t offsetOfHolder() {
return offsetof(ICSetProp_CallScripted, holder_); return offsetof(ICSetPropCallSetter, holder_);
} }
static size_t offsetOfHolderShape() { static size_t offsetOfHolderShape() {
return offsetof(ICSetProp_CallScripted, holderShape_); return offsetof(ICSetPropCallSetter, holderShape_);
} }
static size_t offsetOfSetter() { static size_t offsetOfSetter() {
return offsetof(ICSetProp_CallScripted, setter_); return offsetof(ICSetPropCallSetter, setter_);
} }
static size_t offsetOfPCOffset() { static size_t offsetOfPCOffset() {
return offsetof(ICSetProp_CallScripted, pcOffset_); return offsetof(ICSetPropCallSetter, pcOffset_);
} }
class Compiler : public ICStubCompiler { class Compiler : public ICStubCompiler {
protected:
RootedObject obj_; RootedObject obj_;
RootedObject holder_; RootedObject holder_;
RootedFunction setter_; RootedFunction setter_;
uint32_t pcOffset_; uint32_t pcOffset_;
public:
Compiler(JSContext *cx, ICStub::Kind kind, HandleObject obj, HandleObject holder,
HandleFunction setter, uint32_t pcOffset)
: ICStubCompiler(cx, kind),
obj_(cx, obj),
holder_(cx, holder),
setter_(cx, setter),
pcOffset_(pcOffset)
{
JS_ASSERT(kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative);
}
};
};
// Stub for calling a scripted setter on a native object.
class ICSetProp_CallScripted : public ICSetPropCallSetter
{
friend class ICStubSpace;
protected:
ICSetProp_CallScripted(IonCode *stubCode, HandleShape shape, HandleObject holder,
HandleShape holderShape, HandleFunction setter, uint32_t pcOffset)
: ICSetPropCallSetter(SetProp_CallScripted, stubCode, shape, holder, holderShape,
setter, pcOffset)
{}
public:
static inline ICSetProp_CallScripted *New(ICStubSpace *space, IonCode *code,
HandleShape shape, HandleObject holder,
HandleShape holderShape, HandleFunction setter,
uint32_t pcOffset)
{
if (!code)
return NULL;
return space->allocate<ICSetProp_CallScripted>(code, shape, holder, holderShape, setter,
pcOffset);
}
class Compiler : public ICSetPropCallSetter::Compiler {
protected:
bool generateStubCode(MacroAssembler &masm); bool generateStubCode(MacroAssembler &masm);
public: public:
Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter, Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter,
uint32_t pcOffset) uint32_t pcOffset)
: ICStubCompiler(cx, ICStub::SetProp_CallScripted), : ICSetPropCallSetter::Compiler(cx, ICStub::SetProp_CallScripted,
obj_(cx, obj), obj, holder, setter, pcOffset)
holder_(cx, holder),
setter_(cx, setter),
pcOffset_(pcOffset)
{} {}
ICStub *getStub(ICStubSpace *space) { ICStub *getStub(ICStubSpace *space) {
@ -4453,6 +4562,50 @@ class ICSetProp_CallScripted : public ICStub
}; };
}; };
// Stub for calling a native setter on a native object.
class ICSetProp_CallNative : public ICSetPropCallSetter
{
friend class ICStubSpace;
protected:
ICSetProp_CallNative(IonCode *stubCode, HandleShape shape, HandleObject holder,
HandleShape holderShape, HandleFunction setter, uint32_t pcOffset)
: ICSetPropCallSetter(SetProp_CallNative, stubCode, shape, holder, holderShape,
setter, pcOffset)
{}
public:
static inline ICSetProp_CallNative *New(ICStubSpace *space, IonCode *code,
HandleShape shape, HandleObject holder,
HandleShape holderShape, HandleFunction setter,
uint32_t pcOffset)
{
if (!code)
return NULL;
return space->allocate<ICSetProp_CallNative>(code, shape, holder, holderShape, setter,
pcOffset);
}
class Compiler : public ICSetPropCallSetter::Compiler {
protected:
bool generateStubCode(MacroAssembler &masm);
public:
Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter,
uint32_t pcOffset)
: ICSetPropCallSetter::Compiler(cx, ICStub::SetProp_CallNative,
obj, holder, setter, pcOffset)
{}
ICStub *getStub(ICStubSpace *space) {
RootedShape shape(cx, obj_->lastProperty());
RootedShape holderShape(cx, holder_->lastProperty());
return ICSetProp_CallNative::New(space, getStubCode(), shape, holder_, holderShape,
setter_, pcOffset_);
}
};
};
// Call // Call
// JSOP_CALL // JSOP_CALL
// JSOP_FUNAPPLY // JSOP_FUNAPPLY