зеркало из https://github.com/mozilla/gecko-dev.git
Bug 864928 - Remove ScriptAnalysis::analyzeTypes, r=jandem.
This commit is contained in:
Родитель
a8d96b359f
Коммит
3a92a6a72f
|
@ -1787,88 +1787,6 @@ ScriptAnalysis::needsArgsObj(JSContext *cx)
|
|||
return needsArgsObj(cx, seen, SSAValue::PushedValue(pcOff, 0));
|
||||
}
|
||||
|
||||
CrossSSAValue
|
||||
CrossScriptSSA::foldValue(const CrossSSAValue &cv)
|
||||
{
|
||||
const Frame &frame = getFrame(cv.frame);
|
||||
const SSAValue &v = cv.v;
|
||||
|
||||
JSScript *parentScript = NULL;
|
||||
ScriptAnalysis *parentAnalysis = NULL;
|
||||
if (frame.parent != INVALID_FRAME) {
|
||||
parentScript = getFrame(frame.parent).script;
|
||||
parentAnalysis = parentScript->analysis();
|
||||
}
|
||||
|
||||
if (v.kind() == SSAValue::VAR && v.varInitial() && parentScript) {
|
||||
uint32_t slot = v.varSlot();
|
||||
if (slot >= ArgSlot(0) && slot < LocalSlot(frame.script, 0)) {
|
||||
uint32_t argc = GET_ARGC(frame.parentpc);
|
||||
SSAValue argv = parentAnalysis->poppedValue(frame.parentpc, argc - 1 - (slot - ArgSlot(0)));
|
||||
return foldValue(CrossSSAValue(frame.parent, argv));
|
||||
}
|
||||
}
|
||||
|
||||
if (v.kind() == SSAValue::PUSHED) {
|
||||
jsbytecode *pc = frame.script->code + v.pushedOffset();
|
||||
|
||||
switch (JSOp(*pc)) {
|
||||
case JSOP_THIS:
|
||||
if (parentScript) {
|
||||
uint32_t argc = GET_ARGC(frame.parentpc);
|
||||
SSAValue thisv = parentAnalysis->poppedValue(frame.parentpc, argc);
|
||||
return foldValue(CrossSSAValue(frame.parent, thisv));
|
||||
}
|
||||
break;
|
||||
|
||||
case JSOP_CALL: {
|
||||
/*
|
||||
* If there is a single inline callee with a single return site,
|
||||
* propagate back to that.
|
||||
*/
|
||||
JSScript *callee = NULL;
|
||||
uint32_t calleeFrame = INVALID_FRAME;
|
||||
for (unsigned i = 0; i < numFrames(); i++) {
|
||||
if (iterFrame(i).parent == cv.frame && iterFrame(i).parentpc == pc) {
|
||||
if (callee)
|
||||
return cv; /* Multiple callees */
|
||||
callee = iterFrame(i).script;
|
||||
calleeFrame = iterFrame(i).index;
|
||||
}
|
||||
}
|
||||
if (callee && callee->analysis()->numReturnSites() == 1) {
|
||||
ScriptAnalysis *analysis = callee->analysis();
|
||||
uint32_t offset = 0;
|
||||
while (offset < callee->length) {
|
||||
jsbytecode *pc = callee->code + offset;
|
||||
if (analysis->maybeCode(pc) && JSOp(*pc) == JSOP_RETURN)
|
||||
return foldValue(CrossSSAValue(calleeFrame, analysis->poppedValue(pc, 0)));
|
||||
offset += GetBytecodeLength(pc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_TOID: {
|
||||
/*
|
||||
* TOID acts as identity for integers, so to get better precision
|
||||
* we should propagate its popped values forward if it acted as
|
||||
* identity.
|
||||
*/
|
||||
ScriptAnalysis *analysis = frame.script->analysis();
|
||||
SSAValue toidv = analysis->poppedValue(pc, 0);
|
||||
if (analysis->getValueTypes(toidv)->getKnownTypeTag() == JSVAL_TYPE_INT32)
|
||||
return foldValue(CrossSSAValue(cv.frame, toidv));
|
||||
break;
|
||||
}
|
||||
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
return cv;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
|
|
|
@ -78,15 +78,6 @@ class Bytecode
|
|||
/* Whether this is a catch/finally entry point. */
|
||||
bool exceptionEntry : 1;
|
||||
|
||||
/*
|
||||
* Side effects of this bytecode were not determined by type inference.
|
||||
* Either a property set with unknown lvalue, or call with unknown callee.
|
||||
*/
|
||||
bool monitoredTypes : 1;
|
||||
|
||||
/* Call whose result should be monitored. */
|
||||
bool monitoredTypesReturn : 1;
|
||||
|
||||
/*
|
||||
* Dynamically observed state about the execution of this opcode. These are
|
||||
* hints about the script for use during compilation.
|
||||
|
@ -129,14 +120,6 @@ class Bytecode
|
|||
*/
|
||||
Vector<SlotValue> *pendingValues;
|
||||
};
|
||||
|
||||
/* --------- Type inference --------- */
|
||||
|
||||
/* Types for all values pushed by this bytecode. */
|
||||
types::StackTypeSet *pushedTypes;
|
||||
|
||||
/* Any type barriers in place at this bytecode. */
|
||||
types::TypeBarrier *typeBarriers;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -471,7 +454,6 @@ class SSAValue
|
|||
uint32_t phiSlot() const;
|
||||
uint32_t phiLength() const;
|
||||
const SSAValue &phiValue(uint32_t i) const;
|
||||
types::TypeSet *phiTypes() const;
|
||||
|
||||
/* Offset at which this phi node was created. */
|
||||
uint32_t phiOffset() const {
|
||||
|
@ -571,7 +553,6 @@ class SSAValue
|
|||
*/
|
||||
struct SSAPhiNode
|
||||
{
|
||||
types::StackTypeSet types;
|
||||
uint32_t slot;
|
||||
uint32_t length;
|
||||
SSAValue *options;
|
||||
|
@ -599,13 +580,6 @@ SSAValue::phiValue(uint32_t i) const
|
|||
return u.phi.node->options[i];
|
||||
}
|
||||
|
||||
inline types::TypeSet *
|
||||
SSAValue::phiTypes() const
|
||||
{
|
||||
JS_ASSERT(kind() == PHI);
|
||||
return &u.phi.node->types;
|
||||
}
|
||||
|
||||
class SSAUseChain
|
||||
{
|
||||
public:
|
||||
|
@ -654,7 +628,6 @@ class ScriptAnalysis
|
|||
bool ranBytecode_;
|
||||
bool ranSSA_;
|
||||
bool ranLifetimes_;
|
||||
bool ranInference_;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Whether the compartment was in debug mode when we performed the analysis. */
|
||||
|
@ -689,15 +662,10 @@ class ScriptAnalysis
|
|||
bool ranBytecode() { return ranBytecode_; }
|
||||
bool ranSSA() { return ranSSA_; }
|
||||
bool ranLifetimes() { return ranLifetimes_; }
|
||||
bool ranInference() { return ranInference_; }
|
||||
|
||||
void analyzeBytecode(JSContext *cx);
|
||||
void analyzeSSA(JSContext *cx);
|
||||
void analyzeLifetimes(JSContext *cx);
|
||||
void analyzeTypes(JSContext *cx);
|
||||
|
||||
/* Analyze the effect of invoking 'new' on script. */
|
||||
void analyzeTypesNew(JSContext *cx);
|
||||
|
||||
bool OOM() const { return outOfMemory; }
|
||||
bool failed() const { return hadFailure; }
|
||||
|
@ -760,45 +728,6 @@ class ScriptAnalysis
|
|||
}
|
||||
const SlotValue *newValues(const jsbytecode *pc) { return newValues(pc - script_->code); }
|
||||
|
||||
inline types::StackTypeSet *pushedTypes(uint32_t offset, uint32_t which = 0);
|
||||
inline types::StackTypeSet *pushedTypes(const jsbytecode *pc, uint32_t which);
|
||||
|
||||
bool hasPushedTypes(const jsbytecode *pc) { return getCode(pc).pushedTypes != NULL; }
|
||||
|
||||
types::TypeBarrier *typeBarriers(JSContext *cx, uint32_t offset) {
|
||||
if (getCode(offset).typeBarriers)
|
||||
pruneTypeBarriers(cx, offset);
|
||||
return getCode(offset).typeBarriers;
|
||||
}
|
||||
types::TypeBarrier *typeBarriers(JSContext *cx, const jsbytecode *pc) {
|
||||
return typeBarriers(cx, pc - script_->code);
|
||||
}
|
||||
void addTypeBarrier(JSContext *cx, const jsbytecode *pc,
|
||||
types::TypeSet *target, types::Type type);
|
||||
void addSingletonTypeBarrier(JSContext *cx, const jsbytecode *pc,
|
||||
types::TypeSet *target,
|
||||
HandleObject singleton, HandleId singletonId);
|
||||
|
||||
/* Remove obsolete type barriers at the given offset. */
|
||||
void pruneTypeBarriers(JSContext *cx, uint32_t offset);
|
||||
|
||||
/*
|
||||
* Remove still-active type barriers at the given offset. If 'all' is set,
|
||||
* then all barriers are removed, otherwise only those deemed excessive
|
||||
* are removed.
|
||||
*/
|
||||
void breakTypeBarriers(JSContext *cx, uint32_t offset, bool all);
|
||||
|
||||
/* Break all type barriers used in computing v. */
|
||||
void breakTypeBarriersSSA(JSContext *cx, const SSAValue &v);
|
||||
|
||||
inline void addPushedType(JSContext *cx, uint32_t offset, uint32_t which, types::Type type);
|
||||
|
||||
inline types::StackTypeSet *getValueTypes(const SSAValue &v);
|
||||
|
||||
inline types::StackTypeSet *poppedTypes(uint32_t offset, uint32_t which);
|
||||
inline types::StackTypeSet *poppedTypes(const jsbytecode *pc, uint32_t which);
|
||||
|
||||
bool trackUseChain(const SSAValue &v) {
|
||||
JS_ASSERT_IF(v.kind() == SSAValue::VAR, trackSlot(v.varSlot()));
|
||||
return v.kind() != SSAValue::EMPTY &&
|
||||
|
@ -912,9 +841,6 @@ class ScriptAnalysis
|
|||
{}
|
||||
};
|
||||
|
||||
/* Type inference helpers */
|
||||
bool analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferenceState &state);
|
||||
|
||||
typedef Vector<SSAValue, 16> SeenVector;
|
||||
bool needsArgsObj(JSContext *cx, SeenVector &seen, const SSAValue &v);
|
||||
bool needsArgsObj(JSContext *cx, SeenVector &seen, SSAUseChain *use);
|
||||
|
@ -928,84 +854,6 @@ class ScriptAnalysis
|
|||
#endif
|
||||
};
|
||||
|
||||
/* SSA value as used by CrossScriptSSA, identifies the frame it came from. */
|
||||
struct CrossSSAValue
|
||||
{
|
||||
unsigned frame;
|
||||
SSAValue v;
|
||||
CrossSSAValue(unsigned frame, const SSAValue &v) : frame(frame), v(v) {}
|
||||
};
|
||||
|
||||
/*
|
||||
* Analysis for managing SSA values from multiple call stack frames. These are
|
||||
* created by the backend compiler when inlining functions, and allow for
|
||||
* values to be tracked as they flow into or out of the inlined frames.
|
||||
*/
|
||||
class CrossScriptSSA
|
||||
{
|
||||
public:
|
||||
|
||||
static const uint32_t OUTER_FRAME = UINT32_MAX;
|
||||
static const unsigned INVALID_FRAME = uint32_t(-2);
|
||||
|
||||
struct Frame {
|
||||
uint32_t index;
|
||||
JSScript *script;
|
||||
uint32_t depth; /* Distance from outer frame to this frame, in sizeof(Value) */
|
||||
uint32_t parent;
|
||||
jsbytecode *parentpc;
|
||||
|
||||
Frame(uint32_t index, JSScript *script, uint32_t depth, uint32_t parent,
|
||||
jsbytecode *parentpc)
|
||||
: index(index), script(script), depth(depth), parent(parent), parentpc(parentpc)
|
||||
{}
|
||||
};
|
||||
|
||||
const Frame &getFrame(uint32_t index) {
|
||||
if (index == OUTER_FRAME)
|
||||
return outerFrame;
|
||||
return inlineFrames[index];
|
||||
}
|
||||
|
||||
unsigned numFrames() { return 1 + inlineFrames.length(); }
|
||||
const Frame &iterFrame(unsigned i) {
|
||||
if (i == 0)
|
||||
return outerFrame;
|
||||
return inlineFrames[i - 1];
|
||||
}
|
||||
|
||||
JSScript *outerScript() { return outerFrame.script; }
|
||||
|
||||
/* Total length of scripts preceding a frame. */
|
||||
size_t frameLength(uint32_t index) {
|
||||
if (index == OUTER_FRAME)
|
||||
return 0;
|
||||
size_t res = outerFrame.script->length;
|
||||
for (unsigned i = 0; i < index; i++)
|
||||
res += inlineFrames[i].script->length;
|
||||
return res;
|
||||
}
|
||||
|
||||
inline types::StackTypeSet *getValueTypes(const CrossSSAValue &cv);
|
||||
|
||||
bool addInlineFrame(JSScript *script, uint32_t depth, uint32_t parent,
|
||||
jsbytecode *parentpc)
|
||||
{
|
||||
uint32_t index = inlineFrames.length();
|
||||
return inlineFrames.append(Frame(index, script, depth, parent, parentpc));
|
||||
}
|
||||
|
||||
CrossScriptSSA(JSContext *cx, JSScript *outer)
|
||||
: outerFrame(OUTER_FRAME, outer, 0, INVALID_FRAME, NULL), inlineFrames(cx)
|
||||
{}
|
||||
|
||||
CrossSSAValue foldValue(const CrossSSAValue &cv);
|
||||
|
||||
private:
|
||||
Frame outerFrame;
|
||||
Vector<Frame> inlineFrames;
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
void PrintBytecode(JSContext *cx, HandleScript script, jsbytecode *pc);
|
||||
#endif
|
||||
|
|
|
@ -29,64 +29,6 @@ ScriptAnalysis::poppedValue(const jsbytecode *pc, uint32_t which)
|
|||
return poppedValue(pc - script_->code, which);
|
||||
}
|
||||
|
||||
inline types::StackTypeSet *
|
||||
ScriptAnalysis::pushedTypes(uint32_t offset, uint32_t which)
|
||||
{
|
||||
JS_ASSERT(offset < script_->length);
|
||||
JS_ASSERT(which < GetDefCount(script_, offset) +
|
||||
(ExtendedDef(script_->code + offset) ? 1 : 0));
|
||||
types::StackTypeSet *array = getCode(offset).pushedTypes;
|
||||
JS_ASSERT(array);
|
||||
return array + which;
|
||||
}
|
||||
|
||||
inline types::StackTypeSet *
|
||||
ScriptAnalysis::pushedTypes(const jsbytecode *pc, uint32_t which)
|
||||
{
|
||||
return pushedTypes(pc - script_->code, which);
|
||||
}
|
||||
|
||||
inline types::StackTypeSet *
|
||||
ScriptAnalysis::getValueTypes(const SSAValue &v)
|
||||
{
|
||||
switch (v.kind()) {
|
||||
case SSAValue::PUSHED:
|
||||
return pushedTypes(v.pushedOffset(), v.pushedIndex());
|
||||
case SSAValue::VAR:
|
||||
JS_ASSERT(!slotEscapes(v.varSlot()));
|
||||
if (v.varInitial()) {
|
||||
if (v.varSlot() < LocalSlot(script_, 0))
|
||||
return types::TypeScript::SlotTypes(script_, v.varSlot());
|
||||
return undefinedTypeSet;
|
||||
} else {
|
||||
/*
|
||||
* Results of intermediate assignments have the same type as
|
||||
* the first type pushed by the assignment op. Note that this
|
||||
* may not be the exact same value as was pushed, due to
|
||||
* post-inc/dec ops.
|
||||
*/
|
||||
return pushedTypes(v.varOffset(), 0);
|
||||
}
|
||||
case SSAValue::PHI:
|
||||
return &v.phiNode()->types;
|
||||
default:
|
||||
/* Cannot compute types for empty SSA values. */
|
||||
MOZ_ASSUME_UNREACHABLE("Bad SSA value");
|
||||
}
|
||||
}
|
||||
|
||||
inline types::StackTypeSet *
|
||||
ScriptAnalysis::poppedTypes(uint32_t offset, uint32_t which)
|
||||
{
|
||||
return getValueTypes(poppedValue(offset, which));
|
||||
}
|
||||
|
||||
inline types::StackTypeSet *
|
||||
ScriptAnalysis::poppedTypes(const jsbytecode *pc, uint32_t which)
|
||||
{
|
||||
return getValueTypes(poppedValue(pc, which));
|
||||
}
|
||||
|
||||
inline SSAUseChain *&
|
||||
ScriptAnalysis::useChain(const SSAValue &v)
|
||||
{
|
||||
|
@ -107,12 +49,6 @@ ScriptAnalysis::getCallPC(jsbytecode *pc)
|
|||
return script_->code + uses->offset;
|
||||
}
|
||||
|
||||
inline types::StackTypeSet *
|
||||
CrossScriptSSA::getValueTypes(const CrossSSAValue &cv)
|
||||
{
|
||||
return getFrame(cv.frame).script->analysis()->getValueTypes(cv.v);
|
||||
}
|
||||
|
||||
} /* namespace analyze */
|
||||
} /* namespace js */
|
||||
|
||||
|
|
2104
js/src/jsinfer.cpp
2104
js/src/jsinfer.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -571,22 +571,8 @@ class StackTypeSet : public TypeSet
|
|||
*/
|
||||
static StackTypeSet *make(JSContext *cx, const char *name);
|
||||
|
||||
/* Constraints for type inference. */
|
||||
|
||||
void addSubset(JSContext *cx, TypeSet *target);
|
||||
void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
StackTypeSet *target, jsid id);
|
||||
void addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
StackTypeSet *target, jsid id);
|
||||
void addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
StackTypeSet *objectTypes, StackTypeSet *valueTypes);
|
||||
void addCall(JSContext *cx, TypeCallsite *site);
|
||||
void addArith(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
TypeSet *target, TypeSet *other = NULL);
|
||||
void addTransformThis(JSContext *cx, JSScript *script, TypeSet *target);
|
||||
void addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
Type type, StackTypeSet *types = NULL);
|
||||
void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
|
||||
/* Propagate any types from this set into target. */
|
||||
void addSubset(JSContext *cx, StackTypeSet *target);
|
||||
|
||||
/*
|
||||
* Constraints for JIT compilation.
|
||||
|
@ -679,16 +665,8 @@ class HeapTypeSet : public TypeSet
|
|||
{
|
||||
public:
|
||||
|
||||
/* Constraints for type inference. */
|
||||
|
||||
void addSubset(JSContext *cx, TypeSet *target);
|
||||
void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
StackTypeSet *target, jsid id);
|
||||
void addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id);
|
||||
void addFilterPrimitives(JSContext *cx, TypeSet *target);
|
||||
void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
|
||||
|
||||
/* Constraints for JIT compilation. */
|
||||
/* Propagate any types from this set into target. */
|
||||
void addSubset(JSContext *cx, HeapTypeSet *target);
|
||||
|
||||
/* Completely freeze the contents of this type set. */
|
||||
void addFreeze(JSContext *cx);
|
||||
|
@ -1152,7 +1130,7 @@ struct TypeObject : gc::Cell
|
|||
void clearAddendum(ExclusiveContext *cx);
|
||||
void clearNewScriptAddendum(ExclusiveContext *cx);
|
||||
void clearBinaryDataAddendum(ExclusiveContext *cx);
|
||||
void getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force = false);
|
||||
void getFromPrototypes(JSContext *cx, jsid id, HeapTypeSet *types, bool force = false);
|
||||
|
||||
void print();
|
||||
|
||||
|
@ -1500,10 +1478,6 @@ struct TypeCompartment
|
|||
void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
|
||||
void addPendingRecompile(JSContext *cx, JSScript *script);
|
||||
|
||||
/* Monitor future effects on a bytecode. */
|
||||
void monitorBytecode(JSContext *cx, JSScript *script, uint32_t offset,
|
||||
bool returnOnly = false);
|
||||
|
||||
/* Mark any type set containing obj as having a generic object type. */
|
||||
void markSetsUnknown(JSContext *cx, TypeObject *obj);
|
||||
|
||||
|
|
|
@ -1682,18 +1682,6 @@ JSScript::ensureRanAnalysis(JSContext *cx)
|
|||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::ensureRanInference(JSContext *cx)
|
||||
{
|
||||
if (!ensureRanAnalysis(cx))
|
||||
return false;
|
||||
if (!analysis()->ranInference()) {
|
||||
js::types::AutoEnterAnalysis enter(cx);
|
||||
analysis()->analyzeTypes(cx);
|
||||
}
|
||||
return !analysis()->OOM() && !cx->zone()->types.pendingNukeTypes;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::hasAnalysis()
|
||||
{
|
||||
|
@ -1723,14 +1711,6 @@ JSScript::clearPropertyReadTypes()
|
|||
types->propertyReadTypes = NULL;
|
||||
}
|
||||
|
||||
inline void
|
||||
js::analyze::ScriptAnalysis::addPushedType(JSContext *cx, uint32_t offset, uint32_t which,
|
||||
js::types::Type type)
|
||||
{
|
||||
js::types::TypeSet *pushed = pushedTypes(offset, which);
|
||||
pushed->addType(cx, type);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
template <>
|
||||
|
|
|
@ -2834,11 +2834,6 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
|
|||
}
|
||||
}
|
||||
|
||||
if (script->hasAnalysis() && script->analysis()->ranInference()) {
|
||||
types::AutoEnterAnalysis enter(cx);
|
||||
types::TypeScript::MonitorUnknown(cx, script, script->argumentsBytecode());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче