Bug 1338828 part 1 - Add CacheIR SetProp/SetElem stubs for proxies. r=h4writer

This commit is contained in:
Jan de Mooij 2017-02-21 13:48:44 +01:00
Родитель f9bc8c7133
Коммит 71aecda25d
7 изменённых файлов: 205 добавлений и 11 удалений

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

@ -1505,6 +1505,79 @@ BaselineCacheIRCompiler::emitCallSetArrayLength()
return true;
}
typedef bool (*ProxySetPropertyFn)(JSContext*, HandleObject, HandleId, HandleValue, bool);
static const VMFunction ProxySetPropertyInfo =
FunctionInfo<ProxySetPropertyFn>(ProxySetProperty, "ProxySetProperty");
bool
BaselineCacheIRCompiler::emitCallProxySet()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
Address idAddr(stubAddress(reader.stubOffset()));
bool strict = reader.readBool();
AutoScratchRegister scratch(allocator, masm);
allocator.discardStack(masm);
AutoStubFrame stubFrame(*this);
stubFrame.enter(masm, scratch);
// Load the jsid in the scratch register.
masm.loadPtr(idAddr, scratch);
masm.Push(Imm32(strict));
masm.Push(val);
masm.Push(scratch);
masm.Push(obj);
if (!callVM(masm, ProxySetPropertyInfo))
return false;
stubFrame.leave(masm);
return true;
}
typedef bool (*ProxySetPropertyByValueFn)(JSContext*, HandleObject, HandleValue, HandleValue, bool);
static const VMFunction ProxySetPropertyByValueInfo =
FunctionInfo<ProxySetPropertyByValueFn>(ProxySetPropertyByValue, "ProxySetPropertyByValue");
bool
BaselineCacheIRCompiler::emitCallProxySetByValue()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
bool strict = reader.readBool();
allocator.discardStack(masm);
// We need a scratch register but we don't have any registers available on
// x86, so temporarily store |obj| in the frame's scratch slot.
int scratchOffset = BaselineFrame::reverseOffsetOfScratchValue();
masm.storePtr(obj, Address(BaselineFrameReg, scratchOffset));
AutoStubFrame stubFrame(*this);
stubFrame.enter(masm, obj);
// Restore |obj|. Because we entered a stub frame we first have to load
// the original frame pointer.
masm.loadPtr(Address(BaselineFrameReg, 0), obj);
masm.loadPtr(Address(obj, scratchOffset), obj);
masm.Push(Imm32(strict));
masm.Push(val);
masm.Push(idVal);
masm.Push(obj);
if (!callVM(masm, ProxySetPropertyByValueInfo))
return false;
stubFrame.leave(masm);
return true;
}
bool
BaselineCacheIRCompiler::emitTypeMonitorResult()
{

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

@ -1447,7 +1447,6 @@ SetPropIRGenerator::maybeEmitIdGuard(jsid id)
emitIdGuard(setElemKeyValueId(), id);
}
GetNameIRGenerator::GetNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
HandleObject env, HandlePropertyName name)
: IRGenerator(cx, script, pc, CacheKind::GetName),
@ -1904,9 +1903,14 @@ SetPropIRGenerator::tryAttachStub()
return true;
if (tryAttachSetArrayLength(obj, objId, id, rhsValId))
return true;
if (tryAttachProxy(obj, objId, id, rhsValId))
return true;
return false;
}
if (tryAttachProxyElement(obj, objId, rhsValId))
return true;
uint32_t index;
Int32OperandId indexId;
if (maybeGuardInt32Index(idVal_, setElemKeyValueId(), &index, &indexId)) {
@ -2506,6 +2510,69 @@ SetPropIRGenerator::tryAttachSetUnboxedArrayElementHole(HandleObject obj, ObjOpe
return true;
}
bool
SetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id,
ValOperandId rhsId)
{
MOZ_ASSERT(obj->is<ProxyObject>());
writer.guardIsProxy(objId);
// Ensure that the incoming object is not a DOM proxy, so that we can get to
// the specialized stubs
writer.guardNotDOMProxy(objId);
if (cacheKind_ == CacheKind::SetProp) {
writer.callProxySet(objId, id, rhsId, IsStrictSetPC(pc_));
} else {
// We could call maybeEmitIdGuard here and then emit CallProxySet, but
// for SetElem we prefer to attach a stub that can handle any Value
// so we don't attach a new stub for every id.
MOZ_ASSERT(cacheKind_ == CacheKind::SetElem);
writer.callProxySetByValue(objId, setElemKeyValueId(), rhsId, IsStrictSetPC(pc_));
}
writer.returnFromIC();
trackAttached("GenericProxy");
return true;
}
bool
SetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id,
ValOperandId rhsId)
{
switch (GetProxyStubType(cx_, obj, id)) {
case ProxyStubType::None:
return false;
case ProxyStubType::DOMExpando:
case ProxyStubType::DOMShadowed:
case ProxyStubType::DOMUnshadowed:
case ProxyStubType::Generic:
return tryAttachGenericProxy(obj, objId, id, rhsId);
}
MOZ_CRASH("Unexpected ProxyStubType");
}
bool
SetPropIRGenerator::tryAttachProxyElement(HandleObject obj, ObjOperandId objId, ValOperandId rhsId)
{
if (!obj->is<ProxyObject>())
return false;
writer.guardIsProxy(objId);
// Like GetPropIRGenerator::tryAttachProxyElement, don't check for DOM
// proxies here as we don't have specialized DOM stubs for this.
MOZ_ASSERT(cacheKind_ == CacheKind::SetElem);
writer.callProxySetByValue(objId, setElemKeyValueId(), rhsId, IsStrictSetPC(pc_));
writer.returnFromIC();
trackAttached("ProxyElement");
return true;
}
bool
SetPropIRGenerator::tryAttachAddSlotStub(HandleObjectGroup oldGroup, HandleShape oldShape)
{

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

@ -195,6 +195,8 @@ extern const char* CacheKindNames[];
_(CallNativeSetter) \
_(CallScriptedSetter) \
_(CallSetArrayLength) \
_(CallProxySet) \
_(CallProxySetByValue) \
\
/* The *Result ops load a value into the cache's result register. */ \
_(LoadFixedSlotResult) \
@ -707,6 +709,18 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
buffer_.writeByte(uint32_t(strict));
writeOperandId(rhs);
}
void callProxySet(ObjOperandId obj, jsid id, ValOperandId rhs, bool strict) {
writeOpWithOperandId(CacheOp::CallProxySet, obj);
writeOperandId(rhs);
addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id);
buffer_.writeByte(uint32_t(strict));
}
void callProxySetByValue(ObjOperandId obj, ValOperandId id, ValOperandId rhs, bool strict) {
writeOpWithOperandId(CacheOp::CallProxySetByValue, obj);
writeOperandId(id);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(strict));
}
void loadBooleanResult(bool val) {
writeOp(CacheOp::LoadBooleanResult);
@ -1077,6 +1091,11 @@ class MOZ_RAII SetPropIRGenerator : public IRGenerator
bool tryAttachSetUnboxedArrayElementHole(HandleObject obj, ObjOperandId objId, uint32_t index,
Int32OperandId indexId, ValOperandId rhsId);
bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id,
ValOperandId rhsId);
bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId);
bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId, ValOperandId rhsId);
void trackAttached(const char* name);
public:

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

