name_obj,
line_offset,
column_offset,
- isolate->native_context(),
+ isolate->global_context(),
NULL,
pre_data_impl,
Utils::OpenHandle(*script_data),
i::Handle<i::JSFunction> result =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
function,
- isolate->native_context());
+ isolate->global_context());
return Local<Script>(ToApi<Script>(result));
}
i::Handle<i::SharedFunctionInfo>
function_info(i::SharedFunctionInfo::cast(*obj), isolate);
fun = isolate->factory()->NewFunctionFromSharedFunctionInfo(
- function_info, isolate->native_context());
+ function_info, isolate->global_context());
} else {
fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate);
}
i::Object** ctx = reinterpret_cast<i::Object**>(this);
i::Handle<i::Context> context =
i::Handle<i::Context>::cast(i::Handle<i::Object>(ctx));
- isolate->bootstrapper()->ReattachGlobal(
- context,
- Utils::OpenHandle(*global_object));
+ i::Handle<i::JSGlobalProxy> global_proxy =
+ i::Handle<i::JSGlobalProxy>::cast(Utils::OpenHandle(*global_object));
+ isolate->bootstrapper()->ReattachGlobal(context, global_proxy);
}
void Bootstrapper::DetachGlobal(Handle<Context> env) {
Factory* factory = env->GetIsolate()->factory();
- JSGlobalProxy::cast(env->global_proxy())->
- set_native_context(*factory->null_value());
- SetObjectPrototype(Handle<JSObject>(env->global_proxy()),
- factory->null_value());
+ Handle<JSGlobalProxy> global_proxy(JSGlobalProxy::cast(env->global_proxy()));
+ global_proxy->set_native_context(*factory->null_value());
+ SetObjectPrototype(global_proxy, factory->null_value());
env->set_global_proxy(env->global_object());
env->global_object()->set_global_receiver(env->global_object());
}
void Bootstrapper::ReattachGlobal(Handle<Context> env,
- Handle<Object> global_object) {
- ASSERT(global_object->IsJSGlobalProxy());
- Handle<JSGlobalProxy> global = Handle<JSGlobalProxy>::cast(global_object);
- env->global_object()->set_global_receiver(*global);
- env->set_global_proxy(*global);
- SetObjectPrototype(global, Handle<JSObject>(env->global_object()));
- global->set_native_context(*env);
+ Handle<JSGlobalProxy> global_proxy) {
+ env->global_object()->set_global_receiver(*global_proxy);
+ env->set_global_proxy(*global_proxy);
+ SetObjectPrototype(global_proxy, Handle<JSObject>(env->global_object()));
+ global_proxy->set_native_context(*env);
}
Handle<JSGlobalProxy> global_proxy) {
// Set the native context for the global object.
inner_global->set_native_context(*native_context());
+ inner_global->set_global_context(*native_context());
inner_global->set_global_receiver(*global_proxy);
global_proxy->set_native_context(*native_context());
native_context()->set_global_proxy(*global_proxy);
Handle<JSBuiltinsObject>::cast(factory()->NewGlobalObject(builtins_fun));
builtins->set_builtins(*builtins);
builtins->set_native_context(*native_context());
+ builtins->set_global_context(*native_context());
builtins->set_global_receiver(*builtins);
// Set up the 'global' properties of the builtins object. The
void DetachGlobal(Handle<Context> env);
// Reattach an outer global object to an environment.
- void ReattachGlobal(Handle<Context> env, Handle<Object> global_object);
+ void ReattachGlobal(Handle<Context> env, Handle<JSGlobalProxy> global_proxy);
// Traverses the pointers for memory management.
void Iterate(ObjectVisitor* v);
script_(Handle<Script>(Script::cast(shared_info_->script()))),
extension_(NULL),
pre_parse_data_(NULL),
+ context_(closure->context()),
osr_ast_id_(BailoutId::None()),
zone_(zone),
deferred_handles_(NULL) {
// optimized code.
unoptimized.SetFunction(info()->function());
unoptimized.SetScope(info()->scope());
+ unoptimized.SetContext(info()->context());
if (should_recompile) unoptimized.EnableDeoptimizationSupport();
bool succeeded = FullCodeGenerator::MakeCode(&unoptimized);
if (should_recompile) {
info.MarkAsGlobal();
info.SetExtension(extension);
info.SetPreParseData(pre_data);
+ info.SetContext(context);
if (FLAG_use_strict) {
info.SetLanguageMode(FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE);
}
info.MarkAsEval();
if (is_global) info.MarkAsGlobal();
info.SetLanguageMode(language_mode);
- info.SetCallingContext(context);
+ info.SetContext(context);
result = MakeFunctionInfo(&info);
if (!result.is_null()) {
// Explicitly disable optimization for eval code. We're not yet prepared
Handle<Script> script() const { return script_; }
v8::Extension* extension() const { return extension_; }
ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; }
- Handle<Context> calling_context() const { return calling_context_; }
+ Handle<Context> context() const { return context_; }
BailoutId osr_ast_id() const { return osr_ast_id_; }
void MarkAsEval() {
ASSERT(!is_lazy());
pre_parse_data_ = pre_parse_data;
}
- void SetCallingContext(Handle<Context> context) {
- ASSERT(is_eval());
- calling_context_ = context;
+ void SetContext(Handle<Context> context) {
+ context_ = context;
}
void MarkCompilingForDebugging(Handle<Code> current_code) {
ASSERT(mode_ != OPTIMIZE);
void SaveHandles() {
SaveHandle(&closure_);
SaveHandle(&shared_info_);
- SaveHandle(&calling_context_);
+ SaveHandle(&context_);
SaveHandle(&script_);
}
v8::Extension* extension_;
ScriptDataImpl* pre_parse_data_;
- // The context of the caller is needed for eval code, and will be a null
- // handle otherwise.
- Handle<Context> calling_context_;
+ // The context of the caller for eval code, and the global context for a
+ // global script. Will be a null handle otherwise.
+ Handle<Context> context_;
// Compilation mode flag and whether deoptimization is allowed.
Mode mode_;
Context* context = reinterpret_cast<Context*>(result);
context->set_map_no_write_barrier(global_context_map());
context->set_closure(function);
+ context->set_previous(function->context());
context->set_extension(scope_info);
+ context->set_global_object(function->context()->global_object());
ASSERT(context->IsGlobalContext());
ASSERT(result->IsContext());
return context;
}
+Handle<Context> Isolate::global_context() {
+ GlobalObject* global = thread_local_top()->context_->global_object();
+ return Handle<Context>(global->global_context());
+}
+
+
Handle<Context> Isolate::GetCallingNativeContext() {
JavaScriptFrameIterator it;
#ifdef ENABLE_DEBUGGER_SUPPORT
void IterateThread(ThreadVisitor* v, char* t);
- // Returns the current native context.
+ // Returns the current native and global context.
Handle<Context> native_context();
+ Handle<Context> global_context();
// Returns the native context of the calling JavaScript code. That
// is, the native context of the top-most JavaScript frame.
ACCESSORS(GlobalObject, builtins, JSBuiltinsObject, kBuiltinsOffset)
ACCESSORS(GlobalObject, native_context, Context, kNativeContextOffset)
+ACCESSORS(GlobalObject, global_context, Context, kGlobalContextOffset)
ACCESSORS(GlobalObject, global_receiver, JSObject, kGlobalReceiverOffset)
ACCESSORS(JSGlobalProxy, native_context, Object, kNativeContextOffset)
shared,
CurrentGlobalLanguageMode(),
RelocInfo::kNoPosition);
- Object* obj;
- { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
-
- CompilationCacheTable* cache =
- reinterpret_cast<CompilationCacheTable*>(obj);
- int entry = cache->FindInsertionEntry(key.Hash());
+ CompilationCacheTable* cache;
+ MaybeObject* maybe_cache = EnsureCapacity(1, &key);
+ if (!maybe_cache->To(&cache)) return maybe_cache;
Object* k;
- { MaybeObject* maybe_k = key.AsObject();
- if (!maybe_k->ToObject(&k)) return maybe_k;
- }
+ MaybeObject* maybe_k = key.AsObject();
+ if (!maybe_k->To(&k)) return maybe_k;
+ int entry = cache->FindInsertionEntry(key.Hash());
cache->set(EntryToIndex(entry), k);
cache->set(EntryToIndex(entry) + 1, value);
cache->ElementAdded();
// [native context]: the natives corresponding to this global object.
DECL_ACCESSORS(native_context, Context)
+ // [global context]: the most recent (i.e. innermost) global context.
+ DECL_ACCESSORS(global_context, Context)
+
// [global receiver]: the global receiver object of the context
DECL_ACCESSORS(global_receiver, JSObject)
// Layout description.
static const int kBuiltinsOffset = JSObject::kHeaderSize;
static const int kNativeContextOffset = kBuiltinsOffset + kPointerSize;
- static const int kGlobalReceiverOffset = kNativeContextOffset + kPointerSize;
+ static const int kGlobalContextOffset = kNativeContextOffset + kPointerSize;
+ static const int kGlobalReceiverOffset = kGlobalContextOffset + kPointerSize;
static const int kHeaderSize = kGlobalReceiverOffset + kPointerSize;
private:
FunctionLiteral* result = NULL;
{ Scope* scope = NewScope(top_scope_, GLOBAL_SCOPE);
info->SetGlobalScope(scope);
+ if (!info->context().is_null()) {
+ scope = Scope::DeserializeScopeChain(*info->context(), scope, zone());
+ }
if (info->is_eval()) {
- Handle<SharedFunctionInfo> shared = info->shared_info();
- if (!info->is_global() && (shared.is_null() || shared->is_function())) {
- scope = Scope::DeserializeScopeChain(*info->calling_context(), scope,
- zone());
- }
if (!scope->is_global_scope() || info->language_mode() != CLASSIC_MODE) {
scope = NewScope(scope, EVAL_SCOPE);
}
+ } else if (info->is_global()) {
+ scope = NewScope(scope, GLOBAL_SCOPE);
}
scope->set_start_position(0);
scope->set_end_position(source->length());
- FunctionState function_state(this, scope, isolate());
+
+ FunctionState function_state(this, scope, isolate()); // Enters 'scope'.
top_scope_->SetLanguageMode(info->language_mode());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
bool ok = true;
declaration_scope->is_strict_or_extended_eval_scope() ||
declaration_scope->is_block_scope() ||
declaration_scope->is_module_scope() ||
- declaration->AsModuleDeclaration() != NULL) {
+ declaration_scope->is_global_scope()) {
// Declare the variable in the declaration scope.
- var = declaration_scope->LocalLookup(name);
+ // For the global scope, we have to check for collisions with earlier
+ // (i.e., enclosing) global scopes, to maintain the illusion of a single
+ // global scope.
+ var = declaration_scope->is_global_scope()
+ ? declaration_scope->Lookup(name)
+ : declaration_scope->LocalLookup(name);
if (var == NULL) {
// Declare the name.
var = declaration_scope->DeclareLocal(
name, mode, declaration->initialization(), proxy->interface());
- } else {
+ } else if ((mode != VAR || var->mode() != VAR) &&
+ (!declaration_scope->is_global_scope() ||
+ (mode != VAR && mode != CONST) ||
+ (var->mode() != VAR && var->mode() != CONST))) {
// The name was declared in this scope before; check for conflicting
// re-declarations. We have a conflict if either of the declarations is
- // not a var. There is similar code in runtime.cc in the Declare
+ // not a var (in the global scope, we also have to ignore legacy const for
+ // compatibility). There is similar code in runtime.cc in the Declare
// functions. The function CheckNonConflictingScope checks for conflicting
// var and let bindings from different scopes whereas this is a check for
// conflicting declarations within the same scope. This check also covers
+ // the special case
//
// function () { let x; { var x; } }
//
// because the var declaration is hoisted to the function scope where 'x'
// is already bound.
- if ((mode != VAR) || (var->mode() != VAR)) {
- // We only have vars, consts and lets in declarations.
- ASSERT(var->mode() == VAR ||
- var->mode() == CONST ||
- var->mode() == CONST_HARMONY ||
- var->mode() == LET);
- if (is_extended_mode()) {
- // In harmony mode we treat re-declarations as early errors. See
- // ES5 16 for a definition of early errors.
- SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
- const char* elms[2] = { "Variable", *c_string };
- Vector<const char*> args(elms, 2);
- ReportMessage("redeclaration", args);
- *ok = false;
- return;
- }
- const char* type = (var->mode() == VAR)
- ? "var" : var->is_const_mode() ? "const" : "let";
- Handle<String> type_string =
- isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
- Expression* expression =
- NewThrowTypeError(isolate()->factory()->redeclaration_symbol(),
- type_string, name);
- declaration_scope->SetIllegalRedeclaration(expression);
+ // We only have vars, consts and lets in declarations.
+ ASSERT(var->mode() == VAR ||
+ var->mode() == CONST ||
+ var->mode() == CONST_HARMONY ||
+ var->mode() == LET);
+ if (is_extended_mode()) {
+ // In harmony mode we treat re-declarations as early errors. See
+ // ES5 16 for a definition of early errors.
+ SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
+ const char* elms[2] = { "Variable", *c_string };
+ Vector<const char*> args(elms, 2);
+ ReportMessage("redeclaration", args);
+ *ok = false;
+ return;
}
+ const char* type =
+ (var->mode() == VAR) ? "var" : var->is_const_mode() ? "const" : "let";
+ Handle<String> type_string =
+ isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED);
+ Expression* expression =
+ NewThrowTypeError(isolate()->factory()->redeclaration_symbol(),
+ type_string, name);
+ declaration_scope->SetIllegalRedeclaration(expression);
}
}
// Runtime::DeclareContextSlot() calls.
declaration_scope->AddDeclaration(declaration);
- if ((mode == CONST || mode == CONST_HARMONY) &&
- declaration_scope->is_global_scope()) {
+ if (mode == CONST && declaration_scope->is_global_scope()) {
// For global const variables we bind the proxy to a variable.
ASSERT(resolve); // should be set by all callers
Variable::Kind kind = Variable::NORMAL;
FunctionLiteral::DECLARATION,
CHECK_OK);
// Even if we're not at the top-level of the global or a function
- // scope, we treat is as such and introduce the function with it's
+ // scope, we treat it as such and introduce the function with its
// initial value upon entering the corresponding scope.
- VariableMode mode = is_extended_mode() ? LET : VAR;
+ // In extended mode, a function behaves as a lexical binding, except in the
+ // global scope.
+ VariableMode mode =
+ is_extended_mode() && !top_scope_->is_global_scope() ? LET : VAR;
VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue());
Declaration* declaration =
factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_);
// declaration statement has been executed. This is important in
// browsers where the global object (window) has lots of
// properties defined in prototype objects.
- if (initialization_scope->is_global_scope()) {
+ if (initialization_scope->is_global_scope() &&
+ mode != LET && mode != CONST_HARMONY) {
// Compute the arguments for the runtime call.
ZoneList<Expression*>* arguments =
new(zone()) ZoneList<Expression*>(3, zone());
#undef DEF_VISIT
-// Assumes code has been parsed and scopes have been analyzed. Mutates the
-// AST, so the AST should not continue to be used in the case of failure.
+// Assumes code has been parsed. Mutates the AST, so the AST should not
+// continue to be used in the case of failure.
bool Rewriter::Rewrite(CompilationInfo* info) {
FunctionLiteral* function = info->function();
ASSERT(function != NULL);
isolate->heap()->AllocateGlobalContext(function, scope_info);
if (!maybe_result->To(&result)) return maybe_result;
+ ASSERT(function->context() == isolate->context());
+ ASSERT(function->context()->global_object() == result->global_object());
isolate->set_context(result);
+ result->global_object()->set_global_context(result);
return result; // non-failure
}
} else {
ASSERT(scope_info->Type() == EVAL_SCOPE);
info.MarkAsEval();
- info.SetCallingContext(Handle<Context>(function_->context()));
+ info.SetContext(Handle<Context>(function_->context()));
}
if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
scope = info.function()->scope();
already_resolved_(false),
zone_(zone) {
SetDefaults(type, outer_scope, Handle<ScopeInfo>::null());
- // At some point we might want to provide outer scopes to
- // eval scopes (by walking the stack and reading the scope info).
- // In that case, the ASSERT below needs to be adjusted.
- ASSERT_EQ(type == GLOBAL_SCOPE, outer_scope == NULL);
+ // The outermost scope must be a global scope.
+ ASSERT(type == GLOBAL_SCOPE || outer_scope != NULL);
ASSERT(!HasIllegalRedeclaration());
}
// gave up on it (e.g. by encountering a local with the same in the outer
// scope which was not promoted to a context, this can happen if we use
// debugger to evaluate arbitrary expressions at a break point).
- if (var->is_global()) {
+ if (var->IsGlobalObjectProperty()) {
var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
} else if (var->is_dynamic()) {
var = NonLocal(proxy->name(), DYNAMIC);
scope_contains_with_ ||
is_catch_scope() ||
is_block_scope() ||
- is_module_scope())) {
+ is_module_scope() ||
+ is_global_scope())) {
var->set_is_used(true);
}
// Global variables do not need to be allocated.
- return !var->is_global() && var->is_used();
+ return !var->IsGlobalObjectProperty() && var->is_used();
}
// catch-bound variables are always allocated in a context.
if (var->mode() == TEMPORARY) return false;
if (is_catch_scope() || is_block_scope() || is_module_scope()) return true;
+ if (is_global_scope() && (var->mode() == LET || var->mode() == CONST_HARMONY))
+ return true;
return var->has_forced_context_allocation() ||
scope_calls_eval_ ||
inner_scope_calls_eval_ ||
- scope_contains_with_ ||
- var->is_global();
+ scope_contains_with_;
}
}
-bool Variable::is_global() const {
+bool Variable::IsGlobalObjectProperty() const {
// Temporaries are never global, they must always be allocated in the
// activation frame.
- return mode_ != TEMPORARY && scope_ != NULL && scope_->is_global_scope();
+ return mode_ != TEMPORARY && mode_ != LET && mode_ != CONST_HARMONY
+ && scope_ != NULL && scope_->is_global_scope();
}
bool IsStackAllocated() const { return IsParameter() || IsStackLocal(); }
bool IsContextSlot() const { return location_ == CONTEXT; }
bool IsLookupSlot() const { return location_ == LOOKUP; }
+ bool IsGlobalObjectProperty() const;
bool is_dynamic() const {
return (mode_ == DYNAMIC ||
return initialization_flag_ == kNeedsInitialization;
}
- bool is_global() const;
bool is_this() const { return kind_ == THIS; }
bool is_arguments() const { return kind_ == ARGUMENTS; }
EXPECT_RESULT, Number::New(1));
}
+ { SimpleContext context;
+ context.Check("function x() { return 4 }; x()",
+ EXPECT_RESULT, Number::New(4));
+ context.Check("x()",
+ EXPECT_RESULT, Number::New(4));
+ context.Check("this.x()",
+ EXPECT_RESULT, Number::New(4));
+ }
+
{ SimpleContext context;
context.Check("let x = 2; x",
EXPECT_RESULT, Number::New(2));
context.Check("x",
EXPECT_RESULT, Number::New(2));
- context.Check("this.x",
- EXPECT_RESULT, Number::New(2));
+ // TODO(rossberg): The current ES6 draft spec does not reflect lexical
+ // bindings on the global object. However, this will probably change, in
+ // which case we reactivate the following test.
+ // context.Check("this.x",
+ // EXPECT_RESULT, Number::New(2));
}
{ SimpleContext context;
EXPECT_RESULT, Number::New(3));
context.Check("x",
EXPECT_RESULT, Number::New(3));
- context.Check("this.x",
- EXPECT_RESULT, Number::New(3));
- }
-
- { SimpleContext context;
- context.Check("function x() { return 4 }; x()",
- EXPECT_RESULT, Number::New(4));
- context.Check("x()",
- EXPECT_RESULT, Number::New(4));
- context.Check("this.x()",
- EXPECT_RESULT, Number::New(4));
+ // TODO(rossberg): The current ES6 draft spec does not reflect lexical
+ // bindings on the global object. However, this will probably change, in
+ // which case we reactivate the following test.
+ // context.Check("this.x",
+ // EXPECT_RESULT, Number::New(3));
}
// TODO(rossberg): All of the below should actually be errors in Harmony.
context.Check("let x = 1; x",
EXPECT_RESULT, Number::New(1));
context.Check("var x = 2; x",
- EXPECT_RESULT, Number::New(2));
+ EXPECT_ERROR);
}
{ SimpleContext context;
context.Check("let x = 1; x",
EXPECT_RESULT, Number::New(1));
context.Check("let x = 2; x",
- EXPECT_RESULT, Number::New(2));
+ EXPECT_ERROR);
}
{ SimpleContext context;
context.Check("let x = 1; x",
EXPECT_RESULT, Number::New(1));
context.Check("const x = 2; x",
- EXPECT_RESULT, Number::New(2));
+ EXPECT_ERROR);
}
{ SimpleContext context;
context.Check("let x = 1; x",
EXPECT_RESULT, Number::New(1));
context.Check("function x() { return 2 }; x()",
- EXPECT_RESULT, Number::New(2));
+ EXPECT_ERROR);
}
{ SimpleContext context;
context.Check("const x = 1; x",
EXPECT_RESULT, Number::New(1));
context.Check("var x = 2; x",
- EXPECT_EXCEPTION);
+ EXPECT_ERROR);
}
{ SimpleContext context;
context.Check("const x = 1; x",
EXPECT_RESULT, Number::New(1));
context.Check("let x = 2; x",
- EXPECT_EXCEPTION);
+ EXPECT_ERROR);
}
{ SimpleContext context;
context.Check("const x = 1; x",
EXPECT_RESULT, Number::New(1));
context.Check("const x = 2; x",
- EXPECT_RESULT, Number::New(1));
+ EXPECT_ERROR);
}
{ SimpleContext context;
context.Check("const x = 1; x",
EXPECT_RESULT, Number::New(1));
context.Check("function x() { return 2 }; x()",
- EXPECT_EXCEPTION);
+ EXPECT_ERROR);
}
}
function CheckException(e) {
var string = e.toString();
assertTrue(string.indexOf("has already been declared") >= 0 ||
- string.indexOf("redeclaration") >= 0); return 'Conflict';
+ string.indexOf("redeclaration") >= 0);
+ return 'Conflict';
}