Bug 917441 - Remove dependence of IonBuilder on ScriptAnalysis, r=jandem.

This commit is contained in:
Brian Hackett 2013-09-18 09:43:21 -06:00
Родитель 89075a8c47
Коммит 67b88e4fd7
16 изменённых файлов: 140 добавлений и 63 удалений

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

@ -4817,6 +4817,16 @@ ICSetElem_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
return tailCallVM(DoSetElemFallbackInfo, masm);
}
void
BaselineScript::noteArrayWriteHole(uint32_t pcOffset)
{
ICEntry &entry = icEntryFromPCOffset(pcOffset);
ICFallbackStub *stub = entry.fallbackStub();
if (stub->isSetElem_Fallback())
stub->toSetElem_Fallback()->noteArrayWriteHole();
}
//
// SetElem_Dense
//

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

@ -3375,6 +3375,13 @@ class ICSetElem_Fallback : public ICFallbackStub
return space->allocate<ICSetElem_Fallback>(code);
}
void noteArrayWriteHole() {
extra_ = 1;
}
bool hasArrayWriteHole() const {
return extra_;
}
// Compiler for this stub kind.
class Compiler : public ICStubCompiler {
protected:

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

@ -26,6 +26,12 @@ SetElemICInspector::sawOOBDenseWrite() const
if (stub->isSetElem_DenseAdd())
return true;
}
// Check for a write hole bit on the SetElem_Fallback stub.
ICStub *stub = icEntry_->fallbackStub();
if (stub->isSetElem_Fallback())
return stub->toSetElem_Fallback()->hasArrayWriteHole();
return false;
}

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

@ -267,6 +267,7 @@ struct BaselineScript
void toggleSPS(bool enable);
void noteAccessedGetter(uint32_t pcOffset);
void noteArrayWriteHole(uint32_t pcOffset);
static size_t offsetOfFlags() {
return offsetof(BaselineScript, flags_);

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

@ -15,7 +15,9 @@ using namespace js::jit;
BytecodeAnalysis::BytecodeAnalysis(JSScript *script)
: script_(script),
infos_()
infos_(),
usesScopeChain_(false),
hasTryFinally_(false)
{
}
@ -144,6 +146,26 @@ BytecodeAnalysis::init(JSContext *cx)
}
break;
case JSOP_NAME:
case JSOP_CALLNAME:
case JSOP_BINDNAME:
case JSOP_SETNAME:
case JSOP_DELNAME:
case JSOP_GETALIASEDVAR:
case JSOP_CALLALIASEDVAR:
case JSOP_SETALIASEDVAR:
case JSOP_LAMBDA:
case JSOP_DEFFUN:
case JSOP_DEFVAR:
case JSOP_DEFCONST:
case JSOP_SETCONST:
usesScopeChain_ = true;
break;
case JSOP_FINALLY:
hasTryFinally_ = true;
break;
default:
break;
}

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

@ -39,6 +39,9 @@ class BytecodeAnalysis
JSScript *script_;
Vector<BytecodeInfo, 0, IonAllocPolicy> infos_;
bool usesScopeChain_;
bool hasTryFinally_;
public:
explicit BytecodeAnalysis(JSScript *script);
@ -54,6 +57,14 @@ class BytecodeAnalysis
return &infos_[pc - script_->code];
return NULL;
}
bool usesScopeChain() {
return usesScopeChain_;
}
bool hasTryFinally() {
return hasTryFinally_;
}
};

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