@ -933,6 +933,18 @@ IonCacheIRCompiler::emitCallSetArrayLength()
MOZ_CRASH("Baseline-specific op");
}
bool
IonCacheIRCompiler::emitCallProxySet()
{
MOZ_CRASH("Baseline-specific op");
}
bool
IonCacheIRCompiler::emitCallProxySetByValue()
{
MOZ_CRASH("Baseline-specific op");
}
bool
IonCacheIRCompiler::emitLoadTypedObjectResult()
{

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

@ -1440,15 +1440,6 @@ EmitObjectOpResultCheck(MacroAssembler& masm, Label* failure, bool strict,
masm.bind(&noStrictError);
}
static bool
ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, bool strict)
{
RootedValue receiver(cx, ObjectValue(*proxy));
ObjectOpResult result;
return Proxy::set(cx, proxy, id, v, receiver, result)
&& result.checkStrictErrorOrWarning(cx, proxy, id, strict);
}
static bool
EmitCallProxySet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher,
HandleId propId, LiveRegisterSet liveRegs, Register object,

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

@ -354,6 +354,31 @@ Proxy::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, Handle
return handler->set(cx, proxy, id, v, receiver, result);
}
bool
js::ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, HandleValue val, bool strict)
{
ObjectOpResult result;
RootedValue receiver(cx, ObjectValue(*proxy));
if (!Proxy::set(cx, proxy, id, val, receiver, result))
return false;
return result.checkStrictErrorOrWarning(cx, proxy, id, strict);
}
bool
js::ProxySetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal, HandleValue val,
bool strict)
{
RootedId id(cx);
if (!ValueToId<CanGC>(cx, idVal, &id))
return false;
ObjectOpResult result;
RootedValue receiver(cx, ObjectValue(*proxy));
if (!Proxy::set(cx, proxy, id, val, receiver, result))
return false;
return result.checkStrictErrorOrWarning(cx, proxy, id, strict);
}
bool
Proxy::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props)
{

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

@ -79,7 +79,7 @@ proxy_Call(JSContext* cx, unsigned argc, Value* vp);
bool
proxy_Construct(JSContext* cx, unsigned argc, Value* vp);
// These two functions are used by JIT code
// These functions are used by JIT code
bool
ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp);
@ -88,6 +88,13 @@ bool
ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal,
MutableHandleValue vp);
bool
ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, HandleValue val, bool strict);
bool
ProxySetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal, HandleValue val,
bool strict);
} /* namespace js */
#endif /* proxy_Proxy_h */