Bug 1824051 - Handle IC for scripted proxy get in Ion r=iain,jandem

Differential Revision: https://phabricator.services.mozilla.com/D182133
This commit is contained in:
Doug Thayer 2023-08-15 21:51:09 +00:00
Родитель e77934e39a
Коммит 4a0b1e43c4
16 изменённых файлов: 518 добавлений и 22 удалений

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

@ -9592,6 +9592,8 @@ void CacheIRCompiler::callVMInternal(MacroAssembler& masm, VMFunctionId id) {
sizeof(ExitFrameLayout) - ExitFrameLayout::bytesPoppedAfterCall();
masm.implicitPop(frameSize + framePop);
masm.freeStack(asIon()->localTracingSlots() * sizeof(Value));
// Pop IonICCallFrameLayout.
masm.Pop(FramePointer);
masm.freeStack(IonICCallFrameLayout::Size() - sizeof(void*));

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

@ -57,6 +57,7 @@
#include "js/RegExpFlags.h" // JS::RegExpFlag
#include "js/ScalarType.h" // js::Scalar::Type
#include "proxy/DOMProxy.h"
#include "proxy/ScriptedProxyHandler.h"
#include "util/CheckedArithmetic.h"
#include "util/Unicode.h"
#include "vm/ArrayBufferViewObject.h"
@ -4588,6 +4589,18 @@ void CodeGenerator::visitGuardIsTypedArray(LGuardIsTypedArray* guard) {
bailoutFrom(&bail, guard->snapshot());
}
void CodeGenerator::visitGuardHasProxyHandler(LGuardHasProxyHandler* guard) {
Register obj = ToRegister(guard->input());
Label bail;
Address handlerAddr(obj, ProxyObject::offsetOfHandler());
masm.branchPtr(Assembler::NotEqual, handlerAddr,
ImmPtr(guard->mir()->handler()), &bail);
bailoutFrom(&bail, guard->snapshot());
}
void CodeGenerator::visitGuardObjectIdentity(LGuardObjectIdentity* guard) {
Register input = ToRegister(guard->input());
Register expected = ToRegister(guard->expected());
@ -14536,6 +14549,77 @@ void CodeGenerator::visitMegamorphicSetElement(LMegamorphicSetElement* lir) {
masm.bind(&done);
}
void CodeGenerator::visitLoadScriptedProxyHandler(
LLoadScriptedProxyHandler* ins) {
const Register obj = ToRegister(ins->getOperand(0));
Register output = ToRegister(ins->output());
masm.loadPtr(Address(obj, ProxyObject::offsetOfReservedSlots()), output);
masm.unboxObject(Address(output, js::detail::ProxyReservedSlots::offsetOfSlot(
ScriptedProxyHandler::HANDLER_EXTRA)),
output);
}
#ifdef JS_PUNBOX64
void CodeGenerator::visitCheckScriptedProxyGetResult(
LCheckScriptedProxyGetResult* ins) {
ValueOperand target = ToValue(ins, LCheckScriptedProxyGetResult::TargetIndex);
ValueOperand value = ToValue(ins, LCheckScriptedProxyGetResult::ValueIndex);
ValueOperand id = ToValue(ins, LCheckScriptedProxyGetResult::IdIndex);
Register scratch = ToRegister(ins->temp0());
Register scratch2 = ToRegister(ins->temp1());
using Fn = bool (*)(JSContext*, HandleObject, HandleValue, HandleValue,
MutableHandleValue);
OutOfLineCode* ool = oolCallVM<Fn, CheckProxyGetByValueResult>(
ins, ArgList(scratch, id, value), StoreValueTo(value));
masm.unboxObject(target, scratch);
masm.branchTestObjectNeedsProxyResultValidation(Assembler::NonZero, scratch,
scratch2, ool->entry());
masm.bind(ool->rejoin());
}
#endif
void CodeGenerator::visitIdToStringOrSymbol(LIdToStringOrSymbol* ins) {
ValueOperand id = ToValue(ins, LIdToStringOrSymbol::IdIndex);
ValueOperand output = ToOutValue(ins);
Register scratch = ToRegister(ins->temp0());
masm.moveValue(id, output);
Label done, callVM;
Maybe<Label> bail;
MDefinition* idDef = ins->mir()->idVal();
if (idDef->isBox()) {
idDef = idDef->toBox()->input();
}
if (idDef->type() != MIRType::Int32) {
bail.emplace();
ScratchTagScope tag(masm, output);
masm.splitTagForTest(output, tag);
masm.branchTestString(Assembler::Equal, tag, &done);
masm.branchTestSymbol(Assembler::Equal, tag, &done);
masm.branchTestInt32(Assembler::NotEqual, tag, &*bail);
}
masm.unboxInt32(output, scratch);
using Fn = JSLinearString* (*)(JSContext*, int);
OutOfLineCode* ool = oolCallVM<Fn, Int32ToString<CanGC>>(
ins, ArgList(scratch), StoreRegisterTo(output.scratchReg()));
emitIntToString(scratch, output.scratchReg(), ool->entry());
masm.bind(ool->rejoin());
masm.tagValue(JSVAL_TYPE_STRING, output.scratchReg(), output);
masm.bind(&done);
if (bail) {
bailoutFrom(&*bail, ins->snapshot());
}
}
void CodeGenerator::visitLoadFixedSlotV(LLoadFixedSlotV* ins) {
const Register obj = ToRegister(ins->getOperand(0));
size_t slot = ins->mir()->slot();

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

@ -53,7 +53,8 @@ IonCacheIRCompiler::IonCacheIRCompiler(JSContext* cx, TempAllocator& alloc,
writer_(writer),
ic_(ic),
ionScript_(ionScript),
savedLiveRegs_(false) {
savedLiveRegs_(false),
localTracingSlots_(0) {
MOZ_ASSERT(ic_);
MOZ_ASSERT(ionScript_);
}
@ -272,6 +273,22 @@ void IonCacheIRCompiler::enterStubFrame(MacroAssembler& masm,
enteredStubFrame_ = true;
}
void IonCacheIRCompiler::storeTracedValue(MacroAssembler& masm,
ValueOperand value) {
MOZ_ASSERT(localTracingSlots_ < 255);
masm.Push(value);
localTracingSlots_++;
}
void IonCacheIRCompiler::loadTracedValue(MacroAssembler& masm,
uint8_t slotIndex,
ValueOperand value) {
MOZ_ASSERT(slotIndex <= localTracingSlots_);
int32_t offset = IonICCallFrameLayout::LocallyTracedValueOffset +
slotIndex * sizeof(Value);
masm.loadValue(Address(FramePointer, -offset), value);
}
bool IonCacheIRCompiler::init() {
if (!allocator.init()) {
return false;
@ -594,6 +611,8 @@ JitCode* IonCacheIRCompiler::compile(IonICStub* stub) {
return nullptr;
}
newStubCode->setLocalTracingSlots(localTracingSlots_);
for (CodeOffset offset : nextCodeOffsets_) {
Assembler::PatchDataWithValueCheck(CodeLocationLabel(newStubCode, offset),
ImmPtr(stub->nextCodeRawPtr()),
@ -922,6 +941,145 @@ bool IonCacheIRCompiler::emitCallScriptedGetterResult(
return true;
}
#ifdef JS_PUNBOX64
template <typename IdType>
bool IonCacheIRCompiler::emitCallScriptedProxyGetShared(ValOperandId targetId,
ObjOperandId receiverId,
ObjOperandId handlerId,
uint32_t trapOffset,
IdType id) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
AutoSaveLiveRegisters save(*this);
AutoOutputRegister output(*this);
ValueOperand target = allocator.useValueRegister(masm, targetId);
Register receiver = allocator.useRegister(masm, receiverId);
Register handler = allocator.useRegister(masm, handlerId);
ValueOperand idVal;
if constexpr (std::is_same_v<IdType, ValOperandId>) {
idVal = allocator.useValueRegister(masm, id);
}
JSFunction* trap = &objectStubField(trapOffset)->as<JSFunction>();
AutoScratchRegister scratch(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
ValueOperand scratchVal(scratch);
ValueOperand scratchVal2(scratch2);
allocator.discardStack(masm);
uint32_t framePushedBefore = masm.framePushed();
enterStubFrame(masm, save);
// We need to keep the target around to potentially validate the proxy result
storeTracedValue(masm, target);
if constexpr (std::is_same_v<IdType, ValOperandId>) {
// Same for the id, assuming it's not baked in
storeTracedValue(masm, idVal);
}
uint32_t framePushedBeforeArgs = masm.framePushed();
// The JitFrameLayout pushed below will be aligned to JitStackAlignment,
// so we just have to make sure the stack is aligned after we push the
// |this| + argument Values.
uint32_t argSize = (std::max(trap->nargs(), (size_t)3) + 1) * sizeof(Value);
uint32_t padding =
ComputeByteAlignment(masm.framePushed() + argSize, JitStackAlignment);
MOZ_ASSERT(padding % sizeof(uintptr_t) == 0);
MOZ_ASSERT(padding < JitStackAlignment);
masm.reserveStack(padding);
for (size_t i = 3; i < trap->nargs(); i++) {
masm.Push(UndefinedValue());
}
masm.tagValue(JSVAL_TYPE_OBJECT, receiver, scratchVal);
masm.Push(scratchVal);
if constexpr (std::is_same_v<IdType, ValOperandId>) {
masm.Push(idVal);
} else {
masm.movePropertyKey(idStubField(id), scratch);
masm.tagValue(JSVAL_TYPE_STRING, scratch, scratchVal);
masm.Push(scratchVal);
}
masm.Push(target);
masm.tagValue(JSVAL_TYPE_OBJECT, handler, scratchVal);
masm.Push(scratchVal);
masm.movePtr(ImmGCPtr(trap), scratch);
masm.Push(scratch);
masm.PushFrameDescriptorForJitCall(FrameType::IonICCall, /* argc = */ 3);
// Check stack alignment. Add 2 * sizeof(uintptr_t) for the return address and
// frame pointer pushed by the call/callee.
MOZ_ASSERT(
((masm.framePushed() + 2 * sizeof(uintptr_t)) % JitStackAlignment) == 0);
MOZ_ASSERT(trap->hasJitEntry());
masm.loadJitCodeRaw(scratch, scratch);
masm.callJit(scratch);
masm.storeCallResultValue(output);
Label success, end;
loadTracedValue(masm, 0, scratchVal);
masm.unboxObject(scratchVal, scratch);
masm.branchTestObjectNeedsProxyResultValidation(Assembler::Zero, scratch,
scratch2, &success);
if constexpr (std::is_same_v<IdType, ValOperandId>) {
loadTracedValue(masm, 1, scratchVal2);
} else {
masm.moveValue(StringValue(idStubField(id).toString()), scratchVal2);
}
uint32_t framePushedAfterCall = masm.framePushed();
masm.freeStack(masm.framePushed() - framePushedBeforeArgs);
masm.Push(output.valueReg());
masm.Push(scratchVal2);
masm.Push(scratch);
using Fn = bool (*)(JSContext*, HandleObject, HandleValue, HandleValue,
MutableHandleValue);
callVM<Fn, CheckProxyGetByValueResult>(masm);
masm.storeCallResultValue(output);
masm.jump(&end);
masm.bind(&success);
masm.setFramePushed(framePushedAfterCall);
// Restore the frame pointer and stack pointer.
masm.loadPtr(Address(FramePointer, 0), FramePointer);
masm.freeStack(masm.framePushed() - framePushedBefore);
masm.bind(&end);
return true;
}
bool IonCacheIRCompiler::emitCallScriptedProxyGetResult(
ValOperandId targetId, ObjOperandId receiverId, ObjOperandId handlerId,
uint32_t trapOffset, uint32_t id, uint32_t nargsAndFlags) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
return emitCallScriptedProxyGetShared(targetId, receiverId, handlerId,
trapOffset, id);
}
bool IonCacheIRCompiler::emitCallScriptedProxyGetByValueResult(
ValOperandId targetId, ObjOperandId receiverId, ObjOperandId handlerId,
ValOperandId idId, uint32_t trapOffset, uint32_t nargsAndFlags) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
return emitCallScriptedProxyGetShared(targetId, receiverId, handlerId,
trapOffset, idId);
}
#endif
bool IonCacheIRCompiler::emitCallInlinedGetterResult(
ValOperandId receiverId, uint32_t getterOffset, uint32_t icScriptOffset,
bool sameRealm, uint32_t nargsAndFlagsOffset) {

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

@ -53,6 +53,7 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler {
#endif
IonICPerfSpewer& perfSpewer() { return perfSpewer_; }
uint8_t localTracingSlots() const { return localTracingSlots_; }
private:
const CacheIRWriter& writer_;
@ -64,6 +65,7 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler {
mozilla::Maybe<CodeOffset> stubJitCodeOffset_;
bool savedLiveRegs_;
uint8_t localTracingSlots_;
IonICPerfSpewer perfSpewer_;
@ -74,6 +76,9 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler {
T rawInt64StubField(uint32_t offset);
void enterStubFrame(MacroAssembler& masm, const AutoSaveLiveRegisters&);
void storeTracedValue(MacroAssembler& masm, ValueOperand value);
void loadTracedValue(MacroAssembler& masm, uint8_t slotIndex,
ValueOperand value);
template <typename Fn, Fn fn>
void callVM(MacroAssembler& masm);
@ -82,6 +87,13 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler {
CacheOp op, ObjOperandId objId, uint32_t offsetOffset, ValOperandId rhsId,
uint32_t newShapeOffset, mozilla::Maybe<uint32_t> numNewSlotsOffset);
template <typename IdType>
[[nodiscard]] bool emitCallScriptedProxyGetShared(ValOperandId targetId,
ObjOperandId receiverId,
ObjOperandId handlerId,
uint32_t trapOffset,
IdType id);
void pushStubCodePointer();
CACHE_IR_COMPILER_UNSHARED_GENERATED

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

@ -1145,7 +1145,8 @@ static void TraceIonICCallFrame(JSTracer* trc, const JSJitFrameIter& frame) {
TraceRoot(trc, layout->stubCode(), "ion-ic-call-code");
for (int i = 0; i < (*layout->stubCode())->localTracingSlots(); ++i) {
TraceRoot(trc, layout->locallyTracedValuePtr(i), "TODO");
TraceRoot(trc, layout->locallyTracedValuePtr(i),
"ion-ic-local-tracing-slot");
}
}

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

@ -1976,6 +1976,29 @@
num_temps: 1
mir_op: ClampToUint8
- name: LoadScriptedProxyHandler
result_type: WordSized
operands:
object: WordSized
mir_op: true
#ifdef JS_PUNBOX64
- name: CheckScriptedProxyGetResult
operands:
target: BoxedValue
id: BoxedValue
value: BoxedValue
num_temps: 2
mir_op: true
#endif
- name: IdToStringOrSymbol
result_type: BoxedValue
operands:
id: BoxedValue
num_temps: 1
mir_op: true
# Load a boxed value from an object's fixed slot.
- name: LoadFixedSlotV
result_type: BoxedValue
@ -2696,6 +2719,11 @@
object: WordSized
num_temps: 1
- name: GuardHasProxyHandler
operands:
object: WordSized
mir_op: true
- name: GuardNoDenseElements
operands:
in: WordSized

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

@ -4422,6 +4422,21 @@ void LIRGenerator::visitStoreTypedArrayElementHole(
}
}
void LIRGenerator::visitLoadScriptedProxyHandler(
MLoadScriptedProxyHandler* ins) {
LLoadScriptedProxyHandler* lir = new (alloc())
LLoadScriptedProxyHandler(useRegisterAtStart(ins->object()));
define(lir, ins);
}
void LIRGenerator::visitIdToStringOrSymbol(MIdToStringOrSymbol* ins) {
LIdToStringOrSymbol* lir =
new (alloc()) LIdToStringOrSymbol(useBoxAtStart(ins->idVal()), temp());
assignSnapshot(lir, ins->bailoutKind());
defineBox(lir, ins);
assignSafepoint(lir, ins);
}
void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins) {
MDefinition* obj = ins->object();
MOZ_ASSERT(obj->type() == MIRType::Object);
@ -4907,6 +4922,15 @@ void LIRGenerator::visitGuardIsTypedArray(MGuardIsTypedArray* ins) {
redefine(ins, ins->object());
}
void LIRGenerator::visitGuardHasProxyHandler(MGuardHasProxyHandler* ins) {
MOZ_ASSERT(ins->object()->type() == MIRType::Object);
auto* lir = new (alloc()) LGuardHasProxyHandler(useRegister(ins->object()));
assignSnapshot(lir, ins->bailoutKind());
add(lir, ins);
redefine(ins, ins->object());
}
void LIRGenerator::visitNurseryObject(MNurseryObject* ins) {
MOZ_ASSERT(ins->type() == MIRType::Object);
@ -6112,6 +6136,21 @@ void LIRGenerator::visitCheckIsObj(MCheckIsObj* ins) {
assignSafepoint(lir, ins);
}
#ifdef JS_PUNBOX64
void LIRGenerator::visitCheckScriptedProxyGetResult(
MCheckScriptedProxyGetResult* ins) {
MDefinition* target = ins->target();
MDefinition* id = ins->id();
MDefinition* value = ins->value();
LCheckScriptedProxyGetResult* lir =
new (alloc()) LCheckScriptedProxyGetResult(useBox(target), useBox(id),
useBox(value), temp(), temp());
add(lir, ins);
assignSafepoint(lir, ins);
}
#endif
void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins) {
MDefinition* checkVal = ins->checkValue();
MOZ_ASSERT(checkVal->type() == MIRType::Value);

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

@ -3416,6 +3416,17 @@ AliasSet MGuardArgumentsObjectFlags::getAliasSet() const {
return AliasSet::Load(AliasSet::FixedSlot);
}
MDefinition* MIdToStringOrSymbol::foldsTo(TempAllocator& alloc) {
if (idVal()->isBox()) {
MIRType idType = idVal()->toBox()->input()->type();
if (idType == MIRType::String || idType == MIRType::Symbol) {
return idVal();
}
}
return this;
}
MDefinition* MReturnFromCtor::foldsTo(TempAllocator& alloc) {
MDefinition* rval = value();
if (rval->isBox()) {

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

@ -522,6 +522,31 @@
# The flags are packed with the length in a fixed private slot.
alias_set: custom
- name: LoadScriptedProxyHandler
operands:
object: Object
result_type: Object
congruent_to: if_operands_equal
alias_set: none
#ifdef JS_PUNBOX64
- name: CheckScriptedProxyGetResult
operands:
target: Value
id: Value
value: Value
guard: true
alias_set: none
#endif
- name: IdToStringOrSymbol
operands:
idVal: Value
result_type: Value
congruent_to: if_operands_equal
alias_set: none
folds_to: custom
# Given a MIRType::Value A and a MIRType::Object B:
# If the Value may be safely unboxed to an Object, return Object(A).
# Otherwise, return B.
@ -1732,6 +1757,17 @@
congruent_to: if_operands_equal
alias_set: none
- name: GuardHasProxyHandler
operands:
object: Object
arguments:
handler: const void*
result_type: Object
guard: true
movable: true
congruent_to: if_operands_equal
alias_set: none
# Loads a specific JSObject* that was originally nursery-allocated.
# See also WarpObjectField.
- name: NurseryObject

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

@ -1081,6 +1081,7 @@ bool ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
_(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>>) \
_(MixPolicy<StringPolicy<0>, StringPolicy<1>>) \
_(MixPolicy<BoxPolicy<0>, BoxPolicy<1>>) \
_(MixPolicy<BoxPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>) \
_(MixPolicy<ObjectPolicy<0>, BoxPolicy<2>, ObjectPolicy<3>>) \
_(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, ObjectPolicy<1>>) \
_(MixPolicy<UnboxedInt32Policy<0>, BigIntPolicy<1>>) \

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

@ -112,6 +112,20 @@ class MOZ_STACK_CLASS CallInfo {
setCallee(callee);
setThis(thisVal);
}
void initForProxyGet(MDefinition* callee, MDefinition* handler,
MDefinition* target, MDefinition* id,
MDefinition* receiver) {
MOZ_ASSERT(args_.empty());
setCallee(callee);
setThis(handler);
static_assert(decltype(args_)::InlineLength >= 3,
"Appending three arguments should be infallible");
MOZ_ALWAYS_TRUE(args_.append(target));
MOZ_ALWAYS_TRUE(args_.append(id));
MOZ_ALWAYS_TRUE(args_.append(receiver));
}
void initForSetterCall(MDefinition* callee, MDefinition* thisVal,
MDefinition* rhs) {
MOZ_ASSERT(args_.empty());

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

@ -295,6 +295,12 @@ class MOZ_RAII WarpCacheIRTranspiler : public WarpBuilderShared {
bool sameRealm,
uint32_t nargsAndFlagsOffset);
#ifndef JS_CODEGEN_X86
[[nodiscard]] bool emitCallScriptedProxyGetShared(
MDefinition* target, MDefinition* receiver, MDefinition* handler,
MDefinition* id, MDefinition* trapDef, WrappedFunction* trap);
#endif
CACHE_IR_TRANSPILER_GENERATED
public:
@ -791,6 +797,18 @@ bool WarpCacheIRTranspiler::emitGuardIsTypedArray(ObjOperandId objId) {
return true;
}
bool WarpCacheIRTranspiler::emitGuardHasProxyHandler(ObjOperandId objId,
uint32_t handlerOffset) {
MDefinition* obj = getOperand(objId);
const void* handler = rawPointerField(handlerOffset);
auto* ins = MGuardHasProxyHandler::New(alloc(), obj, handler);
add(ins);
setOperand(objId, ins);
return true;
}
bool WarpCacheIRTranspiler::emitGuardProto(ObjOperandId objId,
uint32_t protoOffset) {
MDefinition* def = getOperand(objId);
@ -894,6 +912,26 @@ bool WarpCacheIRTranspiler::emitGuardDynamicSlotValue(ObjOperandId objId,
return true;
}
bool WarpCacheIRTranspiler::emitLoadScriptedProxyHandler(ObjOperandId resultId,
ObjOperandId objId) {
MDefinition* obj = getOperand(objId);
auto* load = MLoadScriptedProxyHandler::New(alloc(), obj);
add(load);
return defineOperand(resultId, load);
}
bool WarpCacheIRTranspiler::emitIdToStringOrSymbol(ValOperandId resultId,
ValOperandId idId) {
MDefinition* id = getOperand(idId);
auto* ins = MIdToStringOrSymbol::New(alloc(), id);
add(ins);
return defineOperand(resultId, ins);
}
bool WarpCacheIRTranspiler::emitGuardSpecificAtom(StringOperandId strId,
uint32_t expectedOffset) {
MDefinition* str = getOperand(strId);
@ -5104,6 +5142,80 @@ bool WarpCacheIRTranspiler::emitCallInlinedFunction(ObjOperandId calleeId,
CallKind::Scripted);
}
#ifdef JS_PUNBOX64
bool WarpCacheIRTranspiler::emitCallScriptedProxyGetShared(
MDefinition* target, MDefinition* receiver, MDefinition* handler,
MDefinition* id, MDefinition* trapDef, WrappedFunction* trap) {
CallInfo callInfo(alloc(), /* constructing = */ false,
/* ignoresRval = */ false);
callInfo.initForProxyGet(trapDef, handler, target, id, receiver);
MCall* call = makeCall(callInfo, /* needsThisCheck = */ false, trap);
if (!call) {
return false;
}
addEffectful(call);
if (!current->ensureHasSlots(3)) {
return false;
}
current->push(call);
current->push(id);
current->push(target);
MResumePoint* resumePoint =
MResumePoint::New(alloc(), current, loc_.toRawBytecode(),
ResumeMode::ResumeAfterCheckProxyGetResult);
if (!resumePoint) {
return false;
}
call->setResumePoint(resumePoint);
current->pop();
current->pop();
MCheckScriptedProxyGetResult* check =
MCheckScriptedProxyGetResult::New(alloc(), target, id, call);
add(check);
return true;
}
bool WarpCacheIRTranspiler::emitCallScriptedProxyGetResult(
ValOperandId targetId, ObjOperandId receiverId, ObjOperandId handlerId,
uint32_t trapOffset, uint32_t idOffset, uint32_t nargsAndFlags) {
MDefinition* target = getOperand(targetId);
MDefinition* receiver = getOperand(receiverId);
MDefinition* handler = getOperand(handlerId);
MDefinition* trap = objectStubField(trapOffset);
jsid id = idStubField(idOffset);
MDefinition* idDef = constant(StringValue(id.toAtom()));
uint16_t nargs = nargsAndFlags >> 16;
FunctionFlags flags = FunctionFlags(uint16_t(nargsAndFlags));
WrappedFunction* wrappedTarget =
maybeWrappedFunction(trap, CallKind::Scripted, nargs, flags);
return emitCallScriptedProxyGetShared(target, receiver, handler, idDef, trap,
wrappedTarget);
}
bool WarpCacheIRTranspiler::emitCallScriptedProxyGetByValueResult(
ValOperandId targetId, ObjOperandId receiverId, ObjOperandId handlerId,
ValOperandId idId, uint32_t trapOffset, uint32_t nargsAndFlags) {
MDefinition* target = getOperand(targetId);
MDefinition* receiver = getOperand(receiverId);
MDefinition* handler = getOperand(handlerId);
MDefinition* trap = objectStubField(trapOffset);
MDefinition* idDef = getOperand(idId);
uint16_t nargs = nargsAndFlags >> 16;
FunctionFlags flags = FunctionFlags(uint16_t(nargsAndFlags));
WrappedFunction* wrappedTarget =
maybeWrappedFunction(trap, CallKind::Scripted, nargs, flags);
return emitCallScriptedProxyGetShared(target, receiver, handler, idDef, trap,
wrappedTarget);
}
#endif
bool WarpCacheIRTranspiler::emitCallClassHook(ObjOperandId calleeId,
Int32OperandId argcId,
CallFlags flags,

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

@ -1239,12 +1239,7 @@ static PropertyFlags ComputePropertyFlags(const PropertyDescriptor& desc) {
flags.setFlag(PropertyFlag::Writable, desc.writable());
} else {
MOZ_ASSERT(desc.isAccessorDescriptor());
if (desc.hasGetter()) {
flags.setFlag(PropertyFlag::HasGetter);
}
if (desc.hasSetter()) {
flags.setFlag(PropertyFlag::HasSetter);
}
flags.setFlag(PropertyFlag::AccessorProperty);
}
return flags;

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

@ -42,10 +42,13 @@ GetObjectFlagsForNewProperty(const JSClass* clasp, ObjectFlags flags, jsid id,
// JIT.
if (propFlags.isDataProperty() && !propFlags.writable()) {
flags.setFlag(ObjectFlag::NeedsProxyGetSetResultValidation);
} else if (propFlags.hasGetter() != propFlags.hasSetter()) {
} else if (propFlags.isAccessorProperty()) {
// This will cover us for both get trap validation and set trap
// validation. We could be more aggressive and have one flag for each,
// since their requirements are inverted, but this should be fine.
// validation. We could be more aggressive, because what we really
// care about is if there is a getter but not a setter and vice
// versa, but the first pass at doing that resulted in test
// failures. We'll need to work on that as a follow-up if it is
// important.
flags.setFlag(ObjectFlag::NeedsProxyGetSetResultValidation);
}
}
@ -71,6 +74,9 @@ inline ObjectFlags CopyPropMapObjectFlags(ObjectFlags dest,
if (source.hasFlag(ObjectFlag::HasNonWritableOrAccessorPropExclProto)) {
dest.setFlag(ObjectFlag::HasNonWritableOrAccessorPropExclProto);
}
if (source.hasFlag(ObjectFlag::NeedsProxyGetSetResultValidation)) {
dest.setFlag(ObjectFlag::NeedsProxyGetSetResultValidation);
}
return dest;
}

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

@ -1094,8 +1094,7 @@ void PropMap::dump(js::GenericPrinter& out) const {
dumpFlag(PropertyFlag::Enumerable, "enumerable");
dumpFlag(PropertyFlag::Configurable, "configurable");
dumpFlag(PropertyFlag::Writable, "writable");
dumpFlag(PropertyFlag::HasGetter, "hasGetter");
dumpFlag(PropertyFlag::HasSetter, "hasSetter");
dumpFlag(PropertyFlag::AccessorProperty, "accessor");
dumpFlag(PropertyFlag::CustomDataProperty, "custom-data");
out.putChar(')');
}

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

@ -32,11 +32,9 @@ enum class PropertyFlag : uint8_t {
Enumerable = 1 << 1,
Writable = 1 << 2,
// Whether this property is an accessor property and has a getter
HasGetter = 1 << 3,
// Whether this property is an accessor property and has a setter
HasSetter = 1 << 4,
// Whether this is an accessor property. Accessor properties have a slot that
// stores a GetterSetter instance.
AccessorProperty = 1 << 3,
// If set, this is a custom data property. The property is exposed as a data
// property to JS code and PropertyDescriptor, but instead of an object slot
@ -46,7 +44,7 @@ enum class PropertyFlag : uint8_t {
// properties.
//
// This flag is deprecated (we don't want to add more uses).
CustomDataProperty = 1 << 5,
CustomDataProperty = 1 << 4,
};
class PropertyFlags : public EnumFlags<PropertyFlag> {
@ -70,9 +68,9 @@ class PropertyFlags : public EnumFlags<PropertyFlag> {
bool isDataProperty() const {
return !isAccessorProperty() && !isCustomDataProperty();
}
bool isAccessorProperty() const { return hasGetter() || hasSetter(); }
bool hasGetter() const { return hasFlag(PropertyFlag::HasGetter); }
bool hasSetter() const { return hasFlag(PropertyFlag::HasSetter); }
bool isAccessorProperty() const {
return hasFlag(PropertyFlag::AccessorProperty);
}
bool isCustomDataProperty() const {
return hasFlag(PropertyFlag::CustomDataProperty);
}