Backed out changeset 0b365c68c8a9 (bug 995336) for Android armv6 crashes.

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2014-04-24 12:22:33 -04:00
Родитель 7262b1ae70
Коммит a3e615580e
21 изменённых файлов: 273 добавлений и 267 удалений

Просмотреть файл

@ -300,6 +300,7 @@ static const PhaseInfo phases[] = {
{ PHASE_DISCARD_TI, "Discard TI", PHASE_DISCARD_ANALYSIS },
{ PHASE_FREE_TI_ARENA, "Free TI Arena", PHASE_DISCARD_ANALYSIS },
{ PHASE_SWEEP_TYPES, "Sweep Types", PHASE_DISCARD_ANALYSIS },
{ PHASE_CLEAR_SCRIPT_ANALYSIS, "Clear Script Analysis", PHASE_DISCARD_ANALYSIS },
{ PHASE_SWEEP_OBJECT, "Sweep Object", PHASE_SWEEP },
{ PHASE_SWEEP_STRING, "Sweep String", PHASE_SWEEP },
{ PHASE_SWEEP_SCRIPT, "Sweep Script", PHASE_SWEEP },

Просмотреть файл

@ -52,6 +52,7 @@ enum Phase {
PHASE_DISCARD_TI,
PHASE_FREE_TI_ARENA,
PHASE_SWEEP_TYPES,
PHASE_CLEAR_SCRIPT_ANALYSIS,
PHASE_SWEEP_OBJECT,
PHASE_SWEEP_STRING,
PHASE_SWEEP_SCRIPT,

Просмотреть файл

@ -10,7 +10,6 @@
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
#include "jit/FixedList.h"
#include "jit/IonAnalysis.h"
#include "jit/IonLinker.h"
#include "jit/IonSpewer.h"
#ifdef JS_ION_PERF
@ -80,9 +79,16 @@ BaselineCompiler::compile()
AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
AutoTraceLog logCompile(logger, TraceLogger::BaselineCompilation);
if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
if (!script->ensureHasTypes(cx))
return Method_Error;
// Only need to analyze scripts which are marked |argumensHasVarBinding|, to
// compute |needsArgsObj| flag.
if (script->argumentsHasVarBinding()) {
if (!script->ensureRanAnalysis(cx))
return Method_Error;
}
// Pin analysis info during compilation.
types::AutoEnterAnalysis autoEnterAnalysis(cx);
@ -234,7 +240,18 @@ BaselineCompiler::compile()
baselineScript->toggleSPS(true);
uint32_t *bytecodeMap = baselineScript->bytecodeTypeMap();
types::FillBytecodeTypeMap(script, bytecodeMap);
uint32_t added = 0;
for (jsbytecode *pc = script->code(); pc < script->codeEnd(); pc += GetBytecodeLength(pc)) {
JSOp op = JSOp(*pc);
if (js_CodeSpec[op].format & JOF_TYPESET) {
bytecodeMap[added++] = script->pcToOffset(pc);
if (added == script->nTypeSets())
break;
}
}
JS_ASSERT(added == script->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.

Просмотреть файл

@ -304,9 +304,6 @@ TryToSpecializeBinaryArithOp(ICStub **stubs,
MIRType
BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc)
{
if (!hasBaselineScript())
return MIRType_None;
MIRType result;
ICStub *stubs[2];
@ -452,9 +449,6 @@ BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
DeclEnvObject *
BaselineInspector::templateDeclEnvObject()
{
if (!hasBaselineScript())
return nullptr;
JSObject *res = &templateCallObject()->as<ScopeObject>().enclosingScope();
JS_ASSERT(res);
@ -464,9 +458,6 @@ BaselineInspector::templateDeclEnvObject()
CallObject *
BaselineInspector::templateCallObject()
{
if (!hasBaselineScript())
return nullptr;
JSObject *res = baselineScript()->templateScope();
JS_ASSERT(res);
@ -476,9 +467,6 @@ BaselineInspector::templateCallObject()
JSObject *
BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter)
{
if (!hasBaselineScript())
return nullptr;
const ICEntry &entry = icEntryFromPC(pc);
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
if (stub->isGetProp_CallScripted() ||
@ -497,9 +485,6 @@ BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, J
JSObject *
BaselineInspector::commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter)
{
if (!hasBaselineScript())
return nullptr;
const ICEntry &entry = icEntryFromPC(pc);
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {

Просмотреть файл

@ -297,10 +297,6 @@ class CompileInfo
return executionMode_;
}
bool executionModeIsAnalysis() const {
return executionMode_ == DefinitePropertiesAnalysis || executionMode_ == ArgumentsUsageAnalysis;
}
bool isParallelExecution() const {
return executionMode_ == ParallelExecution;
}

Просмотреть файл

@ -67,7 +67,6 @@ CanIonCompile(JSScript *script, ExecutionMode cmode)
case SequentialExecution: return script->canIonCompile();
case ParallelExecution: return script->canParallelIonCompile();
case DefinitePropertiesAnalysis: return true;
case ArgumentsUsageAnalysis: return true;
default:;
}
MOZ_ASSUME_UNREACHABLE("No such execution mode");

Просмотреть файл

@ -1947,6 +1947,11 @@ CheckScript(JSContext *cx, JSScript *script, bool osr)
return false;
}
if (!script->analyzedArgsUsage() && !script->ensureRanAnalysis(cx)) {
IonSpew(IonSpew_Abort, "OOM under ensureRanAnalysis");
return false;
}
if (!script->compileAndGo()) {
IonSpew(IonSpew_Abort, "not compile-and-go");
return false;

Просмотреть файл

@ -2241,7 +2241,7 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
IonContext ictx(cx, &temp);
if (!cx->compartment()->ensureJitCompartmentExists(cx))
return false;
return Method_Error;
if (!script->hasBaselineScript()) {
MethodStatus status = BaselineCompile(cx, script);
@ -2301,6 +2301,7 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
// appear in the graph.
Vector<MInstruction *> instructions(cx);
Vector<MDefinition *> useWorklist(cx);
for (MUseDefIterator uses(thisValue); uses; uses++) {
MDefinition *use = uses.def();
@ -2360,114 +2361,3 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
return true;
}
static bool
ArgumentsUseCanBeLazy(JSContext *cx, JSScript *script, MInstruction *ins, size_t index)
{
// We can read the frame's arguments directly for f.apply(x, arguments).
if (ins->isCall()) {
if (*ins->toCall()->resumePoint()->pc() == JSOP_FUNAPPLY &&
ins->toCall()->numActualArgs() == 2 &&
index == MCall::IndexOfArgument(1))
{
return true;
}
}
// arguments[i] can read fp->canonicalActualArg(i) directly.
if (ins->isCallGetElement() && index == 0)
return true;
// arguments.length length can read fp->numActualArgs() directly.
if (ins->isCallGetProperty() && index == 0 && ins->toCallGetProperty()->name() == cx->names().length)
return true;
return false;
}
bool
jit::AnalyzeArgumentsUsage(JSContext *cx, JSScript *scriptArg)
{
RootedScript script(cx, scriptArg);
types::AutoEnterAnalysis enter(cx);
JS_ASSERT(!script->analyzedArgsUsage());
// Treat the script as needing an arguments object until we determine it
// does not need one. This both allows us to easily see where the arguments
// object can escape through assignments to the function's named arguments,
// and also simplifies handling of early returns.
script->setNeedsArgsObj(true);
if (!jit::IsIonEnabled(cx) || !script->compileAndGo())
return true;
static const uint32_t MAX_SCRIPT_SIZE = 10000;
if (script->length() > MAX_SCRIPT_SIZE)
return true;
if (!script->ensureHasTypes(cx))
return false;
LifoAlloc alloc(types::TypeZone::TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
TempAllocator temp(&alloc);
IonContext ictx(cx, &temp);
if (!cx->compartment()->ensureJitCompartmentExists(cx))
return false;
MIRGraph graph(&temp);
CompileInfo info(script, script->functionNonDelazifying(),
/* osrPc = */ nullptr, /* constructing = */ false,
ArgumentsUsageAnalysis,
/* needsArgsObj = */ true);
AutoTempAllocatorRooter root(cx, &temp);
const OptimizationInfo *optimizationInfo = js_IonOptimizations.get(Optimization_Normal);
types::CompilerConstraintList *constraints = types::NewCompilerConstraintList(temp);
if (!constraints)
return false;
BaselineInspector inspector(script);
const JitCompileOptions options(cx);
IonBuilder builder(nullptr, CompileCompartment::get(cx->compartment()), options, &temp, &graph, constraints,
&inspector, &info, optimizationInfo, /* baselineFrame = */ nullptr);
if (!builder.build()) {
if (builder.abortReason() == AbortReason_Alloc)
return false;
return true;
}
if (!SplitCriticalEdges(graph))
return false;
if (!RenumberBlocks(graph))
return false;
if (!BuildDominatorTree(graph))
return false;
if (!EliminatePhis(&builder, graph, AggressiveObservability))
return false;
MDefinition *argumentsValue = graph.begin()->getSlot(info.argsObjSlot());
for (MUseDefIterator uses(argumentsValue); uses; uses++) {
MDefinition *use = uses.def();
// Don't track |arguments| through assignments to phis.
if (!use->isInstruction())
return true;
if (!ArgumentsUseCanBeLazy(cx, script, use->toInstruction(), uses.index()))
return true;
}
script->setNeedsArgsObj(false);
return true;
}

Просмотреть файл

@ -7,8 +7,6 @@
#ifndef jit_IonAnalysis_h
#define jit_IonAnalysis_h
#ifdef JS_ION
// This file declares various analysis passes that operate on MIR.
#include "jit/IonAllocPolicy.h"
@ -138,12 +136,7 @@ AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
types::TypeObject *type, HandleObject baseobj,
Vector<types::TypeNewScript::Initializer> *initializerList);
bool
AnalyzeArgumentsUsage(JSContext *cx, JSScript *script);
} // namespace jit
} // namespace js
#endif // JS_ION
#endif /* jit_IonAnalysis_h */

Просмотреть файл

@ -124,7 +124,6 @@ IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp,
argTypes(nullptr),
typeArray(nullptr),
typeArrayHint(0),
bytecodeTypeMap(nullptr),
loopDepth_(loopDepth),
callerResumePoint_(nullptr),
callerBuilder_(nullptr),
@ -146,7 +145,7 @@ IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp,
script_ = info->script();
pc = info->startPC();
JS_ASSERT(script()->hasBaselineScript() == (info->executionMode() != ArgumentsUsageAnalysis));
JS_ASSERT(script()->hasBaselineScript());
JS_ASSERT(!!analysisContext == (info->executionMode() == DefinitePropertiesAnalysis));
}
@ -610,17 +609,6 @@ IonBuilder::init()
if (!analysis().init(alloc(), gsn))
return false;
// The baseline script normally has the bytecode type map, but compute
// it ourselves if we do not have a baseline script.
if (script()->hasBaselineScript()) {
bytecodeTypeMap = script()->baselineScript()->bytecodeTypeMap();
} else {
bytecodeTypeMap = alloc_->lifoAlloc()->newArrayUninitialized<uint32_t>(script()->nTypeSets());
if (!bytecodeTypeMap)
return false;
types::FillBytecodeTypeMap(script(), bytecodeTypeMap);
}
return true;
}
@ -998,10 +986,8 @@ IonBuilder::initScopeChain(MDefinition *callee)
scope = MFunctionEnvironment::New(alloc(), callee);
current->add(scope);
// This reproduce what is done in CallObject::createForFunction. Skip
// this for analyses, as the script might not have a baseline script
// with template objects yet.
if (fun->isHeavyweight() && !info().executionModeIsAnalysis()) {
// This reproduce what is done in CallObject::createForFunction
if (fun->isHeavyweight()) {
if (fun->isNamedLambda()) {
scope = createDeclEnvObject(callee, scope);
if (!scope)
@ -3587,12 +3573,7 @@ IonBuilder::jsop_try()
return abort("Has try-finally");
// Try-catch within inline frames is not yet supported.
JS_ASSERT(!isInlineBuilder());
// Try-catch during the arguments usage analysis is not yet supported. Code
// accessing the arguments within the 'catch' block is not accounted for.
if (info().executionMode() == ArgumentsUsageAnalysis)
return abort("Try-catch during arguments usage analysis");
JS_ASSERT(script()->uninlineable() && !isInlineBuilder());
graph().setHasTryBlock();
@ -4115,10 +4096,6 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo)
if (target == nullptr)
return InliningDecision_DontInline;
// Never inline during the arguments usage analysis.
if (info().executionMode() == ArgumentsUsageAnalysis)
return InliningDecision_DontInline;
// Native functions provide their own detection in inlineNativeCall().
if (target->isNative())
return InliningDecision_Inline;
@ -5664,8 +5641,14 @@ IonBuilder::jsop_initprop(PropertyName *name)
// In parallel execution, we never require write barriers. See
// forkjoin.cpp for more information.
if (info().executionMode() == ParallelExecution)
switch (info().executionMode()) {
case SequentialExecution:
case DefinitePropertiesAnalysis:
break;
case ParallelExecution:
needsBarrier = false;
break;
}
if (templateObject->isFixedSlot(shape->slot())) {
MStoreFixedSlot *store = MStoreFixedSlot::New(alloc(), obj, shape->slot(), value);
@ -6681,21 +6664,6 @@ IonBuilder::jsop_getelem()
MDefinition *index = current->pop();
MDefinition *obj = current->pop();
// Always use a call if we are performing analysis and not actually
// emitting code, to simplify later analysis.
if (info().executionModeIsAnalysis()) {
MInstruction *ins = MCallGetElement::New(alloc(), obj, index);
current->add(ins);
current->push(ins);
if (!resumeAfter(ins))
return false;
types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(ins, types, true);
}
bool emitted = false;
if (!getElemTryTypedObject(&emitted, obj, index) || emitted)
@ -8568,11 +8536,11 @@ IonBuilder::jsop_getprop(PropertyName *name)
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
current->peek(-1), name, types);
// Always use a call if we are performing analysis and
// Always use a call if we are doing the definite properties analysis and
// not actually emitting code, to simplify later analysis. Also skip deeper
// analysis if there are no known types for this operation, as it will
// always invalidate when executing.
if (info().executionModeIsAnalysis() || types->empty()) {
if (info().executionMode() == DefinitePropertiesAnalysis || types->empty()) {
MDefinition *obj = current->peek(-1);
MCallGetProperty *call = MCallGetProperty::New(alloc(), obj, name, *pc == JSOP_CALLPROP);
current->add(call);
@ -8581,7 +8549,7 @@ IonBuilder::jsop_getprop(PropertyName *name)
// constants read off the prototype chain, to allow inlining later on.
// In this case we still need the getprop call so that the later
// analysis knows when the |this| value has been read from.
if (info().executionModeIsAnalysis()) {
if (info().executionMode() == DefinitePropertiesAnalysis) {
if (!getPropTryConstant(&emitted, name, types) || emitted)
return emitted;
}
@ -9048,7 +9016,7 @@ IonBuilder::jsop_setprop(PropertyName *name)
// Always use a call if we are doing the definite properties analysis and
// not actually emitting code, to simplify later analysis.
if (info().executionModeIsAnalysis()) {
if (info().executionMode() == DefinitePropertiesAnalysis) {
MInstruction *ins = MCallSetProperty::New(alloc(), obj, value, name, script()->strict());
current->add(ins);
current->push(value);
@ -9634,10 +9602,11 @@ IonBuilder::jsop_this()
return true;
}
// If we are doing an analysis, we might not yet know the type of |this|.
// Instead of bailing out just push the |this| slot, as this code won't
// actually execute and it does not matter whether |this| is primitive.
if (info().executionModeIsAnalysis()) {
// If we are doing a definite properties analysis, we don't yet know the
// |this| type as its type object is being created right now. Instead of
// bailing out just push the |this| slot, as this code won't actually
// execute and it does not matter whether |this| is primitive.
if (info().executionMode() == DefinitePropertiesAnalysis) {
current->pushSlot(info().thisSlot());
return true;
}
@ -10038,7 +10007,7 @@ IonBuilder::addShapeGuard(MDefinition *obj, Shape *const shape, BailoutKind bail
types::TemporaryTypeSet *
IonBuilder::bytecodeTypes(jsbytecode *pc)
{
return types::TypeScript::BytecodeTypes(script(), pc, bytecodeTypeMap, &typeArrayHint, typeArray);
return types::TypeScript::BytecodeTypes(script(), pc, &typeArrayHint, typeArray);
}
TypeDescrSetHash *

Просмотреть файл

@ -837,7 +837,6 @@ class IonBuilder : public MIRGenerator
types::TemporaryTypeSet *thisTypes, *argTypes, *typeArray;
uint32_t typeArrayHint;
uint32_t *bytecodeTypeMap;
GSNCache gsn;
ScopeCoordinateNameCache scopeCoordinateNameCache;

Просмотреть файл

@ -1482,6 +1482,12 @@ IonBuilder::inlineForceSequentialOrInParallelSection(CallInfo &callInfo)
ExecutionMode executionMode = info().executionMode();
switch (executionMode) {
case SequentialExecution:
case DefinitePropertiesAnalysis:
// In sequential mode, leave as is, because we'd have to
// access the "in warmup" flag of the runtime.
return InliningStatus_NotInlined;
case ParallelExecution: {
// During Parallel Exec, we always force sequential, so
// replace with true. This permits UCE to eliminate the
@ -1492,11 +1498,6 @@ IonBuilder::inlineForceSequentialOrInParallelSection(CallInfo &callInfo)
current->push(ins);
return InliningStatus_Inlined;
}
default:
// In sequential mode, leave as is, because we'd have to
// access the "in warmup" flag of the runtime.
return InliningStatus_NotInlined;
}
MOZ_ASSUME_UNREACHABLE("Invalid execution mode");
@ -1521,6 +1522,11 @@ IonBuilder::inlineForkJoinGetSlice(CallInfo &callInfo)
callInfo.setImplicitlyUsedUnchecked();
switch (info().executionMode()) {
case SequentialExecution:
case DefinitePropertiesAnalysis:
// ForkJoinGetSlice acts as identity for sequential execution.
current->push(callInfo.getArg(0));
return InliningStatus_Inlined;
case ParallelExecution:
if (LIRGenerator::allowInlineForkJoinGetSlice()) {
MForkJoinGetSlice *getSlice = MForkJoinGetSlice::New(alloc(),
@ -1530,11 +1536,6 @@ IonBuilder::inlineForkJoinGetSlice(CallInfo &callInfo)
return InliningStatus_Inlined;
}
return InliningStatus_NotInlined;
default:
// ForkJoinGetSlice acts as identity for sequential execution.
current->push(callInfo.getArg(0));
return InliningStatus_Inlined;
}
MOZ_ASSUME_UNREACHABLE("Invalid execution mode");
@ -1550,10 +1551,11 @@ IonBuilder::inlineNewDenseArray(CallInfo &callInfo)
// par. mode we use inlined MIR.
ExecutionMode executionMode = info().executionMode();
switch (executionMode) {
case SequentialExecution:
case DefinitePropertiesAnalysis:
return inlineNewDenseArrayForSequentialExecution(callInfo);
case ParallelExecution:
return inlineNewDenseArrayForParallelExecution(callInfo);
default:
return inlineNewDenseArrayForSequentialExecution(callInfo);
}
MOZ_ASSUME_UNREACHABLE("unknown ExecutionMode");

Просмотреть файл

@ -1922,6 +1922,81 @@ TypeCompartment::newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<
return object;
}
static inline jsbytecode *
PreviousOpcode(HandleScript script, jsbytecode *pc)
{
ScriptAnalysis *analysis = script->analysis();
JS_ASSERT(analysis->isReachable(pc));
if (pc == script->code())
return nullptr;
for (pc--;; pc--) {
if (analysis->isReachable(pc))
break;
}
return pc;
}
/*
* If pc is an array initializer within an outer multidimensional array
* initializer, find the opcode of the previous newarray. nullptr otherwise.
*/
static inline jsbytecode *
FindPreviousInnerInitializer(HandleScript script, jsbytecode *initpc)
{
if (!script->hasAnalysis())
return nullptr;
if (!script->analysis()->isReachable(initpc))
return nullptr;
/*
* Pattern match the following bytecode, which will appear between
* adjacent initializer elements:
*
* endinit (for previous initializer)
* initelem_array (for previous initializer)
* newarray
*/
if (*initpc != JSOP_NEWARRAY)
return nullptr;
jsbytecode *last = PreviousOpcode(script, initpc);
if (!last || *last != JSOP_INITELEM_ARRAY)
return nullptr;
last = PreviousOpcode(script, last);
if (!last || *last != JSOP_ENDINIT)
return nullptr;
/*
* Find the start of the previous initializer. Keep track of initializer
* depth to skip over inner initializers within the previous one (e.g. for
* arrays with three or more dimensions).
*/
size_t initDepth = 0;
jsbytecode *previnit;
for (previnit = last; previnit; previnit = PreviousOpcode(script, previnit)) {
if (*previnit == JSOP_ENDINIT)
initDepth++;
if (*previnit == JSOP_NEWINIT ||
*previnit == JSOP_NEWARRAY ||
*previnit == JSOP_NEWOBJECT)
{
if (--initDepth == 0)
break;
}
}
if (!previnit || *previnit != JSOP_NEWARRAY)
return nullptr;
return previnit;
}
TypeObject *
TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key)
{
@ -1940,8 +2015,24 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
TypeObject *res = nullptr;
/*
* If this is an array initializer nested in another array initializer,
* try to reuse the type objects from earlier elements to avoid
* distinguishing elements of the outer array unnecessarily.
*/
jsbytecode *pc = key.script->offsetToPC(key.offset);
RootedScript keyScript(cx, key.script);
jsbytecode *prev = FindPreviousInnerInitializer(keyScript, pc);
if (prev) {
AllocationSiteKey nkey;
nkey.script = key.script;
nkey.offset = key.script->pcToOffset(prev);
nkey.kind = JSProto_Array;
AllocationSiteTable::Ptr p = cx->compartment()->types.allocationSiteTable->lookup(nkey);
if (p)
res = p->value();
}
if (!res) {
RootedObject proto(cx);
@ -3397,21 +3488,6 @@ IsAboutToBeFinalized(TypeObjectKey *key)
return isAboutToBeFinalized;
}
void
types::FillBytecodeTypeMap(JSScript *script, uint32_t *bytecodeMap)
{
uint32_t added = 0;
for (jsbytecode *pc = script->code(); pc < script->codeEnd(); pc += GetBytecodeLength(pc)) {
JSOp op = JSOp(*pc);
if (js_CodeSpec[op].format & JOF_TYPESET) {
bytecodeMap[added++] = script->pcToOffset(pc);
if (added == script->nTypeSets())
break;
}
}
JS_ASSERT(added == script->nTypeSets());
}
void
types::TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
{
@ -3533,6 +3609,28 @@ JSScript::makeTypes(JSContext *cx)
}
#endif
return analyzedArgsUsage() || ensureRanAnalysis(cx);
}
bool
JSScript::makeAnalysis(JSContext *cx)
{
JS_ASSERT(types && !types->analysis);
AutoEnterAnalysis enter(cx);
types->analysis = cx->typeLifoAlloc().new_<ScriptAnalysis>(this);
if (!types->analysis)
return false;
RootedScript self(cx, this);
if (!self->types->analysis->analyzeBytecode(cx)) {
self->types->analysis = nullptr;
return false;
}
return true;
}
@ -4261,8 +4359,6 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
/* Sweep and find compressed indexes for each compiler output. */
size_t newCompilerOutputCount = 0;
#ifdef JS_ION
if (compilerOutputs) {
for (size_t i = 0; i < compilerOutputs->length(); i++) {
CompilerOutput &output = (*compilerOutputs)[i];
@ -4277,7 +4373,6 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
}
}
}
#endif
{
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI);
@ -4289,15 +4384,11 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
if (releaseTypes) {
if (script->hasParallelIonScript()) {
#ifdef JS_ION
// It's possible that we preserved the parallel
// IonScript. The heuristic for their preservation is
// independent of general JIT code preservation.
MOZ_ASSERT(jit::ShouldPreserveParallelJITCode(rt, script));
script->parallelIonScript()->recompileInfoRef().shouldSweep(*this);
#else
MOZ_CRASH();
#endif
} else {
script->types->destroy();
script->types = nullptr;
@ -4349,6 +4440,14 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
JS_ALWAYS_TRUE(compilerOutputs->resize(newCompilerOutputCount));
}
{
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_CLEAR_SCRIPT_ANALYSIS);
for (CellIterUnderGC i(zone(), FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
script->clearAnalysis();
}
}
{
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_FREE_TI_ARENA);
rt->freeLifoAlloc.transferFrom(&oldAlloc);

Просмотреть файл

@ -150,13 +150,7 @@ enum ExecutionMode {
* MIR analysis performed when invoking 'new' on a script, to determine
* definite properties. Used by the optimizing JIT.
*/
DefinitePropertiesAnalysis,
/*
* MIR analysis performed when executing a script which uses its arguments,
* when it is not known whether a lazy arguments value can be used.
*/
ArgumentsUsageAnalysis
DefinitePropertiesAnalysis
};
/*
@ -192,6 +186,10 @@ namespace jit {
class TempAllocator;
}
namespace analyze {
class ScriptAnalysis;
}
namespace types {
class TypeZone;
@ -1244,6 +1242,9 @@ class TypeScript
{
friend class ::JSScript;
/* Analysis information for the script, cleared on each GC. */
analyze::ScriptAnalysis *analysis;
public:
/* Array of type type sets for variables and JOF_TYPESET ops. */
StackTypeSet *typeArray() const { return (StackTypeSet *) (uintptr_t(this) + sizeof(TypeScript)); }
@ -1257,7 +1258,7 @@ class TypeScript
static inline StackTypeSet *BytecodeTypes(JSScript *script, jsbytecode *pc);
template <typename TYPESET>
static inline TYPESET *BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *bytecodeMap,
static inline TYPESET *BytecodeTypes(JSScript *script, jsbytecode *pc,
uint32_t *hint, TYPESET *typeArray);
/* Get a type object for an allocation site in this script. */
@ -1309,9 +1310,6 @@ class TypeScript
#endif
};
void
FillBytecodeTypeMap(JSScript *script, uint32_t *bytecodeMap);
class RecompileInfo;
// Allocate a CompilerOutput for a finished compilation and generate the type

Просмотреть файл

@ -567,10 +567,15 @@ TypeScript::ArgTypes(JSScript *script, unsigned i)
template <typename TYPESET>
/* static */ inline TYPESET *
TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *bytecodeMap,
uint32_t *hint, TYPESET *typeArray)
TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPESET *typeArray)
{
JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
#ifdef JS_ION
uint32_t *bytecodeMap = script->baselineScript()->bytecodeTypeMap();
#else
uint32_t *bytecodeMap = nullptr;
MOZ_CRASH();
#endif
uint32_t offset = script->pcToOffset(pc);
// See if this pc is the next typeset opcode after the last one looked up.
@ -612,11 +617,11 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc)
JS_ASSERT(CurrentThreadCanAccessRuntime(script->runtimeFromMainThread()));
#ifdef JS_ION
uint32_t *hint = script->baselineScript()->bytecodeTypeMap() + script->nTypeSets();
return BytecodeTypes(script, pc, script->baselineScript()->bytecodeTypeMap(),
hint, script->types->typeArray());
#else
uint32_t *hint = nullptr;
MOZ_CRASH();
#endif
return BytecodeTypes(script, pc, hint, script->types->typeArray());
}
struct AllocationSiteKey : public DefaultHasher<AllocationSiteKey> {
@ -1351,6 +1356,39 @@ JSScript::ensureHasTypes(JSContext *cx)
return types || makeTypes(cx);
}
inline bool
JSScript::ensureRanAnalysis(JSContext *cx)
{
js::types::AutoEnterAnalysis aea(cx);
if (!ensureHasTypes(cx))
return false;
if (!hasAnalysis() && !makeAnalysis(cx))
return false;
JS_ASSERT(hasAnalysis());
return true;
}
inline bool
JSScript::hasAnalysis()
{
return types && types->analysis;
}
inline js::analyze::ScriptAnalysis *
JSScript::analysis()
{
JS_ASSERT(hasAnalysis());
return types->analysis;
}
inline void
JSScript::clearAnalysis()
{
if (types)
types->analysis = nullptr;
}
namespace js {
template <>

Просмотреть файл

@ -284,6 +284,19 @@ js_DumpPCCounts(JSContext *cx, HandleScript script, js::Sprinter *sp)
// Bytecode Parser
/////////////////////////////////////////////////////////////////////
// Ensure that script analysis reports the same stack depth.
static void
AssertStackDepth(JSScript *script, uint32_t offset, uint32_t stackDepth) {
/*
* If this assertion fails, run the failing test case under gdb and use the
* following gdb command to understand the execution path of this function.
*
* call js_DumpScriptDepth(cx, script, pc)
*/
if (script->hasAnalysis())
script->analysis()->assertMatchingStackDepthAtOffset(offset, stackDepth);
}
namespace {
class BytecodeParser
@ -487,6 +500,7 @@ BytecodeParser::addJump(uint32_t offset, uint32_t *currentOffset,
code = alloc().new_<Bytecode>();
if (!code)
return false;
AssertStackDepth(script_, offset, stackDepth);
if (!code->captureOffsetStack(alloc(), offsetStack, stackDepth)) {
reportOOM();
return false;
@ -639,6 +653,7 @@ BytecodeParser::parse()
reportOOM();
return false;
}
AssertStackDepth(script_, successorOffset, stackDepth);
if (!nextcode->captureOffsetStack(alloc(), offsetStack, stackDepth)) {
reportOOM();
return false;

Просмотреть файл

@ -3450,17 +3450,13 @@ void
JSScript::setArgumentsHasVarBinding()
{
argsHasVarBinding_ = true;
#ifdef JS_ION
needsArgsAnalysis_ = true;
#else
// The arguments analysis is performed by IonBuilder.
needsArgsObj_ = true;
#endif
}
void
JSScript::setNeedsArgsObj(bool needsArgsObj)
{
JS_ASSERT(!analyzedArgsUsage());
JS_ASSERT_IF(needsArgsObj, argumentsHasVarBinding());
needsArgsAnalysis_ = false;
needsArgsObj_ = needsArgsObj;

Просмотреть файл

@ -50,6 +50,10 @@ class Shape;
class WatchpointMap;
class NestedScopeObject;
namespace analyze {
class ScriptAnalysis;
}
namespace frontend {
class BytecodeEmitter;
}
@ -1130,7 +1134,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
/*
* As an optimization, even when argsHasLocalBinding, the function prologue
* may not need to create an arguments object. This is determined by
* needsArgsObj which is set by AnalyzeArgumentsUsage before running
* needsArgsObj which is set by ScriptAnalysis::analyzeSSA before running
* the script the first time. When !needsArgsObj, the prologue may simply
* write MagicValue(JS_OPTIMIZED_ARGUMENTS) to 'arguments's slot and any
* uses of 'arguments' will be guaranteed to handle this magic value.
@ -1138,7 +1142,6 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
* that needsArgsObj is only called after the script has been analyzed.
*/
bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
inline bool ensureHasAnalyzedArgsUsage(JSContext *cx);
bool needsArgsObj() const {
JS_ASSERT(analyzedArgsUsage());
return needsArgsObj_;
@ -1314,6 +1317,19 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
/* Ensure the script has a TypeScript. */
inline bool ensureHasTypes(JSContext *cx);
/*
* Ensure the script has bytecode analysis information. Performed when the
* script first runs, or first runs after a TypeScript GC purge.
*/
inline bool ensureRanAnalysis(JSContext *cx);
/* Ensure the script has type inference analysis information. */
inline bool ensureRanInference(JSContext *cx);
inline bool hasAnalysis();
inline void clearAnalysis();
inline js::analyze::ScriptAnalysis *analysis();
inline js::GlobalObject &global() const;
js::GlobalObject &uninlinedGlobal() const;
@ -1326,6 +1342,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
private:
bool makeTypes(JSContext *cx);
bool makeAnalysis(JSContext *cx);
public:
uint32_t getUseCount() const {

Просмотреть файл

@ -11,7 +11,6 @@
#include "jit/AsmJSLink.h"
#include "jit/BaselineJIT.h"
#include "jit/IonAnalysis.h"
#include "vm/ScopeObject.h"
#include "jscompartmentinlines.h"
@ -174,16 +173,4 @@ JSScript::setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselin
updateBaselineOrIonRaw();
}
inline bool
JSScript::ensureHasAnalyzedArgsUsage(JSContext *cx)
{
if (analyzedArgsUsage())
return true;
#ifdef JS_ION
return js::jit::AnalyzeArgumentsUsage(cx, this);
#else
MOZ_CRASH();
#endif
}
#endif /* jsscriptinlines_h */

Просмотреть файл

@ -33,7 +33,6 @@
#include "builtin/Eval.h"
#include "jit/BaselineJIT.h"
#include "jit/Ion.h"
#include "jit/IonAnalysis.h"
#include "js/OldDebugAPI.h"
#include "vm/Debugger.h"
#include "vm/Opcodes.h"
@ -2866,7 +2865,7 @@ CASE(JSOP_TABLESWITCH)
CASE(JSOP_ARGUMENTS)
JS_ASSERT(!REGS.fp()->fun()->hasRest());
if (!script->ensureHasAnalyzedArgsUsage(cx))
if (!script->analyzedArgsUsage() && !script->ensureRanAnalysis(cx))
goto error;
if (script->needsArgsObj()) {
ArgumentsObject *obj = ArgumentsObject::createExpected(cx, REGS.fp());

Просмотреть файл

@ -1150,7 +1150,7 @@ class DebugScopeProxy : public BaseProxyHandler
if (scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
CallObject &callobj = scope->as<CallObject>();
RootedScript script(cx, callobj.callee().nonLazyScript());
if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
if (!script->ensureHasTypes(cx))
return false;
Bindings &bindings = script->bindings;