Bug 1155618 - Fix more out of memory handling issues r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 07 Sep 2015 11:36:55 +0100
changeset 293821 7c18fbc2d1515d4f88ac207ac4691b2f93b839d5
parent 293820 8408b26adf818039e669e807f20d6c2e5d7c054a
child 293822 460c903030a7685507b9670997eebfca775fd211
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1155618
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1155618 - Fix more out of memory handling issues r=terrence
js/src/asmjs/AsmJSFrameIterator.cpp
js/src/asmjs/AsmJSValidate.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/FullParseHandler.h
js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
js/src/jsiter.cpp
js/src/jsscript.cpp
js/src/vm/ObjectGroup.cpp
js/src/vm/Runtime.h
js/src/vm/ScopeObject.cpp
js/src/vm/TypeInference.cpp
js/src/vm/TypeInference.h
--- a/js/src/asmjs/AsmJSFrameIterator.cpp
+++ b/js/src/asmjs/AsmJSFrameIterator.cpp
@@ -245,17 +245,17 @@ GenerateProfilingEpilogue(MacroAssembler
         // and the async interrupt exit. Since activation.fp can be read at any
         // time and still points to the current frame, be careful to only update
         // sp after activation.fp has been repointed to the caller's frame.
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32)
         masm.loadPtr(Address(masm.getStackPointer(), 0), scratch2);
         masm.storePtr(scratch2, Address(scratch, AsmJSActivation::offsetOfFP()));
         DebugOnly<uint32_t> prePop = masm.currentOffset();
         masm.addToStackPtr(Imm32(sizeof(void *)));
