--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1902,56 +1902,16 @@ ICSetElem_TypedArray::Compiler::generate
return true;
}
//
// In_Fallback
//
static bool
-TryAttachNativeInStub(JSContext* cx, HandleScript outerScript, ICIn_Fallback* stub,
- HandleValue key, HandleObject obj, bool* attached)
-{
- MOZ_ASSERT(!*attached);
-
- RootedId id(cx);
- if (!IsOptimizableElementPropertyName(cx, key, &id))
- return true;
-
- RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
- Rooted<PropertyResult> prop(cx);
- RootedObject holder(cx);
- if (!LookupPropertyPure(cx, obj, id, holder.address(), prop.address()))
- return true;
-
- if (prop.isNonNativeProperty()) {
- MOZ_ASSERT(!IsCacheableProtoChain(obj, holder, false));
- return true;
- }
-
- RootedShape shape(cx, prop.maybeShape());
- if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
- ICStub::Kind kind = (obj == holder) ? ICStub::In_Native
- : ICStub::In_NativePrototype;
- JitSpew(JitSpew_BaselineIC, " Generating In(Native %s) stub",
- (obj == holder) ? "direct" : "prototype");
- ICInNativeCompiler compiler(cx, kind, obj, holder, name);
- ICStub* newStub = compiler.getStub(compiler.getStubSpace(outerScript));
- if (!newStub)
- return false;
-
- *attached = true;
- stub->addNewStub(newStub);
- return true;
- }
-
- return true;
-}
-
-static bool
TryAttachNativeInDoesNotExistStub(JSContext* cx, HandleScript outerScript,
ICIn_Fallback* stub, HandleValue key,
HandleObject obj, bool* attached)
{
MOZ_ASSERT(!*attached);
RootedId id(cx);
if (!IsOptimizableElementPropertyName(cx, key, &id))
@@ -2027,22 +1987,17 @@ DoInFallback(JSContext* cx, BaselineFram
return true;
if (attached)
return true;
if (obj->isNative()) {
RootedScript script(cx, frame->script());
bool attached = false;
- if (cond) {
- if (!TryAttachNativeInStub(cx, script, stub, key, obj, &attached))
- return false;
- if (attached)
- return true;
- } else {
+ if (!cond) {
if (!TryAttachNativeInDoesNotExistStub(cx, script, stub, key, obj, &attached))
return false;
if (attached)
return true;
}
}
return true;
@@ -2068,63 +2023,16 @@ ICIn_Fallback::Compiler::generateStubCod
masm.pushValue(R1);
masm.pushValue(R0);
masm.push(ICStubReg);
pushStubPayload(masm, R0.scratchReg());
return tailCallVM(DoInFallbackInfo, masm);
}
-bool
-ICInNativeCompiler::generateStubCode(MacroAssembler& masm)
-{
- MOZ_ASSERT(engine_ == Engine::Baseline);
-
- Label failure, failurePopR0Scratch;
-
- masm.branchTestString(Assembler::NotEqual, R0, &failure);
- masm.branchTestObject(Assembler::NotEqual, R1, &failure);
-
- AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
- Register scratch = regs.takeAny();
-
- // Check key identity.
- Register strExtract = masm.extractString(R0, ExtractTemp0);
- masm.loadPtr(Address(ICStubReg, ICInNativeStub::offsetOfName()), scratch);
- masm.branchPtr(Assembler::NotEqual, strExtract, scratch, &failure);
-
- // Unbox and shape guard object.
- Register objReg = masm.extractObject(R1, ExtractTemp0);
- masm.loadPtr(Address(ICStubReg, ICInNativeStub::offsetOfShape()), scratch);
- masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
-
- if (kind == ICStub::In_NativePrototype) {
- // Shape guard holder. Use R0 scrachReg since on x86 there're not enough registers.
- Register holderReg = R0.scratchReg();
- masm.push(R0.scratchReg());
- masm.loadPtr(Address(ICStubReg, ICIn_NativePrototype::offsetOfHolder()),
- holderReg);
- masm.loadPtr(Address(ICStubReg, ICIn_NativePrototype::offsetOfHolderShape()),
- scratch);
- masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failurePopR0Scratch);
- masm.addToStackPtr(Imm32(sizeof(size_t)));
- }
-
- masm.moveValue(BooleanValue(true), R0);
-
- EmitReturnFromIC(masm);
-
- // Failure case - jump to next stub
- masm.bind(&failurePopR0Scratch);
- masm.pop(R0.scratchReg());
- masm.bind(&failure);
- EmitStubGuardFailure(masm);
- return true;
-}
-
ICStub*
ICInNativeDoesNotExistCompiler::getStub(ICStubSpace* space)
{
Rooted<ShapeVector> shapes(cx, ShapeVector(cx));
if (!shapes.append(obj_->as<NativeObject>().lastProperty()))
return nullptr;
if (!GetProtoShapes(obj_, protoChainDepth_, &shapes))
@@ -5503,31 +5411,16 @@ ICSetElem_TypedArray::ICSetElem_TypedArr
: ICStub(SetElem_TypedArray, stubCode),
shape_(shape)
{
extra_ = uint8_t(type);
MOZ_ASSERT(extra_ == type);
extra_ |= (static_cast<uint16_t>(expectOutOfBounds) << 8);
}
-ICInNativeStub::ICInNativeStub(ICStub::Kind kind, JitCode* stubCode, HandleShape shape,
- HandlePropertyName name)
- : ICStub(kind, stubCode),
- shape_(shape),
- name_(name)
-{ }
-
-ICIn_NativePrototype::ICIn_NativePrototype(JitCode* stubCode, HandleShape shape,
- HandlePropertyName name, HandleObject holder,
- HandleShape holderShape)
- : ICInNativeStub(In_NativePrototype, stubCode, shape, name),
- holder_(holder),
- holderShape_(holderShape)
-{ }
-
ICIn_NativeDoesNotExist::ICIn_NativeDoesNotExist(JitCode* stubCode, size_t protoChainDepth,
HandlePropertyName name)
: ICStub(In_NativeDoesNotExist, stubCode),
name_(name)
{
MOZ_ASSERT(protoChainDepth <= MAX_PROTO_CHAIN_DEPTH);
extra_ = protoChainDepth;
}
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -708,113 +708,16 @@ class ICIn_Fallback : public ICFallbackS
{ }
ICStub* getStub(ICStubSpace* space) {
return newStub<ICIn_Fallback>(space, getStubCode());
}
};
};
-// Base class for In_Native and In_NativePrototype stubs.
-class ICInNativeStub : public ICStub
-{
- GCPtrShape shape_;
- GCPtrPropertyName name_;
-
- protected:
- ICInNativeStub(ICStub::Kind kind, JitCode* stubCode, HandleShape shape,
- HandlePropertyName name);
-
- public:
- GCPtrShape& shape() {
- return shape_;
- }
- static size_t offsetOfShape() {
- return offsetof(ICInNativeStub, shape_);
- }
-
- GCPtrPropertyName& name() {
- return name_;
- }
- static size_t offsetOfName() {
- return offsetof(ICInNativeStub, name_);
- }
-};
-
-// Stub for confirming an own property on a native object.
-class ICIn_Native : public ICInNativeStub
-{
- friend class ICStubSpace;
-
- ICIn_Native(JitCode* stubCode, HandleShape shape, HandlePropertyName name)
- : ICInNativeStub(In_Native, stubCode, shape, name)
- {}
-};
-
-// Stub for confirming a property on a native object's prototype. Note that due to
-// the shape teleporting optimization, we only have to guard on the object's shape
-// and the holder's shape.
-class ICIn_NativePrototype : public ICInNativeStub
-{
- friend class ICStubSpace;
-
- GCPtrObject holder_;
- GCPtrShape holderShape_;
-
- ICIn_NativePrototype(JitCode* stubCode, HandleShape shape, HandlePropertyName name,
- HandleObject holder, HandleShape holderShape);
-
- public:
- GCPtrObject& holder() {
- return holder_;
- }
- GCPtrShape& holderShape() {
- return holderShape_;
- }
- static size_t offsetOfHolder() {
- return offsetof(ICIn_NativePrototype, holder_);
- }
- static size_t offsetOfHolderShape() {
- return offsetof(ICIn_NativePrototype, holderShape_);
- }
-};
-
-// Compiler for In_Native and In_NativePrototype stubs.
-class ICInNativeCompiler : public ICStubCompiler
-{
- RootedObject obj_;
- RootedObject holder_;
- RootedPropertyName name_;
-
- MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
-
- public:
- ICInNativeCompiler(JSContext* cx, ICStub::Kind kind, HandleObject obj, HandleObject holder,
- HandlePropertyName name)
- : ICStubCompiler(cx, kind, Engine::Baseline),
- obj_(cx, obj),
- holder_(cx, holder),
- name_(cx, name)
- {}
-
- ICStub* getStub(ICStubSpace* space) {
- RootedShape shape(cx, obj_->as<NativeObject>().lastProperty());
- if (kind == ICStub::In_Native) {
- MOZ_ASSERT(obj_ == holder_);
- return newStub<ICIn_Native>(space, getStubCode(), shape, name_);
- }
-
- MOZ_ASSERT(obj_ != holder_);
- MOZ_ASSERT(kind == ICStub::In_NativePrototype);
- RootedShape holderShape(cx, holder_->as<NativeObject>().lastProperty());
- return newStub<ICIn_NativePrototype>(space, getStubCode(), shape, name_, holder_,
- holderShape);
- }
-};
-
template <size_t ProtoChainDepth> class ICIn_NativeDoesNotExistImpl;
class ICIn_NativeDoesNotExist : public ICStub
{
friend class ICStubSpace;
GCPtrPropertyName name_;
--- a/js/src/jit/BaselineICList.h
+++ b/js/src/jit/BaselineICList.h
@@ -51,18 +51,16 @@ namespace jit {
_(GetElem_Fallback) \
\
_(SetElem_Fallback) \
_(SetElem_DenseOrUnboxedArray) \
_(SetElem_DenseOrUnboxedArrayAdd) \
_(SetElem_TypedArray) \
\
_(In_Fallback) \
- _(In_Native) \
- _(In_NativePrototype) \
_(In_NativeDoesNotExist) \
\
_(GetName_Fallback) \
\
_(BindName_Fallback) \
\
_(GetIntrinsic_Fallback) \
_(GetIntrinsic_Constant) \
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -36,16 +36,28 @@ GetPropIRGenerator::GetPropIRGenerator(J
val_(val),
idVal_(idVal),
engine_(engine),
isTemporarilyUnoptimizable_(isTemporarilyUnoptimizable),
canAttachGetter_(canAttachGetter),
preliminaryObjectAction_(PreliminaryObjectAction::None)
{}
+static void EmitNameOrSymbolGuard(CacheIRWriter& writer, jsid id, ValOperandId valId)
+{
+ if (JSID_IS_SYMBOL(id)) {
+ SymbolOperandId symId = writer.guardIsSymbol(valId);
+ writer.guardSpecificSymbol(symId, JSID_TO_SYMBOL(id));
+ } else {
+ MOZ_ASSERT(JSID_IS_ATOM(id));
+ StringOperandId strId = writer.guardIsString(valId);
+ writer.guardSpecificAtom(strId, JSID_TO_ATOM(id));
+ }
+}
+
static void
EmitLoadSlotResult(CacheIRWriter& writer, ObjOperandId holderOp, NativeObject* holder,
Shape* shape)
{
if (holder->isFixedSlot(shape->slot())) {
writer.loadFixedSlotResult(holderOp, NativeObject::getFixedSlotOffset(shape->slot()));
} else {
size_t dynamicSlotOffset = holder->dynamicSlotIndex(shape->slot()) * sizeof(Value);
@@ -358,16 +370,46 @@ TestMatchingReceiver(CacheIRWriter& writ
} else {
Shape* shape = obj->maybeShape();
MOZ_ASSERT(shape);
writer.guardShape(objId, shape);
}
}
static void
+EmitReadSlotGuard(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
+ Shape* shape, ObjOperandId objId)
+{
+ Maybe<ObjOperandId> expandoId;
+ TestMatchingReceiver(writer, obj, shape, objId, &expandoId);
+
+ if (obj != holder) {
+ GeneratePrototypeGuards(writer, obj, holder, objId);
+
+ if (holder) {
+ // Guard on the holder's shape.
+ ObjOperandId holderId = writer.loadObject(holder);
+ writer.guardShape(holderId, holder->as<NativeObject>().lastProperty());
+ } else {
+ // The property does not exist. Guard on everything in the prototype
+ // chain. This is guaranteed to see only Native objects because of
+ // CanAttachNativeGetProp().
+ JSObject* proto = obj->taggedProto().toObjectOrNull();
+ ObjOperandId lastObjId = objId;
+ while (proto) {
+ ObjOperandId protoId = writer.loadProto(lastObjId);
+ writer.guardShape(protoId, proto->as<NativeObject>().lastProperty());
+ proto = proto->staticPrototype();
+ lastObjId = protoId;
+ }
+ }
+ }
+}
+
+static void
EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
Shape* shape, ObjOperandId objId)
{
Maybe<ObjOperandId> expandoId;
TestMatchingReceiver(writer, obj, shape, objId, &expandoId);
ObjOperandId holderId;
if (obj != holder) {
@@ -1306,25 +1348,17 @@ GetPropIRGenerator::maybeEmitIdGuard(jsi
if (cacheKind_ == CacheKind::GetProp) {
// Constant PropertyName, no guards necessary.
MOZ_ASSERT(&idVal_.toString()->asAtom() == JSID_TO_ATOM(id));
return;
}
MOZ_ASSERT(cacheKind_ == CacheKind::GetElem);
- ValOperandId valId = getElemKeyValueId();
- if (JSID_IS_SYMBOL(id)) {
- SymbolOperandId symId = writer.guardIsSymbol(valId);
- writer.guardSpecificSymbol(symId, JSID_TO_SYMBOL(id));
- } else {
- MOZ_ASSERT(JSID_IS_ATOM(id));
- StringOperandId strId = writer.guardIsString(valId);
- writer.guardSpecificAtom(strId, JSID_TO_ATOM(id));
- }
+ EmitNameOrSymbolGuard(writer, id, getElemKeyValueId());
}
GetNameIRGenerator::GetNameIRGenerator(JSContext* cx, jsbytecode* pc, HandleScript script,
HandleObject env, HandlePropertyName name)
: IRGenerator(cx, pc, CacheKind::GetName),
script_(script),
env_(env),
name_(name)
@@ -1566,28 +1600,80 @@ InIRGenerator::tryAttachDenseIn(HandleVa
writer.guardShape(objId, obj->as<NativeObject>().lastProperty());
writer.loadDenseElementExistsResult(objId, indexId);
writer.returnFromIC();
return true;
}
bool
+InIRGenerator::tryAttachNativeIn(HandleValue key, ValOperandId keyId,
+ HandleObject obj, ObjOperandId objId)
+{
+ RootedId id(cx_);
+ bool nameOrSymbol;
+ if (!ValueToNameOrSymbolId(cx_, key, &id, &nameOrSymbol)) {
+ cx_->clearPendingException();
+ return false;
+ }
+ if (!nameOrSymbol)
+ return false;
+
+ PropertyResult prop;
+ JSObject* holder;
+ if (!LookupPropertyPure(cx_, obj, id, &holder, &prop))
+ return false;
+
+ if (prop.isNonNativeProperty())
+ return false;
+
+ if (!IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop))
+ return false;
+
+ EmitNameOrSymbolGuard(writer, id, keyId);
+ EmitReadSlotGuard(writer, obj, holder, prop.maybeShape(), objId);
+ writer.loadBooleanResult(true);
+ writer.returnFromIC();
+
+ return true;
+}
+
+bool
+InIRGenerator::maybeGuardSpecificId(jsid id, ValOperandId valId)
+{
+ if (JSID_IS_ATOM(id)) {
+ StringOperandId strId = writer.guardIsString(valId);
+ writer.guardSpecificAtom(strId, JSID_TO_ATOM(id));
+ return true;
+ }
+
+ if (JSID_IS_SYMBOL(id)) {
+ SymbolOperandId symId = writer.guardIsSymbol(valId);
+ writer.guardSpecificSymbol(symId, JSID_TO_SYMBOL(id));
+ return true;
+ }
+
+ return false;
+}
+
+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);
if (tryAttachDenseIn(key_, keyId, obj_, objId))
return true;
+ if (tryAttachNativeIn(key_, keyId, obj_, objId))
+ return true;
return false;
}
bool
IRGenerator::maybeGuardInt32Index(const Value& index, ValOperandId indexId,
uint32_t* int32Index, Int32OperandId* int32IndexId)
{
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -204,16 +204,17 @@ enum class CacheKind : uint8_t
_(LoadFrameArgumentResult) \
_(LoadEnvironmentFixedSlotResult) \
_(LoadEnvironmentDynamicSlotResult) \
_(CallScriptedGetterResult) \
_(CallNativeGetterResult) \
_(CallProxyGetResult) \
_(CallProxyGetByValueResult) \
_(LoadUndefinedResult) \
+ _(LoadBooleanResult) \
\
_(TypeMonitorResult) \
_(ReturnFromIC)
enum class CacheOp {
#define DEFINE_OP(op) op,
CACHE_IR_OPS(DEFINE_OP)
#undef DEFINE_OP
@@ -637,16 +638,20 @@ class MOZ_RAII CacheIRWriter : public JS
writeOperandId(rhs);
}
void callSetArrayLength(ObjOperandId obj, bool strict, ValOperandId rhs) {
writeOpWithOperandId(CacheOp::CallSetArrayLength, obj);
buffer_.writeByte(uint32_t(strict));
writeOperandId(rhs);
}
+ void loadBooleanResult(bool val) {
+ writeOp(CacheOp::LoadBooleanResult);
+ buffer_.writeByte(uint32_t(val));
+ }
void loadUndefinedResult() {
writeOp(CacheOp::LoadUndefinedResult);
}
void loadFixedSlotResult(ObjOperandId obj, size_t offset) {
writeOpWithOperandId(CacheOp::LoadFixedSlotResult, obj);
addStubField(offset, StubField::Type::RawWord);
}
void loadDynamicSlotResult(ObjOperandId obj, size_t offset) {
@@ -1003,16 +1008,20 @@ class MOZ_RAII SetPropIRGenerator : publ
// InIRGenerator generates CacheIR for a In IC.
class MOZ_RAII InIRGenerator : public IRGenerator
{
HandleValue key_;
HandleObject obj_;
bool tryAttachDenseIn(HandleValue key, ValOperandId keyId,
HandleObject obj, ObjOperandId objId);
+ bool tryAttachNativeIn(HandleValue key, ValOperandId keyId,
+ HandleObject obj, ObjOperandId objId);
+
+ bool maybeGuardSpecificId(jsid id, ValOperandId valId);
public:
InIRGenerator(JSContext* cx, jsbytecode* pc,
HandleValue key, HandleObject obj);
bool tryAttachStub();
};
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -1434,16 +1434,29 @@ CacheIRCompiler::emitLoadUndefinedResult
AutoOutputRegister output(*this);
if (output.hasValue())
masm.moveValue(UndefinedValue(), output.valueReg());
else
masm.assumeUnreachable("Should have monitored undefined result");
return true;
}
+bool
+CacheIRCompiler::emitLoadBooleanResult()
+{
+ AutoOutputRegister output(*this);
+ if (output.hasValue()) {
+ Value val = BooleanValue(reader.readBool());
+ masm.moveValue(val, output.valueReg());
+ }
+ else
+ masm.assumeUnreachable("Should have monitored result");
+ return true;
+}
+
static void
EmitStoreResult(MacroAssembler& masm, Register reg, JSValueType type,
const AutoOutputRegister& output)
{
if (output.hasValue()) {
masm.tagValue(type, reg, output.valueReg());
return;
}
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -30,16 +30,17 @@ namespace jit {
_(GuardNoDetachedTypedObjects) \
_(GuardNoDenseElements) \
_(GuardAndGetIndexFromString) \
_(LoadProto) \
_(LoadEnclosingEnvironment) \
_(LoadDOMExpandoValue) \
_(LoadDOMExpandoValueIgnoreGeneration)\
_(LoadUndefinedResult) \
+ _(LoadBooleanResult) \
_(LoadInt32ArrayLengthResult) \
_(LoadUnboxedArrayLengthResult) \
_(LoadArgumentsObjectLengthResult) \
_(LoadFunctionLengthResult) \
_(LoadStringLengthResult) \
_(LoadStringCharResult) \
_(LoadArgumentsObjectArgResult) \
_(LoadDenseElementResult) \
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -309,30 +309,16 @@ ICStub::trace(JSTracer* trc)
TraceEdge(trc, &updateStub->object(), "baseline-update-singleton");
break;
}
case ICStub::TypeUpdate_ObjectGroup: {
ICTypeUpdate_ObjectGroup* updateStub = toTypeUpdate_ObjectGroup();
TraceEdge(trc, &updateStub->group(), "baseline-update-group");
break;
}
- case ICStub::In_Native: {
- ICIn_Native* inStub = toIn_Native();
- TraceEdge(trc, &inStub->shape(), "baseline-innative-stub-shape");
- TraceEdge(trc, &inStub->name(), "baseline-innative-stub-name");
- break;
- }
- case ICStub::In_NativePrototype: {
- ICIn_NativePrototype* inStub = toIn_NativePrototype();
- TraceEdge(trc, &inStub->shape(), "baseline-innativeproto-stub-shape");
- TraceEdge(trc, &inStub->name(), "baseline-innativeproto-stub-name");
- TraceEdge(trc, &inStub->holder(), "baseline-innativeproto-stub-holder");
- TraceEdge(trc, &inStub->holderShape(), "baseline-innativeproto-stub-holdershape");
- break;
- }
case ICStub::In_NativeDoesNotExist: {
ICIn_NativeDoesNotExist* inStub = toIn_NativeDoesNotExist();
TraceEdge(trc, &inStub->name(), "baseline-innativedoesnotexist-stub-name");
JS_STATIC_ASSERT(ICIn_NativeDoesNotExist::MAX_PROTO_CHAIN_DEPTH == 8);
switch (inStub->protoChainDepth()) {
case 0: inStub->toImpl<0>()->traceShapes(trc); break;
case 1: inStub->toImpl<1>()->traceShapes(trc); break;
case 2: inStub->toImpl<2>()->traceShapes(trc); break;