Bug 1161312 - De-offset ScriptSource offsets from starting column in JSScript and LazyScript. (r=jimb)
authorShu-yu Guo <shu@rfrn.org>
Fri, 05 May 2017 13:01:02 -0700
changeset 356908 041899558dd5c8c1ff7abe7fd393bda48c3f323a
parent 356907 dd650c37854b8944953d9b4bbf9ece2f23bdf410
child 356909 0ad1250ede3a5f0d419bcd584945a6669fed9754
push id31776
push userihsiao@mozilla.com
push dateMon, 08 May 2017 03:11:58 +0000
treeherdermozilla-central@c3e5497cff1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs1161312
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1161312 - De-offset ScriptSource offsets from starting column in JSScript and LazyScript. (r=jimb) The JS shell, for testing purposes, allows passing in an OOB column number, which offsets all token positions by column. These positions need to be de-offset before being saved as offsets into the ScriptSource buffer in the script structures.
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SharedContext.h
js/src/jit-test/tests/parser/bug-1161312.js
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -676,18 +676,18 @@ frontend::CompileLazyFunction(JSContext*
     Parser<FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(), options, chars, length,
                                               /* foldConstants = */ true, usedNames, nullptr,
                                               lazy);
     if (!parser.checkOptions())
         return false;
 
     Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
     MOZ_ASSERT(!lazy->isLegacyGenerator());
-    ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind(),
-                                                  lazy->asyncKind());
+    ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->toStringStart() + lazy->column(),
+                                                  lazy->strict(), lazy->generatorKind(), lazy->asyncKind());
     if (!pn)
         return false;
 
     RootedScriptSource sourceObject(cx, lazy->sourceObject());
     MOZ_ASSERT(sourceObject);
 
     Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
                                                   lazy->begin(), lazy->end(),
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -3568,29 +3568,31 @@ Parser<ParseHandler, CharT>::appendToCal
         return false;
 
     handler.addToCallSiteObject(callSiteObj, rawNode, cookedNode);
     return true;
 }
 
 template <>
 ParseNode*
-Parser<FullParseHandler, char16_t>::standaloneLazyFunction(HandleFunction fun, bool strict,
+Parser<FullParseHandler, char16_t>::standaloneLazyFunction(HandleFunction fun,
+                                                           uint32_t toStringStart,
+                                                           bool strict,
                                                            GeneratorKind generatorKind,
                                                            FunctionAsyncKind asyncKind)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     Node pn = handler.newFunctionStatement(pos());
     if (!pn)
         return null();
 
     Directives directives(strict);
-    FunctionBox* funbox = newFunctionBox(pn, fun, /* toStringStart = */ 0, directives,
-                                         generatorKind, asyncKind, /* tryAnnexB = */ false);
+    FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, directives, generatorKind,
+                                         asyncKind, /* tryAnnexB = */ false);
     if (!funbox)
         return null();
     funbox->initFromLazyFunction();
 
     Directives newDirectives = directives;
     ParseContext funpc(this, funbox, &newDirectives);
     if (!funpc.init())
         return null();
@@ -3754,24 +3756,24 @@ Parser<ParseHandler, CharT>::functionFor
         if (!checkBindingIdentifier(propertyName, nameOffset, nameYieldHandling))
             return false;
     }
 
     if (bodyType == StatementListBody) {
         MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
                                          reportMissingClosing(JSMSG_CURLY_AFTER_BODY,
                                                               JSMSG_CURLY_OPENED, openedPos));
-        funbox->setEnd(pos().end);
+        funbox->setEnd(tokenStream);
     } else {
 #if !JS_HAS_EXPR_CLOSURES
         MOZ_ASSERT(kind == Arrow);
 #endif
         if (tokenStream.hadError())
             return false;
-        funbox->setEnd(pos().end);
+        funbox->setEnd(tokenStream);
         if (kind == Statement && !matchOrInsertSemicolonAfterExpression())
             return false;
     }
 
     if (IsMethodDefinitionKind(kind) && pc->superScopeNeedsHomeObject())
         funbox->setNeedsHomeObject();
 
     if (!finishFunction(isStandaloneFunction))
