Bug 940852 - Record baseline frame information before Ion compilation, r=jandem.

This commit is contained in:
Brian Hackett 2013-11-21 10:37:38 -08:00
parent 1390b9dc37
commit 28436d4108
4 changed files with 104 additions and 29 deletions

View File

@ -1637,6 +1637,13 @@ IonCompile(JSContext *cx, JSScript *script,
BaselineInspector inspector(script);
BaselineFrameInspector *baselineFrameInspector = nullptr;
if (baselineFrame) {
baselineFrameInspector = NewBaselineFrameInspector(temp, baselineFrame);
if (!baselineFrameInspector)
return AbortReason_Alloc;
}
AutoFlushCache afc("IonCompile", cx->runtime()->jitRuntime());
AutoTempAllocatorRooter root(cx, temp);
@ -1647,7 +1654,7 @@ IonCompile(JSContext *cx, JSScript *script,
IonBuilder *builder = alloc->new_<IonBuilder>((JSContext *) nullptr,
CompileCompartment::get(cx->compartment()),
temp, graph, constraints,
&inspector, info, baselineFrame);
&inspector, info, baselineFrameInspector);
if (!builder)
return AbortReason_Alloc;

View File

@ -37,9 +37,73 @@ using namespace js::jit;
using mozilla::DebugOnly;
using mozilla::Maybe;
class jit::BaselineFrameInspector
{
public:
types::Type thisType;
JSObject *singletonScopeChain;
Vector<types::Type, 4, IonAllocPolicy> argTypes;
Vector<types::Type, 4, IonAllocPolicy> varTypes;
BaselineFrameInspector(TempAllocator *temp)
: thisType(types::Type::UndefinedType()),
singletonScopeChain(nullptr),
argTypes(*temp),
varTypes(*temp)
{}
};
BaselineFrameInspector *
jit::NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame)
{
JS_ASSERT(frame);
BaselineFrameInspector *inspector = temp->lifoAlloc()->new_<BaselineFrameInspector>(temp);
if (!inspector)
return nullptr;
// Note: copying the actual values into a temporary structure for use
// during compilation could capture nursery pointers, so the values' types
// are recorded instead.
inspector->thisType = types::GetValueType(frame->thisValue());
if (frame->scopeChain()->hasSingletonType())
inspector->singletonScopeChain = frame->scopeChain();
JSScript *script = frame->script();
if (script->function()) {
if (!inspector->argTypes.reserve(frame->numFormalArgs()))
return nullptr;
for (size_t i = 0; i < frame->numFormalArgs(); i++) {
if (script->formalIsAliased(i))
inspector->argTypes.infallibleAppend(types::Type::UndefinedType());
else if (!script->argsObjAliasesFormals())
inspector->argTypes.infallibleAppend(types::GetValueType(frame->unaliasedFormal(i)));
else if (frame->hasArgsObj())
inspector->argTypes.infallibleAppend(types::GetValueType(frame->argsObj().arg(i)));
else
inspector->argTypes.infallibleAppend(types::Type::UndefinedType());
}
}
if (!inspector->varTypes.reserve(frame->script()->nfixed))
return nullptr;
for (size_t i = 0; i < frame->script()->nfixed; i++) {
if (script->varIsAliased(i))
inspector->varTypes.infallibleAppend(types::Type::UndefinedType());
else
inspector->varTypes.infallibleAppend(types::GetValueType(frame->unaliasedVar(i)));
}
return inspector;
}
IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp, TempAllocator *temp, MIRGraph *graph,
types::CompilerConstraintList *constraints,
BaselineInspector *inspector, CompileInfo *info, BaselineFrame *baselineFrame,
BaselineInspector *inspector, CompileInfo *info, BaselineFrameInspector *baselineFrame,
size_t inliningDepth, uint32_t loopDepth)
: MIRGenerator(comp, temp, graph, info),
backgroundCodegen_(nullptr),
@ -859,7 +923,7 @@ IonBuilder::initParameters()
// frame to determine possible initial types for 'this' and parameters.
if (thisTypes->empty() && baselineFrame_) {
if (!thisTypes->addType(types::GetValueType(baselineFrame_->thisValue()), alloc_->lifoAlloc()))
if (!thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc()))
return false;
}
@ -872,7 +936,7 @@ IonBuilder::initParameters()
if (types->empty() && baselineFrame_ &&
!script_->baselineScript()->modifiesArguments())
{
if (!types->addType(types::GetValueType(baselineFrame_->argv()[i]), alloc_->lifoAlloc()))
if (!types->addType(baselineFrame_->argTypes[i], alloc_->lifoAlloc()))
return false;
}
@ -5814,30 +5878,23 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool
MPhi *phi = block->getSlot(i)->toPhi();
// Get the value from the baseline frame.
Value existingValue;
// Get the type from the baseline frame.
types::Type existingType = types::Type::UndefinedType();
uint32_t arg = i - info().firstArgSlot();
uint32_t var = i - info().firstLocalSlot();
if (info().fun() && i == info().thisSlot()) {
existingValue = baselineFrame_->thisValue();
} else if (arg < info().nargs()) {
if (info().needsArgsObj())
existingValue = baselineFrame_->argsObj().arg(arg);
else
existingValue = baselineFrame_->unaliasedFormal(arg);
} else {
existingValue = baselineFrame_->unaliasedVar(var);
}
if (info().fun() && i == info().thisSlot())
existingType = baselineFrame_->thisType;
else if (arg < info().nargs())
existingType = baselineFrame_->argTypes[arg];
else
existingType = baselineFrame_->varTypes[var];
// Extract typeset from value.
MIRType type = existingValue.isDouble()
? MIRType_Double
: MIRTypeFromValueType(existingValue.extractNonDoubleType());
types::Type ntype = types::GetValueType(existingValue);
types::TemporaryTypeSet *typeSet =
alloc_->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype);
alloc_->lifoAlloc()->new_<types::TemporaryTypeSet>(existingType);
if (!typeSet)
return nullptr;
MIRType type = MIRTypeFromValueType(typeSet->getKnownTypeTag());
phi->addBackedgeType(type, typeSet);
}
}
@ -9110,7 +9167,7 @@ IonBuilder::jsop_this()
}
if (thisTypes->getKnownTypeTag() == JSVAL_TYPE_OBJECT ||
(thisTypes->empty() && baselineFrame_ && baselineFrame_->thisValue().isObject()))
(thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject()))
{
// This is safe, because if the entry type of |this| is an object, it
// will necessarily be an object throughout the entire function. OSR
@ -9294,12 +9351,13 @@ IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall)
// entering the Ion code a different call object will be created.
if (script() == outerScript && baselineFrame_ && info().osrPc()) {
JSObject *scope = baselineFrame_->scopeChain();
if (scope->is<CallObject>() &&
scope->as<CallObject>().callee().nonLazyScript() == outerScript)
JSObject *singletonScope = baselineFrame_->singletonScopeChain;
if (singletonScope &&
singletonScope->is<CallObject>() &&
singletonScope->as<CallObject>().callee().nonLazyScript() == outerScript)
{
JS_ASSERT(scope->hasSingletonType());
*pcall = scope;
JS_ASSERT(singletonScope->hasSingletonType());
*pcall = singletonScope;
return true;
}
}