@ -1606,9 +1606,6 @@ IonCompile(JSContext *cx, JSScript *script,
script);
#endif
if (!script->ensureRanAnalysis(cx))
return AbortReason_Alloc;
LifoAlloc *alloc = cx->new_<LifoAlloc>(BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
if (!alloc)
return AbortReason_Alloc;

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

@ -42,6 +42,7 @@ IonBuilder::IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
cx(cx),
baselineFrame_(baselineFrame),
abortReason_(AbortReason_Disable),
analysis_(info->script()),
loopDepth_(loopDepth),
callerResumePoint_(NULL),
callerBuilder_(NULL),
@ -231,10 +232,10 @@ IonBuilder::canEnterInlinedFunction(JSFunction *target)
JSScript *targetScript = target->nonLazyScript();
if (!targetScript->ensureRanAnalysis(cx))
if (targetScript->uninlineable)
return false;
if (targetScript->uninlineable)
if (!targetScript->analyzedArgsUsage())
return false;
if (targetScript->needsArgsObj())
@ -370,7 +371,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock *entry, jsbytecode *start, jsbytecod
continue;
if (slot >= info().firstStackSlot())
continue;
if (!script()->analysis()->maybeCode(pc))
if (!analysis().maybeInfo(pc))
continue;
MPhi *phi = entry->getSlot(slot)->toPhi();
@ -491,11 +492,23 @@ IonBuilder::pushLoop(CFGState::State initial, jsbytecode *stopAt, MBasicBlock *e
}
bool
IonBuilder::build()
IonBuilder::init()
{
if (!script()->ensureHasBytecodeTypeMap(cx))
return false;
if (!analysis().init(cx))
return false;
return true;
}
bool
IonBuilder::build()
{
if (!init())
return false;
setCurrentAndSpecializePhis(newBlock(pc));
if (!current)
return false;
@ -633,11 +646,11 @@ bool
IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoint,
CallInfo &callInfo)
{
inlineCallInfo_ = &callInfo;
if (!script()->ensureHasBytecodeTypeMap(cx))
if (!init())
return false;
inlineCallInfo_ = &callInfo;
IonSpew(IonSpew_Scripts, "Inlining script %s:%d (%p)",
script()->filename(), script()->lineno, (void *)script());
@ -842,7 +855,7 @@ IonBuilder::initScopeChain(MDefinition *callee)
// from earlier. However, always make a scope chain when |needsArgsObj| is true
// for the script, since arguments object construction requires the scope chain
// to be passed in.
if (!info().needsArgsObj() && !script()->analysis()->usesScopeChain())
if (!info().needsArgsObj() && !analysis().usesScopeChain())
return true;
// The scope chain is only tracked in scripts that have NAME opcodes which
@ -3355,7 +3368,7 @@ IonBuilder::jsop_try()
return abort("Try-catch support disabled");
// Try-finally is not yet supported.
if (script()->analysis()->hasTryFinally())
if (analysis().hasTryFinally())
return abort("Has try-finally");
// Try-catch within inline frames is not yet supported.
@ -3401,7 +3414,7 @@ IonBuilder::jsop_try()
return false;
MBasicBlock *successor;
if (script()->analysis()->maybeCode(afterTry)) {
if (analysis().maybeInfo(afterTry)) {
successor = newBlock(current, afterTry);
if (!successor)
return false;
@ -3748,7 +3761,10 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
BaselineInspector inspector(cx, calleeScript);
// Improve type information of |this| when not set.
if (callInfo.constructing() && !callInfo.thisArg()->resultTypeSet()) {
if (callInfo.constructing() &&
!callInfo.thisArg()->resultTypeSet() &&
calleeScript->types)
{
types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript);
if (!types->unknown()) {
MTypeBarrier *barrier = MTypeBarrier::New(callInfo.thisArg(), cloneTypeSet(types), Bailout_Normal);
@ -3773,7 +3789,6 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
IonBuilder inlineBuilder(cx, &temp(), &graph(), &inspector, info, NULL,
inliningDepth_ + 1, loopDepth_);
if (!inlineBuilder.buildInline(this, outerResumePoint, callInfo)) {
JS_ASSERT(calleeScript->hasAnalysis());
if (cx->isExceptionPending()) {
IonSpew(IonSpew_Abort, "Inline builder raised exception.");
abortReason_ = AbortReason_Error;
@ -3931,7 +3946,7 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo)
return false;
}
if (targetScript->analysis()->hasLoops()) {
if (targetScript->hasLoops()) {
IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: big function that contains a loop",
targetScript->filename(), targetScript->lineno);
return false;
@ -5087,7 +5102,7 @@ IonBuilder::testNeedsArgumentCheck(JSContext *cx, JSFunction *target, CallInfo &
return true;
JSScript *targetScript = target->nonLazyScript();
if (!targetScript->hasAnalysis())
if (!targetScript->types)
return true;
if (!ArgumentTypesMatch(callInfo.thisArg(), cloneTypeSet(types::TypeScript::ThisTypes(targetScript))))
@ -5661,7 +5676,8 @@ IonBuilder::addBlock(MBasicBlock *block, uint32_t loopDepth)
MBasicBlock *
IonBuilder::newBlock(MBasicBlock *predecessor, jsbytecode *pc)
{
MBasicBlock *block = MBasicBlock::New(graph(), info(), predecessor, pc, MBasicBlock::NORMAL);
MBasicBlock *block = MBasicBlock::New(graph(), &analysis(), info(),
predecessor, pc, MBasicBlock::NORMAL);
return addBlock(block, loopDepth_);
}
@ -5683,7 +5699,8 @@ IonBuilder::newBlockPopN(MBasicBlock *predecessor, jsbytecode *pc, uint32_t popp
MBasicBlock *
IonBuilder::newBlockAfter(MBasicBlock *at, MBasicBlock *predecessor, jsbytecode *pc)
{
MBasicBlock *block = MBasicBlock::New(graph(), info(), predecessor, pc, MBasicBlock::NORMAL);
MBasicBlock *block = MBasicBlock::New(graph(), &analysis(), info(),
predecessor, pc, MBasicBlock::NORMAL);
if (!block)
return NULL;
graph().insertBlockAfter(at, block);
@ -5693,7 +5710,8 @@ IonBuilder::newBlockAfter(MBasicBlock *at, MBasicBlock *predecessor, jsbytecode
MBasicBlock *
IonBuilder::newBlock(MBasicBlock *predecessor, jsbytecode *pc, uint32_t loopDepth)
{
MBasicBlock *block = MBasicBlock::New(graph(), info(), predecessor, pc, MBasicBlock::NORMAL);
MBasicBlock *block = MBasicBlock::New(graph(), &analysis(), info(),
predecessor, pc, MBasicBlock::NORMAL);
return addBlock(block, loopDepth);
}
@ -5719,7 +5737,7 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
uint32_t slot = info().scopeChainSlot();
MInstruction *scopev;
if (script()->analysis()->usesScopeChain()) {
if (analysis().usesScopeChain()) {
scopev = MOsrScopeChain::New(entry);
} else {
// Use an undefined value if the script does not need its scope
@ -6470,7 +6488,7 @@ IonBuilder::jsop_intrinsic(PropertyName *name)
bool
IonBuilder::jsop_bindname(PropertyName *name)
{
JS_ASSERT(script()->analysis()->usesScopeChain());
JS_ASSERT(analysis().usesScopeChain());
MDefinition *scopeChain = current->scopeChain();
MBindNameCache *ins = MBindNameCache::New(scopeChain, name, script(), pc);
@ -7348,13 +7366,10 @@ IonBuilder::jsop_setelem_dense(types::TemporaryTypeSet::DoubleConversion convers
MOZ_ASSUME_UNREACHABLE("Unknown double conversion");
}
bool writeHole;
bool writeHole = false;
if (safety == SetElem_Normal) {
writeHole = script()->analysis()->getCode(pc).arrayWriteHole;
SetElemICInspector icInspect(inspector->setElemICInspector(pc));
writeHole |= icInspect.sawOOBDenseWrite();
} else {
writeHole = false;
writeHole = icInspect.sawOOBDenseWrite();
}
// Use MStoreElementHole if this SETELEM has written to out-of-bounds
@ -8399,9 +8414,7 @@ IonBuilder::getPropTryCache(bool *emitted, PropertyName *name, jsid id,
bool barrier, types::TemporaryTypeSet *types)
{
JS_ASSERT(*emitted == false);
bool accessGetter =
script()->analysis()->getCode(pc).accessGetter ||
inspector->hasSeenAccessedGetter(pc);
bool accessGetter = inspector->hasSeenAccessedGetter(pc);
MDefinition *obj = current->peek(-1);
@ -8831,7 +8844,7 @@ IonBuilder::jsop_lambda(JSFunction *fun)
if (fun->isInterpreted() && !fun->getOrCreateScript(cx))
return false;
JS_ASSERT(script()->analysis()->usesScopeChain());
JS_ASSERT(analysis().usesScopeChain());
if (fun->isArrow())
return abort("bound arrow function");
if (fun->isNative() && IsAsmJSModuleNative(fun->native()))
@ -8857,7 +8870,7 @@ IonBuilder::jsop_defvar(uint32_t index)
attrs |= JSPROP_READONLY;
// Pass the ScopeChain.
JS_ASSERT(script()->analysis()->usesScopeChain());
JS_ASSERT(analysis().usesScopeChain());
// Bake the name pointer into the MDefVar.
MDefVar *defvar = MDefVar::New(name, attrs, current->scopeChain());
@ -8873,7 +8886,7 @@ IonBuilder::jsop_deffun(uint32_t index)
if (fun->isNative() && IsAsmJSModuleNative(fun->native()))
return abort("asm.js module function");
JS_ASSERT(script()->analysis()->usesScopeChain());
JS_ASSERT(analysis().usesScopeChain());
MDefFun *deffun = MDefFun::New(fun, current->scopeChain());
current->add(deffun);

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

@ -12,6 +12,7 @@
// This file declares the data structures for building a MIRGraph from a
// JSScript.
#include "jit/BytecodeAnalysis.h"
#include "jit/MIR.h"
#include "jit/MIRGraph.h"
@ -640,10 +641,18 @@ class IonBuilder : public MIRGenerator
AbortReason abortReason() { return abortReason_; }
private:
bool init();
JSContext *cx;
BaselineFrame *baselineFrame_;
AbortReason abortReason_;
// Basic analysis information about the script.
BytecodeAnalysis analysis_;
BytecodeAnalysis &analysis() {
return analysis_;
}
jsbytecode *pc;
MBasicBlock *current;
uint32_t loopDepth_;

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

@ -158,7 +158,7 @@ MIRGraph::forkJoinSlice()
}
MBasicBlock *
MBasicBlock::New(MIRGraph &graph, CompileInfo &info,
MBasicBlock::New(MIRGraph &graph, BytecodeAnalysis *analysis, CompileInfo &info,
MBasicBlock *pred, jsbytecode *entryPc, Kind kind)
{
JS_ASSERT(entryPc != NULL);
@ -167,7 +167,7 @@ MBasicBlock::New(MIRGraph &graph, CompileInfo &info,
if (!block->init())
return NULL;
if (!block->inherit(pred, 0))
if (!block->inherit(analysis, pred, 0))
return NULL;
return block;
@ -181,7 +181,7 @@ MBasicBlock::NewPopN(MIRGraph &graph, CompileInfo &info,
if (!block->init())
return NULL;
if (!block->inherit(pred, popped))
if (!block->inherit(NULL, pred, popped))
return NULL;
return block;
@ -210,14 +210,14 @@ MBasicBlock *
MBasicBlock::NewPendingLoopHeader(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, jsbytecode *entryPc)
{
return MBasicBlock::New(graph, info, pred, entryPc, PENDING_LOOP_HEADER);
return MBasicBlock::New(graph, NULL, info, pred, entryPc, PENDING_LOOP_HEADER);
}
MBasicBlock *
MBasicBlock::NewSplitEdge(MIRGraph &graph, CompileInfo &info, MBasicBlock *pred)
{
return pred->pc()
? MBasicBlock::New(graph, info, pred, pred->pc(), SPLIT_EDGE)
? MBasicBlock::New(graph, NULL, info, pred, pred->pc(), SPLIT_EDGE)
: MBasicBlock::NewAsmJS(graph, info, pred, SPLIT_EDGE);
}
@ -323,7 +323,7 @@ MBasicBlock::copySlots(MBasicBlock *from)
}
bool
MBasicBlock::inherit(MBasicBlock *pred, uint32_t popped)
MBasicBlock::inherit(BytecodeAnalysis *analysis, MBasicBlock *pred, uint32_t popped)
{
if (pred) {
stackPosition_ = pred->stackPosition_;
@ -332,7 +332,7 @@ MBasicBlock::inherit(MBasicBlock *pred, uint32_t popped)
if (kind_ != PENDING_LOOP_HEADER)
copySlots(pred);
} else {
uint32_t stackDepth = info().script()->analysis()->getCode(pc()).stackDepth;
uint32_t stackDepth = analysis->info(pc()).stackDepth;
stackPosition_ = info().firstStackSlot() + stackDepth;
JS_ASSERT(stackPosition_ >= popped);
stackPosition_ -= popped;

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

@ -18,6 +18,7 @@
namespace js {
namespace jit {
class BytecodeAnalysis;
class MBasicBlock;
class MIRGraph;
class MStart;
@ -46,7 +47,7 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
MBasicBlock(MIRGraph &graph, CompileInfo &info, jsbytecode *pc, Kind kind);
bool init();
void copySlots(MBasicBlock *from);
bool inherit(MBasicBlock *pred, uint32_t popped);
bool inherit(BytecodeAnalysis *analysis, MBasicBlock *pred, uint32_t popped);
bool inheritResumePoint(MBasicBlock *pred);
void assertUsesAreNotWithin(MUseIterator use, MUseIterator end);
@ -67,7 +68,7 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
// Creates a new basic block for a MIR generator. If |pred| is not NULL,
// its slots and stack depth are initialized from |pred|.
static MBasicBlock *New(MIRGraph &graph, CompileInfo &info,
static MBasicBlock *New(MIRGraph &graph, BytecodeAnalysis *analysis, CompileInfo &info,
MBasicBlock *pred, jsbytecode *entryPc, Kind kind);
static MBasicBlock *NewPopN(MIRGraph &graph, CompileInfo &info,
MBasicBlock *pred, jsbytecode *entryPc, Kind kind, uint32_t popn);

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

@ -78,13 +78,6 @@ class Bytecode
/* Whether this is a catch/finally entry point. */
bool exceptionEntry : 1;
/*
* Dynamically observed state about the execution of this opcode. These are
* hints about the script for use during compilation.
*/
bool arrayWriteHole: 1; /* SETELEM which has written to an array hole. */
bool accessGetter: 1; /* Property read on a shape with a getter hook. */
/* Stack depth before this opcode. */
uint32_t stackDepth;

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

@ -4040,12 +4040,6 @@ NativeGetInline(JSContext *cx,
{
jsbytecode *pc;
JSScript *script = cx->currentScript(&pc);
if (script && script->hasAnalysis()) {
analyze::Bytecode *code = script->analysis()->maybeCode(pc);
if (code)
code->accessGetter = true;
}
#ifdef JS_ION
if (script && script->hasBaselineScript()) {
switch (JSOp(*pc)) {

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

@ -2959,6 +2959,20 @@ JSScript::updateBaselineOrIonRaw()
#endif
}
bool
JSScript::hasLoops()
{
if (!hasTrynotes())
return false;
JSTryNote *tn = trynotes()->vector;
JSTryNote *tnlimit = tn + trynotes()->length;
for (; tn < tnlimit; tn++) {
if (tn->kind == JSTRY_ITER || tn->kind == JSTRY_LOOP)
return true;
}
return false;
}
static inline void
LazyScriptHash(uint32_t lineno, uint32_t column, uint32_t begin, uint32_t end,
HashNumber hashes[3])

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

@ -932,6 +932,8 @@ class JSScript : public js::gc::Cell
return reinterpret_cast<js::TryNoteArray *>(data + trynotesOffset());
}
bool hasLoops();
js::HeapPtrAtom &getAtom(size_t index) const {
JS_ASSERT(index < natoms);
return atoms[index];

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

@ -1224,9 +1224,8 @@ ModOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs
static JS_ALWAYS_INLINE bool
SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, const Value &value,
bool strict, JSScript *maybeScript = NULL, jsbytecode *pc = NULL)
bool strict, JSScript *script = NULL, jsbytecode *pc = NULL)
{
RootedScript script(cx, maybeScript);
types::TypeScript::MonitorAssign(cx, obj, id);
if (obj->isNative() && JSID_IS_INT(id)) {
@ -1234,14 +1233,12 @@ SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, con
int32_t i = JSID_TO_INT(id);
if ((uint32_t)i >= length) {
// Annotate script if provided with information (e.g. baseline)
if (script && script->hasAnalysis()) {
JS_ASSERT(pc);
script->analysis()->getCode(pc).arrayWriteHole = true;
}
if (script && script->hasBaselineScript() && *pc == JSOP_SETELEM)
script->baselineScript()->noteArrayWriteHole(pc - script->code);
}
}
if (obj->isNative() && !obj->setHadElementsAccess(cx))
if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx))
return false;
RootedValue tmp(cx, value);