Bug 1263881 - Check the the number of body level lexicals doesn't exceed that which we can store in Bindings r=shu
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 13 Apr 2016 14:06:21 +0100
changeset 330896 009ffacae51adc5d234a7fdde48c82970de097f8
parent 330895 a5d85a401db37ce21888bd641f78dc3d3007ca1c
child 330897 18e8a39074a8b35de64b4b1a8f403f6e1883dc59
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu
bugs1263881
milestone48.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 1263881 - Check the the number of body level lexicals doesn't exceed that which we can store in Bindings r=shu
js/src/devtools/automation/cgc-jittest-timeouts.txt
js/src/frontend/Parser.cpp
js/src/jit-test/tests/parser/bug-1263881-1.js
js/src/jit-test/tests/parser/bug-1263881-2.js
js/src/jit-test/tests/parser/bug-1263881-3.js
js/src/jsscript.h
js/src/vm/ScopeObject.h
--- a/js/src/devtools/automation/cgc-jittest-timeouts.txt
+++ b/js/src/devtools/automation/cgc-jittest-timeouts.txt
@@ -18,15 +18,18 @@ debug/DebuggeeWouldRun-02.js
 gc/bug-1014972.js
 gc/bug-1246593.js
 gc/bug-906236.js
 gc/bug-906241.js
 ion/bug787921.js
 ion/bug977966.js
 parallel/alloc-many-objs.js
 parallel/alloc-too-many-objs.js
+parser/bug-1263881-1.js
+parser/bug-1263881-2.js
+parser/bug-1263881-3.js
 saved-stacks/bug-1006876-too-much-recursion.js
 self-test/assertDeepEq.js
 sunspider/check-string-unpack-code.js
 v8-v5/check-earley-boyer.js
 v8-v5/check-raytrace.js
 v8-v5/check-regexp.js
 v8-v5/check-splay.js
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -89,17 +89,19 @@ typedef Handle<NestedStaticScope*> Handl
     JS_END_MACRO
 
 #define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errno)
 
 template <>
 bool
 ParseContext<FullParseHandler>::checkLocalsOverflow(TokenStream& ts)
 {
-    if (vars_.length() + bodyLevelLexicals_.length() >= LOCALNO_LIMIT) {
+    if (vars_.length() + bodyLevelLexicals_.length() >= LOCALNO_LIMIT ||
+        bodyLevelLexicals_.length() >= Bindings::BODY_LEVEL_LEXICAL_LIMIT)
+    {
         ts.reportError(JSMSG_TOO_MANY_LOCALS);
         return false;
     }
     return true;
 }
 
 static void
 MarkUsesAsHoistedLexical(ParseNode* pn)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parser/bug-1263881-1.js
@@ -0,0 +1,11 @@
+// |jit-test| error: SyntaxError
+let moduleRepo = {};
+setModuleResolveHook(function(module, specifier) {
+        return moduleRepo[specifier];
+});
+moduleRepo['a'] = parseModule("export let a = 1;");
+let s = "";
+let max = 65536;
+for (let i = 0; i < max; i++)
+  s += "import * as ns" + i + " from 'a';\n";
+parseModule(s);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parser/bug-1263881-2.js
@@ -0,0 +1,6 @@
+// |jit-test| error: SyntaxError
+let s = "";
+let max = 65536;
+for (let i = 0; i < max; i++)
+  s += "let ns" + i + " = "+ i +";\n";
+eval(s);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parser/bug-1263881-3.js
@@ -0,0 +1,7 @@
+// |jit-test| error: SyntaxError
+let s = "function foo() {\n";
+let max = 65536;
+for (let i = 0; i < max; i++)
+  s += "let ns" + i + " = "+ i +";\n";
+s += "};";
+eval(s);
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -249,16 +249,17 @@ class Bindings
      * bindingArrayAndFlag_.
      */
     static const uintptr_t TEMPORARY_STORAGE_BIT = 0x1;
     bool bindingArrayUsingTemporaryStorage() const {
         return bindingArrayAndFlag_ & TEMPORARY_STORAGE_BIT;
     }
 
   public:
+    static const uint32_t BODY_LEVEL_LEXICAL_LIMIT = UINT16_LIMIT;
 
     Binding* bindingArray() const {
         return reinterpret_cast<Binding*>(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT);
     }
 
     Bindings()
       : callObjShape_(nullptr), bindingArrayAndFlag_(TEMPORARY_STORAGE_BIT),
         numArgs_(0), numBlockScoped_(0),
@@ -429,22 +430,36 @@ class MutableBindingsOperations : public
 {
     Bindings& bindings() { return static_cast<Outer*>(this)->get(); }
 
   public:
     void setCallObjShape(HandleShape shape) { bindings().callObjShape_ = shape; }
     void setBindingArray(const Binding* bindingArray, uintptr_t temporaryBit) {
         bindings().bindingArrayAndFlag_ = uintptr_t(bindingArray) | temporaryBit;
     }
-    void setNumArgs(uint16_t num) { bindings().numArgs_ = num; }
-    void setNumVars(uint32_t num) { bindings().numVars_ = num; }
-    void setNumBodyLevelLexicals(uint16_t num) { bindings().numBodyLevelLexicals_ = num; }
-    void setNumBlockScoped(uint16_t num) { bindings().numBlockScoped_ = num; }
-    void setNumUnaliasedVars(uint32_t num) { bindings().numUnaliasedVars_ = num; }
-    void setNumUnaliasedBodyLevelLexicals(uint16_t num) {
+    void setNumArgs(uint32_t num) {
+        MOZ_ASSERT(num <= UINT16_MAX);
+        bindings().numArgs_ = num;
+    }
+    void setNumVars(uint32_t num) {
+        bindings().numVars_ = num;
+    }
+    void setNumBodyLevelLexicals(uint32_t num) {
+        MOZ_ASSERT(num <= UINT16_MAX);
+        bindings().numBodyLevelLexicals_ = num;
+    }
+    void setNumBlockScoped(uint32_t num) {
+        MOZ_ASSERT(num <= UINT16_MAX);
+        bindings().numBlockScoped_ = num;
+    }
+    void setNumUnaliasedVars(uint32_t num) {
+        bindings().numUnaliasedVars_ = num;
+    }
+    void setNumUnaliasedBodyLevelLexicals(uint32_t num) {
+        MOZ_ASSERT(num <= UINT16_MAX);
         bindings().numUnaliasedBodyLevelLexicals_ = num;
     }
     void setAliasedBodyLevelLexicalBegin(uint32_t offset) {
         bindings().aliasedBodyLevelLexicalBegin_ = offset;
     }
     uint8_t* switchToScriptStorage(Binding* permanentStorage) {
         return bindings().switchToScriptStorage(permanentStorage);
     }
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -136,18 +136,20 @@ class StaticBlockScope : public NestedSt
     static const uint32_t BlockFlagsMask = 0x1;
     static const uint32_t IsForCatchParametersFlag = 0x1;
 
   public:
     static const unsigned RESERVED_SLOTS = LOCAL_OFFSET_AND_FLAGS_SLOT + 1;
 
     /* Return the number of variables associated with this block. */
     uint32_t numVariables() const {
-        // TODO: propertyCount() is O(n), use O(1) lastProperty()->slot() instead
-        return propertyCount();
+        uint32_t num = 0;
+        if (!lastProperty()->isEmptyShape())
+            num = lastProperty()->slot() + 1 - RESERVED_SLOTS;
+        return num;
     }
 
   private:
     /*
      * Even static blocks contain an object slot for each binding i,
      * 0 <= i < slotCount.
      */
     const Value& slotValue(unsigned i) {