View File

@ -24,6 +24,12 @@ namespace jit {
class CodeGenerator;
class CallInfo;
class BaselineInspector;
class BaselineFrameInspector;
// Records information about a baseline frame for compilation that is stable
// when later used off thread.
BaselineFrameInspector *
NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame);
class IonBuilder : public MIRGenerator
{
@ -207,7 +213,7 @@ class IonBuilder : public MIRGenerator
public:
IonBuilder(JSContext *analysisContext, CompileCompartment *comp, TempAllocator *temp, MIRGraph *graph,
types::CompilerConstraintList *constraints,
BaselineInspector *inspector, CompileInfo *info, BaselineFrame *baselineFrame,
BaselineInspector *inspector, CompileInfo *info, BaselineFrameInspector *baselineFrame,
size_t inliningDepth = 0, uint32_t loopDepth = 0);
bool build();
@ -745,7 +751,7 @@ class IonBuilder : public MIRGenerator
bool init();
JSContext *analysisContext;
BaselineFrame *baselineFrame_;
BaselineFrameInspector *baselineFrame_;
AbortReason abortReason_;
TypeRepresentationSetHash *reprSetHash_;

View File

@ -209,6 +209,10 @@ class Type
return (JSValueType) data;
}
bool isSomeObject() const {
return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
}
bool isAnyObject() const {
return data == JSVAL_TYPE_OBJECT;
}