Bug 674283 - Add source map urls to JSScript. r=jorendorff.

This commit is contained in:
Nick Fitzgerald 2011-07-29 10:44:45 -05:00
parent 303c5e0ae1
commit 9098b89abc
7 changed files with 105 additions and 13 deletions

View File

@ -16,7 +16,18 @@ try { \n\
catch (e) \n\
{ \n\
xx += 1; \n\
}";
}\n\
//@sourceMappingURL=http://example.com/path/to/source-map.json";
static bool
CharsMatch(const jschar *p, const char *q) {
while (*q) {
if (*p++ != *q++)
return false;
}
return true;
}
// Bug 670958 - fix JS_GetScriptLineExtent, among others
BEGIN_TEST(testScriptInfo)
@ -34,7 +45,8 @@ BEGIN_TEST(testScriptInfo)
CHECK_EQUAL(JS_PCToLineNumber(cx, script, start), startLine);
CHECK_EQUAL(JS_GetScriptLineExtent(cx, script), 10);
CHECK(strcmp(JS_GetScriptFilename(cx, script), __FILE__) == 0);
CHECK(CharsMatch(JS_GetScriptSourceMap(cx, script), "http://example.com/path/to/source-map.json"));
return true;
}
END_TEST(testScriptInfo)

View File

@ -23,6 +23,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Nick Fitzgerald <nfitzgerald@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -422,7 +423,7 @@ JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
JSTrapHandler *handlerp, jsval *closurep)
{
JSTrap *trap;
DBG_LOCK(cx->runtime);
trap = FindTrap(cx->runtime, script, pc);
if (handlerp)
@ -1045,6 +1046,12 @@ JS_GetScriptFilename(JSContext *cx, JSScript *script)
return script->filename;
}
JS_PUBLIC_API(const jschar *)
JS_GetScriptSourceMap(JSContext *cx, JSScript *script)
{
return script->sourceMap;
}
JS_PUBLIC_API(uintN)
JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
{
@ -1131,7 +1138,7 @@ JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
jschar *chars;
JSBool ok;
size_t len = length;
if (!CheckDebugMode(cx))
return JS_FALSE;

View File

@ -23,6 +23,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Nick Fitzgerald <nfitzgerald@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -349,6 +350,9 @@ JS_GetValidFrameCalleeObject(JSContext *cx, JSStackFrame *fp, jsval *vp);
extern JS_PUBLIC_API(const char *)
JS_GetScriptFilename(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(const jschar *)
JS_GetScriptSourceMap(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(uintN)
JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script);

View File

@ -23,6 +23,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Nick Fitzgerald <nfitzgerald@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -179,6 +180,7 @@ TokenStream::init(const jschar *base, size_t length, const char *fn, uintN ln, J
userbuf.init(base, length);
linebase = base;
prevLinebase = NULL;
sourceMap = NULL;
JSSourceHandler listener = cx->debugHooks->sourceHandler;
void *listenerData = cx->debugHooks->sourceHandlerData;
@ -247,6 +249,8 @@ TokenStream::~TokenStream()
{
if (flags & TSF_OWNFILENAME)
cx->free_((void *) filename);
if (sourceMap)
cx->free_(sourceMap);
}
/* Use the fastest available getc. */
@ -1132,6 +1136,19 @@ TokenStream::matchUnicodeEscapeIdent(int32 *cp)
return false;
}
/*
* Helper function which returns true if the first length(q) characters in p are
* the same as the characters in q.
*/
static bool
CharsMatch(const jschar *p, const char *q) {
while (*q) {
if (*p++ != *q++)
return false;
}
return true;
}
bool
TokenStream::getAtLine()
{
@ -1145,12 +1162,7 @@ TokenStream::getAtLine()
* "//@line 123\n" sets the number of the *next* line after the
* comment to 123. If we reach here, we've already seen "//".
*/
if (peekChars(5, cp) &&
cp[0] == '@' &&
cp[1] == 'l' &&
cp[2] == 'i' &&
cp[3] == 'n' &&
cp[4] == 'e') {
if (peekChars(5, cp) && CharsMatch(cp, "@line")) {
skipChars(5);
while ((c = getChar()) != '\n' && c != EOF && IsSpaceOrBOM2(c))
continue;
@ -1200,6 +1212,42 @@ TokenStream::getAtLine()
return true;
}
bool
TokenStream::getAtSourceMappingURL()
{
jschar peeked[18];
/* Match comments of the form @sourceMappingURL=<url> */
if (peekChars(18, peeked) && CharsMatch(peeked, "@sourceMappingURL=")) {
skipChars(18);
tokenbuf.clear();
jschar c;
while (!IsSpaceOrBOM2((c = getChar())) &&
((char) c) != '\0' &&
((char) c) != EOF)
tokenbuf.append(c);
if (tokenbuf.empty())
/* The source map's URL was missing, but not quite an exception that
* we should stop and drop everything for, though. */
return true;
int len = tokenbuf.length();
if (sourceMap)
cx->free_(sourceMap);
sourceMap = (jschar *) cx->malloc_(sizeof(jschar) * (len + 1));
if (!sourceMap)
return false;
for (int i = 0; i < len; i++)
sourceMap[i] = tokenbuf[i];
sourceMap[len] = '\0';
}
return true;
}
Token *
TokenStream::newToken(ptrdiff_t adjust)
{
@ -1254,7 +1302,7 @@ bool
TokenStream::putIdentInTokenbuf(const jschar *identStart)
{
int32 c, qc;
const jschar *tmp = userbuf.addressOfNextRawChar();
const jschar *tmp = userbuf.addressOfNextRawChar();
userbuf.setAddressOfNextRawChar(identStart);
tokenbuf.clear();
@ -1483,7 +1531,7 @@ TokenStream::getTokenInternal()
}
}
/*
/*
* Identifiers containing no Unicode escapes can be atomized directly
* from userbuf. The rest must have the escapes converted via
* tokenbuf before atomizing.
@ -1681,7 +1729,7 @@ TokenStream::getTokenInternal()
goto error;
}
/*
/*
* Unlike identifiers and strings, numbers cannot contain escaped
* chars, so we don't need to use tokenbuf. Instead we can just
* convert the jschars in userbuf directly to the numeric value.
@ -1899,6 +1947,9 @@ TokenStream::getTokenInternal()
if (cx->hasAtLineOption() && !getAtLine())
goto error;
if (!getAtSourceMappingURL())
goto error;
skipline:
/* Optimize line skipping if we are not in an HTML comment. */
if (flags & TSF_IN_HTML_COMMENT) {

View File

@ -22,6 +22,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Nick Fitzgerald <nfitzgerald@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -485,6 +486,14 @@ class TokenStream
return matchToken(tt);
}
/*
* Give up responsibility for managing the sourceMap filename's memory.
*/
const jschar *releaseSourceMap() {
const jschar* sm = sourceMap;
sourceMap = NULL;
return sm;
}
private:
/*
@ -589,6 +598,7 @@ class TokenStream
bool matchUnicodeEscapeIdent(int32 *c);
bool peekChars(intN n, jschar *cp);
bool getAtLine();
bool getAtSourceMappingURL();
bool getXMLEntity();
bool getXMLTextOrTag(TokenKind *ttp, Token **tpp);
@ -626,6 +636,7 @@ class TokenStream
const jschar *prevLinebase; /* start of previous line; NULL if on the first line */
TokenBuf userbuf; /* user input buffer */
const char *filename; /* input filename or null */
jschar *sourceMap; /* source map's filename or null */
void *listenerTSData;/* listener data for this TokenStream */
CharBuffer tokenbuf; /* current token string buffer */
int8 oneCharTokens[128]; /* table of one-char tokens */

View File

@ -23,6 +23,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Nick Fitzgerald <nfitzgerald@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -1190,6 +1191,8 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
if (script->principals)
JSPRINCIPALS_HOLD(cx, script->principals);
script->sourceMap = (jschar *) cg->parser->tokenStream.releaseSourceMap();
if (!js_FinishTakingSrcNotes(cx, cg, script->notes()))
goto bad;
if (cg->ntrynotes != 0)
@ -1402,6 +1405,9 @@ DestroyScript(JSContext *cx, JSScript *script, JSObject *owner)
script->pcCounters.destroy(cx);
if (script->sourceMap)
cx->free_(script->sourceMap);
memset(script, JS_FREE_PATTERN, script->totalSize());
cx->free_(script);
}

View File

@ -505,6 +505,7 @@ struct JSScript {
js::Bindings bindings; /* names of top-level variables in this script
(and arguments if this is a function script) */
JSPrincipals *principals;/* principals for this script */
jschar *sourceMap; /* source map file or null */
JSObject *ownerObject;