2011-05-11 11:26:11 +00:00
|
|
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
2014-04-29 06:42:26 +00:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2015-08-14 09:41:32 +00:00
|
|
|
#include "src/contexts.h"
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2015-11-26 16:22:34 +00:00
|
|
|
#include "src/ast/scopeinfo.h"
|
2014-06-03 08:12:43 +00:00
|
|
|
#include "src/bootstrapper.h"
|
2015-07-31 11:07:50 +00:00
|
|
|
#include "src/debug/debug.h"
|
2015-09-01 09:25:19 +00:00
|
|
|
#include "src/isolate-inl.h"
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2009-05-25 10:05:56 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
2008-07-03 15:10:15 +00:00
|
|
|
|
2014-11-07 16:29:13 +00:00
|
|
|
|
2014-11-12 11:34:09 +00:00
|
|
|
Handle<ScriptContextTable> ScriptContextTable::Extend(
|
|
|
|
Handle<ScriptContextTable> table, Handle<Context> script_context) {
|
|
|
|
Handle<ScriptContextTable> result;
|
2014-11-07 16:29:13 +00:00
|
|
|
int used = table->used();
|
|
|
|
int length = table->length();
|
|
|
|
CHECK(used >= 0 && length > 0 && used < length);
|
2015-09-01 07:06:49 +00:00
|
|
|
if (used + kFirstContextSlot == length) {
|
2014-11-07 16:29:13 +00:00
|
|
|
CHECK(length < Smi::kMaxValue / 2);
|
2015-08-05 08:53:17 +00:00
|
|
|
Isolate* isolate = table->GetIsolate();
|
|
|
|
Handle<FixedArray> copy =
|
|
|
|
isolate->factory()->CopyFixedArrayAndGrow(table, length);
|
|
|
|
copy->set_map(isolate->heap()->script_context_table_map());
|
|
|
|
result = Handle<ScriptContextTable>::cast(copy);
|
2014-11-07 16:29:13 +00:00
|
|
|
} else {
|
|
|
|
result = table;
|
|
|
|
}
|
|
|
|
result->set_used(used + 1);
|
|
|
|
|
2014-11-12 11:34:09 +00:00
|
|
|
DCHECK(script_context->IsScriptContext());
|
2015-09-01 07:06:49 +00:00
|
|
|
result->set(used + kFirstContextSlot, *script_context);
|
2014-11-07 16:29:13 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-12 11:34:09 +00:00
|
|
|
bool ScriptContextTable::Lookup(Handle<ScriptContextTable> table,
|
2014-11-07 16:29:13 +00:00
|
|
|
Handle<String> name, LookupResult* result) {
|
|
|
|
for (int i = 0; i < table->used(); i++) {
|
|
|
|
Handle<Context> context = GetContext(table, i);
|
2014-11-12 11:34:09 +00:00
|
|
|
DCHECK(context->IsScriptContext());
|
[es6] Parameter scopes for sloppy eval
This CL is a nightmare! For the utterly irrelevant edge case of a sloppy function with non-simple parameters and a call to direct eval, like here,
let x = 1;
function f(g = () => x) {
var y
eval("var x = 2")
return g() + x // f() = 3
}
we have to do all of the following, on top of the declaration block ("varblock") contexts we already introduce around the body:
- Introduce the ability for varblock contexts to have both a ScopeInfo and an extension object (e.g., the body varblock in the example will contain both a static var y and a dynamic var x). No other scope needs that. Since there are no context slots left, a special new struct is introduced that pairs up scope info and extension object.
- When declaring lookup slots in the runtime, this new struct is allocated in the case where an extension object has to be added to a block scope (at which point the block's extension slot still contains a plain ScopeInfo).
- While at it, introduce some abstraction to access context extension slots in a more controlled manner, in order to keep special-casing to a minimum.
- Make sure that even empty varblock contexts do not get optimised away when they contain a sloppy eval, so that they can host the potential extension object.
- Extend dynamic search for declaration contexts (used by sloppy direct eval) to recognize varblock contexts.
- In the parser, if a function has a sloppy direct eval, introduce an additional varblock scope around each non-simple (desugared) parameter, as required by the spec to contain possible dynamic var bindings.
- In the pattern rewriter, add the ability to hoist the named variables the pattern declares to an outer scope. That is required because the actual destructuring has to be evaluated inside the protecting varblock scope, but the bindings that the desugaring introduces are in the outer scope.
- ScopeInfos need to save the information whether a block is a varblock, to make sloppy eval calls work correctly that deserialise them as part of the scope chain.
- Add the ability to materialize block scopes with extension objects in the debugger. Likewise, enable setting extension variables in block scopes via the debugger interface.
- While at it, refactor and unify some respective code in the debugger.
Sorry, this CL is large. I could try to split it up, but everything is rather entangled.
@mstarzinger: Please review the changes to contexts.
@yangguo: Please have a look at the debugger stuff.
R=littledan@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:811,v8:2160
LOG=N
Review URL: https://codereview.chromium.org/1292753007
Cr-Commit-Position: refs/heads/master@{#30295}
2015-08-21 10:58:35 +00:00
|
|
|
Handle<ScopeInfo> scope_info(context->scope_info());
|
2014-11-07 16:29:13 +00:00
|
|
|
int slot_index = ScopeInfo::ContextSlotIndex(
|
2015-09-10 12:54:53 +00:00
|
|
|
scope_info, name, &result->mode, &result->init_flag,
|
2014-11-07 16:29:13 +00:00
|
|
|
&result->maybe_assigned_flag);
|
|
|
|
|
2015-09-10 12:54:53 +00:00
|
|
|
if (slot_index >= 0) {
|
2014-11-07 16:29:13 +00:00
|
|
|
result->context_index = i;
|
|
|
|
result->slot_index = slot_index;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
[es6] Parameter scopes for sloppy eval
This CL is a nightmare! For the utterly irrelevant edge case of a sloppy function with non-simple parameters and a call to direct eval, like here,
let x = 1;
function f(g = () => x) {
var y
eval("var x = 2")
return g() + x // f() = 3
}
we have to do all of the following, on top of the declaration block ("varblock") contexts we already introduce around the body:
- Introduce the ability for varblock contexts to have both a ScopeInfo and an extension object (e.g., the body varblock in the example will contain both a static var y and a dynamic var x). No other scope needs that. Since there are no context slots left, a special new struct is introduced that pairs up scope info and extension object.
- When declaring lookup slots in the runtime, this new struct is allocated in the case where an extension object has to be added to a block scope (at which point the block's extension slot still contains a plain ScopeInfo).
- While at it, introduce some abstraction to access context extension slots in a more controlled manner, in order to keep special-casing to a minimum.
- Make sure that even empty varblock contexts do not get optimised away when they contain a sloppy eval, so that they can host the potential extension object.
- Extend dynamic search for declaration contexts (used by sloppy direct eval) to recognize varblock contexts.
- In the parser, if a function has a sloppy direct eval, introduce an additional varblock scope around each non-simple (desugared) parameter, as required by the spec to contain possible dynamic var bindings.
- In the pattern rewriter, add the ability to hoist the named variables the pattern declares to an outer scope. That is required because the actual destructuring has to be evaluated inside the protecting varblock scope, but the bindings that the desugaring introduces are in the outer scope.
- ScopeInfos need to save the information whether a block is a varblock, to make sloppy eval calls work correctly that deserialise them as part of the scope chain.
- Add the ability to materialize block scopes with extension objects in the debugger. Likewise, enable setting extension variables in block scopes via the debugger interface.
- While at it, refactor and unify some respective code in the debugger.
Sorry, this CL is large. I could try to split it up, but everything is rather entangled.
@mstarzinger: Please review the changes to contexts.
@yangguo: Please have a look at the debugger stuff.
R=littledan@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:811,v8:2160
LOG=N
Review URL: https://codereview.chromium.org/1292753007
Cr-Commit-Position: refs/heads/master@{#30295}
2015-08-21 10:58:35 +00:00
|
|
|
bool Context::is_declaration_context() {
|
|
|
|
if (IsFunctionContext() || IsNativeContext() || IsScriptContext()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!IsBlockContext()) return false;
|
|
|
|
Object* ext = extension();
|
|
|
|
// If we have the special extension, we immediately know it must be a
|
|
|
|
// declaration scope. That's just a small performance shortcut.
|
|
|
|
return ext->IsSloppyBlockWithEvalContextExtension()
|
|
|
|
|| ScopeInfo::cast(ext)->is_declaration_scope();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-28 15:22:08 +00:00
|
|
|
Context* Context::declaration_context() {
|
|
|
|
Context* current = this;
|
[es6] Parameter scopes for sloppy eval
This CL is a nightmare! For the utterly irrelevant edge case of a sloppy function with non-simple parameters and a call to direct eval, like here,
let x = 1;
function f(g = () => x) {
var y
eval("var x = 2")
return g() + x // f() = 3
}
we have to do all of the following, on top of the declaration block ("varblock") contexts we already introduce around the body:
- Introduce the ability for varblock contexts to have both a ScopeInfo and an extension object (e.g., the body varblock in the example will contain both a static var y and a dynamic var x). No other scope needs that. Since there are no context slots left, a special new struct is introduced that pairs up scope info and extension object.
- When declaring lookup slots in the runtime, this new struct is allocated in the case where an extension object has to be added to a block scope (at which point the block's extension slot still contains a plain ScopeInfo).
- While at it, introduce some abstraction to access context extension slots in a more controlled manner, in order to keep special-casing to a minimum.
- Make sure that even empty varblock contexts do not get optimised away when they contain a sloppy eval, so that they can host the potential extension object.
- Extend dynamic search for declaration contexts (used by sloppy direct eval) to recognize varblock contexts.
- In the parser, if a function has a sloppy direct eval, introduce an additional varblock scope around each non-simple (desugared) parameter, as required by the spec to contain possible dynamic var bindings.
- In the pattern rewriter, add the ability to hoist the named variables the pattern declares to an outer scope. That is required because the actual destructuring has to be evaluated inside the protecting varblock scope, but the bindings that the desugaring introduces are in the outer scope.
- ScopeInfos need to save the information whether a block is a varblock, to make sloppy eval calls work correctly that deserialise them as part of the scope chain.
- Add the ability to materialize block scopes with extension objects in the debugger. Likewise, enable setting extension variables in block scopes via the debugger interface.
- While at it, refactor and unify some respective code in the debugger.
Sorry, this CL is large. I could try to split it up, but everything is rather entangled.
@mstarzinger: Please review the changes to contexts.
@yangguo: Please have a look at the debugger stuff.
R=littledan@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:811,v8:2160
LOG=N
Review URL: https://codereview.chromium.org/1292753007
Cr-Commit-Position: refs/heads/master@{#30295}
2015-08-21 10:58:35 +00:00
|
|
|
while (!current->is_declaration_context()) {
|
2011-06-28 15:22:08 +00:00
|
|
|
current = current->previous();
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(current->closure() == closure());
|
2011-06-28 15:22:08 +00:00
|
|
|
}
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
[es6] Parameter scopes for sloppy eval
This CL is a nightmare! For the utterly irrelevant edge case of a sloppy function with non-simple parameters and a call to direct eval, like here,
let x = 1;
function f(g = () => x) {
var y
eval("var x = 2")
return g() + x // f() = 3
}
we have to do all of the following, on top of the declaration block ("varblock") contexts we already introduce around the body:
- Introduce the ability for varblock contexts to have both a ScopeInfo and an extension object (e.g., the body varblock in the example will contain both a static var y and a dynamic var x). No other scope needs that. Since there are no context slots left, a special new struct is introduced that pairs up scope info and extension object.
- When declaring lookup slots in the runtime, this new struct is allocated in the case where an extension object has to be added to a block scope (at which point the block's extension slot still contains a plain ScopeInfo).
- While at it, introduce some abstraction to access context extension slots in a more controlled manner, in order to keep special-casing to a minimum.
- Make sure that even empty varblock contexts do not get optimised away when they contain a sloppy eval, so that they can host the potential extension object.
- Extend dynamic search for declaration contexts (used by sloppy direct eval) to recognize varblock contexts.
- In the parser, if a function has a sloppy direct eval, introduce an additional varblock scope around each non-simple (desugared) parameter, as required by the spec to contain possible dynamic var bindings.
- In the pattern rewriter, add the ability to hoist the named variables the pattern declares to an outer scope. That is required because the actual destructuring has to be evaluated inside the protecting varblock scope, but the bindings that the desugaring introduces are in the outer scope.
- ScopeInfos need to save the information whether a block is a varblock, to make sloppy eval calls work correctly that deserialise them as part of the scope chain.
- Add the ability to materialize block scopes with extension objects in the debugger. Likewise, enable setting extension variables in block scopes via the debugger interface.
- While at it, refactor and unify some respective code in the debugger.
Sorry, this CL is large. I could try to split it up, but everything is rather entangled.
@mstarzinger: Please review the changes to contexts.
@yangguo: Please have a look at the debugger stuff.
R=littledan@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:811,v8:2160
LOG=N
Review URL: https://codereview.chromium.org/1292753007
Cr-Commit-Position: refs/heads/master@{#30295}
2015-08-21 10:58:35 +00:00
|
|
|
JSObject* Context::extension_object() {
|
|
|
|
DCHECK(IsNativeContext() || IsFunctionContext() || IsBlockContext());
|
|
|
|
Object* object = extension();
|
|
|
|
if (object == nullptr) return nullptr;
|
|
|
|
if (IsBlockContext()) {
|
|
|
|
if (!object->IsSloppyBlockWithEvalContextExtension()) return nullptr;
|
|
|
|
object = SloppyBlockWithEvalContextExtension::cast(object)->extension();
|
|
|
|
}
|
|
|
|
DCHECK(object->IsJSContextExtensionObject() ||
|
|
|
|
(IsNativeContext() && object->IsJSGlobalObject()));
|
|
|
|
return JSObject::cast(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
JSReceiver* Context::extension_receiver() {
|
|
|
|
DCHECK(IsNativeContext() || IsWithContext() ||
|
|
|
|
IsFunctionContext() || IsBlockContext());
|
|
|
|
return IsWithContext() ? JSReceiver::cast(extension()) : extension_object();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ScopeInfo* Context::scope_info() {
|
|
|
|
DCHECK(IsModuleContext() || IsScriptContext() || IsBlockContext());
|
|
|
|
Object* object = extension();
|
|
|
|
if (object->IsSloppyBlockWithEvalContextExtension()) {
|
|
|
|
DCHECK(IsBlockContext());
|
|
|
|
object = SloppyBlockWithEvalContextExtension::cast(object)->scope_info();
|
|
|
|
}
|
|
|
|
return ScopeInfo::cast(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String* Context::catch_name() {
|
|
|
|
DCHECK(IsCatchContext());
|
|
|
|
return String::cast(extension());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-12 11:34:09 +00:00
|
|
|
Context* Context::script_context() {
|
Get rid of static module allocation, do it in code.
Modules now have their own local scope, represented by their own context.
Module instance objects have an accessor for every export that forwards
access to the respective slot from the module's context. (Exports that are
modules themselves, however, are simple data properties.)
All modules have a _hosting_ scope/context, which (currently) is the
(innermost) enclosing global scope. To deal with recursion, nested modules
are hosted by the same scope as global ones.
For every (global or nested) module literal, the hosting context has an
internal slot that points directly to the respective module context. This
enables quick access to (statically resolved) module members by 2-dimensional
access through the hosting context. For example,
module A {
let x;
module B { let y; }
}
module C { let z; }
allocates contexts as follows:
[header| .A | .B | .C | A | C ] (global)
| | |
| | +-- [header| z ] (module)
| |
| +------- [header| y ] (module)
|
+------------ [header| x | B ] (module)
Here, .A, .B, .C are the internal slots pointing to the hosted module
contexts, whereas A, B, C hold the actual instance objects (note that every
module context also points to the respective instance object through its
extension slot in the header).
To deal with arbitrary recursion and aliases between modules,
they are created and initialized in several stages. Each stage applies to
all modules in the hosting global scope, including nested ones.
1. Allocate: for each module _literal_, allocate the module contexts and
respective instance object and wire them up. This happens in the
PushModuleContext runtime function, as generated by AllocateModules
(invoked by VisitDeclarations in the hosting scope).
2. Bind: for each module _declaration_ (i.e. literals as well as aliases),
assign the respective instance object to respective local variables. This
happens in VisitModuleDeclaration, and uses the instance objects created
in the previous stage.
For each module _literal_, this phase also constructs a module descriptor
for the next stage. This happens in VisitModuleLiteral.
3. Populate: invoke the DeclareModules runtime function to populate each
_instance_ object with accessors for it exports. This is generated by
DeclareModules (invoked by VisitDeclarations in the hosting scope again),
and uses the descriptors generated in the previous stage.
4. Initialize: execute the module bodies (and other code) in sequence. This
happens by the separate statements generated for module bodies. To reenter
the module scopes properly, the parser inserted ModuleStatements.
R=mstarzinger@chromium.org,svenpanne@chromium.org
BUG=
Review URL: https://codereview.chromium.org/11093074
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13033 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2012-11-22 10:25:22 +00:00
|
|
|
Context* current = this;
|
2014-11-12 11:34:09 +00:00
|
|
|
while (!current->IsScriptContext()) {
|
Get rid of static module allocation, do it in code.
Modules now have their own local scope, represented by their own context.
Module instance objects have an accessor for every export that forwards
access to the respective slot from the module's context. (Exports that are
modules themselves, however, are simple data properties.)
All modules have a _hosting_ scope/context, which (currently) is the
(innermost) enclosing global scope. To deal with recursion, nested modules
are hosted by the same scope as global ones.
For every (global or nested) module literal, the hosting context has an
internal slot that points directly to the respective module context. This
enables quick access to (statically resolved) module members by 2-dimensional
access through the hosting context. For example,
module A {
let x;
module B { let y; }
}
module C { let z; }
allocates contexts as follows:
[header| .A | .B | .C | A | C ] (global)
| | |
| | +-- [header| z ] (module)
| |
| +------- [header| y ] (module)
|
+------------ [header| x | B ] (module)
Here, .A, .B, .C are the internal slots pointing to the hosted module
contexts, whereas A, B, C hold the actual instance objects (note that every
module context also points to the respective instance object through its
extension slot in the header).
To deal with arbitrary recursion and aliases between modules,
they are created and initialized in several stages. Each stage applies to
all modules in the hosting global scope, including nested ones.
1. Allocate: for each module _literal_, allocate the module contexts and
respective instance object and wire them up. This happens in the
PushModuleContext runtime function, as generated by AllocateModules
(invoked by VisitDeclarations in the hosting scope).
2. Bind: for each module _declaration_ (i.e. literals as well as aliases),
assign the respective instance object to respective local variables. This
happens in VisitModuleDeclaration, and uses the instance objects created
in the previous stage.
For each module _literal_, this phase also constructs a module descriptor
for the next stage. This happens in VisitModuleLiteral.
3. Populate: invoke the DeclareModules runtime function to populate each
_instance_ object with accessors for it exports. This is generated by
DeclareModules (invoked by VisitDeclarations in the hosting scope again),
and uses the descriptors generated in the previous stage.
4. Initialize: execute the module bodies (and other code) in sequence. This
happens by the separate statements generated for module bodies. To reenter
the module scopes properly, the parser inserted ModuleStatements.
R=mstarzinger@chromium.org,svenpanne@chromium.org
BUG=
Review URL: https://codereview.chromium.org/11093074
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13033 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2012-11-22 10:25:22 +00:00
|
|
|
current = current->previous();
|
|
|
|
}
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-17 09:03:08 +00:00
|
|
|
Context* Context::native_context() {
|
2015-07-01 15:34:18 +00:00
|
|
|
// Fast case: the receiver context is already a native context.
|
|
|
|
if (IsNativeContext()) return this;
|
|
|
|
// The global object has a direct pointer to the native context. If the
|
|
|
|
// following DCHECK fails, the native context is probably being accessed
|
|
|
|
// indirectly during bootstrapping. This is unsupported.
|
2015-11-02 14:57:59 +00:00
|
|
|
DCHECK(global_object()->IsJSGlobalObject());
|
2015-07-01 15:34:18 +00:00
|
|
|
return global_object()->native_context();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Split window support from V8.
Here is a description of the background and design of split window in Chrome and V8:
https://docs.google.com/a/google.com/Doc?id=chhjkpg_47fwddxbfr
This change list splits the window object into two parts: 1) an inner window object used as the global object of contexts; 2) an outer window object exposed to JavaScript and accessible by the name 'window'. Firefox did it awhile ago, here are some discussions: https://wiki.mozilla.org/Gecko:SplitWindow. One additional benefit of splitting window in Chrome is that accessing global variables don't need security checks anymore, it can improve applications that use many global variables.
V8 support of split window:
There are a small number of changes on V8 api to support split window:
Security context is removed from V8, so does related API functions;
A global object can be detached from its context and reused by a new context;
Access checks on an object template can be turned on/off by default;
An object can turn on its access checks later;
V8 has a new object type, ApiGlobalObject, which is the outer window object type. The existing JSGlobalObject becomes the inner window object type. Security checks are moved from JSGlobalObject to ApiGlobalObject. ApiGlobalObject is the one exposed to JavaScript, it is accessible through Context::Global(). ApiGlobalObject's prototype is set to JSGlobalObject so that property lookups are forwarded to JSGlobalObject. ApiGlobalObject forwards all other property access requests to JSGlobalObject, such as SetProperty, DeleteProperty, etc.
Security token is moved to a global context, and ApiGlobalObject has a reference to its global context. JSGlobalObject has a reference to its global context as well. When accessing properties on a global object in JavaScript, the domain security check is performed by comparing the security token of the lexical context (Top::global_context()) to the token of global object's context. The check is only needed when the receiver is a window object, such as 'window.document'. Accessing global variables, such as 'var foo = 3; foo' does not need checks because the receiver is the inner window object.
When an outer window is detached from its global context (when a frame navigates away from a page), it is completely detached from the inner window. A new context is created for the new page, and the outer global object is reused. At this point, the access check on the DOMWindow wrapper of the old context is turned on. The code in old context is still able to access DOMWindow properties, but it has to go through domain security checks.
It is debatable on how to implement the outer window object. Currently each property access function has to check if the receiver is ApiGlobalObject type. This approach might be error-prone that one may forget to check the receiver when adding new functions. It is unlikely a performance issue because accessing global variables are more common than 'window.foo' style coding.
I am still working on the ARM port, and I'd like to hear comments and suggestions on the best way to support it in V8.
Review URL: http://codereview.chromium.org/7366
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@540 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2008-10-21 19:07:58 +00:00
|
|
|
JSObject* Context::global_proxy() {
|
2012-08-17 09:03:08 +00:00
|
|
|
return native_context()->global_proxy_object();
|
Split window support from V8.
Here is a description of the background and design of split window in Chrome and V8:
https://docs.google.com/a/google.com/Doc?id=chhjkpg_47fwddxbfr
This change list splits the window object into two parts: 1) an inner window object used as the global object of contexts; 2) an outer window object exposed to JavaScript and accessible by the name 'window'. Firefox did it awhile ago, here are some discussions: https://wiki.mozilla.org/Gecko:SplitWindow. One additional benefit of splitting window in Chrome is that accessing global variables don't need security checks anymore, it can improve applications that use many global variables.
V8 support of split window:
There are a small number of changes on V8 api to support split window:
Security context is removed from V8, so does related API functions;
A global object can be detached from its context and reused by a new context;
Access checks on an object template can be turned on/off by default;
An object can turn on its access checks later;
V8 has a new object type, ApiGlobalObject, which is the outer window object type. The existing JSGlobalObject becomes the inner window object type. Security checks are moved from JSGlobalObject to ApiGlobalObject. ApiGlobalObject is the one exposed to JavaScript, it is accessible through Context::Global(). ApiGlobalObject's prototype is set to JSGlobalObject so that property lookups are forwarded to JSGlobalObject. ApiGlobalObject forwards all other property access requests to JSGlobalObject, such as SetProperty, DeleteProperty, etc.
Security token is moved to a global context, and ApiGlobalObject has a reference to its global context. JSGlobalObject has a reference to its global context as well. When accessing properties on a global object in JavaScript, the domain security check is performed by comparing the security token of the lexical context (Top::global_context()) to the token of global object's context. The check is only needed when the receiver is a window object, such as 'window.document'. Accessing global variables, such as 'var foo = 3; foo' does not need checks because the receiver is the inner window object.
When an outer window is detached from its global context (when a frame navigates away from a page), it is completely detached from the inner window. A new context is created for the new page, and the outer global object is reused. At this point, the access check on the DOMWindow wrapper of the old context is turned on. The code in old context is still able to access DOMWindow properties, but it has to go through domain security checks.
It is debatable on how to implement the outer window object. Currently each property access function has to check if the receiver is ApiGlobalObject type. This approach might be error-prone that one may forget to check the receiver when adding new functions. It is unlikely a performance issue because accessing global variables are more common than 'window.foo' style coding.
I am still working on the ARM port, and I'd like to hear comments and suggestions on the best way to support it in V8.
Review URL: http://codereview.chromium.org/7366
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@540 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2008-10-21 19:07:58 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 09:52:11 +00:00
|
|
|
|
Split window support from V8.
Here is a description of the background and design of split window in Chrome and V8:
https://docs.google.com/a/google.com/Doc?id=chhjkpg_47fwddxbfr
This change list splits the window object into two parts: 1) an inner window object used as the global object of contexts; 2) an outer window object exposed to JavaScript and accessible by the name 'window'. Firefox did it awhile ago, here are some discussions: https://wiki.mozilla.org/Gecko:SplitWindow. One additional benefit of splitting window in Chrome is that accessing global variables don't need security checks anymore, it can improve applications that use many global variables.
V8 support of split window:
There are a small number of changes on V8 api to support split window:
Security context is removed from V8, so does related API functions;
A global object can be detached from its context and reused by a new context;
Access checks on an object template can be turned on/off by default;
An object can turn on its access checks later;
V8 has a new object type, ApiGlobalObject, which is the outer window object type. The existing JSGlobalObject becomes the inner window object type. Security checks are moved from JSGlobalObject to ApiGlobalObject. ApiGlobalObject is the one exposed to JavaScript, it is accessible through Context::Global(). ApiGlobalObject's prototype is set to JSGlobalObject so that property lookups are forwarded to JSGlobalObject. ApiGlobalObject forwards all other property access requests to JSGlobalObject, such as SetProperty, DeleteProperty, etc.
Security token is moved to a global context, and ApiGlobalObject has a reference to its global context. JSGlobalObject has a reference to its global context as well. When accessing properties on a global object in JavaScript, the domain security check is performed by comparing the security token of the lexical context (Top::global_context()) to the token of global object's context. The check is only needed when the receiver is a window object, such as 'window.document'. Accessing global variables, such as 'var foo = 3; foo' does not need checks because the receiver is the inner window object.
When an outer window is detached from its global context (when a frame navigates away from a page), it is completely detached from the inner window. A new context is created for the new page, and the outer global object is reused. At this point, the access check on the DOMWindow wrapper of the old context is turned on. The code in old context is still able to access DOMWindow properties, but it has to go through domain security checks.
It is debatable on how to implement the outer window object. Currently each property access function has to check if the receiver is ApiGlobalObject type. This approach might be error-prone that one may forget to check the receiver when adding new functions. It is unlikely a performance issue because accessing global variables are more common than 'window.foo' style coding.
I am still working on the ARM port, and I'd like to hear comments and suggestions on the best way to support it in V8.
Review URL: http://codereview.chromium.org/7366
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@540 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2008-10-21 19:07:58 +00:00
|
|
|
void Context::set_global_proxy(JSObject* object) {
|
2012-08-17 09:03:08 +00:00
|
|
|
native_context()->set_global_proxy_object(object);
|
Split window support from V8.
Here is a description of the background and design of split window in Chrome and V8:
https://docs.google.com/a/google.com/Doc?id=chhjkpg_47fwddxbfr
This change list splits the window object into two parts: 1) an inner window object used as the global object of contexts; 2) an outer window object exposed to JavaScript and accessible by the name 'window'. Firefox did it awhile ago, here are some discussions: https://wiki.mozilla.org/Gecko:SplitWindow. One additional benefit of splitting window in Chrome is that accessing global variables don't need security checks anymore, it can improve applications that use many global variables.
V8 support of split window:
There are a small number of changes on V8 api to support split window:
Security context is removed from V8, so does related API functions;
A global object can be detached from its context and reused by a new context;
Access checks on an object template can be turned on/off by default;
An object can turn on its access checks later;
V8 has a new object type, ApiGlobalObject, which is the outer window object type. The existing JSGlobalObject becomes the inner window object type. Security checks are moved from JSGlobalObject to ApiGlobalObject. ApiGlobalObject is the one exposed to JavaScript, it is accessible through Context::Global(). ApiGlobalObject's prototype is set to JSGlobalObject so that property lookups are forwarded to JSGlobalObject. ApiGlobalObject forwards all other property access requests to JSGlobalObject, such as SetProperty, DeleteProperty, etc.
Security token is moved to a global context, and ApiGlobalObject has a reference to its global context. JSGlobalObject has a reference to its global context as well. When accessing properties on a global object in JavaScript, the domain security check is performed by comparing the security token of the lexical context (Top::global_context()) to the token of global object's context. The check is only needed when the receiver is a window object, such as 'window.document'. Accessing global variables, such as 'var foo = 3; foo' does not need checks because the receiver is the inner window object.
When an outer window is detached from its global context (when a frame navigates away from a page), it is completely detached from the inner window. A new context is created for the new page, and the outer global object is reused. At this point, the access check on the DOMWindow wrapper of the old context is turned on. The code in old context is still able to access DOMWindow properties, but it has to go through domain security checks.
It is debatable on how to implement the outer window object. Currently each property access function has to check if the receiver is ApiGlobalObject type. This approach might be error-prone that one may forget to check the receiver when adding new functions. It is unlikely a performance issue because accessing global variables are more common than 'window.foo' style coding.
I am still working on the ARM port, and I'd like to hear comments and suggestions on the best way to support it in V8.
Review URL: http://codereview.chromium.org/7366
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@540 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2008-10-21 19:07:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-06 15:50:40 +00:00
|
|
|
/**
|
|
|
|
* Lookups a property in an object environment, taking the unscopables into
|
|
|
|
* account. This is used For HasBinding spec algorithms for ObjectEnvironment.
|
|
|
|
*/
|
|
|
|
static Maybe<PropertyAttributes> UnscopableLookup(LookupIterator* it) {
|
|
|
|
Isolate* isolate = it->isolate();
|
|
|
|
|
|
|
|
Maybe<PropertyAttributes> attrs = JSReceiver::GetPropertyAttributes(it);
|
2015-03-02 12:22:27 +00:00
|
|
|
DCHECK(attrs.IsJust() || isolate->has_pending_exception());
|
|
|
|
if (!attrs.IsJust() || attrs.FromJust() == ABSENT) return attrs;
|
2014-08-06 15:50:40 +00:00
|
|
|
|
2014-11-13 08:47:52 +00:00
|
|
|
Handle<Symbol> unscopables_symbol = isolate->factory()->unscopables_symbol();
|
2014-08-06 15:50:40 +00:00
|
|
|
Handle<Object> receiver = it->GetReceiver();
|
|
|
|
Handle<Object> unscopables;
|
|
|
|
MaybeHandle<Object> maybe_unscopables =
|
|
|
|
Object::GetProperty(receiver, unscopables_symbol);
|
|
|
|
if (!maybe_unscopables.ToHandle(&unscopables)) {
|
2015-03-02 11:26:55 +00:00
|
|
|
return Nothing<PropertyAttributes>();
|
2014-08-06 15:50:40 +00:00
|
|
|
}
|
|
|
|
if (!unscopables->IsSpecObject()) return attrs;
|
2014-12-16 20:07:27 +00:00
|
|
|
Handle<Object> blacklist;
|
|
|
|
MaybeHandle<Object> maybe_blacklist =
|
|
|
|
Object::GetProperty(unscopables, it->name());
|
|
|
|
if (!maybe_blacklist.ToHandle(&blacklist)) {
|
2014-08-06 15:50:40 +00:00
|
|
|
DCHECK(isolate->has_pending_exception());
|
2015-03-02 11:26:55 +00:00
|
|
|
return Nothing<PropertyAttributes>();
|
2014-08-06 15:50:40 +00:00
|
|
|
}
|
2015-03-31 15:14:04 +00:00
|
|
|
return blacklist->BooleanValue() ? Just(ABSENT) : attrs;
|
2014-08-06 15:50:40 +00:00
|
|
|
}
|
|
|
|
|
2014-11-07 16:29:13 +00:00
|
|
|
static void GetAttributesAndBindingFlags(VariableMode mode,
|
|
|
|
InitializationFlag init_flag,
|
|
|
|
PropertyAttributes* attributes,
|
|
|
|
BindingFlags* binding_flags) {
|
|
|
|
switch (mode) {
|
|
|
|
case VAR:
|
|
|
|
*attributes = NONE;
|
|
|
|
*binding_flags = MUTABLE_IS_INITIALIZED;
|
|
|
|
break;
|
|
|
|
case LET:
|
|
|
|
*attributes = NONE;
|
|
|
|
*binding_flags = (init_flag == kNeedsInitialization)
|
|
|
|
? MUTABLE_CHECK_INITIALIZED
|
|
|
|
: MUTABLE_IS_INITIALIZED;
|
|
|
|
break;
|
|
|
|
case CONST_LEGACY:
|
|
|
|
*attributes = READ_ONLY;
|
|
|
|
*binding_flags = (init_flag == kNeedsInitialization)
|
|
|
|
? IMMUTABLE_CHECK_INITIALIZED
|
|
|
|
: IMMUTABLE_IS_INITIALIZED;
|
|
|
|
break;
|
|
|
|
case CONST:
|
|
|
|
*attributes = READ_ONLY;
|
|
|
|
*binding_flags = (init_flag == kNeedsInitialization)
|
|
|
|
? IMMUTABLE_CHECK_INITIALIZED_HARMONY
|
|
|
|
: IMMUTABLE_IS_INITIALIZED_HARMONY;
|
|
|
|
break;
|
2015-02-26 18:40:50 +00:00
|
|
|
case IMPORT:
|
|
|
|
// TODO(ES6)
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
2014-11-07 16:29:13 +00:00
|
|
|
case DYNAMIC:
|
|
|
|
case DYNAMIC_GLOBAL:
|
|
|
|
case DYNAMIC_LOCAL:
|
|
|
|
case TEMPORARY:
|
|
|
|
// Note: Fixed context slots are statically allocated by the compiler.
|
|
|
|
// Statically allocated variables always have a statically known mode,
|
|
|
|
// which is the mode with which they were declared when added to the
|
|
|
|
// scope. Thus, the DYNAMIC mode (which corresponds to dynamically
|
|
|
|
// declared variables that were introduced through declaration nodes)
|
|
|
|
// must not appear here.
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-06 15:50:40 +00:00
|
|
|
|
2011-06-16 14:12:58 +00:00
|
|
|
Handle<Object> Context::Lookup(Handle<String> name,
|
|
|
|
ContextLookupFlags flags,
|
2011-09-21 08:51:44 +00:00
|
|
|
int* index,
|
2011-08-30 11:23:57 +00:00
|
|
|
PropertyAttributes* attributes,
|
|
|
|
BindingFlags* binding_flags) {
|
2011-03-18 20:35:07 +00:00
|
|
|
Isolate* isolate = GetIsolate();
|
|
|
|
Handle<Context> context(this, isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
|
2015-08-26 11:16:38 +00:00
|
|
|
*index = kNotFound;
|
2008-07-03 15:10:15 +00:00
|
|
|
*attributes = ABSENT;
|
2011-08-30 11:23:57 +00:00
|
|
|
*binding_flags = MISSING_BINDING;
|
2008-07-03 15:10:15 +00:00
|
|
|
|
|
|
|
if (FLAG_trace_contexts) {
|
|
|
|
PrintF("Context::Lookup(");
|
|
|
|
name->ShortPrint();
|
|
|
|
PrintF(")\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (FLAG_trace_contexts) {
|
2010-09-30 07:22:53 +00:00
|
|
|
PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
|
2014-11-12 11:34:09 +00:00
|
|
|
if (context->IsScriptContext()) PrintF(" (script context)");
|
2012-08-17 09:03:08 +00:00
|
|
|
if (context->IsNativeContext()) PrintF(" (native context)");
|
2008-07-03 15:10:15 +00:00
|
|
|
PrintF("\n");
|
|
|
|
}
|
|
|
|
|
2011-09-21 08:51:44 +00:00
|
|
|
// 1. Check global objects, subjects of with, and extension objects.
|
2015-10-12 14:30:46 +00:00
|
|
|
if ((context->IsNativeContext() ||
|
|
|
|
(context->IsWithContext() && ((flags & SKIP_WITH_CONTEXT) == 0)) ||
|
[es6] Parameter scopes for sloppy eval
This CL is a nightmare! For the utterly irrelevant edge case of a sloppy function with non-simple parameters and a call to direct eval, like here,
let x = 1;
function f(g = () => x) {
var y
eval("var x = 2")
return g() + x // f() = 3
}
we have to do all of the following, on top of the declaration block ("varblock") contexts we already introduce around the body:
- Introduce the ability for varblock contexts to have both a ScopeInfo and an extension object (e.g., the body varblock in the example will contain both a static var y and a dynamic var x). No other scope needs that. Since there are no context slots left, a special new struct is introduced that pairs up scope info and extension object.
- When declaring lookup slots in the runtime, this new struct is allocated in the case where an extension object has to be added to a block scope (at which point the block's extension slot still contains a plain ScopeInfo).
- While at it, introduce some abstraction to access context extension slots in a more controlled manner, in order to keep special-casing to a minimum.
- Make sure that even empty varblock contexts do not get optimised away when they contain a sloppy eval, so that they can host the potential extension object.
- Extend dynamic search for declaration contexts (used by sloppy direct eval) to recognize varblock contexts.
- In the parser, if a function has a sloppy direct eval, introduce an additional varblock scope around each non-simple (desugared) parameter, as required by the spec to contain possible dynamic var bindings.
- In the pattern rewriter, add the ability to hoist the named variables the pattern declares to an outer scope. That is required because the actual destructuring has to be evaluated inside the protecting varblock scope, but the bindings that the desugaring introduces are in the outer scope.
- ScopeInfos need to save the information whether a block is a varblock, to make sloppy eval calls work correctly that deserialise them as part of the scope chain.
- Add the ability to materialize block scopes with extension objects in the debugger. Likewise, enable setting extension variables in block scopes via the debugger interface.
- While at it, refactor and unify some respective code in the debugger.
Sorry, this CL is large. I could try to split it up, but everything is rather entangled.
@mstarzinger: Please review the changes to contexts.
@yangguo: Please have a look at the debugger stuff.
R=littledan@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:811,v8:2160
LOG=N
Review URL: https://codereview.chromium.org/1292753007
Cr-Commit-Position: refs/heads/master@{#30295}
2015-08-21 10:58:35 +00:00
|
|
|
context->IsFunctionContext() || context->IsBlockContext()) &&
|
|
|
|
context->extension_receiver() != nullptr) {
|
|
|
|
Handle<JSReceiver> object(context->extension_receiver());
|
2014-11-07 16:29:13 +00:00
|
|
|
|
|
|
|
if (context->IsNativeContext()) {
|
|
|
|
if (FLAG_trace_contexts) {
|
2014-11-12 11:34:09 +00:00
|
|
|
PrintF(" - trying other script contexts\n");
|
2014-11-07 16:29:13 +00:00
|
|
|
}
|
2014-11-12 11:34:09 +00:00
|
|
|
// Try other script contexts.
|
|
|
|
Handle<ScriptContextTable> script_contexts(
|
|
|
|
context->global_object()->native_context()->script_context_table());
|
|
|
|
ScriptContextTable::LookupResult r;
|
|
|
|
if (ScriptContextTable::Lookup(script_contexts, name, &r)) {
|
2014-11-07 16:29:13 +00:00
|
|
|
if (FLAG_trace_contexts) {
|
2014-11-12 11:34:09 +00:00
|
|
|
Handle<Context> c = ScriptContextTable::GetContext(script_contexts,
|
2014-11-07 16:29:13 +00:00
|
|
|
r.context_index);
|
2014-11-12 11:34:09 +00:00
|
|
|
PrintF("=> found property in script context %d: %p\n",
|
2014-11-07 16:29:13 +00:00
|
|
|
r.context_index, reinterpret_cast<void*>(*c));
|
|
|
|
}
|
|
|
|
*index = r.slot_index;
|
|
|
|
GetAttributesAndBindingFlags(r.mode, r.init_flag, attributes,
|
|
|
|
binding_flags);
|
2014-11-12 11:34:09 +00:00
|
|
|
return ScriptContextTable::GetContext(script_contexts,
|
2014-11-07 16:29:13 +00:00
|
|
|
r.context_index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-21 08:51:44 +00:00
|
|
|
// Context extension objects needs to behave as if they have no
|
|
|
|
// prototype. So even if we want to follow prototype chains, we need
|
|
|
|
// to only do a local lookup for context extension objects.
|
2015-03-02 11:26:55 +00:00
|
|
|
Maybe<PropertyAttributes> maybe = Nothing<PropertyAttributes>();
|
2011-09-21 08:51:44 +00:00
|
|
|
if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
|
|
|
|
object->IsJSContextExtensionObject()) {
|
2014-07-25 18:32:11 +00:00
|
|
|
maybe = JSReceiver::GetOwnPropertyAttributes(object, name);
|
2014-08-08 11:42:59 +00:00
|
|
|
} else if (context->IsWithContext()) {
|
2015-05-19 14:51:10 +00:00
|
|
|
// A with context will never bind "this".
|
|
|
|
if (name->Equals(*isolate->factory()->this_string())) {
|
|
|
|
maybe = Just(ABSENT);
|
|
|
|
} else {
|
|
|
|
LookupIterator it(object, name);
|
|
|
|
maybe = UnscopableLookup(&it);
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
} else {
|
2014-07-25 18:32:11 +00:00
|
|
|
maybe = JSReceiver::GetPropertyAttributes(object, name);
|
2011-09-21 08:51:44 +00:00
|
|
|
}
|
2014-08-06 15:50:40 +00:00
|
|
|
|
2015-03-02 12:22:27 +00:00
|
|
|
if (!maybe.IsJust()) return Handle<Object>();
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(!isolate->has_pending_exception());
|
2015-03-02 12:22:27 +00:00
|
|
|
*attributes = maybe.FromJust();
|
2013-07-19 14:07:23 +00:00
|
|
|
|
2015-03-02 12:22:27 +00:00
|
|
|
if (maybe.FromJust() != ABSENT) {
|
2011-09-21 08:51:44 +00:00
|
|
|
if (FLAG_trace_contexts) {
|
|
|
|
PrintF("=> found property in context object %p\n",
|
|
|
|
reinterpret_cast<void*>(*object));
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2011-09-21 08:51:44 +00:00
|
|
|
return object;
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-21 08:51:44 +00:00
|
|
|
// 2. Check the context proper if it has slots.
|
2014-10-29 10:59:41 +00:00
|
|
|
if (context->IsFunctionContext() || context->IsBlockContext() ||
|
2015-03-13 15:15:42 +00:00
|
|
|
context->IsScriptContext()) {
|
2011-09-21 08:51:44 +00:00
|
|
|
// Use serialized scope information of functions and blocks to search
|
|
|
|
// for the context index.
|
[es6] Parameter scopes for sloppy eval
This CL is a nightmare! For the utterly irrelevant edge case of a sloppy function with non-simple parameters and a call to direct eval, like here,
let x = 1;
function f(g = () => x) {
var y
eval("var x = 2")
return g() + x // f() = 3
}
we have to do all of the following, on top of the declaration block ("varblock") contexts we already introduce around the body:
- Introduce the ability for varblock contexts to have both a ScopeInfo and an extension object (e.g., the body varblock in the example will contain both a static var y and a dynamic var x). No other scope needs that. Since there are no context slots left, a special new struct is introduced that pairs up scope info and extension object.
- When declaring lookup slots in the runtime, this new struct is allocated in the case where an extension object has to be added to a block scope (at which point the block's extension slot still contains a plain ScopeInfo).
- While at it, introduce some abstraction to access context extension slots in a more controlled manner, in order to keep special-casing to a minimum.
- Make sure that even empty varblock contexts do not get optimised away when they contain a sloppy eval, so that they can host the potential extension object.
- Extend dynamic search for declaration contexts (used by sloppy direct eval) to recognize varblock contexts.
- In the parser, if a function has a sloppy direct eval, introduce an additional varblock scope around each non-simple (desugared) parameter, as required by the spec to contain possible dynamic var bindings.
- In the pattern rewriter, add the ability to hoist the named variables the pattern declares to an outer scope. That is required because the actual destructuring has to be evaluated inside the protecting varblock scope, but the bindings that the desugaring introduces are in the outer scope.
- ScopeInfos need to save the information whether a block is a varblock, to make sloppy eval calls work correctly that deserialise them as part of the scope chain.
- Add the ability to materialize block scopes with extension objects in the debugger. Likewise, enable setting extension variables in block scopes via the debugger interface.
- While at it, refactor and unify some respective code in the debugger.
Sorry, this CL is large. I could try to split it up, but everything is rather entangled.
@mstarzinger: Please review the changes to contexts.
@yangguo: Please have a look at the debugger stuff.
R=littledan@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:811,v8:2160
LOG=N
Review URL: https://codereview.chromium.org/1292753007
Cr-Commit-Position: refs/heads/master@{#30295}
2015-08-21 10:58:35 +00:00
|
|
|
Handle<ScopeInfo> scope_info(context->IsFunctionContext()
|
|
|
|
? context->closure()->shared()->scope_info()
|
|
|
|
: context->scope_info());
|
2011-10-11 08:41:19 +00:00
|
|
|
VariableMode mode;
|
2011-11-03 11:59:51 +00:00
|
|
|
InitializationFlag init_flag;
|
2014-07-30 13:54:45 +00:00
|
|
|
// TODO(sigurds) Figure out whether maybe_assigned_flag should
|
|
|
|
// be used to compute binding_flags.
|
|
|
|
MaybeAssignedFlag maybe_assigned_flag;
|
|
|
|
int slot_index = ScopeInfo::ContextSlotIndex(
|
2015-09-10 12:54:53 +00:00
|
|
|
scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
|
2015-09-10 12:54:53 +00:00
|
|
|
if (slot_index >= 0) {
|
2008-07-03 15:10:15 +00:00
|
|
|
if (FLAG_trace_contexts) {
|
|
|
|
PrintF("=> found local in context slot %d (mode = %d)\n",
|
2011-09-21 08:51:44 +00:00
|
|
|
slot_index, mode);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2011-09-21 08:51:44 +00:00
|
|
|
*index = slot_index;
|
2014-11-07 16:29:13 +00:00
|
|
|
GetAttributesAndBindingFlags(mode, init_flag, attributes,
|
|
|
|
binding_flags);
|
2008-07-03 15:10:15 +00:00
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
2011-06-16 14:12:58 +00:00
|
|
|
// Check the slot corresponding to the intermediate context holding
|
|
|
|
// only the function name variable.
|
2011-09-21 08:51:44 +00:00
|
|
|
if (follow_context_chain && context->IsFunctionContext()) {
|
2011-10-25 08:33:08 +00:00
|
|
|
VariableMode mode;
|
|
|
|
int function_index = scope_info->FunctionContextSlotIndex(*name, &mode);
|
2011-09-21 08:51:44 +00:00
|
|
|
if (function_index >= 0) {
|
2008-07-03 15:10:15 +00:00
|
|
|
if (FLAG_trace_contexts) {
|
|
|
|
PrintF("=> found intermediate function in context slot %d\n",
|
2011-09-21 08:51:44 +00:00
|
|
|
function_index);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
2011-09-21 08:51:44 +00:00
|
|
|
*index = function_index;
|
2008-07-03 15:10:15 +00:00
|
|
|
*attributes = READ_ONLY;
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(mode == CONST_LEGACY || mode == CONST);
|
2014-03-11 14:41:22 +00:00
|
|
|
*binding_flags = (mode == CONST_LEGACY)
|
2011-10-25 08:33:08 +00:00
|
|
|
? IMMUTABLE_IS_INITIALIZED : IMMUTABLE_IS_INITIALIZED_HARMONY;
|
2008-07-03 15:10:15 +00:00
|
|
|
return context;
|
|
|
|
}
|
|
|
|
}
|
2011-09-21 08:51:44 +00:00
|
|
|
|
|
|
|
} else if (context->IsCatchContext()) {
|
|
|
|
// Catch contexts have the variable name in the extension slot.
|
[es6] Parameter scopes for sloppy eval
This CL is a nightmare! For the utterly irrelevant edge case of a sloppy function with non-simple parameters and a call to direct eval, like here,
let x = 1;
function f(g = () => x) {
var y
eval("var x = 2")
return g() + x // f() = 3
}
we have to do all of the following, on top of the declaration block ("varblock") contexts we already introduce around the body:
- Introduce the ability for varblock contexts to have both a ScopeInfo and an extension object (e.g., the body varblock in the example will contain both a static var y and a dynamic var x). No other scope needs that. Since there are no context slots left, a special new struct is introduced that pairs up scope info and extension object.
- When declaring lookup slots in the runtime, this new struct is allocated in the case where an extension object has to be added to a block scope (at which point the block's extension slot still contains a plain ScopeInfo).
- While at it, introduce some abstraction to access context extension slots in a more controlled manner, in order to keep special-casing to a minimum.
- Make sure that even empty varblock contexts do not get optimised away when they contain a sloppy eval, so that they can host the potential extension object.
- Extend dynamic search for declaration contexts (used by sloppy direct eval) to recognize varblock contexts.
- In the parser, if a function has a sloppy direct eval, introduce an additional varblock scope around each non-simple (desugared) parameter, as required by the spec to contain possible dynamic var bindings.
- In the pattern rewriter, add the ability to hoist the named variables the pattern declares to an outer scope. That is required because the actual destructuring has to be evaluated inside the protecting varblock scope, but the bindings that the desugaring introduces are in the outer scope.
- ScopeInfos need to save the information whether a block is a varblock, to make sloppy eval calls work correctly that deserialise them as part of the scope chain.
- Add the ability to materialize block scopes with extension objects in the debugger. Likewise, enable setting extension variables in block scopes via the debugger interface.
- While at it, refactor and unify some respective code in the debugger.
Sorry, this CL is large. I could try to split it up, but everything is rather entangled.
@mstarzinger: Please review the changes to contexts.
@yangguo: Please have a look at the debugger stuff.
R=littledan@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:811,v8:2160
LOG=N
Review URL: https://codereview.chromium.org/1292753007
Cr-Commit-Position: refs/heads/master@{#30295}
2015-08-21 10:58:35 +00:00
|
|
|
if (String::Equals(name, handle(context->catch_name()))) {
|
2011-09-21 08:51:44 +00:00
|
|
|
if (FLAG_trace_contexts) {
|
|
|
|
PrintF("=> found in catch context\n");
|
|
|
|
}
|
|
|
|
*index = Context::THROWN_OBJECT_INDEX;
|
|
|
|
*attributes = NONE;
|
|
|
|
*binding_flags = MUTABLE_IS_INITIALIZED;
|
|
|
|
return context;
|
|
|
|
}
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
2011-09-21 08:51:44 +00:00
|
|
|
// 3. Prepare to continue with the previous (next outermost) context.
|
2015-10-12 14:30:46 +00:00
|
|
|
if (context->IsNativeContext() ||
|
|
|
|
((flags & STOP_AT_DECLARATION_SCOPE) != 0 &&
|
|
|
|
context->is_declaration_context())) {
|
2008-07-03 15:10:15 +00:00
|
|
|
follow_context_chain = false;
|
2008-10-24 10:59:40 +00:00
|
|
|
} else {
|
2011-03-18 20:35:07 +00:00
|
|
|
context = Handle<Context>(context->previous(), isolate);
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
} while (follow_context_chain);
|
|
|
|
|
|
|
|
if (FLAG_trace_contexts) {
|
|
|
|
PrintF("=> no property/slot found\n");
|
|
|
|
}
|
2008-10-24 10:59:40 +00:00
|
|
|
return Handle<Object>::null();
|
2008-07-03 15:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-06 16:36:28 +00:00
|
|
|
void Context::InitializeGlobalSlots() {
|
|
|
|
DCHECK(IsScriptContext());
|
|
|
|
DisallowHeapAllocation no_gc;
|
|
|
|
|
[es6] Parameter scopes for sloppy eval
This CL is a nightmare! For the utterly irrelevant edge case of a sloppy function with non-simple parameters and a call to direct eval, like here,
let x = 1;
function f(g = () => x) {
var y
eval("var x = 2")
return g() + x // f() = 3
}
we have to do all of the following, on top of the declaration block ("varblock") contexts we already introduce around the body:
- Introduce the ability for varblock contexts to have both a ScopeInfo and an extension object (e.g., the body varblock in the example will contain both a static var y and a dynamic var x). No other scope needs that. Since there are no context slots left, a special new struct is introduced that pairs up scope info and extension object.
- When declaring lookup slots in the runtime, this new struct is allocated in the case where an extension object has to be added to a block scope (at which point the block's extension slot still contains a plain ScopeInfo).
- While at it, introduce some abstraction to access context extension slots in a more controlled manner, in order to keep special-casing to a minimum.
- Make sure that even empty varblock contexts do not get optimised away when they contain a sloppy eval, so that they can host the potential extension object.
- Extend dynamic search for declaration contexts (used by sloppy direct eval) to recognize varblock contexts.
- In the parser, if a function has a sloppy direct eval, introduce an additional varblock scope around each non-simple (desugared) parameter, as required by the spec to contain possible dynamic var bindings.
- In the pattern rewriter, add the ability to hoist the named variables the pattern declares to an outer scope. That is required because the actual destructuring has to be evaluated inside the protecting varblock scope, but the bindings that the desugaring introduces are in the outer scope.
- ScopeInfos need to save the information whether a block is a varblock, to make sloppy eval calls work correctly that deserialise them as part of the scope chain.
- Add the ability to materialize block scopes with extension objects in the debugger. Likewise, enable setting extension variables in block scopes via the debugger interface.
- While at it, refactor and unify some respective code in the debugger.
Sorry, this CL is large. I could try to split it up, but everything is rather entangled.
@mstarzinger: Please review the changes to contexts.
@yangguo: Please have a look at the debugger stuff.
R=littledan@chromium.org, mstarzinger@chromium.org, yangguo@chromium.org
BUG=v8:811,v8:2160
LOG=N
Review URL: https://codereview.chromium.org/1292753007
Cr-Commit-Position: refs/heads/master@{#30295}
2015-08-21 10:58:35 +00:00
|
|
|
ScopeInfo* scope_info = this->scope_info();
|
2015-07-06 16:36:28 +00:00
|
|
|
|
|
|
|
int context_globals = scope_info->ContextGlobalCount();
|
|
|
|
if (context_globals > 0) {
|
|
|
|
PropertyCell* empty_cell = GetHeap()->empty_property_cell();
|
|
|
|
|
|
|
|
int context_locals = scope_info->ContextLocalCount();
|
|
|
|
int index = Context::MIN_CONTEXT_SLOTS + context_locals;
|
|
|
|
for (int i = 0; i < context_globals; i++) {
|
|
|
|
set(index++, empty_cell);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
void Context::AddOptimizedFunction(JSFunction* function) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(IsNativeContext());
|
|
|
|
#ifdef ENABLE_SLOW_DCHECKS
|
2012-07-03 13:01:31 +00:00
|
|
|
if (FLAG_enable_slow_asserts) {
|
|
|
|
Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
|
|
|
|
while (!element->IsUndefined()) {
|
|
|
|
CHECK(element != function);
|
|
|
|
element = JSFunction::cast(element)->next_function_link();
|
|
|
|
}
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
|
2012-08-17 09:03:08 +00:00
|
|
|
// Check that the context belongs to the weak native contexts list.
|
2010-12-07 11:31:57 +00:00
|
|
|
bool found = false;
|
2012-08-17 09:03:08 +00:00
|
|
|
Object* context = GetHeap()->native_contexts_list();
|
2010-12-07 11:31:57 +00:00
|
|
|
while (!context->IsUndefined()) {
|
|
|
|
if (context == this) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
|
|
|
|
}
|
|
|
|
CHECK(found);
|
|
|
|
#endif
|
2012-10-23 08:25:04 +00:00
|
|
|
|
|
|
|
// If the function link field is already used then the function was
|
|
|
|
// enqueued as a code flushing candidate and we remove it now.
|
|
|
|
if (!function->next_function_link()->IsUndefined()) {
|
|
|
|
CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
|
|
|
|
flusher->EvictCandidate(function);
|
|
|
|
}
|
|
|
|
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(function->next_function_link()->IsUndefined());
|
2012-10-23 08:25:04 +00:00
|
|
|
|
2015-05-29 08:06:19 +00:00
|
|
|
function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST),
|
|
|
|
UPDATE_WEAK_WRITE_BARRIER);
|
2015-05-27 14:13:04 +00:00
|
|
|
set(OPTIMIZED_FUNCTIONS_LIST, function, UPDATE_WEAK_WRITE_BARRIER);
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Context::RemoveOptimizedFunction(JSFunction* function) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(IsNativeContext());
|
2010-12-07 11:31:57 +00:00
|
|
|
Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
|
|
|
|
JSFunction* prev = NULL;
|
|
|
|
while (!element->IsUndefined()) {
|
|
|
|
JSFunction* element_function = JSFunction::cast(element);
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(element_function->next_function_link()->IsUndefined() ||
|
2010-12-07 11:31:57 +00:00
|
|
|
element_function->next_function_link()->IsJSFunction());
|
|
|
|
if (element_function == function) {
|
|
|
|
if (prev == NULL) {
|
2015-05-27 14:13:04 +00:00
|
|
|
set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link(),
|
|
|
|
UPDATE_WEAK_WRITE_BARRIER);
|
2010-12-07 11:31:57 +00:00
|
|
|
} else {
|
2015-05-29 08:06:19 +00:00
|
|
|
prev->set_next_function_link(element_function->next_function_link(),
|
|
|
|
UPDATE_WEAK_WRITE_BARRIER);
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
2015-05-29 08:06:19 +00:00
|
|
|
element_function->set_next_function_link(GetHeap()->undefined_value(),
|
|
|
|
UPDATE_WEAK_WRITE_BARRIER);
|
2010-12-07 11:31:57 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
prev = element_function;
|
|
|
|
element = element_function->next_function_link();
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-04 13:53:24 +00:00
|
|
|
void Context::SetOptimizedFunctionsListHead(Object* head) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(IsNativeContext());
|
2015-05-27 14:13:04 +00:00
|
|
|
set(OPTIMIZED_FUNCTIONS_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
|
2013-09-04 13:53:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-07 11:31:57 +00:00
|
|
|
Object* Context::OptimizedFunctionsListHead() {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(IsNativeContext());
|
2010-12-07 11:31:57 +00:00
|
|
|
return get(OPTIMIZED_FUNCTIONS_LIST);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-04 13:53:24 +00:00
|
|
|
void Context::AddOptimizedCode(Code* code) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(IsNativeContext());
|
|
|
|
DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
|
|
|
|
DCHECK(code->next_code_link()->IsUndefined());
|
2013-09-04 13:53:24 +00:00
|
|
|
code->set_next_code_link(get(OPTIMIZED_CODE_LIST));
|
2015-05-27 14:13:04 +00:00
|
|
|
set(OPTIMIZED_CODE_LIST, code, UPDATE_WEAK_WRITE_BARRIER);
|
2013-09-04 13:53:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Context::SetOptimizedCodeListHead(Object* head) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(IsNativeContext());
|
2015-05-27 14:13:04 +00:00
|
|
|
set(OPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
|
2013-09-04 13:53:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Object* Context::OptimizedCodeListHead() {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(IsNativeContext());
|
2013-09-04 13:53:24 +00:00
|
|
|
return get(OPTIMIZED_CODE_LIST);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Context::SetDeoptimizedCodeListHead(Object* head) {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(IsNativeContext());
|
2015-05-27 14:13:04 +00:00
|
|
|
set(DEOPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
|
2013-09-04 13:53:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Object* Context::DeoptimizedCodeListHead() {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK(IsNativeContext());
|
2013-09-04 13:53:24 +00:00
|
|
|
return get(DEOPTIMIZED_CODE_LIST);
|
2010-12-07 11:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-17 09:58:22 +00:00
|
|
|
Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() {
|
2014-04-17 13:27:02 +00:00
|
|
|
Isolate* isolate = GetIsolate();
|
|
|
|
Handle<Object> result(error_message_for_code_gen_from_strings(), isolate);
|
2013-02-25 14:46:09 +00:00
|
|
|
if (!result->IsUndefined()) return result;
|
2014-09-10 12:38:12 +00:00
|
|
|
return isolate->factory()->NewStringFromStaticChars(
|
2014-04-17 13:27:02 +00:00
|
|
|
"Code generation from strings disallowed for this context");
|
2012-09-17 09:58:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-26 11:16:38 +00:00
|
|
|
#define COMPARE_NAME(index, type, name) \
|
|
|
|
if (string->IsOneByteEqualTo(STATIC_CHAR_VECTOR(#name))) return index;
|
|
|
|
|
|
|
|
int Context::ImportedFieldIndexForName(Handle<String> string) {
|
|
|
|
NATIVE_CONTEXT_IMPORTED_FIELDS(COMPARE_NAME)
|
|
|
|
return kNotFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Context::IntrinsicIndexForName(Handle<String> string) {
|
|
|
|
NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
|
|
|
|
return kNotFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef COMPARE_NAME
|
|
|
|
|
|
|
|
|
2015-08-27 10:18:21 +00:00
|
|
|
bool Context::IsJSBuiltin(Handle<Context> native_context,
|
|
|
|
Handle<JSFunction> function) {
|
|
|
|
#define COMPARE_FUNCTION(index, type, name) \
|
|
|
|
if (*function == native_context->get(index)) return true;
|
|
|
|
NATIVE_CONTEXT_JS_BUILTINS(COMPARE_FUNCTION);
|
|
|
|
#undef COMPARE_FUNCTION
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-24 10:59:40 +00:00
|
|
|
#ifdef DEBUG
|
2012-07-09 08:59:03 +00:00
|
|
|
bool Context::IsBootstrappingOrValidParentContext(
|
|
|
|
Object* object, Context* child) {
|
2008-10-24 10:59:40 +00:00
|
|
|
// During bootstrapping we allow all objects to pass as
|
|
|
|
// contexts. This is necessary to fix circular dependencies.
|
2013-02-25 14:46:09 +00:00
|
|
|
if (child->GetIsolate()->bootstrapper()->IsActive()) return true;
|
2012-07-09 08:59:03 +00:00
|
|
|
if (!object->IsContext()) return false;
|
|
|
|
Context* context = Context::cast(object);
|
2014-11-12 11:34:09 +00:00
|
|
|
return context->IsNativeContext() || context->IsScriptContext() ||
|
2012-08-27 09:40:26 +00:00
|
|
|
context->IsModuleContext() || !child->IsModuleContext();
|
2008-10-24 10:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-03 06:57:16 +00:00
|
|
|
bool Context::IsBootstrappingOrGlobalObject(Isolate* isolate, Object* object) {
|
2008-10-24 10:59:40 +00:00
|
|
|
// During bootstrapping we allow all objects to pass as global
|
|
|
|
// objects. This is necessary to fix circular dependencies.
|
2011-03-18 20:35:07 +00:00
|
|
|
return isolate->heap()->gc_state() != Heap::NOT_IN_GC ||
|
2015-11-02 14:57:59 +00:00
|
|
|
isolate->bootstrapper()->IsActive() || object->IsJSGlobalObject();
|
2008-10-24 10:59:40 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-11-06 08:07:52 +00:00
|
|
|
|
|
|
|
void Context::IncrementErrorsThrown() {
|
|
|
|
DCHECK(IsNativeContext());
|
|
|
|
|
|
|
|
int previous_value = errors_thrown()->value();
|
|
|
|
set_errors_thrown(Smi::FromInt(previous_value + 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Context::GetErrorsThrown() { return errors_thrown()->value(); }
|
|
|
|
|
2015-06-01 22:46:54 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|