mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 867160 - Allow baseline to bypass scriptAnalysis on most scripts. r=jandem
This commit is contained in:
parent
06a84c0e3f
commit
a0970d479a
@ -213,6 +213,7 @@ VPATH += $(srcdir)/ion
|
|||||||
VPATH += $(srcdir)/ion/shared
|
VPATH += $(srcdir)/ion/shared
|
||||||
|
|
||||||
CPPSRCS += MIR.cpp \
|
CPPSRCS += MIR.cpp \
|
||||||
|
BytecodeAnalysis.cpp \
|
||||||
BaselineCompiler.cpp \
|
BaselineCompiler.cpp \
|
||||||
BaselineIC.cpp \
|
BaselineIC.cpp \
|
||||||
BaselineFrame.cpp \
|
BaselineFrame.cpp \
|
||||||
|
@ -29,6 +29,9 @@ BaselineCompiler::BaselineCompiler(JSContext *cx, HandleScript script)
|
|||||||
bool
|
bool
|
||||||
BaselineCompiler::init()
|
BaselineCompiler::init()
|
||||||
{
|
{
|
||||||
|
if (!analysis_.init())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!labels_.init(script->length))
|
if (!labels_.init(script->length))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -64,8 +67,12 @@ BaselineCompiler::compile()
|
|||||||
IonSpew(IonSpew_BaselineScripts, "Baseline compiling script %s:%d (%p)",
|
IonSpew(IonSpew_BaselineScripts, "Baseline compiling script %s:%d (%p)",
|
||||||
script->filename(), script->lineno, script.get());
|
script->filename(), script->lineno, script.get());
|
||||||
|
|
||||||
if (!script->ensureRanAnalysis(cx))
|
// Only need to analyze scripts which are marked |argumensHasVarBinding|, to
|
||||||
return Method_Error;
|
// compute |needsArgsObj| flag.
|
||||||
|
if (script->argumentsHasVarBinding()) {
|
||||||
|
if (!script->ensureRanAnalysis(cx))
|
||||||
|
return Method_Error;
|
||||||
|
}
|
||||||
|
|
||||||
// Pin analysis info during compilation.
|
// Pin analysis info during compilation.
|
||||||
types::AutoEnterAnalysis autoEnterAnalysis(cx);
|
types::AutoEnterAnalysis autoEnterAnalysis(cx);
|
||||||
@ -537,10 +544,10 @@ BaselineCompiler::emitBody()
|
|||||||
IonSpew(IonSpew_BaselineOp, "Compiling op @ %d: %s",
|
IonSpew(IonSpew_BaselineOp, "Compiling op @ %d: %s",
|
||||||
int(pc - script->code), js_CodeName[op]);
|
int(pc - script->code), js_CodeName[op]);
|
||||||
|
|
||||||
analyze::Bytecode *code = script->analysis()->maybeCode(pc);
|
BytecodeInfo *info = analysis_.maybeInfo(pc);
|
||||||
|
|
||||||
// Skip unreachable ops.
|
// Skip unreachable ops.
|
||||||
if (!code) {
|
if (!info) {
|
||||||
if (op == JSOP_STOP)
|
if (op == JSOP_STOP)
|
||||||
break;
|
break;
|
||||||
pc += GetBytecodeLength(pc);
|
pc += GetBytecodeLength(pc);
|
||||||
@ -549,9 +556,9 @@ BaselineCompiler::emitBody()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fully sync the stack if there are incoming jumps.
|
// Fully sync the stack if there are incoming jumps.
|
||||||
if (code->jumpTarget) {
|
if (info->jumpTarget) {
|
||||||
frame.syncStack(0);
|
frame.syncStack(0);
|
||||||
frame.setStackDepth(code->stackDepth);
|
frame.setStackDepth(info->stackDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always sync in debug mode.
|
// Always sync in debug mode.
|
||||||
@ -2419,7 +2426,7 @@ BaselineCompiler::emit_JSOP_ARGUMENTS()
|
|||||||
frame.syncStack(0);
|
frame.syncStack(0);
|
||||||
|
|
||||||
Label done;
|
Label done;
|
||||||
if (!script->needsArgsObj()) {
|
if (!script->argumentsHasVarBinding() || !script->needsArgsObj()) {
|
||||||
// We assume the script does not need an arguments object. However, this
|
// We assume the script does not need an arguments object. However, this
|
||||||
// assumption can be invalidated later, see argumentsOptimizationFailed
|
// assumption can be invalidated later, see argumentsOptimizationFailed
|
||||||
// in JSScript. Because we can't invalidate baseline JIT code, we set a
|
// in JSScript. Because we can't invalidate baseline JIT code, we set a
|
||||||
|
@ -13,9 +13,11 @@
|
|||||||
#include "jsinfer.h"
|
#include "jsinfer.h"
|
||||||
#include "jsinterp.h"
|
#include "jsinterp.h"
|
||||||
|
|
||||||
|
#include "IonAllocPolicy.h"
|
||||||
#include "BaselineJIT.h"
|
#include "BaselineJIT.h"
|
||||||
#include "BaselineIC.h"
|
#include "BaselineIC.h"
|
||||||
#include "FixedList.h"
|
#include "FixedList.h"
|
||||||
|
#include "BytecodeAnalysis.h"
|
||||||
|
|
||||||
#if defined(JS_CPU_X86)
|
#if defined(JS_CPU_X86)
|
||||||
# include "x86/BaselineCompiler-x86.h"
|
# include "x86/BaselineCompiler-x86.h"
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "BaselineFrameInfo.h"
|
#include "BaselineFrameInfo.h"
|
||||||
#include "IonSpewer.h"
|
#include "IonSpewer.h"
|
||||||
|
#include "shared/BaselineCompiler-shared.h"
|
||||||
|
|
||||||
#include "jsanalyze.h"
|
#include "jsanalyze.h"
|
||||||
#include "jsinferinlines.h"
|
#include "jsinferinlines.h"
|
||||||
@ -147,8 +148,8 @@ void
|
|||||||
FrameInfo::assertValidState(jsbytecode *pc)
|
FrameInfo::assertValidState(jsbytecode *pc)
|
||||||
{
|
{
|
||||||
// Check stack depth.
|
// Check stack depth.
|
||||||
analyze::Bytecode *code = script->analysis()->maybeCode(pc);
|
BytecodeInfo *info = compiler.analysis().maybeInfo(pc);
|
||||||
JS_ASSERT_IF(code, stackDepth() == code->stackDepth);
|
JS_ASSERT_IF(info, stackDepth() == info->stackDepth);
|
||||||
|
|
||||||
// Start at the bottom, find the first value that's not synced.
|
// Start at the bottom, find the first value that's not synced.
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "BaselineJIT.h"
|
#include "BaselineJIT.h"
|
||||||
#include "BaselineFrame.h"
|
#include "BaselineFrame.h"
|
||||||
#include "BaselineRegisters.h"
|
#include "BaselineRegisters.h"
|
||||||
|
#include "BytecodeAnalysis.h"
|
||||||
#include "IonMacroAssembler.h"
|
#include "IonMacroAssembler.h"
|
||||||
#include "FixedList.h"
|
#include "FixedList.h"
|
||||||
|
|
||||||
@ -158,8 +159,11 @@ class StackValue
|
|||||||
|
|
||||||
enum StackAdjustment { AdjustStack, DontAdjustStack };
|
enum StackAdjustment { AdjustStack, DontAdjustStack };
|
||||||
|
|
||||||
|
class BaselineCompilerShared;
|
||||||
|
|
||||||
class FrameInfo
|
class FrameInfo
|
||||||
{
|
{
|
||||||
|
BaselineCompilerShared &compiler;
|
||||||
RootedScript script;
|
RootedScript script;
|
||||||
MacroAssembler &masm;
|
MacroAssembler &masm;
|
||||||
|
|
||||||
@ -167,8 +171,10 @@ class FrameInfo
|
|||||||
size_t spIndex;
|
size_t spIndex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FrameInfo(JSContext *cx, HandleScript script, MacroAssembler &masm)
|
FrameInfo(JSContext *cx, BaselineCompilerShared &compiler, HandleScript script,
|
||||||
: script(cx, script),
|
MacroAssembler &masm)
|
||||||
|
: compiler(compiler),
|
||||||
|
script(cx, script),
|
||||||
masm(masm),
|
masm(masm),
|
||||||
stack(),
|
stack(),
|
||||||
spIndex(0)
|
spIndex(0)
|
||||||
|
138
js/src/ion/BytecodeAnalysis.cpp
Normal file
138
js/src/ion/BytecodeAnalysis.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "ion/BytecodeAnalysis.h"
|
||||||
|
#include "jsopcode.h"
|
||||||
|
#include "jsopcodeinlines.h"
|
||||||
|
|
||||||
|
using namespace js;
|
||||||
|
using namespace js::ion;
|
||||||
|
|
||||||
|
BytecodeAnalysis::BytecodeAnalysis(JSScript *script)
|
||||||
|
: script_(script),
|
||||||
|
infos_()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BytecodeAnalysis::init()
|
||||||
|
{
|
||||||
|
if (!infos_.growByUninitialized(script_->length))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
jsbytecode *end = script_->code + script_->length;
|
||||||
|
|
||||||
|
// Clear all BytecodeInfo.
|
||||||
|
mozilla::PodZero(infos_.begin(), infos_.length());
|
||||||
|
infos_[0].init(/*stackDepth=*/0);
|
||||||
|
|
||||||
|
for (jsbytecode *pc = script_->code; pc < end; pc += GetBytecodeLength(pc)) {
|
||||||
|
JSOp op = JSOp(*pc);
|
||||||
|
unsigned offset = pc - script_->code;
|
||||||
|
|
||||||
|
IonSpew(IonSpew_BaselineOp, "Analyzing op @ %d (end=%d): %s",
|
||||||
|
int(pc - script_->code), int(end - script_->code), js_CodeName[op]);
|
||||||
|
|
||||||
|
// If this bytecode info has not yet been initialized, it's not reachable.
|
||||||
|
if (!infos_[offset].initialized)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
unsigned stackDepth = infos_[offset].stackDepth;
|
||||||
|
#ifdef DEBUG
|
||||||
|
for (jsbytecode *chkpc = pc + 1; chkpc < (pc + GetBytecodeLength(pc)); chkpc++)
|
||||||
|
JS_ASSERT(!infos_[chkpc - script_->code].initialized);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Treat decompose ops as no-ops which do not adjust the stack. We will
|
||||||
|
// pick up the stack depths as we go through the decomposed version.
|
||||||
|
if (!(js_CodeSpec[op].format & JOF_DECOMPOSE)) {
|
||||||
|
unsigned nuses = GetUseCount(script_, offset);
|
||||||
|
unsigned ndefs = GetDefCount(script_, offset);
|
||||||
|
|
||||||
|
JS_ASSERT(stackDepth >= nuses);
|
||||||
|
stackDepth -= nuses;
|
||||||
|
stackDepth += ndefs;
|
||||||
|
|
||||||
|
// If stack depth exceeds max allowed by analysis, fail fast.
|
||||||
|
JS_ASSERT(stackDepth <= BytecodeInfo::MAX_STACK_DEPTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == JSOP_TABLESWITCH) {
|
||||||
|
unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
|
||||||
|
jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
|
||||||
|
int32_t low = GET_JUMP_OFFSET(pc2);
|
||||||
|
pc2 += JUMP_OFFSET_LEN;
|
||||||
|
int32_t high = GET_JUMP_OFFSET(pc2);
|
||||||
|
pc2 += JUMP_OFFSET_LEN;
|
||||||
|
|
||||||
|
infos_[defaultOffset].init(stackDepth);
|
||||||
|
infos_[defaultOffset].jumpTarget = true;
|
||||||
|
|
||||||
|
for (int32_t i = low; i <= high; i++) {
|
||||||
|
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
|
||||||
|
if (targetOffset != offset) {
|
||||||
|
infos_[targetOffset].init(stackDepth);
|
||||||
|
infos_[targetOffset].jumpTarget = true;
|
||||||
|
}
|
||||||
|
pc2 += JUMP_OFFSET_LEN;
|
||||||
|
}
|
||||||
|
} else if (op == JSOP_TRY) {
|
||||||
|
JSTryNote *tn = script_->trynotes()->vector;
|
||||||
|
JSTryNote *tnlimit = tn + script_->trynotes()->length;
|
||||||
|
for (; tn < tnlimit; tn++) {
|
||||||
|
unsigned startOffset = script_->mainOffset + tn->start;
|
||||||
|
if (startOffset == offset + 1) {
|
||||||
|
unsigned catchOffset = startOffset + tn->length;
|
||||||
|
|
||||||
|
if (tn->kind != JSTRY_ITER) {
|
||||||
|
infos_[catchOffset].init(stackDepth);
|
||||||
|
infos_[catchOffset].jumpTarget = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jump = IsJumpOpcode(op);
|
||||||
|
if (jump) {
|
||||||
|
// Case instructions do not push the lvalue back when branching.
|
||||||
|
unsigned newStackDepth = stackDepth;
|
||||||
|
if (op == JSOP_CASE)
|
||||||
|
newStackDepth--;
|
||||||
|
|
||||||
|
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
|
||||||
|
|
||||||
|
// If this is a a backedge to an un-analyzed segment, analyze from there.
|
||||||
|
bool jumpBack = (targetOffset < offset) && !infos_[targetOffset].initialized;
|
||||||
|
|
||||||
|
infos_[targetOffset].init(newStackDepth);
|
||||||
|
infos_[targetOffset].jumpTarget = true;
|
||||||
|
|
||||||
|
if (jumpBack)
|
||||||
|
pc = script_->code + targetOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle any fallthrough from this opcode.
|
||||||
|
if (BytecodeFallsThrough(op)) {
|
||||||
|
jsbytecode *nextpc = pc + GetBytecodeLength(pc);
|
||||||
|
JS_ASSERT(nextpc < end);
|
||||||
|
unsigned nextOffset = nextpc - script_->code;
|
||||||
|
|
||||||
|
infos_[nextOffset].init(stackDepth);
|
||||||
|
|
||||||
|
if (jump)
|
||||||
|
infos_[nextOffset].jumpFallthrough = true;
|
||||||
|
|
||||||
|
// Treat the fallthrough of a branch instruction as a jump target.
|
||||||
|
if (jump)
|
||||||
|
infos_[nextOffset].jumpTarget = true;
|
||||||
|
else
|
||||||
|
infos_[nextOffset].fallthrough = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
63
js/src/ion/BytecodeAnalysis.h
Normal file
63
js/src/ion/BytecodeAnalysis.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef jsion_bytecodeanalysis_h__
|
||||||
|
#define jsion_bytecodeanalysis_h__
|
||||||
|
|
||||||
|
#include "jscntxt.h"
|
||||||
|
|
||||||
|
#include "IonAllocPolicy.h"
|
||||||
|
#include "js/Vector.h"
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
namespace ion {
|
||||||
|
|
||||||
|
|
||||||
|
// Basic information about bytecodes in the script. Used to help baseline compilation.
|
||||||
|
struct BytecodeInfo
|
||||||
|
{
|
||||||
|
static const uint16_t MAX_STACK_DEPTH = 0xffffU;
|
||||||
|
uint16_t stackDepth;
|
||||||
|
bool initialized : 1;
|
||||||
|
bool jumpTarget : 1;
|
||||||
|
bool jumpFallthrough : 1;
|
||||||
|
bool fallthrough : 1;
|
||||||
|
|
||||||
|
void init(unsigned depth) {
|
||||||
|
JS_ASSERT(depth <= MAX_STACK_DEPTH);
|
||||||
|
JS_ASSERT_IF(initialized, stackDepth == depth);
|
||||||
|
initialized = true;
|
||||||
|
stackDepth = depth;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BytecodeAnalysis
|
||||||
|
{
|
||||||
|
JSScript *script_;
|
||||||
|
Vector<BytecodeInfo, 0, IonAllocPolicy> infos_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BytecodeAnalysis(JSScript *script);
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
BytecodeInfo &info(jsbytecode *pc) {
|
||||||
|
JS_ASSERT(infos_[pc - script_->code].initialized);
|
||||||
|
return infos_[pc - script_->code];
|
||||||
|
}
|
||||||
|
|
||||||
|
BytecodeInfo *maybeInfo(jsbytecode *pc) {
|
||||||
|
if (infos_[pc - script_->code].initialized)
|
||||||
|
return &infos_[pc - script_->code];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ion
|
||||||
|
} // namespace js
|
||||||
|
|
||||||
|
#endif // jsion_bytecodeanalysis_h__
|
@ -18,7 +18,8 @@ BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, HandleScript scrip
|
|||||||
ionCompileable_(ion::IsEnabled(cx) && CanIonCompileScript(cx, script, false)),
|
ionCompileable_(ion::IsEnabled(cx) && CanIonCompileScript(cx, script, false)),
|
||||||
ionOSRCompileable_(ion::IsEnabled(cx) && CanIonCompileScript(cx, script, true)),
|
ionOSRCompileable_(ion::IsEnabled(cx) && CanIonCompileScript(cx, script, true)),
|
||||||
debugMode_(cx->compartment->debugMode()),
|
debugMode_(cx->compartment->debugMode()),
|
||||||
frame(cx, script, masm),
|
analysis_(script),
|
||||||
|
frame(cx, *this, script, masm),
|
||||||
stubSpace_(),
|
stubSpace_(),
|
||||||
icEntries_(),
|
icEntries_(),
|
||||||
pcMappingEntries_(),
|
pcMappingEntries_(),
|
||||||
|
@ -28,6 +28,7 @@ class BaselineCompilerShared
|
|||||||
bool ionOSRCompileable_;
|
bool ionOSRCompileable_;
|
||||||
bool debugMode_;
|
bool debugMode_;
|
||||||
|
|
||||||
|
BytecodeAnalysis analysis_;
|
||||||
FrameInfo frame;
|
FrameInfo frame;
|
||||||
|
|
||||||
FallbackICStubSpace stubSpace_;
|
FallbackICStubSpace stubSpace_;
|
||||||
@ -129,6 +130,11 @@ class BaselineCompilerShared
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool callVM(const VMFunction &fun);
|
bool callVM(const VMFunction &fun);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BytecodeAnalysis &analysis() {
|
||||||
|
return analysis_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ion
|
} // namespace ion
|
||||||
|
@ -39,18 +39,6 @@ analyze::PrintBytecode(JSContext *cx, HandleScript script, jsbytecode *pc)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline bool
|
|
||||||
IsJumpOpcode(JSOp op)
|
|
||||||
{
|
|
||||||
uint32_t type = JOF_TYPE(js_CodeSpec[op].format);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* LABEL opcodes have type JOF_JUMP but are no-ops, don't treat them as
|
|
||||||
* jumps to avoid degrading precision.
|
|
||||||
*/
|
|
||||||
return type == JOF_JUMP && op != JSOP_LABEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// Bytecode Analysis
|
// Bytecode Analysis
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
@ -590,7 +578,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Handle any fallthrough from this opcode. */
|
/* Handle any fallthrough from this opcode. */
|
||||||
if (!BytecodeNoFallThrough(op)) {
|
if (BytecodeFallsThrough(op)) {
|
||||||
JS_ASSERT(successorOffset < script_->length);
|
JS_ASSERT(successorOffset < script_->length);
|
||||||
|
|
||||||
Bytecode *&nextcode = codeArray[successorOffset];
|
Bytecode *&nextcode = codeArray[successorOffset];
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
#include "jsinfer.h"
|
#include "jsinfer.h"
|
||||||
#include "jsscript.h"
|
#include "jsscript.h"
|
||||||
|
#include "jsopcodeinlines.h"
|
||||||
|
|
||||||
#include "ds/LifoAlloc.h"
|
#include "ds/LifoAlloc.h"
|
||||||
#include "js/TemplateLib.h"
|
#include "js/TemplateLib.h"
|
||||||
@ -171,46 +172,6 @@ class Bytecode
|
|||||||
types::TypeBarrier *typeBarriers;
|
types::TypeBarrier *typeBarriers;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline unsigned
|
|
||||||
GetDefCount(JSScript *script, unsigned offset)
|
|
||||||
{
|
|
||||||
JS_ASSERT(offset < script->length);
|
|
||||||
jsbytecode *pc = script->code + offset;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add an extra pushed value for OR/AND opcodes, so that they are included
|
|
||||||
* in the pushed array of stack values for type inference.
|
|
||||||
*/
|
|
||||||
switch (JSOp(*pc)) {
|
|
||||||
case JSOP_OR:
|
|
||||||
case JSOP_AND:
|
|
||||||
return 1;
|
|
||||||
case JSOP_PICK:
|
|
||||||
/*
|
|
||||||
* Pick pops and pushes how deep it looks in the stack + 1
|
|
||||||
* items. i.e. if the stack were |a b[2] c[1] d[0]|, pick 2
|
|
||||||
* would pop b, c, and d to rearrange the stack to |a c[0]
|
|
||||||
* d[1] b[2]|.
|
|
||||||
*/
|
|
||||||
return (pc[1] + 1);
|
|
||||||
default:
|
|
||||||
return StackDefs(script, pc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned
|
|
||||||
GetUseCount(JSScript *script, unsigned offset)
|
|
||||||
{
|
|
||||||
JS_ASSERT(offset < script->length);
|
|
||||||
jsbytecode *pc = script->code + offset;
|
|
||||||
|
|
||||||
if (JSOp(*pc) == JSOP_PICK)
|
|
||||||
return (pc[1] + 1);
|
|
||||||
if (js_CodeSpec[*pc].nuses == -1)
|
|
||||||
return StackUses(script, pc);
|
|
||||||
return js_CodeSpec[*pc].nuses;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For opcodes which assign to a local variable or argument, track an extra def
|
* For opcodes which assign to a local variable or argument, track an extra def
|
||||||
* during SSA analysis for the value's use chain and assigned type.
|
* during SSA analysis for the value's use chain and assigned type.
|
||||||
@ -235,27 +196,6 @@ ExtendedDef(jsbytecode *pc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return whether op bytecodes do not fallthrough (they may do a jump). */
|
|
||||||
static inline bool
|
|
||||||
BytecodeNoFallThrough(JSOp op)
|
|
||||||
{
|
|
||||||
switch (op) {
|
|
||||||
case JSOP_GOTO:
|
|
||||||
case JSOP_DEFAULT:
|
|
||||||
case JSOP_RETURN:
|
|
||||||
case JSOP_STOP:
|
|
||||||
case JSOP_RETRVAL:
|
|
||||||
case JSOP_THROW:
|
|
||||||
case JSOP_TABLESWITCH:
|
|
||||||
return true;
|
|
||||||
case JSOP_GOSUB:
|
|
||||||
/* These fall through indirectly, after executing a 'finally'. */
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For opcodes which access local variables or arguments, we track an extra
|
* For opcodes which access local variables or arguments, we track an extra
|
||||||
* use during SSA analysis for the value of the variable before/after the op.
|
* use during SSA analysis for the value of the variable before/after the op.
|
||||||
|
@ -13,6 +13,78 @@
|
|||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
static inline unsigned
|
||||||
|
GetDefCount(JSScript *script, unsigned offset)
|
||||||
|
{
|
||||||
|
JS_ASSERT(offset < script->length);
|
||||||
|
jsbytecode *pc = script->code + offset;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add an extra pushed value for OR/AND opcodes, so that they are included
|
||||||
|
* in the pushed array of stack values for type inference.
|
||||||
|
*/
|
||||||
|
switch (JSOp(*pc)) {
|
||||||
|
case JSOP_OR:
|
||||||
|
case JSOP_AND:
|
||||||
|
return 1;
|
||||||
|
case JSOP_PICK:
|
||||||
|
/*
|
||||||
|
* Pick pops and pushes how deep it looks in the stack + 1
|
||||||
|
* items. i.e. if the stack were |a b[2] c[1] d[0]|, pick 2
|
||||||
|
* would pop b, c, and d to rearrange the stack to |a c[0]
|
||||||
|
* d[1] b[2]|.
|
||||||
|
*/
|
||||||
|
return (pc[1] + 1);
|
||||||
|
default:
|
||||||
|
return StackDefs(script, pc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned
|
||||||
|
GetUseCount(JSScript *script, unsigned offset)
|
||||||
|
{
|
||||||
|
JS_ASSERT(offset < script->length);
|
||||||
|
jsbytecode *pc = script->code + offset;
|
||||||
|
|
||||||
|
if (JSOp(*pc) == JSOP_PICK)
|
||||||
|
return (pc[1] + 1);
|
||||||
|
if (js_CodeSpec[*pc].nuses == -1)
|
||||||
|
return StackUses(script, pc);
|
||||||
|
return js_CodeSpec[*pc].nuses;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
IsJumpOpcode(JSOp op)
|
||||||
|
{
|
||||||
|
uint32_t type = JOF_TYPE(js_CodeSpec[op].format);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LABEL opcodes have type JOF_JUMP but are no-ops, don't treat them as
|
||||||
|
* jumps to avoid degrading precision.
|
||||||
|
*/
|
||||||
|
return type == JOF_JUMP && op != JSOP_LABEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
BytecodeFallsThrough(JSOp op)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case JSOP_GOTO:
|
||||||
|
case JSOP_DEFAULT:
|
||||||
|
case JSOP_RETURN:
|
||||||
|
case JSOP_STOP:
|
||||||
|
case JSOP_RETRVAL:
|
||||||
|
case JSOP_THROW:
|
||||||
|
case JSOP_TABLESWITCH:
|
||||||
|
return false;
|
||||||
|
case JSOP_GOSUB:
|
||||||
|
/* These fall through indirectly, after executing a 'finally'. */
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline PropertyName *
|
static inline PropertyName *
|
||||||
GetNameFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op)
|
GetNameFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op)
|
||||||
{
|
{
|
||||||
|
@ -837,7 +837,7 @@ MakeJITScript(JSContext *cx, JSScript *script)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Add an edge for fallthrough from this chunk to the next one. */
|
/* Add an edge for fallthrough from this chunk to the next one. */
|
||||||
if (!BytecodeNoFallThrough(op)) {
|
if (BytecodeFallsThrough(op)) {
|
||||||
CrossChunkEdge edge;
|
CrossChunkEdge edge;
|
||||||
edge.source = offset;
|
edge.source = offset;
|
||||||
edge.target = nextOffset;
|
edge.target = nextOffset;
|
||||||
|
Loading…
Reference in New Issue
Block a user