"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",
--- /dev/null
+// 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
--- /dev/null
+// 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_
}
-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();
}
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_; }
#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"
#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"
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());
}
}
+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;
}
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."]
};
}
-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)
// 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)
kOptimizationDisabled,
kStrictModeFunction,
kUsesArguments,
- kUsesSuper,
+ kUsesSuperProperty,
+ kUsesSuperConstructorCall,
kHasDuplicateParameters,
kNative,
kInlineBuiltin,
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();
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(),
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.
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);
} 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()),
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_;
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;
// 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;
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");
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;
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; }
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".
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.
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_;
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 {
{"", 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},
{"\"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 }"
"}",
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());
}
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();
+}());
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();
+}());
'../../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',