harmony-classes: Implement 'super(...)' call syntactic restriction.
authordslomov <dslomov@chromium.org>
Fri, 28 Nov 2014 04:08:48 +0000 (20:08 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 28 Nov 2014 04:08:58 +0000 (04:08 +0000)
R=rossberg@chromium.org,arv@chromium.org
BUG=v8:3330
LOG=N

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

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

17 files changed:
BUILD.gn
src/ast-this-access-visitor.cc [new file with mode: 0644]
src/ast-this-access-visitor.h [new file with mode: 0644]
src/ast.cc
src/ast.h
src/compiler.cc
src/messages.js
src/objects-inl.h
src/objects.h
src/parser.cc
src/preparser.h
src/scopes.cc
src/scopes.h
test/cctest/test-parsing.cc
test/mjsunit/harmony/classes.js
test/mjsunit/harmony/super.js
tools/gyp/v8.gyp

index 26f4a46..0c7fae6 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -429,6 +429,8 @@ source_set("v8_base") {
     "src/assert-scope.cc",
     "src/ast-numbering.cc",
     "src/ast-numbering.h",
+    "src/ast-this-access-visitor.cc",
+    "src/ast-this-access-visitor.h",
     "src/ast-value-factory.cc",
     "src/ast-value-factory.h",
     "src/ast.cc",
diff --git a/src/ast-this-access-visitor.cc b/src/ast-this-access-visitor.cc
new file mode 100644 (file)
index 0000000..e66f961
--- /dev/null
@@ -0,0 +1,232 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/ast-this-access-visitor.h"
+#include "src/parser.h"
+
+namespace v8 {
+namespace internal {
+
+typedef class AstThisAccessVisitor ATAV;  // for code shortitude.
+
+ATAV::AstThisAccessVisitor(Zone* zone) : uses_this_(false) {
+  InitializeAstVisitor(zone);
+}
+
+
+void ATAV::VisitVariableProxy(VariableProxy* proxy) {
+  if (proxy->is_this()) {
+    uses_this_ = true;
+  }
+}
+
+
+// ---------------------------------------------------------------------------
+// -- Leaf nodes -------------------------------------------------------------
+// ---------------------------------------------------------------------------
+
+void ATAV::VisitVariableDeclaration(VariableDeclaration* leaf) {}
+void ATAV::VisitFunctionDeclaration(FunctionDeclaration* leaf) {}
+void ATAV::VisitModuleDeclaration(ModuleDeclaration* leaf) {}
+void ATAV::VisitImportDeclaration(ImportDeclaration* leaf) {}
+void ATAV::VisitExportDeclaration(ExportDeclaration* leaf) {}
+void ATAV::VisitModuleVariable(ModuleVariable* leaf) {}
+void ATAV::VisitModulePath(ModulePath* leaf) {}
+void ATAV::VisitModuleUrl(ModuleUrl* leaf) {}
+void ATAV::VisitEmptyStatement(EmptyStatement* leaf) {}
+void ATAV::VisitContinueStatement(ContinueStatement* leaf) {}
+void ATAV::VisitBreakStatement(BreakStatement* leaf) {}
+void ATAV::VisitDebuggerStatement(DebuggerStatement* leaf) {}
+void ATAV::VisitFunctionLiteral(FunctionLiteral* leaf) {}
+void ATAV::VisitNativeFunctionLiteral(NativeFunctionLiteral* leaf) {}
+void ATAV::VisitLiteral(Literal* leaf) {}
+void ATAV::VisitRegExpLiteral(RegExpLiteral* leaf) {}
+void ATAV::VisitThisFunction(ThisFunction* leaf) {}
+void ATAV::VisitSuperReference(SuperReference* leaf) {}
+
+
+// ---------------------------------------------------------------------------
+// -- Pass-through nodes------------------------------------------------------
+// ---------------------------------------------------------------------------
+void ATAV::VisitModuleLiteral(ModuleLiteral* e) { Visit(e->body()); }
+
+
+void ATAV::VisitBlock(Block* stmt) { VisitStatements(stmt->statements()); }
+
+
+void ATAV::VisitExpressionStatement(ExpressionStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void ATAV::VisitIfStatement(IfStatement* stmt) {
+  Visit(stmt->condition());
+  Visit(stmt->then_statement());
+  Visit(stmt->else_statement());
+}
+
+
+void ATAV::VisitReturnStatement(ReturnStatement* stmt) {
+  Visit(stmt->expression());
+}
+
+
+void ATAV::VisitWithStatement(WithStatement* stmt) {
+  Visit(stmt->expression());
+  Visit(stmt->statement());
+}
+
+
+void ATAV::VisitSwitchStatement(SwitchStatement* stmt) {
+  Visit(stmt->tag());
+  ZoneList<CaseClause*>* clauses = stmt->cases();
+  for (int i = 0; i < clauses->length(); i++) {
+    Visit(clauses->at(i));
+  }
+}
+
+
+void ATAV::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+  Visit(stmt->try_block());
+  Visit(stmt->finally_block());
+}
+
+
+void ATAV::VisitClassLiteral(ClassLiteral* e) {
+  VisitIfNotNull(e->extends());
+  VisitIfNotNull(e->constructor());
+  ZoneList<ObjectLiteralProperty*>* properties = e->properties();
+  for (int i = 0; i < properties->length(); i++) {
+    Visit(properties->at(i)->value());
+  }
+}
+
+
+void ATAV::VisitConditional(Conditional* e) {
+  Visit(e->condition());
+  Visit(e->then_expression());
+  Visit(e->else_expression());
+}
+
+
+void ATAV::VisitObjectLiteral(ObjectLiteral* e) {
+  ZoneList<ObjectLiteralProperty*>* properties = e->properties();
+  for (int i = 0; i < properties->length(); i++) {
+    Visit(properties->at(i)->value());
+  }
+}
+
+
+void ATAV::VisitArrayLiteral(ArrayLiteral* e) { VisitExpressions(e->values()); }
+
+
+void ATAV::VisitYield(Yield* stmt) {
+  Visit(stmt->generator_object());
+  Visit(stmt->expression());
+}
+
+
+void ATAV::VisitThrow(Throw* stmt) { Visit(stmt->exception()); }
+
+
+void ATAV::VisitProperty(Property* e) {
+  Visit(e->obj());
+  Visit(e->key());
+}
+
+
+void ATAV::VisitCall(Call* e) {
+  Visit(e->expression());
+  VisitExpressions(e->arguments());
+}
+
+
+void ATAV::VisitCallNew(CallNew* e) {
+  Visit(e->expression());
+  VisitExpressions(e->arguments());
+}
+
+
+void ATAV::VisitCallRuntime(CallRuntime* e) {
+  VisitExpressions(e->arguments());
+}
+
+
+void ATAV::VisitUnaryOperation(UnaryOperation* e) { Visit(e->expression()); }
+
+
+void ATAV::VisitBinaryOperation(BinaryOperation* e) {
+  Visit(e->left());
+  Visit(e->right());
+}
+
+
+void ATAV::VisitCompareOperation(CompareOperation* e) {
+  Visit(e->left());
+  Visit(e->right());
+}
+
+
+void ATAV::VisitCaseClause(CaseClause* cc) {
+  if (!cc->is_default()) Visit(cc->label());
+  VisitStatements(cc->statements());
+}
+
+
+void ATAV::VisitModuleStatement(ModuleStatement* stmt) { Visit(stmt->body()); }
+
+
+void ATAV::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  Visit(stmt->try_block());
+  Visit(stmt->catch_block());
+}
+
+
+void ATAV::VisitDoWhileStatement(DoWhileStatement* loop) {
+  Visit(loop->body());
+  Visit(loop->cond());
+}
+
+
+void ATAV::VisitWhileStatement(WhileStatement* loop) {
+  Visit(loop->cond());
+  Visit(loop->body());
+}
+
+
+void ATAV::VisitForStatement(ForStatement* loop) {
+  VisitIfNotNull(loop->init());
+  VisitIfNotNull(loop->cond());
+  Visit(loop->body());
+  VisitIfNotNull(loop->next());
+}
+
+
+void ATAV::VisitForInStatement(ForInStatement* loop) {
+  Visit(loop->each());
+  Visit(loop->subject());
+  Visit(loop->body());
+}
+
+
+void ATAV::VisitForOfStatement(ForOfStatement* loop) {
+  Visit(loop->each());
+  Visit(loop->subject());
+  Visit(loop->body());
+}
+
+
+void ATAV::VisitAssignment(Assignment* stmt) {
+  Expression* l = stmt->target();
+  Visit(l);
+  Visit(stmt->value());
+}
+
+
+void ATAV::VisitCountOperation(CountOperation* e) {
+  Expression* l = e->expression();
+  Visit(l);
+}
+}
+}  // namespace v8::internal
diff --git a/src/ast-this-access-visitor.h b/src/ast-this-access-visitor.h
new file mode 100644 (file)
index 0000000..3317922
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_AST_THIS_ACCESS_VISITOR_H_
+#define V8_AST_THIS_ACCESS_VISITOR_H_
+#include "src/ast.h"
+
+namespace v8 {
+namespace internal {
+
+class AstThisAccessVisitor : public AstVisitor {
+ public:
+  explicit AstThisAccessVisitor(Zone* zone);
+
+  bool UsesThis() { return uses_this_; }
+
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+ private:
+  bool uses_this_;
+
+  void VisitIfNotNull(AstNode* node) {
+    if (node != NULL) Visit(node);
+  }
+
+  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+  DISALLOW_COPY_AND_ASSIGN(AstThisAccessVisitor);
+};
+}
+}  // namespace v8::intrenal
+#endif  // V8_AST_THIS_ACCESS_VISITOR_H_
index 874f984..35347ce 100644 (file)
@@ -151,9 +151,16 @@ StrictMode FunctionLiteral::strict_mode() const {
 }
 
 
-bool FunctionLiteral::uses_super() const {
+bool FunctionLiteral::uses_super_property() const {
   DCHECK_NOT_NULL(scope());
-  return scope()->uses_super() || scope()->inner_uses_super();
+  return scope()->uses_super_property() || scope()->inner_uses_super_property();
+}
+
+
+bool FunctionLiteral::uses_super_constructor_call() const {
+  DCHECK_NOT_NULL(scope());
+  return scope()->uses_super_constructor_call() ||
+         scope()->inner_uses_super_constructor_call();
 }
 
 
index c9592e6..d57aaa8 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -2513,11 +2513,12 @@ class FunctionLiteral FINAL : public Expression {
   bool is_expression() const { return IsExpression::decode(bitfield_); }
   bool is_anonymous() const { return IsAnonymous::decode(bitfield_); }
   StrictMode strict_mode() const;
-  bool uses_super() const;
+  bool uses_super_property() const;
+  bool uses_super_constructor_call() const;
 
   static bool NeedsHomeObject(Expression* literal) {
     return literal != NULL && literal->IsFunctionLiteral() &&
-           literal->AsFunctionLiteral()->uses_super();
+           literal->AsFunctionLiteral()->uses_super_property();
   }
 
   int materialized_literal_count() { return materialized_literal_count_; }
index a3bde5d..546ac88 100644 (file)
@@ -7,6 +7,7 @@
 #include "src/compiler.h"
 
 #include "src/ast-numbering.h"
+#include "src/ast-this-access-visitor.h"
 #include "src/bootstrapper.h"
 #include "src/codegen.h"
 #include "src/compilation-cache.h"
@@ -20,6 +21,7 @@
 #include "src/isolate-inl.h"
 #include "src/lithium.h"
 #include "src/liveedit.h"
+#include "src/messages.h"
 #include "src/parser.h"
 #include "src/rewriter.h"
 #include "src/runtime-profiler.h"
@@ -615,7 +617,9 @@ static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
   MaybeDisableOptimization(function_info, lit->dont_optimize_reason());
   function_info->set_dont_cache(lit->flags()->Contains(kDontCache));
   function_info->set_kind(lit->kind());
-  function_info->set_uses_super(lit->uses_super());
+  function_info->set_uses_super_property(lit->uses_super_property());
+  function_info->set_uses_super_constructor_call(
+      lit->uses_super_constructor_call());
   function_info->set_asm_function(lit->scope()->asm_function());
 }
 
@@ -758,12 +762,84 @@ static bool Renumber(CompilationInfo* info) {
 }
 
 
+static void ThrowSuperConstructorCheckError(CompilationInfo* info) {
+  MaybeHandle<Object> obj = info->isolate()->factory()->NewTypeError(
+      "super_constructor_call", HandleVector<Object>(nullptr, 0));
+  Handle<Object> exception;
+  if (!obj.ToHandle(&exception)) return;
+
+  FunctionLiteral* lit = info->function();
+  MessageLocation location(info->script(), lit->start_position(),
+                           lit->end_position());
+  USE(info->isolate()->Throw(*exception, &location));
+}
+
+
+static bool CheckSuperConstructorCall(CompilationInfo* info) {
+  FunctionLiteral* function = info->function();
+  if (!function->uses_super_constructor_call()) return true;
+
+  if (function->is_default_constructor()) return true;
+
+  ZoneList<Statement*>* body = function->body();
+  CHECK(body->length() > 0);
+
+  int super_call_index = 0;
+  // Allow 'use strict' and similiar and empty statements.
+  while (true) {
+    CHECK(super_call_index < body->length());  // We know there is a super call.
+    Statement* stmt = body->at(super_call_index);
+    if (stmt->IsExpressionStatement() &&
+        stmt->AsExpressionStatement()->expression()->IsLiteral()) {
+      super_call_index++;
+      continue;
+    }
+    if (stmt->IsEmptyStatement()) {
+      super_call_index++;
+      continue;
+    }
+    break;
+  }
+
+  ExpressionStatement* exprStm =
+      body->at(super_call_index)->AsExpressionStatement();
+  if (exprStm == nullptr) {
+    ThrowSuperConstructorCheckError(info);
+    return false;
+  }
+  Call* callExpr = exprStm->expression()->AsCall();
+  if (callExpr == nullptr) {
+    ThrowSuperConstructorCheckError(info);
+    return false;
+  }
+
+  if (!callExpr->expression()->IsSuperReference()) {
+    ThrowSuperConstructorCheckError(info);
+    return false;
+  }
+
+  ZoneList<Expression*>* arguments = callExpr->arguments();
+
+  AstThisAccessVisitor this_access_visitor(info->zone());
+  this_access_visitor.VisitExpressions(arguments);
+
+  if (this_access_visitor.HasStackOverflow()) return false;
+  if (this_access_visitor.UsesThis()) {
+    ThrowSuperConstructorCheckError(info);
+    return false;
+  }
+
+  return true;
+}
+
+
 bool Compiler::Analyze(CompilationInfo* info) {
   DCHECK(info->function() != NULL);
   if (!Rewriter::Rewrite(info)) return false;
   if (!Scope::Analyze(info)) return false;
   if (!Renumber(info)) return false;
   DCHECK(info->scope() != NULL);
+  if (!CheckSuperConstructorCall(info)) return false;
   return true;
 }
 
index 142e47b..78fac32 100644 (file)
@@ -182,6 +182,8 @@ var kMessages = {
   prototype_parent_not_an_object: ["Class extends value does not have valid prototype property ", "%0"],
   duplicate_constructor:         ["A class may only have one constructor"],
   sloppy_lexical:                ["Block-scoped declarations (let, const, function, class) not yet supported outside strict mode"],
+  super_constructor_call:        ["'super(...)' constructor call is currently only supported if it is the first statement of a constructor and its arguments do not access 'this'"],
+  super_constructor_call:        ["A 'super' constructor call may only appear as the first statement of a function, and its arguments may not access 'this'. Other forms are not yet supported."]
 };
 
 
index 98d96a8..34c3f2d 100644 (file)
@@ -5792,7 +5792,10 @@ void SharedFunctionInfo::set_kind(FunctionKind kind) {
 }
 
 
-BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, uses_super, kUsesSuper)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, uses_super_property,
+               kUsesSuperProperty)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, uses_super_constructor_call,
+               kUsesSuperConstructorCall)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative)
 BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, inline_builtin,
                kInlineBuiltin)
index ea84ebf..c284a49 100644 (file)
@@ -6831,9 +6831,12 @@ 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 super. This is needed to set up the
-  // [[HomeObject]] on the function instance.
-  DECL_BOOLEAN_ACCESSORS(uses_super)
+  // Indicates that this function uses a super property.
+  // This is needed to set up the [[HomeObject]] on the function instance.
+  DECL_BOOLEAN_ACCESSORS(uses_super_property)
+
+  // Indicates that this function uses the super constructor.
+  DECL_BOOLEAN_ACCESSORS(uses_super_constructor_call)
 
   // True if the function has any duplicated parameter names.
   DECL_BOOLEAN_ACCESSORS(has_duplicate_parameters)
@@ -7112,7 +7115,8 @@ class SharedFunctionInfo: public HeapObject {
     kOptimizationDisabled,
     kStrictModeFunction,
     kUsesArguments,
-    kUsesSuper,
+    kUsesSuperProperty,
+    kUsesSuperConstructorCall,
     kHasDuplicateParameters,
     kNative,
     kInlineBuiltin,
index 712fdd4..22c0f5c 100644 (file)
@@ -301,7 +301,7 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
           Runtime::FunctionForId(Runtime::kDefaultConstructorSuperCall), args,
           pos);
       body->Add(factory()->NewExpressionStatement(call, pos), zone());
-      function_scope->RecordSuperUsage();
+      function_scope->RecordSuperConstructorCallUsage();
     }
 
     materialized_literal_count = function_state.materialized_literal_count();
@@ -1053,8 +1053,8 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
       DCHECK(expression->IsFunctionLiteral());
       result = expression->AsFunctionLiteral();
     } else if (shared_info->is_default_constructor()) {
-      result = DefaultConstructor(shared_info->uses_super(), scope,
-                                  shared_info->start_position(),
+      result = DefaultConstructor(shared_info->uses_super_constructor_call(),
+                                  scope, shared_info->start_position(),
                                   shared_info->end_position());
     } else {
       result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(),
index bdab177..b50019c 100644 (file)
@@ -979,7 +979,8 @@ class PreParserScope {
   bool IsDeclared(const PreParserIdentifier& identifier) const { return false; }
   void DeclareParameter(const PreParserIdentifier& identifier, VariableMode) {}
   void RecordArgumentsUsage() {}
-  void RecordSuperUsage() {}
+  void RecordSuperPropertyUsage() {}
+  void RecordSuperConstructorCallUsage() {}
   void RecordThisUsage() {}
 
   // Allow scope->Foo() to work.
@@ -2563,7 +2564,6 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(bool* ok) {
     int new_pos = position();
     ExpressionT result = this->EmptyExpression();
     if (Check(Token::SUPER)) {
-      scope_->RecordSuperUsage();
       result = this->SuperReference(scope_, factory());
     } else {
       result = this->ParseMemberWithNewPrefixesExpression(CHECK_OK);
@@ -2623,10 +2623,12 @@ ParserBase<Traits>::ParseMemberExpression(bool* ok) {
   } else if (peek() == Token::SUPER) {
     int beg_pos = position();
     Consume(Token::SUPER);
-    scope_->RecordSuperUsage();
     Token::Value next = peek();
-    if (next == Token::PERIOD || next == Token::LBRACK ||
-        next == Token::LPAREN) {
+    if (next == Token::PERIOD || next == Token::LBRACK) {
+      scope_->RecordSuperPropertyUsage();
+      result = this->SuperReference(scope_, factory());
+    } else if (next == Token::LPAREN) {
+      scope_->RecordSuperConstructorCallUsage();
       result = this->SuperReference(scope_, factory());
     } else {
       ReportMessageAt(Scanner::Location(beg_pos, position()),
index 65a91fc..74c3f0b 100644 (file)
@@ -161,7 +161,8 @@ void Scope::SetDefaults(ScopeType scope_type,
   scope_contains_with_ = false;
   scope_calls_eval_ = false;
   scope_uses_arguments_ = false;
-  scope_uses_super_ = false;
+  scope_uses_super_property_ = false;
+  scope_uses_super_constructor_call_ = false;
   scope_uses_this_ = false;
   asm_module_ = false;
   asm_function_ = outer_scope != NULL && outer_scope->asm_module_;
@@ -171,7 +172,8 @@ void Scope::SetDefaults(ScopeType scope_type,
   inner_scope_calls_eval_ = false;
   inner_scope_uses_arguments_ = false;
   inner_scope_uses_this_ = false;
-  inner_scope_uses_super_ = false;
+  inner_scope_uses_super_property_ = false;
+  inner_scope_uses_super_constructor_call_ = false;
   force_eager_compilation_ = false;
   force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
       ? outer_scope->has_forced_context_allocation() : false;
@@ -375,7 +377,9 @@ Scope* Scope::FinalizeBlockScope() {
 
   // Propagate usage flags to outer scope.
   if (uses_arguments()) outer_scope_->RecordArgumentsUsage();
-  if (uses_super()) outer_scope_->RecordSuperUsage();
+  if (uses_super_property()) outer_scope_->RecordSuperPropertyUsage();
+  if (uses_super_constructor_call())
+    outer_scope_->RecordSuperConstructorCallUsage();
   if (uses_this()) outer_scope_->RecordThisUsage();
 
   return NULL;
@@ -896,12 +900,20 @@ void Scope::Print(int n) {
   if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
   if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
   if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n");
-  if (scope_uses_super_) Indent(n1, "// scope uses 'super'\n");
+  if (scope_uses_super_property_)
+    Indent(n1, "// scope uses 'super' property\n");
+  if (scope_uses_super_constructor_call_) {
+    Indent(n1, "// scope uses 'super' constructor\n");
+  }
   if (scope_uses_this_) Indent(n1, "// scope uses 'this'\n");
   if (inner_scope_uses_arguments_) {
     Indent(n1, "// inner scope uses 'arguments'\n");
   }
-  if (inner_scope_uses_super_) Indent(n1, "// inner scope uses 'super'\n");
+  if (inner_scope_uses_super_property_)
+    Indent(n1, "// inner scope uses 'super' property\n");
+  if (inner_scope_uses_super_constructor_call_) {
+    Indent(n1, "// inner scope uses 'super' constructor\n");
+  }
   if (inner_scope_uses_this_) Indent(n1, "// inner scope uses 'this'\n");
   if (outer_scope_calls_sloppy_eval_) {
     Indent(n1, "// outer scope calls 'eval' in sloppy context\n");
@@ -1174,8 +1186,13 @@ void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) {
       if (inner->scope_uses_arguments_ || inner->inner_scope_uses_arguments_) {
         inner_scope_uses_arguments_ = true;
       }
-      if (inner->scope_uses_super_ || inner->inner_scope_uses_super_) {
-        inner_scope_uses_super_ = true;
+      if (inner->scope_uses_super_property_ ||
+          inner->inner_scope_uses_super_property_) {
+        inner_scope_uses_super_property_ = true;
+      }
+      if (inner->uses_super_constructor_call() ||
+          inner->inner_scope_uses_super_constructor_call_) {
+        inner_scope_uses_super_constructor_call_ = true;
       }
       if (inner->scope_uses_this_ || inner->inner_scope_uses_this_) {
         inner_scope_uses_this_ = true;
index 4975ab4..8d79006 100644 (file)
@@ -214,7 +214,12 @@ class Scope: public ZoneObject {
   void RecordArgumentsUsage() { scope_uses_arguments_ = true; }
 
   // Inform the scope that the corresponding code uses "super".
-  void RecordSuperUsage() { scope_uses_super_ = true; }
+  void RecordSuperPropertyUsage() { scope_uses_super_property_ = true; }
+
+  // Inform the scope that the corresponding code invokes "super" constructor.
+  void RecordSuperConstructorCallUsage() {
+    scope_uses_super_constructor_call_ = true;
+  }
 
   // Inform the scope that the corresponding code uses "this".
   void RecordThisUsage() { scope_uses_this_ = true; }
@@ -307,10 +312,20 @@ class Scope: public ZoneObject {
   bool uses_arguments() const { return scope_uses_arguments_; }
   // Does any inner scope access "arguments".
   bool inner_uses_arguments() const { return inner_scope_uses_arguments_; }
-  // Does this scope access "super".
-  bool uses_super() const { return scope_uses_super_; }
-  // Does any inner scope access "super".
-  bool inner_uses_super() const { return inner_scope_uses_super_; }
+  // 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_;
+  }
+  // Does this scope calls "super" constructor.
+  bool uses_super_constructor_call() const {
+    return scope_uses_super_constructor_call_;
+  }
+  // Does  any inner scope calls "super" constructor.
+  bool inner_uses_super_constructor_call() const {
+    return inner_scope_uses_super_constructor_call_;
+  }
   // Does this scope access "this".
   bool uses_this() const { return scope_uses_this_; }
   // Does any inner scope access "this".
@@ -496,8 +511,10 @@ class Scope: public ZoneObject {
   bool scope_calls_eval_;
   // This scope uses "arguments".
   bool scope_uses_arguments_;
-  // This scope uses "super".
-  bool scope_uses_super_;
+  // This scope uses "super" property ('super.foo').
+  bool scope_uses_super_property_;
+  // This scope uses "super" constructor ('super(..)').
+  bool scope_uses_super_constructor_call_;
   // This scope uses "this".
   bool scope_uses_this_;
   // This scope contains an "use asm" annotation.
@@ -514,7 +531,8 @@ 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_;
+  bool inner_scope_uses_super_property_;
+  bool inner_scope_uses_super_constructor_call_;
   bool inner_scope_uses_this_;
   bool force_eager_compilation_;
   bool force_context_allocation_;
index 80d3406..4e2f828 100644 (file)
@@ -932,11 +932,13 @@ TEST(ScopeUsesArgumentsSuperThis) {
   enum Expected {
     NONE = 0,
     ARGUMENTS = 1,
-    SUPER = 2,
-    THIS = 4,
-    INNER_ARGUMENTS = 8,
-    INNER_SUPER = 16,
-    INNER_THIS = 32
+    SUPER_PROPERTY = 2,
+    SUPER_CONSTRUCTOR_CALL = 4,
+    THIS = 8,
+    INNER_ARGUMENTS = 16,
+    INNER_SUPER_PROPERTY = 32,
+    INNER_SUPER_CONSTRUCTOR_CALL = 64,
+    INNER_THIS = 128
   };
 
   static const struct {
@@ -946,27 +948,29 @@ TEST(ScopeUsesArgumentsSuperThis) {
         {"", NONE},
         {"return this", THIS},
         {"return arguments", ARGUMENTS},
-        {"return super()", SUPER},
-        {"return super.x", SUPER},
+        {"return super()", SUPER_CONSTRUCTOR_CALL},
+        {"return super.x", SUPER_PROPERTY},
         {"return arguments[0]", ARGUMENTS},
         {"return this + arguments[0]", ARGUMENTS | THIS},
-        {"return this + arguments[0] + super.x", ARGUMENTS | SUPER | THIS},
+        {"return this + arguments[0] + super.x",
+         ARGUMENTS | SUPER_PROPERTY | THIS},
         {"return x => this + x", INNER_THIS},
-        {"return x => super() + x", INNER_SUPER},
+        {"return x => super() + x", INNER_SUPER_CONSTRUCTOR_CALL},
         {"this.foo = 42;", THIS},
         {"this.foo();", THIS},
         {"if (foo()) { this.f() }", THIS},
-        {"if (foo()) { super.f() }", SUPER},
+        {"if (foo()) { super.f() }", SUPER_PROPERTY},
         {"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
         {"while (true) { this.f() }", THIS},
-        {"while (true) { super.f() }", SUPER},
+        {"while (true) { super.f() }", SUPER_PROPERTY},
         {"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
         // Multiple nesting levels must work as well.
         {"while (true) { while (true) { while (true) return this } }", THIS},
         {"while (true) { while (true) { while (true) return super() } }",
-         SUPER},
+         SUPER_CONSTRUCTOR_CALL},
         {"if (1) { return () => { while (true) new this() } }", INNER_THIS},
-        {"if (1) { return () => { while (true) new super() } }", INNER_SUPER},
+        {"if (1) { return () => { while (true) new super() } }", NONE},
+        {"if (1) { return () => { while (true) new new super() } }", NONE},
         // Note that propagation of the inner_uses_this() value does not
         // cross boundaries of normal functions onto parent scopes.
         {"return function (x) { return this + x }", NONE},
@@ -981,9 +985,10 @@ TEST(ScopeUsesArgumentsSuperThis) {
         {"\"use strict\"; while (true) { let x; this, arguments; }",
          INNER_ARGUMENTS | INNER_THIS},
         {"\"use strict\"; while (true) { let x; this, super(), arguments; }",
-         INNER_ARGUMENTS | INNER_SUPER | INNER_THIS},
+         INNER_ARGUMENTS | INNER_SUPER_CONSTRUCTOR_CALL | INNER_THIS},
         {"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
-        {"\"use strict\"; if (foo()) { let x; super.f() }", INNER_SUPER},
+        {"\"use strict\"; if (foo()) { let x; super.f() }",
+         INNER_SUPER_PROPERTY},
         {"\"use strict\"; if (1) {"
          "  let x; return function () { return this + super() + arguments }"
          "}",
@@ -1033,12 +1038,17 @@ TEST(ScopeUsesArgumentsSuperThis) {
       i::Scope* scope = script_scope->inner_scopes()->at(0);
       CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
                scope->uses_arguments());
-      CHECK_EQ((source_data[i].expected & SUPER) != 0, scope->uses_super());
+      CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
+               scope->uses_super_property());
+      CHECK_EQ((source_data[i].expected & SUPER_CONSTRUCTOR_CALL) != 0,
+               scope->uses_super_constructor_call());
       CHECK_EQ((source_data[i].expected & THIS) != 0, scope->uses_this());
       CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
                scope->inner_uses_arguments());
-      CHECK_EQ((source_data[i].expected & INNER_SUPER) != 0,
-               scope->inner_uses_super());
+      CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
+               scope->inner_uses_super_property());
+      CHECK_EQ((source_data[i].expected & INNER_SUPER_CONSTRUCTOR_CALL) != 0,
+               scope->inner_uses_super_constructor_call());
       CHECK_EQ((source_data[i].expected & INNER_THIS) != 0,
                scope->inner_uses_this());
     }
index 4291770..5cea2a9 100644 (file)
@@ -777,3 +777,75 @@ function assertAccessorDescriptor(object, name) {
     var x = (class x extends x {});
   }, ReferenceError);
 })();
+
+
+(function TestSuperCallSyntacticRestriction() {
+  assertThrows(function() {
+    class C {
+      constructor() {
+        var y;
+        super();
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(this.x);
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(this);
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        super(1, 2, Object.getPrototypeOf(this));
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        { super(1, 2); }
+      }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    class C {
+      constructor() {
+        if (1) super();
+      }
+    }; new C();
+  }, TypeError);
+
+  class C1 extends Object {
+    constructor() {
+      'use strict';
+      super();
+    }
+  };
+  new C1();
+
+  class C2 extends Object {
+    constructor() {
+      ; 'use strict';;;;;
+      super();
+    }
+  };
+  new C2();
+
+  class C3 extends Object {
+    constructor() {
+      ; 'use strict';;;;;
+      // This is a comment.
+      super();
+    }
+  };
+  new C3();
+}());
index d972407..6dcc393 100644 (file)
@@ -1861,3 +1861,61 @@ function Subclass(base, constructor) {
   T1.__proto = null;
   assertThrows(function() { new T1(); }, TypeError);
 }());
+
+
+(function TestSuperCallSyntacticRestriction() {
+  assertThrows(function() {
+    function C() {
+        var y;
+        super();
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      super(this.x);
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      super(this);
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      super(1, 2, Object.getPrototypeOf(this));
+    }
+    new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      { super(1, 2); }
+    }; new C();
+  }, TypeError);
+  assertThrows(function() {
+    function C() {
+      if (1) super();
+    }; new C();
+  }, TypeError);
+
+  function C1() {
+    'use strict';
+    super();
+  };
+  new C1();
+
+  function C2() {
+    ; 'use strict';;;;;
+    super();
+  };
+  new C2();
+
+  function C3() {
+    ; 'use strict';;;;;
+    // This is a comment.
+    super();
+  }
+  new C3();
+}());
index 0f79d18..4958528 100644 (file)
         '../../src/assembler.h',
         '../../src/assert-scope.h',
         '../../src/assert-scope.cc',
+        '../../src/ast-this-access-visitor.cc',
+        '../../src/ast-this-access-visitor.h',
         '../../src/ast-value-factory.cc',
         '../../src/ast-value-factory.h',
         '../../src/ast-numbering.cc',