From 74fa9a367b09505acb786b1155dfbb0c0d689bc0 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 6 May 2013 22:20:26 -0400 Subject: [PATCH] Backed out changeset 4ca9a6bd8f64 (bug 865059) for jsreftest crashes. --- js/src/frontend/BytecodeEmitter.cpp | 9 --- js/src/ion/BaselineInspector.cpp | 14 ---- js/src/ion/BaselineInspector.h | 1 - js/src/ion/IonBuilder.cpp | 52 ++++++-------- js/src/ion/IonFrames.cpp | 3 - js/src/ion/MCallOptimize.cpp | 2 +- js/src/ion/MIR.h | 2 +- js/src/jsanalyze.cpp | 24 ++++++- js/src/jsanalyze.h | 14 +++- js/src/jscntxt.h | 1 - js/src/jscompartment.h | 6 -- js/src/jsinfer.cpp | 102 +++++++--------------------- js/src/jsinfer.h | 16 ----- js/src/jsinferinlines.h | 55 +-------------- js/src/jsinterp.cpp | 6 +- js/src/jsobj.cpp | 8 +-- js/src/jsscript.h | 15 ++-- js/src/methodjit/Compiler.cpp | 9 +-- js/src/methodjit/InvokeHelpers.cpp | 4 -- js/src/methodjit/MonoIC.cpp | 2 +- js/src/shell/js.cpp | 15 ++-- js/src/vm/Xdr.h | 2 +- 22 files changed, 100 insertions(+), 262 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 411af3e13822..70f1dd61b9b8 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -4367,9 +4367,6 @@ EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) if (EmitJump(cx, bce, op, top - bce->offset()) < 0) return false; - if (!bce->tryNoteList.append(JSTRY_LOOP, bce->stackDepth, top, bce->offset())) - return false; - /* Now fixup all breaks and continues. */ return PopStatementBCE(cx, bce); } @@ -4556,9 +4553,6 @@ EmitDo(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (beq < 0) return false; - if (!bce->tryNoteList.append(JSTRY_LOOP, bce->stackDepth, top, bce->offset())) - return false; - /* * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex * note gets bigger. @@ -4615,9 +4609,6 @@ EmitWhile(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) if (beq < 0) return false; - if (!bce->tryNoteList.append(JSTRY_LOOP, bce->stackDepth, top, bce->offset())) - return false; - if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, beq - jmp)) return false; diff --git a/js/src/ion/BaselineInspector.cpp b/js/src/ion/BaselineInspector.cpp index 7a60a5274d28..b0596fa0c625 100644 --- a/js/src/ion/BaselineInspector.cpp +++ b/js/src/ion/BaselineInspector.cpp @@ -10,20 +10,6 @@ using namespace js; using namespace js::ion; -bool -SetElemICInspector::sawOOBDenseWrite() const -{ - if (!icEntry_) - return false; - - // Check for a SetElem_DenseAdd stub. - for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) { - if (stub->isSetElem_DenseAdd()) - return true; - } - return false; -} - bool SetElemICInspector::sawOOBTypedArrayWrite() const { diff --git a/js/src/ion/BaselineInspector.h b/js/src/ion/BaselineInspector.h index 9cc0c0e8976e..70aa3edd81a2 100644 --- a/js/src/ion/BaselineInspector.h +++ b/js/src/ion/BaselineInspector.h @@ -39,7 +39,6 @@ class SetElemICInspector : public ICInspector : ICInspector(inspector, pc, icEntry) { } - bool sawOOBDenseWrite() const; bool sawOOBTypedArrayWrite() const; }; diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp index 95086aa4657e..f146468fef7b 100644 --- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -197,7 +197,7 @@ IonBuilder::canEnterInlinedFunction(JSFunction *target) { RootedScript targetScript(cx, target->nonLazyScript()); - if (!targetScript->ensureRanAnalysis(cx)) + if (!targetScript->hasAnalysis()) return false; if (!targetScript->analysis()->ionInlineable()) @@ -313,7 +313,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock *entry, jsbytecode *start, jsbytecod MPhi *phi = entry->getSlot(slot)->toPhi(); if (js_CodeSpec[*last].format & JOF_TYPESET) { - types::StackTypeSet *typeSet = types::TypeScript::BytecodeTypes(script(), last); + types::StackTypeSet *typeSet = script()->analysis()->bytecodeTypes(last); if (!typeSet->empty()) { MIRType type = MIRTypeFromValueType(typeSet->getKnownTypeTag()); phi->addBackedgeType(type, typeSet); @@ -427,9 +427,6 @@ IonBuilder::pushLoop(CFGState::State initial, jsbytecode *stopAt, MBasicBlock *e bool IonBuilder::build() { - if (!script()->ensureHasBytecodeTypeMap(cx)) - return false; - setCurrentAndSpecializePhis(newBlock(pc)); if (!current) return false; @@ -4554,7 +4551,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc) if (!resumeAfter(apply)) return false; - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); return pushTypeBarrier(apply, types, true); } @@ -4875,7 +4872,7 @@ IonBuilder::makeCall(HandleFunction target, CallInfo &callInfo, bool cloneAtCall if (!resumeAfter(call)) return false; - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); bool barrier = true; if (call->isDOMFunction()) { @@ -4968,7 +4965,7 @@ IonBuilder::jsop_eval(uint32_t argc) current->add(ins); current->push(ins); - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); return resumeAfter(ins) && pushTypeBarrier(ins, types, true); } @@ -5021,7 +5018,7 @@ IonBuilder::jsop_newarray(uint32_t count) return false; types::StackTypeSet::DoubleConversion conversion = - types::TypeScript::BytecodeTypes(script(), pc)->convertDoubleElements(cx); + script()->analysis()->bytecodeTypes(pc)->convertDoubleElements(cx); if (conversion == types::StackTypeSet::AlwaysConvertToDoubles) templateObject->setShouldConvertDoubleElements(); @@ -5422,10 +5419,7 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool bool haveValue = false; Value existingValue; - if (info().fun() && i == info().thisSlot()) { - haveValue = true; - existingValue = fp.thisValue(); - } else { + { uint32_t arg = i - info().firstArgSlot(); uint32_t var = i - info().firstLocalSlot(); if (arg < info().nargs()) { @@ -5826,7 +5820,7 @@ IonBuilder::jsop_getgname(HandlePropertyName name) return jsop_getname(name); } - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); bool barrier = PropertyReadNeedsTypeBarrier(cx, globalType, name, types); // If the property is permanent, a shape guard isn't necessary. @@ -6001,14 +5995,14 @@ IonBuilder::jsop_getname(HandlePropertyName name) if (!resumeAfter(ins)) return false; - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); return pushTypeBarrier(ins, types, true); } bool IonBuilder::jsop_intrinsic(HandlePropertyName name) { - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); JSValueType type = types->getKnownTypeTag(); // If we haven't executed this opcode yet, we need to get the intrinsic @@ -6104,7 +6098,7 @@ IonBuilder::jsop_getelem() MInstruction *ins; - bool cacheable = obj->mightBeType(MIRType_Object) && !obj->mightBeType(MIRType_String) && + bool cacheable = obj->type() == MIRType_Object && (index->mightBeType(MIRType_Int32) || index->mightBeType(MIRType_String)); // Turn off cacheing if the element is int32 and we've seen non-native objects as the target @@ -6112,7 +6106,7 @@ IonBuilder::jsop_getelem() if (index->mightBeType(MIRType_Int32) && script()->analysis()->getCode(pc).nonNativeGetElement) cacheable = false; - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); bool barrier = PropertyReadNeedsTypeBarrier(cx, obj, NULL, types); // Always add a barrier if the index might be a string, so that the cache @@ -6150,7 +6144,7 @@ IonBuilder::jsop_getelem_dense() MDefinition *id = current->pop(); MDefinition *obj = current->pop(); - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); bool barrier = PropertyReadNeedsTypeBarrier(cx, obj, NULL, types); bool needsHoleCheck = !ElementAccessIsPacked(cx, obj); @@ -6338,7 +6332,7 @@ IonBuilder::jsop_getelem_typed(int arrayType) if (staticAccess) return true; - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); MDefinition *id = current->pop(); MDefinition *obj = current->pop(); @@ -6505,15 +6499,11 @@ IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion, MElements *elements = MElements::New(obj); current->add(elements); - bool writeHole = script()->analysis()->getCode(pc).arrayWriteHole; - SetElemICInspector icInspect(inspector->setElemICInspector(pc)); - writeHole |= icInspect.sawOOBDenseWrite(); - // Use MStoreElementHole if this SETELEM has written to out-of-bounds // indexes in the past. Otherwise, use MStoreElement so that we can hoist // the initialized length and bounds check. MStoreElementCommon *store; - if (writeHole && writeOutOfBounds) { + if (script()->analysis()->getCode(pc).arrayWriteHole && writeOutOfBounds) { MStoreElementHole *ins = MStoreElementHole::New(obj, elements, id, newValue); store = ins; @@ -6654,7 +6644,7 @@ IonBuilder::jsop_length() bool IonBuilder::jsop_length_fastPath() { - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); if (types->getKnownTypeTag() != JSVAL_TYPE_INT32) return false; @@ -6758,7 +6748,7 @@ IonBuilder::jsop_arguments_getelem() current->add(load); current->push(load); - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); return pushTypeBarrier(load, types, true); } @@ -7172,7 +7162,7 @@ IonBuilder::jsop_getprop(HandlePropertyName name) bool emitted = false; - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); // Try to optimize arguments.length. if (!getPropTryArgumentsLength(&emitted) || emitted) @@ -7756,9 +7746,7 @@ IonBuilder::jsop_this() } types::StackTypeSet *types = types::TypeScript::ThisTypes(script()); - if (types && (types->getKnownTypeTag() == JSVAL_TYPE_OBJECT || - (types->empty() && fp && fp.thisValue().isObject()))) - { + if (types && types->getKnownTypeTag() == JSVAL_TYPE_OBJECT) { // This is safe, because if the entry type of |this| is an object, it // will necessarily be an object throughout the entire function. OSR // can introduce a phi, but this phi will be specialized. @@ -7895,7 +7883,7 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc) current->add(load); current->push(load); - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); + types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc); return pushTypeBarrier(load, types, true); } diff --git a/js/src/ion/IonFrames.cpp b/js/src/ion/IonFrames.cpp index 7c2ddb979ccf..26210157b089 100644 --- a/js/src/ion/IonFrames.cpp +++ b/js/src/ion/IonFrames.cpp @@ -435,9 +435,6 @@ HandleException(JSContext *cx, const IonFrameIterator &frame, ResumeFromExceptio break; } - case JSTRY_LOOP: - break; - default: JS_NOT_REACHED("Invalid try note"); } diff --git a/js/src/ion/MCallOptimize.cpp b/js/src/ion/MCallOptimize.cpp index 10adfa5a28df..25209fd8228f 100644 --- a/js/src/ion/MCallOptimize.cpp +++ b/js/src/ion/MCallOptimize.cpp @@ -119,7 +119,7 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native) types::StackTypeSet * IonBuilder::getInlineReturnTypeSet() { - return types::TypeScript::BytecodeTypes(script(), pc); + return script()->analysis()->bytecodeTypes(pc); } MIRType diff --git a/js/src/ion/MIR.h b/js/src/ion/MIR.h index 0e1252c42bad..edf21e5cb6c1 100644 --- a/js/src/ion/MIR.h +++ b/js/src/ion/MIR.h @@ -2737,7 +2737,7 @@ class MBitXor : public MBinaryBitwiseInstruction return this; } MDefinition *foldIfEqual() { - return this; + return MConstant::New(Int32Value(0)); } }; diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp index 14c8200551ad..9d6a0443d494 100644 --- a/js/src/jsanalyze.cpp +++ b/js/src/jsanalyze.cpp @@ -191,6 +191,10 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx) startcode->stackDepth = 0; codeArray[0] = startcode; + /* Number of JOF_TYPESET opcodes we have encountered. */ + unsigned nTypeSets = 0; + types::TypeSet *typeArray = script_->types->typeArray(); + unsigned offset, nextOffset = 0; while (nextOffset < length) { offset = nextOffset; @@ -267,6 +271,22 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx) stackDepth += ndefs; } + /* + * Assign an observed type set to each reachable JOF_TYPESET opcode. + * This may be less than the number of type sets in the script if some + * are unreachable, and may be greater in case the number of type sets + * overflows a uint16_t. In the latter case a single type set will be + * used for the observed types of all ops after the overflow. + */ + if ((js_CodeSpec[op].format & JOF_TYPESET) && cx->typeInferenceEnabled()) { + if (nTypeSets < script_->nTypeSets) { + code->observedTypes = typeArray[nTypeSets++].toStackTypeSet(); + } else { + JS_ASSERT(nTypeSets == UINT16_MAX); + code->observedTypes = typeArray[nTypeSets - 1].toStackTypeSet(); + } + } + switch (op) { case JSOP_RETURN: @@ -373,7 +393,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx) if (catchOffset > forwardCatch) forwardCatch = catchOffset; - if (tn->kind != JSTRY_ITER && tn->kind != JSTRY_LOOP) { + if (tn->kind != JSTRY_ITER) { if (!addJump(cx, catchOffset, &nextOffset, &forwardJump, &forwardLoop, stackDepth)) return; getCode(catchOffset).exceptionEntry = true; @@ -1475,7 +1495,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx) if (startOffset == offset + 1) { unsigned catchOffset = startOffset + tn->length; - if (tn->kind != JSTRY_ITER && tn->kind != JSTRY_LOOP) { + if (tn->kind != JSTRY_ITER) { checkBranchTarget(cx, catchOffset, branchTargets, values, stackDepth); checkExceptionTarget(cx, catchOffset, exceptionTargets); } diff --git a/js/src/jsanalyze.h b/js/src/jsanalyze.h index 504ecedbd8e4..44d8e9469b64 100644 --- a/js/src/jsanalyze.h +++ b/js/src/jsanalyze.h @@ -122,8 +122,13 @@ class Bytecode private: - /* If this is a JSOP_LOOPHEAD or JSOP_LOOPENTRY, information about the loop. */ - LoopAnalysis *loop; + union { + /* If this is a JOF_TYPESET opcode, index into the observed types for the op. */ + types::StackTypeSet *observedTypes; + + /* If this is a JSOP_LOOPHEAD or JSOP_LOOPENTRY, information about the loop. */ + LoopAnalysis *loop; + }; /* --------- Lifetime analysis --------- */ @@ -881,6 +886,11 @@ class ScriptAnalysis return (cs->format & JOF_POST) && !popGuaranteed(pc); } + types::StackTypeSet *bytecodeTypes(const jsbytecode *pc) { + JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET); + return getCode(pc).observedTypes; + } + const SSAValue &poppedValue(uint32_t offset, uint32_t which) { JS_ASSERT(offset < script_->length); JS_ASSERT(which < GetUseCount(script_, offset) + diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index a236c6d71bab..fac69eddf9e6 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1752,7 +1752,6 @@ struct JSContext : js::ContextFriendFields, #endif inline bool typeInferenceEnabled() const; - inline bool jaegerCompilationAllowed() const; void updateJITEnabled(); diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index ec486810be1e..fe5a0b4e4633 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -411,12 +411,6 @@ JSContext::typeInferenceEnabled() const return compartment->zone()->types.inferenceEnabled; } -inline bool -JSContext::jaegerCompilationAllowed() const -{ - return compartment->zone()->types.jaegerCompilationAllowed; -} - inline js::Handle JSContext::global() const { diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 4d145a4b9d93..53970a767efb 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -1274,7 +1274,7 @@ PropertyAccess(JSContext *cx, JSScript *script, jsbytecode *pc, TypeObject *obje target->addSubset(cx, types); } else { JS_ASSERT_IF(script->hasAnalysis(), - target == TypeScript::BytecodeTypes(script, pc)); + target == script->analysis()->bytecodeTypes(pc)); if (!types->hasPropagatedProperty()) object->getFromPrototypes(cx, id, types); if (UsePropertyTypeBarrier(pc)) { @@ -1421,7 +1421,7 @@ TypeConstraintCall::newType(JSContext *cx, TypeSet *source, Type type) jsbytecode *pc = callsite->pc; JS_ASSERT_IF(script->hasAnalysis(), - callsite->returnTypes == TypeScript::BytecodeTypes(script, pc)); + callsite->returnTypes == script->analysis()->bytecodeTypes(pc)); if (type.isUnknown() || type.isAnyObject()) { /* Monitor calls on unknown functions. */ @@ -2467,12 +2467,10 @@ TypeZone::init(JSContext *cx) !cx->hasOption(JSOPTION_TYPE_INFERENCE) || !cx->runtime->jitSupportsFloatingPoint) { - jaegerCompilationAllowed = true; return; } inferenceEnabled = true; - jaegerCompilationAllowed = cx->hasOption(JSOPTION_METHODJIT); } TypeObject * @@ -2694,28 +2692,13 @@ types::UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc, if (key != JSProto_Object && !(key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray)) return GenericObject; - /* - * All loops in the script will have a JSTRY_ITER or JSTRY_LOOP try note - * indicating their boundary. - */ + AutoEnterAnalysis enter(cx); - if (!script->hasTrynotes()) - return SingletonObject; + if (!script->ensureRanAnalysis(cx)) + return GenericObject; - unsigned offset = pc - script->code; - - JSTryNote *tn = script->trynotes()->vector; - JSTryNote *tnlimit = tn + script->trynotes()->length; - for (; tn < tnlimit; tn++) { - if (tn->kind != JSTRY_ITER && tn->kind != JSTRY_LOOP) - continue; - - unsigned startOffset = script->mainOffset + tn->start; - unsigned endOffset = startOffset + tn->length; - - if (offset >= startOffset && offset < endOffset) - return GenericObject; - } + if (script->analysis()->getCode(pc).inLoop) + return GenericObject; return SingletonObject; } @@ -4314,7 +4297,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen case JSOP_CALLGNAME: { jsid id = GetAtomId(cx, script, pc, 0); - StackTypeSet *seen = TypeScript::BytecodeTypes(script, pc); + StackTypeSet *seen = bytecodeTypes(pc); seen->addSubset(cx, &pushed[0]); /* @@ -4346,7 +4329,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen case JSOP_GETINTRINSIC: case JSOP_CALLNAME: case JSOP_CALLINTRINSIC: { - StackTypeSet *seen = TypeScript::BytecodeTypes(script, pc); + StackTypeSet *seen = bytecodeTypes(pc); addTypeBarrier(cx, pc, seen, Type::UnknownType()); seen->addSubset(cx, &pushed[0]); break; @@ -4375,7 +4358,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen break; case JSOP_GETXPROP: { - StackTypeSet *seen = TypeScript::BytecodeTypes(script, pc); + StackTypeSet *seen = bytecodeTypes(pc); addTypeBarrier(cx, pc, seen, Type::UnknownType()); seen->addSubset(cx, &pushed[0]); break; @@ -4429,7 +4412,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen * there is little benefit to maintaining a TypeSet for the aliased * variable. Instead, we monitor/barrier all reads unconditionally. */ - TypeScript::BytecodeTypes(script, pc)->addSubset(cx, &pushed[0]); + bytecodeTypes(pc)->addSubset(cx, &pushed[0]); break; case JSOP_SETALIASEDVAR: @@ -4445,7 +4428,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen break; case JSOP_REST: { - StackTypeSet *types = TypeScript::BytecodeTypes(script, pc); + StackTypeSet *types = script->analysis()->bytecodeTypes(pc); if (script->compileAndGo) { TypeObject *rest = TypeScript::InitObject(cx, script, pc, JSProto_Array); if (!rest) @@ -4479,7 +4462,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen case JSOP_GETPROP: case JSOP_CALLPROP: { jsid id = GetAtomId(cx, script, pc, 0); - StackTypeSet *seen = TypeScript::BytecodeTypes(script, pc); + StackTypeSet *seen = script->analysis()->bytecodeTypes(pc); HeapTypeSet *input = &script->types->propertyReadTypes[state.propertyReadIndex++]; poppedTypes(pc, 0)->addSubset(cx, input); @@ -4508,7 +4491,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen case JSOP_GETELEM: case JSOP_CALLELEM: { - StackTypeSet *seen = TypeScript::BytecodeTypes(script, pc); + StackTypeSet *seen = script->analysis()->bytecodeTypes(pc); /* Don't try to compute a precise callee for CALLELEM. */ if (op == JSOP_CALLELEM) @@ -4596,7 +4579,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen case JSOP_FUNCALL: case JSOP_FUNAPPLY: case JSOP_NEW: { - StackTypeSet *seen = TypeScript::BytecodeTypes(script, pc); + StackTypeSet *seen = script->analysis()->bytecodeTypes(pc); seen->addSubset(cx, &pushed[0]); /* Construct the base call information about this site. */ @@ -4644,7 +4627,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen case JSOP_NEWINIT: case JSOP_NEWARRAY: case JSOP_NEWOBJECT: { - StackTypeSet *types = TypeScript::BytecodeTypes(script, pc); + StackTypeSet *types = script->analysis()->bytecodeTypes(pc); types->addSubset(cx, &pushed[0]); bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && GET_UINT8(pc) == JSProto_Array)); @@ -4877,9 +4860,6 @@ ScriptAnalysis::analyzeTypes(JSContext *cx) return; } - if (!script_->ensureHasBytecodeTypeMap(cx)) - return; - /* * Set this early to avoid reentrance. Any failures are OOMs, and will nuke * all types in the compartment. @@ -5289,7 +5269,7 @@ AnalyzePoppedThis(JSContext *cx, SSAUseChain *use, Shape *shape = type->proto ? type->proto->nativeLookup(cx, id) : NULL; if (shape && shape->hasSlot()) { Value protov = type->proto->getSlot(shape->slot()); - TypeSet *types = TypeScript::BytecodeTypes(script, pc); + TypeSet *types = script->analysis()->bytecodeTypes(pc); types->addType(cx, GetValueType(cx, protov)); } @@ -5581,7 +5561,7 @@ ScriptAnalysis::printTypes(JSContext *cx) continue; if (js_CodeSpec[*pc].format & JOF_TYPESET) { - TypeSet *types = TypeScript::BytecodeTypes(script_, pc); + TypeSet *types = script_->analysis()->bytecodeTypes(pc); printf(" typeset %d:", (int) (types - script_->types->typeArray())); types->print(); printf("\n"); @@ -5633,11 +5613,6 @@ types::MarkIteratorUnknownSlow(JSContext *cx) AutoEnterAnalysis enter(cx); - if (!script->ensureHasTypes(cx)) { - cx->compartment->types.setPendingNukeTypes(cx); - return; - } - /* * This script is iterating over an actual Iterator or Generator object, or * an object with a custom __iterator__ hook. In such cases 'for in' loops @@ -5721,16 +5696,15 @@ void types::TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type) { JS_ASSERT(cx->typeInferenceEnabled()); - AutoEnterAnalysis enter(cx); /* Directly update associated type sets for applicable bytecodes. */ if (js_CodeSpec[*pc].format & JOF_TYPESET) { - if (!script->ensureHasBytecodeTypeMap(cx)) { + if (!script->ensureRanAnalysis(cx)) { cx->compartment->types.setPendingNukeTypes(cx); return; } - TypeSet *types = TypeScript::BytecodeTypes(script, pc); + TypeSet *types = script->analysis()->bytecodeTypes(pc); if (!types->hasType(type)) { InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s", script->id(), pc - script->code, TypeString(type)); @@ -5829,13 +5803,13 @@ types::TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const AutoEnterAnalysis enter(cx); - if (!script->ensureHasBytecodeTypeMap(cx)) { + if (!script->ensureRanAnalysis(cx)) { cx->compartment->types.setPendingNukeTypes(cx); return; } Type type = GetValueType(cx, rval); - TypeSet *types = TypeScript::BytecodeTypes(script, pc); + TypeSet *types = script->analysis()->bytecodeTypes(pc); if (types->hasType(type)) return; @@ -5932,7 +5906,7 @@ JSScript::makeTypes(JSContext *cx) return false; } new(types) TypeScript(); - return analyzedArgsUsage() || ensureRanAnalysis(cx); + return true; } AutoEnterAnalysis enter(cx); @@ -6002,36 +5976,6 @@ JSScript::makeTypes(JSContext *cx) } #endif - return analyzedArgsUsage() || ensureRanAnalysis(cx); -} - -bool -JSScript::makeBytecodeTypeMap(JSContext *cx) -{ - JS_ASSERT(cx->typeInferenceEnabled()); - JS_ASSERT(types && !types->bytecodeMap); - - types->bytecodeMap = cx->analysisLifoAlloc().newArrayUninitialized(nTypeSets + 1); - - if (!types->bytecodeMap) - return false; - - uint32_t added = 0; - for (jsbytecode *pc = code; pc < code + length; pc += GetBytecodeLength(pc)) { - JSOp op = JSOp(*pc); - if (js_CodeSpec[op].format & JOF_TYPESET) { - types->bytecodeMap[added++] = pc - code; - if (added == nTypeSets) - break; - } - } - - JS_ASSERT(added == nTypeSets); - - // The last entry in the last index found, and is used to avoid binary - // searches for the sought entry when queries are in linear order. - types->bytecodeMap[nTypeSets] = 0; - return true; } diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index f7e4119e438f..02351bb1bdc3 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -1177,12 +1177,6 @@ class TypeScript /* Analysis information for the script, cleared on each GC. */ analyze::ScriptAnalysis *analysis; - /* - * List mapping indexes of bytecode type sets to the offset of the opcode - * they correspond to. Cleared on each GC. - */ - uint32_t *bytecodeMap; - public: /* Dynamic types generated at points within this script. */ TypeResult *dynamicList; @@ -1207,9 +1201,6 @@ class TypeScript /* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */ static inline StackTypeSet *SlotTypes(JSScript *script, unsigned slot); - /* Get the type set for values observed at an opcode. */ - static inline StackTypeSet *BytecodeTypes(JSScript *script, jsbytecode *pc); - /* Get the default 'new' object for a given standard class, per the script's global. */ static inline TypeObject *StandardType(JSContext *cx, JSProtoKey kind); @@ -1475,13 +1466,6 @@ struct TypeZone /* Whether type inference is enabled in this compartment. */ bool inferenceEnabled; - /* - * JM compilation is allowed only if script analysis has been used to - * monitor the behavior of all scripts in this zone since its creation. - * OSR in JM requires this property. - */ - bool jaegerCompilationAllowed; - TypeZone(JS::Zone *zone); ~TypeZone(); void init(JSContext *cx); diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index c2891122ae76..7cd3ac186fb5 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -586,7 +586,7 @@ TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing) if (args.callee().isFunction()) { JSFunction *fun = args.callee().toFunction(); if (fun->isInterpreted()) { - if (!fun->nonLazyScript()->ensureHasTypes(cx)) + if (!fun->nonLazyScript()->ensureRanAnalysis(cx)) return false; if (cx->typeInferenceEnabled()) TypeMonitorCallSlow(cx, &args.callee(), args, constructing); @@ -858,49 +858,6 @@ TypeScript::SlotTypes(JSScript *script, unsigned slot) return types->toStackTypeSet(); } -/* static */ inline StackTypeSet * -TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc) -{ - JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET); - JS_ASSERT(script->types && script->types->bytecodeMap); - uint32_t *bytecodeMap = script->types->bytecodeMap; - uint32_t *hint = bytecodeMap + script->nTypeSets; - uint32_t offset = pc - script->code; - JS_ASSERT(offset < script->length); - - // See if this pc is the next typeset opcode after the last one looked up. - if (bytecodeMap[*hint + 1] == offset && (*hint + 1) < script->nTypeSets) { - (*hint)++; - return script->types->typeArray()->toStackTypeSet() + *hint; - } - - // See if this pc is the same as the last one looked up. - if (bytecodeMap[*hint] == offset) - return script->types->typeArray()->toStackTypeSet() + *hint; - - // Fall back to a binary search. - size_t bottom = 0; - size_t top = script->nTypeSets - 1; - size_t mid = (bottom + top) / 2; - while (mid < top) { - if (bytecodeMap[mid] < offset) - bottom = mid + 1; - else if (bytecodeMap[mid] > offset) - top = mid; - else - break; - mid = (bottom + top) / 2; - } - - // We should have have zeroed in on either the exact offset, unless there - // are more JOF_TYPESET opcodes than nTypeSets in the script (as can happen - // if the script is very long). - JS_ASSERT(bytecodeMap[mid] == offset || mid == top); - - *hint = mid; - return script->types->typeArray()->toStackTypeSet() + *hint; -} - /* static */ inline TypeObject * TypeScript::StandardType(JSContext *cx, JSProtoKey key) { @@ -1825,12 +1782,6 @@ JSScript::ensureHasTypes(JSContext *cx) return types || makeTypes(cx); } -inline bool -JSScript::ensureHasBytecodeTypeMap(JSContext *cx) -{ - return ensureHasTypes(cx) && (types->bytecodeMap || makeBytecodeTypeMap(cx)); -} - inline bool JSScript::ensureRanAnalysis(JSContext *cx) { @@ -1872,10 +1823,8 @@ JSScript::analysis() inline void JSScript::clearAnalysis() { - if (types) { + if (types) types->analysis = NULL; - types->bytecodeMap = NULL; - } } inline void diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index cf735bf67db7..5765a5deb33b 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -565,7 +565,7 @@ js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChainArg, c if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg)) return false; - if (!script->ensureHasTypes(cx)) + if (!script->ensureRanAnalysis(cx)) return false; TypeScript::SetThis(cx, script, efg.fp()->thisValue()); @@ -3366,11 +3366,7 @@ END_CASE(JSOP_ARRAYPUSH) regs.sp -= 1; if (!ok) goto error; - break; } - - case JSTRY_LOOP: - break; } } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index bc18b1ffe451..036114d30f55 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1520,9 +1520,7 @@ js::CreateThisForFunctionWithProto(JSContext *cx, HandleObject callee, JSObject } if (res && cx->typeInferenceEnabled()) { - JSScript *script = callee->toFunction()->nonLazyScript(); - if (!script->ensureHasTypes(cx)) - return NULL; + RootedScript script(cx, callee->toFunction()->nonLazyScript()); TypeScript::SetThis(cx, script, types::Type::ObjectType(res)); } @@ -1549,9 +1547,7 @@ js::CreateThisForFunction(JSContext *cx, HandleObject callee, bool newType) /* Reshape the singleton before passing it as the 'this' value. */ JSObject::clear(cx, nobj); - JSScript *calleeScript = callee->toFunction()->nonLazyScript(); - if (!calleeScript->ensureHasTypes(cx)) - return NULL; + RootedScript calleeScript(cx, callee->toFunction()->nonLazyScript()); TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(nobj)); return nobj; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 367098821e57..2b0f20100e33 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -49,15 +49,12 @@ namespace analyze { /* * Type of try note associated with each catch or finally block, and also with - * for-in and other kinds of loops. Non-for-in loops do not need these notes - * for exception unwinding, but storing their boundaries here is helpful for - * heuristics that need to know whether a given op is inside a loop. + * for-in loops. */ typedef enum JSTryNoteKind { JSTRY_CATCH, JSTRY_FINALLY, - JSTRY_ITER, - JSTRY_LOOP + JSTRY_ITER } JSTryNoteKind; /* @@ -67,9 +64,9 @@ struct JSTryNote { uint8_t kind; /* one of JSTryNoteKind */ uint8_t padding; /* explicit padding on uint16_t boundary */ uint16_t stackDepth; /* stack depth upon exception handler entry */ - uint32_t start; /* start of the try statement or loop + uint32_t start; /* start of the try statement or for-in loop relative to script->main */ - uint32_t length; /* length of the try statement or loop */ + uint32_t length; /* length of the try statement or for-in loop */ }; namespace js { @@ -720,9 +717,6 @@ class JSScript : public js::gc::Cell /* Ensure the script has a TypeScript. */ inline bool ensureHasTypes(JSContext *cx); - /* Ensure the script has a TypeScript and map for computing BytecodeTypes. */ - inline bool ensureHasBytecodeTypeMap(JSContext *cx); - /* * Ensure the script has bytecode analysis information. Performed when the * script first runs, or first runs after a TypeScript GC purge. @@ -764,7 +758,6 @@ class JSScript : public js::gc::Cell private: bool makeTypes(JSContext *cx); - bool makeBytecodeTypeMap(JSContext *cx); bool makeAnalysis(JSContext *cx); #ifdef JS_METHODJIT diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index e74ce5bb6af1..2c9f05b8cba7 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -121,8 +121,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, gcNumber(cx->runtime->gcNumber), pcLengths(NULL) { - JS_ASSERT(cx->jaegerCompilationAllowed()); - if (!IsIonEnabled(cx)) { /* Once a script starts getting really hot we will inline calls in it. */ if (!debugMode() && cx->typeInferenceEnabled() && globalObj && @@ -996,9 +994,6 @@ mjit::CanMethodJIT(JSContext *cx, JSScript *script, jsbytecode *pc, if (!cx->methodJitEnabled) return Compile_Abort; - if (!cx->jaegerCompilationAllowed()) - return Compile_Abort; - #ifdef JS_ION if (ion::IsBaselineEnabled(cx) || ion::IsEnabled(cx)) return Compile_Abort; @@ -8128,7 +8123,7 @@ mjit::Compiler::testBarrier(RegisterID typeReg, RegisterID dataReg, if (!cx->typeInferenceEnabled() || !(js_CodeSpec[*PC].format & JOF_TYPESET)) return state; - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script_, PC); + types::StackTypeSet *types = analysis->bytecodeTypes(PC); if (types->unknown()) { /* * If the result of this opcode is already unknown, there is no way for @@ -8193,7 +8188,7 @@ mjit::Compiler::testPushedType(RejoinState rejoin, int which, bool ool) if (!cx->typeInferenceEnabled() || !(js_CodeSpec[*PC].format & JOF_TYPESET)) return; - types::TypeSet *types = types::TypeScript::BytecodeTypes(script_, PC); + types::TypeSet *types = analysis->bytecodeTypes(PC); if (types->unknown()) return; diff --git a/js/src/methodjit/InvokeHelpers.cpp b/js/src/methodjit/InvokeHelpers.cpp index 87dfcd71951e..582558fb60f2 100644 --- a/js/src/methodjit/InvokeHelpers.cpp +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -115,11 +115,7 @@ FindExceptionHandler(JSContext *cx) cx->regs().sp -= 1; if (!ok) goto error; - break; } - - case JSTRY_LOOP: - break; } } } else { diff --git a/js/src/methodjit/MonoIC.cpp b/js/src/methodjit/MonoIC.cpp index debeb4957b2d..f9228fe5de30 100644 --- a/js/src/methodjit/MonoIC.cpp +++ b/js/src/methodjit/MonoIC.cpp @@ -437,7 +437,7 @@ mjit::NativeStubEpilogue(VMFrame &f, Assembler &masm, NativeStubLinker::FinalJum * the call. We don't assume knowledge about the types that natives can * return, except when generating specialized paths in FastBuiltins. */ - types::TypeSet *types = types::TypeScript::BytecodeTypes(f.script(), f.pc()); + types::TypeSet *types = f.script()->analysis()->bytecodeTypes(f.pc()); if (!masm.generateTypeCheck(f.cx, resultAddress, types, &mismatches)) THROWV(false); } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index de4e85abc5d2..c37eb426cee9 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1809,7 +1809,7 @@ JS_STATIC_ASSERT(JSTRY_CATCH == 0); JS_STATIC_ASSERT(JSTRY_FINALLY == 1); JS_STATIC_ASSERT(JSTRY_ITER == 2); -static const char* const TryNoteNames[] = { "catch", "finally", "iter", "loop" }; +static const char* const TryNoteNames[] = { "catch", "finally", "iter" }; static JSBool TryNotes(JSContext *cx, HandleScript script, Sprinter *sp) @@ -4927,6 +4927,11 @@ ProcessArgs(JSContext *cx, JSObject *obj_, OptionParser *op) if (op->getBoolOption('s')) JS_ToggleOptions(cx, JSOPTION_STRICT); + if (op->getBoolOption("no-jm")) { + enableMethodJit = false; + JS_ToggleOptions(cx, JSOPTION_METHODJIT); + } + if (op->getBoolOption('d')) { JS_SetRuntimeDebugMode(JS_GetRuntime(cx), true); JS_SetDebugMode(cx, true); @@ -5116,17 +5121,13 @@ Shell(JSContext *cx, OptionParser *op, char **envp) JSAutoRequest ar(cx); /* - * First check to see if type inference and JM are enabled. These flags - * must be set on the compartment when it is constructed. + * First check to see if type inference is enabled. This flag must be set + * on the compartment when it is constructed. */ if (op->getBoolOption("no-ti")) { enableTypeInference = false; JS_ToggleOptions(cx, JSOPTION_TYPE_INFERENCE); } - if (op->getBoolOption("no-jm")) { - enableMethodJit = false; - JS_ToggleOptions(cx, JSOPTION_METHODJIT); - } RootedObject glob(cx); glob = NewGlobalObject(cx, NULL); diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 0698e79fb633..24831c45350a 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -26,7 +26,7 @@ namespace js { * and saved versions. If deserialization fails, the data should be * invalidated if possible. */ -static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 142); +static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 141); class XDRBuffer { public: