VariableDeclaration* function = scope()->function();
DCHECK(function->proxy()->var()->mode() == CONST ||
function->proxy()->var()->mode() == CONST_LEGACY);
- DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ DCHECK(!function->proxy()->var()->IsUnallocatedOrGlobalSlot());
VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
Variable* variable = proxy->var();
bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
globals_->Add(variable->name(), zone());
globals_->Add(variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
zone());
break;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
}
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
EmitDebugCheckDeclarationContext(variable);
}
break;
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ VariableDeclaration");
__ mov(r2, Operand(variable->name()));
// Declaration nodes are always introduced in one of four modes.
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
globals_->Add(variable->name(), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
Comment cmnt(masm_, "[ FunctionDeclaration");
VisitForAccumulatorValue(declaration->fun());
__ str(result_register(), StackOperand(variable));
break;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ FunctionDeclaration");
EmitDebugCheckDeclarationContext(variable);
VisitForAccumulatorValue(declaration->fun());
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ FunctionDeclaration");
__ mov(r2, Operand(variable->name()));
__ mov(r1, Operand(Smi::FromInt(NONE)));
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
// TODO(rossberg)
break;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ ImportDeclaration");
EmitDebugCheckDeclarationContext(variable);
// TODO(rossberg)
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::LOOKUP:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::LOOKUP:
UNREACHABLE();
}
}
// Three cases: global variables, lookup variables, and all other types of
// variables.
switch (var->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
Comment cmnt(masm_, "[ Global variable");
__ ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
__ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::CONTEXT: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable");
if (var->binding_needs_init()) {
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ Lookup variable");
Label done, slow;
// Generate code for loading from variables potentially shadowed
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
// Global var, const, or let.
__ mov(StoreDescriptor::NameRegister(), Operand(var->name()));
__ ldr(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
// "delete this" is allowed.
bool is_this = var->HasThisName(isolate());
DCHECK(is_sloppy(language_mode()) || is_this);
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
__ ldr(r2, GlobalObjectOperand());
__ mov(r1, Operand(var->name()));
__ mov(r0, Operand(Smi::FromInt(SLOPPY)));
DCHECK(!context()->IsEffect());
DCHECK(!context()->IsTest());
VariableProxy* proxy = expr->AsVariableProxy();
- if (proxy != NULL && proxy->var()->IsUnallocated()) {
+ if (proxy != NULL && proxy->var()->IsUnallocatedOrGlobalSlot()) {
Comment cmnt(masm_, "[ Global variable");
__ ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
__ mov(LoadDescriptor::NameRegister(), Operand(proxy->name()));
VariableDeclaration* function = scope()->function();
DCHECK(function->proxy()->var()->mode() == CONST ||
function->proxy()->var()->mode() == CONST_LEGACY);
- DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ DCHECK(!function->proxy()->var()->IsUnallocatedOrGlobalSlot());
VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
globals_->Add(variable->name(), zone());
globals_->Add(variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
zone());
break;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
}
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
EmitDebugCheckDeclarationContext(variable);
}
break;
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ VariableDeclaration");
__ Mov(x2, Operand(variable->name()));
// Declaration nodes are always introduced in one of four modes.
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
globals_->Add(variable->name(), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
Comment cmnt(masm_, "[ Function Declaration");
VisitForAccumulatorValue(declaration->fun());
__ Str(result_register(), StackOperand(variable));
break;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ Function Declaration");
EmitDebugCheckDeclarationContext(variable);
VisitForAccumulatorValue(declaration->fun());
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ Function Declaration");
__ Mov(x2, Operand(variable->name()));
__ Mov(x1, Smi::FromInt(NONE));
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
// TODO(rossberg)
break;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ ImportDeclaration");
EmitDebugCheckDeclarationContext(variable);
// TODO(rossberg)
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::LOOKUP:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::LOOKUP:
UNREACHABLE();
}
}
// Three cases: global variables, lookup variables, and all other types of
// variables.
switch (var->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
Comment cmnt(masm_, "Global variable");
__ Ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
__ Mov(LoadDescriptor::NameRegister(), Operand(var->name()));
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::CONTEXT: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, var->IsContextSlot()
? "Context variable"
: "Stack variable");
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Label done, slow;
// Generate code for loading from variables potentially shadowed by
// eval-introduced variables.
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
ASM_LOCATION("FullCodeGenerator::EmitVariableAssignment");
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
// Global var, const, or let.
__ Mov(StoreDescriptor::NameRegister(), Operand(var->name()));
__ Ldr(StoreDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
// "delete this" is allowed.
bool is_this = var->HasThisName(isolate());
DCHECK(is_sloppy(language_mode()) || is_this);
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
__ Ldr(x12, GlobalObjectMemOperand());
__ Mov(x11, Operand(var->name()));
__ Mov(x10, Smi::FromInt(SLOPPY));
DCHECK(!context()->IsEffect());
DCHECK(!context()->IsTest());
VariableProxy* proxy = expr->AsVariableProxy();
- if (proxy != NULL && proxy->var()->IsUnallocated()) {
+ if (proxy != NULL && proxy->var()->IsUnallocatedOrGlobalSlot()) {
Comment cmnt(masm_, "Global variable");
__ Ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
__ Mov(LoadDescriptor::NameRegister(), Operand(proxy->name()));
Variable* var = var_proxy->var();
// The global identifier "undefined" is immutable. Everything
// else could be reassigned.
- return var != NULL && var->location() == Variable::UNALLOCATED &&
+ return var != NULL && var->IsUnallocatedOrGlobalSlot() &&
var_proxy->raw_name()->IsOneByteEqualTo("undefined");
}
void VariableProxy::SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
ICSlotCache* cache) {
variable_feedback_slot_ = slot;
- if (var()->IsUnallocated()) {
+ if (var()->IsUnallocatedOrGlobalSlot()) {
cache->Add(VariableICSlotPair(var(), slot));
}
}
if (UsesVariableFeedbackSlot()) {
// VariableProxies that point to the same Variable within a function can
// make their loads from the same IC slot.
- if (var()->IsUnallocated()) {
+ if (var()->IsUnallocatedOrGlobalSlot()) {
for (int i = 0; i < cache->length(); i++) {
VariableICSlotPair& pair = cache->at(i);
if (pair.variable() == var()) {
Property* property = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(property);
if ((assign_type == VARIABLE &&
- expr->AsVariableProxy()->var()->IsUnallocated()) ||
+ expr->AsVariableProxy()->var()->IsUnallocatedOrGlobalSlot()) ||
assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) {
ic_slots++;
}
if (FunctionLiteral::NeedsHomeObject(value)) ic_slots++;
}
- if (scope() != NULL && class_variable_proxy()->var()->IsUnallocated()) {
+ if (scope() != NULL &&
+ class_variable_proxy()->var()->IsUnallocatedOrGlobalSlot()) {
ic_slots++;
}
if (proxy != NULL) {
if (proxy->var()->is_possibly_eval(isolate)) {
return POSSIBLY_EVAL_CALL;
- } else if (proxy->var()->IsUnallocated()) {
+ } else if (proxy->var()->IsUnallocatedOrGlobalSlot()) {
return GLOBAL_CALL;
} else if (proxy->var()->IsLookupSlot()) {
return LOOKUP_SLOT_CALL;
void BindTo(Variable* var);
bool UsesVariableFeedbackSlot() const {
- return var()->IsUnallocated() || var()->IsLookupSlot();
+ return var()->IsUnallocatedOrGlobalSlot() || var()->IsLookupSlot();
}
virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
bool global_call() const {
VariableProxy* proxy = expression_->AsVariableProxy();
- return proxy != NULL && proxy->var()->IsUnallocated();
+ return proxy != NULL && proxy->var()->IsUnallocatedOrGlobalSlot();
}
bool known_global_function() const {
// Gets the bailout id just before reading a variable proxy, but only for
// unallocated variables.
static BailoutId BeforeId(VariableProxy* proxy) {
- return proxy->var()->location() == Variable::UNALLOCATED ? proxy->BeforeId()
- : BailoutId::None();
+ return proxy->var()->IsUnallocatedOrGlobalSlot() ? proxy->BeforeId()
+ : BailoutId::None();
}
VariableMode mode = decl->mode();
bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET;
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
Handle<Oddball> value = variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
: isolate()->factory()->undefined_value();
globals()->push_back(value);
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (hole_init) {
Node* value = jsgraph()->TheHoleConstant();
environment()->Bind(variable, value);
}
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
if (hole_init) {
Node* value = jsgraph()->TheHoleConstant();
const Operator* op = javascript()->StoreContext(0, variable->index());
NewNode(op, current_context(), value);
}
break;
- case Variable::LOOKUP:
+ case VariableLocation::LOOKUP:
UNIMPLEMENTED();
}
}
void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
Variable* variable = decl->proxy()->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
decl->fun(), info()->script(), info());
// Check for stack-overflow exception.
globals()->push_back(function);
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
VisitForValue(decl->fun());
Node* value = environment()->Pop();
environment()->Bind(variable, value);
break;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
VisitForValue(decl->fun());
Node* value = environment()->Pop();
const Operator* op = javascript()->StoreContext(0, variable->index());
NewNode(op, current_context(), value);
break;
}
- case Variable::LOOKUP:
+ case VariableLocation::LOOKUP:
UNIMPLEMENTED();
}
}
switch (assign_type) {
case VARIABLE: {
Variable* variable = expr->target()->AsVariableProxy()->var();
- if (variable->location() == Variable::PARAMETER ||
- variable->location() == Variable::LOCAL ||
- variable->location() == Variable::CONTEXT) {
+ if (variable->location() == VariableLocation::PARAMETER ||
+ variable->location() == VariableLocation::LOCAL ||
+ variable->location() == VariableLocation::CONTEXT) {
needs_frame_state_before = false;
}
break;
}
case Call::LOOKUP_SLOT_CALL: {
Variable* variable = callee->AsVariableProxy()->var();
- DCHECK(variable->location() == Variable::LOOKUP);
+ DCHECK(variable->location() == VariableLocation::LOOKUP);
Node* name = jsgraph()->Constant(variable->name());
const Operator* op =
javascript()->CallRuntime(Runtime::kLoadLookupSlot, 2);
Node* the_hole = jsgraph()->TheHoleConstant();
VariableMode mode = variable->mode();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
// Global var, const, or let variable.
Node* global = BuildLoadGlobalObject();
Handle<Name> name = variable->name();
states.AddToNode(value, bailout_id, combine);
return value;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
// Local var, const, or let variable.
Node* value = environment()->Lookup(variable);
if (mode == CONST_LEGACY) {
}
return value;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
// Context variable (potentially up the context chain).
int depth = current_scope()->ContextChainLength(variable->scope());
bool immutable = variable->maybe_assigned() == kNotAssigned;
}
return value;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
// Dynamic lookup of context variable (anywhere in the chain).
Node* value = jsgraph()->TheHoleConstant();
Handle<String> name = variable->name();
states.AddToNode(value, bailout_id, combine);
} else if (mode == DYNAMIC_LOCAL) {
Variable* local = variable->local_if_not_shadowed();
- DCHECK(local->location() == Variable::CONTEXT); // Must be context.
+ DCHECK(local->location() ==
+ VariableLocation::CONTEXT); // Must be context.
int depth = current_scope()->ContextChainLength(local->scope());
uint32_t check_bitset = ComputeBitsetForDynamicContext(variable);
const Operator* op = javascript()->LoadDynamicContext(
BailoutId bailout_id,
OutputFrameStateCombine combine) {
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
// Global var, const, or let variable.
Node* global = BuildLoadGlobalObject();
Node* name = jsgraph()->Constant(variable->name());
PrepareFrameState(result, bailout_id, combine);
return result;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::CONTEXT: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::CONTEXT: {
// Local var, const, or let variable or context variable.
return jsgraph()->BooleanConstant(variable->HasThisName(isolate()));
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
// Dynamic lookup of context variable (anywhere in the chain).
Node* name = jsgraph()->Constant(variable->name());
const Operator* op =
Node* the_hole = jsgraph()->TheHoleConstant();
VariableMode mode = variable->mode();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
// Global var, const, or let variable.
Node* global = BuildLoadGlobalObject();
Handle<Name> name = variable->name();
states.AddToNode(store, bailout_id, combine);
return store;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
// Local var, const, or let variable.
if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
// Perform an initialization check for legacy const variables.
}
environment()->Bind(variable, value);
return value;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
// Context variable (potentially up the context chain).
int depth = current_scope()->ContextChainLength(variable->scope());
if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
const Operator* op = javascript()->StoreContext(depth, variable->index());
return NewNode(op, current_context(), value);
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
// Dynamic lookup of context variable (anywhere in the chain).
Node* name = jsgraph()->Constant(variable->name());
Node* language = jsgraph()->Constant(language_mode());
DCHECK(context->IsScriptContext());
Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
int slot_index = ScopeInfo::ContextSlotIndex(
- scope_info, name, &result->mode, &result->init_flag,
+ scope_info, name, &result->mode, &result->location, &result->init_flag,
&result->maybe_assigned_flag);
- if (slot_index >= 0) {
+ if (slot_index >= 0 && result->location == VariableLocation::CONTEXT) {
result->context_index = i;
result->slot_index = slot_index;
return true;
ScopeInfo::cast(context->extension()), isolate);
}
VariableMode mode;
+ VariableLocation location;
InitializationFlag init_flag;
// TODO(sigurds) Figure out whether maybe_assigned_flag should
// be used to compute binding_flags.
MaybeAssignedFlag maybe_assigned_flag;
int slot_index = ScopeInfo::ContextSlotIndex(
- scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
+ scope_info, name, &mode, &location, &init_flag, &maybe_assigned_flag);
DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
- if (slot_index >= 0) {
+ if (slot_index >= 0 && location == VariableLocation::CONTEXT) {
if (FLAG_trace_contexts) {
PrintF("=> found local in context slot %d (mode = %d)\n",
slot_index, mode);
}
+void Context::InitializeGlobalSlots() {
+ DCHECK(IsScriptContext());
+ DisallowHeapAllocation no_gc;
+
+ ScopeInfo* scope_info = ScopeInfo::cast(extension());
+
+ 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++) {
+ // Clear both read and write slots.
+ set(index++, empty_cell);
+ set(index++, empty_cell);
+ }
+ }
+}
+
+
void Context::AddOptimizedFunction(JSFunction* function) {
DCHECK(IsNativeContext());
#ifdef ENABLE_SLOW_DCHECKS
int context_index;
int slot_index;
VariableMode mode;
+ VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
};
that->global_object()->native_context()->security_token();
}
+ // Initializes global variable bindings in given script context.
+ void InitializeGlobalSlots();
+
// A native context holds a list of all functions with optimized code.
void AddOptimizedFunction(JSFunction* function);
void RemoveOptimizedFunction(JSFunction* function);
Handle<Context> Factory::NewNativeContext() {
- Handle<FixedArray> array = NewFixedArray(Context::NATIVE_CONTEXT_SLOTS);
+ Handle<FixedArray> array =
+ NewFixedArray(Context::NATIVE_CONTEXT_SLOTS, TENURED);
array->set_map_no_write_barrier(*native_context_map());
Handle<Context> context = Handle<Context>::cast(array);
context->set_js_array_maps(*undefined_value());
}
+enum class VariableLocation {
+ // Before and during variable allocation, a variable whose location is
+ // not yet determined. After allocation, a variable looked up as a
+ // property on the global object (and possibly absent). name() is the
+ // variable name, index() is invalid.
+ UNALLOCATED,
+
+ // A slot in the parameter section on the stack. index() is the
+ // parameter index, counting left-to-right. The receiver is index -1;
+ // the first parameter is index 0.
+ PARAMETER,
+
+ // A slot in the local section on the stack. index() is the variable
+ // index in the stack frame, starting at 0.
+ LOCAL,
+
+ // An indexed slot in a heap context. index() is the variable index in
+ // the context object on the heap, starting at 0. scope() is the
+ // corresponding scope.
+ CONTEXT,
+
+ // An indexed slot in a script context that contains a respective global
+ // property cell. name() is the variable name, index() is the variable
+ // index in the context object on the heap, starting at 0. scope() is the
+ // corresponding script scope.
+ GLOBAL,
+
+ // A named slot in a heap context. name() is the variable name in the
+ // context object on the heap, with lookup starting at the current
+ // context. index() is invalid.
+ LOOKUP
+};
+
+
// ES6 Draft Rev3 10.2 specifies declarative environment records with mutable
// and immutable bindings that can be in two states: initialized and
// uninitialized. In ES5 only immutable bindings have these two states. When
cell->set_value(Smi::FromInt(Isolate::kArrayProtectorValid));
set_array_protector(*cell);
+ cell = factory->NewPropertyCell();
+ cell->set_value(the_hole_value());
+ set_empty_property_cell(*cell);
+
set_weak_stack_trace_list(Smi::FromInt(0));
set_allocation_sites_scratchpad(
V(ArrayList, retained_maps, RetainedMaps) \
V(WeakHashTable, weak_object_to_code_table, WeakObjectToCodeTable) \
V(PropertyCell, array_protector, ArrayProtector) \
+ V(PropertyCell, empty_property_cell, EmptyPropertyCell) \
V(Object, weak_stack_trace_list, WeakStackTraceList)
// Entries in this list are limited to Smis and are not visited during GC.
DCHECK(current_block()->HasPredecessor());
Variable* variable = expr->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
if (IsLexicalVariableMode(variable->mode())) {
// TODO(rossberg): should this be an DCHECK?
return Bailout(kReferenceToGlobalLexicalVariable);
}
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
HValue* value = LookupAndMakeLive(variable);
if (value == graph()->GetConstantHole()) {
DCHECK(IsDeclaredVariableMode(variable->mode()) &&
return ast_context()->ReturnValue(value);
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
HValue* context = BuildContextChainWalk(variable);
HLoadContextSlot::Mode mode;
switch (variable->mode()) {
return ast_context()->ReturnInstruction(instr, expr->id());
}
- case Variable::LOOKUP:
+ case VariableLocation::LOOKUP:
return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup);
}
}
CHECK_ALIVE(VisitForValue(operation));
switch (var->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
HandleGlobalVariableAssignment(var,
Top(),
expr->AssignmentId());
break;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (var->mode() == CONST_LEGACY) {
return Bailout(kUnsupportedConstCompoundAssignment);
}
BindIfLive(var, Top());
break;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
// Bail out if we try to mutate a parameter value in a function
// using the arguments object. We do not (yet) correctly handle the
// arguments property of the function.
break;
}
- case Variable::LOOKUP:
+ case VariableLocation::LOOKUP:
return Bailout(kCompoundAssignmentToLookupSlot);
}
return ast_context()->ReturnValue(Pop());
// Handle the assignment.
switch (var->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
CHECK_ALIVE(VisitForValue(expr->value()));
HandleGlobalVariableAssignment(var,
Top(),
expr->AssignmentId());
return ast_context()->ReturnValue(Pop());
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
// Perform an initialization check for let declared variables
// or parameters.
if (var->mode() == LET && expr->op() == Token::ASSIGN) {
return ast_context()->ReturnValue(value);
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
// Bail out if we try to mutate a parameter value in a function using
// the arguments object. We do not (yet) correctly handle the
// arguments property of the function.
return ast_context()->ReturnValue(Pop());
}
- case Variable::LOOKUP:
+ case VariableLocation::LOOKUP:
return Bailout(kAssignmentToLOOKUPVariable);
}
} else {
return ast_context()->ReturnInstruction(instr, expr->id());
} else if (proxy != NULL) {
Variable* var = proxy->var();
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
Bailout(kDeleteWithGlobalVariable);
} else if (var->IsStackAllocated() || var->IsContextSlot()) {
// Result of deleting non-global variables is false. 'this' is not really
Push(after);
switch (var->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
HandleGlobalVariableAssignment(var,
after,
expr->AssignmentId());
break;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
BindIfLive(var, after);
break;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
// Bail out if we try to mutate a parameter value in a function
// using the arguments object. We do not (yet) correctly handle the
// arguments property of the function.
break;
}
- case Variable::LOOKUP:
+ case VariableLocation::LOOKUP:
return Bailout(kLookupVariableInCountOperation);
}
Variable* variable = proxy->var();
bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
globals_.Add(variable->name(), zone());
globals_.Add(variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
: isolate()->factory()->undefined_value(), zone());
return;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (hole_init) {
HValue* value = graph()->GetConstantHole();
environment()->Bind(variable, value);
}
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
if (hole_init) {
HValue* value = graph()->GetConstantHole();
HValue* context = environment()->context();
}
}
break;
- case Variable::LOOKUP:
+ case VariableLocation::LOOKUP:
return Bailout(kUnsupportedLookupSlotInDeclaration);
}
}
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
globals_.Add(variable->name(), zone());
Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
declaration->fun(), current_info()->script(), top_info());
globals_.Add(function, zone());
return;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
CHECK_ALIVE(VisitForValue(declaration->fun()));
HValue* value = Pop();
BindIfLive(variable, value);
break;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
CHECK_ALIVE(VisitForValue(declaration->fun()));
HValue* value = Pop();
HValue* context = environment()->context();
}
break;
}
- case Variable::LOOKUP:
+ case VariableLocation::LOOKUP:
return Bailout(kUnsupportedLookupSlotInDeclaration);
}
}
VariableDeclaration* function = scope()->function();
DCHECK(function->proxy()->var()->mode() == CONST ||
function->proxy()->var()->mode() == CONST_LEGACY);
- DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ DCHECK(!function->proxy()->var()->IsUnallocatedOrGlobalSlot());
VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
Variable* variable = proxy->var();
bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
globals_->Add(variable->name(), zone());
globals_->Add(variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
: isolate()->factory()->undefined_value(), zone());
break;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
__ mov(StackOperand(variable),
}
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
EmitDebugCheckDeclarationContext(variable);
}
break;
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ VariableDeclaration");
__ push(esi);
__ push(Immediate(variable->name()));
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
globals_->Add(variable->name(), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
Comment cmnt(masm_, "[ FunctionDeclaration");
VisitForAccumulatorValue(declaration->fun());
__ mov(StackOperand(variable), result_register());
break;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ FunctionDeclaration");
EmitDebugCheckDeclarationContext(variable);
VisitForAccumulatorValue(declaration->fun());
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ FunctionDeclaration");
__ push(esi);
__ push(Immediate(variable->name()));
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
// TODO(rossberg)
break;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ ImportDeclaration");
EmitDebugCheckDeclarationContext(variable);
// TODO(rossberg)
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::LOOKUP:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::LOOKUP:
UNREACHABLE();
}
}
// Three cases: global variables, lookup variables, and all other types of
// variables.
switch (var->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
Comment cmnt(masm_, "[ Global variable");
__ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
__ mov(LoadDescriptor::NameRegister(), var->name());
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::CONTEXT: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable");
if (var->binding_needs_init()) {
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ Lookup variable");
Label done, slow;
// Generate code for loading from variables potentially shadowed
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
// Global var, const, or let.
__ mov(StoreDescriptor::NameRegister(), var->name());
__ mov(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
// "delete this" is allowed.
bool is_this = var->HasThisName(isolate());
DCHECK(is_sloppy(language_mode()) || is_this);
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
__ push(GlobalObjectOperand());
__ push(Immediate(var->name()));
__ push(Immediate(Smi::FromInt(SLOPPY)));
DCHECK(!context()->IsEffect());
DCHECK(!context()->IsTest());
- if (proxy != NULL && proxy->var()->IsUnallocated()) {
+ if (proxy != NULL && proxy->var()->IsUnallocatedOrGlobalSlot()) {
Comment cmnt(masm_, "[ Global variable");
__ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
__ mov(LoadDescriptor::NameRegister(), Immediate(proxy->name()));
ZoneList<Variable*> stack_list(current_scope->StackLocalCount(), zone);
ZoneList<Variable*> context_list(
current_scope->ContextLocalCount(), zone);
- current_scope->CollectStackAndContextLocals(&stack_list, &context_list);
+ ZoneList<Variable*> globals_list(current_scope->ContextGlobalCount(),
+ zone);
+ current_scope->CollectStackAndContextLocals(&stack_list, &context_list,
+ &globals_list);
context_list.Sort(&Variable::CompareIndex);
for (int i = 0; i < context_list.length(); i++) {
VariableDeclaration* function = scope()->function();
DCHECK(function->proxy()->var()->mode() == CONST ||
function->proxy()->var()->mode() == CONST_LEGACY);
- DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ DCHECK(!function->proxy()->var()->IsUnallocatedOrGlobalSlot());
VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
Variable* variable = proxy->var();
bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
globals_->Add(variable->name(), zone());
globals_->Add(variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
zone());
break;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
}
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
EmitDebugCheckDeclarationContext(variable);
}
break;
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ VariableDeclaration");
__ li(a2, Operand(variable->name()));
// Declaration nodes are always introduced in one of four modes.
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
globals_->Add(variable->name(), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
Comment cmnt(masm_, "[ FunctionDeclaration");
VisitForAccumulatorValue(declaration->fun());
__ sw(result_register(), StackOperand(variable));
break;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ FunctionDeclaration");
EmitDebugCheckDeclarationContext(variable);
VisitForAccumulatorValue(declaration->fun());
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ FunctionDeclaration");
__ li(a2, Operand(variable->name()));
__ li(a1, Operand(Smi::FromInt(NONE)));
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
// TODO(rossberg)
break;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ ImportDeclaration");
EmitDebugCheckDeclarationContext(variable);
// TODO(rossberg)
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::LOOKUP:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::LOOKUP:
UNREACHABLE();
}
}
// Three cases: global variables, lookup variables, and all other types of
// variables.
switch (var->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
Comment cmnt(masm_, "[ Global variable");
__ lw(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
__ li(LoadDescriptor::NameRegister(), Operand(var->name()));
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::CONTEXT: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable");
if (var->binding_needs_init()) {
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ Lookup variable");
Label done, slow;
// Generate code for loading from variables potentially shadowed
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
// Global var, const, or let.
__ mov(StoreDescriptor::ValueRegister(), result_register());
__ li(StoreDescriptor::NameRegister(), Operand(var->name()));
// "delete this" is allowed.
bool is_this = var->HasThisName(isolate());
DCHECK(is_sloppy(language_mode()) || is_this);
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
__ lw(a2, GlobalObjectOperand());
__ li(a1, Operand(var->name()));
__ li(a0, Operand(Smi::FromInt(SLOPPY)));
DCHECK(!context()->IsEffect());
DCHECK(!context()->IsTest());
VariableProxy* proxy = expr->AsVariableProxy();
- if (proxy != NULL && proxy->var()->IsUnallocated()) {
+ if (proxy != NULL && proxy->var()->IsUnallocatedOrGlobalSlot()) {
Comment cmnt(masm_, "[ Global variable");
__ lw(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
__ li(LoadDescriptor::NameRegister(), Operand(proxy->name()));
VariableDeclaration* function = scope()->function();
DCHECK(function->proxy()->var()->mode() == CONST ||
function->proxy()->var()->mode() == CONST_LEGACY);
- DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ DCHECK(!function->proxy()->var()->IsUnallocatedOrGlobalSlot());
VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
Variable* variable = proxy->var();
bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
globals_->Add(variable->name(), zone());
globals_->Add(variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
zone());
break;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
}
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
EmitDebugCheckDeclarationContext(variable);
}
break;
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ VariableDeclaration");
__ li(a2, Operand(variable->name()));
// Declaration nodes are always introduced in one of four modes.
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
globals_->Add(variable->name(), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
Comment cmnt(masm_, "[ FunctionDeclaration");
VisitForAccumulatorValue(declaration->fun());
__ sd(result_register(), StackOperand(variable));
break;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ FunctionDeclaration");
EmitDebugCheckDeclarationContext(variable);
VisitForAccumulatorValue(declaration->fun());
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ FunctionDeclaration");
__ li(a2, Operand(variable->name()));
__ li(a1, Operand(Smi::FromInt(NONE)));
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
// TODO(rossberg)
break;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ ImportDeclaration");
EmitDebugCheckDeclarationContext(variable);
// TODO(rossberg)
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::LOOKUP:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::LOOKUP:
UNREACHABLE();
}
}
// Three cases: global variables, lookup variables, and all other types of
// variables.
switch (var->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
Comment cmnt(masm_, "[ Global variable");
// Use inline caching. Variable name is passed in a2 and the global
// object (receiver) in a0.
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::CONTEXT: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable");
if (var->binding_needs_init()) {
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ Lookup variable");
Label done, slow;
// Generate code for loading from variables potentially shadowed
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
// Global var, const, or let.
__ mov(StoreDescriptor::ValueRegister(), result_register());
__ li(StoreDescriptor::NameRegister(), Operand(var->name()));
// "delete this" is allowed.
bool is_this = var->HasThisName(isolate());
DCHECK(is_sloppy(language_mode()) || is_this);
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
__ ld(a2, GlobalObjectOperand());
__ li(a1, Operand(var->name()));
__ li(a0, Operand(Smi::FromInt(SLOPPY)));
DCHECK(!context()->IsEffect());
DCHECK(!context()->IsTest());
VariableProxy* proxy = expr->AsVariableProxy();
- if (proxy != NULL && proxy->var()->IsUnallocated()) {
+ if (proxy != NULL && proxy->var()->IsUnallocatedOrGlobalSlot()) {
Comment cmnt(masm_, "[ Global variable");
__ ld(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
__ li(LoadDescriptor::NameRegister(), Operand(proxy->name()));
// If the slot is present and mode != NULL, sets *mode to the corresponding
// mode for that variable.
static int ContextSlotIndex(Handle<ScopeInfo> scope_info, Handle<String> name,
- VariableMode* mode, InitializationFlag* init_flag,
+ VariableMode* mode, VariableLocation* location,
+ InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag);
// Lookup support for serialized scope info. Returns the
V(ParameterCount) \
V(StackLocalCount) \
V(ContextLocalCount) \
+ V(ContextGlobalCount) \
V(StrongModeFreeVariableCount)
#define FIELD_ACCESSORS(name) \
int StackLocalFirstSlotIndex();
int StackLocalEntriesIndex();
int ContextLocalNameEntriesIndex();
+ int ContextGlobalNameEntriesIndex();
int ContextLocalInfoEntriesIndex();
+ int ContextGlobalInfoEntriesIndex();
int StrongModeFreeVariableNameEntriesIndex();
int StrongModeFreeVariablePositionEntriesIndex();
int ReceiverEntryIndex();
int FunctionNameEntryIndex();
+ int Lookup(Handle<String> name, int start, int end, VariableMode* mode,
+ VariableLocation* location, InitializationFlag* init_flag,
+ MaybeAssignedFlag* maybe_assigned_flag);
+
// Used for the function name variable for named function expressions, and for
// the receiver.
enum VariableAllocationInfo { NONE, STACK, CONTEXT, UNUSED };
// TODO(sigurds) figure out if kNotAssigned is OK here
var = new (zone()) Variable(declaration_scope, name, mode, kind,
declaration->initialization(), kNotAssigned);
- var->AllocateTo(Variable::LOOKUP, -1);
+ var->AllocateTo(VariableLocation::LOOKUP, -1);
resolve = true;
}
VariableDeclaration* function = scope()->function();
DCHECK(function->proxy()->var()->mode() == CONST ||
function->proxy()->var()->mode() == CONST_LEGACY);
- DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ DCHECK(!function->proxy()->var()->IsUnallocatedOrGlobalSlot());
VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
Variable* variable = proxy->var();
bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
globals_->Add(variable->name(), zone());
globals_->Add(variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
zone());
break;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
}
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
EmitDebugCheckDeclarationContext(variable);
}
break;
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ VariableDeclaration");
__ mov(r5, Operand(variable->name()));
// Declaration nodes are always introduced in one of four modes.
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
globals_->Add(variable->name(), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
Comment cmnt(masm_, "[ FunctionDeclaration");
VisitForAccumulatorValue(declaration->fun());
__ StoreP(result_register(), StackOperand(variable));
break;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ FunctionDeclaration");
EmitDebugCheckDeclarationContext(variable);
VisitForAccumulatorValue(declaration->fun());
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ FunctionDeclaration");
__ mov(r5, Operand(variable->name()));
__ LoadSmiLiteral(r4, Smi::FromInt(NONE));
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
// TODO(rossberg)
break;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ ImportDeclaration");
EmitDebugCheckDeclarationContext(variable);
// TODO(rossberg)
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::LOOKUP:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::LOOKUP:
UNREACHABLE();
}
}
// Three cases: global variables, lookup variables, and all other types of
// variables.
switch (var->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
Comment cmnt(masm_, "[ Global variable");
__ LoadP(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
__ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::CONTEXT: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable");
if (var->binding_needs_init()) {
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ Lookup variable");
Label done, slow;
// Generate code for loading from variables potentially shadowed
EmbeddedVector<char, 128> buf;
int pos = SNPrintF(buf, "VAR PROXY");
switch (var->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::UNALLOCATED:
break;
- case Variable::PARAMETER:
+ case VariableLocation::PARAMETER:
SNPrintF(buf + pos, " parameter[%d]", var->index());
break;
- case Variable::LOCAL:
+ case VariableLocation::LOCAL:
SNPrintF(buf + pos, " local[%d]", var->index());
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
SNPrintF(buf + pos, " context[%d]", var->index());
break;
- case Variable::LOOKUP:
+ case VariableLocation::GLOBAL:
+ SNPrintF(buf + pos, " global[%d]", var->index());
+ break;
+ case VariableLocation::LOOKUP:
SNPrintF(buf + pos, " lookup");
break;
}
if (scope_info->LocalIsSynthetic(i)) continue;
Handle<String> name(scope_info->LocalName(i));
VariableMode mode;
+ VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
locals->set(local * 2, *name);
int context_slot_index = ScopeInfo::ContextSlotIndex(
- scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
+ scope_info, name, &mode, &location, &init_flag, &maybe_assigned_flag);
+ DCHECK(VariableLocation::CONTEXT == location);
Object* value = context->get(context_slot_index);
locals->set(local * 2 + 1, value);
local++;
static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
Handle<String> parameter_name) {
VariableMode mode;
+ VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
- return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag,
- &maybe_assigned_flag) != -1;
+ return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &location,
+ &init_flag, &maybe_assigned_flag) != -1;
}
Handle<Object> receiver;
switch (scope_info->scope_type()) {
case FUNCTION_SCOPE: {
- VariableMode variable_mode;
+ VariableMode mode;
+ VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
// Don't bother creating a fake context node if "this" is in the context
// already.
if (ScopeInfo::ContextSlotIndex(
- scope_info, isolate->factory()->this_string(), &variable_mode,
+ scope_info, isolate->factory()->this_string(), &mode, &location,
&init_flag, &maybe_assigned_flag) >= 0) {
return target;
}
Handle<String> next_name(scope_info->ContextLocalName(i));
if (String::Equals(variable_name, next_name)) {
VariableMode mode;
+ VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
- int context_index = ScopeInfo::ContextSlotIndex(
- scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
+ int context_index =
+ ScopeInfo::ContextSlotIndex(scope_info, next_name, &mode, &location,
+ &init_flag, &maybe_assigned_flag);
context->set(context_index, *new_value);
return true;
}
}
+static inline bool IsDebugContext(Isolate* isolate, Context* context) {
+ // Try to unwrap script context if it exist.
+ if (context->IsScriptContext()) context = context->previous();
+ DCHECK_NOT_NULL(context);
+ return context == *isolate->debug()->debug_context();
+}
+
+
RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
HandleScope scope(isolate);
// Enter the top context from before the debugger was invoked.
SaveContext save(isolate);
SaveContext* top = &save;
- while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
+ while (top != NULL && IsDebugContext(isolate, *top->context())) {
top = top->prev();
}
if (top != NULL) {
Handle<ScriptContextTable> script_context_table(
native_context->script_context_table());
- Handle<String> clashed_name;
Object* name_clash_result =
FindNameClash(scope_info, global_object, script_context_table);
if (isolate->has_pending_exception()) return name_clash_result;
// Script contexts have a canonical empty function as their closure, not the
// anonymous closure containing the global code. See
// FullCodeGenerator::PushFunctionArgumentForContextAllocation.
- Handle<JSFunction> closure(native_context->closure());
+ Handle<JSFunction> closure(global_object->IsJSBuiltinsObject()
+ ? *function
+ : native_context->closure());
Handle<Context> result =
isolate->factory()->NewScriptContext(closure, scope_info);
+ result->InitializeGlobalSlots();
+
DCHECK(function->context() == isolate->context());
- DCHECK(function->context()->global_object() == result->global_object());
+ DCHECK(*global_object == result->global_object());
Handle<ScriptContextTable> new_script_context_table =
ScriptContextTable::Extend(script_context_table, result);
// Collect stack and context locals.
ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
+ ZoneList<Variable*> context_globals(scope->ContextGlobalCount(), zone);
ZoneList<Variable*> strong_mode_free_variables(0, zone);
scope->CollectStackAndContextLocals(&stack_locals, &context_locals,
+ &context_globals,
&strong_mode_free_variables);
const int stack_local_count = stack_locals.length();
const int context_local_count = context_locals.length();
+ const int context_global_count = context_globals.length();
const int strong_mode_free_variable_count =
strong_mode_free_variables.length();
// Make sure we allocate the correct amount.
- DCHECK(scope->ContextLocalCount() == context_local_count);
+ DCHECK_EQ(scope->ContextLocalCount(), context_local_count);
+ DCHECK_EQ(scope->ContextGlobalCount(), context_global_count);
bool simple_parameter_list =
scope->is_function_scope() ? scope->is_simple_parameter_list() : true;
function_name_info = NONE;
function_variable_mode = VAR;
}
+ DCHECK(context_global_count == 0 || scope->scope_type() == SCRIPT_SCOPE);
const bool has_function_name = function_name_info != NONE;
const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT;
const int parameter_count = scope->num_parameters();
const int length = kVariablePartIndex + parameter_count +
(1 + stack_local_count) + 2 * context_local_count +
+ 2 * context_global_count +
3 * strong_mode_free_variable_count +
(has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
scope_info->SetParameterCount(parameter_count);
scope_info->SetStackLocalCount(stack_local_count);
scope_info->SetContextLocalCount(context_local_count);
+ scope_info->SetContextGlobalCount(context_global_count);
scope_info->SetStrongModeFreeVariableCount(strong_mode_free_variable_count);
int index = kVariablePartIndex;
scope_info->set(index++, *context_locals[i]->name());
}
+ // Add context globals' names.
+ DCHECK(index == scope_info->ContextGlobalNameEntriesIndex());
+ for (int i = 0; i < context_global_count; ++i) {
+ scope_info->set(index++, *context_globals[i]->name());
+ }
+
// Add context locals' info.
DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
for (int i = 0; i < context_local_count; ++i) {
scope_info->set(index++, Smi::FromInt(value));
}
+ // Add context globals' info.
+ DCHECK(index == scope_info->ContextGlobalInfoEntriesIndex());
+ for (int i = 0; i < context_global_count; ++i) {
+ Variable* var = context_globals[i];
+ // TODO(ishell): do we need this kind of info for globals here?
+ uint32_t value =
+ ContextLocalMode::encode(var->mode()) |
+ ContextLocalInitFlag::encode(var->initialization_flag()) |
+ ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
+ scope_info->set(index++, Smi::FromInt(value));
+ }
+
DCHECK(index == scope_info->StrongModeFreeVariableNameEntriesIndex());
for (int i = 0; i < strong_mode_free_variable_count; ++i) {
scope_info->set(index++, *strong_mode_free_variables[i]->name());
const int stack_local_count = 0;
const int context_local_count = 1;
+ const int context_global_count = 0;
const int strong_mode_free_variable_count = 0;
const bool simple_parameter_list = true;
const VariableAllocationInfo receiver_info = CONTEXT;
const int parameter_count = 0;
const int length = kVariablePartIndex + parameter_count +
(1 + stack_local_count) + 2 * context_local_count +
+ 2 * context_global_count +
3 * strong_mode_free_variable_count +
(has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
scope_info->SetParameterCount(parameter_count);
scope_info->SetStackLocalCount(stack_local_count);
scope_info->SetContextLocalCount(context_local_count);
+ scope_info->SetContextGlobalCount(context_global_count);
scope_info->SetStrongModeFreeVariableCount(strong_mode_free_variable_count);
int index = kVariablePartIndex;
int ScopeInfo::ContextLength() {
if (length() > 0) {
int context_locals = ContextLocalCount();
+ int context_globals = ContextGlobalCount();
bool function_name_context_slot =
FunctionVariableField::decode(Flags()) == CONTEXT;
- bool has_context = context_locals > 0 || function_name_context_slot ||
+ bool has_context = context_locals > 0 || context_globals > 0 ||
+ function_name_context_slot ||
scope_type() == WITH_SCOPE ||
(scope_type() == ARROW_SCOPE && CallsSloppyEval()) ||
(scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) ||
scope_type() == MODULE_SCOPE;
+
if (has_context) {
- return Context::MIN_CONTEXT_SLOTS + context_locals +
- (function_name_context_slot ? 1 : 0);
+ return Context::MIN_CONTEXT_SLOTS + context_locals + 2 * context_globals +
+ (function_name_context_slot ? 1 : 0);
}
}
return 0;
String* ScopeInfo::ContextLocalName(int var) {
- DCHECK(0 <= var && var < ContextLocalCount());
+ DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
int info_index = ContextLocalNameEntriesIndex() + var;
return String::cast(get(info_index));
}
VariableMode ScopeInfo::ContextLocalMode(int var) {
- DCHECK(0 <= var && var < ContextLocalCount());
+ DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
int info_index = ContextLocalInfoEntriesIndex() + var;
int value = Smi::cast(get(info_index))->value();
return ContextLocalMode::decode(value);
InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
- DCHECK(0 <= var && var < ContextLocalCount());
+ DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
int info_index = ContextLocalInfoEntriesIndex() + var;
int value = Smi::cast(get(info_index))->value();
return ContextLocalInitFlag::decode(value);
MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
- DCHECK(0 <= var && var < ContextLocalCount());
+ DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
int info_index = ContextLocalInfoEntriesIndex() + var;
int value = Smi::cast(get(info_index))->value();
return ContextLocalMaybeAssignedFlag::decode(value);
int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
Handle<String> name, VariableMode* mode,
+ VariableLocation* location,
InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag) {
DCHECK(name->IsInternalizedString());
DCHECK(mode != NULL);
+ DCHECK(location != NULL);
DCHECK(init_flag != NULL);
if (scope_info->length() > 0) {
ContextSlotCache* context_slot_cache =
scope_info->GetIsolate()->context_slot_cache();
- int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag,
- maybe_assigned_flag);
+ int result = context_slot_cache->Lookup(*scope_info, *name, mode, location,
+ init_flag, maybe_assigned_flag);
if (result != ContextSlotCache::kNotFound) {
DCHECK(result < scope_info->ContextLength());
return result;
}
+ DCHECK_EQ(scope_info->ContextGlobalNameEntriesIndex(),
+ scope_info->ContextLocalNameEntriesIndex() +
+ scope_info->ContextLocalCount());
int start = scope_info->ContextLocalNameEntriesIndex();
- int end = scope_info->ContextLocalNameEntriesIndex() +
- scope_info->ContextLocalCount();
+ int end = scope_info->ContextGlobalNameEntriesIndex() +
+ scope_info->ContextGlobalCount();
for (int i = start; i < end; ++i) {
if (*name == scope_info->get(i)) {
int var = i - start;
*mode = scope_info->ContextLocalMode(var);
*init_flag = scope_info->ContextLocalInitFlag(var);
*maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
- result = Context::MIN_CONTEXT_SLOTS + var;
- context_slot_cache->Update(scope_info, name, *mode, *init_flag,
- *maybe_assigned_flag, result);
+
+ if (var < scope_info->ContextLocalCount()) {
+ *location = VariableLocation::CONTEXT;
+ result = Context::MIN_CONTEXT_SLOTS + var;
+ } else {
+ var -= scope_info->ContextLocalCount();
+ *location = VariableLocation::GLOBAL;
+ result = Context::MIN_CONTEXT_SLOTS +
+ scope_info->ContextLocalCount() + 2 * var;
+ }
+
+ context_slot_cache->Update(scope_info, name, *mode, *location,
+ *init_flag, *maybe_assigned_flag, result);
DCHECK(result < scope_info->ContextLength());
return result;
}
}
- // Cache as not found. Mode, init flag and maybe assigned flag don't matter.
- context_slot_cache->Update(scope_info, name, INTERNAL, kNeedsInitialization,
+ // Cache as not found. Mode, location, init flag and maybe assigned flag
+ // don't matter.
+ context_slot_cache->Update(scope_info, name, INTERNAL,
+ VariableLocation::CONTEXT, kNeedsInitialization,
kNotAssigned, -1);
}
return -1;
}
-int ScopeInfo::ContextLocalInfoEntriesIndex() {
+int ScopeInfo::ContextGlobalNameEntriesIndex() {
return ContextLocalNameEntriesIndex() + ContextLocalCount();
}
-int ScopeInfo::StrongModeFreeVariableNameEntriesIndex() {
+int ScopeInfo::ContextLocalInfoEntriesIndex() {
+ return ContextGlobalNameEntriesIndex() + ContextGlobalCount();
+}
+
+
+int ScopeInfo::ContextGlobalInfoEntriesIndex() {
return ContextLocalInfoEntriesIndex() + ContextLocalCount();
}
+int ScopeInfo::StrongModeFreeVariableNameEntriesIndex() {
+ return ContextGlobalInfoEntriesIndex() + ContextGlobalCount();
+}
+
+
int ScopeInfo::StrongModeFreeVariablePositionEntriesIndex() {
return StrongModeFreeVariableNameEntriesIndex() +
StrongModeFreeVariableCount();
int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
+ VariableLocation* location,
InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag) {
int index = Hash(data, name);
if ((key.data == data) && key.name->Equals(name)) {
Value result(values_[index]);
if (mode != NULL) *mode = result.mode();
+ if (location != NULL) *location = result.location();
if (init_flag != NULL) *init_flag = result.initialization_flag();
if (maybe_assigned_flag != NULL)
*maybe_assigned_flag = result.maybe_assigned_flag();
void ContextSlotCache::Update(Handle<Object> data, Handle<String> name,
- VariableMode mode, InitializationFlag init_flag,
+ VariableMode mode, VariableLocation location,
+ InitializationFlag init_flag,
MaybeAssignedFlag maybe_assigned_flag,
int slot_index) {
DisallowHeapAllocation no_gc;
key.data = *data;
key.name = *internalized_name;
// Please note value only takes a uint as index.
- values_[index] = Value(mode, init_flag, maybe_assigned_flag,
+ values_[index] = Value(mode, location, init_flag, maybe_assigned_flag,
slot_index - kNotFound).raw();
#ifdef DEBUG
- ValidateEntry(data, name, mode, init_flag, maybe_assigned_flag, slot_index);
+ ValidateEntry(data, name, mode, location, init_flag, maybe_assigned_flag,
+ slot_index);
#endif
}
}
void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name,
VariableMode mode,
+ VariableLocation location,
InitializationFlag init_flag,
MaybeAssignedFlag maybe_assigned_flag,
int slot_index) {
DCHECK(key.name->Equals(*name));
Value result(values_[index]);
DCHECK(result.mode() == mode);
+ DCHECK(result.location() == location);
DCHECK(result.initialization_flag() == init_flag);
DCHECK(result.maybe_assigned_flag() == maybe_assigned_flag);
DCHECK(result.index() + kNotFound == slot_index);
// Lookup context slot index for (data, name).
// If absent, kNotFound is returned.
int Lookup(Object* data, String* name, VariableMode* mode,
- InitializationFlag* init_flag,
+ VariableLocation* location, InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag);
// Update an element in the cache.
void Update(Handle<Object> data, Handle<String> name, VariableMode mode,
- InitializationFlag init_flag,
+ VariableLocation location, InitializationFlag init_flag,
MaybeAssignedFlag maybe_assigned_flag, int slot_index);
// Clear the cache.
#ifdef DEBUG
void ValidateEntry(Handle<Object> data, Handle<String> name,
- VariableMode mode, InitializationFlag init_flag,
+ VariableMode mode, VariableLocation location,
+ InitializationFlag init_flag,
MaybeAssignedFlag maybe_assigned_flag, int slot_index);
#endif
};
struct Value {
- Value(VariableMode mode, InitializationFlag init_flag,
- MaybeAssignedFlag maybe_assigned_flag, int index) {
+ enum VariableLocationFlag { kContext, kGlobal };
+
+ Value(VariableMode mode, VariableLocation location,
+ InitializationFlag init_flag, MaybeAssignedFlag maybe_assigned_flag,
+ int index) {
+ DCHECK(location == VariableLocation::CONTEXT ||
+ location == VariableLocation::GLOBAL);
+ VariableLocationFlag location_flag =
+ location == VariableLocation::CONTEXT ? kContext : kGlobal;
DCHECK(ModeField::is_valid(mode));
+ DCHECK(VariableLocationField::is_valid(location_flag));
DCHECK(InitField::is_valid(init_flag));
DCHECK(MaybeAssignedField::is_valid(maybe_assigned_flag));
DCHECK(IndexField::is_valid(index));
value_ = ModeField::encode(mode) | IndexField::encode(index) |
+ VariableLocationField::encode(location_flag) |
InitField::encode(init_flag) |
MaybeAssignedField::encode(maybe_assigned_flag);
DCHECK(mode == this->mode());
+ DCHECK(location == this->location());
DCHECK(init_flag == this->initialization_flag());
DCHECK(maybe_assigned_flag == this->maybe_assigned_flag());
DCHECK(index == this->index());
VariableMode mode() { return ModeField::decode(value_); }
+ VariableLocation location() {
+ switch (VariableLocationField::decode(value_)) {
+ case kContext:
+ return VariableLocation::CONTEXT;
+ case kGlobal:
+ return VariableLocation::GLOBAL;
+ }
+ UNREACHABLE();
+ return VariableLocation::CONTEXT;
+ }
+
InitializationFlag initialization_flag() {
return InitField::decode(value_);
}
class ModeField : public BitField<VariableMode, 0, 4> {};
class InitField : public BitField<InitializationFlag, 4, 1> {};
class MaybeAssignedField : public BitField<MaybeAssignedFlag, 5, 1> {};
- class IndexField : public BitField<int, 6, 32 - 6> {};
+ class VariableLocationField : public BitField<VariableLocationFlag, 6, 1> {
+ };
+ class IndexField : public BitField<int, 7, 32 - 7> {};
private:
uint32_t value_;
namespace v8 {
namespace internal {
+// TODO(ishell): remove this once compiler support is landed.
+bool enable_context_globals = false;
+
// ----------------------------------------------------------------------------
// Implementation of LocalsMap
//
num_var_or_const_ = 0;
num_stack_slots_ = 0;
num_heap_slots_ = 0;
+ num_global_slots_ = 0;
num_modules_ = 0;
module_var_ = NULL,
rest_parameter_ = NULL;
// Check context slot lookup.
VariableMode mode;
- Variable::Location location = Variable::CONTEXT;
+ VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
- int index = ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode,
- &init_flag, &maybe_assigned_flag);
+ int index =
+ ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode, &location,
+ &init_flag, &maybe_assigned_flag);
if (index < 0) {
// Check parameters.
index = scope_info_->ParameterIndex(*name_handle);
if (index < 0) return NULL;
mode = DYNAMIC;
- location = Variable::LOOKUP;
+ location = VariableLocation::LOOKUP;
init_flag = kCreatedInitialized;
// Be conservative and flag parameters as maybe assigned. Better information
// would require ScopeInfo to serialize the maybe_assigned bit also for
// parameters.
maybe_assigned_flag = kMaybeAssigned;
+ } else {
+ DCHECK(location != VariableLocation::GLOBAL ||
+ (is_script_scope() && IsDeclaredVariableMode(mode) &&
+ !IsLexicalVariableMode(mode)));
}
Variable::Kind kind = Variable::NORMAL;
- if (location == Variable::CONTEXT &&
+ if (location == VariableLocation::CONTEXT &&
index == scope_info_->ReceiverContextSlotIndex()) {
kind = Variable::THIS;
}
VariableDeclaration* declaration = factory->NewVariableDeclaration(
proxy, mode, this, RelocInfo::kNoPosition);
DeclareFunctionVar(declaration);
- var->AllocateTo(Variable::CONTEXT, index);
+ var->AllocateTo(VariableLocation::CONTEXT, index);
return var;
} else {
return NULL;
void Scope::CollectStackAndContextLocals(
ZoneList<Variable*>* stack_locals, ZoneList<Variable*>* context_locals,
+ ZoneList<Variable*>* context_globals,
ZoneList<Variable*>* strong_mode_free_variables) {
DCHECK(stack_locals != NULL);
DCHECK(context_locals != NULL);
+ DCHECK(context_globals != NULL);
// Collect internals which are always allocated on the heap.
for (int i = 0; i < internals_.length(); i++) {
stack_locals->Add(var, zone());
} else if (var->IsContextSlot()) {
context_locals->Add(var, zone());
+ } else if (var->IsGlobalSlot()) {
+ context_globals->Add(var, zone());
}
}
}
for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
if (scope->is_eval_scope()) return false;
if (scope->scope_inside_with_) return false;
- if (scope->num_heap_slots_ > 0) return false;
+ if (scope->ContextLocalCount() > 0) return false;
}
return true;
}
static void PrintLocation(Variable* var) {
switch (var->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::UNALLOCATED:
break;
- case Variable::PARAMETER:
+ case VariableLocation::PARAMETER:
PrintF("parameter[%d]", var->index());
break;
- case Variable::LOCAL:
+ case VariableLocation::LOCAL:
PrintF("local[%d]", var->index());
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
PrintF("context[%d]", var->index());
break;
- case Variable::LOOKUP:
+ case VariableLocation::GLOBAL:
+ PrintF("global[%d]", var->index());
+ break;
+ case VariableLocation::LOOKUP:
PrintF("lookup");
break;
}
static void PrintMap(int indent, VariableMap* map) {
for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
Variable* var = reinterpret_cast<Variable*>(p->value);
- PrintVar(indent, var);
+ if (var == NULL) {
+ Indent(indent, "<?>\n");
+ } else {
+ PrintVar(indent, var);
+ }
}
}
Indent(n1, "// outer scope calls 'eval' in sloppy context\n");
}
if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
- if (num_stack_slots_ > 0) { Indent(n1, "// ");
- PrintF("%d stack slots\n", num_stack_slots_); }
- if (num_heap_slots_ > 0) { Indent(n1, "// ");
- PrintF("%d heap slots\n", num_heap_slots_); }
+ if (num_stack_slots_ > 0) {
+ Indent(n1, "// ");
+ PrintF("%d stack slots\n", num_stack_slots_);
+ }
+ if (num_heap_slots_ > 0) {
+ Indent(n1, "// ");
+ PrintF("%d heap slots (including %d global slots)\n", num_heap_slots_,
+ num_global_slots_);
+ }
// Print locals.
if (function_ != NULL) {
Variable::NORMAL,
init_flag);
// Allocate it by giving it a dynamic lookup.
- var->AllocateTo(Variable::LOOKUP, -1);
+ var->AllocateTo(VariableLocation::LOOKUP, -1);
}
return var;
}
if (is_block_scope()) {
DeclarationScope()->AllocateStackSlot(var);
} else {
- var->AllocateTo(Variable::LOCAL, num_stack_slots_++);
+ var->AllocateTo(VariableLocation::LOCAL, num_stack_slots_++);
}
}
void Scope::AllocateHeapSlot(Variable* var) {
- var->AllocateTo(Variable::CONTEXT, num_heap_slots_++);
+ var->AllocateTo(VariableLocation::CONTEXT, num_heap_slots_++);
}
} else {
DCHECK(var->IsUnallocated() || var->IsParameter());
if (var->IsUnallocated()) {
- var->AllocateTo(Variable::PARAMETER, index);
+ var->AllocateTo(VariableLocation::PARAMETER, index);
}
}
+ } else {
+ DCHECK(!var->IsGlobalSlot());
}
}
}
-void Scope::AllocateNonParameterLocals(Isolate* isolate) {
+void Scope::AllocateDeclaredGlobal(Isolate* isolate, Variable* var) {
+ DCHECK(var->scope() == this);
+ DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
+ !var->IsStackLocal());
+ if (var->IsUnallocated() && var->IsStaticGlobalObjectProperty()) {
+ DCHECK_EQ(-1, var->index());
+ DCHECK(var->name()->IsString());
+ var->AllocateTo(VariableLocation::GLOBAL, num_heap_slots_);
+ num_global_slots_++;
+ // Each global variable occupies two slots in the context: for reads
+ // and writes.
+ num_heap_slots_ += 2;
+ }
+}
+
+
+void Scope::AllocateNonParameterLocalsAndDeclaredGlobals(Isolate* isolate) {
// All variables that have no rewrite yet are non-parameter locals.
for (int i = 0; i < temps_.length(); i++) {
AllocateNonParameterLocal(isolate, temps_[i]);
AllocateNonParameterLocal(isolate, vars[i].var());
}
+ if (enable_context_globals) {
+ for (int i = 0; i < var_count; i++) {
+ AllocateDeclaredGlobal(isolate, vars[i].var());
+ }
+ }
+
// For now, function_ must be allocated at the very end. If it gets
// allocated in the context, it must be the last slot in the context,
// because of the current ScopeInfo implementation (see
// Parameters must be allocated first, if any.
if (is_function_scope()) AllocateParameterLocals(isolate);
if (has_this_declaration()) AllocateReceiver();
- AllocateNonParameterLocals(isolate);
+ AllocateNonParameterLocalsAndDeclaredGlobals(isolate);
// Force allocation of a context for this scope if necessary. For a 'with'
// scope and for a function scope that makes an 'eval' call we need a context,
int Scope::ContextLocalCount() const {
if (num_heap_slots() == 0) return 0;
+ bool is_function_var_in_context =
+ function_ != NULL && function_->proxy()->var()->IsContextSlot();
return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
- (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0);
+ 2 * num_global_slots() - (is_function_var_in_context ? 1 : 0);
}
+
+
+int Scope::ContextGlobalCount() const { return num_global_slots(); }
} // namespace internal
} // namespace v8
// handled separately.
void CollectStackAndContextLocals(
ZoneList<Variable*>* stack_locals, ZoneList<Variable*>* context_locals,
+ ZoneList<Variable*>* context_globals,
ZoneList<Variable*>* strong_mode_free_variables = nullptr);
// Current number of var or const locals.
// Result of variable allocation.
int num_stack_slots() const { return num_stack_slots_; }
int num_heap_slots() const { return num_heap_slots_; }
+ int num_global_slots() const { return num_global_slots_; }
int StackLocalCount() const;
int ContextLocalCount() const;
+ int ContextGlobalCount() const;
// For script scopes, the number of module literals (including nested ones).
int num_modules() const { return num_modules_; }
// Computed via AllocateVariables; function, block and catch scopes only.
int num_stack_slots_;
int num_heap_slots_;
+ int num_global_slots_;
// The number of modules (including nested ones).
int num_modules_;
void AllocateHeapSlot(Variable* var);
void AllocateParameterLocals(Isolate* isolate);
void AllocateNonParameterLocal(Isolate* isolate, Variable* var);
- void AllocateNonParameterLocals(Isolate* isolate);
+ void AllocateDeclaredGlobal(Isolate* isolate, Variable* var);
+ void AllocateNonParameterLocalsAndDeclaredGlobals(Isolate* isolate);
void AllocateVariablesRecursively(Isolate* isolate);
void AllocateParameter(Variable* var, int index);
void AllocateReceiver();
ZoneList<Variable*> local_vars(locals, zone());
ZoneList<Variable*> context_vars(scope->ContextLocalCount(), zone());
- scope->CollectStackAndContextLocals(&local_vars, &context_vars);
+ ZoneList<Variable*> global_vars(scope->ContextGlobalCount(), zone());
+ scope->CollectStackAndContextLocals(&local_vars, &context_vars,
+ &global_vars);
for (int i = 0; i < locals; i++) {
PrintObserved(local_vars.at(i),
frame->GetExpression(i),
name_(name),
mode_(mode),
kind_(kind),
- location_(UNALLOCATED),
+ location_(VariableLocation::UNALLOCATED),
index_(-1),
initializer_position_(RelocInfo::kNoPosition),
has_strong_mode_reference_(false),
bool Variable::IsGlobalObjectProperty() const {
// Temporaries are never global, they must always be allocated in the
// activation frame.
- return (IsDynamicVariableMode(mode_) ||
- (IsDeclaredVariableMode(mode_) && !IsLexicalVariableMode(mode_))) &&
+ return IsDynamicVariableMode(mode_) || IsStaticGlobalObjectProperty();
+}
+
+
+bool Variable::IsStaticGlobalObjectProperty() const {
+ // Temporaries are never global, they must always be allocated in the
+ // activation frame.
+ return (IsDeclaredVariableMode(mode_) && !IsLexicalVariableMode(mode_)) &&
scope_ != NULL && scope_->is_script_scope() && !is_this();
}
public:
enum Kind { NORMAL, FUNCTION, CLASS, THIS, ARGUMENTS };
- enum Location {
- // Before and during variable allocation, a variable whose location is
- // not yet determined. After allocation, a variable looked up as a
- // property on the global object (and possibly absent). name() is the
- // variable name, index() is invalid.
- UNALLOCATED,
-
- // A slot in the parameter section on the stack. index() is the
- // parameter index, counting left-to-right. The receiver is index -1;
- // the first parameter is index 0.
- PARAMETER,
-
- // A slot in the local section on the stack. index() is the variable
- // index in the stack frame, starting at 0.
- LOCAL,
-
- // An indexed slot in a heap context. index() is the variable index in
- // the context object on the heap, starting at 0. scope() is the
- // corresponding scope.
- CONTEXT,
-
- // A named slot in a heap context. name() is the variable name in the
- // context object on the heap, with lookup starting at the current
- // context. index() is invalid.
- LOOKUP
- };
-
Variable(Scope* scope, const AstRawString* name, VariableMode mode, Kind kind,
InitializationFlag initialization_flag,
MaybeAssignedFlag maybe_assigned_flag = kNotAssigned);
return !is_this() && name().is_identical_to(n);
}
- bool IsUnallocated() const { return location_ == UNALLOCATED; }
- bool IsParameter() const { return location_ == PARAMETER; }
- bool IsStackLocal() const { return location_ == LOCAL; }
+ bool IsUnallocated() const {
+ return location_ == VariableLocation::UNALLOCATED;
+ }
+ bool IsParameter() const { return location_ == VariableLocation::PARAMETER; }
+ bool IsStackLocal() const { return location_ == VariableLocation::LOCAL; }
bool IsStackAllocated() const { return IsParameter() || IsStackLocal(); }
- bool IsContextSlot() const { return location_ == CONTEXT; }
- bool IsLookupSlot() const { return location_ == LOOKUP; }
+ bool IsContextSlot() const { return location_ == VariableLocation::CONTEXT; }
+ bool IsGlobalSlot() const { return location_ == VariableLocation::GLOBAL; }
+ bool IsUnallocatedOrGlobalSlot() const {
+ return IsUnallocated() || IsGlobalSlot();
+ }
+ bool IsLookupSlot() const { return location_ == VariableLocation::LOOKUP; }
bool IsGlobalObjectProperty() const;
+ bool IsStaticGlobalObjectProperty() const;
bool is_dynamic() const { return IsDynamicVariableMode(mode_); }
bool is_const_mode() const { return IsImmutableVariableMode(mode_); }
local_if_not_shadowed_ = local;
}
- Location location() const { return location_; }
+ VariableLocation location() const { return location_; }
int index() const { return index_; }
InitializationFlag initialization_flag() const {
return initialization_flag_;
}
- void AllocateTo(Location location, int index) {
+ void AllocateTo(VariableLocation location, int index) {
location_ = location;
index_ = index;
}
const AstRawString* name_;
VariableMode mode_;
Kind kind_;
- Location location_;
+ VariableLocation location_;
int index_;
int initializer_position_;
// Tracks whether the variable is bound to a VariableProxy which is in strong
VariableDeclaration* function = scope()->function();
DCHECK(function->proxy()->var()->mode() == CONST ||
function->proxy()->var()->mode() == CONST_LEGACY);
- DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ DCHECK(!function->proxy()->var()->IsUnallocatedOrGlobalSlot());
VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
Variable* variable = proxy->var();
bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
globals_->Add(variable->name(), zone());
globals_->Add(variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
zone());
break;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
}
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
EmitDebugCheckDeclarationContext(variable);
}
break;
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ VariableDeclaration");
__ Push(rsi);
__ Push(variable->name());
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
globals_->Add(variable->name(), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
Comment cmnt(masm_, "[ FunctionDeclaration");
VisitForAccumulatorValue(declaration->fun());
__ movp(StackOperand(variable), result_register());
break;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ FunctionDeclaration");
EmitDebugCheckDeclarationContext(variable);
VisitForAccumulatorValue(declaration->fun());
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ FunctionDeclaration");
__ Push(rsi);
__ Push(variable->name());
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::UNALLOCATED:
+ case VariableLocation::GLOBAL:
// TODO(rossberg)
break;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ ImportDeclaration");
EmitDebugCheckDeclarationContext(variable);
// TODO(rossberg)
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::LOOKUP:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::LOOKUP:
UNREACHABLE();
}
}
// Three cases: global variables, lookup variables, and all other types of
// variables.
switch (var->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
Comment cmnt(masm_, "[ Global variable");
__ Move(LoadDescriptor::NameRegister(), var->name());
__ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::CONTEXT: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot"
: "[ Stack slot");
if (var->binding_needs_init()) {
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ Lookup slot");
Label done, slow;
// Generate code for loading from variables potentially shadowed
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
// Global var, const, or let.
__ Move(StoreDescriptor::NameRegister(), var->name());
__ movp(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
// "delete this" is allowed.
bool is_this = var->HasThisName(isolate());
DCHECK(is_sloppy(language_mode()) || is_this);
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
__ Push(GlobalObjectOperand());
__ Push(var->name());
__ Push(Smi::FromInt(SLOPPY));
DCHECK(!context()->IsEffect());
DCHECK(!context()->IsTest());
- if (proxy != NULL && proxy->var()->IsUnallocated()) {
+ if (proxy != NULL && proxy->var()->IsUnallocatedOrGlobalSlot()) {
Comment cmnt(masm_, "[ Global variable");
__ Move(LoadDescriptor::NameRegister(), proxy->name());
__ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
VariableDeclaration* function = scope()->function();
DCHECK(function->proxy()->var()->mode() == CONST ||
function->proxy()->var()->mode() == CONST_LEGACY);
- DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
+ DCHECK(!function->proxy()->var()->IsUnallocatedOrGlobalSlot());
VisitVariableDeclaration(function);
}
VisitDeclarations(scope()->declarations());
Variable* variable = proxy->var();
bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
globals_->Add(variable->name(), zone());
globals_->Add(variable->binding_needs_init()
? isolate()->factory()->the_hole_value()
: isolate()->factory()->undefined_value(), zone());
break;
- case Variable::PARAMETER:
- case Variable::LOCAL:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
__ mov(StackOperand(variable),
}
break;
- case Variable::CONTEXT:
+ case VariableLocation::CONTEXT:
if (hole_init) {
Comment cmnt(masm_, "[ VariableDeclaration");
EmitDebugCheckDeclarationContext(variable);
}
break;
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ VariableDeclaration");
__ push(esi);
__ push(Immediate(variable->name()));
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
globals_->Add(variable->name(), zone());
Handle<SharedFunctionInfo> function =
Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL: {
Comment cmnt(masm_, "[ FunctionDeclaration");
VisitForAccumulatorValue(declaration->fun());
__ mov(StackOperand(variable), result_register());
break;
}
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ FunctionDeclaration");
EmitDebugCheckDeclarationContext(variable);
VisitForAccumulatorValue(declaration->fun());
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ FunctionDeclaration");
__ push(esi);
__ push(Immediate(variable->name()));
VariableProxy* proxy = declaration->proxy();
Variable* variable = proxy->var();
switch (variable->location()) {
- case Variable::UNALLOCATED:
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED:
// TODO(rossberg)
break;
- case Variable::CONTEXT: {
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, "[ ImportDeclaration");
EmitDebugCheckDeclarationContext(variable);
// TODO(rossberg)
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::LOOKUP:
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::LOOKUP:
UNREACHABLE();
}
}
// Three cases: global variables, lookup variables, and all other types of
// variables.
switch (var->location()) {
- case Variable::UNALLOCATED: {
+ case VariableLocation::GLOBAL:
+ case VariableLocation::UNALLOCATED: {
Comment cmnt(masm_, "[ Global variable");
__ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
__ mov(LoadDescriptor::NameRegister(), var->name());
break;
}
- case Variable::PARAMETER:
- case Variable::LOCAL:
- case Variable::CONTEXT: {
+ case VariableLocation::PARAMETER:
+ case VariableLocation::LOCAL:
+ case VariableLocation::CONTEXT: {
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable");
if (var->binding_needs_init()) {
break;
}
- case Variable::LOOKUP: {
+ case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ Lookup variable");
Label done, slow;
// Generate code for loading from variables potentially shadowed
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
// Global var, const, or let.
__ mov(StoreDescriptor::NameRegister(), var->name());
__ mov(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
// "delete this" is allowed.
bool is_this = var->HasThisName(isolate());
DCHECK(is_sloppy(language_mode()) || is_this);
- if (var->IsUnallocated()) {
+ if (var->IsUnallocatedOrGlobalSlot()) {
__ push(GlobalObjectOperand());
__ push(Immediate(var->name()));
__ push(Immediate(Smi::FromInt(SLOPPY)));
DCHECK(!context()->IsEffect());
DCHECK(!context()->IsTest());
- if (proxy != NULL && proxy->var()->IsUnallocated()) {
+ if (proxy != NULL && proxy->var()->IsUnallocatedOrGlobalSlot()) {
Comment cmnt(masm_, "[ Global variable");
__ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
__ mov(LoadDescriptor::NameRegister(), Immediate(proxy->name()));
i::Variable* var = scope->Lookup(name);
CHECK(var);
- if (var->location() == Variable::UNALLOCATED) {
+ if (var->location() == VariableLocation::UNALLOCATED) {
CHECK_EQ(0, expected);
} else {
CHECK(var->IsStackAllocated());
// Function f has 3 LoadICs, one for each o, but the ICs share the same
// feedback vector IC slot.
CompileRun(
- "var o = 10;"
+ "o = 10;"
"function f() {"
" var x = o + 10;"
" return o + x + o;"
// Locations in the type feedback vector where call counts are maintained for
// the two calls made from bar();
-const kFooCallExtraIndex = 5;
-const kArrayCallExtraIndex = 9;
-
-function GetCallCount(func, slot) {
- var vector = %GetTypeFeedbackVector(func);
- // Call counts are recorded doubled.
- var value = %FixedArrayGet(vector, slot);
- return Math.floor(value / 2);
-}
-
-function foo(a) { return a[3] * 16; }
-
-function bar(a) {
- var result = 0;
- for (var i = 0; i < 10; i++) {
- result = foo(a);
- if (i % 2 === 0) {
- var r = Array();
- r[0] = 1;
- result += r[0];
+
+(function() {
+ const kFooCallExtraIndex = 5;
+ const kArrayCallExtraIndex = 7;
+
+ function GetCallCount(func, slot) {
+ var vector = %GetTypeFeedbackVector(func);
+ // Call counts are recorded doubled.
+ var value = %FixedArrayGet(vector, slot);
+ return Math.floor(value / 2);
+ }
+
+ function foo(a) { return a[3] * 16; }
+
+ function bar(a) {
+ var result = 0;
+ for (var i = 0; i < 10; i++) {
+ result = foo(a);
+ if (i % 2 === 0) {
+ var r = Array();
+ r[0] = 1;
+ result += r[0];
+ }
}
+ return result;
}
- return result;
-}
-var a = [1, 2, 3];
-bar(a);
-assertEquals(10, GetCallCount(bar, kFooCallExtraIndex));
-assertEquals(5, GetCallCount(bar, kArrayCallExtraIndex));
+ var a = [1, 2, 3];
+ bar(a);
+ assertEquals(10, GetCallCount(bar, kFooCallExtraIndex));
+ assertEquals(5, GetCallCount(bar, kArrayCallExtraIndex));
-%OptimizeFunctionOnNextCall(bar);
-bar(a);
+ %OptimizeFunctionOnNextCall(bar);
+ bar(a);
+})();