зеркало из https://github.com/mozilla/gecko-dev.git
Bug 917441 - Remove dependence of IonBuilder on ScriptAnalysis, r=jandem.
This commit is contained in:
Родитель
89075a8c47
Коммит
67b88e4fd7
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче