Reviewers: Dmitry Lomov (chromium),
Message:
dslomov, could you have an early look at this "dynamic strong mode scoping
errors CL?
The approach here is that when binding a script to a context, we check the
free
variables we know of (so, not inside lazy functions) against the context.
This CL does *not* implement checking variables inside lazy functions
whenever
the lazy func is compiled.
(Iirc this was the approach we talked about, though other approaches such as
doing the check whenever a function is called were on the table... so this
checks inside eager functions at compile time, not at call time.)
No tests yet because there's no trivial way to make a test consist of
multiple
.js files (though, d8 does the right thing w/ "d8 foo.js bar.js", so,
compiles
them separately).
Description:
Strawman: check strong mode free variables against the global object.
[Work in progress, not for committing]
BUG=
Please review this at https://codereview.chromium.org/1005063002/
Base URL: https://chromium.googlesource.com/v8/v8.git@master
Affected files (+75, -16 lines):
M src/api.cc
M src/messages.js
M src/objects.h
M src/scopeinfo.cc
M src/scopes.h
M src/scopes.cc
Index: src/api.cc
diff --git a/src/api.cc b/src/api.cc
index
2d2bd1f23b8b11d80b6c1bc190a856b43b15ac99..af7459cc09f18d5a92fe8b73138b6dc8e75a8626
100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -36,6 +36,7 @@
#include "src/messages.h"
#include "src/natives.h"
#include "src/parser.h"
+#include "src/pending-compilation-error-handler.h"
#include "src/profile-generator-inl.h"
#include "src/property.h"
#include "src/property-details.h"
@@ -1490,9 +1491,29 @@ Local<Script> UnboundScript::BindToCurrentContext() {
i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
i::Handle<i::SharedFunctionInfo>
function_info(i::SharedFunctionInfo::cast(*obj), obj->GetIsolate());
+ i::Isolate* isolate = obj->GetIsolate();
+
+ i::ScopeInfo* scope_info = function_info->scope_info();
+ i::Handle<i::JSReceiver>
global(isolate->native_context()->global_object());
+ for (int i = 0; i < scope_info->StrongModeFreeVariableCount(); ++i) {
+ i::Handle<i::Name> name(scope_info->StrongModeFreeVariableName(i));
+ Maybe<bool> has = i::JSReceiver::HasOwnProperty(global, name);
+ if (has.IsJust() && !has.FromJust()) {
+ i::PendingCompilationErrorHandler pending_error_handler_;
+ pending_error_handler_.ReportMessageAt(
+ // FIXME: location
+ 0, 0, "strong_unbound_global", reinterpret_cast<const
char*>(NULL),
+ i::kReferenceError);
+ i::Handle<i::Script>
script(i::Script::cast(function_info->script()));
+ pending_error_handler_.ThrowPendingError(isolate, script);
+ isolate->ReportPendingMessages();
+ isolate->OptionalRescheduleException(true);
+ return Local<Script>();
+ }
+ }
i::Handle<i::JSFunction> function =
obj->GetIsolate()->factory()->NewFunctionFromSharedFunctionInfo(
- function_info, obj->GetIsolate()->native_context());
+ function_info, isolate->native_context());
return ToApiHandle<Script>(function);
}
@@ -1940,7 +1961,9 @@ MaybeLocal<Script>
ScriptCompiler::Compile(Local<Context> context,
i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
Local<UnboundScript> generic = ToApiHandle<UnboundScript>(result);
if (generic.IsEmpty()) return Local<Script>();
- RETURN_ESCAPED(generic->BindToCurrentContext());
+ Local<Script> bound = generic->BindToCurrentContext();
+ if (bound.IsEmpty()) return Local<Script>();
+ RETURN_ESCAPED(bound);
}
Index: src/messages.js
diff --git a/src/messages.js b/src/messages.js
index
12170c463a54cfca49b984226a5e07964ed57f32..b7df55df51f5a3d51a4cab067fa7d68521c64452
100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -172,6 +172,7 @@ var kMessages = {
strong_for_in: ["In strong mode, 'for'-'in' loops are
deprecated, use 'for'-'of' instead"],
strong_empty: ["In strong mode, empty sub-statements
are deprecated, make them explicit with '{}' instead"],
strong_use_before_declaration: ["In strong mode, declaring
variable '", "%0", "' before its use is required"],
+ strong_unbound_global: ["In strong mode, using an undeclared
global variable is not allowed"],
strong_super_call_missing: ["In strong mode, invoking the super
constructor in a subclass is required"],
strong_super_call_duplicate: ["In strong mode, invoking the super
constructor multiple times is deprecated"],
strong_super_call_nested: ["In strong mode, invoking the super
constructor nested inside another statement or expression is deprecated"],
Index: src/objects.h
diff --git a/src/objects.h b/src/objects.h
index
cf6d1613e6545724162d07b7fa22e4ab759f58c6..2c4f3ddb45cd3cd5c588555646966c7ee22119ac
100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -4306,6 +4306,8 @@ class ScopeInfo : public FixedArray {
// exposed to the user in a debugger.
bool LocalIsSynthetic(int var);
+ String* StrongModeFreeVariableName(int var);
+
// Lookup support for serialized scope info. Returns the
// the stack slot index for a given slot name if the slot is
// present; otherwise returns a value < 0. The name must be an
internalized
@@ -4358,11 +4360,12 @@ class ScopeInfo : public FixedArray {
// 3. The number of non-parameter variables allocated on the stack.
// 4. The number of non-parameter and parameter variables allocated in
the
// context.
-#define FOR_EACH_NUMERIC_FIELD(V) \
- V(Flags) \
- V(ParameterCount) \
- V(StackLocalCount) \
- V(ContextLocalCount)
+#define FOR_EACH_NUMERIC_FIELD(V) \
+ V(Flags) \
+ V(ParameterCount) \
+ V(StackLocalCount) \
+ V(ContextLocalCount) \
+ V(StrongModeFreeVariableCount)
#define FIELD_ACCESSORS(name) \
void Set##name(int value) { \
@@ -4414,10 +4417,12 @@ class ScopeInfo : public FixedArray {
// information about the function variable. It always occupies two
array
// slots: a. The name of the function variable.
// b. The context or stack slot index for the variable.
+ // FIXME: update the comment
int ParameterEntriesIndex();
int StackLocalEntriesIndex();
int ContextLocalNameEntriesIndex();
int ContextLocalInfoEntriesIndex();
+ int StrongModeFreeVariableEntriesIndex();
int FunctionNameEntryIndex();
// Location of the function variable for named function expressions.
Index: src/scopeinfo.cc
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index
d62bc4129588196d3f3faf6d7c1fd035b39bbaa6..ed4705465e0e293b0baad49035bfdb38e1e32141
100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -18,9 +18,14 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate,
Zone* zone,
// Collect stack and context locals.
ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
- scope->CollectStackAndContextLocals(&stack_locals, &context_locals);
+ ZoneList<Variable*> strong_mode_free_variables(0, zone);
+
+ scope->CollectStackAndContextLocals(&stack_locals, &context_locals,
+ &strong_mode_free_variables);
const int stack_local_count = stack_locals.length();
const int context_local_count = context_locals.length();
+ const int strong_mode_free_variable_count =
+ strong_mode_free_variables.length();
// Make sure we allocate the correct amount.
DCHECK(scope->StackLocalCount() == stack_local_count);
DCHECK(scope->ContextLocalCount() == context_local_count);
@@ -49,9 +54,9 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate,
Zone* zone,
const bool has_function_name = function_name_info != NONE;
const int parameter_count = scope->num_parameters();
- const int length = kVariablePartIndex
- + parameter_count + stack_local_count + 2 * context_local_count
- + (has_function_name ? 2 : 0);
+ const int length = kVariablePartIndex + parameter_count +
stack_local_count +
+ 2 * context_local_count + (has_function_name ? 2 : 0)
+
+ strong_mode_free_variable_count;
Factory* factory = isolate->factory();
Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
@@ -71,6 +76,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate,
Zone* zone,
scope_info->SetParameterCount(parameter_count);
scope_info->SetStackLocalCount(stack_local_count);
scope_info->SetContextLocalCount(context_local_count);
+
scope_info->SetStrongModeFreeVariableCount(strong_mode_free_variable_count);
int index = kVariablePartIndex;
// Add parameters.
@@ -113,6 +119,11 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate,
Zone* zone,
scope_info->set(index++, Smi::FromInt(value));
}
+ DCHECK(index == scope_info->StrongModeFreeVariableEntriesIndex());
+ for (int i = 0; i < strong_mode_free_variable_count; ++i) {
+ scope_info->set(index++, *strong_mode_free_variables[i]->name());
+ }
+
// If present, add the function variable name and its index.
DCHECK(index == scope_info->FunctionNameEntryIndex());
if (has_function_name) {
@@ -285,6 +296,13 @@ bool ScopeInfo::LocalIsSynthetic(int var) {
}
+String* ScopeInfo::StrongModeFreeVariableName(int var) {
+ DCHECK(0 <= var && var < StrongModeFreeVariableCount());
+ int info_index = StrongModeFreeVariableEntriesIndex() + var;
+ return String::cast(get(info_index));
+}
+
+
int ScopeInfo::StackSlotIndex(String* name) {
DCHECK(name->IsInternalizedString());
if (length() > 0) {
@@ -432,11 +450,16 @@ int ScopeInfo::ContextLocalInfoEntriesIndex() {
}
-int ScopeInfo::FunctionNameEntryIndex() {
+int ScopeInfo::StrongModeFreeVariableEntriesIndex() {
return ContextLocalInfoEntriesIndex() + ContextLocalCount();
}
+int ScopeInfo::FunctionNameEntryIndex() {
+ return StrongModeFreeVariableEntriesIndex() +
StrongModeFreeVariableCount();
+}
+
+
int ContextSlotCache::Hash(Object* data, String* name) {
// Uses only lower 32 bits if pointers are larger.
uintptr_t addr_hash =
Index: src/scopes.cc
diff --git a/src/scopes.cc b/src/scopes.cc
index
c744dd418bbaaca2b74567048f30ecf208274da3..7e7955fba17c3dc0e13703b5ed5a0c2ce2ac0f24
100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -593,8 +593,9 @@ class VarAndOrder {
};
-void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
- ZoneList<Variable*>*
context_locals) {
+void Scope::CollectStackAndContextLocals(
+ ZoneList<Variable*>* stack_locals, ZoneList<Variable*>* context_locals,
+ ZoneList<Variable*>* strong_mode_free_variables) {
DCHECK(stack_locals != NULL);
DCHECK(context_locals != NULL);
@@ -628,6 +629,11 @@ void
Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
p != NULL;
p = variables_.Next(p)) {
Variable* var = reinterpret_cast<Variable*>(p->value);
+ if (is_strong(language_mode()) && strong_mode_free_variables &&
+ var->mode() == DYNAMIC_GLOBAL) {
+ strong_mode_free_variables->Add(var, zone());
+ }
+
if (var->is_used()) {
vars.Add(VarAndOrder(var, p->order), zone());
}
Index: src/scopes.h
diff --git a/src/scopes.h b/src/scopes.h
index
44434fa3622091d19d6b9e511e881883fb0b802f..25c629a2e3a89824df2ab9fa18dced4e73f1849d
100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -415,8 +415,9 @@ class Scope: public ZoneObject {
// Collect stack and context allocated local variables in this scope.
Note
// that the function variable - if present - is not collected and should
be
// handled separately.
- void CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
- ZoneList<Variable*>* context_locals);
+ void CollectStackAndContextLocals(
+ ZoneList<Variable*>* stack_locals, ZoneList<Variable*>*
context_locals,
+ ZoneList<Variable*>* strong_mode_free_variables = nullptr);
// Current number of var or const locals.
int num_var_or_const() { return num_var_or_const_; }
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.