mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changeset 4ca9a6bd8f64 (bug 865059) for jsreftest crashes.
This commit is contained in:
parent
0dbb3c55f6
commit
c7f7e6de00
@ -4367,9 +4367,6 @@ EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
|
|||||||
if (EmitJump(cx, bce, op, top - bce->offset()) < 0)
|
if (EmitJump(cx, bce, op, top - bce->offset()) < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!bce->tryNoteList.append(JSTRY_LOOP, bce->stackDepth, top, bce->offset()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Now fixup all breaks and continues. */
|
/* Now fixup all breaks and continues. */
|
||||||
return PopStatementBCE(cx, bce);
|
return PopStatementBCE(cx, bce);
|
||||||
}
|
}
|
||||||
@ -4556,9 +4553,6 @@ EmitDo(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||||||
if (beq < 0)
|
if (beq < 0)
|
||||||
return false;
|
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
|
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
|
||||||
* note gets bigger.
|
* note gets bigger.
|
||||||
@ -4615,9 +4609,6 @@ EmitWhile(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
|
|||||||
if (beq < 0)
|
if (beq < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!bce->tryNoteList.append(JSTRY_LOOP, bce->stackDepth, top, bce->offset()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, beq - jmp))
|
if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, beq - jmp))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -10,20 +10,6 @@
|
|||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::ion;
|
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
|
bool
|
||||||
SetElemICInspector::sawOOBTypedArrayWrite() const
|
SetElemICInspector::sawOOBTypedArrayWrite() const
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,6 @@ class SetElemICInspector : public ICInspector
|
|||||||
: ICInspector(inspector, pc, icEntry)
|
: ICInspector(inspector, pc, icEntry)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
bool sawOOBDenseWrite() const;
|
|
||||||
bool sawOOBTypedArrayWrite() const;
|
bool sawOOBTypedArrayWrite() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ IonBuilder::canEnterInlinedFunction(JSFunction *target)
|
|||||||
{
|
{
|
||||||
RootedScript targetScript(cx, target->nonLazyScript());
|
RootedScript targetScript(cx, target->nonLazyScript());
|
||||||
|
|
||||||
if (!targetScript->ensureRanAnalysis(cx))
|
if (!targetScript->hasAnalysis())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!targetScript->analysis()->ionInlineable())
|
if (!targetScript->analysis()->ionInlineable())
|
||||||
@ -313,7 +313,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock *entry, jsbytecode *start, jsbytecod
|
|||||||
MPhi *phi = entry->getSlot(slot)->toPhi();
|
MPhi *phi = entry->getSlot(slot)->toPhi();
|
||||||
|
|
||||||
if (js_CodeSpec[*last].format & JOF_TYPESET) {
|
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()) {
|
if (!typeSet->empty()) {
|
||||||
MIRType type = MIRTypeFromValueType(typeSet->getKnownTypeTag());
|
MIRType type = MIRTypeFromValueType(typeSet->getKnownTypeTag());
|
||||||
phi->addBackedgeType(type, typeSet);
|
phi->addBackedgeType(type, typeSet);
|
||||||
@ -427,9 +427,6 @@ IonBuilder::pushLoop(CFGState::State initial, jsbytecode *stopAt, MBasicBlock *e
|
|||||||
bool
|
bool
|
||||||
IonBuilder::build()
|
IonBuilder::build()
|
||||||
{
|
{
|
||||||
if (!script()->ensureHasBytecodeTypeMap(cx))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
setCurrentAndSpecializePhis(newBlock(pc));
|
setCurrentAndSpecializePhis(newBlock(pc));
|
||||||
if (!current)
|
if (!current)
|
||||||
return false;
|
return false;
|
||||||
@ -4554,7 +4551,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
|
|||||||
if (!resumeAfter(apply))
|
if (!resumeAfter(apply))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
|
||||||
return pushTypeBarrier(apply, types, true);
|
return pushTypeBarrier(apply, types, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4875,7 +4872,7 @@ IonBuilder::makeCall(HandleFunction target, CallInfo &callInfo, bool cloneAtCall
|
|||||||
if (!resumeAfter(call))
|
if (!resumeAfter(call))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
|
||||||
|
|
||||||
bool barrier = true;
|
bool barrier = true;
|
||||||
if (call->isDOMFunction()) {
|
if (call->isDOMFunction()) {
|
||||||
@ -4968,7 +4965,7 @@ IonBuilder::jsop_eval(uint32_t argc)
|
|||||||
current->add(ins);
|
current->add(ins);
|
||||||
current->push(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);
|
return resumeAfter(ins) && pushTypeBarrier(ins, types, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5021,7 +5018,7 @@ IonBuilder::jsop_newarray(uint32_t count)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
types::StackTypeSet::DoubleConversion conversion =
|
types::StackTypeSet::DoubleConversion conversion =
|
||||||
types::TypeScript::BytecodeTypes(script(), pc)->convertDoubleElements(cx);
|
script()->analysis()->bytecodeTypes(pc)->convertDoubleElements(cx);
|
||||||
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles)
|
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles)
|
||||||
templateObject->setShouldConvertDoubleElements();
|
templateObject->setShouldConvertDoubleElements();
|
||||||
|
|
||||||
@ -5422,10 +5419,7 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool
|
|||||||
|
|
||||||
bool haveValue = false;
|
bool haveValue = false;
|
||||||
Value existingValue;
|
Value existingValue;
|
||||||
if (info().fun() && i == info().thisSlot()) {
|
{
|
||||||
haveValue = true;
|
|
||||||
existingValue = fp.thisValue();
|
|
||||||
} else {
|
|
||||||
uint32_t arg = i - info().firstArgSlot();
|
uint32_t arg = i - info().firstArgSlot();
|
||||||
uint32_t var = i - info().firstLocalSlot();
|
uint32_t var = i - info().firstLocalSlot();
|
||||||
if (arg < info().nargs()) {
|
if (arg < info().nargs()) {
|
||||||
@ -5826,7 +5820,7 @@ IonBuilder::jsop_getgname(HandlePropertyName name)
|
|||||||
return jsop_getname(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);
|
bool barrier = PropertyReadNeedsTypeBarrier(cx, globalType, name, types);
|
||||||
|
|
||||||
// If the property is permanent, a shape guard isn't necessary.
|
// If the property is permanent, a shape guard isn't necessary.
|
||||||
@ -6001,14 +5995,14 @@ IonBuilder::jsop_getname(HandlePropertyName name)
|
|||||||
if (!resumeAfter(ins))
|
if (!resumeAfter(ins))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
|
||||||
return pushTypeBarrier(ins, types, true);
|
return pushTypeBarrier(ins, types, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IonBuilder::jsop_intrinsic(HandlePropertyName name)
|
IonBuilder::jsop_intrinsic(HandlePropertyName name)
|
||||||
{
|
{
|
||||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
|
||||||
JSValueType type = types->getKnownTypeTag();
|
JSValueType type = types->getKnownTypeTag();
|
||||||
|
|
||||||
// If we haven't executed this opcode yet, we need to get the intrinsic
|
// If we haven't executed this opcode yet, we need to get the intrinsic
|
||||||
@ -6104,7 +6098,7 @@ IonBuilder::jsop_getelem()
|
|||||||
|
|
||||||
MInstruction *ins;
|
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));
|
(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
|
// 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)
|
if (index->mightBeType(MIRType_Int32) && script()->analysis()->getCode(pc).nonNativeGetElement)
|
||||||
cacheable = false;
|
cacheable = false;
|
||||||
|
|
||||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
|
||||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, obj, NULL, types);
|
bool barrier = PropertyReadNeedsTypeBarrier(cx, obj, NULL, types);
|
||||||
|
|
||||||
// Always add a barrier if the index might be a string, so that the cache
|
// 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 *id = current->pop();
|
||||||
MDefinition *obj = 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 barrier = PropertyReadNeedsTypeBarrier(cx, obj, NULL, types);
|
||||||
bool needsHoleCheck = !ElementAccessIsPacked(cx, obj);
|
bool needsHoleCheck = !ElementAccessIsPacked(cx, obj);
|
||||||
|
|
||||||
@ -6338,7 +6332,7 @@ IonBuilder::jsop_getelem_typed(int arrayType)
|
|||||||
if (staticAccess)
|
if (staticAccess)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
|
||||||
|
|
||||||
MDefinition *id = current->pop();
|
MDefinition *id = current->pop();
|
||||||
MDefinition *obj = current->pop();
|
MDefinition *obj = current->pop();
|
||||||
@ -6505,15 +6499,11 @@ IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
|
|||||||
MElements *elements = MElements::New(obj);
|
MElements *elements = MElements::New(obj);
|
||||||
current->add(elements);
|
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
|
// Use MStoreElementHole if this SETELEM has written to out-of-bounds
|
||||||
// indexes in the past. Otherwise, use MStoreElement so that we can hoist
|
// indexes in the past. Otherwise, use MStoreElement so that we can hoist
|
||||||
// the initialized length and bounds check.
|
// the initialized length and bounds check.
|
||||||
MStoreElementCommon *store;
|
MStoreElementCommon *store;
|
||||||
if (writeHole && writeOutOfBounds) {
|
if (script()->analysis()->getCode(pc).arrayWriteHole && writeOutOfBounds) {
|
||||||
MStoreElementHole *ins = MStoreElementHole::New(obj, elements, id, newValue);
|
MStoreElementHole *ins = MStoreElementHole::New(obj, elements, id, newValue);
|
||||||
store = ins;
|
store = ins;
|
||||||
|
|
||||||
@ -6654,7 +6644,7 @@ IonBuilder::jsop_length()
|
|||||||
bool
|
bool
|
||||||
IonBuilder::jsop_length_fastPath()
|
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)
|
if (types->getKnownTypeTag() != JSVAL_TYPE_INT32)
|
||||||
return false;
|
return false;
|
||||||
@ -6758,7 +6748,7 @@ IonBuilder::jsop_arguments_getelem()
|
|||||||
current->add(load);
|
current->add(load);
|
||||||
current->push(load);
|
current->push(load);
|
||||||
|
|
||||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
|
||||||
return pushTypeBarrier(load, types, true);
|
return pushTypeBarrier(load, types, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7172,7 +7162,7 @@ IonBuilder::jsop_getprop(HandlePropertyName name)
|
|||||||
|
|
||||||
bool emitted = false;
|
bool emitted = false;
|
||||||
|
|
||||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
|
||||||
|
|
||||||
// Try to optimize arguments.length.
|
// Try to optimize arguments.length.
|
||||||
if (!getPropTryArgumentsLength(&emitted) || emitted)
|
if (!getPropTryArgumentsLength(&emitted) || emitted)
|
||||||
@ -7756,9 +7746,7 @@ IonBuilder::jsop_this()
|
|||||||
}
|
}
|
||||||
|
|
||||||
types::StackTypeSet *types = types::TypeScript::ThisTypes(script());
|
types::StackTypeSet *types = types::TypeScript::ThisTypes(script());
|
||||||
if (types && (types->getKnownTypeTag() == JSVAL_TYPE_OBJECT ||
|
if (types && types->getKnownTypeTag() == JSVAL_TYPE_OBJECT) {
|
||||||
(types->empty() && fp && fp.thisValue().isObject())))
|
|
||||||
{
|
|
||||||
// This is safe, because if the entry type of |this| is an object, it
|
// This is safe, because if the entry type of |this| is an object, it
|
||||||
// will necessarily be an object throughout the entire function. OSR
|
// will necessarily be an object throughout the entire function. OSR
|
||||||
// can introduce a phi, but this phi will be specialized.
|
// can introduce a phi, but this phi will be specialized.
|
||||||
@ -7895,7 +7883,7 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
|
|||||||
current->add(load);
|
current->add(load);
|
||||||
current->push(load);
|
current->push(load);
|
||||||
|
|
||||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
types::StackTypeSet *types = script()->analysis()->bytecodeTypes(pc);
|
||||||
return pushTypeBarrier(load, types, true);
|
return pushTypeBarrier(load, types, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,9 +435,6 @@ HandleException(JSContext *cx, const IonFrameIterator &frame, ResumeFromExceptio
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JSTRY_LOOP:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
JS_NOT_REACHED("Invalid try note");
|
JS_NOT_REACHED("Invalid try note");
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
|
|||||||
types::StackTypeSet *
|
types::StackTypeSet *
|
||||||
IonBuilder::getInlineReturnTypeSet()
|
IonBuilder::getInlineReturnTypeSet()
|
||||||
{
|
{
|
||||||
return types::TypeScript::BytecodeTypes(script(), pc);
|
return script()->analysis()->bytecodeTypes(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
MIRType
|
MIRType
|
||||||
|
@ -2737,7 +2737,7 @@ class MBitXor : public MBinaryBitwiseInstruction
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
MDefinition *foldIfEqual() {
|
MDefinition *foldIfEqual() {
|
||||||
return this;
|
return MConstant::New(Int32Value(0));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -191,6 +191,10 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
|||||||
startcode->stackDepth = 0;
|
startcode->stackDepth = 0;
|
||||||
codeArray[0] = startcode;
|
codeArray[0] = startcode;
|
||||||
|
|
||||||
|
/* Number of JOF_TYPESET opcodes we have encountered. */
|
||||||
|
unsigned nTypeSets = 0;
|
||||||
|
types::TypeSet *typeArray = script_->types->typeArray();
|
||||||
|
|
||||||
unsigned offset, nextOffset = 0;
|
unsigned offset, nextOffset = 0;
|
||||||
while (nextOffset < length) {
|
while (nextOffset < length) {
|
||||||
offset = nextOffset;
|
offset = nextOffset;
|
||||||
@ -267,6 +271,22 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
|||||||
stackDepth += ndefs;
|
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) {
|
switch (op) {
|
||||||
|
|
||||||
case JSOP_RETURN:
|
case JSOP_RETURN:
|
||||||
@ -373,7 +393,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
|||||||
if (catchOffset > forwardCatch)
|
if (catchOffset > forwardCatch)
|
||||||
forwardCatch = catchOffset;
|
forwardCatch = catchOffset;
|
||||||
|
|
||||||
if (tn->kind != JSTRY_ITER && tn->kind != JSTRY_LOOP) {
|
if (tn->kind != JSTRY_ITER) {
|
||||||
if (!addJump(cx, catchOffset, &nextOffset, &forwardJump, &forwardLoop, stackDepth))
|
if (!addJump(cx, catchOffset, &nextOffset, &forwardJump, &forwardLoop, stackDepth))
|
||||||
return;
|
return;
|
||||||
getCode(catchOffset).exceptionEntry = true;
|
getCode(catchOffset).exceptionEntry = true;
|
||||||
@ -1475,7 +1495,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
|||||||
if (startOffset == offset + 1) {
|
if (startOffset == offset + 1) {
|
||||||
unsigned catchOffset = startOffset + tn->length;
|
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);
|
checkBranchTarget(cx, catchOffset, branchTargets, values, stackDepth);
|
||||||
checkExceptionTarget(cx, catchOffset, exceptionTargets);
|
checkExceptionTarget(cx, catchOffset, exceptionTargets);
|
||||||
}
|
}
|
||||||
|
@ -122,8 +122,13 @@ class Bytecode
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
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. */
|
/* If this is a JSOP_LOOPHEAD or JSOP_LOOPENTRY, information about the loop. */
|
||||||
LoopAnalysis *loop;
|
LoopAnalysis *loop;
|
||||||
|
};
|
||||||
|
|
||||||
/* --------- Lifetime analysis --------- */
|
/* --------- Lifetime analysis --------- */
|
||||||
|
|
||||||
@ -881,6 +886,11 @@ class ScriptAnalysis
|
|||||||
return (cs->format & JOF_POST) && !popGuaranteed(pc);
|
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) {
|
const SSAValue &poppedValue(uint32_t offset, uint32_t which) {
|
||||||
JS_ASSERT(offset < script_->length);
|
JS_ASSERT(offset < script_->length);
|
||||||
JS_ASSERT(which < GetUseCount(script_, offset) +
|
JS_ASSERT(which < GetUseCount(script_, offset) +
|
||||||
|
@ -1752,7 +1752,6 @@ struct JSContext : js::ContextFriendFields,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline bool typeInferenceEnabled() const;
|
inline bool typeInferenceEnabled() const;
|
||||||
inline bool jaegerCompilationAllowed() const;
|
|
||||||
|
|
||||||
void updateJITEnabled();
|
void updateJITEnabled();
|
||||||
|
|
||||||
|
@ -411,12 +411,6 @@ JSContext::typeInferenceEnabled() const
|
|||||||
return compartment->zone()->types.inferenceEnabled;
|
return compartment->zone()->types.inferenceEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
|
||||||
JSContext::jaegerCompilationAllowed() const
|
|
||||||
{
|
|
||||||
return compartment->zone()->types.jaegerCompilationAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline js::Handle<js::GlobalObject*>
|
inline js::Handle<js::GlobalObject*>
|
||||||
JSContext::global() const
|
JSContext::global() const
|
||||||
{
|
{
|
||||||
|
@ -1274,7 +1274,7 @@ PropertyAccess(JSContext *cx, JSScript *script, jsbytecode *pc, TypeObject *obje
|
|||||||
target->addSubset(cx, types);
|
target->addSubset(cx, types);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT_IF(script->hasAnalysis(),
|
JS_ASSERT_IF(script->hasAnalysis(),
|
||||||
target == TypeScript::BytecodeTypes(script, pc));
|
target == script->analysis()->bytecodeTypes(pc));
|
||||||
if (!types->hasPropagatedProperty())
|
if (!types->hasPropagatedProperty())
|
||||||
object->getFromPrototypes(cx, id, types);
|
object->getFromPrototypes(cx, id, types);
|
||||||
if (UsePropertyTypeBarrier(pc)) {
|
if (UsePropertyTypeBarrier(pc)) {
|
||||||
@ -1421,7 +1421,7 @@ TypeConstraintCall::newType(JSContext *cx, TypeSet *source, Type type)
|
|||||||
jsbytecode *pc = callsite->pc;
|
jsbytecode *pc = callsite->pc;
|
||||||
|
|
||||||
JS_ASSERT_IF(script->hasAnalysis(),
|
JS_ASSERT_IF(script->hasAnalysis(),
|
||||||
callsite->returnTypes == TypeScript::BytecodeTypes(script, pc));
|
callsite->returnTypes == script->analysis()->bytecodeTypes(pc));
|
||||||
|
|
||||||
if (type.isUnknown() || type.isAnyObject()) {
|
if (type.isUnknown() || type.isAnyObject()) {
|
||||||
/* Monitor calls on unknown functions. */
|
/* Monitor calls on unknown functions. */
|
||||||
@ -2467,12 +2467,10 @@ TypeZone::init(JSContext *cx)
|
|||||||
!cx->hasOption(JSOPTION_TYPE_INFERENCE) ||
|
!cx->hasOption(JSOPTION_TYPE_INFERENCE) ||
|
||||||
!cx->runtime->jitSupportsFloatingPoint)
|
!cx->runtime->jitSupportsFloatingPoint)
|
||||||
{
|
{
|
||||||
jaegerCompilationAllowed = true;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
inferenceEnabled = true;
|
inferenceEnabled = true;
|
||||||
jaegerCompilationAllowed = cx->hasOption(JSOPTION_METHODJIT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeObject *
|
TypeObject *
|
||||||
@ -2694,28 +2692,13 @@ types::UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc,
|
|||||||
if (key != JSProto_Object && !(key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray))
|
if (key != JSProto_Object && !(key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray))
|
||||||
return GenericObject;
|
return GenericObject;
|
||||||
|
|
||||||
/*
|
AutoEnterAnalysis enter(cx);
|
||||||
* All loops in the script will have a JSTRY_ITER or JSTRY_LOOP try note
|
|
||||||
* indicating their boundary.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!script->hasTrynotes())
|
if (!script->ensureRanAnalysis(cx))
|
||||||
return SingletonObject;
|
return GenericObject;
|
||||||
|
|
||||||
unsigned offset = pc - script->code;
|
if (script->analysis()->getCode(pc).inLoop)
|
||||||
|
|
||||||
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;
|
return GenericObject;
|
||||||
}
|
|
||||||
|
|
||||||
return SingletonObject;
|
return SingletonObject;
|
||||||
}
|
}
|
||||||
@ -4314,7 +4297,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
|
|||||||
case JSOP_CALLGNAME: {
|
case JSOP_CALLGNAME: {
|
||||||
jsid id = GetAtomId(cx, script, pc, 0);
|
jsid id = GetAtomId(cx, script, pc, 0);
|
||||||
|
|
||||||
StackTypeSet *seen = TypeScript::BytecodeTypes(script, pc);
|
StackTypeSet *seen = bytecodeTypes(pc);
|
||||||
seen->addSubset(cx, &pushed[0]);
|
seen->addSubset(cx, &pushed[0]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4346,7 +4329,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
|
|||||||
case JSOP_GETINTRINSIC:
|
case JSOP_GETINTRINSIC:
|
||||||
case JSOP_CALLNAME:
|
case JSOP_CALLNAME:
|
||||||
case JSOP_CALLINTRINSIC: {
|
case JSOP_CALLINTRINSIC: {
|
||||||
StackTypeSet *seen = TypeScript::BytecodeTypes(script, pc);
|
StackTypeSet *seen = bytecodeTypes(pc);
|
||||||
addTypeBarrier(cx, pc, seen, Type::UnknownType());
|
addTypeBarrier(cx, pc, seen, Type::UnknownType());
|
||||||
seen->addSubset(cx, &pushed[0]);
|
seen->addSubset(cx, &pushed[0]);
|
||||||
break;
|
break;
|
||||||
@ -4375,7 +4358,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case JSOP_GETXPROP: {
|
case JSOP_GETXPROP: {
|
||||||
StackTypeSet *seen = TypeScript::BytecodeTypes(script, pc);
|
StackTypeSet *seen = bytecodeTypes(pc);
|
||||||
addTypeBarrier(cx, pc, seen, Type::UnknownType());
|
addTypeBarrier(cx, pc, seen, Type::UnknownType());
|
||||||
seen->addSubset(cx, &pushed[0]);
|
seen->addSubset(cx, &pushed[0]);
|
||||||
break;
|
break;
|
||||||
@ -4429,7 +4412,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
|
|||||||
* there is little benefit to maintaining a TypeSet for the aliased
|
* there is little benefit to maintaining a TypeSet for the aliased
|
||||||
* variable. Instead, we monitor/barrier all reads unconditionally.
|
* variable. Instead, we monitor/barrier all reads unconditionally.
|
||||||
*/
|
*/
|
||||||
TypeScript::BytecodeTypes(script, pc)->addSubset(cx, &pushed[0]);
|
bytecodeTypes(pc)->addSubset(cx, &pushed[0]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSOP_SETALIASEDVAR:
|
case JSOP_SETALIASEDVAR:
|
||||||
@ -4445,7 +4428,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case JSOP_REST: {
|
case JSOP_REST: {
|
||||||
StackTypeSet *types = TypeScript::BytecodeTypes(script, pc);
|
StackTypeSet *types = script->analysis()->bytecodeTypes(pc);
|
||||||
if (script->compileAndGo) {
|
if (script->compileAndGo) {
|
||||||
TypeObject *rest = TypeScript::InitObject(cx, script, pc, JSProto_Array);
|
TypeObject *rest = TypeScript::InitObject(cx, script, pc, JSProto_Array);
|
||||||
if (!rest)
|
if (!rest)
|
||||||
@ -4479,7 +4462,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
|
|||||||
case JSOP_GETPROP:
|
case JSOP_GETPROP:
|
||||||
case JSOP_CALLPROP: {
|
case JSOP_CALLPROP: {
|
||||||
jsid id = GetAtomId(cx, script, pc, 0);
|
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++];
|
HeapTypeSet *input = &script->types->propertyReadTypes[state.propertyReadIndex++];
|
||||||
poppedTypes(pc, 0)->addSubset(cx, input);
|
poppedTypes(pc, 0)->addSubset(cx, input);
|
||||||
@ -4508,7 +4491,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
|
|||||||
|
|
||||||
case JSOP_GETELEM:
|
case JSOP_GETELEM:
|
||||||
case JSOP_CALLELEM: {
|
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. */
|
/* Don't try to compute a precise callee for CALLELEM. */
|
||||||
if (op == JSOP_CALLELEM)
|
if (op == JSOP_CALLELEM)
|
||||||
@ -4596,7 +4579,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
|
|||||||
case JSOP_FUNCALL:
|
case JSOP_FUNCALL:
|
||||||
case JSOP_FUNAPPLY:
|
case JSOP_FUNAPPLY:
|
||||||
case JSOP_NEW: {
|
case JSOP_NEW: {
|
||||||
StackTypeSet *seen = TypeScript::BytecodeTypes(script, pc);
|
StackTypeSet *seen = script->analysis()->bytecodeTypes(pc);
|
||||||
seen->addSubset(cx, &pushed[0]);
|
seen->addSubset(cx, &pushed[0]);
|
||||||
|
|
||||||
/* Construct the base call information about this site. */
|
/* Construct the base call information about this site. */
|
||||||
@ -4644,7 +4627,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
|
|||||||
case JSOP_NEWINIT:
|
case JSOP_NEWINIT:
|
||||||
case JSOP_NEWARRAY:
|
case JSOP_NEWARRAY:
|
||||||
case JSOP_NEWOBJECT: {
|
case JSOP_NEWOBJECT: {
|
||||||
StackTypeSet *types = TypeScript::BytecodeTypes(script, pc);
|
StackTypeSet *types = script->analysis()->bytecodeTypes(pc);
|
||||||
types->addSubset(cx, &pushed[0]);
|
types->addSubset(cx, &pushed[0]);
|
||||||
|
|
||||||
bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && GET_UINT8(pc) == JSProto_Array));
|
bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && GET_UINT8(pc) == JSProto_Array));
|
||||||
@ -4877,9 +4860,6 @@ ScriptAnalysis::analyzeTypes(JSContext *cx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!script_->ensureHasBytecodeTypeMap(cx))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set this early to avoid reentrance. Any failures are OOMs, and will nuke
|
* Set this early to avoid reentrance. Any failures are OOMs, and will nuke
|
||||||
* all types in the compartment.
|
* all types in the compartment.
|
||||||
@ -5289,7 +5269,7 @@ AnalyzePoppedThis(JSContext *cx, SSAUseChain *use,
|
|||||||
Shape *shape = type->proto ? type->proto->nativeLookup(cx, id) : NULL;
|
Shape *shape = type->proto ? type->proto->nativeLookup(cx, id) : NULL;
|
||||||
if (shape && shape->hasSlot()) {
|
if (shape && shape->hasSlot()) {
|
||||||
Value protov = type->proto->getSlot(shape->slot());
|
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));
|
types->addType(cx, GetValueType(cx, protov));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5581,7 +5561,7 @@ ScriptAnalysis::printTypes(JSContext *cx)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (js_CodeSpec[*pc].format & JOF_TYPESET) {
|
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()));
|
printf(" typeset %d:", (int) (types - script_->types->typeArray()));
|
||||||
types->print();
|
types->print();
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@ -5633,11 +5613,6 @@ types::MarkIteratorUnknownSlow(JSContext *cx)
|
|||||||
|
|
||||||
AutoEnterAnalysis enter(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
|
* 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
|
* 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)
|
types::TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->typeInferenceEnabled());
|
JS_ASSERT(cx->typeInferenceEnabled());
|
||||||
|
|
||||||
AutoEnterAnalysis enter(cx);
|
AutoEnterAnalysis enter(cx);
|
||||||
|
|
||||||
/* Directly update associated type sets for applicable bytecodes. */
|
/* Directly update associated type sets for applicable bytecodes. */
|
||||||
if (js_CodeSpec[*pc].format & JOF_TYPESET) {
|
if (js_CodeSpec[*pc].format & JOF_TYPESET) {
|
||||||
if (!script->ensureHasBytecodeTypeMap(cx)) {
|
if (!script->ensureRanAnalysis(cx)) {
|
||||||
cx->compartment->types.setPendingNukeTypes(cx);
|
cx->compartment->types.setPendingNukeTypes(cx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TypeSet *types = TypeScript::BytecodeTypes(script, pc);
|
TypeSet *types = script->analysis()->bytecodeTypes(pc);
|
||||||
if (!types->hasType(type)) {
|
if (!types->hasType(type)) {
|
||||||
InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s",
|
InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s",
|
||||||
script->id(), pc - script->code, TypeString(type));
|
script->id(), pc - script->code, TypeString(type));
|
||||||
@ -5829,13 +5803,13 @@ types::TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const
|
|||||||
|
|
||||||
AutoEnterAnalysis enter(cx);
|
AutoEnterAnalysis enter(cx);
|
||||||
|
|
||||||
if (!script->ensureHasBytecodeTypeMap(cx)) {
|
if (!script->ensureRanAnalysis(cx)) {
|
||||||
cx->compartment->types.setPendingNukeTypes(cx);
|
cx->compartment->types.setPendingNukeTypes(cx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type type = GetValueType(cx, rval);
|
Type type = GetValueType(cx, rval);
|
||||||
TypeSet *types = TypeScript::BytecodeTypes(script, pc);
|
TypeSet *types = script->analysis()->bytecodeTypes(pc);
|
||||||
if (types->hasType(type))
|
if (types->hasType(type))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -5932,7 +5906,7 @@ JSScript::makeTypes(JSContext *cx)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
new(types) TypeScript();
|
new(types) TypeScript();
|
||||||
return analyzedArgsUsage() || ensureRanAnalysis(cx);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoEnterAnalysis enter(cx);
|
AutoEnterAnalysis enter(cx);
|
||||||
@ -6002,36 +5976,6 @@ JSScript::makeTypes(JSContext *cx)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return analyzedArgsUsage() || ensureRanAnalysis(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
JSScript::makeBytecodeTypeMap(JSContext *cx)
|
|
||||||
{
|
|
||||||
JS_ASSERT(cx->typeInferenceEnabled());
|
|
||||||
JS_ASSERT(types && !types->bytecodeMap);
|
|
||||||
|
|
||||||
types->bytecodeMap = cx->analysisLifoAlloc().newArrayUninitialized<uint32_t>(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1177,12 +1177,6 @@ class TypeScript
|
|||||||
/* Analysis information for the script, cleared on each GC. */
|
/* Analysis information for the script, cleared on each GC. */
|
||||||
analyze::ScriptAnalysis *analysis;
|
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:
|
public:
|
||||||
/* Dynamic types generated at points within this script. */
|
/* Dynamic types generated at points within this script. */
|
||||||
TypeResult *dynamicList;
|
TypeResult *dynamicList;
|
||||||
@ -1207,9 +1201,6 @@ class TypeScript
|
|||||||
/* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
|
/* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
|
||||||
static inline StackTypeSet *SlotTypes(JSScript *script, unsigned slot);
|
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. */
|
/* Get the default 'new' object for a given standard class, per the script's global. */
|
||||||
static inline TypeObject *StandardType(JSContext *cx, JSProtoKey kind);
|
static inline TypeObject *StandardType(JSContext *cx, JSProtoKey kind);
|
||||||
|
|
||||||
@ -1475,13 +1466,6 @@ struct TypeZone
|
|||||||
/* Whether type inference is enabled in this compartment. */
|
/* Whether type inference is enabled in this compartment. */
|
||||||
bool inferenceEnabled;
|
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(JS::Zone *zone);
|
||||||
~TypeZone();
|
~TypeZone();
|
||||||
void init(JSContext *cx);
|
void init(JSContext *cx);
|
||||||
|
@ -586,7 +586,7 @@ TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
|
|||||||
if (args.callee().isFunction()) {
|
if (args.callee().isFunction()) {
|
||||||
JSFunction *fun = args.callee().toFunction();
|
JSFunction *fun = args.callee().toFunction();
|
||||||
if (fun->isInterpreted()) {
|
if (fun->isInterpreted()) {
|
||||||
if (!fun->nonLazyScript()->ensureHasTypes(cx))
|
if (!fun->nonLazyScript()->ensureRanAnalysis(cx))
|
||||||
return false;
|
return false;
|
||||||
if (cx->typeInferenceEnabled())
|
if (cx->typeInferenceEnabled())
|
||||||
TypeMonitorCallSlow(cx, &args.callee(), args, constructing);
|
TypeMonitorCallSlow(cx, &args.callee(), args, constructing);
|
||||||
@ -858,49 +858,6 @@ TypeScript::SlotTypes(JSScript *script, unsigned slot)
|
|||||||
return types->toStackTypeSet();
|
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 *
|
/* static */ inline TypeObject *
|
||||||
TypeScript::StandardType(JSContext *cx, JSProtoKey key)
|
TypeScript::StandardType(JSContext *cx, JSProtoKey key)
|
||||||
{
|
{
|
||||||
@ -1825,12 +1782,6 @@ JSScript::ensureHasTypes(JSContext *cx)
|
|||||||
return types || makeTypes(cx);
|
return types || makeTypes(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
|
||||||
JSScript::ensureHasBytecodeTypeMap(JSContext *cx)
|
|
||||||
{
|
|
||||||
return ensureHasTypes(cx) && (types->bytecodeMap || makeBytecodeTypeMap(cx));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
JSScript::ensureRanAnalysis(JSContext *cx)
|
JSScript::ensureRanAnalysis(JSContext *cx)
|
||||||
{
|
{
|
||||||
@ -1872,10 +1823,8 @@ JSScript::analysis()
|
|||||||
inline void
|
inline void
|
||||||
JSScript::clearAnalysis()
|
JSScript::clearAnalysis()
|
||||||
{
|
{
|
||||||
if (types) {
|
if (types)
|
||||||
types->analysis = NULL;
|
types->analysis = NULL;
|
||||||
types->bytecodeMap = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -565,7 +565,7 @@ js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChainArg, c
|
|||||||
if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
|
if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!script->ensureHasTypes(cx))
|
if (!script->ensureRanAnalysis(cx))
|
||||||
return false;
|
return false;
|
||||||
TypeScript::SetThis(cx, script, efg.fp()->thisValue());
|
TypeScript::SetThis(cx, script, efg.fp()->thisValue());
|
||||||
|
|
||||||
@ -3366,11 +3366,7 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||||||
regs.sp -= 1;
|
regs.sp -= 1;
|
||||||
if (!ok)
|
if (!ok)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case JSTRY_LOOP:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1520,9 +1520,7 @@ js::CreateThisForFunctionWithProto(JSContext *cx, HandleObject callee, JSObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (res && cx->typeInferenceEnabled()) {
|
if (res && cx->typeInferenceEnabled()) {
|
||||||
JSScript *script = callee->toFunction()->nonLazyScript();
|
RootedScript script(cx, callee->toFunction()->nonLazyScript());
|
||||||
if (!script->ensureHasTypes(cx))
|
|
||||||
return NULL;
|
|
||||||
TypeScript::SetThis(cx, script, types::Type::ObjectType(res));
|
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. */
|
/* Reshape the singleton before passing it as the 'this' value. */
|
||||||
JSObject::clear(cx, nobj);
|
JSObject::clear(cx, nobj);
|
||||||
|
|
||||||
JSScript *calleeScript = callee->toFunction()->nonLazyScript();
|
RootedScript calleeScript(cx, callee->toFunction()->nonLazyScript());
|
||||||
if (!calleeScript->ensureHasTypes(cx))
|
|
||||||
return NULL;
|
|
||||||
TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(nobj));
|
TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(nobj));
|
||||||
|
|
||||||
return nobj;
|
return nobj;
|
||||||
|
@ -49,15 +49,12 @@ namespace analyze {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Type of try note associated with each catch or finally block, and also with
|
* 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-in loops.
|
||||||
* for exception unwinding, but storing their boundaries here is helpful for
|
|
||||||
* heuristics that need to know whether a given op is inside a loop.
|
|
||||||
*/
|
*/
|
||||||
typedef enum JSTryNoteKind {
|
typedef enum JSTryNoteKind {
|
||||||
JSTRY_CATCH,
|
JSTRY_CATCH,
|
||||||
JSTRY_FINALLY,
|
JSTRY_FINALLY,
|
||||||
JSTRY_ITER,
|
JSTRY_ITER
|
||||||
JSTRY_LOOP
|
|
||||||
} JSTryNoteKind;
|
} JSTryNoteKind;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -67,9 +64,9 @@ struct JSTryNote {
|
|||||||
uint8_t kind; /* one of JSTryNoteKind */
|
uint8_t kind; /* one of JSTryNoteKind */
|
||||||
uint8_t padding; /* explicit padding on uint16_t boundary */
|
uint8_t padding; /* explicit padding on uint16_t boundary */
|
||||||
uint16_t stackDepth; /* stack depth upon exception handler entry */
|
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 */
|
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 {
|
namespace js {
|
||||||
@ -720,9 +717,6 @@ class JSScript : public js::gc::Cell
|
|||||||
/* Ensure the script has a TypeScript. */
|
/* Ensure the script has a TypeScript. */
|
||||||
inline bool ensureHasTypes(JSContext *cx);
|
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
|
* Ensure the script has bytecode analysis information. Performed when the
|
||||||
* script first runs, or first runs after a TypeScript GC purge.
|
* script first runs, or first runs after a TypeScript GC purge.
|
||||||
@ -764,7 +758,6 @@ class JSScript : public js::gc::Cell
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool makeTypes(JSContext *cx);
|
bool makeTypes(JSContext *cx);
|
||||||
bool makeBytecodeTypeMap(JSContext *cx);
|
|
||||||
bool makeAnalysis(JSContext *cx);
|
bool makeAnalysis(JSContext *cx);
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
|
@ -121,8 +121,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript,
|
|||||||
gcNumber(cx->runtime->gcNumber),
|
gcNumber(cx->runtime->gcNumber),
|
||||||
pcLengths(NULL)
|
pcLengths(NULL)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->jaegerCompilationAllowed());
|
|
||||||
|
|
||||||
if (!IsIonEnabled(cx)) {
|
if (!IsIonEnabled(cx)) {
|
||||||
/* Once a script starts getting really hot we will inline calls in it. */
|
/* Once a script starts getting really hot we will inline calls in it. */
|
||||||
if (!debugMode() && cx->typeInferenceEnabled() && globalObj &&
|
if (!debugMode() && cx->typeInferenceEnabled() && globalObj &&
|
||||||
@ -996,9 +994,6 @@ mjit::CanMethodJIT(JSContext *cx, JSScript *script, jsbytecode *pc,
|
|||||||
if (!cx->methodJitEnabled)
|
if (!cx->methodJitEnabled)
|
||||||
return Compile_Abort;
|
return Compile_Abort;
|
||||||
|
|
||||||
if (!cx->jaegerCompilationAllowed())
|
|
||||||
return Compile_Abort;
|
|
||||||
|
|
||||||
#ifdef JS_ION
|
#ifdef JS_ION
|
||||||
if (ion::IsBaselineEnabled(cx) || ion::IsEnabled(cx))
|
if (ion::IsBaselineEnabled(cx) || ion::IsEnabled(cx))
|
||||||
return Compile_Abort;
|
return Compile_Abort;
|
||||||
@ -8128,7 +8123,7 @@ mjit::Compiler::testBarrier(RegisterID typeReg, RegisterID dataReg,
|
|||||||
if (!cx->typeInferenceEnabled() || !(js_CodeSpec[*PC].format & JOF_TYPESET))
|
if (!cx->typeInferenceEnabled() || !(js_CodeSpec[*PC].format & JOF_TYPESET))
|
||||||
return state;
|
return state;
|
||||||
|
|
||||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script_, PC);
|
types::StackTypeSet *types = analysis->bytecodeTypes(PC);
|
||||||
if (types->unknown()) {
|
if (types->unknown()) {
|
||||||
/*
|
/*
|
||||||
* If the result of this opcode is already unknown, there is no way for
|
* 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))
|
if (!cx->typeInferenceEnabled() || !(js_CodeSpec[*PC].format & JOF_TYPESET))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
types::TypeSet *types = types::TypeScript::BytecodeTypes(script_, PC);
|
types::TypeSet *types = analysis->bytecodeTypes(PC);
|
||||||
if (types->unknown())
|
if (types->unknown())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -115,11 +115,7 @@ FindExceptionHandler(JSContext *cx)
|
|||||||
cx->regs().sp -= 1;
|
cx->regs().sp -= 1;
|
||||||
if (!ok)
|
if (!ok)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case JSTRY_LOOP:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -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
|
* the call. We don't assume knowledge about the types that natives can
|
||||||
* return, except when generating specialized paths in FastBuiltins.
|
* 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))
|
if (!masm.generateTypeCheck(f.cx, resultAddress, types, &mismatches))
|
||||||
THROWV(false);
|
THROWV(false);
|
||||||
}
|
}
|
||||||
|
@ -1809,7 +1809,7 @@ JS_STATIC_ASSERT(JSTRY_CATCH == 0);
|
|||||||
JS_STATIC_ASSERT(JSTRY_FINALLY == 1);
|
JS_STATIC_ASSERT(JSTRY_FINALLY == 1);
|
||||||
JS_STATIC_ASSERT(JSTRY_ITER == 2);
|
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
|
static JSBool
|
||||||
TryNotes(JSContext *cx, HandleScript script, Sprinter *sp)
|
TryNotes(JSContext *cx, HandleScript script, Sprinter *sp)
|
||||||
@ -4927,6 +4927,11 @@ ProcessArgs(JSContext *cx, JSObject *obj_, OptionParser *op)
|
|||||||
if (op->getBoolOption('s'))
|
if (op->getBoolOption('s'))
|
||||||
JS_ToggleOptions(cx, JSOPTION_STRICT);
|
JS_ToggleOptions(cx, JSOPTION_STRICT);
|
||||||
|
|
||||||
|
if (op->getBoolOption("no-jm")) {
|
||||||
|
enableMethodJit = false;
|
||||||
|
JS_ToggleOptions(cx, JSOPTION_METHODJIT);
|
||||||
|
}
|
||||||
|
|
||||||
if (op->getBoolOption('d')) {
|
if (op->getBoolOption('d')) {
|
||||||
JS_SetRuntimeDebugMode(JS_GetRuntime(cx), true);
|
JS_SetRuntimeDebugMode(JS_GetRuntime(cx), true);
|
||||||
JS_SetDebugMode(cx, true);
|
JS_SetDebugMode(cx, true);
|
||||||
@ -5116,17 +5121,13 @@ Shell(JSContext *cx, OptionParser *op, char **envp)
|
|||||||
JSAutoRequest ar(cx);
|
JSAutoRequest ar(cx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First check to see if type inference and JM are enabled. These flags
|
* First check to see if type inference is enabled. This flag must be set
|
||||||
* must be set on the compartment when it is constructed.
|
* on the compartment when it is constructed.
|
||||||
*/
|
*/
|
||||||
if (op->getBoolOption("no-ti")) {
|
if (op->getBoolOption("no-ti")) {
|
||||||
enableTypeInference = false;
|
enableTypeInference = false;
|
||||||
JS_ToggleOptions(cx, JSOPTION_TYPE_INFERENCE);
|
JS_ToggleOptions(cx, JSOPTION_TYPE_INFERENCE);
|
||||||
}
|
}
|
||||||
if (op->getBoolOption("no-jm")) {
|
|
||||||
enableMethodJit = false;
|
|
||||||
JS_ToggleOptions(cx, JSOPTION_METHODJIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
RootedObject glob(cx);
|
RootedObject glob(cx);
|
||||||
glob = NewGlobalObject(cx, NULL);
|
glob = NewGlobalObject(cx, NULL);
|
||||||
|
@ -26,7 +26,7 @@ namespace js {
|
|||||||
* and saved versions. If deserialization fails, the data should be
|
* and saved versions. If deserialization fails, the data should be
|
||||||
* invalidated if possible.
|
* 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 {
|
class XDRBuffer {
|
||||||
public:
|
public:
|
||||||
|
Loading…
Reference in New Issue
Block a user