mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 568142 - Part 1: Add column numbers to error reports. r=jorendorff
This commit is contained in:
parent
3a886a65cd
commit
ffaca98dfe
@ -386,41 +386,58 @@ EmitBackPatchOp(JSContext *cx, BytecodeEmitter *bce, JSOp op, ptrdiff_t *lastp)
|
||||
return EmitJump(cx, bce, op, delta);
|
||||
}
|
||||
|
||||
/* A macro for inlining at the top of EmitTree (whence it came). */
|
||||
#define UPDATE_LINE_NUMBER_NOTES(cx, bce, line) \
|
||||
JS_BEGIN_MACRO \
|
||||
unsigned line_ = (line); \
|
||||
unsigned delta_ = line_ - bce->currentLine(); \
|
||||
if (delta_ != 0) { \
|
||||
/* \
|
||||
* Encode any change in the current source line number by using \
|
||||
* either several SRC_NEWLINE notes or just one SRC_SETLINE note, \
|
||||
* whichever consumes less space. \
|
||||
* \
|
||||
* NB: We handle backward line number deltas (possible with for \
|
||||
* loops where the update part is emitted after the body, but its \
|
||||
* line number is <= any line number in the body) here by letting \
|
||||
* unsigned delta_ wrap to a very large number, which triggers a \
|
||||
* SRC_SETLINE. \
|
||||
*/ \
|
||||
bce->current->currentLine = line_; \
|
||||
if (delta_ >= (unsigned)(2 + ((line_ > SN_3BYTE_OFFSET_MASK)<<1))) { \
|
||||
if (NewSrcNote2(cx, bce, SRC_SETLINE, (ptrdiff_t)line_) < 0) \
|
||||
return false; \
|
||||
} else { \
|
||||
do { \
|
||||
if (NewSrcNote(cx, bce, SRC_NEWLINE) < 0) \
|
||||
return false; \
|
||||
} while (--delta_ != 0); \
|
||||
} \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
/* Updates line number notes, not column notes. */
|
||||
static inline bool
|
||||
UpdateLineNumberNotes(JSContext *cx, BytecodeEmitter *bce, unsigned line)
|
||||
{
|
||||
unsigned delta = line - bce->currentLine();
|
||||
if (delta != 0) {
|
||||
/*
|
||||
* Encode any change in the current source line number by using
|
||||
* either several SRC_NEWLINE notes or just one SRC_SETLINE note,
|
||||
* whichever consumes less space.
|
||||
*
|
||||
* NB: We handle backward line number deltas (possible with for
|
||||
* loops where the update part is emitted after the body, but its
|
||||
* line number is <= any line number in the body) here by letting
|
||||
* unsigned delta_ wrap to a very large number, which triggers a
|
||||
* SRC_SETLINE.
|
||||
*/
|
||||
bce->current->currentLine = line;
|
||||
bce->current->lastColumn = 0;
|
||||
if (delta >= (unsigned)(2 + ((line > SN_3BYTE_OFFSET_MASK)<<1))) {
|
||||
if (NewSrcNote2(cx, bce, SRC_SETLINE, (ptrdiff_t)line) < 0)
|
||||
return false;
|
||||
} else {
|
||||
do {
|
||||
if (NewSrcNote(cx, bce, SRC_NEWLINE) < 0)
|
||||
return false;
|
||||
} while (--delta != 0);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* A function, so that we avoid macro-bloating all the other callsites. */
|
||||
static bool
|
||||
UpdateLineNumberNotes(JSContext *cx, BytecodeEmitter *bce, unsigned line)
|
||||
UpdateSourceCoordNotes(JSContext *cx, BytecodeEmitter *bce, TokenPtr pos)
|
||||
{
|
||||
UPDATE_LINE_NUMBER_NOTES(cx, bce, line);
|
||||
if (!UpdateLineNumberNotes(cx, bce, pos.lineno))
|
||||
return false;
|
||||
|
||||
ptrdiff_t colspan = ptrdiff_t(pos.index) -
|
||||
ptrdiff_t(bce->current->lastColumn);
|
||||
if (colspan != 0) {
|
||||
if (colspan < 0) {
|
||||
colspan += SN_COLSPAN_DOMAIN;
|
||||
} else if (colspan >= SN_COLSPAN_DOMAIN / 2) {
|
||||
ReportStatementTooLarge(cx, bce->topStmt);
|
||||
return false;
|
||||
}
|
||||
if (NewSrcNote2(cx, bce, SRC_COLSPAN, colspan) < 0)
|
||||
return false;
|
||||
bce->current->lastColumn = pos.index;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -436,7 +453,7 @@ EmitLoopHead(JSContext *cx, BytecodeEmitter *bce, ParseNode *nextpn)
|
||||
JS_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
|
||||
if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
|
||||
nextpn = nextpn->pn_head;
|
||||
if (!UpdateLineNumberNotes(cx, bce, nextpn->pn_pos.begin.lineno))
|
||||
if (!UpdateSourceCoordNotes(cx, bce, nextpn->pn_pos.begin))
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -451,7 +468,7 @@ EmitLoopEntry(JSContext *cx, BytecodeEmitter *bce, ParseNode *nextpn)
|
||||
JS_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
|
||||
if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
|
||||
nextpn = nextpn->pn_head;
|
||||
if (!UpdateLineNumberNotes(cx, bce, nextpn->pn_pos.begin.lineno))
|
||||
if (!UpdateSourceCoordNotes(cx, bce, nextpn->pn_pos.begin))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2690,7 +2707,7 @@ MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *
|
||||
(!bce->sc->inFunction() || bce->sc->fun()->isHeavyweight()))
|
||||
{
|
||||
bce->switchToProlog();
|
||||
if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
|
||||
if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin))
|
||||
return false;
|
||||
if (!EmitIndexOp(cx, prologOp, atomIndex, bce))
|
||||
return false;
|
||||
@ -4105,7 +4122,7 @@ EmitTry(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
|
||||
/* Indicate that we're emitting a subroutine body. */
|
||||
stmtInfo.type = STMT_SUBROUTINE;
|
||||
if (!UpdateLineNumberNotes(cx, bce, pn->pn_kid3->pn_pos.begin.lineno))
|
||||
if (!UpdateSourceCoordNotes(cx, bce, pn->pn_kid3->pn_pos.begin))
|
||||
return false;
|
||||
if (Emit1(cx, bce, JSOP_FINALLY) < 0 ||
|
||||
!EmitTree(cx, bce, pn->pn_kid3) ||
|
||||
@ -4699,6 +4716,8 @@ EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
|
||||
}
|
||||
#endif
|
||||
if (op == JSOP_POP) {
|
||||
if (!UpdateSourceCoordNotes(cx, bce, pn3->pn_pos.begin))
|
||||
return false;
|
||||
if (!EmitTree(cx, bce, pn3))
|
||||
return false;
|
||||
if (pn3->isKind(PNK_VAR) || pn3->isKind(PNK_CONST) || pn3->isKind(PNK_LET)) {
|
||||
@ -4762,6 +4781,8 @@ EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
|
||||
/* Check for update code to do before the condition (if any). */
|
||||
pn3 = forHead->pn_kid3;
|
||||
if (pn3) {
|
||||
if (!UpdateSourceCoordNotes(cx, bce, pn3->pn_pos.begin))
|
||||
return false;
|
||||
op = JSOP_POP;
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
if (pn3->isKind(PNK_ASSIGN)) {
|
||||
@ -4910,7 +4931,7 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
bce->switchToProlog();
|
||||
if (!EmitIndex32(cx, JSOP_DEFFUN, index, bce))
|
||||
return false;
|
||||
if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
|
||||
if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin))
|
||||
return false;
|
||||
bce->switchToMain();
|
||||
|
||||
@ -5102,6 +5123,9 @@ EmitContinue(JSContext *cx, BytecodeEmitter *bce, PropertyName *label)
|
||||
static bool
|
||||
EmitReturn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
{
|
||||
if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin))
|
||||
return false;
|
||||
|
||||
/* Push a return value */
|
||||
if (ParseNode *pn2 = pn->pn_kid) {
|
||||
if (!EmitTree(cx, bce, pn2))
|
||||
@ -5179,6 +5203,9 @@ EmitStatement(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
if (!pn2)
|
||||
return true;
|
||||
|
||||
if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Top-level or called-from-a-native JS_Execute/EvaluateScript,
|
||||
* debugger, and eval frames may need the value of the ultimate
|
||||
@ -5927,6 +5954,8 @@ EmitArray(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
static bool
|
||||
EmitUnary(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
{
|
||||
if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin))
|
||||
return false;
|
||||
/* Unary op, including unary +/-. */
|
||||
JSOp op = pn->getOp();
|
||||
ParseNode *pn2 = pn->pn_kid;
|
||||
@ -6028,7 +6057,8 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
pn->pn_offset = top;
|
||||
|
||||
/* Emit notes to tell the current bytecode's source line number. */
|
||||
UPDATE_LINE_NUMBER_NOTES(cx, bce, pn->pn_pos.begin.lineno);
|
||||
if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
|
||||
return false;
|
||||
|
||||
switch (pn->getKind()) {
|
||||
case PNK_FUNCTION:
|
||||
@ -6627,7 +6657,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
|
||||
/* bce->emitLevel == 1 means we're last on the stack, so finish up. */
|
||||
if (ok && bce->emitLevel == 1) {
|
||||
if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.end.lineno))
|
||||
if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.end))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -7092,7 +7122,7 @@ JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
|
||||
{"switch", 2},
|
||||
{"funcdef", 1},
|
||||
{"catch", 1},
|
||||
{"unused", -1},
|
||||
{"colspan", 1},
|
||||
{"newline", 0},
|
||||
{"setline", 1},
|
||||
{"xdelta", 0},
|
||||
|
@ -73,6 +73,8 @@ struct BytecodeEmitter
|
||||
unsigned noteLimit; /* limit number for source notes in notePool */
|
||||
ptrdiff_t lastNoteOffset; /* code offset for last source note */
|
||||
unsigned currentLine; /* line number for tree-based srcnote gen */
|
||||
unsigned lastColumn; /* zero-based column index on currentLine of
|
||||
last SRC_COLSPAN-annotated opcode */
|
||||
} prolog, main, *current;
|
||||
|
||||
Parser *const parser; /* the parser */
|
||||
@ -174,6 +176,7 @@ struct BytecodeEmitter
|
||||
unsigned noteLimit() const { return current->noteLimit; }
|
||||
ptrdiff_t lastNoteOffset() const { return current->lastNoteOffset; }
|
||||
unsigned currentLine() const { return current->currentLine; }
|
||||
unsigned lastColumn() const { return current->lastColumn; }
|
||||
|
||||
inline ptrdiff_t countFinalSourceNotes();
|
||||
|
||||
@ -249,7 +252,7 @@ EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *body);
|
||||
* +---------+-----+ +---+-----------+
|
||||
*
|
||||
* At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE,
|
||||
* SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode.
|
||||
* SRC_COLSPAN, SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode.
|
||||
*
|
||||
* NB: the js_SrcNoteSpec array in BytecodeEmitter.cpp is indexed by this
|
||||
* enum, so its initializers need to match the order here.
|
||||
@ -310,7 +313,7 @@ enum SrcNoteType {
|
||||
SRC_SWITCHBREAK = 18, /* JSOP_GOTO is a break in a switch */
|
||||
SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */
|
||||
SRC_CATCH = 20, /* catch block has guard */
|
||||
/* 21 is unused */
|
||||
SRC_COLSPAN = 21, /* number of columns this opcode spans */
|
||||
SRC_NEWLINE = 22, /* bytecode follows a source newline */
|
||||
SRC_SETLINE = 23, /* a file-absolute source line number note */
|
||||
SRC_XDELTA = 24 /* 24-31 are for extended delta notes */
|
||||
@ -346,7 +349,7 @@ enum SrcNoteType {
|
||||
? SRC_XDELTA \
|
||||
: *(sn) >> SN_DELTA_BITS))
|
||||
#define SN_SET_TYPE(sn,type) SN_MAKE_NOTE(sn, type, SN_DELTA(sn))
|
||||
#define SN_IS_GETTABLE(sn) (SN_TYPE(sn) < SRC_NEWLINE)
|
||||
#define SN_IS_GETTABLE(sn) (SN_TYPE(sn) < SRC_COLSPAN)
|
||||
|
||||
#define SN_DELTA(sn) ((ptrdiff_t)(SN_IS_XDELTA(sn) \
|
||||
? *(sn) & SN_XDELTA_MASK \
|
||||
@ -366,6 +369,19 @@ enum SrcNoteType {
|
||||
#define SN_3BYTE_OFFSET_FLAG 0x80
|
||||
#define SN_3BYTE_OFFSET_MASK 0x7f
|
||||
|
||||
/*
|
||||
* Negative SRC_COLSPAN offsets are rare, but can arise with for(;;) loops and
|
||||
* other constructs that generate code in non-source order. They can also arise
|
||||
* due to failure to update pn->pn_pos.end to be the last child's end -- such
|
||||
* failures are bugs to fix.
|
||||
*
|
||||
* Source note offsets in general must be non-negative and less than 0x800000,
|
||||
* per the above SN_3BYTE_* definitions. To encode negative colspans, we bias
|
||||
* them by the offset domain size and restrict non-negative colspans to less
|
||||
* than half this domain.
|
||||
*/
|
||||
#define SN_COLSPAN_DOMAIN ptrdiff_t(SN_3BYTE_OFFSET_FLAG << 16)
|
||||
|
||||
#define SN_MAX_OFFSET ((size_t)((ptrdiff_t)SN_3BYTE_OFFSET_FLAG << 16) - 1)
|
||||
|
||||
#define SN_LENGTH(sn) ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \
|
||||
|
@ -259,7 +259,7 @@ def check_output(out, err, rc, test):
|
||||
if rc != test.expect_status:
|
||||
# Allow a non-zero exit code if we want to allow OOM, but only if we
|
||||
# actually got OOM.
|
||||
return test.allow_oom and ': out of memory' in err and 'Assertion failure' not in err
|
||||
return test.allow_oom and 'out of memory' in err and 'Assertion failure' not in err
|
||||
|
||||
return True
|
||||
|
||||
|
@ -65,6 +65,7 @@ CPPSRCS = \
|
||||
testXDR.cpp \
|
||||
testProfileStrings.cpp \
|
||||
testJSEvaluateScript.cpp \
|
||||
testErrorCopying.cpp \
|
||||
$(NULL)
|
||||
|
||||
CSRCS = \
|
||||
|
35
js/src/jsapi-tests/testErrorCopying.cpp
Normal file
35
js/src/jsapi-tests/testErrorCopying.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*
|
||||
* Tests that the column number of error reports is properly copied over from
|
||||
* other reports when invoked from the C++ api.
|
||||
*/
|
||||
/* 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 "tests.h"
|
||||
#include "jscntxt.h"
|
||||
|
||||
static uint32_t column = 0;
|
||||
|
||||
static void
|
||||
my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
|
||||
{
|
||||
column = report->column;
|
||||
}
|
||||
|
||||
BEGIN_TEST(testErrorCopying_columnCopied)
|
||||
{
|
||||
//0 1 2
|
||||
//0123456789012345678901234567
|
||||
EXEC("function check() { Object; foo; }");
|
||||
|
||||
JS::RootedValue rval(cx);
|
||||
JS_SetErrorReporter(cx, my_ErrorReporter);
|
||||
CHECK(!JS_CallFunctionName(cx, global, "check", 0, NULL, rval.address()));
|
||||
CHECK(column == 27);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testErrorCopying_columnCopied)
|
@ -6039,6 +6039,7 @@ struct JSErrorReport {
|
||||
const jschar *ucmessage; /* the (default) error message */
|
||||
const jschar **messageArgs; /* arguments for the error message */
|
||||
int16_t exnType; /* One of the JSExnType constants */
|
||||
unsigned column; /* zero-based column index in line */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -43,6 +43,7 @@ DEFINE_ATOM(call, "call")
|
||||
DEFINE_ATOM(callee, "callee")
|
||||
DEFINE_ATOM(caller, "caller")
|
||||
DEFINE_ATOM(classPrototype, "prototype")
|
||||
DEFINE_ATOM(columnNumber, "columnNumber")
|
||||
DEFINE_ATOM(constructor, "constructor")
|
||||
DEFINE_ATOM(each, "each")
|
||||
DEFINE_ATOM(eval, "eval")
|
||||
|
@ -474,7 +474,7 @@ PopulateReportBlame(JSContext *cx, JSErrorReport *report)
|
||||
return;
|
||||
|
||||
report->filename = iter.script()->filename;
|
||||
report->lineno = PCToLineNumber(iter.script(), iter.pc());
|
||||
report->lineno = PCToLineNumber(iter.script(), iter.pc(), &report->column);
|
||||
report->originPrincipals = iter.script()->originPrincipals;
|
||||
}
|
||||
|
||||
|
@ -96,6 +96,7 @@ struct JSExnPrivate
|
||||
js::HeapPtrString message;
|
||||
js::HeapPtrString filename;
|
||||
unsigned lineno;
|
||||
unsigned column;
|
||||
size_t stackDepth;
|
||||
int exnType;
|
||||
JSStackTraceElem stackElems[1];
|
||||
@ -216,6 +217,7 @@ CopyErrorReport(JSContext *cx, JSErrorReport *report)
|
||||
|
||||
/* Copy non-pointer members. */
|
||||
copy->lineno = report->lineno;
|
||||
copy->column = report->column;
|
||||
copy->errorNumber = report->errorNumber;
|
||||
copy->exnType = report->exnType;
|
||||
|
||||
@ -250,7 +252,8 @@ SetExnPrivate(JSContext *cx, JSObject *exnObject, JSExnPrivate *priv);
|
||||
|
||||
static bool
|
||||
InitExnPrivate(JSContext *cx, HandleObject exnObject, HandleString message,
|
||||
HandleString filename, unsigned lineno, JSErrorReport *report, int exnType)
|
||||
HandleString filename, unsigned lineno, unsigned column,
|
||||
JSErrorReport *report, int exnType)
|
||||
{
|
||||
JS_ASSERT(exnObject->isError());
|
||||
JS_ASSERT(!exnObject->getPrivate());
|
||||
@ -326,6 +329,7 @@ InitExnPrivate(JSContext *cx, HandleObject exnObject, HandleString message,
|
||||
priv->message.init(message);
|
||||
priv->filename.init(filename);
|
||||
priv->lineno = lineno;
|
||||
priv->column = column;
|
||||
priv->stackDepth = frames.length();
|
||||
priv->exnType = exnType;
|
||||
for (size_t i = 0; i < frames.length(); ++i) {
|
||||
@ -436,7 +440,15 @@ exn_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
|
||||
atom = cx->runtime->atomState.lineNumberAtom;
|
||||
if (str == atom) {
|
||||
prop = js_lineNumber_str;
|
||||
v = INT_TO_JSVAL(priv->lineno);
|
||||
v = UINT_TO_JSVAL(priv->lineno);
|
||||
attrs = JSPROP_ENUMERATE;
|
||||
goto define;
|
||||
}
|
||||
|
||||
atom = cx->runtime->atomState.columnNumberAtom;
|
||||
if (str == atom) {
|
||||
prop = js_columnNumber_str;
|
||||
v = UINT_TO_JSVAL(priv->column);
|
||||
attrs = JSPROP_ENUMERATE;
|
||||
goto define;
|
||||
}
|
||||
@ -585,16 +597,16 @@ Exception(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
|
||||
/* Set the 'lineNumber' property. */
|
||||
uint32_t lineno;
|
||||
uint32_t lineno, column = 0;
|
||||
if (args.length() > 2) {
|
||||
if (!ToUint32(cx, args[2], &lineno))
|
||||
return false;
|
||||
} else {
|
||||
lineno = iter.done() ? 0 : PCToLineNumber(iter.script(), iter.pc());
|
||||
lineno = iter.done() ? 0 : PCToLineNumber(iter.script(), iter.pc(), &column);
|
||||
}
|
||||
|
||||
int exnType = args.callee().toFunction()->getExtendedSlot(0).toInt32();
|
||||
if (!InitExnPrivate(cx, obj, message, filename, lineno, NULL, exnType))
|
||||
if (!InitExnPrivate(cx, obj, message, filename, lineno, column, NULL, exnType))
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*obj);
|
||||
@ -791,6 +803,7 @@ InitErrorClass(JSContext *cx, Handle<GlobalObject*> global, int type, HandleObje
|
||||
RootedId messageId(cx, NameToId(cx->runtime->atomState.messageAtom));
|
||||
RootedId fileNameId(cx, NameToId(cx->runtime->atomState.fileNameAtom));
|
||||
RootedId lineNumberId(cx, NameToId(cx->runtime->atomState.lineNumberAtom));
|
||||
RootedId columnNumberId(cx, NameToId(cx->runtime->atomState.columnNumberAtom));
|
||||
if (!DefineNativeProperty(cx, errorProto, nameId, nameValue,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, 0, 0, 0) ||
|
||||
!DefineNativeProperty(cx, errorProto, messageId, empty,
|
||||
@ -798,6 +811,8 @@ InitErrorClass(JSContext *cx, Handle<GlobalObject*> global, int type, HandleObje
|
||||
!DefineNativeProperty(cx, errorProto, fileNameId, empty,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
|
||||
!DefineNativeProperty(cx, errorProto, lineNumberId, zeroValue,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
|
||||
!DefineNativeProperty(cx, errorProto, columnNumberId, zeroValue,
|
||||
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE, 0, 0))
|
||||
{
|
||||
return NULL;
|
||||
@ -988,7 +1003,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
|
||||
tv[3] = STRING_TO_JSVAL(filenameStr);
|
||||
|
||||
if (!InitExnPrivate(cx, errObject, messageStr, filenameStr,
|
||||
reportp->lineno, reportp, exn)) {
|
||||
reportp->lineno, reportp->column, reportp, exn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1108,11 +1123,19 @@ js_ReportUncaughtException(JSContext *cx)
|
||||
lineno = 0;
|
||||
}
|
||||
|
||||
uint32_t column;
|
||||
if (!JS_GetProperty(cx, exnObject, js_columnNumber_str, &roots[5]) ||
|
||||
!ToUint32(cx, roots[5], &column))
|
||||
{
|
||||
column = 0;
|
||||
}
|
||||
|
||||
reportp = &report;
|
||||
PodZero(&report);
|
||||
report.filename = filename.ptr();
|
||||
report.lineno = (unsigned) lineno;
|
||||
report.exnType = int16_t(JSEXN_NONE);
|
||||
report.column = (unsigned) column;
|
||||
if (str) {
|
||||
if (JSFixedString *fixed = str->ensureFixed(cx))
|
||||
report.ucmessage = fixed->chars();
|
||||
@ -1183,6 +1206,7 @@ js_CopyErrorObject(JSContext *cx, HandleObject errobj, HandleObject scope)
|
||||
return NULL;
|
||||
JS::Anchor<JSString *> filenameAnchor(copy->filename);
|
||||
copy->lineno = priv->lineno;
|
||||
copy->column = priv->column;
|
||||
copy->stackDepth = 0;
|
||||
copy->exnType = priv->exnType;
|
||||
|
||||
|
@ -1881,9 +1881,11 @@ js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
}
|
||||
|
||||
unsigned
|
||||
js::PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc)
|
||||
js::PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc,
|
||||
unsigned *columnp)
|
||||
{
|
||||
unsigned lineno = startLine;
|
||||
unsigned column = 0;
|
||||
|
||||
/*
|
||||
* Walk through source notes accumulating their deltas, keeping track of
|
||||
@ -1898,25 +1900,41 @@ js::PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbyt
|
||||
if (type == SRC_SETLINE) {
|
||||
if (offset <= target)
|
||||
lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
|
||||
column = 0;
|
||||
} else if (type == SRC_NEWLINE) {
|
||||
if (offset <= target)
|
||||
lineno++;
|
||||
column = 0;
|
||||
}
|
||||
|
||||
if (offset > target)
|
||||
break;
|
||||
|
||||
if (type == SRC_COLSPAN) {
|
||||
ptrdiff_t colspan = js_GetSrcNoteOffset(sn, 0);
|
||||
|
||||
if (colspan >= SN_COLSPAN_DOMAIN / 2)
|
||||
colspan -= SN_COLSPAN_DOMAIN;
|
||||
JS_ASSERT(ptrdiff_t(column) + colspan >= 0);
|
||||
column += colspan;
|
||||
}
|
||||
}
|
||||
|
||||
if (columnp)
|
||||
*columnp = column;
|
||||
|
||||
return lineno;
|
||||
}
|
||||
|
||||
unsigned
|
||||
js::PCToLineNumber(JSScript *script, jsbytecode *pc)
|
||||
js::PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp)
|
||||
{
|
||||
/* Cope with StackFrame.pc value prior to entering js_Interpret. */
|
||||
if (!pc)
|
||||
return 0;
|
||||
|
||||
return PCToLineNumber(script->lineno, script->notes(), script->code, pc);
|
||||
return PCToLineNumber(script->lineno, script->notes(), script->code, pc,
|
||||
columnp);
|
||||
}
|
||||
|
||||
/* The line number limit is the same as the jssrcnote offset limit. */
|
||||
|
@ -1180,10 +1180,11 @@ js_GetScriptLineExtent(JSScript *script);
|
||||
namespace js {
|
||||
|
||||
extern unsigned
|
||||
PCToLineNumber(JSScript *script, jsbytecode *pc);
|
||||
PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp = NULL);
|
||||
|
||||
extern unsigned
|
||||
PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc);
|
||||
PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc,
|
||||
unsigned *columnp = NULL);
|
||||
|
||||
extern unsigned
|
||||
CurrentLine(JSContext *cx);
|
||||
|
@ -1583,6 +1583,7 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp)
|
||||
"ofs", "line", "pc", "delta", "desc", "args");
|
||||
Sprint(sp, "---- ---- ----- ------ -------- ------\n");
|
||||
unsigned offset = 0;
|
||||
unsigned colspan = 0;
|
||||
unsigned lineno = script->lineno;
|
||||
jssrcnote *notes = script->notes();
|
||||
unsigned switchTableEnd = 0, switchTableStart = 0;
|
||||
@ -1598,6 +1599,12 @@ SrcNotes(JSContext *cx, JSScript *script, Sprinter *sp)
|
||||
}
|
||||
Sprint(sp, "%3u: %4u %5u [%4u] %-8s", unsigned(sn - notes), lineno, offset, delta, name);
|
||||
switch (type) {
|
||||
case SRC_COLSPAN:
|
||||
colspan = js_GetSrcNoteOffset(sn, 0);
|
||||
if (colspan >= SN_COLSPAN_DOMAIN / 2)
|
||||
colspan -= SN_COLSPAN_DOMAIN;
|
||||
Sprint(sp, "%d", colspan);
|
||||
break;
|
||||
case SRC_SETLINE:
|
||||
lineno = js_GetSrcNoteOffset(sn, 0);
|
||||
Sprint(sp, " lineno %u", lineno);
|
||||
@ -4290,7 +4297,7 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
|
||||
prefix = JS_smprintf("%s:", report->filename);
|
||||
if (report->lineno) {
|
||||
tmp = prefix;
|
||||
prefix = JS_smprintf("%s%u: ", tmp ? tmp : "", report->lineno);
|
||||
prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column);
|
||||
JS_free(cx, tmp);
|
||||
}
|
||||
if (JSREPORT_IS_WARNING(report->flags)) {
|
||||
|
73
js/src/tests/ecma/extensions/errorcolumnblame.js
Normal file
73
js/src/tests/ecma/extensions/errorcolumnblame.js
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var BUGNUMBER = 568142;
|
||||
var summary = 'error reporting blames column as well as line';
|
||||
|
||||
function test(f, col) {
|
||||
var caught = false;
|
||||
try {
|
||||
f();
|
||||
} catch (e) {
|
||||
caught = true;
|
||||
assertEq(e.columnNumber, col);
|
||||
}
|
||||
assertEq(caught, true);
|
||||
}
|
||||
|
||||
/* Note single hard tab before return! */
|
||||
function foo(o) {
|
||||
return o.p;
|
||||
}
|
||||
test(foo, 1);
|
||||
|
||||
//234567890123456789
|
||||
test(function(f) { return f.bar; }, 19);
|
||||
test(function(f) { return f(); }, 19);
|
||||
/* Cover negative colspan case using for(;;) loop with error in update part. */
|
||||
test(function(){
|
||||
//0 1 2 3 4
|
||||
//012345678901234567890123456789012345678901
|
||||
eval("function baz() { for (var i = 0; i < 10; i += a.b); assertEq(i !== i, true); }");
|
||||
baz();
|
||||
}, 41);
|
||||
|
||||
// 1 2 3
|
||||
//234567890123456789012345678901234
|
||||
test(function() { var tmp = null; tmp(); }, 34)
|
||||
test(function() { var tmp = null; tmp.foo; }, 35)
|
||||
|
||||
/* Just a generic 'throw'. */
|
||||
test(function() {
|
||||
//234567890123
|
||||
foo({}); throw new Error('a');
|
||||
}, 13);
|
||||
|
||||
/* Be sure to report the right statement */
|
||||
test(function() {
|
||||
function f() { return true; }
|
||||
function g() { return false; }
|
||||
//234567890123456789012345678
|
||||
f(); g(); f(); if (f()) a += e;
|
||||
}, 28);
|
||||
|
||||
//2345678901234567890
|
||||
test(function() { e++; }, 18);
|
||||
test(function() {print += e; }, 17);
|
||||
test(function(){e += 1 }, 16);
|
||||
test(function() { print[e]; }, 19);
|
||||
test(function() { e[1]; }, 18);
|
||||
test(function() { e(); }, 18);
|
||||
test(function() { 1(); }, 18);
|
||||
test(function() { Object.defineProperty() }, 18);
|
||||
|
||||
test(function() {
|
||||
//23456789012345678901
|
||||
function foo() { asdf; } foo()
|
||||
}, 21);
|
||||
|
||||
reportCompare(0, 0, "ok");
|
||||
|
||||
printStatus("All tests passed!");
|
Loading…
Reference in New Issue
Block a user