mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] Audit uses of PC in analysis and inference for UntrapOpcode, bug 657975, bug 657979, bug 657984.
This commit is contained in:
parent
14097cb845
commit
79674e33bc
24
js/src/jit-test/tests/basic/bug657975.js
Normal file
24
js/src/jit-test/tests/basic/bug657975.js
Normal 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()
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user