-        MOZ_ASSERT(PostStorePrePopFP == masm.currentOffset() - prePop);
+        MOZ_ASSERT_IF(!masm.oom(), PostStorePrePopFP == masm.currentOffset() - prePop);
 #else
         masm.pop(Address(scratch, AsmJSActivation::offsetOfFP()));
         MOZ_ASSERT(PostStorePrePopFP == 0);
 #endif
 
         masm.bind(profilingReturn);
         masm.ret();
     }
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -12381,17 +12381,18 @@ CheckModule(ExclusiveContext* cx, AsmJSP
 #endif
 
     m.startFunctionBodies();
 
     ScopedJSDeletePtr<ModuleCompileResults> mcd;
     if (!CheckFunctions(m, &mcd))
         return false;
 
-    m.finishFunctionBodies(&mcd);
+    if (!m.finishFunctionBodies(&mcd))
+        return false;
 
     if (!CheckFuncPtrTables(m))
         return false;
 
     if (!CheckModuleReturn(m))
         return false;
 
     TokenKind tk;
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2918,17 +2918,18 @@ BytecodeEmitter::emitNumberOp(double dva
             return emit1(JSOP_ZERO);
         if (ival == 1)
             return emit1(JSOP_ONE);
         if ((int)(int8_t)ival == ival)
             return emit2(JSOP_INT8, uint8_t(int8_t(ival)));
 
         uint32_t u = uint32_t(ival);
         if (u < JS_BIT(16)) {
-            emitUint16Operand(JSOP_UINT16, u);
+            if (!emitUint16Operand(JSOP_UINT16, u))
+                return false;
         } else if (u < JS_BIT(24)) {
             ptrdiff_t off;
             if (!emitN(JSOP_UINT24, 3, &off))
                 return false;
             SET_UINT24(code(off), u);
         } else {
             ptrdiff_t off;
             if (!emitN(JSOP_INT32, 4, &off))
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -477,16 +477,18 @@ class FullParseHandler
         ParseNode* makeGen = new_<NullaryNode>(PNK_GENERATOR, yieldPos);
         if (!makeGen)
             return false;
 
         MOZ_ASSERT(genName->getOp() == JSOP_GETNAME);
         genName->setOp(JSOP_SETNAME);
         genName->markAsAssigned();
         ParseNode* genInit = newBinary(PNK_ASSIGN, genName, makeGen);
+        if (!genInit)
+            return false;
 
         ParseNode* initialYield = newYieldExpression(yieldPos.begin, nullptr, genInit,
                                                      JSOP_INITIALYIELD);
         if (!initialYield)
             return false;
 
         stmtList->prepend(initialYield);
         return true;
--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -513,17 +513,19 @@ struct AssemblerBufferWithConstantPools 
 
             inhibitNops_ = false;
         }
     }
 
     void markNextAsBranch() {
         // If the previous thing inserted was the last instruction of the node,
         // then whoops, we want to mark the first instruction of the next node.
-        this->ensureSpace(InstSize);
+        if (!this->ensureSpace(InstSize))
+            return;
+
         MOZ_ASSERT(this->getTail() != nullptr);
         this->getTail()->markNextAsBranch();
     }
 
     bool isNextBranch() const {
         MOZ_ASSERT(this->getTail() != nullptr);
         return this->getTail()->isNextBranch();
     }
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -515,18 +515,20 @@ NewPropertyIteratorObject(JSContext* cx,
 
 NativeIterator*
 NativeIterator::allocateIterator(JSContext* cx, uint32_t numGuards, const AutoIdVector& props)
 {
     JS_STATIC_ASSERT(sizeof(ReceiverGuard) == 2 * sizeof(void*));
 
     size_t plength = props.length();
     NativeIterator* ni = cx->zone()->pod_malloc_with_extra<NativeIterator, void*>(plength + numGuards * 2);
-    if (!ni)
+    if (!ni) {
+        ReportOutOfMemory(cx);
         return nullptr;
+    }
 
     AutoValueVector strings(cx);
     ni->props_array = ni->props_cursor = reinterpret_cast<HeapPtrFlatString*>(ni + 1);
     ni->props_end = ni->props_array + plength;
     if (plength) {
         for (size_t i = 0; i < plength; i++) {
             JSFlatString* str = IdToString(cx, props[i]);
             if (!str || !strings.append(StringValue(str)))
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3242,18 +3242,20 @@ js::detail::CopyScript(JSContext* cx, Ha
     uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
     uint32_t nblockscopes = src->hasBlockScopes() ? src->blockScopes()->length : 0;
     uint32_t nyieldoffsets = src->hasYieldOffsets() ? src->yieldOffsets().length() : 0;
 
     /* Script data */
 
     size_t size = src->dataSize();
     uint8_t* data = AllocScriptData(cx->zone(), size);
-    if (size && !data)
+    if (size && !data) {
+        ReportOutOfMemory(cx);
         return false;
+    }
 
     /* Bindings */
 
     Rooted<Bindings> bindings(cx);
     if (!Bindings::clone(cx, &bindings, data, src))
         return false;
 
     /* Objects */
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -549,20 +549,22 @@ ObjectGroup::defaultNewGroup(ExclusiveCo
     }
 
     ObjectGroupCompartment::newTablePostBarrier(cx, table, clasp, proto, associated);
 
     if (proto.isObject()) {
         RootedObject obj(cx, proto.toObject());
 
         if (associated) {
-            if (associated->is<JSFunction>())
-                TypeNewScript::make(cx->asJSContext(), group, &associated->as<JSFunction>());
-            else
+            if (associated->is<JSFunction>()) {
+                if (!TypeNewScript::make(cx->asJSContext(), group, &associated->as<JSFunction>()))
+                    return nullptr;
+            } else {
                 group->setTypeDescr(&associated->as<TypeDescr>());
+            }
         }
 
         /*
          * Some builtin objects have slotful native properties baked in at
          * creation via the Shape::{insert,get}initialShape mechanism. Since
          * these properties are never explicitly defined on new objects, update
          * the type information for them here.
          */
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -2164,28 +2164,28 @@ class MOZ_STACK_CLASS AutoInitGCManagedO
             rt->handlingInitFailure = true;
             ptr_.reset(nullptr);
             rt->handlingInitFailure = false;
         }
 #endif
     }
 
     T& operator*() const {
-        return *ptr_.get();
+        return *get();
     }
 
     T* operator->() const {
-        return ptr_.get();
+        return get();
     }
 
     explicit operator bool() const {
-        return ptr_.get() != nullptr;
+        return get() != nullptr;
     }
 
-    T* get() {
+    T* get() const {
         return ptr_.get();
     }
 
     T* release() {
         return ptr_.release();
     }
 
     AutoInitGCManagedObject(const AutoInitGCManagedObject<T>& other) = delete;
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1105,23 +1105,32 @@ ScopeIter::incrementStaticScopeIter()
         ssi_++;
 }
 
 void
 ScopeIter::settle()
 {
     // Check for trying to iterate a function frame before the prologue has
     // created the CallObject, in which case we have to skip.
-    if (frame_ && frame_.isNonEvalFunctionFrame() &&
-        frame_.fun()->needsCallObject() && !frame_.hasCallObj())
+    if (frame_ && frame_.isNonEvalFunctionFrame() && frame_.fun()->needsCallObject() &&
+        !frame_.hasCallObj())
     {
         MOZ_ASSERT(ssi_.type() == StaticScopeIter<CanGC>::Function);
         incrementStaticScopeIter();
     }
 
+    // Check for trying to iterate a strict eval frame before the prologue has
+    // created the CallObject.
+    if (frame_ && frame_.isStrictEvalFrame() && !frame_.hasCallObj() && !ssi_.done()) {
+        MOZ_ASSERT(ssi_.type() == StaticScopeIter<CanGC>::Block);
+        incrementStaticScopeIter();
+        MOZ_ASSERT(ssi_.type() == StaticScopeIter<CanGC>::Eval);
+        incrementStaticScopeIter();
+    }
+
     // Check if we have left the extent of the initial frame after we've
     // settled on a static scope.
     if (frame_ && (ssi_.done() || maybeStaticScope() == frame_.script()->enclosingStaticScope()))
         frame_ = NullFramePtr();
 
 #ifdef DEBUG
     if (!ssi_.done() && hasAnyScopeObject()) {
         switch (ssi_.type()) {
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3483,39 +3483,40 @@ PreliminaryObjectArrayWithTemplate::mayb
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeNewScript
 /////////////////////////////////////////////////////////////////////
 
 // Make a TypeNewScript for |group|, and set it up to hold the preliminary
 // objects created with the group.
-/* static */ void
+/* static */ bool
 TypeNewScript::make(JSContext* cx, ObjectGroup* group, JSFunction* fun)
 {
     MOZ_ASSERT(cx->zone()->types.activeAnalysis);
     MOZ_ASSERT(!group->newScript());
     MOZ_ASSERT(!group->maybeUnboxedLayout());
 
     if (group->unknownProperties())
-        return;
+        return true;
 
     ScopedJSDeletePtr<TypeNewScript> newScript(cx->new_<TypeNewScript>());
     if (!newScript)
-        return;
+        return false;
 
     newScript->function_ = fun;
 
     newScript->preliminaryObjects = group->zone()->new_<PreliminaryObjectArray>();
     if (!newScript->preliminaryObjects)
-        return;
+        return true;
 
     group->setNewScript(newScript.forget());
 
     gc::TraceTypeNewScript(group);
+    return true;
 }
 
 // Make a TypeNewScript with the same initializer list as |newScript| but with
 // a new template object.
 /* static */ TypeNewScript*
 TypeNewScript::makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
                                  PlainObject* templateObject)
 {
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -959,17 +959,17 @@ class TypeNewScript
     void trace(JSTracer* trc);
     void sweep();
 
     void registerNewObject(PlainObject* res);
     bool maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force = false);
 
     bool rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* group);
 
-    static void make(JSContext* cx, ObjectGroup* group, JSFunction* fun);
+    static bool make(JSContext* cx, ObjectGroup* group, JSFunction* fun);
     static TypeNewScript* makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
                                             PlainObject* templateObject);
 
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 };
 
 /* Is this a reasonable PC to be doing inlining on? */
 inline bool isInlinableCall(jsbytecode* pc);