Bug 1359952 - Add HasPropIRGenerator r=jandem

This combines InIRGenerator with HasOwnIRGenerator.

MozReview-Commit-ID: 7FQX5YmVrM7

--HG--
extra : rebase_source : 9b0e735e303f6fa57d4407bec5b81bc8307d365a
This commit is contained in:
Ted Campbell 2017-04-27 12:11:17 -04:00
Родитель d561466341
Коммит 43e26a60a0
4 изменённых файлов: 111 добавлений и 230 удалений

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

@ -1208,8 +1208,6 @@ DoInFallback(JSContext* cx, BaselineFrame* frame, ICIn_Fallback* stub_,
return false; return false;
} }
RootedObject obj(cx, &objValue.toObject());
if (stub->state().maybeTransition()) if (stub->state().maybeTransition())
stub->discardStubs(cx); stub->discardStubs(cx);
@ -1218,7 +1216,7 @@ DoInFallback(JSContext* cx, BaselineFrame* frame, ICIn_Fallback* stub_,
jsbytecode* pc = stub->icEntry()->pc(script); jsbytecode* pc = stub->icEntry()->pc(script);
ICStubEngine engine = ICStubEngine::Baseline; ICStubEngine engine = ICStubEngine::Baseline;
InIRGenerator gen(cx, script, pc, stub->state().mode(), key, obj); HasPropIRGenerator gen(cx, script, pc, CacheKind::In, stub->state().mode(), key, objValue);
bool attached = false; bool attached = false;
if (gen.tryAttachStub()) { if (gen.tryAttachStub()) {
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
@ -1230,6 +1228,7 @@ DoInFallback(JSContext* cx, BaselineFrame* frame, ICIn_Fallback* stub_,
stub->state().trackNotAttached(); stub->state().trackNotAttached();
} }
RootedObject obj(cx, &objValue.toObject());
bool cond = false; bool cond = false;
if (!OperatorIn(cx, key, obj, &cond)) if (!OperatorIn(cx, key, obj, &cond))
return false; return false;
@ -1284,7 +1283,8 @@ DoHasOwnFallback(JSContext* cx, BaselineFrame* frame, ICHasOwn_Fallback* stub_,
jsbytecode* pc = stub->icEntry()->pc(script); jsbytecode* pc = stub->icEntry()->pc(script);
ICStubEngine engine = ICStubEngine::Baseline; ICStubEngine engine = ICStubEngine::Baseline;
HasOwnIRGenerator gen(cx, script, pc, stub->state().mode(), keyValue, objValue); HasPropIRGenerator gen(cx, script, pc, CacheKind::HasOwn,
stub->state().mode(), keyValue, objValue);
bool attached = false; bool attached = false;
if (gen.tryAttachStub()) { if (gen.tryAttachStub()) {
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),

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

@ -440,7 +440,7 @@ EmitReadSlotGuard(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
lastObjId = protoId; lastObjId = protoId;
} }
} }
} else if (obj->is<UnboxedPlainObject>()) { } else if (obj->is<UnboxedPlainObject>() && expandoId.isSome()) {
holderId->emplace(*expandoId); holderId->emplace(*expandoId);
} else { } else {
holderId->emplace(objId); holderId->emplace(objId);
@ -2056,232 +2056,144 @@ BindNameIRGenerator::trackNotAttached()
#endif #endif
} }
InIRGenerator::InIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, HasPropIRGenerator::HasPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
ICState::Mode mode, HandleValue key, HandleObject obj) CacheKind cacheKind, ICState::Mode mode,
: IRGenerator(cx, script, pc, CacheKind::In, mode), HandleValue idVal, HandleValue val)
key_(key), obj_(obj) : IRGenerator(cx, script, pc, cacheKind, mode),
val_(val),
idVal_(idVal)
{ } { }
bool bool
InIRGenerator::tryAttachDenseIn(uint32_t index, Int32OperandId indexId, HasPropIRGenerator::tryAttachDense(HandleObject obj, ObjOperandId objId,
HandleObject obj, ObjOperandId objId) uint32_t index, Int32OperandId indexId)
{ {
if (!obj->isNative()) if (!obj->isNative())
return false; return false;
if (!obj->as<NativeObject>().containsDenseElement(index)) if (!obj->as<NativeObject>().containsDenseElement(index))
return false; return false;
// Guard shape to ensure object class is NativeObject.
writer.guardShape(objId, obj->as<NativeObject>().lastProperty()); writer.guardShape(objId, obj->as<NativeObject>().lastProperty());
writer.loadDenseElementExistsResult(objId, indexId); writer.loadDenseElementExistsResult(objId, indexId);
writer.returnFromIC(); writer.returnFromIC();
trackAttached("DenseIn"); trackAttached("DenseHasProp");
return true; return true;
} }
bool bool
InIRGenerator::tryAttachDenseInHole(uint32_t index, Int32OperandId indexId, HasPropIRGenerator::tryAttachDenseHole(HandleObject obj, ObjOperandId objId,
HandleObject obj, ObjOperandId objId) uint32_t index, Int32OperandId indexId)
{ {
bool hasOwn = (cacheKind_ == CacheKind::HasOwn);
if (!obj->isNative()) if (!obj->isNative())
return false; return false;
if (obj->as<NativeObject>().containsDenseElement(index)) if (obj->as<NativeObject>().containsDenseElement(index))
return false; return false;
if (!CanAttachDenseElementHole(obj, hasOwn))
if (!CanAttachDenseElementHole(obj, false))
return false; return false;
// Guard on the shape, to prevent non-dense elements from appearing. // Guard shape to ensure class is NativeObject and to prevent non-dense
// elements being added. Also ensures prototype doesn't change if dynamic
// checks aren't emitted.
writer.guardShape(objId, obj->as<NativeObject>().lastProperty()); writer.guardShape(objId, obj->as<NativeObject>().lastProperty());
// Generate prototype guards if needed. This includes monitoring that
// properties were not added in the chain.
if (!hasOwn)
GeneratePrototypeHoleGuards(writer, obj, objId); GeneratePrototypeHoleGuards(writer, obj, objId);
writer.loadDenseElementHoleExistsResult(objId, indexId); writer.loadDenseElementHoleExistsResult(objId, indexId);
writer.returnFromIC(); writer.returnFromIC();
trackAttached("DenseInHole"); trackAttached("DenseHasPropHole");
return true; return true;
} }
bool bool
InIRGenerator::tryAttachNativeIn(HandleId key, ValOperandId keyId, HasPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId,
HandleObject obj, ObjOperandId objId) HandleId key, ValOperandId keyId)
{ {
bool hasOwn = (cacheKind_ == CacheKind::HasOwn);
JSObject* holder = nullptr;
PropertyResult prop; PropertyResult prop;
JSObject* holder;
if (!LookupPropertyPure(cx_, obj, key, &holder, &prop))
return false;
if (!prop.isNativeProperty()) if (hasOwn) {
return false;
Maybe<ObjOperandId> holderId;
emitIdGuard(keyId, key);
EmitReadSlotGuard(writer, obj, holder, objId, &holderId);
writer.loadBooleanResult(true);
writer.returnFromIC();
trackAttached("NativeIn");
return true;
}
bool
InIRGenerator::tryAttachNativeInDoesNotExist(HandleId key, ValOperandId keyId,
HandleObject obj, ObjOperandId objId)
{
if (!CheckHasNoSuchProperty(cx_, obj, key))
return false;
Maybe<ObjOperandId> holderId;
emitIdGuard(keyId, key);
EmitReadSlotGuard(writer, obj, nullptr, objId, &holderId);
writer.loadBooleanResult(false);
writer.returnFromIC();
trackAttached("NativeInDoesNotExist");
return true;
}
bool
InIRGenerator::tryAttachStub()
{
MOZ_ASSERT(cacheKind_ == CacheKind::In);
AutoAssertNoPendingException aanpe(cx_);
ValOperandId keyId(writer.setInputOperandId(0));
ValOperandId valId(writer.setInputOperandId(1));
ObjOperandId objId = writer.guardIsObject(valId);
RootedId id(cx_);
bool nameOrSymbol;
if (!ValueToNameOrSymbolId(cx_, key_, &id, &nameOrSymbol)) {
cx_->clearPendingException();
return false;
}
if (nameOrSymbol) {
if (tryAttachNativeIn(id, keyId, obj_, objId))
return true;
if (tryAttachNativeInDoesNotExist(id, keyId, obj_, objId))
return true;
trackNotAttached();
return false;
}
uint32_t index;
Int32OperandId indexId;
if (maybeGuardInt32Index(key_, keyId, &index, &indexId)) {
if (tryAttachDenseIn(index, indexId, obj_, objId))
return true;
if (tryAttachDenseInHole(index, indexId, obj_, objId))
return true;
trackNotAttached();
return false;
}
trackNotAttached();
return false;
}
void
InIRGenerator::trackAttached(const char* name)
{
#ifdef JS_CACHEIR_SPEW
CacheIRSpewer& sp = CacheIRSpewer::singleton();
if (sp.enabled()) {
LockGuard<Mutex> guard(sp.lock());
sp.beginCache(guard, *this);
sp.valueProperty(guard, "base", ObjectValue(*obj_));
sp.valueProperty(guard, "property", key_);
sp.attached(guard, name);
sp.endCache(guard);
}
#endif
}
void
InIRGenerator::trackNotAttached()
{
#ifdef JS_CACHEIR_SPEW
CacheIRSpewer& sp = CacheIRSpewer::singleton();
if (sp.enabled()) {
LockGuard<Mutex> guard(sp.lock());
sp.beginCache(guard, *this);
sp.valueProperty(guard, "base", ObjectValue(*obj_));
sp.valueProperty(guard, "property", key_);
sp.endCache(guard);
}
#endif
}
HasOwnIRGenerator::HasOwnIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
ICState::Mode mode, HandleValue key, HandleValue value)
: IRGenerator(cx, script, pc, CacheKind::HasOwn, mode),
key_(key), val_(value)
{ }
bool
HasOwnIRGenerator::tryAttachNativeHasOwn(HandleId key, ValOperandId keyId,
HandleObject obj, ObjOperandId objId)
{
PropertyResult prop;
if (!LookupOwnPropertyPure(cx_, obj, key, &prop)) if (!LookupOwnPropertyPure(cx_, obj, key, &prop))
return false; return false;
holder = obj;
} else {
if (!LookupPropertyPure(cx_, obj, key, &holder, &prop))
return false;
}
if (!prop.isFound()) if (!prop.isFound())
return false; return false;
if (!obj->isNative() && !obj->is<UnboxedPlainObject>()) // Use MegamorphicHasOwnResult if applicable
return false; if (hasOwn && mode_ == ICState::Mode::Megamorphic) {
if (mode_ == ICState::Mode::Megamorphic) {
writer.megamorphicHasOwnResult(objId, keyId); writer.megamorphicHasOwnResult(objId, keyId);
writer.returnFromIC(); writer.returnFromIC();
trackAttached("MegamorphicHasOwn"); trackAttached("MegamorphicHasProp");
return true; return true;
} }
Maybe<ObjOperandId> expandoId; Maybe<ObjOperandId> tempId;
emitIdGuard(keyId, key); emitIdGuard(keyId, key);
TestMatchingReceiver(writer, obj, objId, &expandoId); EmitReadSlotGuard(writer, obj, holder, objId, &tempId);
writer.loadBooleanResult(true); writer.loadBooleanResult(true);
writer.returnFromIC(); writer.returnFromIC();
trackAttached("NativeHasOwn"); trackAttached("NativeHasProp");
return true; return true;
} }
bool bool
HasOwnIRGenerator::tryAttachNativeHasOwnDoesNotExist(HandleId key, ValOperandId keyId, HasPropIRGenerator::tryAttachNativeDoesNotExist(HandleObject obj, ObjOperandId objId,
HandleObject obj, ObjOperandId objId) HandleId key, ValOperandId keyId)
{ {
bool hasOwn = (cacheKind_ == CacheKind::HasOwn);
if (hasOwn) {
if (!CheckHasNoSuchOwnProperty(cx_, obj, key)) if (!CheckHasNoSuchOwnProperty(cx_, obj, key))
return false; return false;
} else {
if (!CheckHasNoSuchProperty(cx_, obj, key))
return false;
}
if (mode_ == ICState::Mode::Megamorphic) { // Use MegamorphicHasOwnResult if applicable
if (hasOwn && mode_ == ICState::Mode::Megamorphic) {
writer.megamorphicHasOwnResult(objId, keyId); writer.megamorphicHasOwnResult(objId, keyId);
writer.returnFromIC(); writer.returnFromIC();
trackAttached("MegamorphicHasOwn"); trackAttached("MegamorphicHasOwn");
return true; return true;
} }
Maybe<ObjOperandId> expandoId; Maybe<ObjOperandId> tempId;
emitIdGuard(keyId, key); emitIdGuard(keyId, key);
TestMatchingReceiver(writer, obj, objId, &expandoId); if (hasOwn) {
TestMatchingReceiver(writer, obj, objId, &tempId);
} else {
EmitReadSlotGuard(writer, obj, nullptr, objId, &tempId);
}
writer.loadBooleanResult(false); writer.loadBooleanResult(false);
writer.returnFromIC(); writer.returnFromIC();
trackAttached("NativeHasOwnDoesNotExist"); trackAttached("NativeDoesNotExist");
return true; return true;
} }
bool bool
HasOwnIRGenerator::tryAttachProxyElement(ValOperandId keyId, HandleObject obj, ObjOperandId objId) HasPropIRGenerator::tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
ValOperandId keyId)
{ {
MOZ_ASSERT(cacheKind_ == CacheKind::HasOwn);
if (!obj->is<ProxyObject>()) if (!obj->is<ProxyObject>())
return false; return false;
@ -2289,34 +2201,19 @@ HasOwnIRGenerator::tryAttachProxyElement(ValOperandId keyId, HandleObject obj, O
writer.callProxyHasOwnResult(objId, keyId); writer.callProxyHasOwnResult(objId, keyId);
writer.returnFromIC(); writer.returnFromIC();
trackAttached("ProxyHasOwn"); trackAttached("ProxyHasProp");
return true; return true;
} }
bool bool
HasOwnIRGenerator::tryAttachDenseHasOwn(uint32_t index, Int32OperandId indexId, HasPropIRGenerator::tryAttachStub()
HandleObject obj, ObjOperandId objId)
{ {
if (!obj->isNative()) MOZ_ASSERT(cacheKind_ == CacheKind::In ||
return false; cacheKind_ == CacheKind::HasOwn);
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()
{
MOZ_ASSERT(cacheKind_ == CacheKind::HasOwn);
AutoAssertNoPendingException aanpe(cx_); AutoAssertNoPendingException aanpe(cx_);
// NOTE: Argument order is PROPERTY, OBJECT
ValOperandId keyId(writer.setInputOperandId(0)); ValOperandId keyId(writer.setInputOperandId(0));
ValOperandId valId(writer.setInputOperandId(1)); ValOperandId valId(writer.setInputOperandId(1));
@ -2325,23 +2222,25 @@ HasOwnIRGenerator::tryAttachStub()
return false; return false;
} }
RootedObject obj(cx_, &val_.toObject()); RootedObject obj(cx_, &val_.toObject());
ObjOperandId objId = writer.guardIsObject(valId); ObjOperandId objId = writer.guardIsObject(valId);
if (tryAttachProxyElement(keyId, obj, objId)) // Optimize DOM Proxies for JSOP_HASOWN
if (cacheKind_ == CacheKind::HasOwn) {
if (tryAttachProxyElement(obj, objId, keyId))
return true; return true;
}
RootedId id(cx_); RootedId id(cx_);
bool nameOrSymbol; bool nameOrSymbol;
if (!ValueToNameOrSymbolId(cx_, key_, &id, &nameOrSymbol)) { if (!ValueToNameOrSymbolId(cx_, idVal_, &id, &nameOrSymbol)) {
cx_->clearPendingException(); cx_->clearPendingException();
return false; return false;
} }
if (nameOrSymbol) { if (nameOrSymbol) {
if (tryAttachNativeHasOwn(id, keyId, obj, objId)) if (tryAttachNative(obj, objId, id, keyId))
return true; return true;
if (tryAttachNativeHasOwnDoesNotExist(id, keyId, obj, objId)) if (tryAttachNativeDoesNotExist(obj, objId, id, keyId))
return true; return true;
trackNotAttached(); trackNotAttached();
@ -2350,8 +2249,10 @@ HasOwnIRGenerator::tryAttachStub()
uint32_t index; uint32_t index;
Int32OperandId indexId; Int32OperandId indexId;
if (maybeGuardInt32Index(key_, keyId, &index, &indexId)) { if (maybeGuardInt32Index(idVal_, keyId, &index, &indexId)) {
if (tryAttachDenseHasOwn(index, indexId, obj, objId)) if (tryAttachDense(obj, objId, index, indexId))
return true;
if (tryAttachDenseHole(obj, objId, index, indexId))
return true; return true;
trackNotAttached(); trackNotAttached();
@ -2363,7 +2264,7 @@ HasOwnIRGenerator::tryAttachStub()
} }
void void
HasOwnIRGenerator::trackAttached(const char* name) HasPropIRGenerator::trackAttached(const char* name)
{ {
#ifdef JS_CACHEIR_SPEW #ifdef JS_CACHEIR_SPEW
CacheIRSpewer& sp = CacheIRSpewer::singleton(); CacheIRSpewer& sp = CacheIRSpewer::singleton();
@ -2371,7 +2272,7 @@ HasOwnIRGenerator::trackAttached(const char* name)
LockGuard<Mutex> guard(sp.lock()); LockGuard<Mutex> guard(sp.lock());
sp.beginCache(guard, *this); sp.beginCache(guard, *this);
sp.valueProperty(guard, "base", val_); sp.valueProperty(guard, "base", val_);
sp.valueProperty(guard, "property", key_); sp.valueProperty(guard, "property", idVal_);
sp.attached(guard, name); sp.attached(guard, name);
sp.endCache(guard); sp.endCache(guard);
} }
@ -2379,7 +2280,7 @@ HasOwnIRGenerator::trackAttached(const char* name)
} }
void void
HasOwnIRGenerator::trackNotAttached() HasPropIRGenerator::trackNotAttached()
{ {
#ifdef JS_CACHEIR_SPEW #ifdef JS_CACHEIR_SPEW
CacheIRSpewer& sp = CacheIRSpewer::singleton(); CacheIRSpewer& sp = CacheIRSpewer::singleton();
@ -2387,7 +2288,7 @@ HasOwnIRGenerator::trackNotAttached()
LockGuard<Mutex> guard(sp.lock()); LockGuard<Mutex> guard(sp.lock());
sp.beginCache(guard, *this); sp.beginCache(guard, *this);
sp.valueProperty(guard, "base", val_); sp.valueProperty(guard, "base", val_);
sp.valueProperty(guard, "property", key_); sp.valueProperty(guard, "property", idVal_);
sp.endCache(guard); sp.endCache(guard);
} }
#endif #endif

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

@ -1276,51 +1276,31 @@ class MOZ_RAII SetPropIRGenerator : public IRGenerator
} }
}; };
// InIRGenerator generates CacheIR for a In IC. // HasPropIRGenerator generates CacheIR for a HasProp IC. Used for
class MOZ_RAII InIRGenerator : public IRGenerator // CacheKind::In / CacheKind::HasOwn.
class MOZ_RAII HasPropIRGenerator : public IRGenerator
{ {
HandleValue key_;
HandleObject obj_;
bool tryAttachDenseIn(uint32_t index, Int32OperandId indexId,
HandleObject obj, ObjOperandId objId);
bool tryAttachDenseInHole(uint32_t index, Int32OperandId indexId,
HandleObject obj, ObjOperandId objId);
bool tryAttachNativeIn(HandleId key, ValOperandId keyId,
HandleObject obj, ObjOperandId objId);
bool tryAttachNativeInDoesNotExist(HandleId key, ValOperandId keyId,
HandleObject obj, ObjOperandId objId);
void trackAttached(const char* name);
void trackNotAttached();
public:
InIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode, HandleValue key,
HandleObject obj);
bool tryAttachStub();
};
// HasOwnIRGenerator generates CacheIR for a HasOwn IC.
class MOZ_RAII HasOwnIRGenerator : public IRGenerator
{
HandleValue key_;
HandleValue val_; HandleValue val_;
HandleValue idVal_;
bool tryAttachProxyElement(ValOperandId keyId, HandleObject obj, ObjOperandId objId); bool tryAttachDense(HandleObject obj, ObjOperandId objId,
bool tryAttachDenseHasOwn(uint32_t index, Int32OperandId indexId, uint32_t index, Int32OperandId indexId);
HandleObject obj, ObjOperandId objId); bool tryAttachDenseHole(HandleObject obj, ObjOperandId objId,
bool tryAttachNativeHasOwn(HandleId key, ValOperandId keyId, uint32_t index, Int32OperandId indexId);
HandleObject obj, ObjOperandId objId); bool tryAttachNative(HandleObject obj, ObjOperandId objId,
bool tryAttachNativeHasOwnDoesNotExist(HandleId key, ValOperandId keyId, HandleId key, ValOperandId keyId);
HandleObject obj, ObjOperandId objId); bool tryAttachNativeDoesNotExist(HandleObject obj, ObjOperandId objId,
HandleId key, ValOperandId keyId);
bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
ValOperandId keyId);
void trackAttached(const char* name); void trackAttached(const char* name);
void trackNotAttached(); void trackNotAttached();
public: public:
HasOwnIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode, HandleValue key, // NOTE: Argument order is PROPERTY, OBJECT
HandleValue value); HasPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
ICState::Mode mode, HandleValue idVal, HandleValue val);
bool tryAttachStub(); bool tryAttachStub();
}; };

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

@ -355,7 +355,7 @@ IonHasOwnIC::update(JSContext* cx, HandleScript outerScript, IonHasOwnIC* ic,
if (ic->state().canAttachStub()) { if (ic->state().canAttachStub()) {
bool attached = false; bool attached = false;
RootedScript script(cx, ic->script()); RootedScript script(cx, ic->script());
HasOwnIRGenerator gen(cx, script, pc, ic->state().mode(), idVal, val); HasPropIRGenerator gen(cx, script, pc, CacheKind::HasOwn, ic->state().mode(), idVal, val);
if (gen.tryAttachStub()) if (gen.tryAttachStub())
ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached); ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);