Bug 1665396 - Support calling DOM setters in CacheIR. r=jandem

Differential Revision: https://phabricator.services.mozilla.com/D90422
This commit is contained in:
Tom Schuster 2020-09-17 06:43:23 +00:00
Родитель c4fd01303a
Коммит 07459af75f
8 изменённых файлов: 118 добавлений и 8 удалений

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

@ -53,6 +53,9 @@ class JSJitSetterCallArgs : protected JS::MutableHandle<JS::Value> {
explicit JSJitSetterCallArgs(const JS::CallArgs& args)
: JS::MutableHandle<JS::Value>(args[0]) {}
explicit JSJitSetterCallArgs(JS::Rooted<JS::Value>* rooted)
: JS::MutableHandle<JS::Value>(rooted) {}
JS::MutableHandle<JS::Value> operator[](unsigned i) {
MOZ_ASSERT(i == 0);
return *this;

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

@ -2012,6 +2012,35 @@ bool BaselineCacheIRCompiler::emitCallScriptedSetter(
return true;
}
bool BaselineCacheIRCompiler::emitCallDOMSetter(ObjOperandId objId,
uint32_t jitInfoOffset,
ValOperandId rhsId) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
Register obj = allocator.useRegister(masm, objId);
ValueOperand val = allocator.useValueRegister(masm, rhsId);
Address jitInfoAddr(stubAddress(jitInfoOffset));
AutoScratchRegister scratch(allocator, masm);
allocator.discardStack(masm);
AutoStubFrame stubFrame(*this);
stubFrame.enter(masm, scratch);
// Load the JSJitInfo in the scratch register.
masm.loadPtr(jitInfoAddr, scratch);
masm.Push(val);
masm.Push(obj);
masm.Push(scratch);
using Fn = bool (*)(JSContext*, const JSJitInfo*, HandleObject, HandleValue);
callVM<Fn, CallDOMSetter>(masm);
stubFrame.leave(masm);
return true;
}
bool BaselineCacheIRCompiler::emitCallSetArrayLength(ObjOperandId objId,
bool strict,
ValOperandId rhsId) {

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

@ -1065,8 +1065,10 @@ static void EmitCallGetterResult(JSContext* cx, CacheIRWriter& writer,
EmitCallGetterResultNoGuards(cx, writer, obj, holder, shape, receiverId);
}
static bool CanAttachDOMGetter(JSContext* cx, HandleObject obj,
HandleShape shape, ICState::Mode mode) {
static bool CanAttachDOMGetterSetter(JSContext* cx, JSJitInfo::OpType type,
HandleObject obj, HandleShape shape,
ICState::Mode mode) {
MOZ_ASSERT(type == JSJitInfo::Getter || type == JSJitInfo::Setter);
if (!JitOptions.warpBuilder) {
return false;
}
@ -1075,17 +1077,19 @@ static bool CanAttachDOMGetter(JSContext* cx, HandleObject obj,
return false;
}
JSFunction* getter = &shape->getterValue().toObject().as<JSFunction>();
if (!getter->hasJitInfo()) {
Value v =
type == JSJitInfo::Getter ? shape->getterValue() : shape->setterValue();
JSFunction* fun = &v.toObject().as<JSFunction>();
if (!fun->hasJitInfo()) {
return false;
}
if (cx->realm() != getter->realm()) {
if (cx->realm() != fun->realm()) {
return false;
}
const JSJitInfo* jitInfo = getter->jitInfo();
if (jitInfo->type() != JSJitInfo::Getter) {
const JSJitInfo* jitInfo = fun->jitInfo();
if (jitInfo->type() != type) {
return false;
}
@ -1179,7 +1183,8 @@ AttachDecision GetPropIRGenerator::tryAttachNative(HandleObject obj,
MOZ_ASSERT(!idempotent());
maybeEmitIdGuard(id);
if (!isSuper() && CanAttachDOMGetter(cx_, obj, shape, mode_)) {
if (!isSuper() &&
CanAttachDOMGetterSetter(cx_, JSJitInfo::Getter, obj, shape, mode_)) {
EmitCallDOMGetterResult(cx_, writer, obj, holder, shape, objId);
trackAttached("DOMGetter");
@ -3916,6 +3921,16 @@ static void EmitCallSetterNoGuards(JSContext* cx, CacheIRWriter& writer,
writer.returnFromIC();
}
static void EmitCallDOMSetterNoGuards(JSContext* cx, CacheIRWriter& writer,
Shape* shape, ObjOperandId objId,
ValOperandId rhsId) {
JSFunction* setter = &shape->setterValue().toObject().as<JSFunction>();
MOZ_ASSERT(cx->realm() == setter->realm());
writer.callDOMSetter(objId, setter->jitInfo(), rhsId);
writer.returnFromIC();
}
AttachDecision SetPropIRGenerator::tryAttachSetter(HandleObject obj,
ObjOperandId objId,
HandleId id,
@ -3945,6 +3960,13 @@ AttachDecision SetPropIRGenerator::tryAttachSetter(HandleObject obj,
writer.guardHasGetterSetter(objId, propShape);
}
if (CanAttachDOMGetterSetter(cx_, JSJitInfo::Setter, obj, propShape, mode_)) {
EmitCallDOMSetterNoGuards(cx_, writer, propShape, objId, rhsId);
trackAttached("DOMSetter");
return AttachDecision::Attach;
}
EmitCallSetterNoGuards(cx_, writer, obj, holder, propShape, objId, rhsId);
trackAttached("Setter");

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

@ -1440,6 +1440,15 @@
sameRealm: BoolImm
nargsAndFlags: RawWordField
- name: CallDOMSetter
shared: false
transpile: false
cost_estimate: 4
args:
obj: ObjId
jitInfo: RawPointerField
rhs: ValId
- name: CallSetArrayLength
shared: false
transpile: true

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

@ -1093,6 +1093,29 @@ bool IonCacheIRCompiler::emitCallDOMGetterResult(ObjOperandId objId,
return true;
}
bool IonCacheIRCompiler::emitCallDOMSetter(ObjOperandId objId,
uint32_t jitInfoOffset,
ValOperandId rhsId) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
AutoSaveLiveRegisters save(*this);
Register obj = allocator.useRegister(masm, objId);
ValueOperand val = allocator.useValueRegister(masm, rhsId);
const JSJitInfo* info = rawWordStubField<const JSJitInfo*>(jitInfoOffset);
allocator.discardStack(masm);
prepareVMCall(masm, save);
masm.Push(val);
masm.Push(obj);
masm.Push(ImmPtr(info));
using Fn = bool (*)(JSContext*, const JSJitInfo*, HandleObject, HandleValue);
callVM<Fn, jit::CallDOMSetter>(masm);
return true;
}
bool IonCacheIRCompiler::emitProxyGetResult(ObjOperandId objId,
uint32_t idOffset) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);

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

@ -77,6 +77,7 @@ namespace jit {
_(BoxNonStrictThis, js::BoxNonStrictThis) \
_(BuiltinObjectOperation, js::BuiltinObjectOperation) \
_(CallDOMGetter, js::jit::CallDOMGetter) \
_(CallDOMSetter, js::jit::CallDOMSetter) \
_(CallNativeGetter, js::jit::CallNativeGetter) \
_(CallNativeSetter, js::jit::CallNativeSetter) \
_(CharCodeAt, js::jit::CharCodeAt) \

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

@ -1531,6 +1531,26 @@ bool CallNativeSetter(JSContext* cx, HandleFunction callee, HandleObject obj,
return natfun(cx, 1, vp.begin());
}
bool CallDOMSetter(JSContext* cx, const JSJitInfo* info, HandleObject obj,
HandleValue value) {
MOZ_ASSERT(info->type() == JSJitInfo::Setter);
MOZ_ASSERT(obj->isNative());
MOZ_ASSERT(obj->getClass()->isDOMClass());
#ifdef DEBUG
DOMInstanceClassHasProtoAtDepth instanceChecker =
cx->runtime()->DOMcallbacks->instanceClassMatchesProto;
MOZ_ASSERT(instanceChecker(obj->getClass(), info->protoID, info->depth));
#endif
// Loading DOM_OBJECT_SLOT, which must be the first slot.
JS::Value val = JS::GetReservedSlot(obj, 0);
JSJitSetterOp setter = info->setter;
RootedValue v(cx, value);
return setter(cx, obj, val.toPrivate(), JSJitSetterCallArgs(&v));
}
bool EqualStringsHelperPure(JSString* str1, JSString* str2) {
// IC code calls this directly so we shouldn't GC.
AutoUnsafeCallWithABI unsafe;

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

@ -1081,6 +1081,9 @@ MOZ_MUST_USE bool CallNativeGetter(JSContext* cx, HandleFunction callee,
bool CallDOMGetter(JSContext* cx, const JSJitInfo* jitInfo, HandleObject obj,
MutableHandleValue result);
bool CallDOMSetter(JSContext* cx, const JSJitInfo* jitInfo, HandleObject obj,
HandleValue value);
MOZ_MUST_USE bool CallNativeSetter(JSContext* cx, HandleFunction callee,
HandleObject obj, HandleValue rhs);