diff options
author | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-09-05 13:03:09 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-09-05 13:19:33 +0200 |
commit | 2b223cce089bb8cbfb1a463fdd42e09eee63c7b2 (patch) | |
tree | e3d2025041a0f3a6d9eb870455ca8db324b88729 /js/src/vm | |
parent | d90dd7b0c60e7950b668a08d415c0395c92db535 (diff) | |
download | UXP-2b223cce089bb8cbfb1a463fdd42e09eee63c7b2.tar UXP-2b223cce089bb8cbfb1a463fdd42e09eee63c7b2.tar.gz UXP-2b223cce089bb8cbfb1a463fdd42e09eee63c7b2.tar.lz UXP-2b223cce089bb8cbfb1a463fdd42e09eee63c7b2.tar.xz UXP-2b223cce089bb8cbfb1a463fdd42e09eee63c7b2.zip |
Use the correct group for JIT constraints.
This fixes a rare crash/CTD in JS.
This adds information about the constraints to a new RAII class so we
can finish all constraints at the end.
Based on changes in BZ 1568397
Diffstat (limited to 'js/src/vm')
-rw-r--r-- | js/src/vm/TypeInference.cpp | 84 | ||||
-rw-r--r-- | js/src/vm/TypeInference.h | 59 |
2 files changed, 136 insertions, 7 deletions
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 7c2c0194e..88327b47e 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -3084,29 +3084,39 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint }; bool -js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id) +js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, + DPAConstraintInfo& constraintInfo, + ObjectGroup* group, + HandleId id, + bool* added) { /* * Ensure that if the properties named here could have a getter, setter or * a permanent property in any transitive prototype, the definite * properties get cleared from the group. */ + + *added = false; + RootedObject proto(cx, group->proto().toObjectOrNull()); while (proto) { ObjectGroup* protoGroup = JSObject::getGroup(cx, proto); if (!protoGroup) { - cx->recoverFromOutOfMemory(); return false; } if (protoGroup->unknownProperties()) - return false; + return true; HeapTypeSet* protoTypes = protoGroup->getProperty(cx, proto, id); - if (!protoTypes || protoTypes->nonDataProperty() || protoTypes->nonWritableProperty()) + if (!protoTypes) return false; - if (!protoTypes->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(group))) + if (protoTypes->nonDataProperty() || protoTypes->nonWritableProperty()) + return true; + if (!constraintInfo.addProtoConstraint(proto, id)) return false; proto = proto->staticPrototype(); } + + *added = true; return true; } @@ -3612,6 +3622,43 @@ struct DestroyTypeNewScript } // namespace +bool DPAConstraintInfo::finishConstraints(JSContext* cx, ObjectGroup* group) {
+ for (const ProtoConstraint& constraint : protoConstraints_) {
+ ObjectGroup* protoGroup = constraint.proto->group();
+
+ // Note: we rely on the group's type information being unchanged since
+ // AddClearDefiniteGetterSetterForPrototypeChain.
+
+ bool unknownProperties = protoGroup->unknownProperties();
+ MOZ_RELEASE_ASSERT(!unknownProperties);
+
+ HeapTypeSet* protoTypes =
+ protoGroup->getProperty(cx, constraint.proto, constraint.id);
+ MOZ_RELEASE_ASSERT(protoTypes);
+
+ MOZ_ASSERT(!protoTypes->nonDataProperty());
+ MOZ_ASSERT(!protoTypes->nonWritableProperty());
+
+ if (!protoTypes->addConstraint(
+ cx,
+ cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(
+ group))) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ for (const InliningConstraint& constraint : inliningConstraints_) {
+ if (!AddClearDefiniteFunctionUsesInScript(cx, group, constraint.caller,
+ constraint.callee)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ return true;
+}
+ bool TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force) { @@ -3715,10 +3762,17 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, return false; Vector<Initializer> initializerVector(cx); + + DPAConstraintInfo constraintInfo(cx); RootedPlainObject templateRoot(cx, templateObject()); RootedFunction fun(cx, function()); - if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, group, templateRoot, &initializerVector)) + if (!jit::AnalyzeNewScriptDefiniteProperties(cx, + constraintInfo, + fun, + group, + templateRoot, + &initializerVector)) return false; if (!group->newScript()) @@ -3772,6 +3826,14 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, // The definite properties analysis found exactly the properties that // are held in common by the preliminary objects. No further analysis // is needed. +
+ if (!constraintInfo.finishConstraints(cx, group)) {
+ return false;
+ }
+ if (!group->newScript()) {
+ return true;
+ }
+ group->addDefiniteProperties(cx, templateObject()->lastProperty()); destroyNewScript.group = nullptr; @@ -3792,6 +3854,16 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, initialFlags); if (!initialGroup) return false; +
+ // Add the constraints. Use the initialGroup as group referenced by the
+ // constraints because that's the group that will have the TypeNewScript
+ // associated with it. See the detachNewScript and setNewScript calls below.
+ if (!constraintInfo.finishConstraints(cx, initialGroup)) {
+ return false;
+ }
+ if (!group->newScript()) {
+ return true;
+ }
initialGroup->addDefiniteProperties(cx, templateObject()->lastProperty()); group->addDefiniteProperties(cx, prefixShape); diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 94ce7e871..fd021fc96 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -789,8 +789,65 @@ class TemporaryTypeSet : public TypeSet TypedArraySharedness* sharedness); }; +// Stack class to record information about constraints that need to be added +// after finishing the Definite Properties Analysis. When the analysis succeeds, +// the |finishConstraints| method must be called to add the constraints to the +// TypeSets. +// +// There are two constraint types managed here: +// +// 1. Proto constraints for HeapTypeSets, to guard against things like getters +// and setters on the proto chain. +// +// 2. Inlining constraints for StackTypeSets, to invalidate when additional +// functions could be called at call sites where we inlined a function. +// +// This class uses bare GC-thing pointers because GC is suppressed when the +// analysis runs. +class MOZ_RAII DPAConstraintInfo { + struct ProtoConstraint { + JSObject* proto; + jsid id; + ProtoConstraint(JSObject* proto, jsid id) : proto(proto), id(id) {} + }; + struct InliningConstraint { + JSScript* caller; + JSScript* callee; + InliningConstraint(JSScript* caller, JSScript* callee) + : caller(caller), callee(callee) {} + }; + + JS::AutoCheckCannotGC nogc_; + Vector<ProtoConstraint, 8> protoConstraints_; + Vector<InliningConstraint, 4> inliningConstraints_; + +public: + explicit DPAConstraintInfo(JSContext* cx) + : nogc_(cx) + , protoConstraints_(cx) + , inliningConstraints_(cx) + { + } + + DPAConstraintInfo(const DPAConstraintInfo&) = delete; + void operator=(const DPAConstraintInfo&) = delete; + + MOZ_MUST_USE bool addProtoConstraint(JSObject* proto, jsid id) { + return protoConstraints_.emplaceBack(proto, id); + } + MOZ_MUST_USE bool addInliningConstraint(JSScript* caller, JSScript* callee) { + return inliningConstraints_.emplaceBack(caller, callee); + } + + MOZ_MUST_USE bool finishConstraints(JSContext* cx, ObjectGroup* group); +}; + bool -AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id); +AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, + DPAConstraintInfo& constraintInfo, + ObjectGroup* group, + HandleId id, + bool* added); bool AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group, |