@@ -8624,17 +8626,17 @@ Parser<ParseHandler, CharT>::generatorCo
     if (!comp)
         return null();
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
 
     uint32_t end = pos().end;
     handler.setBeginPosition(comp, begin);
     handler.setEndPosition(comp, end);
-    genFunbox->setEnd(end);
+    genFunbox->setEnd(tokenStream);
     handler.addStatementToList(body, comp);
     handler.setEndPosition(body, end);
     handler.setBeginPosition(genfn, begin);
     handler.setEndPosition(genfn, end);
 
     Node generator = newDotGeneratorName();
     if (!generator)
         return null();
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1180,17 +1180,17 @@ class Parser final : public ParserBase, 
     // AsyncFunction constructors.
     Node standaloneFunction(HandleFunction fun, HandleScope enclosingScope,
                             const mozilla::Maybe<uint32_t>& parameterListEnd,
                             GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
                             Directives inheritedDirectives, Directives* newDirectives);
 
     // Parse a function, given only its arguments and body. Used for lazily
     // parsed functions.
-    Node standaloneLazyFunction(HandleFunction fun, bool strict,
+    Node standaloneLazyFunction(HandleFunction fun, uint32_t toStringStart, bool strict,
                                 GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
 
     // Parse an inner function given an enclosing ParseContext and a
     // FunctionBox for the inner function.
     bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t toStringStart,
                        InHandling inHandling, YieldHandling yieldHandling,
                        FunctionSyntaxKind kind,
                        Directives inheritedDirectives, Directives* newDirectives);
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -556,26 +556,38 @@ class FunctionBox : public ObjectBox, pu
     // while the function is being reparsed. This flag can be used to disable
     // certain parsing features that are necessary in general, but unnecessary
     // for validated asm.js.
     bool useAsmOrInsideUseAsm() const {
         return useAsm || insideUseAsm;
     }
 
     void setStart(const TokenStream& tokenStream) {
-        bufStart = tokenStream.currentToken().pos.begin;
-        tokenStream.srcCoords.lineNumAndColumnIndex(bufStart, &startLine, &startColumn);
+        // Token positions are already offset from the start column in
+        // CompileOptions. bufStart and toStringStart, however, refer to
+        // absolute positions within the ScriptSource buffer, and need to
+        // de-offset from the starting column.
+        uint32_t offset = tokenStream.currentToken().pos.begin;
+        MOZ_ASSERT(offset >= tokenStream.options().column);
+        MOZ_ASSERT(toStringStart >= tokenStream.options().column);
+        toStringStart -= tokenStream.options().column;
+        bufStart = offset - tokenStream.options().column;
+        tokenStream.srcCoords.lineNumAndColumnIndex(offset, &startLine, &startColumn);
     }
 
-    void setEnd(uint32_t end) {
+    void setEnd(const TokenStream& tokenStream) {
         // For all functions except class constructors, the buffer and
         // toString ending positions are the same. Class constructors override
         // the toString ending position with the end of the class definition.
-        bufEnd = end;
-        toStringEnd = end;
+        //
+        // Offsets are de-offset for the same reason as in setStart above.
+        uint32_t offset = tokenStream.currentToken().pos.end;
+        MOZ_ASSERT(offset >= tokenStream.options().column);
+        bufEnd = offset - tokenStream.options().column;
+        toStringEnd = bufEnd;
     }
 
     void trace(JSTracer* trc) override;
 };
 
 inline FunctionBox*
 SharedContext::asFunctionBox()
 {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parser/bug-1161312.js
@@ -0,0 +1,3 @@
+// Test that lazy scripts can handle OOB column numbers.
+
+assertEq(evaluate(`var f = x=>saveStack().column; f()`, { columnNumber: 1729 }), 1741);