[INFER] Audit uses of PC in analysis and inference for UntrapOpcode, bug 657975, bug 657979, bug 657984.

This commit is contained in:
Brian Hackett 2011-05-19 10:09:17 -07:00
parent 14097cb845
commit 79674e33bc
6 changed files with 94 additions and 59 deletions

View File

@ -0,0 +1,24 @@
// |jit-test| debug
setDebug(true);
// bug 657975
function f1(){ "use strict"; options('strict'); }
trap(f1, 0, '')
f1()
// bug 657979
function f2(){ with({a:0}){}; }
trap(f2, 0, '')
f2()
x = 0;
// bug 657984 #1
function f3(){ for(y in x); }
trap(f3, 5, '')
f3()
// bug 657984 #2
function f4(){ for(y in x); }
trap(f4, 10, '')
f4()

View File

@ -176,8 +176,10 @@ ScriptAnalysis::addJump(JSContext *cx, unsigned offset,
code->jumpTarget = true;
if (offset < *currentOffset) {
JSOp op = JSOp(script->code[offset]);
if (op == JSOP_TRACE || op == JSOP_NOTRACE)
jsbytecode *pc = script->code + offset;
UntrapOpcode untrap(cx, script, pc);
if (JSOp(*pc) == JSOP_TRACE || JSOp(*pc) == JSOP_NOTRACE)
code->loopHead = true;
/* Scripts containing loops are never inlined. */
@ -790,7 +792,10 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
if (loop && code->safePoint)
loop->hasSafePoints = true;
UntrapOpcode untrap(cx, script, script->code + offset);
jsbytecode *pc = script->code + offset;
UntrapOpcode untrap(cx, script, pc);
JSOp op = (JSOp) *pc;
if (code->loop) {
/*
@ -814,9 +819,6 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
if (loop && code->jumpTarget && offset != loop->entry && offset > loop->lastBlock)
loop->lastBlock = offset;
jsbytecode *pc = script->code + offset;
JSOp op = (JSOp) *pc;
switch (op) {
case JSOP_GETARG:
case JSOP_CALLARG:
@ -911,7 +913,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
#ifdef DEBUG
JSOp nop = JSOp(script->code[targetOffset]);
JS_ASSERT(nop == JSOP_TRACE || nop == JSOP_NOTRACE);
JS_ASSERT(nop == JSOP_TRACE || nop == JSOP_NOTRACE || nop == JSOP_TRAP);
#endif
/*
@ -952,6 +954,8 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
} while (!maybeCode(entry));
jsbytecode *entrypc = script->code + entry;
UntrapOpcode untrap(cx, script, entrypc);
if (JSOp(*entrypc) == JSOP_GOTO || JSOp(*entrypc) == JSOP_GOTOX)
loop->entry = entry + GetJumpOffset(entrypc, entrypc);
else
@ -1795,6 +1799,8 @@ CrossScriptSSA::foldValue(const CrossSSAValue &cv)
if (v.kind() == SSAValue::PUSHED) {
jsbytecode *pc = frame.script->code + v.pushedOffset();
UntrapOpcode untrap(cx, frame.script, pc);
switch (JSOp(*pc)) {
case JSOP_THIS:
if (parentScript) {
@ -1824,6 +1830,7 @@ CrossScriptSSA::foldValue(const CrossSSAValue &cv)
uint32 offset = 0;
while (offset < callee->length) {
jsbytecode *pc = callee->code + offset;
UntrapOpcode untrap(cx, callee, pc);
if (analysis->maybeCode(pc) && JSOp(*pc) == JSOP_RETURN)
return foldValue(CrossSSAValue(calleeFrame, analysis->poppedValue(pc, 0)));
offset += GetBytecodeLength(pc);
@ -1867,6 +1874,8 @@ ScriptAnalysis::printSSA(JSContext *cx)
continue;
jsbytecode *pc = script->code + offset;
UntrapOpcode untrap(cx, script, pc);
PrintBytecode(cx, script, pc);
SlotValue *newv = code->newValues;

View File

@ -226,6 +226,8 @@ GetDefCount(JSScript *script, unsigned offset)
{
JS_ASSERT(offset < script->length);
jsbytecode *pc = script->code + offset;
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
if (js_CodeSpec[*pc].ndefs == -1)
return js_GetEnterBlockStackDefs(NULL, script, pc);
@ -251,6 +253,8 @@ GetUseCount(JSScript *script, unsigned offset)
{
JS_ASSERT(offset < script->length);
jsbytecode *pc = script->code + offset;
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
if (js_CodeSpec[*pc].nuses == -1)
return js_GetVariableStackUses(JSOp(*pc), pc);
return js_CodeSpec[*pc].nuses;
@ -263,6 +267,8 @@ GetUseCount(JSScript *script, unsigned offset)
static inline bool
ExtendedDef(jsbytecode *pc)
{
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
switch ((JSOp)*pc) {
case JSOP_SETARG:
case JSOP_INCARG:
@ -308,6 +314,8 @@ ExtendedUse(jsbytecode *pc)
static inline ptrdiff_t
GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
{
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
uint32 type = JOF_OPTYPE(*pc);
if (JOF_TYPE_IS_EXTENDED_JUMP(type))
return GET_JUMPX_OFFSET(pc2);

View File

@ -1679,13 +1679,16 @@ TypeCompartment::newInitializerTypeObject(JSContext *cx, JSScript *script,
res->initializerObject = true;
res->initializerOffset = offset;
if (JSOp(script->code[offset]) == JSOP_NEWOBJECT) {
jsbytecode *pc = script->code + offset;
UntrapOpcode untrap(cx, script, pc);
if (JSOp(*pc) == JSOP_NEWOBJECT) {
/*
* This object is always constructed the same way and will not be
* observed by other code before all properties have been added. Mark
* all the properties as definite properties of the object.
*/
JSObject *baseobj = script->getObject(GET_SLOTNO(script->code + offset));
JSObject *baseobj = script->getObject(GET_SLOTNO(pc));
if (!res->addDefiniteProperties(cx, baseobj))
return NULL;
@ -1727,6 +1730,8 @@ types::UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc)
{
JS_ASSERT(cx->typeInferenceEnabled());
UntrapOpcode untrap(cx, script, pc);
/*
* Make a heuristic guess at a use of JSOP_NEW that the constructed object
* should have a fresh type object. We do this when the NEW is immediately
@ -2109,12 +2114,15 @@ TypeCompartment::monitorBytecode(JSContext *cx, JSScript *script, uint32 offset)
if (script->analysis(cx)->getCode(offset).monitoredTypes)
return;
jsbytecode *pc = script->code + offset;
UntrapOpcode untrap(cx, script, pc);
/*
* Make sure monitoring is limited to property sets and calls where the
* target of the set/call could be statically unknown, and mark the bytecode
* results as unknown.
*/
JSOp op = JSOp(script->code[offset]);
JSOp op = JSOp(*pc);
switch (op) {
case JSOP_SETNAME:
case JSOP_SETGNAME:
@ -2830,43 +2838,6 @@ TypeObject::print(JSContext *cx)
// Type Analysis
/////////////////////////////////////////////////////////////////////
static inline ptrdiff_t
GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
{
uint32 type = JOF_OPTYPE(*pc);
if (JOF_TYPE_IS_EXTENDED_JUMP(type))
return GET_JUMPX_OFFSET(pc2);
return GET_JUMP_OFFSET(pc2);
}
/* 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_GOTOX:
case JSOP_DEFAULT:
case JSOP_DEFAULTX:
case JSOP_RETURN:
case JSOP_STOP:
case JSOP_RETRVAL:
case JSOP_THROW:
case JSOP_TABLESWITCH:
case JSOP_TABLESWITCHX:
case JSOP_LOOKUPSWITCH:
case JSOP_LOOKUPSWITCHX:
case JSOP_FILTER:
return true;
case JSOP_GOSUB:
case JSOP_GOSUBX:
/* These fall through indirectly, after executing a 'finally'. */
return false;
default:
return false;
}
}
/*
* If the bytecode immediately following code/pc is a test of the value
* pushed by code, that value should be marked as possibly void.
@ -2887,6 +2858,7 @@ CheckNextTest(jsbytecode *pc)
case JSOP_TYPEOFEXPR:
return true;
default:
/* TRAP ok here */
return false;
}
}
@ -2897,6 +2869,8 @@ GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
if (!script->global)
return NULL;
UntrapOpcode untrap(cx, script, pc);
JSOp op = JSOp(*pc);
JS_ASSERT(op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT || op == JSOP_NEWINIT);
@ -2910,7 +2884,7 @@ ScriptAnalysis::setForTypes(JSContext *cx, jsbytecode *pc, TypeSet *types)
/* Find the initial ITER opcode which constructed the active iterator. */
const SSAValue &iterv = poppedValue(pc, 0);
jsbytecode *iterpc = script->code + iterv.pushedOffset();
JS_ASSERT(JSOp(*iterpc) == JSOP_ITER);
JS_ASSERT(JSOp(*iterpc) == JSOP_ITER || JSOp(*iterpc) == JSOP_TRAP);
uintN flags = iterpc[1];
if (flags & JSITER_FOREACH) {
@ -3967,6 +3941,8 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script, JS
while (nextOffset < script->length) {
unsigned offset = nextOffset;
jsbytecode *pc = script->code + offset;
UntrapOpcode untrap(cx, script, pc);
JSOp op = JSOp(*pc);
nextOffset += GetBytecodeLength(pc);
@ -4023,6 +3999,8 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script, JS
return false;
pc = script->code + uses->offset;
UntrapOpcode untrapUse(cx, script, pc);
op = JSOp(*pc);
JSObject *obj = *pbaseobj;
@ -4088,14 +4066,15 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script, JS
/* Callee/this must have been pushed by a CALLPROP. */
SSAValue calleev = analysis->poppedValue(pc, GET_ARGC(pc) + 1);
if (calleev.kind() != SSAValue::PUSHED ||
JSOp(script->code[calleev.pushedOffset()]) != JSOP_CALLPROP ||
calleev.pushedIndex() != 0) {
if (calleev.kind() != SSAValue::PUSHED)
return false;
jsbytecode *calleepc = script->code + calleev.pushedOffset();
UntrapOpcode untrapCallee(cx, script, calleepc);
if (JSOp(*calleepc) != JSOP_CALLPROP || calleev.pushedIndex() != 0)
return false;
}
TypeSet *funcallTypes = analysis->pushedTypes(calleev.pushedOffset(), 0);
TypeSet *scriptTypes = analysis->pushedTypes(calleev.pushedOffset(), 1);
TypeSet *funcallTypes = analysis->pushedTypes(calleepc, 0);
TypeSet *scriptTypes = analysis->pushedTypes(calleepc, 1);
/* Need to definitely be calling Function.call on a specific script. */
TypeObject *funcallObj = funcallTypes->getSingleObject();
@ -4177,6 +4156,9 @@ ScriptAnalysis::printTypes(JSContext *cx)
if (!maybeCode(offset))
continue;
jsbytecode *pc = script->code + offset;
UntrapOpcode untrap(cx, script, pc);
unsigned defCount = GetDefCount(script, offset);
if (!defCount)
continue;
@ -4251,10 +4233,13 @@ ScriptAnalysis::printTypes(JSContext *cx)
if (!maybeCode(offset))
continue;
PrintBytecode(cx, script, script->code + offset);
jsbytecode *pc = script->code + offset;
UntrapOpcode untrap(cx, script, pc);
if (js_CodeSpec[script->code[offset]].format & JOF_TYPESET) {
TypeSet *types = script->bytecodeTypes(script->code + offset);
PrintBytecode(cx, script, pc);
if (js_CodeSpec[*pc].format & JOF_TYPESET) {
TypeSet *types = script->bytecodeTypes(pc);
printf(" typeset %d:", (int) (types - script->typeArray));
types->print(cx);
printf("\n");
@ -4298,6 +4283,8 @@ ScriptAnalysis::printTypes(JSContext *cx)
static inline bool
IgnorePushed(const jsbytecode *pc, unsigned index)
{
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
switch (JSOp(*pc)) {
/* We keep track of the scopes pushed by BINDNAME separately. */
case JSOP_BINDNAME:

View File

@ -208,6 +208,8 @@ UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
static inline bool
CanHaveReadBarrier(const jsbytecode *pc)
{
JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
switch (JSOp(*pc)) {
case JSOP_LENGTH:
case JSOP_GETPROP:
@ -291,6 +293,8 @@ JSContext::markTypeCallerUnexpected(js::types::jstype type)
JSScript *script;
jsbytecode *pc = caller->inlinepc(this, &script);
js::analyze::UntrapOpcode untrap(this, script, pc);
switch ((JSOp)*pc) {
case JSOP_CALL:
case JSOP_EVAL:
@ -515,6 +519,7 @@ JSScript::bytecodeTypes(const jsbytecode *pc)
JS_ASSERT(typeArray);
JSOp op = JSOp(*pc);
JS_ASSERT(op != JSOP_TRAP);
JS_ASSERT(js_CodeSpec[op].format & JOF_TYPESET);
/* All bytecodes with type sets are JOF_ATOM, except JSOP_{GET,CALL}ELEM */
@ -622,8 +627,10 @@ JSScript::getTypeInitObject(JSContext *cx, const jsbytecode *pc, bool isArray)
}
inline void
JSScript::typeMonitor(JSContext *cx, const jsbytecode *pc, const js::Value &rval)
JSScript::typeMonitor(JSContext *cx, jsbytecode *pc, const js::Value &rval)
{
js::analyze::UntrapOpcode untrap(cx, this, pc);
if (cx->typeInferenceEnabled() && (js_CodeSpec[*pc].format & JOF_TYPESET)) {
/* Allow the non-TYPESET scenario to simplify stubs invonked by INC* ops. Yuck. */

View File

@ -595,7 +595,7 @@ struct JSScript {
inline void typeMonitorUnknown(JSContext *cx, const jsbytecode *pc);
/* Monitor a JOF_TYPESET bytecode pushing any value into its pushed type set. */
inline void typeMonitor(JSContext *cx, const jsbytecode *pc, const js::Value &val);
inline void typeMonitor(JSContext *cx, jsbytecode *pc, const js::Value &val);
/* Monitor an assignment at a SETELEM on a non-integer identifier. */
inline void typeMonitorAssign(JSContext *cx, const jsbytecode *pc,