From b921204b94a332091e92ec3cddee1a47d7ee6d22 Mon Sep 17 00:00:00 2001 From: David Mandelin Date: Thu, 14 Oct 2010 16:33:49 -0700 Subject: [PATCH] Bug 603077: OOM safety for JM assembler buffer, r=dvander --- js/src/assembler/assembler/ARMAssembler.cpp | 6 +- js/src/assembler/assembler/ARMAssembler.h | 1 + js/src/assembler/assembler/ARMv7Assembler.h | 1 + .../assembler/AbstractMacroAssembler.h | 5 + js/src/assembler/assembler/AssemblerBuffer.h | 58 ++++++- js/src/assembler/assembler/X86Assembler.h | 5 +- js/src/methodjit/Compiler.cpp | 156 ++++++++++++------ js/src/methodjit/Compiler.h | 24 +-- js/src/methodjit/FastOps.cpp | 29 ++-- js/src/yarr/yarr/RegexJIT.cpp | 5 + 10 files changed, 208 insertions(+), 82 deletions(-) diff --git a/js/src/assembler/assembler/ARMAssembler.cpp b/js/src/assembler/assembler/ARMAssembler.cpp index 0dba21cc001..85fbaf16b44 100644 --- a/js/src/assembler/assembler/ARMAssembler.cpp +++ b/js/src/assembler/assembler/ARMAssembler.cpp @@ -416,7 +416,8 @@ void* ARMAssembler::executableCopy(ExecutablePool* allocator) bkpt(0); void * data = m_buffer.executableCopy(allocator); - fixUpOffsets(data); + if (data) + fixUpOffsets(data); return data; } @@ -426,6 +427,9 @@ void* ARMAssembler::executableCopy(ExecutablePool* allocator) // have been flushed. void* ARMAssembler::executableCopy(void * buffer) { + if (m_buffer.oom()) + return NULL; + ASSERT(m_buffer.sizeOfConstantPool() == 0); memcpy(buffer, m_buffer.data(), m_buffer.size()); diff --git a/js/src/assembler/assembler/ARMAssembler.h b/js/src/assembler/assembler/ARMAssembler.h index 682a6365ecd..7428c0e1717 100644 --- a/js/src/assembler/assembler/ARMAssembler.h +++ b/js/src/assembler/assembler/ARMAssembler.h @@ -146,6 +146,7 @@ namespace JSC { typedef SegmentedVector Jumps; unsigned char *buffer() const { return m_buffer.buffer(); } + bool oom() const { return m_buffer.oom(); } // ARM conditional constants typedef enum { diff --git a/js/src/assembler/assembler/ARMv7Assembler.h b/js/src/assembler/assembler/ARMv7Assembler.h index 68baadbd443..710cbc6e440 100644 --- a/js/src/assembler/assembler/ARMv7Assembler.h +++ b/js/src/assembler/assembler/ARMv7Assembler.h @@ -1905,6 +1905,7 @@ private: bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } void* data() const { return m_buffer.data(); } void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); } + bool oom() const { return m_buffer.oom(); } private: AssemblerBuffer m_buffer; diff --git a/js/src/assembler/assembler/AbstractMacroAssembler.h b/js/src/assembler/assembler/AbstractMacroAssembler.h index b953df43602..fa24df64591 100644 --- a/js/src/assembler/assembler/AbstractMacroAssembler.h +++ b/js/src/assembler/assembler/AbstractMacroAssembler.h @@ -446,6 +446,11 @@ public: return m_assembler.buffer(); } + bool oom() + { + return m_assembler.oom(); + } + void* executableCopy(void* buffer) { return m_assembler.executableCopy(buffer); diff --git a/js/src/assembler/assembler/AssemblerBuffer.h b/js/src/assembler/assembler/AssemblerBuffer.h index 717ed5f01bd..3698c67727f 100644 --- a/js/src/assembler/assembler/AssemblerBuffer.h +++ b/js/src/assembler/assembler/AssemblerBuffer.h @@ -48,6 +48,7 @@ namespace JSC { : m_buffer(m_inlineBuffer) , m_capacity(inlineCapacity) , m_size(0) + , m_oom(false) { } @@ -127,8 +128,20 @@ namespace JSC { return m_size; } + bool oom() const + { + return m_oom; + } + + /* + * The user must check for a NULL return value, which means + * no code was generated, or there was an OOM. + */ void* executableCopy(ExecutablePool* allocator) { + if (m_oom) + return 0; + if (!m_size) return 0; @@ -143,6 +156,7 @@ namespace JSC { } unsigned char *buffer() const { + ASSERT(!m_oom); return reinterpret_cast(m_buffer); } @@ -152,25 +166,59 @@ namespace JSC { if (m_size > m_capacity - size) grow(size); + // If we OOM and size > inlineCapacity, this would crash. + if (m_oom) + return; memcpy(m_buffer + m_size, data, size); m_size += size; } + /* + * OOM handling: This class can OOM in the grow() method trying to + * allocate a new buffer. In response to an OOM, we need to avoid + * crashing and report the error. We also want to make it so that + * users of this class need to check for OOM only at certain points + * and not after every operation. + * + * Our strategy for handling an OOM is to set m_oom, and then set + * m_size to 0, preserving the current buffer. This way, the user + * can continue assembling into the buffer, deferring OOM checking + * until the user wants to read code out of the buffer. + * + * See also the |executableCopy| and |buffer| methods. + */ + void grow(int extraCapacity = 0) { - m_capacity += m_capacity / 2 + extraCapacity; + int newCapacity = m_capacity + m_capacity / 2 + extraCapacity; + char* newBuffer; if (m_buffer == m_inlineBuffer) { - char* newBuffer = static_cast(malloc(m_capacity)); - m_buffer = static_cast(memcpy(newBuffer, m_buffer, m_size)); - } else - m_buffer = static_cast(realloc(m_buffer, m_capacity)); + newBuffer = static_cast(malloc(newCapacity)); + if (!newBuffer) { + m_size = 0; + m_oom = true; + return; + } + memcpy(newBuffer, m_buffer, m_size); + } else { + newBuffer = static_cast(realloc(m_buffer, newCapacity)); + if (!newBuffer) { + m_size = 0; + m_oom = true; + return; + } + } + + m_buffer = newBuffer; + m_capacity = newCapacity; } char m_inlineBuffer[inlineCapacity]; char* m_buffer; int m_capacity; int m_size; + bool m_oom; }; } // namespace JSC diff --git a/js/src/assembler/assembler/X86Assembler.h b/js/src/assembler/assembler/X86Assembler.h index 6147ab95dc3..6d4195c9fe2 100644 --- a/js/src/assembler/assembler/X86Assembler.h +++ b/js/src/assembler/assembler/X86Assembler.h @@ -363,6 +363,7 @@ public: size_t size() const { return m_formatter.size(); } unsigned char *buffer() const { return m_formatter.buffer(); } + bool oom() const { return m_formatter.oom(); } // Stack operations: @@ -2222,12 +2223,13 @@ public: void* executableCopy(ExecutablePool* allocator) { void* copy = m_formatter.executableCopy(allocator); - ASSERT(copy); return copy; } void* executableCopy(void* buffer) { + if (m_formatter.oom()) + return NULL; return memcpy(buffer, m_formatter.buffer(), size()); } @@ -2541,6 +2543,7 @@ private: size_t size() const { return m_buffer.size(); } unsigned char *buffer() const { return m_buffer.buffer(); } + bool oom() const { return m_buffer.oom(); } bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } void* data() const { return m_buffer.data(); } void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); } diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 35fe192c1d1..9c2ae6afcbd 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -67,6 +67,14 @@ using namespace js::mjit::ic; #define ADD_CALLSITE(stub) if (debugMode) addCallSite(__LINE__, (stub)) +#define RETURN_IF_OOM(retval) \ + JS_BEGIN_MACRO \ + if (masm.oom() || stubcc.masm.oom()) { \ + js_ReportOutOfMemory(cx); \ + return retval; \ + } \ + JS_END_MACRO + #if defined(JS_METHODJIT_SPEW) static const char *OpcodeNames[] = { # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) #name, @@ -319,6 +327,8 @@ mjit::Compiler::generateEpilogue() CompileStatus mjit::Compiler::finishThisUp(JITScript **jitp) { + RETURN_IF_OOM(Compile_Error); + for (size_t i = 0; i < branchPatches.length(); i++) { Label label = labelOf(branchPatches[i].pc); branchPatches[i].jump.linkTo(label, &masm); @@ -342,7 +352,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp) JSC::ExecutableAllocator::makeWritable(result, totalSize); masm.executableCopy(result); stubcc.masm.executableCopy(result + masm.size()); - + JSC::LinkBuffer fullCode(result, totalSize); JSC::LinkBuffer stubCode(result + masm.size(), stubcc.size()); @@ -955,7 +965,8 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_VOID) BEGIN_CASE(JSOP_INCNAME) - jsop_nameinc(op, STRICT_VARIANT(stubs::IncName), fullAtomIndex(PC)); + if (!jsop_nameinc(op, STRICT_VARIANT(stubs::IncName), fullAtomIndex(PC))) + return Compile_Error; break; END_CASE(JSOP_INCNAME) @@ -965,7 +976,8 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_INCGNAME) BEGIN_CASE(JSOP_INCPROP) - jsop_propinc(op, STRICT_VARIANT(stubs::IncProp), fullAtomIndex(PC)); + if (!jsop_propinc(op, STRICT_VARIANT(stubs::IncProp), fullAtomIndex(PC))) + return Compile_Error; break; END_CASE(JSOP_INCPROP) @@ -974,7 +986,8 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_INCELEM) BEGIN_CASE(JSOP_DECNAME) - jsop_nameinc(op, STRICT_VARIANT(stubs::DecName), fullAtomIndex(PC)); + if (!jsop_nameinc(op, STRICT_VARIANT(stubs::DecName), fullAtomIndex(PC))) + return Compile_Error; break; END_CASE(JSOP_DECNAME) @@ -984,7 +997,8 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_DECGNAME) BEGIN_CASE(JSOP_DECPROP) - jsop_propinc(op, STRICT_VARIANT(stubs::DecProp), fullAtomIndex(PC)); + if (!jsop_propinc(op, STRICT_VARIANT(stubs::DecProp), fullAtomIndex(PC))) + return Compile_Error; break; END_CASE(JSOP_DECPROP) @@ -993,7 +1007,8 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_DECELEM) BEGIN_CASE(JSOP_NAMEINC) - jsop_nameinc(op, STRICT_VARIANT(stubs::NameInc), fullAtomIndex(PC)); + if (!jsop_nameinc(op, STRICT_VARIANT(stubs::NameInc), fullAtomIndex(PC))) + return Compile_Error; break; END_CASE(JSOP_NAMEINC) @@ -1003,7 +1018,8 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_GNAMEINC) BEGIN_CASE(JSOP_PROPINC) - jsop_propinc(op, STRICT_VARIANT(stubs::PropInc), fullAtomIndex(PC)); + if (!jsop_propinc(op, STRICT_VARIANT(stubs::PropInc), fullAtomIndex(PC))) + return Compile_Error; break; END_CASE(JSOP_PROPINC) @@ -1012,7 +1028,8 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_ELEMINC) BEGIN_CASE(JSOP_NAMEDEC) - jsop_nameinc(op, STRICT_VARIANT(stubs::NameDec), fullAtomIndex(PC)); + if (!jsop_nameinc(op, STRICT_VARIANT(stubs::NameDec), fullAtomIndex(PC))) + return Compile_Error; break; END_CASE(JSOP_NAMEDEC) @@ -1022,7 +1039,8 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_GNAMEDEC) BEGIN_CASE(JSOP_PROPDEC) - jsop_propinc(op, STRICT_VARIANT(stubs::PropDec), fullAtomIndex(PC)); + if (!jsop_propinc(op, STRICT_VARIANT(stubs::PropDec), fullAtomIndex(PC))) + return Compile_Error; break; END_CASE(JSOP_PROPDEC) @@ -1033,30 +1051,36 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_GETTHISPROP) /* Push thisv onto stack. */ jsop_this(); - jsop_getprop(script->getAtom(fullAtomIndex(PC))); + if (!jsop_getprop(script->getAtom(fullAtomIndex(PC)))) + return Compile_Error; END_CASE(JSOP_GETTHISPROP); BEGIN_CASE(JSOP_GETARGPROP) /* Push arg onto stack. */ jsop_getarg(GET_SLOTNO(PC)); - jsop_getprop(script->getAtom(fullAtomIndex(&PC[ARGNO_LEN]))); + if (!jsop_getprop(script->getAtom(fullAtomIndex(&PC[ARGNO_LEN])))) + return Compile_Error; END_CASE(JSOP_GETARGPROP) BEGIN_CASE(JSOP_GETLOCALPROP) frame.pushLocal(GET_SLOTNO(PC)); - jsop_getprop(script->getAtom(fullAtomIndex(&PC[SLOTNO_LEN]))); + if (!jsop_getprop(script->getAtom(fullAtomIndex(&PC[SLOTNO_LEN])))) + return Compile_Error; END_CASE(JSOP_GETLOCALPROP) BEGIN_CASE(JSOP_GETPROP) - jsop_getprop(script->getAtom(fullAtomIndex(PC))); + if (!jsop_getprop(script->getAtom(fullAtomIndex(PC)))) + return Compile_Error; END_CASE(JSOP_GETPROP) BEGIN_CASE(JSOP_LENGTH) - jsop_length(); + if (!jsop_length()) + return Compile_Error; END_CASE(JSOP_LENGTH) BEGIN_CASE(JSOP_GETELEM) - jsop_getelem(); + if (!jsop_getelem()) + return Compile_Error; END_CASE(JSOP_GETELEM) BEGIN_CASE(JSOP_SETELEM) @@ -1347,12 +1371,14 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_BINDNAME) BEGIN_CASE(JSOP_SETPROP) - jsop_setprop(script->getAtom(fullAtomIndex(PC))); + if (!jsop_setprop(script->getAtom(fullAtomIndex(PC)))) + return Compile_Error; END_CASE(JSOP_SETPROP) BEGIN_CASE(JSOP_SETNAME) BEGIN_CASE(JSOP_SETMETHOD) - jsop_setprop(script->getAtom(fullAtomIndex(PC))); + if (!jsop_setprop(script->getAtom(fullAtomIndex(PC)))) + return Compile_Error; END_CASE(JSOP_SETNAME) BEGIN_CASE(JSOP_THROW) @@ -1370,7 +1396,8 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_IN) BEGIN_CASE(JSOP_INSTANCEOF) - jsop_instanceof(); + if (!jsop_instanceof()) + return Compile_Error; END_CASE(JSOP_INSTANCEOF) BEGIN_CASE(JSOP_EXCEPTION) @@ -1598,7 +1625,8 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_STOP) BEGIN_CASE(JSOP_GETXPROP) - jsop_xname(script->getAtom(fullAtomIndex(PC))); + if (!jsop_xname(script->getAtom(fullAtomIndex(PC)))) + return Compile_Error; END_CASE(JSOP_GETXPROP) BEGIN_CASE(JSOP_ENTERBLOCK) @@ -1703,8 +1731,10 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_GLOBALINC) BEGIN_CASE(JSOP_BEGIN) - if (isConstructing) - constructThis(); + if (isConstructing) { + if (!constructThis()) + return Compile_Error; + } END_CASE(JSOP_BEGIN) default: @@ -2392,7 +2422,7 @@ mjit::Compiler::jsop_callprop_slow(JSAtom *atom) return true; } -void +bool mjit::Compiler::jsop_length() { FrameEntry *top = frame.peek(-1); @@ -2411,16 +2441,17 @@ mjit::Compiler::jsop_length() frame.pop(); frame.pushTypedPayload(JSVAL_TYPE_INT32, str); } - return; + return true; } #if defined JS_POLYIC - jsop_getprop(cx->runtime->atomState.lengthAtom); + return jsop_getprop(cx->runtime->atomState.lengthAtom); #else prepareStubCall(Uses(1)); stubCall(stubs::Length); frame.pop(); frame.pushSynced(); + return true; #endif } @@ -2439,7 +2470,7 @@ mjit::Compiler::passPICAddress(PICGenInfo &pic) pic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1); } -void +bool mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck) { FrameEntry *top = frame.peek(-1); @@ -2449,7 +2480,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck) JS_ASSERT_IF(atom == cx->runtime->atomState.lengthAtom, top->getKnownType() != JSVAL_TYPE_STRING); jsop_getprop_slow(); - return; + return true; } /* @@ -2477,6 +2508,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck) Jump j = masm.testObject(Assembler::NotEqual, reg); /* GETPROP_INLINE_TYPE_GUARD is used to patch the jmp, not cmp. */ + RETURN_IF_OOM(false); JS_ASSERT(masm.differenceBetween(pic.fastPathStart, masm.label()) == GETPROP_INLINE_TYPE_GUARD); pic.typeCheck = stubcc.linkExit(j, Uses(1)); @@ -2536,8 +2568,8 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck) #endif pic.storeBack = masm.label(); - /* Assert correctness of hardcoded offsets. */ + RETURN_IF_OOM(false); #if defined JS_NUNBOX32 JS_ASSERT(masm.differenceBetween(pic.storeBack, dbgDslotsLoad) == GETPROP_DSLOTS_LOAD); JS_ASSERT(masm.differenceBetween(pic.storeBack, dbgTypeLoad) == GETPROP_TYPE_LOAD); @@ -2564,10 +2596,11 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck) stubcc.rejoin(Changes(1)); pics.append(pic); + return true; } #ifdef JS_POLYIC -void +bool mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID objReg, RegisterID idReg, RegisterID shapeReg) { @@ -2637,6 +2670,7 @@ mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID obj pic.objReg = objReg; pic.idReg = idReg; + RETURN_IF_OOM(false); #if defined JS_NUNBOX32 JS_ASSERT(masm.differenceBetween(pic.storeBack, dbgDslotsLoad) == GETELEM_DSLOTS_LOAD); JS_ASSERT(masm.differenceBetween(pic.storeBack, dbgTypeLoad) == GETELEM_TYPE_LOAD); @@ -2668,6 +2702,7 @@ mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID obj JS_ASSERT(pic.objReg != pic.shapeReg); pics.append(pic); + return true; } #endif @@ -2768,6 +2803,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom) pic.storeBack = masm.label(); /* Assert correctness of hardcoded offsets. */ + RETURN_IF_OOM(false); JS_ASSERT(masm.differenceBetween(pic.fastPathStart, dbgInlineTypeGuard) == GETPROP_INLINE_TYPE_GUARD); #if defined JS_NUNBOX32 JS_ASSERT(masm.differenceBetween(pic.storeBack, dbgDslotsLoad) == GETPROP_DSLOTS_LOAD); @@ -2814,7 +2850,8 @@ mjit::Compiler::jsop_callprop_str(JSAtom *atom) frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg); /* Get the property. */ - jsop_getprop(atom); + if (!jsop_getprop(atom)) + return false; /* Perform a swap. */ frame.dup2(); @@ -2926,6 +2963,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom) * Assert correctness of hardcoded offsets. * No type guard: type is asserted. */ + RETURN_IF_OOM(false); #if defined JS_NUNBOX32 JS_ASSERT(masm.differenceBetween(pic.storeBack, dbgDslotsLoad) == GETPROP_DSLOTS_LOAD); JS_ASSERT(masm.differenceBetween(pic.storeBack, dbgTypeLoad) == GETPROP_TYPE_LOAD); @@ -2968,7 +3006,7 @@ mjit::Compiler::jsop_callprop(JSAtom *atom) return jsop_callprop_generic(atom); } -void +bool mjit::Compiler::jsop_setprop(JSAtom *atom) { FrameEntry *lhs = frame.peek(-2); @@ -2977,7 +3015,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom) /* If the incoming type will never PIC, take slow path. */ if (lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_OBJECT) { jsop_setprop_slow(atom); - return; + return true; } JSOp op = JSOp(*PC); @@ -3083,6 +3121,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom) stubcc.rejoin(Changes(1)); } + RETURN_IF_OOM(false); #if defined JS_PUNBOX64 pic.labels.setprop.dslotsLoadOffset = masm.differenceBetween(pic.storeBack, dslotsLoadLabel); pic.labels.setprop.inlineShapeOffset = masm.differenceBetween(pic.shapeGuard, inlineShapeOffsetLabel); @@ -3108,6 +3147,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom) #endif pics.append(pic); + return true; } void @@ -3142,15 +3182,14 @@ mjit::Compiler::jsop_name(JSAtom *atom) pics.append(pic); } -void +bool mjit::Compiler::jsop_xname(JSAtom *atom) { PICGenInfo pic(ic::PICInfo::XNAME); FrameEntry *fe = frame.peek(-1); if (fe->isNotType(JSVAL_TYPE_OBJECT)) { - jsop_getprop(atom); - return; + return jsop_getprop(atom); } if (!fe->isTypeKnown()) { @@ -3184,6 +3223,7 @@ mjit::Compiler::jsop_xname(JSAtom *atom) stubcc.rejoin(Changes(1)); pics.append(pic); + return true; } void @@ -3243,16 +3283,17 @@ mjit::Compiler::jsop_name(JSAtom *atom) frame.pushSynced(); } -void +bool mjit::Compiler::jsop_xname(JSAtom *atom) { - jsop_getprop(atom); + return jsop_getprop(atom); } -void +bool mjit::Compiler::jsop_getprop(JSAtom *atom, bool typecheck) { jsop_getprop_slow(); + return true; } bool @@ -3261,10 +3302,11 @@ mjit::Compiler::jsop_callprop(JSAtom *atom) return jsop_callprop_slow(atom); } -void +bool mjit::Compiler::jsop_setprop(JSAtom *atom) { jsop_setprop_slow(atom); + return true; } void @@ -3401,7 +3443,7 @@ mjit::Compiler::jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index) PC += JSOP_GNAMEINC_LENGTH; } -void +bool mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index) { JSAtom *atom = script->getAtom(index); @@ -3435,7 +3477,8 @@ mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index) frame.shift(-1); // OBJ V+1 - jsop_setprop(atom); + if (!jsop_setprop(atom)) + return false; // V+1 if (pop) @@ -3470,7 +3513,8 @@ mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index) frame.shift(-1); // N OBJ N+1 - jsop_setprop(atom); + if (!jsop_setprop(atom)) + return false; // N N+1 frame.pop(); @@ -3487,9 +3531,10 @@ mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index) #endif PC += JSOP_NAMEINC_LENGTH; + return true; } -void +bool mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index) { JSAtom *atom = script->getAtom(index); @@ -3506,7 +3551,8 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index) frame.dup(); // OBJ OBJ - jsop_getprop(atom); + if (!jsop_getprop(atom)) + return false; // OBJ V frame.push(Int32Value(amt)); @@ -3516,7 +3562,8 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index) jsop_binary(JSOP_SUB, stubs::Sub); // OBJ V+1 - jsop_setprop(atom); + if (!jsop_setprop(atom)) + return false; // V+1 if (pop) @@ -3527,7 +3574,8 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index) frame.dup(); // OBJ OBJ - jsop_getprop(atom); + if (!jsop_getprop(atom)) + return false; // OBJ V jsop_pos(); @@ -3548,7 +3596,8 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index) frame.dupAt(-2); // OBJ N N+1 OBJ N+1 - jsop_setprop(atom); + if (!jsop_setprop(atom)) + return false; // OBJ N N+1 N+1 frame.popn(2); @@ -3570,6 +3619,7 @@ mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index) } PC += JSOP_PROPINC_LENGTH; + return true; } void @@ -4124,7 +4174,7 @@ mjit::Compiler::jsop_unbrand() stubCall(stubs::Unbrand); } -void +bool mjit::Compiler::jsop_instanceof() { FrameEntry *lhs = frame.peek(-2); @@ -4137,7 +4187,7 @@ mjit::Compiler::jsop_instanceof() frame.popn(2); frame.takeReg(Registers::ReturnReg); frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, Registers::ReturnReg); - return; + return true; } MaybeJump firstSlow; @@ -4164,7 +4214,8 @@ mjit::Compiler::jsop_instanceof() /* This is sadly necessary because the error case needs the object. */ frame.dup(); - jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false); + if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false)) + return false; /* Primitive prototypes are invalid. */ rhs = frame.peek(-1); @@ -4216,6 +4267,7 @@ mjit::Compiler::jsop_instanceof() if (firstSlow.isSet()) firstSlow.getJump().linkTo(stubcc.masm.label(), &stubcc.masm); stubcc.rejoin(Changes(1)); + return true; } /* @@ -4341,7 +4393,7 @@ mjit::Compiler::leaveBlock() // NULL // call js_CreateThisFromFunctionWithProto(...) // -void +bool mjit::Compiler::constructThis() { JS_ASSERT(isConstructing); @@ -4353,7 +4405,8 @@ mjit::Compiler::constructThis() frame.pushTypedPayload(JSVAL_TYPE_OBJECT, calleeReg); // Get callee.prototype. - jsop_getprop(cx->runtime->atomState.classPrototypeAtom); + if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom)) + return false; // Reach into the proto Value and grab a register for its data. FrameEntry *protoFe = frame.peek(-1); @@ -4373,5 +4426,6 @@ mjit::Compiler::constructThis() masm.move(protoReg, Registers::ArgReg1); stubCall(stubs::CreateThis); frame.freeReg(protoReg); + return true; } diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h index 7c702145e3d..ba2f0942d93 100644 --- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -271,7 +271,7 @@ class Compiler : public BaseCompiler #ifdef JS_MONOIC void passMICAddress(MICGenInfo &mic); #endif - void constructThis(); + bool constructThis(); /* Opcode handlers. */ void jumpAndTrace(Jump j, jsbytecode *target, Jump *slowOne = NULL, Jump *slowTwo = NULL); @@ -291,8 +291,8 @@ class Compiler : public BaseCompiler void inlineCallHelper(uint32 argc, bool callingNew); void fixPrimitiveReturn(Assembler *masm, FrameEntry *fe); void jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index); - void jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index); - void jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index); + bool jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index); + bool jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index); void jsop_eleminc(JSOp op, VoidStub); void jsop_getgname(uint32 index); void jsop_getgname_slow(uint32 index); @@ -302,18 +302,18 @@ class Compiler : public BaseCompiler void jsop_setelem_slow(); void jsop_getelem_slow(); void jsop_unbrand(); - void jsop_getprop(JSAtom *atom, bool typeCheck = true); - void jsop_length(); - void jsop_setprop(JSAtom *atom); + bool jsop_getprop(JSAtom *atom, bool typeCheck = true); + bool jsop_length(); + bool jsop_setprop(JSAtom *atom); void jsop_setprop_slow(JSAtom *atom); bool jsop_callprop_slow(JSAtom *atom); bool jsop_callprop(JSAtom *atom); bool jsop_callprop_obj(JSAtom *atom); bool jsop_callprop_str(JSAtom *atom); bool jsop_callprop_generic(JSAtom *atom); - void jsop_instanceof(); + bool jsop_instanceof(); void jsop_name(JSAtom *atom); - void jsop_xname(JSAtom *atom); + bool jsop_xname(JSAtom *atom); void enterBlock(JSObject *obj); void leaveBlock(); @@ -365,11 +365,11 @@ class Compiler : public BaseCompiler void jsop_arginc(JSOp op, uint32 slot, bool popped); void jsop_localinc(JSOp op, uint32 slot, bool popped); void jsop_setelem(); - void jsop_getelem(); - void jsop_getelem_known_type(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg); - void jsop_getelem_with_pic(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg); + bool jsop_getelem(); + bool jsop_getelem_known_type(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg); + bool jsop_getelem_with_pic(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg); void jsop_getelem_nopic(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg); - void jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID objReg, RegisterID idReg, + bool jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID objReg, RegisterID idReg, RegisterID shapeReg); void jsop_getelem_dense(FrameEntry *obj, FrameEntry *id, RegisterID objReg, MaybeRegisterID &idReg, RegisterID shapeReg); diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp index e96e2af45af..ef6c30e0b9f 100644 --- a/js/src/methodjit/FastOps.cpp +++ b/js/src/methodjit/FastOps.cpp @@ -1398,7 +1398,7 @@ mjit::Compiler::jsop_getelem_dense(FrameEntry *obj, FrameEntry *id, RegisterID o /* Note: linkExits will be hooked up to a leave() after this method completes. */ } -void +bool mjit::Compiler::jsop_getelem_known_type(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg) { switch (id->getKnownType()) { @@ -1421,7 +1421,7 @@ mjit::Compiler::jsop_getelem_known_type(FrameEntry *obj, FrameEntry *id, Registe frame.popn(2); frame.pushRegs(tmpReg, objReg); stubcc.rejoin(Changes(1)); - return; + break; } #ifdef JS_POLYIC case JSVAL_TYPE_STRING: @@ -1431,23 +1431,25 @@ mjit::Compiler::jsop_getelem_known_type(FrameEntry *obj, FrameEntry *id, Registe RegisterID idReg = frame.copyDataIntoReg(id); /* Meat. */ - jsop_getelem_pic(obj, id, objReg, idReg, tmpReg); + if (!jsop_getelem_pic(obj, id, objReg, idReg, tmpReg)) + return false; /* Epilogue. */ frame.popn(2); frame.pushRegs(tmpReg, objReg); frame.freeReg(idReg); stubcc.rejoin(Changes(1)); - return; + break; } #endif default: JS_NOT_REACHED("Invalid known id type."); } + return true; } #ifdef JS_POLYIC -void +bool mjit::Compiler::jsop_getelem_with_pic(FrameEntry *obj, FrameEntry *id, RegisterID tmpReg) { JS_ASSERT(!id->isTypeKnown()); @@ -1472,13 +1474,15 @@ mjit::Compiler::jsop_getelem_with_pic(FrameEntry *obj, FrameEntry *id, RegisterI stubcc.call(stubs::GetElem); Jump toFinalMerge = stubcc.masm.jump(); - jsop_getelem_pic(obj, id, objReg, idReg.reg(), tmpReg); + if (!jsop_getelem_pic(obj, id, objReg, idReg.reg(), tmpReg)) + return false; performedDense.linkTo(masm.label(), &masm); frame.popn(2); frame.pushRegs(tmpReg, objReg); frame.freeReg(idReg.reg()); toFinalMerge.linkTo(stubcc.masm.label(), &stubcc.masm); stubcc.rejoin(Changes(1)); + return true; } #endif @@ -1504,7 +1508,7 @@ mjit::Compiler::jsop_getelem_nopic(FrameEntry *obj, FrameEntry *id, RegisterID t stubcc.rejoin(Changes(1)); } -void +bool mjit::Compiler::jsop_getelem() { FrameEntry *obj = frame.peek(-2); @@ -1512,7 +1516,7 @@ mjit::Compiler::jsop_getelem() if (obj->isTypeKnown() && obj->getKnownType() != JSVAL_TYPE_OBJECT) { jsop_getelem_slow(); - return; + return true; } if (id->isTypeKnown() && @@ -1522,19 +1526,19 @@ mjit::Compiler::jsop_getelem() #endif )) { jsop_getelem_slow(); - return; + return true; } if (id->isTypeKnown() && id->getKnownType() == JSVAL_TYPE_INT32 && id->isConstant() && id->getValue().toInt32() < 0) { jsop_getelem_slow(); - return; + return true; } if (id->isTypeKnown() && id->getKnownType() == JSVAL_TYPE_STRING && id->isConstant()) { /* Never happens, or I'd optimize it. */ jsop_getelem_slow(); - return; + return true; } RegisterID tmpReg; @@ -1552,7 +1556,8 @@ mjit::Compiler::jsop_getelem() #ifdef JS_POLYIC return jsop_getelem_with_pic(obj, id, tmpReg); #else - return jsop_getelem_nopic(obj, id, tmpReg); + jsop_getelem_nopic(obj, id, tmpReg); + return true; #endif } diff --git a/js/src/yarr/yarr/RegexJIT.cpp b/js/src/yarr/yarr/RegexJIT.cpp index 6b7caa3ea6f..480e42f7dcb 100644 --- a/js/src/yarr/yarr/RegexJIT.cpp +++ b/js/src/yarr/yarr/RegexJIT.cpp @@ -1523,6 +1523,11 @@ public: { generate(); + if (oom()) { + m_shouldFallBack = true; + return; + } + ExecutablePool *executablePool = allocator.poolForSize(size()); if (!executablePool) { m_shouldFallBack = true;