mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Add Script.prototype.getOffsetLine.
This commit is contained in:
parent
1c0e0f089a
commit
f87c801c95
27
js/src/jit-test/tests/debug/Script-getOffsetLine-01.js
Normal file
27
js/src/jit-test/tests/debug/Script-getOffsetLine-01.js
Normal file
@ -0,0 +1,27 @@
|
||||
// Basic getOffsetLine test, using Error.lineNumber as the gold standard.
|
||||
|
||||
var g = newGlobal('new-compartment');
|
||||
var dbg = Debug(g);
|
||||
var hits;
|
||||
dbg.hooks = {
|
||||
debuggerHandler: function (frame) {
|
||||
var knownLine = frame.eval("line").return;
|
||||
assertEq(frame.script.getOffsetLine(frame.offset), knownLine);
|
||||
hits++;
|
||||
}
|
||||
};
|
||||
|
||||
hits = 0;
|
||||
g.eval("var line = new Error().lineNumber; debugger;");
|
||||
assertEq(hits, 1);
|
||||
|
||||
hits = 0;
|
||||
g.eval("var s = 2 + 2;\n" +
|
||||
"s += 2;\n" +
|
||||
"line = new Error().lineNumber; debugger;\n" +
|
||||
"s += 2;\n" +
|
||||
"s += 2;\n" +
|
||||
"line = new Error().lineNumber; debugger;\n" +
|
||||
"s += 2;\n" +
|
||||
"assertEq(s, 12);\n");
|
||||
assertEq(hits, 2);
|
21
js/src/jit-test/tests/debug/Script-getOffsetLine-02.js
Normal file
21
js/src/jit-test/tests/debug/Script-getOffsetLine-02.js
Normal file
@ -0,0 +1,21 @@
|
||||
// Frame.script/offset and Script.getOffsetLine work in non-top frames.
|
||||
|
||||
var g = newGlobal('new-compartment');
|
||||
var dbg = Debug(g);
|
||||
var hits = 0;
|
||||
dbg.hooks = {
|
||||
debuggerHandler: function (frame) {
|
||||
var a = [];
|
||||
for (; frame.type == "call"; frame = frame.older)
|
||||
a.push(frame.script.getOffsetLine(frame.offset) - g.line0);
|
||||
assertEq(a.join(","), "1,2,3,4");
|
||||
hits++;
|
||||
}
|
||||
};
|
||||
g.eval("var line0 = Error().lineNumber;\n" +
|
||||
"function f0() { debugger; }\n" +
|
||||
"function f1() { f0(); }\n" +
|
||||
"function f2() { f1(); }\n" +
|
||||
"function f3() { f2(); }\n" +
|
||||
"f3();\n");
|
||||
assertEq(hits, 1);
|
30
js/src/jit-test/tests/debug/surfaces-offsets.js
Normal file
30
js/src/jit-test/tests/debug/surfaces-offsets.js
Normal file
@ -0,0 +1,30 @@
|
||||
// Invalid offsets result in exceptions, not bogus results.
|
||||
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
var g = newGlobal('new-compartment');
|
||||
var dbg = Debug(g);
|
||||
var hits;
|
||||
dbg.hooks = {
|
||||
debuggerHandler: function (frame) {
|
||||
assertEq(frame.script.getOffsetLine(frame.offset), g.line);
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(String(frame.offset)); }, Error);
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(Object(frame.offset)); }, Error);
|
||||
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(-1); }, Error);
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(1000000); }, Error);
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(0.25); }, Error);
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(+Infinity); }, Error);
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(-Infinity); }, Error);
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(NaN); }, Error);
|
||||
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(false); }, Error);
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(true); }, Error);
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(undefined); }, Error);
|
||||
assertThrowsInstanceOf(function () { frame.script.getOffsetLine(); }, Error);
|
||||
hits++;
|
||||
}
|
||||
};
|
||||
|
||||
hits = 0;
|
||||
g.eval("var line = new Error().lineNumber; debugger;");
|
@ -358,3 +358,4 @@ MSG_DEF(JSMSG_DEBUG_OBJECT_WRONG_OWNER, 275, 0, JSEXN_TYPEERR, "Debug.Object bel
|
||||
MSG_DEF(JSMSG_DEBUG_OBJECT_PROTO, 276, 0, JSEXN_TYPEERR, "Debug.Object.prototype is not a valid Debug.Object")
|
||||
MSG_DEF(JSMSG_DEBUG_LOOP, 277, 0, JSEXN_TYPEERR, "cannot debug an object in same compartment as debugger or a compartment that is already debugging the debugger")
|
||||
MSG_DEF(JSMSG_DEBUG_NOT_IDLE, 278, 0, JSEXN_ERR, "can't start debugging: a debuggee script is on the stack")
|
||||
MSG_DEF(JSMSG_DEBUG_BAD_OFFSET, 279, 0, JSEXN_TYPEERR, "invalid script offset")
|
||||
|
@ -1275,6 +1275,38 @@ DebugScript_getLive(JSContext *cx, uintN argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ScriptOffset(JSContext *cx, JSScript *script, const Value &v, size_t *offsetp)
|
||||
{
|
||||
double d;
|
||||
size_t off;
|
||||
|
||||
bool ok = v.isNumber();
|
||||
if (ok) {
|
||||
d = v.toNumber();
|
||||
off = size_t(d);
|
||||
}
|
||||
if (!ok || off != d || !IsValidBytecodeOffset(cx, script, off)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_BAD_OFFSET);
|
||||
return false;
|
||||
}
|
||||
*offsetp = off;
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DebugScript_getOffsetLine(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
REQUIRE_ARGC("Debug.Script.getOffsetLine", 1);
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, vp, "getOffsetLine", obj, script);
|
||||
size_t offset;
|
||||
if (!ScriptOffset(cx, script, vp[2], &offset))
|
||||
return false;
|
||||
uintN lineno = JS_PCToLineNumber(cx, script, script->code + offset);
|
||||
vp->setNumber(lineno);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DebugScript_construct(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
@ -1288,7 +1320,7 @@ static JSPropertySpec DebugScript_properties[] = {
|
||||
};
|
||||
|
||||
static JSFunctionSpec DebugScript_methods[] = {
|
||||
// JS_FN("getOffsetLine", DebugScript_getOffsetLine, 0, 0),
|
||||
JS_FN("getOffsetLine", DebugScript_getOffsetLine, 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
@ -72,9 +72,10 @@
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsopcodeinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "jsautooplen.h"
|
||||
|
||||
@ -170,14 +171,12 @@ js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
return base + GET_UINT16(pc + pcoff);
|
||||
}
|
||||
|
||||
uintN
|
||||
js_GetVariableBytecodeLength(jsbytecode *pc)
|
||||
size_t
|
||||
js_GetVariableBytecodeLength(JSOp op, jsbytecode *pc)
|
||||
{
|
||||
JSOp op;
|
||||
uintN jmplen, ncases;
|
||||
jsint low, high;
|
||||
|
||||
op = (JSOp) *pc;
|
||||
JS_ASSERT(js_CodeSpec[op].length == -1);
|
||||
switch (op) {
|
||||
case JSOP_TABLESWITCHX:
|
||||
@ -5621,4 +5620,27 @@ CallResultEscapes(jsbytecode *pc)
|
||||
return (*pc != JSOP_IFEQ);
|
||||
}
|
||||
|
||||
size_t
|
||||
GetBytecodeLength(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
JSOp op = js_GetOpcode(cx, script, pc);
|
||||
JS_ASSERT(op < JSOP_LIMIT);
|
||||
JS_ASSERT(op != JSOP_TRAP);
|
||||
if (js_CodeSpec[op].length != -1)
|
||||
return js_CodeSpec[op].length;
|
||||
return js_GetVariableBytecodeLength(op, pc);
|
||||
}
|
||||
|
||||
extern bool
|
||||
IsValidBytecodeOffset(JSContext *cx, JSScript *script, size_t offset)
|
||||
{
|
||||
// This could be faster (by following jump instructions if the target is <= offset).
|
||||
for (BytecodeRange r(cx, script); !r.empty(); r.popFront()) {
|
||||
size_t here = r.frontOffset();
|
||||
if (here >= offset)
|
||||
return here == offset;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
@ -381,12 +381,6 @@ js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
obj = (script)->getRegExp(index_); \
|
||||
JS_END_MACRO
|
||||
|
||||
/*
|
||||
* Get the length of variable-length bytecode like JSOP_TABLESWITCH.
|
||||
*/
|
||||
extern uintN
|
||||
js_GetVariableBytecodeLength(jsbytecode *pc);
|
||||
|
||||
/*
|
||||
* Find the number of stack slots used by a variadic opcode such as JSOP_CALL
|
||||
* (for such ops, JSCodeSpec.nuses is -1).
|
||||
@ -467,10 +461,36 @@ extern char *
|
||||
js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
||||
JSString *fallback);
|
||||
|
||||
/*
|
||||
* Given bytecode address pc in script's main program code, return the operand
|
||||
* stack depth just before (JSOp) *pc executes.
|
||||
*/
|
||||
extern uintN
|
||||
js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#define JSDVG_IGNORE_STACK 0
|
||||
#define JSDVG_SEARCH_STACK 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
/*
|
||||
* Get the length of variable-length bytecode like JSOP_TABLESWITCH.
|
||||
*/
|
||||
extern size_t
|
||||
js_GetVariableBytecodeLength(JSOp op, jsbytecode *pc);
|
||||
|
||||
inline size_t
|
||||
js_GetVariableBytecodeLength(jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(*pc != JSOP_TRAP);
|
||||
return js_GetVariableBytecodeLength(JSOp(*pc), pc);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
static inline char *
|
||||
@ -519,6 +539,12 @@ Sprint(Sprinter *sp, const char *format, ...);
|
||||
extern bool
|
||||
CallResultEscapes(jsbytecode *pc);
|
||||
|
||||
extern size_t
|
||||
GetBytecodeLength(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
|
||||
extern bool
|
||||
IsValidBytecodeOffset(JSContext *cx, JSScript *script, size_t offset);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -534,17 +560,4 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
|
||||
JSBool lines, js::Sprinter *sp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Given bytecode address pc in script's main program code, return the operand
|
||||
* stack depth just before (JSOp) *pc executes.
|
||||
*/
|
||||
extern uintN
|
||||
js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsopcode_h___ */
|
||||
|
@ -40,6 +40,22 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
class BytecodeRange {
|
||||
public:
|
||||
BytecodeRange(JSContext *cx, JSScript *script)
|
||||
: cx(cx), script(script), pc(script->code), end(pc + script->length) {}
|
||||
bool empty() const { return pc == end; }
|
||||
jsbytecode *frontPC() const { return pc; }
|
||||
JSOp frontOpcode() const { return js_GetOpcode(cx, script, pc); }
|
||||
size_t frontOffset() const { return pc - script->code; }
|
||||
void popFront() { pc += GetBytecodeLength(cx, script, pc); }
|
||||
|
||||
private:
|
||||
JSContext *cx;
|
||||
JSScript *script;
|
||||
jsbytecode *pc, *end;
|
||||
};
|
||||
|
||||
/*
|
||||
* Warning: this does not skip JSOP_RESETBASE* or JSOP_INDEXBASE* ops, so it is
|
||||
* useful only when checking for optimization opportunities.
|
||||
|
Loading…
Reference in New Issue
Block a user