Commit f6057ff1 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[scopes] Push sloppy eval check through eval scopes

Sloppy eval extends the outer declaration scope's context. This is also
true for sloppy eval inside of other sloppy evals -- the outer declaration
scope's context is extended rather than the outer sloppy eval's
declaration scope. However, we consider eval scopes to also be declaration
scopes, for the purposes of strict eval and caching lookup variables. So,
we need to make sure that we skip through sloppy eval scopes when marking
a scope as calls_sloppy_eval.

In fact, we implement this rather as never marking sloppy eval scopes as
calls_sloppy_eval, under the assumption that the parent scope will already
have been marked calls_sloppy_eval by the outer eval.

As a drive-by, fix a TODO to move this logic from calls_sloppy_eval() to
RecordEvalCall(), rename the variable to something more meaningful, and
make Snapshotting to use a new calls_eval bit on Scope.

Bug: chromium:996751
Change-Id: I27ccc7ef429a7ce60b3bb02bf64a3820ae4a2c36
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1773247
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63455}
parent de2654df
...@@ -168,7 +168,6 @@ Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info) ...@@ -168,7 +168,6 @@ Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info)
#ifdef DEBUG #ifdef DEBUG
already_resolved_ = true; already_resolved_ = true;
#endif #endif
if (scope_info->CallsSloppyEval()) scope_calls_eval_ = true;
set_language_mode(scope_info->language_mode()); set_language_mode(scope_info->language_mode());
num_heap_slots_ = scope_info->ContextLength(); num_heap_slots_ = scope_info->ContextLength();
DCHECK_LE(Context::MIN_CONTEXT_SLOTS, num_heap_slots_); DCHECK_LE(Context::MIN_CONTEXT_SLOTS, num_heap_slots_);
...@@ -184,6 +183,10 @@ DeclarationScope::DeclarationScope(Zone* zone, ScopeType scope_type, ...@@ -184,6 +183,10 @@ DeclarationScope::DeclarationScope(Zone* zone, ScopeType scope_type,
params_(0, zone) { params_(0, zone) {
DCHECK_NE(scope_type, SCRIPT_SCOPE); DCHECK_NE(scope_type, SCRIPT_SCOPE);
SetDefaults(); SetDefaults();
if (scope_info->SloppyEvalCanExtendVars()) {
DCHECK(!is_eval_scope());
sloppy_eval_can_extend_vars_ = true;
}
} }
Scope::Scope(Zone* zone, const AstRawString* catch_variable_name, Scope::Scope(Zone* zone, const AstRawString* catch_variable_name,
...@@ -256,7 +259,8 @@ void Scope::SetDefaults() { ...@@ -256,7 +259,8 @@ void Scope::SetDefaults() {
set_language_mode(LanguageMode::kSloppy); set_language_mode(LanguageMode::kSloppy);
scope_calls_eval_ = false; calls_eval_ = false;
sloppy_eval_can_extend_vars_ = false;
scope_nonlinear_ = false; scope_nonlinear_ = false;
is_hidden_ = false; is_hidden_ = false;
is_debug_evaluate_scope_ = false; is_debug_evaluate_scope_ = false;
...@@ -621,7 +625,7 @@ Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name, ...@@ -621,7 +625,7 @@ Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name,
: NORMAL_VARIABLE; : NORMAL_VARIABLE;
function_ = new (zone()) function_ = new (zone())
Variable(this, name, VariableMode::kConst, kind, kCreatedInitialized); Variable(this, name, VariableMode::kConst, kind, kCreatedInitialized);
if (calls_sloppy_eval()) { if (sloppy_eval_can_extend_vars()) {
cache->NonLocal(name, VariableMode::kDynamic); cache->NonLocal(name, VariableMode::kDynamic);
} else { } else {
cache->variables_.Add(zone(), function_); cache->variables_.Add(zone(), function_);
...@@ -647,7 +651,8 @@ Scope* Scope::FinalizeBlockScope() { ...@@ -647,7 +651,8 @@ Scope* Scope::FinalizeBlockScope() {
#endif #endif
if (variables_.occupancy() > 0 || if (variables_.occupancy() > 0 ||
(is_declaration_scope() && AsDeclarationScope()->calls_sloppy_eval())) { (is_declaration_scope() &&
AsDeclarationScope()->sloppy_eval_can_extend_vars())) {
return this; return this;
} }
...@@ -677,10 +682,10 @@ Scope* Scope::FinalizeBlockScope() { ...@@ -677,10 +682,10 @@ Scope* Scope::FinalizeBlockScope() {
if (inner_scope_calls_eval_) outer_scope()->inner_scope_calls_eval_ = true; if (inner_scope_calls_eval_) outer_scope()->inner_scope_calls_eval_ = true;
// No need to propagate scope_calls_eval_, since if it was relevant to // No need to propagate sloppy_eval_can_extend_vars_, since if it was relevant
// this scope we would have had to bail out at the top. // to this scope we would have had to bail out at the top.
DCHECK(!scope_calls_eval_ || !is_declaration_scope() || DCHECK(!is_declaration_scope() ||
!is_sloppy(language_mode())); !AsDeclarationScope()->sloppy_eval_can_extend_vars());
// This block does not need a context. // This block does not need a context.
num_heap_slots_ = 0; num_heap_slots_ = 0;
...@@ -745,8 +750,8 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) { ...@@ -745,8 +750,8 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) {
outer_closure->locals_.Rewind(top_local_); outer_closure->locals_.Rewind(top_local_);
// Move eval calls since Snapshot's creation into new_parent. // Move eval calls since Snapshot's creation into new_parent.
if (outer_scope_and_calls_eval_->scope_calls_eval_) { if (outer_scope_and_calls_eval_->calls_eval_) {
new_parent->scope_calls_eval_ = true; new_parent->RecordDeclarationScopeEvalCall();
new_parent->inner_scope_calls_eval_ = true; new_parent->inner_scope_calls_eval_ = true;
} }
...@@ -1241,7 +1246,7 @@ int Scope::ContextChainLengthUntilOutermostSloppyEval() const { ...@@ -1241,7 +1246,7 @@ int Scope::ContextChainLengthUntilOutermostSloppyEval() const {
if (!s->NeedsContext()) continue; if (!s->NeedsContext()) continue;
length++; length++;
if (s->is_declaration_scope() && if (s->is_declaration_scope() &&
s->AsDeclarationScope()->calls_sloppy_eval()) { s->AsDeclarationScope()->sloppy_eval_can_extend_vars()) {
result = length; result = length;
} }
} }
...@@ -1670,7 +1675,8 @@ void Scope::Print(int n) { ...@@ -1670,7 +1675,8 @@ void Scope::Print(int n) {
Indent(n1, "// strict mode scope\n"); Indent(n1, "// strict mode scope\n");
} }
if (IsAsmModule()) Indent(n1, "// scope is an asm module\n"); if (IsAsmModule()) Indent(n1, "// scope is an asm module\n");
if (is_declaration_scope() && AsDeclarationScope()->calls_sloppy_eval()) { if (is_declaration_scope() &&
AsDeclarationScope()->sloppy_eval_can_extend_vars()) {
Indent(n1, "// scope calls sloppy 'eval'\n"); Indent(n1, "// scope calls sloppy 'eval'\n");
} }
if (is_declaration_scope() && AsDeclarationScope()->NeedsHomeObject()) { if (is_declaration_scope() && AsDeclarationScope()->NeedsHomeObject()) {
...@@ -1834,8 +1840,9 @@ Variable* Scope::Lookup(VariableProxy* proxy, Scope* scope, ...@@ -1834,8 +1840,9 @@ Variable* Scope::Lookup(VariableProxy* proxy, Scope* scope,
return LookupWith(proxy, scope, outer_scope_end, entry_point, return LookupWith(proxy, scope, outer_scope_end, entry_point,
force_context_allocation); force_context_allocation);
} }
if (V8_UNLIKELY(scope->is_declaration_scope() && if (V8_UNLIKELY(
scope->AsDeclarationScope()->calls_sloppy_eval())) { scope->is_declaration_scope() &&
scope->AsDeclarationScope()->sloppy_eval_can_extend_vars())) {
return LookupSloppyEval(proxy, scope, outer_scope_end, entry_point, return LookupSloppyEval(proxy, scope, outer_scope_end, entry_point,
force_context_allocation); force_context_allocation);
} }
...@@ -1906,7 +1913,7 @@ Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope, ...@@ -1906,7 +1913,7 @@ Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope,
Scope* outer_scope_end, Scope* entry_point, Scope* outer_scope_end, Scope* entry_point,
bool force_context_allocation) { bool force_context_allocation) {
DCHECK(scope->is_declaration_scope() && DCHECK(scope->is_declaration_scope() &&
scope->AsDeclarationScope()->calls_sloppy_eval()); scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
// If we're compiling eval, it's possible that the outer scope is the first // If we're compiling eval, it's possible that the outer scope is the first
// ScopeInfo-backed scope. // ScopeInfo-backed scope.
...@@ -2256,9 +2263,9 @@ void Scope::AllocateVariablesRecursively() { ...@@ -2256,9 +2263,9 @@ void Scope::AllocateVariablesRecursively() {
scope->is_with_scope() || scope->is_module_scope() || scope->is_with_scope() || scope->is_module_scope() ||
scope->IsAsmModule() || scope->ForceContextForLanguageMode() || scope->IsAsmModule() || scope->ForceContextForLanguageMode() ||
(scope->is_function_scope() && (scope->is_function_scope() &&
scope->AsDeclarationScope()->calls_sloppy_eval()) || scope->AsDeclarationScope()->sloppy_eval_can_extend_vars()) ||
(scope->is_block_scope() && scope->is_declaration_scope() && (scope->is_block_scope() && scope->is_declaration_scope() &&
scope->AsDeclarationScope()->calls_sloppy_eval()); scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
// If we didn't allocate any locals in the local context, then we only // 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. // need the minimal number of slots if we must have a context.
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_AST_SCOPES_H_ #ifndef V8_AST_SCOPES_H_
#define V8_AST_SCOPES_H_ #define V8_AST_SCOPES_H_
#include <numeric>
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/base/compiler-specific.h" #include "src/base/compiler-specific.h"
#include "src/base/hashmap.h" #include "src/base/hashmap.h"
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
#include "src/objects/function-kind.h" #include "src/objects/function-kind.h"
#include "src/objects/objects.h" #include "src/objects/objects.h"
#include "src/utils/pointer-with-payload.h" #include "src/utils/pointer-with-payload.h"
#include "src/utils/utils.h"
#include "src/zone/zone.h" #include "src/zone/zone.h"
namespace v8 { namespace v8 {
...@@ -110,8 +112,10 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -110,8 +112,10 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
} }
void RestoreEvalFlag() { void RestoreEvalFlag() {
outer_scope_and_calls_eval_->scope_calls_eval_ = if (outer_scope_and_calls_eval_.GetPayload()) {
outer_scope_and_calls_eval_.GetPayload(); // This recreates both calls_eval and sloppy_eval_can_extend_vars.
outer_scope_and_calls_eval_.GetPointer()->RecordEvalCall();
}
} }
void Reparent(DeclarationScope* new_parent); void Reparent(DeclarationScope* new_parent);
...@@ -264,9 +268,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -264,9 +268,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// Inform the scope and outer scopes that the corresponding code contains an // Inform the scope and outer scopes that the corresponding code contains an
// eval call. // eval call.
void RecordEvalCall() { inline void RecordEvalCall();
scope_calls_eval_ = true;
}
void RecordInnerScopeEvalCall() { void RecordInnerScopeEvalCall() {
inner_scope_calls_eval_ = true; inner_scope_calls_eval_ = true;
...@@ -459,7 +461,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -459,7 +461,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
int ContextChainLength(Scope* scope) const; int ContextChainLength(Scope* scope) const;
// The number of contexts between this and the outermost context that has a // The number of contexts between this and the outermost context that has a
// sloppy eval call. One if this->calls_sloppy_eval(). // sloppy eval call. One if this->sloppy_eval_can_extend_vars().
int ContextChainLengthUntilOutermostSloppyEval() const; int ContextChainLengthUntilOutermostSloppyEval() const;
// Find the closest class scope in the current scope and outer scopes. If no // Find the closest class scope in the current scope and outer scopes. If no
...@@ -702,9 +704,11 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -702,9 +704,11 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// The language mode of this scope. // The language mode of this scope.
STATIC_ASSERT(LanguageModeSize == 2); STATIC_ASSERT(LanguageModeSize == 2);
bool is_strict_ : 1; bool is_strict_ : 1;
// This scope or a nested catch scope or with scope contain an 'eval' call. At // This scope contains an 'eval' call.
// the 'eval' call site this scope is the declaration scope. bool calls_eval_ : 1;
bool scope_calls_eval_ : 1; // The context associated with this scope can be extended by a sloppy eval
// called inside of it.
bool sloppy_eval_can_extend_vars_ : 1;
// This scope's declarations might not be executed in order (e.g., switch). // This scope's declarations might not be executed in order (e.g., switch).
bool scope_nonlinear_ : 1; bool scope_nonlinear_ : 1;
bool is_hidden_ : 1; bool is_hidden_ : 1;
...@@ -752,11 +756,50 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { ...@@ -752,11 +756,50 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
IsClassConstructor(function_kind()))); IsClassConstructor(function_kind())));
} }
bool calls_sloppy_eval() const { // Inform the scope and outer scopes that the corresponding code contains an
// TODO(delphick): Calculate this when setting and change the name of // eval call.
// scope_calls_eval_. void RecordDeclarationScopeEvalCall() {
return !is_script_scope() && scope_calls_eval_ && calls_eval_ = true;
is_sloppy(language_mode());
// If this isn't a sloppy eval, we don't care about it.
if (language_mode() != LanguageMode::kSloppy) return;
// Sloppy eval in script scopes can only introduce global variables anyway,
// so we don't care that it calls sloppy eval.
if (is_script_scope()) return;
// Sloppy eval in a eval scope can only introduce variables into the outer
// (non-eval) declaration scope, not into this eval scope.
if (is_eval_scope()) {
#ifdef DEBUG
// One of three things must be true:
// 1. The outer non-eval declaration scope should already be marked as
// being extendable by sloppy eval, by the current sloppy eval rather
// than the inner one,
// 2. The outer non-eval declaration scope is a script scope and thus
// isn't extendable anyway, or
// 3. This is a debug evaluate and all bets are off.
DeclarationScope* outer_decl_scope = outer_scope()->GetDeclarationScope();
while (outer_decl_scope->is_eval_scope()) {
outer_decl_scope = outer_decl_scope->GetDeclarationScope();
}
if (outer_decl_scope->is_debug_evaluate_scope()) {
// Don't check anything.
// TODO(9662): Figure out where variables declared by an eval inside a
// debug-evaluate actually go.
} else if (!outer_decl_scope->is_script_scope()) {
DCHECK(outer_decl_scope->sloppy_eval_can_extend_vars_);
}
#endif
return;
}
sloppy_eval_can_extend_vars_ = true;
}
bool sloppy_eval_can_extend_vars() const {
return sloppy_eval_can_extend_vars_;
} }
bool was_lazily_parsed() const { return was_lazily_parsed_; } bool was_lazily_parsed() const { return was_lazily_parsed_; }
...@@ -1137,13 +1180,21 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { ...@@ -1137,13 +1180,21 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
RareData* rare_data_ = nullptr; RareData* rare_data_ = nullptr;
}; };
void Scope::RecordEvalCall() {
calls_eval_ = true;
GetDeclarationScope()->RecordDeclarationScopeEvalCall();
RecordInnerScopeEvalCall();
}
Scope::Snapshot::Snapshot(Scope* scope) Scope::Snapshot::Snapshot(Scope* scope)
: outer_scope_and_calls_eval_(scope, scope->scope_calls_eval_), : outer_scope_and_calls_eval_(scope, scope->calls_eval_),
top_inner_scope_(scope->inner_scope_), top_inner_scope_(scope->inner_scope_),
top_unresolved_(scope->unresolved_list_.end()), top_unresolved_(scope->unresolved_list_.end()),
top_local_(scope->GetClosureScope()->locals_.end()) { top_local_(scope->GetClosureScope()->locals_.end()) {
// Reset in order to record eval calls during this Snapshot's lifetime. // Reset in order to record eval calls during this Snapshot's lifetime.
outer_scope_and_calls_eval_.GetPointer()->scope_calls_eval_ = false; outer_scope_and_calls_eval_.GetPointer()->calls_eval_ = false;
outer_scope_and_calls_eval_.GetPointer()->sloppy_eval_can_extend_vars_ =
false;
} }
class ModuleScope final : public DeclarationScope { class ModuleScope final : public DeclarationScope {
......
...@@ -774,7 +774,7 @@ void ScopeIterator::VisitLocalScope(const Visitor& visitor, Mode mode) const { ...@@ -774,7 +774,7 @@ void ScopeIterator::VisitLocalScope(const Visitor& visitor, Mode mode) const {
DCHECK(!context_->IsScriptContext()); DCHECK(!context_->IsScriptContext());
DCHECK(!context_->IsNativeContext()); DCHECK(!context_->IsNativeContext());
DCHECK(!context_->IsWithContext()); DCHECK(!context_->IsWithContext());
if (!context_->scope_info().CallsSloppyEval()) return; if (!context_->scope_info().SloppyEvalCanExtendVars()) return;
if (context_->extension_object().is_null()) return; if (context_->extension_object().is_null()) return;
Handle<JSObject> extension(context_->extension_object(), isolate_); Handle<JSObject> extension(context_->extension_object(), isolate_);
Handle<FixedArray> keys = Handle<FixedArray> keys =
......
...@@ -2275,7 +2275,7 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) { // NOLINT ...@@ -2275,7 +2275,7 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) { // NOLINT
os << "\n - context locals : " << ContextLocalCount(); os << "\n - context locals : " << ContextLocalCount();
os << "\n - scope type: " << scope_type(); os << "\n - scope type: " << scope_type();
if (CallsSloppyEval()) os << "\n - sloppy eval"; if (SloppyEvalCanExtendVars()) os << "\n - sloppy eval";
os << "\n - language mode: " << language_mode(); os << "\n - language mode: " << language_mode();
if (is_declaration_scope()) os << "\n - declaration scope"; if (is_declaration_scope()) os << "\n - declaration scope";
if (HasReceiver()) { if (HasReceiver()) {
......
...@@ -166,7 +166,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, ...@@ -166,7 +166,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
bool has_simple_parameters = false; bool has_simple_parameters = false;
bool is_asm_module = false; bool is_asm_module = false;
bool calls_sloppy_eval = false; bool sloppy_eval_can_extend_vars = false;
if (scope->is_function_scope()) { if (scope->is_function_scope()) {
DeclarationScope* function_scope = scope->AsDeclarationScope(); DeclarationScope* function_scope = scope->AsDeclarationScope();
has_simple_parameters = function_scope->has_simple_parameters(); has_simple_parameters = function_scope->has_simple_parameters();
...@@ -175,13 +175,14 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, ...@@ -175,13 +175,14 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
FunctionKind function_kind = kNormalFunction; FunctionKind function_kind = kNormalFunction;
if (scope->is_declaration_scope()) { if (scope->is_declaration_scope()) {
function_kind = scope->AsDeclarationScope()->function_kind(); function_kind = scope->AsDeclarationScope()->function_kind();
calls_sloppy_eval = scope->AsDeclarationScope()->calls_sloppy_eval(); sloppy_eval_can_extend_vars =
scope->AsDeclarationScope()->sloppy_eval_can_extend_vars();
} }
// Encode the flags. // Encode the flags.
int flags = int flags =
ScopeTypeField::encode(scope->scope_type()) | ScopeTypeField::encode(scope->scope_type()) |
CallsSloppyEvalField::encode(calls_sloppy_eval) | SloppyEvalCanExtendVarsField::encode(sloppy_eval_can_extend_vars) |
LanguageModeField::encode(scope->language_mode()) | LanguageModeField::encode(scope->language_mode()) |
DeclarationScopeField::encode(scope->is_declaration_scope()) | DeclarationScopeField::encode(scope->is_declaration_scope()) |
ReceiverVariableField::encode(receiver_info) | ReceiverVariableField::encode(receiver_info) |
...@@ -356,7 +357,8 @@ Handle<ScopeInfo> ScopeInfo::CreateForWithScope( ...@@ -356,7 +357,8 @@ Handle<ScopeInfo> ScopeInfo::CreateForWithScope(
// Encode the flags. // Encode the flags.
int flags = int flags =
ScopeTypeField::encode(WITH_SCOPE) | CallsSloppyEvalField::encode(false) | ScopeTypeField::encode(WITH_SCOPE) |
SloppyEvalCanExtendVarsField::encode(false) |
LanguageModeField::encode(LanguageMode::kSloppy) | LanguageModeField::encode(LanguageMode::kSloppy) |
DeclarationScopeField::encode(false) | DeclarationScopeField::encode(false) |
ReceiverVariableField::encode(NONE) | HasClassBrandField::encode(false) | ReceiverVariableField::encode(NONE) | HasClassBrandField::encode(false) |
...@@ -418,7 +420,8 @@ Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate, ...@@ -418,7 +420,8 @@ Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate,
// Encode the flags. // Encode the flags.
int flags = int flags =
ScopeTypeField::encode(type) | CallsSloppyEvalField::encode(false) | ScopeTypeField::encode(type) |
SloppyEvalCanExtendVarsField::encode(false) |
LanguageModeField::encode(LanguageMode::kSloppy) | LanguageModeField::encode(LanguageMode::kSloppy) |
DeclarationScopeField::encode(true) | DeclarationScopeField::encode(true) |
ReceiverVariableField::encode(is_empty_function ? UNUSED : CONTEXT) | ReceiverVariableField::encode(is_empty_function ? UNUSED : CONTEXT) |
...@@ -491,12 +494,12 @@ ScopeType ScopeInfo::scope_type() const { ...@@ -491,12 +494,12 @@ ScopeType ScopeInfo::scope_type() const {
return ScopeTypeField::decode(Flags()); return ScopeTypeField::decode(Flags());
} }
bool ScopeInfo::CallsSloppyEval() const { bool ScopeInfo::SloppyEvalCanExtendVars() const {
bool calls_sloppy_eval = bool sloppy_eval_can_extend_vars =
length() > 0 && CallsSloppyEvalField::decode(Flags()); length() > 0 && SloppyEvalCanExtendVarsField::decode(Flags());
DCHECK_IMPLIES(calls_sloppy_eval, is_sloppy(language_mode())); DCHECK_IMPLIES(sloppy_eval_can_extend_vars, is_sloppy(language_mode()));
DCHECK_IMPLIES(calls_sloppy_eval, is_declaration_scope()); DCHECK_IMPLIES(sloppy_eval_can_extend_vars, is_declaration_scope());
return calls_sloppy_eval; return sloppy_eval_can_extend_vars;
} }
LanguageMode ScopeInfo::language_mode() const { LanguageMode ScopeInfo::language_mode() const {
...@@ -517,9 +520,9 @@ int ScopeInfo::ContextLength() const { ...@@ -517,9 +520,9 @@ int ScopeInfo::ContextLength() const {
bool has_context = bool has_context =
context_locals > 0 || force_context || function_name_context_slot || context_locals > 0 || force_context || function_name_context_slot ||
scope_type() == WITH_SCOPE || scope_type() == CLASS_SCOPE || scope_type() == WITH_SCOPE || scope_type() == CLASS_SCOPE ||
(scope_type() == BLOCK_SCOPE && CallsSloppyEval() && (scope_type() == BLOCK_SCOPE && SloppyEvalCanExtendVars() &&
is_declaration_scope()) || is_declaration_scope()) ||
(scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) || (scope_type() == FUNCTION_SCOPE && SloppyEvalCanExtendVars()) ||
(scope_type() == FUNCTION_SCOPE && IsAsmModule()) || (scope_type() == FUNCTION_SCOPE && IsAsmModule()) ||
scope_type() == MODULE_SCOPE; scope_type() == MODULE_SCOPE;
......
...@@ -51,7 +51,7 @@ class ScopeInfo : public FixedArray { ...@@ -51,7 +51,7 @@ class ScopeInfo : public FixedArray {
bool is_class_scope() const; bool is_class_scope() const;
// Does this scope make a sloppy eval call? // Does this scope make a sloppy eval call?
bool CallsSloppyEval() const; bool SloppyEvalCanExtendVars() const;
// Return the number of context slots for code if a context is allocated. This // Return the number of context slots for code if a context is allocated. This
// number consists of three parts: // number consists of three parts:
...@@ -221,9 +221,9 @@ class ScopeInfo : public FixedArray { ...@@ -221,9 +221,9 @@ class ScopeInfo : public FixedArray {
// Properties of scopes. // Properties of scopes.
using ScopeTypeField = BitField<ScopeType, 0, 4>; using ScopeTypeField = BitField<ScopeType, 0, 4>;
using CallsSloppyEvalField = ScopeTypeField::Next<bool, 1>; using SloppyEvalCanExtendVarsField = ScopeTypeField::Next<bool, 1>;
STATIC_ASSERT(LanguageModeSize == 2); STATIC_ASSERT(LanguageModeSize == 2);
using LanguageModeField = CallsSloppyEvalField::Next<LanguageMode, 1>; using LanguageModeField = SloppyEvalCanExtendVarsField::Next<LanguageMode, 1>;
using DeclarationScopeField = LanguageModeField::Next<bool, 1>; using DeclarationScopeField = LanguageModeField::Next<bool, 1>;
using ReceiverVariableField = using ReceiverVariableField =
DeclarationScopeField::Next<VariableAllocationInfo, 2>; DeclarationScopeField::Next<VariableAllocationInfo, 2>;
......
...@@ -105,7 +105,7 @@ void ReparentExpressionScope(uintptr_t stack_limit, Expression* expr, ...@@ -105,7 +105,7 @@ void ReparentExpressionScope(uintptr_t stack_limit, Expression* expr,
// sloppy eval. // sloppy eval.
DCHECK(scope->is_block_scope()); DCHECK(scope->is_block_scope());
DCHECK(scope->is_declaration_scope()); DCHECK(scope->is_declaration_scope());
DCHECK(scope->AsDeclarationScope()->calls_sloppy_eval()); DCHECK(scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
DCHECK(scope->outer_scope()->is_function_scope()); DCHECK(scope->outer_scope()->is_function_scope());
Reparenter r(stack_limit, expr, scope); Reparenter r(stack_limit, expr, scope);
......
...@@ -1293,18 +1293,7 @@ class ParserBase { ...@@ -1293,18 +1293,7 @@ class ParserBase {
Scope* scope) { Scope* scope) {
if (impl()->IsIdentifier(expression) && if (impl()->IsIdentifier(expression) &&
impl()->IsEval(impl()->AsIdentifier(expression))) { impl()->IsEval(impl()->AsIdentifier(expression))) {
scope->RecordInnerScopeEvalCall();
function_state_->RecordFunctionOrEvalCall(); function_state_->RecordFunctionOrEvalCall();
if (is_sloppy(scope->language_mode())) {
// For sloppy scopes we also have to record the call at function level,
// in case it includes declarations that will be hoisted.
scope->GetDeclarationScope()->RecordEvalCall();
}
// This call is only necessary to track evals that may be
// inside arrow function parameter lists. In that case,
// Scope::Snapshot::Reparent will move this bit down into
// the arrow function's scope.
scope->RecordEvalCall(); scope->RecordEvalCall();
return Call::IS_POSSIBLY_EVAL; return Call::IS_POSSIBLY_EVAL;
......
...@@ -2574,12 +2574,11 @@ Block* Parser::BuildParameterInitializationBlock( ...@@ -2574,12 +2574,11 @@ Block* Parser::BuildParameterInitializationBlock(
initial_value, kNoSourcePosition); initial_value, kNoSourcePosition);
} }
Scope* param_scope = scope(); DeclarationScope* param_scope = scope()->AsDeclarationScope();
ScopedPtrList<Statement>* param_init_statements = &init_statements; ScopedPtrList<Statement>* param_init_statements = &init_statements;
base::Optional<ScopedPtrList<Statement>> non_simple_param_init_statements; base::Optional<ScopedPtrList<Statement>> non_simple_param_init_statements;
if (!parameter->is_simple() && if (!parameter->is_simple() && param_scope->sloppy_eval_can_extend_vars()) {
scope()->AsDeclarationScope()->calls_sloppy_eval()) {
param_scope = NewVarblockScope(); param_scope = NewVarblockScope();
param_scope->set_start_position(parameter->pattern->position()); param_scope->set_start_position(parameter->pattern->position());
param_scope->set_end_position(parameter->initializer_end_position); param_scope->set_end_position(parameter->initializer_end_position);
...@@ -2604,7 +2603,7 @@ Block* Parser::BuildParameterInitializationBlock( ...@@ -2604,7 +2603,7 @@ Block* Parser::BuildParameterInitializationBlock(
factory()->NewBlock(true, *non_simple_param_init_statements); factory()->NewBlock(true, *non_simple_param_init_statements);
non_simple_param_init_statements.reset(); non_simple_param_init_statements.reset();
param_block->set_scope(param_scope); param_block->set_scope(param_scope);
param_scope = param_scope->FinalizeBlockScope(); param_scope = param_scope->FinalizeBlockScope()->AsDeclarationScope();
init_statements.Add(param_block); init_statements.Add(param_block);
} }
++index; ++index;
......
...@@ -21,8 +21,9 @@ namespace internal { ...@@ -21,8 +21,9 @@ namespace internal {
namespace { namespace {
using ScopeCallsSloppyEvalField = BitField8<bool, 0, 1>; using ScopeSloppyEvalCanExtendVarsField = BitField8<bool, 0, 1>;
using InnerScopeCallsEvalField = ScopeCallsSloppyEvalField::Next<bool, 1>; using InnerScopeCallsEvalField =
ScopeSloppyEvalCanExtendVarsField::Next<bool, 1>;
using VariableMaybeAssignedField = BitField8<bool, 0, 1>; using VariableMaybeAssignedField = BitField8<bool, 0, 1>;
using VariableContextAllocatedField = VariableMaybeAssignedField::Next<bool, 1>; using VariableContextAllocatedField = VariableMaybeAssignedField::Next<bool, 1>;
...@@ -352,9 +353,9 @@ void PreparseDataBuilder::SaveDataForScope(Scope* scope) { ...@@ -352,9 +353,9 @@ void PreparseDataBuilder::SaveDataForScope(Scope* scope) {
#endif #endif
uint8_t eval = uint8_t eval =
ScopeCallsSloppyEvalField::encode( ScopeSloppyEvalCanExtendVarsField::encode(
scope->is_declaration_scope() && scope->is_declaration_scope() &&
scope->AsDeclarationScope()->calls_sloppy_eval()) | scope->AsDeclarationScope()->sloppy_eval_can_extend_vars()) |
InnerScopeCallsEvalField::encode(scope->inner_scope_calls_eval()); InnerScopeCallsEvalField::encode(scope->inner_scope_calls_eval());
byte_data_.Reserve(kUint8Size); byte_data_.Reserve(kUint8Size);
byte_data_.WriteUint8(eval); byte_data_.WriteUint8(eval);
...@@ -599,7 +600,7 @@ void BaseConsumedPreparseData<Data>::RestoreDataForScope(Scope* scope) { ...@@ -599,7 +600,7 @@ void BaseConsumedPreparseData<Data>::RestoreDataForScope(Scope* scope) {
CHECK(scope_data_->HasRemainingBytes(ByteData::kUint8Size)); CHECK(scope_data_->HasRemainingBytes(ByteData::kUint8Size));
uint32_t eval = scope_data_->ReadUint8(); uint32_t eval = scope_data_->ReadUint8();
if (ScopeCallsSloppyEvalField::decode(eval)) scope->RecordEvalCall(); if (ScopeSloppyEvalCanExtendVarsField::decode(eval)) scope->RecordEvalCall();
if (InnerScopeCallsEvalField::decode(eval)) scope->RecordInnerScopeEvalCall(); if (InnerScopeCallsEvalField::decode(eval)) scope->RecordInnerScopeEvalCall();
if (scope->is_function_scope()) { if (scope->is_function_scope()) {
......
...@@ -386,7 +386,7 @@ PreParserBlock PreParser::BuildParameterInitializationBlock( ...@@ -386,7 +386,7 @@ PreParserBlock PreParser::BuildParameterInitializationBlock(
const PreParserFormalParameters& parameters) { const PreParserFormalParameters& parameters) {
DCHECK(!parameters.is_simple); DCHECK(!parameters.is_simple);
DCHECK(scope()->is_function_scope()); DCHECK(scope()->is_function_scope());
if (scope()->AsDeclarationScope()->calls_sloppy_eval() && if (scope()->AsDeclarationScope()->sloppy_eval_can_extend_vars() &&
preparse_data_builder_ != nullptr) { preparse_data_builder_ != nullptr) {
// We cannot replicate the Scope structure constructed by the Parser, // We cannot replicate the Scope structure constructed by the Parser,
// because we've lost information whether each individual parameter was // because we've lost information whether each individual parameter was
......
...@@ -1098,7 +1098,7 @@ TEST(ScopeUsesArgumentsSuperThis) { ...@@ -1098,7 +1098,7 @@ TEST(ScopeUsesArgumentsSuperThis) {
} }
if (is_sloppy(scope->language_mode())) { if (is_sloppy(scope->language_mode())) {
CHECK_EQ((source_data[i].expected & EVAL) != 0, CHECK_EQ((source_data[i].expected & EVAL) != 0,
scope->AsDeclarationScope()->calls_sloppy_eval()); scope->AsDeclarationScope()->sloppy_eval_can_extend_vars());
} }
} }
} }
......
// Copyright 2019 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.
//
// Flags: --stress-lazy-source-positions
eval(`
eval("");
(function f() {
// This undefined should always be known to be the global undefined value,
// even though there is a sloppy eval call inside the top eval scope.
return undefined;
})();
`);
// The above logic should work through multiple layers of eval nesting.
eval(`
eval(\`
eval(\\\`
eval("");
(function f() {
return undefined;
})();
\\\`);
\`);
`);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment