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
Родитель 4bd2484a4e
Коммит 9d7d97c0a9
7 изменённых файлов: 105 добавлений и 13 удалений

Просмотреть файл

@ -16,7 +16,18 @@ try { \n\
catch (e) \n\ catch (e) \n\
{ \n\ { \n\
xx += 1; \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 // Bug 670958 - fix JS_GetScriptLineExtent, among others
BEGIN_TEST(testScriptInfo) BEGIN_TEST(testScriptInfo)
@ -34,7 +45,8 @@ BEGIN_TEST(testScriptInfo)
CHECK_EQUAL(JS_PCToLineNumber(cx, script, start), startLine); CHECK_EQUAL(JS_PCToLineNumber(cx, script, start), startLine);
CHECK_EQUAL(JS_GetScriptLineExtent(cx, script), 10); CHECK_EQUAL(JS_GetScriptLineExtent(cx, script), 10);
CHECK(strcmp(JS_GetScriptFilename(cx, script), __FILE__) == 0); CHECK(strcmp(JS_GetScriptFilename(cx, script), __FILE__) == 0);
CHECK(CharsMatch(JS_GetScriptSourceMap(cx, script), "http://example.com/path/to/source-map.json"));
return true; return true;
} }
END_TEST(testScriptInfo) END_TEST(testScriptInfo)

Просмотреть файл

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

Просмотреть файл

@ -23,6 +23,7 @@
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Nick Fitzgerald <nfitzgerald@mozilla.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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"), * 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 *) extern JS_PUBLIC_API(const char *)
JS_GetScriptFilename(JSContext *cx, JSScript *script); JS_GetScriptFilename(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(const jschar *)
JS_GetScriptSourceMap(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(uintN) extern JS_PUBLIC_API(uintN)
JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script); JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script);

Просмотреть файл

@ -23,6 +23,7 @@
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Nick Fitzgerald <nfitzgerald@mozilla.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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"), * 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); userbuf.init(base, length);
linebase = base; linebase = base;
prevLinebase = NULL; prevLinebase = NULL;
sourceMap = NULL;
JSSourceHandler listener = cx->debugHooks->sourceHandler; JSSourceHandler listener = cx->debugHooks->sourceHandler;
void *listenerData = cx->debugHooks->sourceHandlerData; void *listenerData = cx->debugHooks->sourceHandlerData;
@ -247,6 +249,8 @@ TokenStream::~TokenStream()
{ {
if (flags & TSF_OWNFILENAME) if (flags & TSF_OWNFILENAME)
cx->free_((void *) filename); cx->free_((void *) filename);
if (sourceMap)
cx->free_(sourceMap);
} }
/* Use the fastest available getc. */ /* Use the fastest available getc. */
@ -1132,6 +1136,19 @@ TokenStream::matchUnicodeEscapeIdent(int32 *cp)
return false; 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 bool
TokenStream::getAtLine() TokenStream::getAtLine()
{ {
@ -1145,12 +1162,7 @@ TokenStream::getAtLine()
* "//@line 123\n" sets the number of the *next* line after the * "//@line 123\n" sets the number of the *next* line after the
* comment to 123. If we reach here, we've already seen "//". * comment to 123. If we reach here, we've already seen "//".
*/ */
if (peekChars(5, cp) && if (peekChars(5, cp) && CharsMatch(cp, "@line")) {
cp[0] == '@' &&
cp[1] == 'l' &&
cp[2] == 'i' &&
cp[3] == 'n' &&
cp[4] == 'e') {
skipChars(5); skipChars(5);
while ((c = getChar()) != '\n' && c != EOF && IsSpaceOrBOM2(c)) while ((c = getChar()) != '\n' && c != EOF && IsSpaceOrBOM2(c))
continue; continue;
@ -1200,6 +1212,42 @@ TokenStream::getAtLine()
return true; 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 * Token *
TokenStream::newToken(ptrdiff_t adjust) TokenStream::newToken(ptrdiff_t adjust)
{ {
@ -1254,7 +1302,7 @@ bool
TokenStream::putIdentInTokenbuf(const jschar *identStart) TokenStream::putIdentInTokenbuf(const jschar *identStart)
{ {
int32 c, qc; int32 c, qc;
const jschar *tmp = userbuf.addressOfNextRawChar(); const jschar *tmp = userbuf.addressOfNextRawChar();
userbuf.setAddressOfNextRawChar(identStart); userbuf.setAddressOfNextRawChar(identStart);
tokenbuf.clear(); tokenbuf.clear();
@ -1483,7 +1531,7 @@ TokenStream::getTokenInternal()
} }
} }
/* /*
* Identifiers containing no Unicode escapes can be atomized directly * Identifiers containing no Unicode escapes can be atomized directly
* from userbuf. The rest must have the escapes converted via * from userbuf. The rest must have the escapes converted via
* tokenbuf before atomizing. * tokenbuf before atomizing.
@ -1681,7 +1729,7 @@ TokenStream::getTokenInternal()
goto error; goto error;
} }
/* /*
* Unlike identifiers and strings, numbers cannot contain escaped * Unlike identifiers and strings, numbers cannot contain escaped
* chars, so we don't need to use tokenbuf. Instead we can just * chars, so we don't need to use tokenbuf. Instead we can just
* convert the jschars in userbuf directly to the numeric value. * convert the jschars in userbuf directly to the numeric value.
@ -1899,6 +1947,9 @@ TokenStream::getTokenInternal()
if (cx->hasAtLineOption() && !getAtLine()) if (cx->hasAtLineOption() && !getAtLine())
goto error; goto error;
if (!getAtSourceMappingURL())
goto error;
skipline: skipline:
/* Optimize line skipping if we are not in an HTML comment. */ /* Optimize line skipping if we are not in an HTML comment. */
if (flags & TSF_IN_HTML_COMMENT) { if (flags & TSF_IN_HTML_COMMENT) {

Просмотреть файл

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

Просмотреть файл

@ -23,6 +23,7 @@
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Nick Fitzgerald <nfitzgerald@mozilla.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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"), * 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) if (script->principals)
JSPRINCIPALS_HOLD(cx, script->principals); JSPRINCIPALS_HOLD(cx, script->principals);
script->sourceMap = (jschar *) cg->parser->tokenStream.releaseSourceMap();
if (!js_FinishTakingSrcNotes(cx, cg, script->notes())) if (!js_FinishTakingSrcNotes(cx, cg, script->notes()))
goto bad; goto bad;
if (cg->ntrynotes != 0) if (cg->ntrynotes != 0)
@ -1402,6 +1405,9 @@ DestroyScript(JSContext *cx, JSScript *script, JSObject *owner)
script->pcCounters.destroy(cx); script->pcCounters.destroy(cx);
if (script->sourceMap)
cx->free_(script->sourceMap);
memset(script, JS_FREE_PATTERN, script->totalSize()); memset(script, JS_FREE_PATTERN, script->totalSize());
cx->free_(script); cx->free_(script);
} }

Просмотреть файл

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