Bug 1285217 - Handle OOM in IonBuilder::testNotDefinedProperty. r=jandem
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1285217.js
@@ -0,0 +1,11 @@
+function f() {
+ var o = {
+ x: 1
+ };
+ for (var i = 0; i < 300; i++) o = Object.create(o);
+ for (var i = 0; i < 15; i++) {
+ assertEq(o.x, 1);
+ eval(o.y, undefined);
+ }
+}
+f();
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -8265,58 +8265,61 @@ IonBuilder::testSingletonPropertyTypes(M
JSObject* proto = GetBuiltinPrototypePure(&script()->global(), key);
if (proto)
return testSingletonProperty(proto, id);
return nullptr;
}
-bool
+ResultWithOOM<bool>
IonBuilder::testNotDefinedProperty(MDefinition* obj, jsid id)
{
TemporaryTypeSet* types = obj->resultTypeSet();
if (!types || types->unknownObject() || types->getKnownMIRType() != MIRType::Object)
- return false;
+ return ResultWithOOM<bool>::ok(false);
for (unsigned i = 0, count = types->getObjectCount(); i < count; i++) {
TypeSet::ObjectKey* key = types->getObject(i);
if (!key)
continue;
while (true) {
+ if (!alloc().ensureBallast())
+ return ResultWithOOM<bool>::fail();
+
if (!key->hasStableClassAndProto(constraints()) || key->unknownProperties())
- return false;
+ return ResultWithOOM<bool>::ok(false);
const Class* clasp = key->clasp();
if (!ClassHasEffectlessLookup(clasp) || ObjectHasExtraOwnProperty(compartment, key, id))
- return false;
+ return ResultWithOOM<bool>::ok(false);
// If the object is a singleton, we can do a lookup now to avoid
// unnecessary invalidations later on, in case the property types
// have not yet been instantiated.
if (key->isSingleton() &&
key->singleton()->is<NativeObject>() &&
key->singleton()->as<NativeObject>().lookupPure(id))
{
- return false;
+ return ResultWithOOM<bool>::ok(false);
}
HeapTypeSetKey property = key->property(id);
if (property.isOwnProperty(constraints()))
- return false;
+ return ResultWithOOM<bool>::ok(false);
JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull());
if (!proto)
break;
key = TypeSet::ObjectKey::get(proto);
}
}
- return true;
+ return ResultWithOOM<bool>::ok(true);
}
bool
IonBuilder::pushTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, BarrierKind kind)
{
MOZ_ASSERT(def == current->peek(-1));
MDefinition* replace = addTypeBarrier(current->pop(), observed, kind);
@@ -11681,17 +11684,20 @@ IonBuilder::getPropTryNotDefined(bool* e
MOZ_ASSERT(*emitted == false);
if (!types->mightBeMIRType(MIRType::Undefined)) {
// Only optimize if we expect this property access to return undefined.
trackOptimizationOutcome(TrackedOutcome::NotUndefined);
return true;
}
- if (!testNotDefinedProperty(obj, id)) {
+ ResultWithOOM<bool> res = testNotDefinedProperty(obj, id);
+ if (res.oom)
+ return false;
+ if (!res.value) {
trackOptimizationOutcome(TrackedOutcome::GenericFailure);
return true;
}
obj->setImplicitlyUsedUnchecked();
pushConstant(UndefinedValue());
trackOptimizationSuccess();
@@ -13798,17 +13804,20 @@ IonBuilder::inTryFold(bool* emitted, MDe
MConstant* idConst = id->maybeConstantValue();
jsid propId;
if (!idConst || !ValueToIdPure(idConst->toJSValue(), &propId))
return true;
if (propId != IdToTypeId(propId))
return true;
- if (!testNotDefinedProperty(obj, propId))
+ ResultWithOOM<bool> res = testNotDefinedProperty(obj, propId);
+ if (res.oom)
+ return false;
+ if (!res.value)
return true;
*emitted = true;
pushConstant(BooleanValue(false));
obj->setImplicitlyUsedUnchecked();
id->setImplicitlyUsedUnchecked();
return true;
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -1043,17 +1043,17 @@ class IonBuilder
MGetPropertyCache* getInlineableGetPropertyCache(CallInfo& callInfo);
JSObject* testGlobalLexicalBinding(PropertyName* name);
JSObject* testSingletonProperty(JSObject* obj, jsid id);
JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id);
- MOZ_MUST_USE bool testNotDefinedProperty(MDefinition* obj, jsid id);
+ ResultWithOOM<bool> testNotDefinedProperty(MDefinition* obj, jsid id);
uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
MDefinition* convertUnboxedObjects(MDefinition* obj);
MDefinition* convertUnboxedObjects(MDefinition* obj,
const BaselineInspector::ObjectGroupVector& list);
uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name,
JSValueType* punboxedType);
MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -39,16 +39,29 @@ namespace js {
class StringObject;
namespace jit {
class BaselineInspector;
class Range;
+template <typename T>
+struct ResultWithOOM {
+ T value;
+ bool oom;
+
+ static ResultWithOOM<T> ok(T val) {
+ return { val, false };
+ }
+ static ResultWithOOM<T> fail() {
+ return { T(), true };
+ }
+};
+
static inline
MIRType MIRTypeFromValue(const js::Value& vp)
{
if (vp.isDouble())
return MIRType::Double;
if (vp.isMagic()) {
switch (vp.whyMagic()) {
case JS_OPTIMIZED_ARGUMENTS: