[es6] super.prop, eval and lazy functions
authorarv <arv@chromium.org>
Thu, 4 Jun 2015 21:16:18 +0000 (14:16 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 4 Jun 2015 21:16:32 +0000 (21:16 +0000)
We used to only store the uses_super_property in the preparse data
logger. Let the logger use NeedsHomeObject instead.

BUG=v8:3768
LOG=N
R=wingo, adamk

Review URL: https://codereview.chromium.org/1164073003

Cr-Commit-Position: refs/heads/master@{#28806}

18 files changed:
src/ast.cc
src/ast.h
src/compiler/ast-graph-builder.cc
src/hydrogen.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/parser.cc
src/parser.h
src/preparse-data-format.h
src/preparse-data.h
src/preparser.cc
src/preparser.h
src/scopes.h
test/cctest/test-parsing.cc
test/mjsunit/harmony/classes-lazy-parsing.js
test/mjsunit/harmony/object-literals-super.js
test/mjsunit/harmony/super.js

index fbefbd46f960ce347d56b8129a0e83de5b8c3843..5141a382f00100ec8dd3ab4f883fcae53a90e3ef 100644 (file)
@@ -234,9 +234,10 @@ LanguageMode FunctionLiteral::language_mode() const {
 }
 
 
-bool FunctionLiteral::uses_super_property() const {
-  DCHECK_NOT_NULL(scope());
-  return scope()->uses_super_property();
+bool FunctionLiteral::NeedsHomeObject(Expression* expr) {
+  if (expr == nullptr || !expr->IsFunctionLiteral()) return false;
+  DCHECK_NOT_NULL(expr->AsFunctionLiteral()->scope());
+  return expr->AsFunctionLiteral()->scope()->NeedsHomeObject();
 }
 
 
index 675daa127e12f53d33ab482e259cd02d7d6f35c8..616ac5a8cb98e88307b9104c768e769e971cbdf4 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -2518,12 +2518,8 @@ class FunctionLiteral final : public Expression {
   bool is_expression() const { return IsExpression::decode(bitfield_); }
   bool is_anonymous() const { return IsAnonymous::decode(bitfield_); }
   LanguageMode language_mode() const;
-  bool uses_super_property() const;
 
-  static bool NeedsHomeObject(Expression* literal) {
-    return literal != NULL && literal->IsFunctionLiteral() &&
-           literal->AsFunctionLiteral()->uses_super_property();
-  }
+  static bool NeedsHomeObject(Expression* expr);
 
   int materialized_literal_count() { return materialized_literal_count_; }
   int expected_property_count() { return expected_property_count_; }
@@ -2602,7 +2598,7 @@ class FunctionLiteral final : public Expression {
     bitfield_ = ShouldBeUsedOnceHintBit::update(bitfield_, kShouldBeUsedOnce);
   }
 
-  FunctionKind kind() { return FunctionKindBits::decode(bitfield_); }
+  FunctionKind kind() const { return FunctionKindBits::decode(bitfield_); }
 
   int ast_node_count() { return ast_properties_.node_count(); }
   AstProperties::Flags* flags() { return ast_properties_.flags(); }
index d1103d7c907b662d0092f98d9fcb80bde29ebdad..a200c701935333f40953e1728b4835205054b48d 100644 (file)
@@ -563,6 +563,11 @@ void AstGraphBuilder::CreateGraphBody(bool stack_check) {
   Variable* rest_parameter = scope->rest_parameter(&rest_index);
   BuildRestArgumentsArray(rest_parameter, rest_index);
 
+  if (scope->this_function_var() != nullptr ||
+      scope->new_target_var() != nullptr) {
+    SetStackOverflow();
+  }
+
   // Emit tracing call if requested to do so.
   if (FLAG_trace) {
     NewNode(javascript()->CallRuntime(Runtime::kTraceEnter, 0));
index 40022a153a760071f3cc4646d1748305a72f152c..9bbafb224977b436edc15841689f0331d908c196 100644 (file)
@@ -4513,6 +4513,11 @@ void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
   if (rest) {
     return Bailout(kRestParameter);
   }
+
+  if (scope->this_function_var() != nullptr ||
+      scope->new_target_var() != nullptr) {
+    return Bailout(kSuperReference);
+  }
 }
 
 
index 6b18ed2c3eb9461fc5ad4bbefba73ff081592a55..700ae041cea4708833a419ec159145b042dd7ef2 100644 (file)
@@ -5410,8 +5410,8 @@ void SharedFunctionInfo::set_kind(FunctionKind kind) {
 }
 
 
-BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, uses_super_property,
-               kUsesSuperProperty)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, needs_home_object,
+               kNeedsHomeObject)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, force_inline, kForceInline)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints,
index 536534713035786f8fdf6bd283dd566261e09e52..126ca1bdc5dd5fa75880548d64ea0249f5e29e3a 100644 (file)
@@ -10580,7 +10580,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
   shared_info->set_dont_cache(
       lit->flags()->Contains(AstPropertiesFlag::kDontCache));
   shared_info->set_kind(lit->kind());
-  shared_info->set_uses_super_property(lit->uses_super_property());
+  shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
   shared_info->set_asm_function(lit->scope()->asm_function());
 }
 
index f77c2407c7089edcc6cc107bc4608e234fe62754..4ea4cceca50d302a59f010c924a2f590698e1478 100644 (file)
@@ -6812,9 +6812,10 @@ class SharedFunctionInfo: public HeapObject {
   // False if the function definitely does not allocate an arguments object.
   DECL_BOOLEAN_ACCESSORS(uses_arguments)
 
-  // Indicates that this function uses a super property.
+  // Indicates that this function uses a super property (or an eval that may
+  // use a super property).
   // This is needed to set up the [[HomeObject]] on the function instance.
-  DECL_BOOLEAN_ACCESSORS(uses_super_property)
+  DECL_BOOLEAN_ACCESSORS(needs_home_object)
 
   // True if the function has any duplicated parameter names.
   DECL_BOOLEAN_ACCESSORS(has_duplicate_parameters)
@@ -7104,7 +7105,7 @@ class SharedFunctionInfo: public HeapObject {
     kStrictModeFunction,
     kStrongModeFunction,
     kUsesArguments,
-    kUsesSuperProperty,
+    kNeedsHomeObject,
     kHasDuplicateParameters,
     kNative,
     kForceInline,
index a961f9140386b67cf84dbfb26b62341d37685dab..75bfbe25ab84611b2a14a95be4f098cd17073728 100644 (file)
@@ -4104,6 +4104,7 @@ void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
       *expected_property_count = entry.property_count();
       scope_->SetLanguageMode(entry.language_mode());
       if (entry.uses_super_property()) scope_->RecordSuperPropertyUsage();
+      if (entry.calls_eval()) scope_->RecordEvalCall();
       return;
     }
     cached_parse_data_->Reject();
@@ -4138,16 +4139,19 @@ void Parser::SkipLazyFunctionBody(int* materialized_literal_count,
   *materialized_literal_count = logger.literals();
   *expected_property_count = logger.properties();
   scope_->SetLanguageMode(logger.language_mode());
-  if (logger.scope_uses_super_property()) {
+  if (logger.uses_super_property()) {
     scope_->RecordSuperPropertyUsage();
   }
+  if (logger.calls_eval()) {
+    scope_->RecordEvalCall();
+  }
   if (produce_cached_parse_data()) {
     DCHECK(log_);
     // Position right after terminal '}'.
     int body_end = scanner()->location().end_pos;
     log_->LogFunction(function_block_pos, body_end, *materialized_literal_count,
                       *expected_property_count, scope_->language_mode(),
-                      scope_->uses_super_property());
+                      scope_->uses_super_property(), scope_->calls_eval());
   }
 }
 
index 9080160c7590f21cce5a7ac3e619e86b60d383f0..05961414098186770fe538b6c0df619daedd78f4 100644 (file)
@@ -216,6 +216,7 @@ class FunctionEntry BASE_EMBEDDED {
     kPropertyCountIndex,
     kLanguageModeIndex,
     kUsesSuperPropertyIndex,
+    kCallsEvalIndex,
     kSize
   };
 
@@ -233,6 +234,7 @@ class FunctionEntry BASE_EMBEDDED {
     return static_cast<LanguageMode>(backing_[kLanguageModeIndex]);
   }
   bool uses_super_property() { return backing_[kUsesSuperPropertyIndex]; }
+  bool calls_eval() { return backing_[kCallsEvalIndex]; }
 
   bool is_valid() { return !backing_.is_empty(); }
 
index dcd881f91e45f6ecdafb67510ae4da6eea6646f7..560693f67eb0022ce11c42b5f19ed6db7330a56b 100644 (file)
@@ -14,7 +14,7 @@ struct PreparseDataConstants {
  public:
   // Layout and constants of the preparse data exchange format.
   static const unsigned kMagicNumber = 0xBadDead;
-  static const unsigned kCurrentVersion = 10;
+  static const unsigned kCurrentVersion = 11;
 
   static const int kMagicOffset = 0;
   static const int kVersionOffset = 1;
index 0cfef9125bcb1ecc84170bf6813f771791b58317..f7ed1ed91ad686aab2b7523ed75c4ef9461719b8 100644 (file)
@@ -53,8 +53,8 @@ class ParserRecorder {
 
   // Logs the scope and some details of a function literal in the source.
   virtual void LogFunction(int start, int end, int literals, int properties,
-                           LanguageMode language_mode,
-                           bool uses_super_property) = 0;
+                           LanguageMode language_mode, bool uses_super_property,
+                           bool calls_eval) = 0;
 
   // Logs an error message and marks the log as containing an error.
   // Further logging will be ignored, and ExtractData will return a vector
@@ -77,15 +77,16 @@ class SingletonLogger : public ParserRecorder {
   void Reset() { has_error_ = false; }
 
   virtual void LogFunction(int start, int end, int literals, int properties,
-                           LanguageMode language_mode,
-                           bool scope_uses_super_property) {
+                           LanguageMode language_mode, bool uses_super_property,
+                           bool calls_eval) {
     DCHECK(!has_error_);
     start_ = start;
     end_ = end;
     literals_ = literals;
     properties_ = properties;
     language_mode_ = language_mode;
-    scope_uses_super_property_ = scope_uses_super_property;
+    uses_super_property_ = uses_super_property;
+    calls_eval_ = calls_eval;
   }
 
   // Logs an error message and marks the log as containing an error.
@@ -118,9 +119,13 @@ class SingletonLogger : public ParserRecorder {
     DCHECK(!has_error_);
     return language_mode_;
   }
-  bool scope_uses_super_property() const {
+  bool uses_super_property() const {
     DCHECK(!has_error_);
-    return scope_uses_super_property_;
+    return uses_super_property_;
+  }
+  bool calls_eval() const {
+    DCHECK(!has_error_);
+    return calls_eval_;
   }
   ParseErrorType error_type() const {
     DCHECK(has_error_);
@@ -143,7 +148,8 @@ class SingletonLogger : public ParserRecorder {
   int literals_;
   int properties_;
   LanguageMode language_mode_;
-  bool scope_uses_super_property_;
+  bool uses_super_property_;
+  bool calls_eval_;
   // For error messages.
   MessageTemplate::Template message_;
   const char* argument_opt_;
@@ -162,14 +168,15 @@ class CompleteParserRecorder : public ParserRecorder {
   virtual ~CompleteParserRecorder() {}
 
   virtual void LogFunction(int start, int end, int literals, int properties,
-                           LanguageMode language_mode,
-                           bool scope_uses_super_property) {
+                           LanguageMode language_mode, bool uses_super_property,
+                           bool calls_eval) {
     function_store_.Add(start);
     function_store_.Add(end);
     function_store_.Add(literals);
     function_store_.Add(properties);
     function_store_.Add(language_mode);
-    function_store_.Add(scope_uses_super_property);
+    function_store_.Add(uses_super_property);
+    function_store_.Add(calls_eval);
   }
 
   // Logs an error message and marks the log as containing an error.
index 2644b4374ad8c16deb50ee22db604f045a3d6fd3..348c6b61ab2f4b3da1de8ff7f077f61f52ce98b8 100644 (file)
@@ -1106,7 +1106,7 @@ void PreParser::ParseLazyFunctionLiteralBody(bool* ok,
   log_->LogFunction(body_start, body_end,
                     function_state_->materialized_literal_count(),
                     function_state_->expected_property_count(), language_mode(),
-                    scope_->uses_super_property());
+                    scope_->uses_super_property(), scope_->calls_eval());
 }
 
 
index 34295c71f297bce5cdca1fc81aa80252298304e5..7a68e835ff2870e5397c2be37f7f17acb4fed00f 100644 (file)
@@ -1624,9 +1624,13 @@ class PreParserTraits {
   static void CheckAssigningFunctionLiteralToProperty(
       PreParserExpression left, PreParserExpression right) {}
 
-  // PreParser doesn't need to keep track of eval calls.
   static void CheckPossibleEvalCall(PreParserExpression expression,
-                                    Scope* scope) {}
+                                    Scope* scope) {
+    if (IsIdentifier(expression) && IsEval(AsIdentifier(expression))) {
+      scope->DeclarationScope()->RecordEvalCall();
+      scope->RecordEvalCall();
+    }
+  }
 
   static PreParserExpression MarkExpressionAsAssigned(
       PreParserExpression expression) {
index 016fc7f7c3d852ccfd58ad68e6cd0d2f903eafb1..c6baba5e29d07abf52c3b3473349dd16e6a5a7bc 100644 (file)
@@ -317,9 +317,12 @@ class Scope: public ZoneObject {
   bool inner_uses_arguments() const { return inner_scope_uses_arguments_; }
   // Does this scope access "super" property (super.foo).
   bool uses_super_property() const { return scope_uses_super_property_; }
-  // Does any inner scope access "super" property.
-  bool inner_uses_super_property() const {
-    return inner_scope_uses_super_property_;
+
+  bool NeedsHomeObject() const {
+    return scope_uses_super_property_ ||
+           (scope_calls_eval_ && (IsConciseMethod(function_kind()) ||
+                                  IsAccessorFunction(function_kind()) ||
+                                  IsConstructor(function_kind())));
   }
 
   const Scope* NearestOuterEvalScope() const {
@@ -611,7 +614,6 @@ class Scope: public ZoneObject {
   bool outer_scope_calls_sloppy_eval_;
   bool inner_scope_calls_eval_;
   bool inner_scope_uses_arguments_;
-  bool inner_scope_uses_super_property_;
   bool force_eager_compilation_;
   bool force_context_allocation_;
 
index 5d9985c4d5cfb0ae6dffde27ef6bfea3893f67db..24cf67b4a16fec074530d8c2a067696e8cc8ed2a 100644 (file)
@@ -976,6 +976,7 @@ TEST(ScopeUsesArgumentsSuperThis) {
     SUPER_PROPERTY = 1 << 1,
     THIS = 1 << 2,
     INNER_ARGUMENTS = 1 << 3,
+    EVAL = 1 << 4
   };
 
   // clang-format off
@@ -1025,6 +1026,11 @@ TEST(ScopeUsesArgumentsSuperThis) {
      "  let x; return { m() { return this + super.m() + arguments } }"
      "}",
      NONE},
+    {"eval(42)", EVAL},
+    {"if (1) { eval(42) }", EVAL},
+    {"eval('super.x')", EVAL},
+    {"eval('this.x')", EVAL},
+    {"eval('arguments')", EVAL},
   };
   // clang-format on
 
@@ -1089,6 +1095,7 @@ TEST(ScopeUsesArgumentsSuperThis) {
       }
       CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
                scope->inner_uses_arguments());
+      CHECK_EQ((source_data[i].expected & EVAL) != 0, scope->calls_eval());
     }
   }
 }
index 2c0301957a494e377e8143801fa2588eab047e72..ceac9aa0761aebe42a0185b400ac6bb7f5b53ef1 100644 (file)
@@ -16,6 +16,19 @@ class Derived extends Base {
   m() {
     return super.m();
   }
+  evalM() {
+    return eval('super.m()');
+  }
 }
 
 assertEquals(42, new Derived().m());
+assertEquals(42, new Derived().evalM());
+
+
+class LazyDerived extends Base {
+  constructor() {
+    eval('super()');
+  }
+}
+assertInstanceof(new LazyDerived(), LazyDerived);
+assertInstanceof(new LazyDerived(), Base);
index 3d713517ce14d0d50aa52396113e2f577018d871..ccf492bf5874ac471b804895fc27392239d8eb8b 100644 (file)
   };
   var o = {
     __proto__: p,
-    eval() {
-      assertSame(super.x, eval('super.x'));
-      assertSame(super.m(), eval('super.m()'));
-      // Global eval.
+    evalM() {
+      assertEquals(1, eval('super.m()'));
+    },
+    evalX() {
+      assertEquals(2, eval('super.x'));
+    },
+    globalEval1() {
+      assertThrows('super.x', SyntaxError);
+      assertThrows('super.m()', SyntaxError);
+    },
+    globalEval2() {
+      super.x;
       assertThrows('super.x', SyntaxError);
       assertThrows('super.m()', SyntaxError);
-      return eval('super.m()');
     }
   };
-  assertSame(1, o.eval());
+  o.evalM();
+  o.evalX();
+  o.globalEval1();
+  o.globalEval2();
 })();
 
 
index 87fceafb299bceffd8fead995e1e4a45f03705c7..1a0dd2add796fc9afb0ed27c807e295555a3eaef 100644 (file)
@@ -2076,17 +2076,27 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44);
     get x() { return 2; }
   }
   class Derived extends Base {
-    eval() {
-      assertSame(super.x, eval('super.x'));
-      assertSame(super.m(), eval('super.m()'));
-      // Global eval.
+    evalM() {
+      assertEquals(1, eval('super.m()'));
+    }
+    evalX() {
+      assertEquals(2, eval('super.x'));
+    }
+    globalEval1() {
+      assertThrows('super.x', SyntaxError);
+      assertThrows('super.m()', SyntaxError);
+    }
+    globalEval2() {
+      super.x;
       assertThrows('super.x', SyntaxError);
       assertThrows('super.m()', SyntaxError);
-      return eval('super.m()');
     }
   }
   let d = new Derived();
-  assertSame(1, d.eval());
+  d.globalEval1();
+  d.globalEval2();
+  d.evalM();
+  d.evalX();
 })();