Bug 1357468 - More Object.hasOwnProperty optimizations for Speedometer. r=jandem

- IC support dense elements, like [0].hasOwnProperty("0")
- IC support unboxed objects
- IC support proxies, i.e. NodeList or other DOM proxies mostly
This commit is contained in:
Tom Schuster 2017-04-18 18:56:25 +02:00
Родитель 58b4255414
Коммит 9d47f2ea8d
7 изменённых файлов: 138 добавлений и 6 удалений

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

@ -672,6 +672,32 @@ BaselineCacheIRCompiler::emitCallProxyGetByValueResult()
return true;
}
typedef bool (*ProxyHasOwnFn)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
static const VMFunction ProxyHasOwnInfo = FunctionInfo<ProxyHasOwnFn>(ProxyHasOwn, "ProxyHasOwn");
bool
BaselineCacheIRCompiler::emitCallProxyHasOwnResult()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
AutoScratchRegister scratch(allocator, masm);
allocator.discardStack(masm);
AutoStubFrame stubFrame(*this);
stubFrame.enter(masm, scratch);
masm.Push(idVal);
masm.Push(obj);
if (!callVM(masm, ProxyHasOwnInfo))
return false;
stubFrame.leave(masm);
return true;
}
bool
BaselineCacheIRCompiler::emitLoadUnboxedPropertyResult()
{

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

@ -2159,7 +2159,10 @@ HasOwnIRGenerator::tryAttachNativeHasOwn(HandleId key, ValOperandId keyId,
if (!LookupOwnPropertyPure(cx_, obj, key, &prop))
return false;
if (!prop.isNativeProperty())
if (!prop.isFound())
return false;
if (!obj->isNative() && !obj->is<UnboxedPlainObject>())
return false;
if (mode_ == ICState::Mode::Megamorphic) {
@ -2169,9 +2172,9 @@ HasOwnIRGenerator::tryAttachNativeHasOwn(HandleId key, ValOperandId keyId,
return true;
}
Maybe<ObjOperandId> holderId;
Maybe<ObjOperandId> expandoId;
emitIdGuard(keyId, key);
EmitReadSlotGuard(writer, obj, obj, prop.shape(), objId, &holderId);
TestMatchingReceiver(writer, obj, nullptr, objId, &expandoId);
writer.loadBooleanResult(true);
writer.returnFromIC();
@ -2203,6 +2206,37 @@ HasOwnIRGenerator::tryAttachNativeHasOwnDoesNotExist(HandleId key, ValOperandId
return true;
}
bool
HasOwnIRGenerator::tryAttachProxyElement(ValOperandId keyId, HandleObject obj, ObjOperandId objId)
{
if (!obj->is<ProxyObject>())
return false;
writer.guardIsProxy(objId);
writer.callProxyHasOwnResult(objId, keyId);
writer.returnFromIC();
trackAttached("ProxyHasOwn");
return true;
}
bool
HasOwnIRGenerator::tryAttachDenseHasOwn(uint32_t index, Int32OperandId indexId,
HandleObject obj, ObjOperandId objId)
{
if (!obj->isNative())
return false;
if (!obj->as<NativeObject>().containsDenseElement(index))
return false;
writer.guardShape(objId, obj->as<NativeObject>().lastProperty());
writer.loadDenseElementExistsResult(objId, indexId);
writer.returnFromIC();
trackAttached("DenseHasOwn");
return true;
}
bool
HasOwnIRGenerator::tryAttachStub()
{
@ -2221,6 +2255,9 @@ HasOwnIRGenerator::tryAttachStub()
ObjOperandId objId = writer.guardIsObject(valId);
if (tryAttachProxyElement(keyId, obj, objId))
return true;
RootedId id(cx_);
bool nameOrSymbol;
if (!ValueToNameOrSymbolId(cx_, key_, &id, &nameOrSymbol)) {
@ -2238,6 +2275,16 @@ HasOwnIRGenerator::tryAttachStub()
return false;
}
uint32_t index;
Int32OperandId indexId;
if (maybeGuardInt32Index(key_, keyId, &index, &indexId)) {
if (tryAttachDenseHasOwn(index, indexId, obj, objId))
return true;
trackNotAttached();
return false;
}
trackNotAttached();
return false;
}

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

@ -242,6 +242,7 @@ extern const char* CacheKindNames[];
_(CallNativeGetterResult) \
_(CallProxyGetResult) \
_(CallProxyGetByValueResult) \
_(CallProxyHasOwnResult) \
_(LoadUndefinedResult) \
_(LoadBooleanResult) \
\
@ -885,6 +886,10 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
writeOpWithOperandId(CacheOp::CallProxyGetByValueResult, obj);
writeOperandId(idVal);
}
void callProxyHasOwnResult(ObjOperandId obj, ValOperandId idVal) {
writeOpWithOperandId(CacheOp::CallProxyHasOwnResult, obj);
writeOperandId(idVal);
}
void loadEnvironmentFixedSlotResult(ObjOperandId obj, size_t offset) {
writeOpWithOperandId(CacheOp::LoadEnvironmentFixedSlotResult, obj);
addStubField(offset, StubField::Type::RawWord);
@ -1286,6 +1291,9 @@ class MOZ_RAII HasOwnIRGenerator : public IRGenerator
HandleValue key_;
HandleValue val_;
bool tryAttachProxyElement(ValOperandId keyId, HandleObject obj, ObjOperandId objId);
bool tryAttachDenseHasOwn(uint32_t index, Int32OperandId indexId,
HandleObject obj, ObjOperandId objId);
bool tryAttachNativeHasOwn(HandleId key, ValOperandId keyId,
HandleObject obj, ObjOperandId objId);
bool tryAttachNativeHasOwnDoesNotExist(HandleId key, ValOperandId keyId,

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

@ -1040,6 +1040,33 @@ IonCacheIRCompiler::emitCallProxyGetByValueResult()
return true;
}
typedef bool (*ProxyHasOwnFn)(JSContext*, HandleObject, HandleValue, MutableHandleValue);
static const VMFunction ProxyHasOwnInfo = FunctionInfo<ProxyHasOwnFn>(ProxyHasOwn, "ProxyHasOwn");
bool
IonCacheIRCompiler::emitCallProxyHasOwnResult()
{
AutoSaveLiveRegisters save(*this);
AutoOutputRegister output(*this);
Register obj = allocator.useRegister(masm, reader.objOperandId());
ValueOperand idVal = allocator.useValueRegister(masm, reader.valOperandId());
allocator.discardStack(masm);
prepareVMCall(masm);
masm.Push(idVal);
masm.Push(obj);
if (!callVM(masm, ProxyHasOwnInfo))
return false;
masm.storeCallResultValue(output);
return true;
}
bool
IonCacheIRCompiler::emitLoadUnboxedPropertyResult()
{

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

@ -1740,15 +1740,21 @@ HasOwnNativeDataProperty(JSContext* cx, JSObject* obj, Value* vp)
{
JS::AutoCheckCannotGC nogc;
if (MOZ_UNLIKELY(!obj->isNative()))
return false;
// vp[0] contains the id, result will be stored in vp[1].
Value idVal = vp[0];
jsid id;
if (!ValueToAtomOrSymbol(cx, idVal, &id))
return false;
if (!obj->isNative()) {
if (obj->is<UnboxedPlainObject>()) {
bool res = obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id);
vp[1].setBoolean(res);
return true;
}
return false;
}
NativeObject* nobj = &obj->as<NativeObject>();
if (nobj->lastProperty()->search(cx, id)) {
vp[1].setBoolean(true);

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

@ -284,6 +284,21 @@ Proxy::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
return handler->hasOwn(cx, proxy, id, bp);
}
bool
js::ProxyHasOwn(JSContext* cx, HandleObject proxy, HandleValue idVal, MutableHandleValue result)
{
RootedId id(cx);
if (!ValueToId<CanGC>(cx, idVal, &id))
return false;
bool hasOwn;
if (!Proxy::hasOwn(cx, proxy, id, &hasOwn))
return false;
result.setBoolean(hasOwn);
return true;
}
static Value
ValueToWindowProxyIfWindow(const Value& v)
{

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

@ -80,6 +80,9 @@ proxy_Construct(JSContext* cx, unsigned argc, Value* vp);
// These functions are used by JIT code
bool
ProxyHasOwn(JSContext* cx, HandleObject proxy, HandleValue idVal, MutableHandleValue result);
bool
ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp);