summaryrefslogtreecommitdiff
path: root/chromium/v8/src/ast
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-05-16 09:59:13 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-05-20 10:28:53 +0000
commit6c11fb357ec39bf087b8b632e2b1e375aef1b38b (patch)
treec8315530db18a8ee566521c39ab8a6af4f72bc03 /chromium/v8/src/ast
parent3ffaed019d0772e59d6cdb2d0d32fe4834c31f72 (diff)
downloadqtwebengine-chromium-6c11fb357ec39bf087b8b632e2b1e375aef1b38b.tar.gz
BASELINE: Update Chromium to 74.0.3729.159
Change-Id: I8d2497da544c275415aedd94dd25328d555de811 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/v8/src/ast')
-rw-r--r--chromium/v8/src/ast/ast-traversal-visitor.h4
-rw-r--r--chromium/v8/src/ast/ast-value-factory.cc1
-rw-r--r--chromium/v8/src/ast/ast-value-factory.h3
-rw-r--r--chromium/v8/src/ast/ast.cc28
-rw-r--r--chromium/v8/src/ast/ast.h137
-rw-r--r--chromium/v8/src/ast/modules.cc47
-rw-r--r--chromium/v8/src/ast/modules.h7
-rw-r--r--chromium/v8/src/ast/prettyprinter.cc9
-rw-r--r--chromium/v8/src/ast/prettyprinter.h1
-rw-r--r--chromium/v8/src/ast/scopes.cc811
-rw-r--r--chromium/v8/src/ast/scopes.h165
-rw-r--r--chromium/v8/src/ast/source-range-ast-visitor.cc13
-rw-r--r--chromium/v8/src/ast/variables.h8
13 files changed, 603 insertions, 631 deletions
diff --git a/chromium/v8/src/ast/ast-traversal-visitor.h b/chromium/v8/src/ast/ast-traversal-visitor.h
index 21986789ba7..b4836ff7847 100644
--- a/chromium/v8/src/ast/ast-traversal-visitor.h
+++ b/chromium/v8/src/ast/ast-traversal-visitor.h
@@ -467,7 +467,7 @@ void AstTraversalVisitor<Subclass>::VisitCompareOperation(
}
template <class Subclass>
-void AstTraversalVisitor<Subclass>::VisitThisFunction(ThisFunction* expr) {
+void AstTraversalVisitor<Subclass>::VisitThisExpression(ThisExpression* expr) {
PROCESS_EXPRESSION(expr);
}
@@ -555,7 +555,6 @@ template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference(
SuperPropertyReference* expr) {
PROCESS_EXPRESSION(expr);
- RECURSE_EXPRESSION(VisitVariableProxy(expr->this_var()));
RECURSE_EXPRESSION(Visit(expr->home_object()));
}
@@ -563,7 +562,6 @@ template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitSuperCallReference(
SuperCallReference* expr) {
PROCESS_EXPRESSION(expr);
- RECURSE_EXPRESSION(VisitVariableProxy(expr->this_var()));
RECURSE_EXPRESSION(VisitVariableProxy(expr->new_target_var()));
RECURSE_EXPRESSION(VisitVariableProxy(expr->this_function_var()));
}
diff --git a/chromium/v8/src/ast/ast-value-factory.cc b/chromium/v8/src/ast/ast-value-factory.cc
index 2a35097f9c7..94d500c07de 100644
--- a/chromium/v8/src/ast/ast-value-factory.cc
+++ b/chromium/v8/src/ast/ast-value-factory.cc
@@ -124,6 +124,7 @@ bool AstRawString::Compare(void* a, void* b) {
DCHECK_EQ(lhs->Hash(), rhs->Hash());
if (lhs->length() != rhs->length()) return false;
+ if (lhs->length() == 0) return true;
const unsigned char* l = lhs->raw_data();
const unsigned char* r = rhs->raw_data();
size_t length = rhs->length();
diff --git a/chromium/v8/src/ast/ast-value-factory.h b/chromium/v8/src/ast/ast-value-factory.h
index 472527bebe2..dd557f5ac95 100644
--- a/chromium/v8/src/ast/ast-value-factory.h
+++ b/chromium/v8/src/ast/ast-value-factory.h
@@ -202,10 +202,12 @@ class AstBigInt {
F(await, "await") \
F(bigint, "bigint") \
F(boolean, "boolean") \
+ F(computed, "<computed>") \
F(constructor, "constructor") \
F(default, "default") \
F(done, "done") \
F(dot, ".") \
+ F(dot_default, ".default") \
F(dot_for, ".for") \
F(dot_generator_object, ".generator_object") \
F(dot_iterator, ".iterator") \
@@ -235,7 +237,6 @@ class AstBigInt {
F(return, "return") \
F(set, "set") \
F(set_space, "set ") \
- F(star_default_star, "*default*") \
F(string, "string") \
F(symbol, "symbol") \
F(target, "target") \
diff --git a/chromium/v8/src/ast/ast.cc b/chromium/v8/src/ast/ast.cc
index 1c1802d602f..f70579bd69c 100644
--- a/chromium/v8/src/ast/ast.cc
+++ b/chromium/v8/src/ast/ast.cc
@@ -23,6 +23,7 @@
#include "src/property-details.h"
#include "src/property.h"
#include "src/string-stream.h"
+#include "src/zone/zone-list-inl.h"
namespace v8 {
namespace internal {
@@ -155,8 +156,8 @@ VariableProxy::VariableProxy(Variable* var, int start_position)
: Expression(start_position, kVariableProxy),
raw_name_(var->raw_name()),
next_unresolved_(nullptr) {
- bit_field_ |= IsThisField::encode(var->is_this()) |
- IsAssignedField::encode(false) |
+ DCHECK(!var->is_this());
+ bit_field_ |= IsAssignedField::encode(false) |
IsResolvedField::encode(false) |
HoleCheckModeField::encode(HoleCheckMode::kElided);
BindTo(var);
@@ -171,7 +172,7 @@ VariableProxy::VariableProxy(const VariableProxy* copy_from)
}
void VariableProxy::BindTo(Variable* var) {
- DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name());
+ DCHECK_EQ(raw_name(), var->raw_name());
set_var(var);
set_is_resolved();
var->set_is_used();
@@ -213,6 +214,18 @@ bool FunctionLiteral::AllowsLazyCompilation() {
return scope()->AllowsLazyCompilation();
}
+bool FunctionLiteral::SafeToSkipArgumentsAdaptor() const {
+ // TODO(bmeurer,verwaest): The --fast_calls_with_arguments_mismatches
+ // is mostly here for checking the real-world impact of the calling
+ // convention. There's not really a point in turning off this flag
+ // otherwise, so we should remove it at some point, when we're done
+ // with the experiments (https://crbug.com/v8/8895).
+ return FLAG_fast_calls_with_arguments_mismatches &&
+ language_mode() == LanguageMode::kStrict &&
+ scope()->arguments() == nullptr &&
+ scope()->rest_parameter() == nullptr;
+}
+
Handle<String> FunctionLiteral::name(Isolate* isolate) const {
return raw_name_ ? raw_name_->string() : isolate->factory()->empty_string();
}
@@ -457,15 +470,10 @@ void ObjectLiteral::BuildBoilerplateDescription(Isolate* isolate) {
has_seen_proto = true;
continue;
}
- if (property->is_computed_name()) {
- continue;
- }
+ if (property->is_computed_name()) continue;
Literal* key = property->key()->AsLiteral();
-
- if (!key->IsPropertyName()) {
- index_keys++;
- }
+ if (!key->IsPropertyName()) index_keys++;
}
Handle<ObjectBoilerplateDescription> boilerplate_description =
diff --git a/chromium/v8/src/ast/ast.h b/chromium/v8/src/ast/ast.h
index 4f9f083d123..80f76bd6e4b 100644
--- a/chromium/v8/src/ast/ast.h
+++ b/chromium/v8/src/ast/ast.h
@@ -11,6 +11,7 @@
#include "src/ast/modules.h"
#include "src/ast/variables.h"
#include "src/bailout-reason.h"
+#include "src/base/threaded-list.h"
#include "src/globals.h"
#include "src/heap/factory.h"
#include "src/isolate.h"
@@ -100,7 +101,7 @@ namespace internal {
V(SuperCallReference) \
V(SuperPropertyReference) \
V(TemplateLiteral) \
- V(ThisFunction) \
+ V(ThisExpression) \
V(Throw) \
V(UnaryOperation) \
V(VariableProxy) \
@@ -483,26 +484,14 @@ inline NestedVariableDeclaration* VariableDeclaration::AsNested() {
class FunctionDeclaration final : public Declaration {
public:
FunctionLiteral* fun() const { return fun_; }
- bool declares_sloppy_block_function() const {
- return DeclaresSloppyBlockFunction::decode(bit_field_);
- }
private:
friend class AstNodeFactory;
- class DeclaresSloppyBlockFunction
- : public BitField<bool, Declaration::kNextBitFieldIndex, 1> {};
-
- FunctionDeclaration(FunctionLiteral* fun, bool declares_sloppy_block_function,
- int pos)
- : Declaration(pos, kFunctionDeclaration), fun_(fun) {
- bit_field_ = DeclaresSloppyBlockFunction::update(
- bit_field_, declares_sloppy_block_function);
- }
+ FunctionDeclaration(FunctionLiteral* fun, int pos)
+ : Declaration(pos, kFunctionDeclaration), fun_(fun) {}
FunctionLiteral* fun_;
-
- static const uint8_t kNextBitFieldIndex = DeclaresSloppyBlockFunction::kNext;
};
@@ -977,14 +966,30 @@ class SloppyBlockFunctionStatement final : public Statement {
public:
Statement* statement() const { return statement_; }
void set_statement(Statement* statement) { statement_ = statement; }
+ Scope* scope() const { return var_->scope(); }
+ Variable* var() const { return var_; }
+ Token::Value init() const { return TokenField::decode(bit_field_); }
+ const AstRawString* name() const { return var_->raw_name(); }
+ SloppyBlockFunctionStatement** next() { return &next_; }
private:
friend class AstNodeFactory;
- SloppyBlockFunctionStatement(int pos, Statement* statement)
- : Statement(pos, kSloppyBlockFunctionStatement), statement_(statement) {}
+ class TokenField
+ : public BitField<Token::Value, Statement::kNextBitFieldIndex, 8> {};
+
+ SloppyBlockFunctionStatement(int pos, Variable* var, Token::Value init,
+ Statement* statement)
+ : Statement(pos, kSloppyBlockFunctionStatement),
+ var_(var),
+ statement_(statement),
+ next_(nullptr) {
+ bit_field_ = TokenField::update(bit_field_, init);
+ }
+ Variable* var_;
Statement* statement_;
+ SloppyBlockFunctionStatement* next_;
};
@@ -1495,11 +1500,15 @@ class ArrayLiteral final : public AggregateLiteral {
enum class HoleCheckMode { kRequired, kElided };
+class ThisExpression final : public Expression {
+ private:
+ friend class AstNodeFactory;
+ ThisExpression() : Expression(kNoSourcePosition, kThisExpression) {}
+};
+
class VariableProxy final : public Expression {
public:
- bool IsValidReferenceExpression() const {
- return !is_this() && !is_new_target();
- }
+ bool IsValidReferenceExpression() const { return !is_new_target(); }
Handle<String> name() const { return raw_name()->string(); }
const AstRawString* raw_name() const {
@@ -1520,8 +1529,6 @@ class VariableProxy final : public Expression {
return Scanner::Location(position(), position() + raw_name()->length());
}
- bool is_this() const { return IsThisField::decode(bit_field_); }
-
bool is_assigned() const { return IsAssignedField::decode(bit_field_); }
void set_is_assigned() {
bit_field_ = IsAssignedField::update(bit_field_, true);
@@ -1594,8 +1601,8 @@ class VariableProxy final : public Expression {
: Expression(start_position, kVariableProxy),
raw_name_(name),
next_unresolved_(nullptr) {
- bit_field_ |= IsThisField::encode(variable_kind == THIS_VARIABLE) |
- IsAssignedField::encode(false) |
+ DCHECK_NE(THIS_VARIABLE, variable_kind);
+ bit_field_ |= IsAssignedField::encode(false) |
IsResolvedField::encode(false) |
IsRemovedFromUnresolvedField::encode(false) |
HoleCheckModeField::encode(HoleCheckMode::kElided);
@@ -1603,9 +1610,8 @@ class VariableProxy final : public Expression {
explicit VariableProxy(const VariableProxy* copy_from);
- class IsThisField : public BitField<bool, Expression::kNextBitFieldIndex, 1> {
- };
- class IsAssignedField : public BitField<bool, IsThisField::kNext, 1> {};
+ class IsAssignedField
+ : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
class IsResolvedField : public BitField<bool, IsAssignedField::kNext, 1> {};
class IsRemovedFromUnresolvedField
: public BitField<bool, IsResolvedField::kNext, 1> {};
@@ -2190,8 +2196,6 @@ class FunctionLiteral final : public Expression {
kWrapped,
};
- enum IdType { kIdTypeInvalid = -1, kIdTypeTopLevel = 0 };
-
enum ParameterFlag : uint8_t {
kNoDuplicateParameters,
kHasDuplicateParameters
@@ -2226,7 +2230,7 @@ class FunctionLiteral final : public Expression {
}
bool is_oneshot_iife() const { return OneshotIIFEBit::decode(bit_field_); }
bool is_toplevel() const {
- return function_literal_id() == FunctionLiteral::kIdTypeTopLevel;
+ return function_literal_id() == kFunctionLiteralIdTopLevel;
}
bool is_wrapped() const { return function_type() == kWrapped; }
LanguageMode language_mode() const;
@@ -2251,6 +2255,18 @@ class FunctionLiteral final : public Expression {
return false;
}
+ // We can safely skip the arguments adaptor frame setup even
+ // in case of arguments mismatches for strict mode functions,
+ // as long as there's
+ //
+ // 1. no use of the arguments object (either explicitly or
+ // potentially implicitly via a direct eval() call), and
+ // 2. rest parameters aren't being used in the function.
+ //
+ // See http://bit.ly/v8-faster-calls-with-arguments-mismatch
+ // for the details here (https://crbug.com/v8/8895).
+ bool SafeToSkipArgumentsAdaptor() const;
+
// Returns either name or inferred name as a cstring.
std::unique_ptr<char[]> GetDebugName() const;
@@ -2550,56 +2566,41 @@ class NativeFunctionLiteral final : public Expression {
};
-class ThisFunction final : public Expression {
- private:
- friend class AstNodeFactory;
- explicit ThisFunction(int pos) : Expression(pos, kThisFunction) {}
-};
-
-
class SuperPropertyReference final : public Expression {
public:
- VariableProxy* this_var() const { return this_var_; }
Expression* home_object() const { return home_object_; }
private:
friend class AstNodeFactory;
- SuperPropertyReference(VariableProxy* this_var, Expression* home_object,
- int pos)
- : Expression(pos, kSuperPropertyReference),
- this_var_(this_var),
- home_object_(home_object) {
- DCHECK(this_var->is_this());
+ // We take in ThisExpression* only as a proof that it was accessed.
+ SuperPropertyReference(Expression* home_object, int pos)
+ : Expression(pos, kSuperPropertyReference), home_object_(home_object) {
DCHECK(home_object->IsProperty());
}
- VariableProxy* this_var_;
Expression* home_object_;
};
class SuperCallReference final : public Expression {
public:
- VariableProxy* this_var() const { return this_var_; }
VariableProxy* new_target_var() const { return new_target_var_; }
VariableProxy* this_function_var() const { return this_function_var_; }
private:
friend class AstNodeFactory;
- SuperCallReference(VariableProxy* this_var, VariableProxy* new_target_var,
+ // We take in ThisExpression* only as a proof that it was accessed.
+ SuperCallReference(VariableProxy* new_target_var,
VariableProxy* this_function_var, int pos)
: Expression(pos, kSuperCallReference),
- this_var_(this_var),
new_target_var_(new_target_var),
this_function_var_(this_function_var) {
- DCHECK(this_var->is_this());
DCHECK(new_target_var->raw_name()->IsOneByteEqualTo(".new.target"));
DCHECK(this_function_var->raw_name()->IsOneByteEqualTo(".this_function"));
}
- VariableProxy* this_var_;
VariableProxy* new_target_var_;
VariableProxy* this_function_var_;
};
@@ -2780,6 +2781,7 @@ class AstNodeFactory final {
: zone_(zone),
ast_value_factory_(ast_value_factory),
empty_statement_(new (zone) class EmptyStatement()),
+ this_expression_(new (zone) class ThisExpression()),
failure_expression_(new (zone) class FailureExpression()) {}
AstNodeFactory* ast_node_factory() { return this; }
@@ -2794,10 +2796,8 @@ class AstNodeFactory final {
return new (zone_) NestedVariableDeclaration(scope, pos);
}
- FunctionDeclaration* NewFunctionDeclaration(FunctionLiteral* fun,
- bool is_sloppy_block_function,
- int pos) {
- return new (zone_) FunctionDeclaration(fun, is_sloppy_block_function, pos);
+ FunctionDeclaration* NewFunctionDeclaration(FunctionLiteral* fun, int pos) {
+ return new (zone_) FunctionDeclaration(fun, pos);
}
Block* NewBlock(int capacity, bool ignore_completion_value) {
@@ -2936,12 +2936,18 @@ class AstNodeFactory final {
return empty_statement_;
}
+ class ThisExpression* ThisExpression() {
+ return this_expression_;
+ }
+
class FailureExpression* FailureExpression() {
return failure_expression_;
}
- SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(int pos) {
- return new (zone_) SloppyBlockFunctionStatement(pos, EmptyStatement());
+ SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(
+ int pos, Variable* var, Token::Value init) {
+ return new (zone_)
+ SloppyBlockFunctionStatement(pos, var, init, EmptyStatement());
}
CaseClause* NewCaseClause(Expression* label,
@@ -3143,6 +3149,8 @@ class AstNodeFactory final {
Expression* value,
int pos) {
DCHECK(Token::IsAssignmentOp(op));
+ DCHECK_NOT_NULL(target);
+ DCHECK_NOT_NULL(value);
if (op != Token::INIT && target->IsVariableProxy()) {
target->AsVariableProxy()->set_is_assigned();
@@ -3206,7 +3214,7 @@ class AstNodeFactory final {
FunctionLiteral::kAnonymousExpression,
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kShouldLazyCompile, 0, /* has_braces */ false,
- FunctionLiteral::kIdTypeTopLevel);
+ kFunctionLiteralIdTopLevel);
}
ClassLiteral::Property* NewClassLiteralProperty(
@@ -3242,22 +3250,16 @@ class AstNodeFactory final {
return new (zone_) DoExpression(block, result, pos);
}
- ThisFunction* NewThisFunction(int pos) {
- return new (zone_) ThisFunction(pos);
- }
-
- SuperPropertyReference* NewSuperPropertyReference(VariableProxy* this_var,
- Expression* home_object,
+ SuperPropertyReference* NewSuperPropertyReference(Expression* home_object,
int pos) {
- return new (zone_) SuperPropertyReference(this_var, home_object, pos);
+ return new (zone_) SuperPropertyReference(home_object, pos);
}
- SuperCallReference* NewSuperCallReference(VariableProxy* this_var,
- VariableProxy* new_target_var,
+ SuperCallReference* NewSuperCallReference(VariableProxy* new_target_var,
VariableProxy* this_function_var,
int pos) {
return new (zone_)
- SuperCallReference(this_var, new_target_var, this_function_var, pos);
+ SuperCallReference(new_target_var, this_function_var, pos);
}
EmptyParentheses* NewEmptyParentheses(int pos) {
@@ -3295,6 +3297,7 @@ class AstNodeFactory final {
Zone* zone_;
AstValueFactory* ast_value_factory_;
class EmptyStatement* empty_statement_;
+ class ThisExpression* this_expression_;
class FailureExpression* failure_expression_;
};
diff --git a/chromium/v8/src/ast/modules.cc b/chromium/v8/src/ast/modules.cc
index 0f66ac91ecd..d1be965a4ab 100644
--- a/chromium/v8/src/ast/modules.cc
+++ b/chromium/v8/src/ast/modules.cc
@@ -91,20 +91,11 @@ void ModuleDescriptor::AddStarExport(const AstRawString* module_request,
}
namespace {
-
Handle<Object> ToStringOrUndefined(Isolate* isolate, const AstRawString* s) {
return (s == nullptr)
? Handle<Object>::cast(isolate->factory()->undefined_value())
: Handle<Object>::cast(s->string());
}
-
-const AstRawString* FromStringOrUndefined(Isolate* isolate,
- AstValueFactory* avfactory,
- Handle<Object> object) {
- if (object->IsUndefined(isolate)) return nullptr;
- return avfactory->GetString(Handle<String>::cast(object));
-}
-
} // namespace
Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize(
@@ -117,21 +108,6 @@ Handle<ModuleInfoEntry> ModuleDescriptor::Entry::Serialize(
location.beg_pos, location.end_pos);
}
-ModuleDescriptor::Entry* ModuleDescriptor::Entry::Deserialize(
- Isolate* isolate, AstValueFactory* avfactory,
- Handle<ModuleInfoEntry> entry) {
- Entry* result = new (avfactory->zone()) Entry(Scanner::Location::invalid());
- result->export_name = FromStringOrUndefined(
- isolate, avfactory, handle(entry->export_name(), isolate));
- result->local_name = FromStringOrUndefined(
- isolate, avfactory, handle(entry->local_name(), isolate));
- result->import_name = FromStringOrUndefined(
- isolate, avfactory, handle(entry->import_name(), isolate));
- result->module_request = entry->module_request();
- result->cell_index = entry->cell_index();
- return result;
-}
-
Handle<FixedArray> ModuleDescriptor::SerializeRegularExports(Isolate* isolate,
Zone* zone) const {
// We serialize regular exports in a way that lets us later iterate over their
@@ -183,29 +159,6 @@ Handle<FixedArray> ModuleDescriptor::SerializeRegularExports(Isolate* isolate,
return result;
}
-void ModuleDescriptor::DeserializeRegularExports(
- Isolate* isolate, AstValueFactory* avfactory,
- Handle<ModuleInfo> module_info) {
- for (int i = 0, count = module_info->RegularExportCount(); i < count; ++i) {
- Handle<String> local_name(module_info->RegularExportLocalName(i), isolate);
- int cell_index = module_info->RegularExportCellIndex(i);
- Handle<FixedArray> export_names(module_info->RegularExportExportNames(i),
- isolate);
-
- for (int j = 0, length = export_names->length(); j < length; ++j) {
- Handle<String> export_name(String::cast(export_names->get(j)), isolate);
-
- Entry* entry =
- new (avfactory->zone()) Entry(Scanner::Location::invalid());
- entry->local_name = avfactory->GetString(local_name);
- entry->export_name = avfactory->GetString(export_name);
- entry->cell_index = cell_index;
-
- AddRegularExport(entry);
- }
- }
-}
-
void ModuleDescriptor::MakeIndirectExportsExplicit(Zone* zone) {
for (auto it = regular_exports_.begin(); it != regular_exports_.end();) {
Entry* entry = it->second;
diff --git a/chromium/v8/src/ast/modules.h b/chromium/v8/src/ast/modules.h
index 44e86dce42b..ebc3e3a2884 100644
--- a/chromium/v8/src/ast/modules.h
+++ b/chromium/v8/src/ast/modules.h
@@ -107,12 +107,7 @@ class ModuleDescriptor : public ZoneObject {
module_request(-1),
cell_index(0) {}
- // (De-)serialization support.
- // Note that the location value is not preserved as it's only needed by the
- // parser. (A Deserialize'd entry has an invalid location.)
Handle<ModuleInfoEntry> Serialize(Isolate* isolate) const;
- static Entry* Deserialize(Isolate* isolate, AstValueFactory* avfactory,
- Handle<ModuleInfoEntry> entry);
};
enum CellIndexKind { kInvalid, kExport, kImport };
@@ -191,8 +186,6 @@ class ModuleDescriptor : public ZoneObject {
Handle<FixedArray> SerializeRegularExports(Isolate* isolate,
Zone* zone) const;
- void DeserializeRegularExports(Isolate* isolate, AstValueFactory* avfactory,
- Handle<ModuleInfo> module_info);
private:
ModuleRequestMap module_requests_;
diff --git a/chromium/v8/src/ast/prettyprinter.cc b/chromium/v8/src/ast/prettyprinter.cc
index a53d07064d5..c7f6e3d9f03 100644
--- a/chromium/v8/src/ast/prettyprinter.cc
+++ b/chromium/v8/src/ast/prettyprinter.cc
@@ -12,6 +12,7 @@
#include "src/globals.h"
#include "src/objects-inl.h"
#include "src/string-builder-inl.h"
+#include "src/vector.h"
namespace v8 {
namespace internal {
@@ -500,8 +501,7 @@ void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) {
Print(")");
}
-void CallPrinter::VisitThisFunction(ThisFunction* node) {}
-
+void CallPrinter::VisitThisExpression(ThisExpression* node) { Print("this"); }
void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {}
@@ -1391,11 +1391,10 @@ void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) {
Visit(node->argument());
}
-void AstPrinter::VisitThisFunction(ThisFunction* node) {
- IndentedScope indent(this, "THIS-FUNCTION", node->position());
+void AstPrinter::VisitThisExpression(ThisExpression* node) {
+ IndentedScope indent(this, "THIS-EXPRESSION", node->position());
}
-
void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {
IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position());
}
diff --git a/chromium/v8/src/ast/prettyprinter.h b/chromium/v8/src/ast/prettyprinter.h
index e6f27669158..e1efdbfb886 100644
--- a/chromium/v8/src/ast/prettyprinter.h
+++ b/chromium/v8/src/ast/prettyprinter.h
@@ -8,6 +8,7 @@
#include "src/allocation.h"
#include "src/ast/ast.h"
#include "src/base/compiler-specific.h"
+#include "src/function-kind.h"
namespace v8 {
namespace internal {
diff --git a/chromium/v8/src/ast/scopes.cc b/chromium/v8/src/ast/scopes.cc
index 28869cd94ae..e625865a110 100644
--- a/chromium/v8/src/ast/scopes.cc
+++ b/chromium/v8/src/ast/scopes.cc
@@ -83,28 +83,6 @@ Variable* VariableMap::Lookup(const AstRawString* name) {
return nullptr;
}
-void SloppyBlockFunctionMap::Delegate::set_statement(Statement* statement) {
- if (statement_ != nullptr) {
- statement_->set_statement(statement);
- }
-}
-
-SloppyBlockFunctionMap::SloppyBlockFunctionMap(Zone* zone)
- : ZoneHashMap(8, ZoneAllocationPolicy(zone)), count_(0) {}
-
-void SloppyBlockFunctionMap::Declare(Zone* zone, const AstRawString* name,
- Scope* scope,
- SloppyBlockFunctionStatement* statement) {
- auto* delegate = new (zone) Delegate(scope, statement, count_++);
- // AstRawStrings are unambiguous, i.e., the same string is always represented
- // by the same AstRawString*.
- Entry* p =
- ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->Hash(),
- ZoneAllocationPolicy(zone));
- delegate->set_next(static_cast<SloppyBlockFunctionMap::Delegate*>(p->value));
- p->value = delegate;
-}
-
// ----------------------------------------------------------------------------
// Implementation of Scope
@@ -132,10 +110,8 @@ DeclarationScope::DeclarationScope(Zone* zone,
: Scope(zone), function_kind_(kNormalFunction), params_(4, zone) {
DCHECK_EQ(scope_type_, SCRIPT_SCOPE);
SetDefaults();
-
- // Make sure that if we don't find the global 'this', it won't be declared as
- // a regular dynamic global by predeclaring it with the right variable kind.
- DeclareDynamicGlobal(ast_value_factory->this_string(), THIS_VARIABLE, this);
+ receiver_ = DeclareDynamicGlobal(ast_value_factory->this_string(),
+ THIS_VARIABLE, this);
}
DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope,
@@ -149,59 +125,19 @@ DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope,
}
ModuleScope::ModuleScope(DeclarationScope* script_scope,
- AstValueFactory* ast_value_factory)
- : DeclarationScope(ast_value_factory->zone(), script_scope, MODULE_SCOPE,
- kModule) {
- Zone* zone = ast_value_factory->zone();
- module_descriptor_ = new (zone) ModuleDescriptor(zone);
+ AstValueFactory* avfactory)
+ : DeclarationScope(avfactory->zone(), script_scope, MODULE_SCOPE, kModule),
+ module_descriptor_(new (avfactory->zone())
+ ModuleDescriptor(avfactory->zone())) {
set_language_mode(LanguageMode::kStrict);
- DeclareThis(ast_value_factory);
+ DeclareThis(avfactory);
}
ModuleScope::ModuleScope(Isolate* isolate, Handle<ScopeInfo> scope_info,
AstValueFactory* avfactory)
- : DeclarationScope(avfactory->zone(), MODULE_SCOPE, scope_info) {
- Zone* zone = avfactory->zone();
- Handle<ModuleInfo> module_info(scope_info->ModuleDescriptorInfo(), isolate);
-
+ : DeclarationScope(avfactory->zone(), MODULE_SCOPE, scope_info),
+ module_descriptor_(nullptr) {
set_language_mode(LanguageMode::kStrict);
- module_descriptor_ = new (zone) ModuleDescriptor(zone);
-
- // Deserialize special exports.
- Handle<FixedArray> special_exports(module_info->special_exports(), isolate);
- for (int i = 0, n = special_exports->length(); i < n; ++i) {
- Handle<ModuleInfoEntry> serialized_entry(
- ModuleInfoEntry::cast(special_exports->get(i)), isolate);
- module_descriptor_->AddSpecialExport(
- ModuleDescriptor::Entry::Deserialize(isolate, avfactory,
- serialized_entry),
- avfactory->zone());
- }
-
- // Deserialize regular exports.
- module_descriptor_->DeserializeRegularExports(isolate, avfactory,
- module_info);
-
- // Deserialize namespace imports.
- Handle<FixedArray> namespace_imports(module_info->namespace_imports(),
- isolate);
- for (int i = 0, n = namespace_imports->length(); i < n; ++i) {
- Handle<ModuleInfoEntry> serialized_entry(
- ModuleInfoEntry::cast(namespace_imports->get(i)), isolate);
- module_descriptor_->AddNamespaceImport(
- ModuleDescriptor::Entry::Deserialize(isolate, avfactory,
- serialized_entry),
- avfactory->zone());
- }
-
- // Deserialize regular imports.
- Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate);
- for (int i = 0, n = regular_imports->length(); i < n; ++i) {
- Handle<ModuleInfoEntry> serialized_entry(
- ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
- module_descriptor_->AddRegularImport(ModuleDescriptor::Entry::Deserialize(
- isolate, avfactory, serialized_entry));
- }
}
Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info)
@@ -262,8 +198,11 @@ void DeclarationScope::SetDefaults() {
force_eager_compilation_ = false;
has_arguments_parameter_ = false;
scope_uses_super_property_ = false;
+ has_checked_syntax_ = false;
+ has_this_reference_ = false;
+ has_this_declaration_ =
+ (is_function_scope() && !is_arrow_scope()) || is_module_scope();
has_rest_ = false;
- sloppy_block_function_map_ = nullptr;
receiver_ = nullptr;
new_target_ = nullptr;
function_ = nullptr;
@@ -319,10 +258,6 @@ bool Scope::HasSimpleParameters() {
return !scope->is_function_scope() || scope->has_simple_parameters();
}
-bool DeclarationScope::ShouldEagerCompile() const {
- return force_eager_compilation_ || should_eager_compile_;
-}
-
void DeclarationScope::set_should_eager_compile() {
should_eager_compile_ = !was_lazily_parsed_;
}
@@ -359,15 +294,16 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
Scope* outer_scope = nullptr;
while (!scope_info.is_null()) {
if (scope_info->scope_type() == WITH_SCOPE) {
- // For scope analysis, debug-evaluate is equivalent to a with scope.
- outer_scope =
- new (zone) Scope(zone, WITH_SCOPE, handle(scope_info, isolate));
-
- // TODO(yangguo): Remove once debug-evaluate properly keeps track of the
- // function scope in which we are evaluating.
if (scope_info->IsDebugEvaluateScope()) {
+ outer_scope = new (zone)
+ DeclarationScope(zone, FUNCTION_SCOPE, handle(scope_info, isolate));
outer_scope->set_is_debug_evaluate_scope();
+ } else {
+ // For scope analysis, debug-evaluate is equivalent to a with scope.
+ outer_scope =
+ new (zone) Scope(zone, WITH_SCOPE, handle(scope_info, isolate));
}
+
} else if (scope_info->scope_type() == SCRIPT_SCOPE) {
// If we reach a script scope, it's the outermost scope. Install the
// scope info of this script context onto the existing script scope to
@@ -455,19 +391,9 @@ const ModuleScope* Scope::AsModuleScope() const {
return static_cast<const ModuleScope*>(this);
}
-int Scope::num_parameters() const {
- return is_declaration_scope() ? AsDeclarationScope()->num_parameters() : 0;
-}
-
void DeclarationScope::DeclareSloppyBlockFunction(
- const AstRawString* name, Scope* scope,
- SloppyBlockFunctionStatement* statement) {
- if (sloppy_block_function_map_ == nullptr) {
- sloppy_block_function_map_ =
- new (zone()->New(sizeof(SloppyBlockFunctionMap)))
- SloppyBlockFunctionMap(zone());
- }
- sloppy_block_function_map_->Declare(zone(), name, scope, statement);
+ SloppyBlockFunctionStatement* sloppy_block_function) {
+ sloppy_block_functions_.Add(sloppy_block_function);
}
void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
@@ -477,8 +403,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_);
DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_);
- SloppyBlockFunctionMap* map = sloppy_block_function_map();
- if (map == nullptr) return;
+ if (sloppy_block_functions_.is_empty()) return;
// In case of complex parameters the current scope is the body scope and the
// parameters are stored in the outer scope.
@@ -486,14 +411,17 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
DCHECK(parameter_scope->is_function_scope() || is_eval_scope() ||
is_script_scope());
- // The declarations need to be added in the order they were seen,
- // so accumulate declared names sorted by index.
- ZoneMap<int, const AstRawString*> names_to_declare(zone());
+ DeclarationScope* decl_scope = this;
+ while (decl_scope->is_eval_scope()) {
+ decl_scope = decl_scope->outer_scope()->GetDeclarationScope();
+ }
+ Scope* outer_scope = decl_scope->outer_scope();
// For each variable which is used as a function declaration in a sloppy
// block,
- for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) {
- const AstRawString* name = static_cast<AstRawString*>(p->key);
+ for (SloppyBlockFunctionStatement* sloppy_block_function :
+ sloppy_block_functions_) {
+ const AstRawString* name = sloppy_block_function->name();
// If the variable wouldn't conflict with a lexical declaration
// or parameter,
@@ -504,79 +432,52 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
continue;
}
- bool declaration_queued = false;
-
- // Write in assignments to var for each block-scoped function declaration
- auto delegates = static_cast<SloppyBlockFunctionMap::Delegate*>(p->value);
-
- DeclarationScope* decl_scope = this;
- while (decl_scope->is_eval_scope()) {
- decl_scope = decl_scope->outer_scope()->GetDeclarationScope();
- }
- Scope* outer_scope = decl_scope->outer_scope();
-
- for (SloppyBlockFunctionMap::Delegate* delegate = delegates;
- delegate != nullptr; delegate = delegate->next()) {
- // Check if there's a conflict with a lexical declaration
- Scope* query_scope = delegate->scope()->outer_scope();
- Variable* var = nullptr;
- bool should_hoist = true;
-
- // Note that we perform this loop for each delegate named 'name',
- // which may duplicate work if those delegates share scopes.
- // It is not sufficient to just do a Lookup on query_scope: for
- // example, that does not prevent hoisting of the function in
- // `{ let e; try {} catch (e) { function e(){} } }`
- do {
- var = query_scope->LookupInScopeOrScopeInfo(name);
- if (var != nullptr && IsLexicalVariableMode(var->mode())) {
- should_hoist = false;
- break;
- }
- query_scope = query_scope->outer_scope();
- } while (query_scope != outer_scope);
-
- if (!should_hoist) continue;
-
- if (!declaration_queued) {
- declaration_queued = true;
- names_to_declare.insert({delegate->index(), name});
- }
-
- if (factory) {
- DCHECK(!is_being_lazily_parsed_);
- int pos = delegate->position();
- Assignment* assignment = factory->NewAssignment(
- Token::ASSIGN, NewUnresolved(factory, name, pos),
- delegate->scope()->NewUnresolved(factory, name, pos), pos);
- assignment->set_lookup_hoisting_mode(LookupHoistingMode::kLegacySloppy);
- Statement* statement = factory->NewExpressionStatement(assignment, pos);
- delegate->set_statement(statement);
+ // Check if there's a conflict with a lexical declaration
+ Scope* query_scope = sloppy_block_function->scope()->outer_scope();
+ Variable* var = nullptr;
+ bool should_hoist = true;
+
+ // It is not sufficient to just do a Lookup on query_scope: for
+ // example, that does not prevent hoisting of the function in
+ // `{ let e; try {} catch (e) { function e(){} } }`
+ do {
+ var = query_scope->LookupInScopeOrScopeInfo(name);
+ if (var != nullptr && IsLexicalVariableMode(var->mode())) {
+ should_hoist = false;
+ break;
}
- }
- }
+ query_scope = query_scope->outer_scope();
+ } while (query_scope != outer_scope);
- if (names_to_declare.empty()) return;
+ if (!should_hoist) continue;
- for (const auto& index_and_name : names_to_declare) {
- const AstRawString* name = index_and_name.second;
if (factory) {
DCHECK(!is_being_lazily_parsed_);
- VariableProxy* proxy = factory->NewVariableProxy(name, NORMAL_VARIABLE);
- auto declaration = factory->NewVariableDeclaration(kNoSourcePosition);
+ int pos = sloppy_block_function->position();
+ bool ok = true;
bool was_added;
+ auto declaration = factory->NewVariableDeclaration(pos);
// Based on the preceding checks, it doesn't matter what we pass as
// sloppy_mode_block_scope_function_redefinition.
- bool ok = true;
- DeclareVariable(declaration, proxy, VariableMode::kVar, NORMAL_VARIABLE,
- Variable::DefaultInitializationFlag(VariableMode::kVar),
- &was_added, nullptr, &ok);
+ Variable* var = DeclareVariable(
+ declaration, name, pos, VariableMode::kVar, NORMAL_VARIABLE,
+ Variable::DefaultInitializationFlag(VariableMode::kVar), &was_added,
+ nullptr, &ok);
DCHECK(ok);
+ VariableProxy* source =
+ factory->NewVariableProxy(sloppy_block_function->var());
+ VariableProxy* target = factory->NewVariableProxy(var);
+ Assignment* assignment = factory->NewAssignment(
+ sloppy_block_function->init(), target, source, pos);
+ assignment->set_lookup_hoisting_mode(LookupHoistingMode::kLegacySloppy);
+ Statement* statement = factory->NewExpressionStatement(assignment, pos);
+ sloppy_block_function->set_statement(statement);
} else {
DCHECK(is_being_lazily_parsed_);
bool was_added;
Variable* var = DeclareVariableName(name, VariableMode::kVar, &was_added);
- var->set_maybe_assigned();
+ if (sloppy_block_function->init() == Token::ASSIGN)
+ var->set_maybe_assigned();
}
}
}
@@ -605,8 +506,7 @@ bool DeclarationScope::Analyze(ParseInfo* info) {
// 1) top-level code,
// 2) a function/eval/module on the top-level
// 3) a function/eval in a scope that was already resolved.
- DCHECK(scope->scope_type() == SCRIPT_SCOPE ||
- scope->outer_scope()->scope_type() == SCRIPT_SCOPE ||
+ DCHECK(scope->is_script_scope() || scope->outer_scope()->is_script_scope() ||
scope->outer_scope()->already_resolved_);
// The outer scope is never lazy.
@@ -633,20 +533,16 @@ bool DeclarationScope::Analyze(ParseInfo* info) {
}
void DeclarationScope::DeclareThis(AstValueFactory* ast_value_factory) {
- DCHECK(!already_resolved_);
- DCHECK(is_declaration_scope());
DCHECK(has_this_declaration());
bool derived_constructor = IsDerivedConstructor(function_kind_);
- bool was_added;
- Variable* var =
- Declare(zone(), ast_value_factory->this_string(),
- derived_constructor ? VariableMode::kConst : VariableMode::kVar,
- THIS_VARIABLE,
- derived_constructor ? kNeedsInitialization : kCreatedInitialized,
- kNotAssigned, &was_added);
- DCHECK(was_added);
- receiver_ = var;
+
+ receiver_ = new (zone())
+ Variable(this, ast_value_factory->this_string(),
+ derived_constructor ? VariableMode::kConst : VariableMode::kVar,
+ THIS_VARIABLE,
+ derived_constructor ? kNeedsInitialization : kCreatedInitialized,
+ kNotAssigned);
}
void DeclarationScope::DeclareArguments(AstValueFactory* ast_value_factory) {
@@ -844,8 +740,9 @@ void Scope::ReplaceOuterScope(Scope* outer) {
Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
DCHECK(!scope_info_.is_null());
DCHECK_NULL(cache->variables_.Lookup(name));
+ DisallowHeapAllocation no_gc;
- Handle<String> name_handle = name->string();
+ String name_handle = *name->string();
// The Scope is backed up by ScopeInfo. This means it cannot operate in a
// heap-independent mode, and all strings must be internalized immediately. So
// it's ok to get the Handle<String> here.
@@ -859,12 +756,12 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
{
location = VariableLocation::CONTEXT;
- index = ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode,
+ index = ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode,
&init_flag, &maybe_assigned_flag);
found = index >= 0;
}
- if (!found && scope_type() == MODULE_SCOPE) {
+ if (!found && is_module_scope()) {
location = VariableLocation::MODULE;
index = scope_info_->ModuleIndex(name_handle, &mode, &init_flag,
&maybe_assigned_flag);
@@ -872,7 +769,7 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
}
if (!found) {
- index = scope_info_->FunctionContextSlotIndex(*name_handle);
+ index = scope_info_->FunctionContextSlotIndex(name_handle);
if (index < 0) return nullptr; // Nowhere found.
Variable* var = AsDeclarationScope()->DeclareFunctionVar(name, cache);
DCHECK_EQ(VariableMode::kConst, var->mode());
@@ -880,18 +777,14 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
return cache->variables_.Lookup(name);
}
- VariableKind kind = NORMAL_VARIABLE;
- if (location == VariableLocation::CONTEXT &&
- index == scope_info_->ReceiverContextSlotIndex()) {
- kind = THIS_VARIABLE;
+ if (!is_module_scope()) {
+ DCHECK_NE(index, scope_info_->ReceiverContextSlotIndex());
}
- // TODO(marja, rossberg): Correctly declare FUNCTION, CLASS, NEW_TARGET, and
- // ARGUMENTS bindings as their corresponding VariableKind.
bool was_added;
Variable* var =
- cache->variables_.Declare(zone(), this, name, mode, kind, init_flag,
- maybe_assigned_flag, &was_added);
+ cache->variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
+ init_flag, maybe_assigned_flag, &was_added);
DCHECK(was_added);
var->AllocateTo(location, index);
return var;
@@ -953,15 +846,29 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
mode == VariableMode::kVar || mode == VariableMode::kLet ||
mode == VariableMode::kConst);
DCHECK(!GetDeclarationScope()->was_lazily_parsed());
- return Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added);
+ Variable* var =
+ Declare(zone(), name, mode, kind, init_flag, kNotAssigned, was_added);
+
+ // Pessimistically assume that top-level variables will be assigned and used.
+ //
+ // Top-level variables in a script can be accessed by other scripts or even
+ // become global properties. While this does not apply to top-level variables
+ // in a module (assuming they are not exported), we must still mark these as
+ // assigned because they might be accessed by a lazily parsed top-level
+ // function, which, for efficiency, we preparse without variable tracking.
+ if (is_script_scope() || is_module_scope()) {
+ if (mode != VariableMode::kConst) var->set_maybe_assigned();
+ var->set_is_used();
+ }
+
+ return var;
}
-// TODO(leszeks): Avoid passing the proxy into here, passing the raw_name alone
-// instead.
Variable* Scope::DeclareVariable(
- Declaration* declaration, VariableProxy* proxy, VariableMode mode,
- VariableKind kind, InitializationFlag init, bool* was_added,
- bool* sloppy_mode_block_scope_function_redefinition, bool* ok) {
+ Declaration* declaration, const AstRawString* name, int pos,
+ VariableMode mode, VariableKind kind, InitializationFlag init,
+ bool* was_added, bool* sloppy_mode_block_scope_function_redefinition,
+ bool* ok) {
DCHECK(IsDeclaredVariableMode(mode));
DCHECK(!already_resolved_);
DCHECK(!GetDeclarationScope()->is_being_lazily_parsed());
@@ -969,7 +876,7 @@ Variable* Scope::DeclareVariable(
if (mode == VariableMode::kVar && !is_declaration_scope()) {
return GetDeclarationScope()->DeclareVariable(
- declaration, proxy, mode, kind, init, was_added,
+ declaration, name, pos, mode, kind, init, was_added,
sloppy_mode_block_scope_function_redefinition, ok);
}
DCHECK(!is_catch_scope());
@@ -977,19 +884,7 @@ Variable* Scope::DeclareVariable(
DCHECK(is_declaration_scope() ||
(IsLexicalVariableMode(mode) && is_block_scope()));
- DCHECK_NOT_NULL(proxy->raw_name());
- const AstRawString* name = proxy->raw_name();
-
- // Pessimistically assume that top-level variables will be assigned.
- //
- // Top-level variables in a script can be accessed by other scripts or even
- // become global properties. While this does not apply to top-level variables
- // in a module (assuming they are not exported), we must still mark these as
- // assigned because they might be accessed by a lazily parsed top-level
- // function, which, for efficiency, we preparse without variable tracking.
- if (is_script_scope() || is_module_scope()) {
- if (mode != VariableMode::kConst) proxy->set_is_assigned();
- }
+ DCHECK_NOT_NULL(name);
Variable* var = LookupLocal(name);
// Declare the variable in the declaration scope.
@@ -1002,7 +897,9 @@ Variable* Scope::DeclareVariable(
// The proxy is bound to a lookup variable to force a dynamic declaration
// using the DeclareEvalVar or DeclareEvalFunction runtime functions.
DCHECK_EQ(NORMAL_VARIABLE, kind);
- var = NonLocal(proxy->raw_name(), VariableMode::kDynamic);
+ var = NonLocal(name, VariableMode::kDynamic);
+ // Mark the var as used in case anyone outside the eval wants to use it.
+ var->set_is_used();
} else {
// Declare the name.
var = DeclareLocal(name, mode, kind, was_added, init);
@@ -1029,16 +926,9 @@ Variable* Scope::DeclareVariable(
// In harmony we treat re-declarations as early errors. See ES5 16 for a
// definition of early errors.
//
- // Allow duplicate function decls for web compat, see bug 4693. If the
- // duplication is allowed, then the var will show up in the
- // SloppyBlockFunctionMap.
- SloppyBlockFunctionMap* map =
- GetDeclarationScope()->sloppy_block_function_map();
- *ok =
- map != nullptr && declaration->IsFunctionDeclaration() &&
- declaration->AsFunctionDeclaration()
- ->declares_sloppy_block_function() &&
- map->Lookup(const_cast<AstRawString*>(name), name->Hash()) != nullptr;
+ // Allow duplicate function decls for web compat, see bug 4693.
+ *ok = var->is_sloppy_block_function() &&
+ kind == SLOPPY_BLOCK_FUNCTION_VARIABLE;
*sloppy_mode_block_scope_function_redefinition = *ok;
}
}
@@ -1055,7 +945,6 @@ Variable* Scope::DeclareVariable(
// lead to repeated DeclareEvalVar or DeclareEvalFunction calls.
decls_.Add(declaration);
declaration->set_var(var);
- proxy->BindTo(var);
return var;
}
@@ -1079,12 +968,16 @@ Variable* Scope::DeclareVariableName(const AstRawString* name,
Variable* var = DeclareLocal(name, mode, kind, was_added);
if (!*was_added) {
if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(var->mode())) {
- // Duplicate functions are allowed in the sloppy mode, but if this is not
- // a function declaration, it's an error. This is an error PreParser
- // hasn't previously detected.
- return nullptr;
+ if (!var->is_sloppy_block_function() ||
+ kind != SLOPPY_BLOCK_FUNCTION_VARIABLE) {
+ // Duplicate functions are allowed in the sloppy mode, but if this is
+ // not a function declaration, it's an error. This is an error PreParser
+ // hasn't previously detected.
+ return nullptr;
+ }
+ // Sloppy block function redefinition.
}
- if (mode == VariableMode::kVar) var->set_maybe_assigned();
+ var->set_maybe_assigned();
}
var->set_is_used();
return var;
@@ -1142,36 +1035,61 @@ Variable* Scope::NewTemporary(const AstRawString* name,
return var;
}
-Declaration* Scope::CheckConflictingVarDeclarations() {
+Declaration* DeclarationScope::CheckConflictingVarDeclarations() {
+ if (has_checked_syntax_) return nullptr;
for (Declaration* decl : decls_) {
// Lexical vs lexical conflicts within the same scope have already been
// captured in Parser::Declare. The only conflicts we still need to check
// are lexical vs nested var.
- Scope* current = nullptr;
if (decl->IsVariableDeclaration() &&
decl->AsVariableDeclaration()->AsNested() != nullptr) {
- current = decl->AsVariableDeclaration()->AsNested()->scope();
- } else if (is_eval_scope() && is_sloppy(language_mode())) {
- if (IsLexicalVariableMode(decl->var()->mode())) continue;
- current = outer_scope_;
+ Scope* current = decl->AsVariableDeclaration()->AsNested()->scope();
+ DCHECK(decl->var()->mode() == VariableMode::kVar ||
+ decl->var()->mode() == VariableMode::kDynamic);
+ // Iterate through all scopes until the declaration scope.
+ do {
+ // There is a conflict if there exists a non-VAR binding.
+ if (current->is_catch_scope()) {
+ current = current->outer_scope();
+ continue;
+ }
+ Variable* other_var = current->LookupLocal(decl->var()->raw_name());
+ if (other_var != nullptr) {
+ DCHECK(IsLexicalVariableMode(other_var->mode()));
+ return decl;
+ }
+ current = current->outer_scope();
+ } while (current != this);
}
- if (current == nullptr) continue;
- DCHECK(decl->var()->mode() == VariableMode::kVar ||
- decl->var()->mode() == VariableMode::kDynamic);
+ }
+
+ if (V8_LIKELY(!is_eval_scope())) return nullptr;
+ if (!is_sloppy(language_mode())) return nullptr;
+
+ // Var declarations in sloppy eval are hoisted to the first non-eval
+ // declaration scope. Check for conflicts between the eval scope that
+ // declaration scope.
+ Scope* end = this;
+ do {
+ end = end->outer_scope_->GetDeclarationScope();
+ } while (end->is_eval_scope());
+ end = end->outer_scope_;
+
+ for (Declaration* decl : decls_) {
+ if (IsLexicalVariableMode(decl->var()->mode())) continue;
+ Scope* current = outer_scope_;
// Iterate through all scopes until and including the declaration scope.
- while (true) {
- // There is a conflict if there exists a non-VAR binding.
+ do {
+ // There is a conflict if there exists a non-VAR binding up to the
+ // declaration scope in which this sloppy-eval runs.
Variable* other_var =
current->LookupInScopeOrScopeInfo(decl->var()->raw_name());
if (other_var != nullptr && IsLexicalVariableMode(other_var->mode())) {
+ DCHECK(!current->is_catch_scope());
return decl;
}
- if (current->is_declaration_scope() &&
- !(current->is_eval_scope() && is_sloppy(current->language_mode()))) {
- break;
- }
current = current->outer_scope();
- }
+ } while (current != end);
}
return nullptr;
}
@@ -1188,6 +1106,21 @@ const AstRawString* Scope::FindVariableDeclaredIn(Scope* scope,
return nullptr;
}
+void DeclarationScope::DeserializeReceiver(AstValueFactory* ast_value_factory) {
+ if (is_script_scope()) {
+ DCHECK_NOT_NULL(receiver_);
+ return;
+ }
+ DCHECK(has_this_declaration());
+ DeclareThis(ast_value_factory);
+ if (is_debug_evaluate_scope()) {
+ receiver_->AllocateTo(VariableLocation::LOOKUP, -1);
+ } else {
+ receiver_->AllocateTo(VariableLocation::CONTEXT,
+ scope_info_->ReceiverContextSlotIndex());
+ }
+}
+
bool DeclarationScope::AllocateVariables(ParseInfo* info) {
// Module variables must be allocated before variable resolution
// to ensure that UpdateNeedsHoleCheck() can detect import variables.
@@ -1197,11 +1130,28 @@ bool DeclarationScope::AllocateVariables(ParseInfo* info) {
DCHECK(info->pending_error_handler()->has_pending_error());
return false;
}
- AllocateVariablesRecursively();
+
+ // // Don't allocate variables of preparsed scopes.
+ if (!was_lazily_parsed()) AllocateVariablesRecursively();
return true;
}
+bool Scope::HasThisReference() const {
+ if (is_declaration_scope() && AsDeclarationScope()->has_this_reference()) {
+ return true;
+ }
+
+ for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
+ if (!scope->is_declaration_scope() ||
+ !scope->AsDeclarationScope()->has_this_declaration()) {
+ if (scope->HasThisReference()) return true;
+ }
+ }
+
+ return false;
+}
+
bool Scope::AllowsLazyParsingWithoutUnresolvedVariables(
const Scope* outer) const {
// If none of the outer scopes need to decide whether to context allocate
@@ -1227,7 +1177,10 @@ bool Scope::AllowsLazyParsingWithoutUnresolvedVariables(
}
bool DeclarationScope::AllowsLazyCompilation() const {
- return !force_eager_compilation_;
+ // Functions which force eager compilation and class member initializer
+ // functions are not lazily compilable.
+ return !force_eager_compilation_ &&
+ !IsClassMembersInitializerFunction(function_kind());
}
int Scope::ContextChainLength(Scope* scope) const {
@@ -1294,9 +1247,9 @@ bool Scope::ShouldBanArguments() {
DeclarationScope* Scope::GetReceiverScope() {
Scope* scope = this;
- while (!scope->is_script_scope() &&
- (!scope->is_function_scope() ||
- scope->AsDeclarationScope()->is_arrow_scope())) {
+ while (!scope->is_declaration_scope() ||
+ (!scope->is_script_scope() &&
+ !scope->AsDeclarationScope()->has_this_declaration())) {
scope = scope->outer_scope();
}
return scope->AsDeclarationScope();
@@ -1310,77 +1263,103 @@ Scope* Scope::GetOuterScopeWithContext() {
return scope;
}
-void Scope::CollectNonLocals(DeclarationScope* max_outer_scope,
- Isolate* isolate, ParseInfo* info,
- Handle<StringSet>* non_locals) {
- // Module variables must be allocated before variable resolution
- // to ensure that UpdateNeedsHoleCheck() can detect import variables.
- if (is_module_scope()) AsModuleScope()->AllocateModuleVariables();
+namespace {
+bool WasLazilyParsed(Scope* scope) {
+ return scope->is_declaration_scope() &&
+ scope->AsDeclarationScope()->was_lazily_parsed();
+}
- // Lazy parsed declaration scopes are already partially analyzed. If there are
- // unresolved references remaining, they just need to be resolved in outer
- // scopes.
- Scope* lookup =
- is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()
- ? outer_scope()
- : this;
-
- for (VariableProxy* proxy : unresolved_list_) {
- DCHECK(!proxy->is_resolved());
- Variable* var =
- Lookup<kParsedScope>(proxy, lookup, max_outer_scope->outer_scope());
- if (var == nullptr) {
- *non_locals = StringSet::Add(isolate, *non_locals, proxy->name());
+} // namespace
+
+template <typename FunctionType>
+void Scope::ForEach(FunctionType callback) {
+ Scope* scope = this;
+ while (true) {
+ Iteration iteration = callback(scope);
+ // Try to descend into inner scopes first.
+ if ((iteration == Iteration::kDescend) && scope->inner_scope_ != nullptr) {
+ scope = scope->inner_scope_;
} else {
- // In this case we need to leave scopes in a way that they can be
- // allocated. If we resolved variables from lazy parsed scopes, we need
- // to context allocate the var.
- ResolveTo(info, proxy, var);
- if (!var->is_dynamic() && lookup != this) var->ForceContextAllocation();
+ // Find the next outer scope with a sibling.
+ while (scope->sibling_ == nullptr) {
+ if (scope == this) return;
+ scope = scope->outer_scope_;
+ }
+ if (scope == this) return;
+ scope = scope->sibling_;
}
}
+}
- // Clear unresolved_list_ as it's in an inconsistent state.
- unresolved_list_.Clear();
+void Scope::CollectNonLocals(DeclarationScope* max_outer_scope,
+ Isolate* isolate, ParseInfo* info,
+ Handle<StringSet>* non_locals) {
+ this->ForEach([max_outer_scope, isolate, info, non_locals](Scope* scope) {
+ // Module variables must be allocated before variable resolution
+ // to ensure that UpdateNeedsHoleCheck() can detect import variables.
+ if (scope->is_module_scope()) {
+ scope->AsModuleScope()->AllocateModuleVariables();
+ }
- for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
- scope->CollectNonLocals(max_outer_scope, isolate, info, non_locals);
- }
+ // Lazy parsed declaration scopes are already partially analyzed. If there
+ // are unresolved references remaining, they just need to be resolved in
+ // outer scopes.
+ Scope* lookup = WasLazilyParsed(scope) ? scope->outer_scope() : scope;
+
+ for (VariableProxy* proxy : scope->unresolved_list_) {
+ DCHECK(!proxy->is_resolved());
+ Variable* var =
+ Lookup<kParsedScope>(proxy, lookup, max_outer_scope->outer_scope());
+ if (var == nullptr) {
+ *non_locals = StringSet::Add(isolate, *non_locals, proxy->name());
+ } else {
+ // In this case we need to leave scopes in a way that they can be
+ // allocated. If we resolved variables from lazy parsed scopes, we need
+ // to context allocate the var.
+ scope->ResolveTo(info, proxy, var);
+ if (!var->is_dynamic() && lookup != scope)
+ var->ForceContextAllocation();
+ }
+ }
+
+ // Clear unresolved_list_ as it's in an inconsistent state.
+ scope->unresolved_list_.Clear();
+ return Iteration::kDescend;
+ });
}
void Scope::AnalyzePartially(DeclarationScope* max_outer_scope,
AstNodeFactory* ast_node_factory,
UnresolvedList* new_unresolved_list) {
- DCHECK_IMPLIES(is_declaration_scope(),
- !AsDeclarationScope()->was_lazily_parsed());
-
- for (VariableProxy* proxy = unresolved_list_.first(); proxy != nullptr;
- proxy = proxy->next_unresolved()) {
- DCHECK(!proxy->is_resolved());
- Variable* var =
- Lookup<kParsedScope>(proxy, this, max_outer_scope->outer_scope());
- if (var == nullptr) {
- // Don't copy unresolved references to the script scope, unless it's a
- // reference to a private name or method. In that case keep it so we
- // can fail later.
- if (!max_outer_scope->outer_scope()->is_script_scope() ||
- proxy->IsPrivateName()) {
- VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
- new_unresolved_list->Add(copy);
+ this->ForEach([max_outer_scope, ast_node_factory,
+ new_unresolved_list](Scope* scope) {
+ DCHECK_IMPLIES(scope->is_declaration_scope(),
+ !scope->AsDeclarationScope()->was_lazily_parsed());
+
+ for (VariableProxy* proxy = scope->unresolved_list_.first();
+ proxy != nullptr; proxy = proxy->next_unresolved()) {
+ DCHECK(!proxy->is_resolved());
+ Variable* var =
+ Lookup<kParsedScope>(proxy, scope, max_outer_scope->outer_scope());
+ if (var == nullptr) {
+ // Don't copy unresolved references to the script scope, unless it's a
+ // reference to a private name or method. In that case keep it so we
+ // can fail later.
+ if (!max_outer_scope->outer_scope()->is_script_scope() ||
+ proxy->IsPrivateName()) {
+ VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
+ new_unresolved_list->Add(copy);
+ }
+ } else {
+ var->set_is_used();
+ if (proxy->is_assigned()) var->set_maybe_assigned();
}
- } else {
- var->set_is_used();
- if (proxy->is_assigned()) var->set_maybe_assigned();
}
- }
- // Clear unresolved_list_ as it's in an inconsistent state.
- unresolved_list_.Clear();
-
- for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
- scope->AnalyzePartially(max_outer_scope, ast_node_factory,
- new_unresolved_list);
- }
+ // Clear unresolved_list_ as it's in an inconsistent state.
+ scope->unresolved_list_.Clear();
+ return Iteration::kDescend;
+ });
}
Handle<StringSet> DeclarationScope::CollectNonLocals(
@@ -1399,7 +1378,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
locals_.Clear();
inner_scope_ = nullptr;
unresolved_list_.Clear();
- sloppy_block_function_map_ = nullptr;
+ sloppy_block_functions_.Clear();
rare_data_ = nullptr;
has_rest_ = false;
@@ -1428,14 +1407,25 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
was_lazily_parsed_ = !aborted;
}
-void Scope::SavePreparseData(Parser* parser) {
- if (PreparseDataBuilder::ScopeIsSkippableFunctionScope(this)) {
- AsDeclarationScope()->SavePreparseDataForDeclarationScope(parser);
- }
+bool Scope::IsSkippableFunctionScope() {
+ // Lazy non-arrow function scopes are skippable. Lazy functions are exactly
+ // those Scopes which have their own PreparseDataBuilder object. This
+ // logic ensures that the scope allocation data is consistent with the
+ // skippable function data (both agree on where the lazy function boundaries
+ // are).
+ if (!is_function_scope()) return false;
+ DeclarationScope* declaration_scope = AsDeclarationScope();
+ return !declaration_scope->is_arrow_scope() &&
+ declaration_scope->preparse_data_builder() != nullptr;
+}
- for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
- scope->SavePreparseData(parser);
- }
+void Scope::SavePreparseData(Parser* parser) {
+ this->ForEach([parser](Scope* scope) {
+ if (scope->IsSkippableFunctionScope()) {
+ scope->AsDeclarationScope()->SavePreparseDataForDeclarationScope(parser);
+ }
+ return Iteration::kDescend;
+ });
}
void DeclarationScope::SavePreparseDataForDeclarationScope(Parser* parser) {
@@ -1685,27 +1675,26 @@ void Scope::Print(int n) {
}
void Scope::CheckScopePositions() {
- // Visible leaf scopes must have real positions.
- if (!is_hidden() && inner_scope_ == nullptr) {
- DCHECK_NE(kNoSourcePosition, start_position());
- DCHECK_NE(kNoSourcePosition, end_position());
- }
- for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
- scope->CheckScopePositions();
- }
+ this->ForEach([](Scope* scope) {
+ // Visible leaf scopes must have real positions.
+ if (!scope->is_hidden() && scope->inner_scope_ == nullptr) {
+ DCHECK_NE(kNoSourcePosition, scope->start_position());
+ DCHECK_NE(kNoSourcePosition, scope->end_position());
+ }
+ return Iteration::kDescend;
+ });
}
void Scope::CheckZones() {
DCHECK(!needs_migration_);
- for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
- if (scope->is_declaration_scope() &&
- scope->AsDeclarationScope()->was_lazily_parsed()) {
+ this->ForEach([](Scope* scope) {
+ if (WasLazilyParsed(scope)) {
DCHECK_NULL(scope->zone());
DCHECK_NULL(scope->inner_scope_);
- continue;
+ return Iteration::kContinue;
}
- scope->CheckZones();
- }
+ return Iteration::kDescend;
+ });
}
#endif // DEBUG
@@ -1803,16 +1792,6 @@ template Variable* Scope::Lookup<Scope::kDeserializedScope>(
VariableProxy* proxy, Scope* scope, Scope* outer_scope_end,
Scope* entry_point, bool force_context_allocation);
-namespace {
-bool CanBeShadowed(Scope* scope, Variable* var) {
- if (var == nullptr) return false;
-
- // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes.
- // TODO(wingo): There are other variables in this category; add them.
- return !var->is_this();
-}
-}; // namespace
-
Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope,
Scope* outer_scope_end, Scope* entry_point,
bool force_context_allocation) {
@@ -1825,7 +1804,7 @@ Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope,
: Lookup<kDeserializedScope>(proxy, scope->outer_scope_,
outer_scope_end, entry_point);
- if (!CanBeShadowed(scope, var)) return var;
+ if (var == nullptr) return var;
// The current scope is a with scope, so the variable binding can not be
// statically resolved. However, note that it was necessary to do a lookup
@@ -1859,7 +1838,7 @@ Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope,
nullptr, force_context_allocation)
: Lookup<kDeserializedScope>(proxy, scope->outer_scope_,
outer_scope_end, entry);
- if (!CanBeShadowed(scope, var)) return var;
+ if (var == nullptr) return var;
// A variable binding may have been found in an outer scope, but the current
// scope makes a sloppy 'eval' call, so the found variable may not be the
@@ -1949,12 +1928,6 @@ void UpdateNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) {
return SetNeedsHoleCheck(var, proxy);
}
- if (var->is_this()) {
- DCHECK(IsDerivedConstructor(scope->GetClosureScope()->function_kind()));
- // TODO(littledan): implement 'this' hole check elimination.
- return SetNeedsHoleCheck(var, proxy);
- }
-
// We should always have valid source positions.
DCHECK_NE(var->initializer_position(), kNoSourcePosition);
DCHECK_NE(proxy->position(), kNoSourcePosition);
@@ -1994,16 +1967,50 @@ void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) {
proxy->BindTo(var);
}
+bool Scope::ResolvePreparsedVariable(VariableProxy* proxy, Scope* scope,
+ Scope* end) {
+ // Resolve the variable in all parsed scopes to force context allocation.
+ for (; scope != end; scope = scope->outer_scope_) {
+ Variable* var = scope->LookupLocal(proxy->raw_name());
+ if (var != nullptr) {
+ var->set_is_used();
+ if (!var->is_dynamic()) {
+ var->ForceContextAllocation();
+ if (proxy->is_assigned()) var->set_maybe_assigned();
+ }
+ return true;
+ }
+ }
+
+ if (!proxy->IsPrivateName()) return true;
+
+ // If we're resolving a private name, throw an exception of we didn't manage
+ // to resolve. In case of eval, also look in all outer scope-info backed
+ // scopes except for the script scope. Don't throw an exception if a reference
+ // was found.
+ Scope* start = scope;
+ for (; !scope->is_script_scope(); scope = scope->outer_scope_) {
+ if (scope->LookupInScopeInfo(proxy->raw_name(), start) != nullptr) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool Scope::ResolveVariablesRecursively(ParseInfo* info) {
DCHECK(info->script_scope()->is_script_scope());
// Lazy parsed declaration scopes are already partially analyzed. If there are
// unresolved references remaining, they just need to be resolved in outer
// scopes.
- if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) {
+ if (WasLazilyParsed(this)) {
DCHECK_EQ(variables_.occupancy(), 0);
+ Scope* end = info->scope();
+ // Resolve in all parsed scopes except for the script scope.
+ if (!end->is_script_scope()) end = end->outer_scope();
+
for (VariableProxy* proxy : unresolved_list_) {
- Variable* var = Lookup<kParsedScope>(proxy, outer_scope(), nullptr);
- if (var == nullptr) {
+ if (!ResolvePreparsedVariable(proxy, outer_scope(), end)) {
info->pending_error_handler()->ReportMessageAt(
proxy->position(), proxy->position() + 1,
MessageTemplate::kInvalidPrivateFieldResolution, proxy->raw_name(),
@@ -2011,11 +2018,6 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info) {
DCHECK(proxy->IsPrivateName());
return false;
}
- if (!var->is_dynamic()) {
- var->set_is_used();
- var->ForceContextAllocation();
- if (proxy->is_assigned()) var->set_maybe_assigned();
- }
}
} else {
// Resolve unresolved variables for this scope.
@@ -2037,7 +2039,7 @@ bool Scope::MustAllocate(Variable* var) {
// Give var a read/write use if there is a chance it might be accessed
// via an eval() call. This is only possible if the variable has a
// visible name.
- if ((var->is_this() || !var->raw_name()->IsEmpty()) &&
+ if (!var->raw_name()->IsEmpty() &&
(inner_scope_calls_eval_ || is_catch_scope() || is_script_scope())) {
var->set_is_used();
if (inner_scope_calls_eval_) var->set_maybe_assigned();
@@ -2118,18 +2120,15 @@ void DeclarationScope::AllocateParameterLocals() {
}
void DeclarationScope::AllocateParameter(Variable* var, int index) {
- if (MustAllocate(var)) {
- if (has_forced_context_allocation_for_parameters() ||
- MustAllocateInContext(var)) {
- DCHECK(var->IsUnallocated() || var->IsContextSlot());
- if (var->IsUnallocated()) {
- AllocateHeapSlot(var);
- }
- } else {
- DCHECK(var->IsUnallocated() || var->IsParameter());
- if (var->IsUnallocated()) {
- var->AllocateTo(VariableLocation::PARAMETER, index);
- }
+ if (!MustAllocate(var)) return;
+ if (has_forced_context_allocation_for_parameters() ||
+ MustAllocateInContext(var)) {
+ DCHECK(var->IsUnallocated() || var->IsContextSlot());
+ if (var->IsUnallocated()) AllocateHeapSlot(var);
+ } else {
+ DCHECK(var->IsUnallocated() || var->IsParameter());
+ if (var->IsUnallocated()) {
+ var->AllocateTo(VariableLocation::PARAMETER, index);
}
}
}
@@ -2142,7 +2141,7 @@ void DeclarationScope::AllocateReceiver() {
}
void Scope::AllocateNonParameterLocal(Variable* var) {
- DCHECK(var->scope() == this);
+ DCHECK_EQ(var->scope(), this);
if (var->IsUnallocated() && MustAllocate(var)) {
if (MustAllocateInContext(var)) {
AllocateHeapSlot(var);
@@ -2201,51 +2200,47 @@ void ModuleScope::AllocateModuleVariables() {
}
void Scope::AllocateVariablesRecursively() {
- DCHECK(!already_resolved_);
-
- // Don't allocate variables of preparsed scopes.
- if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) {
- return;
- }
-
- // Allocate variables for inner scopes.
- for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
- scope->AllocateVariablesRecursively();
- }
-
- DCHECK(!already_resolved_);
- DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, num_heap_slots_);
+ this->ForEach([](Scope* scope) -> Iteration {
+ DCHECK(!scope->already_resolved_);
+ if (WasLazilyParsed(scope)) return Iteration::kContinue;
+ DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, scope->num_heap_slots_);
+
+ // Allocate variables for this scope.
+ // Parameters must be allocated first, if any.
+ if (scope->is_declaration_scope()) {
+ if (scope->is_function_scope()) {
+ scope->AsDeclarationScope()->AllocateParameterLocals();
+ }
+ scope->AsDeclarationScope()->AllocateReceiver();
+ }
+ scope->AllocateNonParameterLocalsAndDeclaredGlobals();
+
+ // Force allocation of a context for this scope if necessary. For a 'with'
+ // scope and for a function scope that makes an 'eval' call we need a
+ // context, even if no local variables were statically allocated in the
+ // scope. Likewise for modules and function scopes representing asm.js
+ // modules. Also force a context, if the scope is stricter than the outer
+ // scope.
+ bool must_have_context =
+ scope->is_with_scope() || scope->is_module_scope() ||
+ scope->IsAsmModule() || scope->ForceContextForLanguageMode() ||
+ (scope->is_function_scope() &&
+ scope->AsDeclarationScope()->calls_sloppy_eval()) ||
+ (scope->is_block_scope() && scope->is_declaration_scope() &&
+ scope->AsDeclarationScope()->calls_sloppy_eval());
- // Allocate variables for this scope.
- // Parameters must be allocated first, if any.
- if (is_declaration_scope()) {
- if (is_function_scope()) {
- AsDeclarationScope()->AllocateParameterLocals();
+ // If we didn't allocate any locals in the local context, then we only
+ // need the minimal number of slots if we must have a context.
+ if (scope->num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
+ !must_have_context) {
+ scope->num_heap_slots_ = 0;
}
- AsDeclarationScope()->AllocateReceiver();
- }
- AllocateNonParameterLocalsAndDeclaredGlobals();
-
- // Force allocation of a context for this scope if necessary. For a 'with'
- // scope and for a function scope that makes an 'eval' call we need a context,
- // even if no local variables were statically allocated in the scope.
- // Likewise for modules and function scopes representing asm.js modules.
- // Also force a context, if the scope is stricter than the outer scope.
- bool must_have_context =
- is_with_scope() || is_module_scope() || IsAsmModule() ||
- ForceContextForLanguageMode() ||
- (is_function_scope() && AsDeclarationScope()->calls_sloppy_eval()) ||
- (is_block_scope() && is_declaration_scope() &&
- AsDeclarationScope()->calls_sloppy_eval());
-
- // If we didn't allocate any locals in the local context, then we only
- // need the minimal number of slots if we must have a context.
- if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && !must_have_context) {
- num_heap_slots_ = 0;
- }
-
- // Allocation done.
- DCHECK(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
+
+ // Allocation done.
+ DCHECK(scope->num_heap_slots_ == 0 ||
+ scope->num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
+ return Iteration::kDescend;
+ });
}
void Scope::AllocateScopeInfosRecursively(Isolate* isolate,
diff --git a/chromium/v8/src/ast/scopes.h b/chromium/v8/src/ast/scopes.h
index 971cfc519b0..732d759757f 100644
--- a/chromium/v8/src/ast/scopes.h
+++ b/chromium/v8/src/ast/scopes.h
@@ -8,6 +8,8 @@
#include "src/ast/ast.h"
#include "src/base/compiler-specific.h"
#include "src/base/hashmap.h"
+#include "src/base/threaded-list.h"
+#include "src/function-kind.h"
#include "src/globals.h"
#include "src/objects.h"
#include "src/pointer-with-payload.h"
@@ -43,37 +45,6 @@ class VariableMap: public ZoneHashMap {
void Add(Zone* zone, Variable* var);
};
-
-// Sloppy block-scoped function declarations to var-bind
-class SloppyBlockFunctionMap : public ZoneHashMap {
- public:
- class Delegate : public ZoneObject {
- public:
- Delegate(Scope* scope, SloppyBlockFunctionStatement* statement, int index)
- : scope_(scope), statement_(statement), next_(nullptr), index_(index) {}
- void set_statement(Statement* statement);
-
- void set_next(Delegate* next) { next_ = next; }
- Delegate* next() const { return next_; }
- Scope* scope() const { return scope_; }
- int index() const { return index_; }
- int position() const { return statement_->position(); }
-
- private:
- Scope* scope_;
- SloppyBlockFunctionStatement* statement_;
- Delegate* next_;
- int index_;
- };
-
- explicit SloppyBlockFunctionMap(Zone* zone);
- void Declare(Zone* zone, const AstRawString* name, Scope* scope,
- SloppyBlockFunctionStatement* statement);
-
- private:
- int count_;
-};
-
class Scope;
template <>
@@ -111,9 +82,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
typedef base::ThreadedList<VariableProxy, VariableProxy::UnresolvedNext>
UnresolvedList;
- // TODO(verwaest): Is this needed on Scope?
- int num_parameters() const;
-
DeclarationScope* AsDeclarationScope();
const DeclarationScope* AsDeclarationScope() const;
ModuleScope* AsModuleScope();
@@ -225,8 +193,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
VariableKind kind, bool* was_added,
InitializationFlag init_flag = kCreatedInitialized);
- Variable* DeclareVariable(Declaration* declaration, VariableProxy* proxy,
- VariableMode mode, VariableKind kind,
+ Variable* DeclareVariable(Declaration* declaration, const AstRawString* name,
+ int pos, VariableMode mode, VariableKind kind,
InitializationFlag init, bool* was_added,
bool* sloppy_mode_block_scope_function_redefinition,
bool* ok);
@@ -280,14 +248,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// TODO(verwaest): Move to DeclarationScope?
Variable* NewTemporary(const AstRawString* name);
- // ---------------------------------------------------------------------------
- // Illegal redeclaration support.
-
- // Check if the scope has conflicting var
- // declarations, i.e. a var declaration that has been hoisted from a nested
- // scope over a let binding of the same name.
- Declaration* CheckConflictingVarDeclarations();
-
// Find variable with (variable->mode() <= |mode_limit|) that was declared in
// |scope|. This is used to catch patterns like `try{}catch(e){let e;}` and
// function([e]) { let e }, which are errors even though the two 'e's are each
@@ -421,6 +381,33 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
return num_heap_slots() > 0;
}
+ // Use Scope::ForEach for depth first traversal of scopes.
+ // Before:
+ // void Scope::VisitRecursively() {
+ // DoSomething();
+ // for (Scope* s = inner_scope_; s != nullptr; s = s->sibling_) {
+ // if (s->ShouldContinue()) continue;
+ // s->VisitRecursively();
+ // }
+ // }
+ //
+ // After:
+ // void Scope::VisitIteratively() {
+ // this->ForEach([](Scope* s) {
+ // s->DoSomething();
+ // return s->ShouldContinue() ? kContinue : kDescend;
+ // });
+ // }
+ template <typename FunctionType>
+ V8_INLINE void ForEach(FunctionType callback);
+ enum Iteration {
+ // Continue the iteration on the same level, do not recurse/descent into
+ // inner scopes.
+ kContinue,
+ // Recurse/descend into inner scopes.
+ kDescend
+ };
+
// ---------------------------------------------------------------------------
// Accessors.
@@ -488,6 +475,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// Find the innermost outer scope that needs a context.
Scope* GetOuterScopeWithContext();
+ bool HasThisReference() const;
+
// Analyze() must have been called once to create the ScopeInfo.
Handle<ScopeInfo> scope_info() const {
DCHECK(!scope_info_.is_null());
@@ -513,6 +502,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
bool HasSimpleParameters();
void set_is_debug_evaluate_scope() { is_debug_evaluate_scope_ = true; }
bool is_debug_evaluate_scope() const { return is_debug_evaluate_scope_; }
+ bool IsSkippableFunctionScope();
bool RemoveInnerScope(Scope* inner_scope) {
DCHECK_NOT_NULL(inner_scope);
@@ -599,6 +589,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
static Variable* LookupSloppyEval(VariableProxy* proxy, Scope* scope,
Scope* outer_scope_end, Scope* entry_point,
bool force_context_allocation);
+ static bool ResolvePreparsedVariable(VariableProxy* proxy, Scope* scope,
+ Scope* end);
void ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var);
V8_WARN_UNUSED_RESULT bool ResolveVariable(ParseInfo* info,
VariableProxy* proxy);
@@ -618,14 +610,15 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// Variable allocation.
void AllocateStackSlot(Variable* var);
- void AllocateHeapSlot(Variable* var);
+ V8_INLINE void AllocateHeapSlot(Variable* var);
void AllocateNonParameterLocal(Variable* var);
void AllocateDeclaredGlobal(Variable* var);
- void AllocateNonParameterLocalsAndDeclaredGlobals();
+ V8_INLINE void AllocateNonParameterLocalsAndDeclaredGlobals();
void AllocateVariablesRecursively();
void AllocateScopeInfosRecursively(Isolate* isolate,
MaybeHandle<ScopeInfo> outer_scope);
+
void AllocateDebuggerScopeInfos(Isolate* isolate,
MaybeHandle<ScopeInfo> outer_scope);
@@ -766,6 +759,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
return var;
}
+ void DeserializeReceiver(AstValueFactory* ast_value_factory);
+
#ifdef DEBUG
void set_is_being_lazily_parsed(bool is_being_lazily_parsed) {
is_being_lazily_parsed_ = is_being_lazily_parsed;
@@ -779,7 +774,23 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
zone_ = zone;
}
- bool ShouldEagerCompile() const;
+ // ---------------------------------------------------------------------------
+ // Illegal redeclaration support.
+
+ // Check if the scope has conflicting var
+ // declarations, i.e. a var declaration that has been hoisted from a nested
+ // scope over a let binding of the same name.
+ Declaration* CheckConflictingVarDeclarations();
+
+ void set_has_checked_syntax(bool has_checked_syntax) {
+ has_checked_syntax_ = has_checked_syntax;
+ }
+ bool has_checked_syntax() const { return has_checked_syntax_; }
+
+ bool ShouldEagerCompile() const {
+ return force_eager_compilation_ || should_eager_compile_;
+ }
+
void set_should_eager_compile();
void SetScriptScopeInfo(Handle<ScopeInfo> scope_info) {
@@ -833,17 +844,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// The variable corresponding to the 'this' value.
Variable* receiver() {
- DCHECK(has_this_declaration());
+ DCHECK(has_this_declaration() || is_script_scope());
DCHECK_NOT_NULL(receiver_);
return receiver_;
}
- // TODO(wingo): Add a GLOBAL_SCOPE scope type which will lexically allocate
- // "this" (and no other variable) on the native context. Script scopes then
- // will not have a "this" declaration.
- bool has_this_declaration() const {
- return (is_function_scope() && !is_arrow_scope()) || is_module_scope();
- }
+ bool has_this_declaration() const { return has_this_declaration_; }
// The variable corresponding to the 'new.target' value.
Variable* new_target_var() { return new_target_; }
@@ -935,17 +941,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
void AddLocal(Variable* var);
void DeclareSloppyBlockFunction(
- const AstRawString* name, Scope* scope,
- SloppyBlockFunctionStatement* statement = nullptr);
+ SloppyBlockFunctionStatement* sloppy_block_function);
- // Go through sloppy_block_function_map_ and hoist those (into this scope)
+ // Go through sloppy_block_functions_ and hoist those (into this scope)
// which should be hoisted.
void HoistSloppyBlockFunctions(AstNodeFactory* factory);
- SloppyBlockFunctionMap* sloppy_block_function_map() {
- return sloppy_block_function_map_;
- }
-
// Compute top scope and allocate variables. For lazy compilation the top
// scope only contains the single lazily compiled function, so this
// doesn't re-allocate variables repeatedly.
@@ -988,9 +989,9 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
void PrintParameters();
#endif
- void AllocateLocals();
- void AllocateParameterLocals();
- void AllocateReceiver();
+ V8_INLINE void AllocateLocals();
+ V8_INLINE void AllocateParameterLocals();
+ V8_INLINE void AllocateReceiver();
void ResetAfterPreparsing(AstValueFactory* ast_value_factory, bool aborted);
@@ -1020,8 +1021,15 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
return preparse_data_builder_;
}
+ void set_has_this_reference() { has_this_reference_ = true; }
+ bool has_this_reference() const { return has_this_reference_; }
+ void UsesThis() {
+ set_has_this_reference();
+ GetReceiverScope()->receiver()->ForceContextAllocation();
+ }
+
private:
- void AllocateParameter(Variable* var, int index);
+ V8_INLINE void AllocateParameter(Variable* var, int index);
// Resolve and fill in the allocation information for all variables
// in this scopes. Must be called *after* all scopes have been
@@ -1055,16 +1063,19 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
#endif
bool is_skipped_function_ : 1;
bool has_inferred_function_name_ : 1;
-
- int num_parameters_ = 0;
+ bool has_checked_syntax_ : 1;
+ bool has_this_reference_ : 1;
+ bool has_this_declaration_ : 1;
// If the scope is a function scope, this is the function kind.
const FunctionKind function_kind_;
+ int num_parameters_ = 0;
+
// Parameter list in source order.
ZonePtrList<Variable> params_;
// Map of function names to lists of functions defined in sloppy blocks
- SloppyBlockFunctionMap* sloppy_block_function_map_;
+ base::ThreadedList<SloppyBlockFunctionStatement> sloppy_block_functions_;
// Convenience variable.
Variable* receiver_;
// Function variable, if any; function scopes only.
@@ -1128,27 +1139,21 @@ Scope::Snapshot::Snapshot(Scope* scope)
class ModuleScope final : public DeclarationScope {
public:
- ModuleScope(DeclarationScope* script_scope,
- AstValueFactory* ast_value_factory);
+ ModuleScope(DeclarationScope* script_scope, AstValueFactory* avfactory);
- // Deserialization.
- // The generated ModuleDescriptor does not preserve all information. In
- // particular, its module_requests map will be empty because we no longer need
- // the map after parsing.
+ // Deserialization. Does not restore the module descriptor.
ModuleScope(Isolate* isolate, Handle<ScopeInfo> scope_info,
- AstValueFactory* ast_value_factory);
+ AstValueFactory* avfactory);
- ModuleDescriptor* module() const {
- DCHECK_NOT_NULL(module_descriptor_);
- return module_descriptor_;
- }
+ // Returns nullptr in a deserialized scope.
+ ModuleDescriptor* module() const { return module_descriptor_; }
// Set MODULE as VariableLocation for all variables that will live in a
// module's export table.
void AllocateModuleVariables();
private:
- ModuleDescriptor* module_descriptor_;
+ ModuleDescriptor* const module_descriptor_;
};
} // namespace internal
diff --git a/chromium/v8/src/ast/source-range-ast-visitor.cc b/chromium/v8/src/ast/source-range-ast-visitor.cc
index 442b23718c0..d171e305875 100644
--- a/chromium/v8/src/ast/source-range-ast-visitor.cc
+++ b/chromium/v8/src/ast/source-range-ast-visitor.cc
@@ -56,7 +56,18 @@ void SourceRangeAstVisitor::MaybeRemoveLastContinuationRange(
if (statements->is_empty()) return;
Statement* last_statement = statements->last();
- AstNodeSourceRanges* last_range = source_range_map_->Find(last_statement);
+ AstNodeSourceRanges* last_range = nullptr;
+
+ if (last_statement->IsExpressionStatement() &&
+ last_statement->AsExpressionStatement()->expression()->IsThrow()) {
+ // For ThrowStatement, source range is tied to Throw expression not
+ // ExpressionStatement.
+ last_range = source_range_map_->Find(
+ last_statement->AsExpressionStatement()->expression());
+ } else {
+ last_range = source_range_map_->Find(last_statement);
+ }
+
if (last_range == nullptr) return;
if (last_range->HasRange(SourceRangeKind::kContinuation)) {
diff --git a/chromium/v8/src/ast/variables.h b/chromium/v8/src/ast/variables.h
index 13a444536dd..6dbb9dbac48 100644
--- a/chromium/v8/src/ast/variables.h
+++ b/chromium/v8/src/ast/variables.h
@@ -6,6 +6,7 @@
#define V8_AST_VARIABLES_H_
#include "src/ast/ast-value-factory.h"
+#include "src/base/threaded-list.h"
#include "src/globals.h"
#include "src/zone/zone.h"
@@ -59,7 +60,7 @@ class Variable final : public ZoneObject {
return ForceContextAllocationField::decode(bit_field_);
}
void ForceContextAllocation() {
- DCHECK(IsUnallocated() || IsContextSlot() ||
+ DCHECK(IsUnallocated() || IsContextSlot() || IsLookupSlot() ||
location() == VariableLocation::MODULE);
bit_field_ = ForceContextAllocationField::update(bit_field_, true);
}
@@ -137,6 +138,9 @@ class Variable final : public ZoneObject {
}
bool is_parameter() const { return kind() == PARAMETER_VARIABLE; }
+ bool is_sloppy_block_function() {
+ return kind() == SLOPPY_BLOCK_FUNCTION_VARIABLE;
+ }
Variable* local_if_not_shadowed() const {
DCHECK(mode() == VariableMode::kDynamicLocal &&
@@ -207,7 +211,7 @@ class Variable final : public ZoneObject {
class VariableModeField : public BitField16<VariableMode, 0, 3> {};
class VariableKindField
- : public BitField16<VariableKind, VariableModeField::kNext, 2> {};
+ : public BitField16<VariableKind, VariableModeField::kNext, 3> {};
class LocationField
: public BitField16<VariableLocation, VariableKindField::kNext, 3> {};
class ForceContextAllocationField