Bug 782869 - Fix incorrect |this| parameter passing to specialized DOM methods. (r=dvander)

This commit is contained in:
Eric Faust 2012-08-15 00:14:20 -07:00
parent b95f463253
commit b1559913eb
5 changed files with 94 additions and 8 deletions

View File

@ -582,15 +582,15 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative *call)
// Nestle the stack up against the pushed arguments, leaving StackPointer at
// &vp[1]
masm.adjustStack(unusedStack);
masm.movePtr(StackPointer, argObj);
// argObj is filled with the extracted object, then returned.
Register obj = masm.extractObject(Address(StackPointer, 0), argObj);
JS_ASSERT(obj == argObj);
// Push a Value containing the callee object: natives are allowed to access their callee before
// setitng the return value. The StackPointer is moved to &vp[0].
masm.Push(ObjectValue(*target));
masm.movePtr(StackPointer, argVp);
// Use argArgc as scratch.
Register obj = masm.extractObject(Address(argObj, 0), argArgc);
// GetReservedSlot(obj, DOM_PROTO_INSTANCE_CLASS_SLOT).toPrivate()
masm.loadPrivate(Address(obj, JSObject::getFixedSlotOffset(0)), argPrivate);
@ -599,11 +599,17 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative *call)
// Push argument into what will become the IonExitFrame
masm.Push(argArgc);
// Push |this| object for passing HandleObject. We push after argc to
// maintain the same sp-relative location of the object pointer with other
// DOMExitFrames.
masm.Push(argObj);
masm.movePtr(StackPointer, argObj);
// Construct native exit frame.
uint32 safepointOffset;
if (!masm.buildFakeExitFrame(argJSContext, &safepointOffset))
return false;
masm.enterFakeExitFrame();
masm.enterFakeDOMFrame(ION_FRAME_DOMMETHOD);
if (!markSafepointAt(safepointOffset, call))
return false;
@ -625,7 +631,7 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative *call)
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &exception);
// Load the outparam vp[0] into output register(s).
masm.loadValue(Address(StackPointer, IonNativeExitFrameLayout::offsetOfResult()), JSReturnOperand);
masm.loadValue(Address(StackPointer, IonDOMMethodExitFrameLayout::offsetOfResult()), JSReturnOperand);
masm.jump(&success);
// Handle exception case.
@ -639,7 +645,7 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative *call)
// is no need for leaveFakeExitFrame.
// Move the StackPointer back to its original location, unwinding the native exit frame.
masm.adjustStack(IonNativeExitFrameLayout::Size() - unusedStack);
masm.adjustStack(IonDOMMethodExitFrameLayout::Size() - unusedStack);
JS_ASSERT(masm.framePushed() == initialStack);
dropArguments(call->numStackArgs() + 1);

View File

@ -123,7 +123,9 @@ IonFrameIterator::isDOMExit() const
if (type_ != IonFrame_Exit)
return false;
IonCode *code = exitFrame()->footer()->ionCode();
return code == ION_FRAME_DOMGETTER || code == ION_FRAME_DOMSETTER;
return code == ION_FRAME_DOMGETTER ||
code == ION_FRAME_DOMSETTER ||
code == ION_FRAME_DOMMETHOD;
}
bool
@ -517,8 +519,15 @@ MarkIonExitFrame(JSTracer *trc, const IonFrameIterator &frame)
if (frame.isDOMExit()) {
IonDOMExitFrameLayout *dom = frame.exitFrame()->DOMExit();
gc::MarkObjectRoot(trc, dom->thisObjAddress(), "ion-dom-args");
if (dom->isSetterFrame())
if (dom->isSetterFrame()) {
gc::MarkValueRoot(trc, dom->vp(), "ion-dom-args");
} else if (dom->isMethodFrame()) {
IonDOMMethodExitFrameLayout *method =
reinterpret_cast<IonDOMMethodExitFrameLayout *>(dom);
size_t len = method->argc() + 2;
Value *vp = method->vp();
gc::MarkValueRootRange(trc, len, vp, "ion-dom-args");
}
return;
}

View File

@ -254,6 +254,41 @@ class IonDOMExitFrameLayout
inline bool isSetterFrame() {
return footer_.ionCode() == ION_FRAME_DOMSETTER;
}
inline bool isMethodFrame() {
return footer_.ionCode() == ION_FRAME_DOMMETHOD;
}
};
class IonDOMMethodExitFrameLayout
{
IonExitFooterFrame footer_;
IonExitFrameLayout exit_;
// This must be the last thing pushed, so as to stay common with
// IonDOMExitFrameLayout.
JSObject *thisObj_;
uintptr_t argc_;
Value CalleeResult_;
public:
static inline size_t Size() {
return sizeof(IonDOMMethodExitFrameLayout);
}
static size_t offsetOfResult() {
return offsetof(IonDOMMethodExitFrameLayout, CalleeResult_);
}
inline Value *vp() {
JS_STATIC_ASSERT(offsetof(IonDOMMethodExitFrameLayout, CalleeResult_) ==
(offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t)));
return &CalleeResult_;
}
inline JSObject **thisObjAddress() {
return &thisObj_;
}
inline uintptr_t argc() {
return argc_;
}
};
// An invalidation bailout stack is at the stack pointer for the callee frame.

View File

@ -43,5 +43,6 @@
#define ION_FRAME_DOMGETTER ((IonCode *)0x1)
#define ION_FRAME_DOMSETTER ((IonCode *)0x2)
#define ION_FRAME_DOMMETHOD ((IonCode *)0x3)
#endif

View File

@ -236,6 +236,41 @@ class IonDOMExitFrameLayout
inline bool isSetterFrame() {
return footer_.ionCode() == ION_FRAME_DOMSETTER;
}
inline bool isMethodFrame() {
return footer_.ionCode() == ION_FRAME_DOMMETHOD;
}
};
class IonDOMMethodExitFrameLayout
{
IonExitFooterFrame footer_;
IonExitFrameLayout exit_;
// This must be the last thing pushed, so as to stay common with
// IonDOMExitFrameLayout.
JSObject *thisObj_;
uintptr_t argc_;
Value CalleeResult_;
public:
static inline size_t Size() {
return sizeof(IonDOMMethodExitFrameLayout);
}
static size_t offsetOfResult() {
return offsetof(IonDOMMethodExitFrameLayout, CalleeResult_);
}
inline Value *vp() {
JS_STATIC_ASSERT(offsetof(IonDOMMethodExitFrameLayout, CalleeResult_) ==
(offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t)));
return &CalleeResult_;
}
inline JSObject **thisObjAddress() {
return &thisObj_;
}
inline uintptr_t argc() {
return argc_;
}
};
class IonOsrFrameLayout : public IonJSFrameLayout