Variable* var = proxy->var();
DCHECK(var->IsUnallocatedOrGlobalSlot() ||
(var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
- __ ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
- __ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
- __ mov(LoadDescriptor::SlotRegister(),
- Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
- // Inside typeof use a regular load, not a contextual load, to avoid
- // a reference error.
- CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ if (var->IsGlobalSlot()) {
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index();
+ int depth = scope()->ContextChainLength(var->scope());
+ __ mov(LoadGlobalViaContextDescriptor::DepthRegister(),
+ Operand(Smi::FromInt(depth)));
+ __ mov(LoadGlobalViaContextDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(slot_index)));
+ __ mov(LoadGlobalViaContextDescriptor::NameRegister(),
+ Operand(var->name()));
+ LoadGlobalViaContextStub stub(isolate(), depth);
+ __ CallStub(&stub);
+
+ } else {
+ __ ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+ __ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
+ __ mov(LoadDescriptor::SlotRegister(),
+ Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+ // Inside typeof use a regular load, not a contextual load, to avoid
+ // a reference error.
+ CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ }
}
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocatedOrGlobalSlot()) {
+ if (var->IsUnallocated()) {
// Global var, const, or let.
__ mov(StoreDescriptor::NameRegister(), Operand(var->name()));
__ ldr(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
CallStoreIC();
+ } else if (var->IsGlobalSlot()) {
+ // Global var, const, or let.
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index() + 1;
+ int depth = scope()->ContextChainLength(var->scope());
+ __ mov(StoreGlobalViaContextDescriptor::DepthRegister(),
+ Operand(Smi::FromInt(depth)));
+ __ mov(StoreGlobalViaContextDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(slot_index)));
+ __ mov(StoreGlobalViaContextDescriptor::NameRegister(),
+ Operand(var->name()));
+ DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(r0));
+ StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+ __ CallStub(&stub);
+
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
const Register StoreTransitionDescriptor::MapRegister() { return r3; }
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return r1; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return r2; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return r3; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return r1; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return r2; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return r3; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return r0; }
+
+
const Register ElementTransitionAndStoreDescriptor::MapRegister() { return r3; }
Variable* var = proxy->var();
DCHECK(var->IsUnallocatedOrGlobalSlot() ||
(var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
- __ Ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
- __ Mov(LoadDescriptor::NameRegister(), Operand(var->name()));
- __ Mov(LoadDescriptor::SlotRegister(),
- SmiFromSlot(proxy->VariableFeedbackSlot()));
- // Inside typeof use a regular load, not a contextual load, to avoid
- // a reference error.
- CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ if (var->IsGlobalSlot()) {
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index();
+ int depth = scope()->ContextChainLength(var->scope());
+ __ Mov(LoadGlobalViaContextDescriptor::DepthRegister(),
+ Operand(Smi::FromInt(depth)));
+ __ Mov(LoadGlobalViaContextDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(slot_index)));
+ __ Mov(LoadGlobalViaContextDescriptor::NameRegister(),
+ Operand(var->name()));
+ LoadGlobalViaContextStub stub(isolate(), depth);
+ __ CallStub(&stub);
+
+ } else {
+ __ Ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
+ __ Mov(LoadDescriptor::NameRegister(), Operand(var->name()));
+ __ Mov(LoadDescriptor::SlotRegister(),
+ SmiFromSlot(proxy->VariableFeedbackSlot()));
+ // Inside typeof use a regular load, not a contextual load, to avoid
+ // a reference error.
+ CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ }
}
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
ASM_LOCATION("FullCodeGenerator::EmitVariableAssignment");
- if (var->IsUnallocatedOrGlobalSlot()) {
+ if (var->IsUnallocated()) {
// Global var, const, or let.
__ Mov(StoreDescriptor::NameRegister(), Operand(var->name()));
__ Ldr(StoreDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
CallStoreIC();
+ } else if (var->IsGlobalSlot()) {
+ // Global var, const, or let.
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index() + 1;
+ int depth = scope()->ContextChainLength(var->scope());
+ __ Mov(StoreGlobalViaContextDescriptor::DepthRegister(),
+ Operand(Smi::FromInt(depth)));
+ __ Mov(StoreGlobalViaContextDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(slot_index)));
+ __ Mov(StoreGlobalViaContextDescriptor::NameRegister(),
+ Operand(var->name()));
+ DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(x0));
+ StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+ __ CallStub(&stub);
+
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
const Register StoreTransitionDescriptor::MapRegister() { return x3; }
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return x1; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return x2; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return x3; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return x1; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return x2; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return x3; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return x0; }
+
+
const Register ElementTransitionAndStoreDescriptor::MapRegister() { return x3; }
void VariableProxy::SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
ICSlotCache* cache) {
variable_feedback_slot_ = slot;
- if (var()->IsUnallocatedOrGlobalSlot()) {
+ if (var()->IsUnallocated()) {
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()->IsUnallocatedOrGlobalSlot()) {
+ if (var()->IsUnallocated()) {
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()->IsUnallocatedOrGlobalSlot()) ||
+ expr->AsVariableProxy()->var()->IsUnallocated()) ||
assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) {
ic_slots++;
}
if (FunctionLiteral::NeedsHomeObject(value)) ic_slots++;
}
- if (scope() != NULL &&
- class_variable_proxy()->var()->IsUnallocatedOrGlobalSlot()) {
+ if (scope() != NULL && class_variable_proxy()->var()->IsUnallocated()) {
ic_slots++;
}
void BindTo(Variable* var);
bool UsesVariableFeedbackSlot() const {
- return var()->IsUnallocatedOrGlobalSlot() || var()->IsLookupSlot();
+ return var()->IsUnallocated() || var()->IsLookupSlot();
}
virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
}
+// static
+Callable CodeFactory::LoadGlobalViaContext(Isolate* isolate, int depth) {
+ LoadGlobalViaContextStub stub(isolate, depth);
+ return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
+}
+
+
+// static
+Callable CodeFactory::StoreGlobalViaContext(Isolate* isolate, int depth,
+ LanguageMode language_mode) {
+ StoreGlobalViaContextStub stub(isolate, depth, language_mode);
+ return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
+}
+
+
// static
Callable CodeFactory::Instanceof(Isolate* isolate,
InstanceofStub::Flags flags) {
// Code stubs. Add methods here as needed to reduce dependency on
// code-stubs.h.
+ static Callable LoadGlobalViaContext(Isolate* isolate, int depth);
+ static Callable StoreGlobalViaContext(Isolate* isolate, int depth,
+ LanguageMode language_mode);
+
static Callable Instanceof(Isolate* isolate, InstanceofStub::Flags flags);
static Callable ToBoolean(
}
-template<>
+template <>
+HValue* CodeStubGraphBuilder<LoadGlobalViaContextStub>::BuildCodeStub() {
+ LoadGlobalViaContextStub* stub = casted_stub();
+ int depth_value = stub->depth();
+ HValue* depth = GetParameter(0);
+ HValue* slot_index = GetParameter(1);
+ HValue* name = GetParameter(2);
+
+ // Choose between dynamic or static context script fetching versions.
+ depth = depth_value < LoadGlobalViaContextStub::kDynamicDepth
+ ? nullptr
+ : AddUncasted<HForceRepresentation>(depth, Representation::Smi());
+ slot_index =
+ AddUncasted<HForceRepresentation>(slot_index, Representation::Smi());
+
+ HValue* script_context = BuildGetParentContext(depth, depth_value);
+ HValue* cell =
+ Add<HLoadKeyed>(script_context, slot_index, nullptr, FAST_ELEMENTS);
+
+ HValue* value = Add<HLoadNamedField>(cell, nullptr,
+ HObjectAccess::ForPropertyCellValue());
+
+ IfBuilder builder(this);
+ HValue* hole_value = graph()->GetConstantHole();
+ builder.IfNot<HCompareObjectEqAndBranch, HValue*>(value, hole_value);
+ builder.Then();
+ { Push(value); }
+ builder.Else();
+ {
+ Add<HPushArguments>(script_context, slot_index, name);
+ Push(Add<HCallRuntime>(
+ isolate()->factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kLoadGlobalViaContext), 3));
+ }
+ builder.End();
+ return Pop();
+}
+
+
+Handle<Code> LoadGlobalViaContextStub::GenerateCode() {
+ return DoGenerateCode(this);
+}
+
+
+template <>
+HValue* CodeStubGraphBuilder<StoreGlobalViaContextStub>::BuildCodeStub() {
+ StoreGlobalViaContextStub* stub = casted_stub();
+ int depth_value = stub->depth();
+ HValue* depth = GetParameter(0);
+ HValue* slot_index = GetParameter(1);
+ HValue* name = GetParameter(2);
+ HValue* value = GetParameter(3);
+
+ // Choose between dynamic or static context script fetching versions.
+ depth = depth_value < StoreGlobalViaContextStub::kDynamicDepth
+ ? nullptr
+ : AddUncasted<HForceRepresentation>(depth, Representation::Smi());
+ slot_index =
+ AddUncasted<HForceRepresentation>(slot_index, Representation::Smi());
+
+ HValue* script_context = BuildGetParentContext(depth, depth_value);
+ HValue* cell =
+ Add<HLoadKeyed>(script_context, slot_index, nullptr, FAST_ELEMENTS);
+
+ // Fast case that requires storing to cell.
+ HIfContinuation if_fast_store_continuation(graph()->CreateBasicBlock(),
+ graph()->CreateBasicBlock());
+
+ // Fast case that does not require storing to cell.
+ HIfContinuation if_fast_no_store_continuation(graph()->CreateBasicBlock(),
+ graph()->CreateBasicBlock());
+
+ // This stub does the same as StoreGlobalStub but in a dynamic manner.
+
+ HValue* cell_contents = Add<HLoadNamedField>(
+ cell, nullptr, HObjectAccess::ForPropertyCellValue());
+
+ IfBuilder if_hole(this);
+ HValue* hole_value = graph()->GetConstantHole();
+ if_hole.IfNot<HCompareObjectEqAndBranch, HValue*>(cell_contents, hole_value);
+ if_hole.Then();
+ {
+ HValue* details = Add<HLoadNamedField>(
+ cell, nullptr, HObjectAccess::ForPropertyCellDetails());
+ HValue* cell_type =
+ BuildDecodeField<PropertyDetails::PropertyCellTypeField>(details);
+
+ // The code below relies on this.
+ STATIC_ASSERT(PropertyCellType::kUndefined < PropertyCellType::kConstant);
+ STATIC_ASSERT(PropertyCellType::kConstant <
+ PropertyCellType::kConstantType);
+ STATIC_ASSERT(PropertyCellType::kConstant < PropertyCellType::kMutable);
+
+ // Handle all cell type cases.
+ IfBuilder if_not_const(this);
+
+ int cell_type_constant = static_cast<int>(PropertyCellType::kConstant);
+ if_not_const.If<HCompareNumericAndBranch, HValue*>(
+ cell_type, Add<HConstant>(cell_type_constant), Token::GT);
+ if_not_const.Then();
+ {
+ // kConstantType or kMutable.
+ IfBuilder if_const_type(this);
+ int cell_type_constant_type =
+ static_cast<int>(PropertyCellType::kConstantType);
+ if_const_type.If<HCompareNumericAndBranch, HValue*>(
+ cell_type, Add<HConstant>(cell_type_constant_type), Token::EQ);
+ if_const_type.Then();
+ {
+ // Check that either both value and cell_contents are smi or
+ // both have the same map.
+ IfBuilder if_cell_is_smi(this);
+ if_cell_is_smi.If<HIsSmiAndBranch>(cell_contents);
+ if_cell_is_smi.Then();
+ {
+ IfBuilder if_value_is_smi(this);
+ if_value_is_smi.If<HIsSmiAndBranch>(value);
+ if_value_is_smi.Then();
+ {
+ // Both cell_contents and value are smis, do store.
+ }
+ if_value_is_smi.Else(); // Slow case.
+ if_value_is_smi.JoinContinuation(&if_fast_store_continuation);
+ }
+ if_cell_is_smi.Else();
+ {
+ IfBuilder if_value_is_heap_object(this);
+ if_value_is_heap_object.IfNot<HIsSmiAndBranch>(value);
+ if_value_is_heap_object.Then();
+ {
+ // Both cell_contents and value are heap objects, do store.
+ HValue* expected_map = Add<HLoadNamedField>(
+ cell_contents, nullptr, HObjectAccess::ForMap());
+ HValue* map =
+ Add<HLoadNamedField>(value, nullptr, HObjectAccess::ForMap());
+ IfBuilder map_check(this);
+ map_check.If<HCompareObjectEqAndBranch>(expected_map, map);
+ map_check.Then();
+ map_check.Else(); // Slow case.
+ map_check.JoinContinuation(&if_fast_store_continuation);
+
+ // The accessor case is handled by the map check above, since
+ // the value must not have a AccessorPair map.
+ }
+ if_value_is_heap_object.Else(); // Slow case.
+ if_value_is_heap_object.JoinContinuation(&if_fast_store_continuation);
+ }
+ if_cell_is_smi.EndUnreachable();
+ }
+ if_const_type.Else();
+ {
+ // Check that the property kind is kData.
+ HValue* kind = BuildDecodeField<PropertyDetails::KindField>(details);
+ HValue* data_kind_value = Add<HConstant>(kData);
+
+ IfBuilder builder(this);
+ builder.If<HCompareNumericAndBranch, HValue*>(kind, data_kind_value,
+ Token::EQ);
+ builder.Then();
+ builder.Else(); // Slow case.
+ builder.JoinContinuation(&if_fast_store_continuation);
+ }
+ if_const_type.EndUnreachable();
+ }
+ if_not_const.Else();
+ {
+ // kUndefined or kConstant, just check that the value matches.
+ IfBuilder builder(this);
+ builder.If<HCompareObjectEqAndBranch>(cell_contents, value);
+ builder.Then();
+ builder.Else(); // Slow case.
+ builder.JoinContinuation(&if_fast_no_store_continuation);
+ }
+ if_not_const.EndUnreachable();
+ }
+ if_hole.Else(); // Slow case.
+ if_hole.JoinContinuation(&if_fast_store_continuation);
+
+ // Do store for fast case.
+ IfBuilder if_fast_store(this, &if_fast_store_continuation);
+ if_fast_store.Then();
+ {
+ // All checks are done, store the value to the cell.
+ Add<HStoreNamedField>(cell, HObjectAccess::ForPropertyCellValue(), value);
+ }
+ if_fast_store.Else();
+ if_fast_store.JoinContinuation(&if_fast_no_store_continuation);
+
+ // Bailout to runtime call for slow case.
+ IfBuilder if_no_fast_store(this, &if_fast_no_store_continuation);
+ if_no_fast_store.Then();
+ {
+ // Nothing else to do.
+ }
+ if_no_fast_store.Else();
+ {
+ // Slow case, call runtime.
+ HInstruction* lang_mode = Add<HConstant>(casted_stub()->language_mode());
+ Add<HPushArguments>(script_context, slot_index, name, value);
+ Add<HPushArguments>(lang_mode);
+ Add<HCallRuntime>(isolate()->factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kStoreGlobalViaContext),
+ 5);
+ }
+ if_no_fast_store.End();
+ return value;
+}
+
+
+Handle<Code> StoreGlobalViaContextStub::GenerateCode() {
+ return DoGenerateCode(this);
+}
+
+
+template <>
HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() {
HValue* value = GetParameter(ElementsTransitionAndStoreStub::kValueIndex);
HValue* map = GetParameter(ElementsTransitionAndStoreStub::kMapIndex);
namespace internal {
+RUNTIME_FUNCTION(UnexpectedStubMiss) {
+ FATAL("Unexpected deopt of a stub");
+ return Smi::FromInt(0);
+}
+
+
CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
: call_descriptor_(stub->GetCallInterfaceDescriptor()),
stack_parameter_count_(no_reg),
}
+void LoadGlobalViaContextStub::InitializeDescriptor(
+ CodeStubDescriptor* descriptor) {
+ // Must never deoptimize.
+ descriptor->Initialize(FUNCTION_ADDR(UnexpectedStubMiss));
+}
+
+
+void StoreGlobalViaContextStub::InitializeDescriptor(
+ CodeStubDescriptor* descriptor) {
+ // Must never deoptimize.
+ descriptor->Initialize(FUNCTION_ADDR(UnexpectedStubMiss));
+}
+
+
void TransitionElementsKindStub::InitializeDescriptor(
CodeStubDescriptor* descriptor) {
descriptor->Initialize(
V(InternalArrayNoArgumentConstructor) \
V(InternalArraySingleArgumentConstructor) \
V(KeyedLoadGeneric) \
+ V(LoadGlobalViaContext) \
V(LoadScriptContextField) \
V(LoadDictionaryElement) \
V(NameDictionaryLookup) \
V(Typeof) \
V(RegExpConstructResult) \
V(StoreFastElement) \
+ V(StoreGlobalViaContext) \
V(StoreScriptContextField) \
V(StringAdd) \
V(ToBoolean) \
};
+class LoadGlobalViaContextStub : public HydrogenCodeStub {
+ public:
+ // Use the loop version for depths higher than this one.
+ static const int kDynamicDepth = 7;
+
+ LoadGlobalViaContextStub(Isolate* isolate, int depth)
+ : HydrogenCodeStub(isolate) {
+ if (depth > kDynamicDepth) depth = kDynamicDepth;
+ set_sub_minor_key(DepthBits::encode(depth));
+ }
+
+ int depth() const { return DepthBits::decode(sub_minor_key()); }
+
+ private:
+ class DepthBits : public BitField<unsigned int, 0, 3> {};
+ STATIC_ASSERT(kDynamicDepth <= DepthBits::kMax);
+
+ DEFINE_CALL_INTERFACE_DESCRIPTOR(LoadGlobalViaContext);
+ DEFINE_HYDROGEN_CODE_STUB(LoadGlobalViaContext, HydrogenCodeStub);
+};
+
+
+class StoreGlobalViaContextStub : public HydrogenCodeStub {
+ public:
+ // Use the loop version for depths higher than this one.
+ static const int kDynamicDepth = 7;
+
+ StoreGlobalViaContextStub(Isolate* isolate, int depth,
+ LanguageMode language_mode)
+ : HydrogenCodeStub(isolate) {
+ if (depth > kDynamicDepth) depth = kDynamicDepth;
+ set_sub_minor_key(DepthBits::encode(depth) |
+ LanguageModeBits::encode(language_mode));
+ }
+
+ int depth() const { return DepthBits::decode(sub_minor_key()); }
+
+ LanguageMode language_mode() const {
+ return LanguageModeBits::decode(sub_minor_key());
+ }
+
+ private:
+ class DepthBits : public BitField<unsigned int, 0, 4> {};
+ STATIC_ASSERT(kDynamicDepth <= DepthBits::kMax);
+
+ class LanguageModeBits : public BitField<LanguageMode, 4, 2> {};
+ STATIC_ASSERT(LANGUAGE_END == 3);
+
+ private:
+ DEFINE_CALL_INTERFACE_DESCRIPTOR(StoreGlobalViaContext);
+ DEFINE_HYDROGEN_CODE_STUB(StoreGlobalViaContext, HydrogenCodeStub);
+};
+
+
class CallApiFunctionStub : public PlatformCodeStub {
public:
explicit CallApiFunctionStub(Isolate* isolate, bool call_data_undefined)
case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED: {
// Global var, const, or let variable.
+ Node* script_context = current_context();
+ int slot_index = -1;
+ if (variable->index() > 0) {
+ DCHECK(variable->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ slot_index = variable->index();
+ int depth = current_scope()->ContextChainLength(variable->scope());
+ if (depth > 0) {
+ const Operator* op = javascript()->LoadContext(
+ depth - 1, Context::PREVIOUS_INDEX, true);
+ script_context = NewNode(op, current_context());
+ }
+ }
Node* global = BuildLoadGlobalObject();
Handle<Name> name = variable->name();
- Node* value = BuildGlobalLoad(global, name, feedback, contextual_mode);
+ Node* value = BuildGlobalLoad(script_context, global, name, feedback,
+ contextual_mode, slot_index);
states.AddToNode(value, bailout_id, combine);
return value;
}
case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED: {
// Global var, const, or let variable.
+ Node* script_context = current_context();
+ int slot_index = -1;
+ if (variable->index() > 0) {
+ DCHECK(variable->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ slot_index = variable->index();
+ int depth = current_scope()->ContextChainLength(variable->scope());
+ if (depth > 0) {
+ const Operator* op = javascript()->LoadContext(
+ depth - 1, Context::PREVIOUS_INDEX, true);
+ script_context = NewNode(op, current_context());
+ }
+ }
Node* global = BuildLoadGlobalObject();
Handle<Name> name = variable->name();
- Node* store = BuildGlobalStore(global, name, value, feedback,
- TypeFeedbackId::None());
+ Node* store =
+ BuildGlobalStore(script_context, global, name, value, feedback,
+ TypeFeedbackId::None(), slot_index);
states.AddToNode(store, bailout_id, combine);
return store;
}
}
-Node* AstGraphBuilder::BuildGlobalLoad(Node* object, Handle<Name> name,
+Node* AstGraphBuilder::BuildGlobalLoad(Node* script_context, Node* global,
+ Handle<Name> name,
const VectorSlotPair& feedback,
- ContextualMode mode) {
+ ContextualMode mode, int slot_index) {
const Operator* op =
- javascript()->LoadGlobal(MakeUnique(name), feedback, mode);
- Node* node = NewNode(op, object, BuildLoadFeedbackVector());
+ javascript()->LoadGlobal(MakeUnique(name), feedback, mode, slot_index);
+ Node* node = NewNode(op, script_context, global, BuildLoadFeedbackVector());
return Record(js_type_feedback_, node, feedback.slot());
}
-Node* AstGraphBuilder::BuildGlobalStore(Node* object, Handle<Name> name,
- Node* value,
+Node* AstGraphBuilder::BuildGlobalStore(Node* script_context, Node* global,
+ Handle<Name> name, Node* value,
const VectorSlotPair& feedback,
- TypeFeedbackId id) {
- const Operator* op =
- javascript()->StoreGlobal(language_mode(), MakeUnique(name), feedback);
- Node* node = NewNode(op, object, value, BuildLoadFeedbackVector());
+ TypeFeedbackId id, int slot_index) {
+ const Operator* op = javascript()->StoreGlobal(
+ language_mode(), MakeUnique(name), feedback, slot_index);
+ Node* node =
+ NewNode(op, script_context, global, value, BuildLoadFeedbackVector());
if (FLAG_vector_stores) {
return Record(js_type_feedback_, node, feedback.slot());
}
Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
Node** value_inputs, bool incomplete) {
- DCHECK(op->ValueInputCount() == value_input_count);
+ DCHECK_EQ(op->ValueInputCount(), value_input_count);
bool has_context = OperatorProperties::HasContextInput(op);
int frame_state_count = OperatorProperties::GetFrameStateInputCount(op);
const VectorSlotPair& feedback);
// Builders for global variable loads and stores.
- Node* BuildGlobalLoad(Node* global, Handle<Name> name,
- const VectorSlotPair& feedback, ContextualMode mode);
- Node* BuildGlobalStore(Node* global, Handle<Name> name, Node* value,
- const VectorSlotPair& feedback, TypeFeedbackId id);
+ Node* BuildGlobalLoad(Node* script_context, Node* global, Handle<Name> name,
+ const VectorSlotPair& feedback, ContextualMode mode,
+ int slot_index);
+ Node* BuildGlobalStore(Node* script_context, Node* global, Handle<Name> name,
+ Node* value, const VectorSlotPair& feedback,
+ TypeFeedbackId id, int slot_index);
// Builders for accessing the function context.
Node* BuildLoadBuiltinsObject();
void JSGenericLowering::LowerJSLoadGlobal(Node* node) {
CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
- const LoadNamedParameters& p = LoadGlobalParametersOf(node->op());
- Callable callable = CodeFactory::LoadICInOptimizedCode(
- isolate(), p.contextual_mode(), SLOPPY, UNINITIALIZED);
- node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
- node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
- ReplaceWithStubCall(node, callable, flags);
+ const LoadGlobalParameters& p = LoadGlobalParametersOf(node->op());
+ if (p.slot_index() >= 0) {
+ Callable callable = CodeFactory::LoadGlobalViaContext(isolate(), 0);
+ Node* script_context = node->InputAt(0);
+ node->ReplaceInput(0, jsgraph()->SmiConstant(0));
+ node->ReplaceInput(1, jsgraph()->SmiConstant(p.slot_index()));
+ node->ReplaceInput(2, jsgraph()->HeapConstant(p.name()));
+ node->ReplaceInput(3, script_context); // Replace old context.
+ ReplaceWithStubCall(node, callable, flags);
+
+ } else {
+ Callable callable = CodeFactory::LoadICInOptimizedCode(
+ isolate(), p.contextual_mode(), SLOPPY, UNINITIALIZED);
+ node->RemoveInput(0); // script context
+ node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
+ node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index()));
+ ReplaceWithStubCall(node, callable, flags);
+ }
}
void JSGenericLowering::LowerJSStoreGlobal(Node* node) {
CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
- const StoreNamedParameters& p = StoreGlobalParametersOf(node->op());
- Callable callable = CodeFactory::StoreIC(isolate(), p.language_mode());
- node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
- if (FLAG_vector_stores) {
- DCHECK(p.feedback().index() != -1);
- node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.feedback().index()));
+ const StoreGlobalParameters& p = StoreGlobalParametersOf(node->op());
+ if (p.slot_index() >= 0) {
+ Callable callable =
+ CodeFactory::StoreGlobalViaContext(isolate(), 0, p.language_mode());
+ Node* script_context = node->InputAt(0);
+ Node* value = node->InputAt(2);
+ node->ReplaceInput(0, jsgraph()->SmiConstant(0));
+ node->ReplaceInput(1, jsgraph()->SmiConstant(p.slot_index()));
+ node->ReplaceInput(2, jsgraph()->HeapConstant(p.name()));
+ node->ReplaceInput(3, value);
+ node->ReplaceInput(4, script_context); // Replace old context.
+ ReplaceWithStubCall(node, callable, flags);
+
} else {
- node->RemoveInput(3);
+ Callable callable = CodeFactory::StoreIC(isolate(), p.language_mode());
+ node->RemoveInput(0); // script context
+ node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name()));
+ if (FLAG_vector_stores) {
+ DCHECK(p.feedback().index() != -1);
+ node->InsertInput(zone(), 3,
+ jsgraph()->SmiConstant(p.feedback().index()));
+ } else {
+ node->RemoveInput(3);
+ }
+ ReplaceWithStubCall(node, callable,
+ CallDescriptor::kPatchableCallSite | flags);
}
- ReplaceWithStubCall(node, callable,
- CallDescriptor::kPatchableCallSite | flags);
}
}
-const LoadNamedParameters& LoadGlobalParametersOf(const Operator* op) {
+bool operator==(LoadGlobalParameters const& lhs,
+ LoadGlobalParameters const& rhs) {
+ return lhs.name() == rhs.name() && lhs.feedback() == rhs.feedback() &&
+ lhs.contextual_mode() == rhs.contextual_mode() &&
+ lhs.slot_index() == rhs.slot_index();
+}
+
+
+bool operator!=(LoadGlobalParameters const& lhs,
+ LoadGlobalParameters const& rhs) {
+ return !(lhs == rhs);
+}
+
+
+size_t hash_value(LoadGlobalParameters const& p) {
+ return base::hash_combine(p.name(), p.contextual_mode(), p.slot_index());
+}
+
+
+std::ostream& operator<<(std::ostream& os, LoadGlobalParameters const& p) {
+ return os << Brief(*p.name().handle()) << ", " << p.contextual_mode()
+ << ", slot: " << p.slot_index();
+}
+
+
+const LoadGlobalParameters& LoadGlobalParametersOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kJSLoadGlobal, op->opcode());
- return OpParameter<LoadNamedParameters>(op);
+ return OpParameter<LoadGlobalParameters>(op);
+}
+
+
+bool operator==(StoreGlobalParameters const& lhs,
+ StoreGlobalParameters const& rhs) {
+ return lhs.language_mode() == rhs.language_mode() &&
+ lhs.name() == rhs.name() && lhs.feedback() == rhs.feedback() &&
+ lhs.slot_index() == rhs.slot_index();
+}
+
+
+bool operator!=(StoreGlobalParameters const& lhs,
+ StoreGlobalParameters const& rhs) {
+ return !(lhs == rhs);
+}
+
+
+size_t hash_value(StoreGlobalParameters const& p) {
+ return base::hash_combine(p.language_mode(), p.name(), p.feedback(),
+ p.slot_index());
+}
+
+
+std::ostream& operator<<(std::ostream& os, StoreGlobalParameters const& p) {
+ return os << p.language_mode() << ", " << Brief(*p.name().handle())
+ << ", slot: " << p.slot_index();
+}
+
+
+const StoreGlobalParameters& StoreGlobalParametersOf(const Operator* op) {
+ DCHECK_EQ(IrOpcode::kJSStoreGlobal, op->opcode());
+ return OpParameter<StoreGlobalParameters>(op);
}
}
-const StoreNamedParameters& StoreGlobalParametersOf(const Operator* op) {
- DCHECK_EQ(IrOpcode::kJSStoreGlobal, op->opcode());
- return OpParameter<StoreNamedParameters>(op);
-}
-
-
bool operator==(StorePropertyParameters const& lhs,
StorePropertyParameters const& rhs) {
return lhs.language_mode() == rhs.language_mode() &&
const Operator* JSOperatorBuilder::LoadGlobal(const Unique<Name>& name,
const VectorSlotPair& feedback,
- ContextualMode contextual_mode) {
- LoadNamedParameters parameters(name, feedback, SLOPPY, contextual_mode);
- return new (zone()) Operator1<LoadNamedParameters>( // --
+ ContextualMode contextual_mode,
+ int slot_index) {
+ LoadGlobalParameters parameters(name, feedback, contextual_mode, slot_index);
+ return new (zone()) Operator1<LoadGlobalParameters>( // --
IrOpcode::kJSLoadGlobal, Operator::kNoProperties, // opcode
"JSLoadGlobal", // name
- 2, 1, 1, 1, 1, 2, // counts
+ 3, 1, 1, 1, 1, 2, // counts
parameters); // parameter
}
const Operator* JSOperatorBuilder::StoreGlobal(LanguageMode language_mode,
const Unique<Name>& name,
- const VectorSlotPair& feedback) {
- StoreNamedParameters parameters(language_mode, feedback, name);
- return new (zone()) Operator1<StoreNamedParameters>( // --
+ const VectorSlotPair& feedback,
+ int slot_index) {
+ StoreGlobalParameters parameters(language_mode, feedback, name, slot_index);
+ return new (zone()) Operator1<StoreGlobalParameters>( // --
IrOpcode::kJSStoreGlobal, Operator::kNoProperties, // opcode
"JSStoreGlobal", // name
- 3, 1, 1, 0, 1, 2, // counts
+ 4, 1, 1, 0, 1, 2, // counts
parameters); // parameter
}
// Defines the property being loaded from an object by a named load. This is
-// used as a parameter by JSLoadNamed and JSLoadGlobal operators.
+// used as a parameter by JSLoadNamed operators.
class LoadNamedParameters final {
public:
LoadNamedParameters(const Unique<Name>& name, const VectorSlotPair& feedback,
const LoadNamedParameters& LoadNamedParametersOf(const Operator* op);
-const LoadNamedParameters& LoadGlobalParametersOf(const Operator* op);
+
+// Defines the property being loaded from an object by a named load. This is
+// used as a parameter by JSLoadGlobal operator.
+class LoadGlobalParameters final {
+ public:
+ LoadGlobalParameters(const Unique<Name>& name, const VectorSlotPair& feedback,
+ ContextualMode contextual_mode, int slot_index)
+ : name_(name),
+ feedback_(feedback),
+ contextual_mode_(contextual_mode),
+ slot_index_(slot_index) {}
+
+ const Unique<Name>& name() const { return name_; }
+ ContextualMode contextual_mode() const { return contextual_mode_; }
+
+ const VectorSlotPair& feedback() const { return feedback_; }
+
+ const int slot_index() const { return slot_index_; }
+
+ private:
+ const Unique<Name> name_;
+ const VectorSlotPair feedback_;
+ const ContextualMode contextual_mode_;
+ const int slot_index_;
+};
+
+bool operator==(LoadGlobalParameters const&, LoadGlobalParameters const&);
+bool operator!=(LoadGlobalParameters const&, LoadGlobalParameters const&);
+
+size_t hash_value(LoadGlobalParameters const&);
+
+std::ostream& operator<<(std::ostream&, LoadGlobalParameters const&);
+
+const LoadGlobalParameters& LoadGlobalParametersOf(const Operator* op);
+
+
+// Defines the property being stored to an object by a named store. This is
+// used as a parameter by JSStoreGlobal operator.
+class StoreGlobalParameters final {
+ public:
+ StoreGlobalParameters(LanguageMode language_mode,
+ const VectorSlotPair& feedback,
+ const Unique<Name>& name, int slot_index)
+ : language_mode_(language_mode),
+ name_(name),
+ feedback_(feedback),
+ slot_index_(slot_index) {}
+
+ LanguageMode language_mode() const { return language_mode_; }
+ const VectorSlotPair& feedback() const { return feedback_; }
+ const Unique<Name>& name() const { return name_; }
+ int slot_index() const { return slot_index_; }
+
+ private:
+ const LanguageMode language_mode_;
+ const Unique<Name> name_;
+ const VectorSlotPair feedback_;
+ int slot_index_;
+};
+
+bool operator==(StoreGlobalParameters const&, StoreGlobalParameters const&);
+bool operator!=(StoreGlobalParameters const&, StoreGlobalParameters const&);
+
+size_t hash_value(StoreGlobalParameters const&);
+
+std::ostream& operator<<(std::ostream&, StoreGlobalParameters const&);
+
+const StoreGlobalParameters& StoreGlobalParametersOf(const Operator* op);
// Defines the property being loaded from an object. This is
// Defines the property being stored to an object by a named store. This is
-// used as a parameter by JSStoreNamed and JSStoreGlobal operators.
+// used as a parameter by JSStoreNamed operator.
class StoreNamedParameters final {
public:
StoreNamedParameters(LanguageMode language_mode,
const StoreNamedParameters& StoreNamedParametersOf(const Operator* op);
-const StoreNamedParameters& StoreGlobalParametersOf(const Operator* op);
-
// Defines the property being stored to an object. This is used as a parameter
// by JSStoreProperty operators.
const Operator* LoadGlobal(const Unique<Name>& name,
const VectorSlotPair& feedback,
- ContextualMode contextual_mode = NOT_CONTEXTUAL);
+ ContextualMode contextual_mode = NOT_CONTEXTUAL,
+ int slot_index = -1);
const Operator* StoreGlobal(LanguageMode language_mode,
const Unique<Name>& name,
- const VectorSlotPair& feedback);
+ const VectorSlotPair& feedback,
+ int slot_index = -1);
const Operator* LoadContext(size_t depth, size_t index, bool immutable);
const Operator* StoreContext(size_t depth, size_t index);
javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true), context,
context, effect);
Node* fast = graph()->NewNode(
- javascript()->LoadGlobal(name, access.feedback(), access.mode()), global,
- vector, context, state1, state2, global, check_true);
+ javascript()->LoadGlobal(name, access.feedback(), access.mode()), context,
+ global, vector, context, state1, state2, global, check_true);
// Slow case, because variable potentially shadowed. Perform dynamic lookup.
uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired;
DEFINE_BOOL(use_ic, true, "use inline caching")
DEFINE_BOOL(trace_ic, false, "trace inline cache state transitions")
DEFINE_BOOL(vector_stores, false, "use vectors for store ics")
+DEFINE_BOOL(global_var_shortcuts, false, "use ic-less global loads and stores")
// macro-assembler-ia32.cc
DEFINE_BOOL(native_code_counters, false,
return HObjectAccess(kInobject, PropertyCell::kValueOffset);
}
+ static HObjectAccess ForPropertyCellDetails() {
+ return HObjectAccess(kInobject, PropertyCell::kDetailsOffset,
+ Representation::Smi());
+ }
+
static HObjectAccess ForCellValue() {
return HObjectAccess(kInobject, Cell::kValueOffset);
}
DCHECK(IsLoopHeader() || first_ == NULL);
HEnvironment* incoming_env = pred->last_environment();
if (IsLoopHeader()) {
- DCHECK(phis()->length() == incoming_env->length());
+ DCHECK_EQ(phis()->length(), incoming_env->length());
for (int i = 0; i < phis_.length(); ++i) {
phis_[i]->AddInput(incoming_env->values()->at(i));
}
}
+void HGraphBuilder::IfBuilder::EndUnreachable() {
+ if (captured_) return;
+ Finish();
+ builder()->set_current_block(nullptr);
+}
+
+
void HGraphBuilder::IfBuilder::End() {
if (captured_) return;
Finish();
}
+HInstruction* HGraphBuilder::BuildGetNativeContext() {
+ // Get the global object, then the native context
+ HValue* global_object = Add<HLoadNamedField>(
+ context(), nullptr,
+ HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
+ return Add<HLoadNamedField>(global_object, nullptr,
+ HObjectAccess::ForObservableJSObjectOffset(
+ GlobalObject::kNativeContextOffset));
+}
+
+
HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) {
// Get the global object, then the native context
HInstruction* context = Add<HLoadNamedField>(
}
-HInstruction* HGraphBuilder::BuildGetNativeContext() {
- // Get the global object, then the native context
- HValue* global_object = Add<HLoadNamedField>(
- context(), nullptr,
- HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
- return Add<HLoadNamedField>(global_object, nullptr,
- HObjectAccess::ForObservableJSObjectOffset(
- GlobalObject::kNativeContextOffset));
+HValue* HGraphBuilder::BuildGetParentContext(HValue* depth, int depth_value) {
+ HValue* script_context = context();
+ if (depth != NULL) {
+ HValue* zero = graph()->GetConstant0();
+
+ Push(script_context);
+ Push(depth);
+
+ LoopBuilder loop(this);
+ loop.BeginBody(2); // Drop script_context and depth from last environment
+ // to appease live range building without simulates.
+ depth = Pop();
+ script_context = Pop();
+
+ script_context = Add<HLoadNamedField>(
+ script_context, nullptr,
+ HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
+ depth = AddUncasted<HSub>(depth, graph()->GetConstant1());
+ depth->ClearFlag(HValue::kCanOverflow);
+
+ IfBuilder if_break(this);
+ if_break.If<HCompareNumericAndBranch, HValue*>(depth, zero, Token::EQ);
+ if_break.Then();
+ {
+ Push(script_context); // The result.
+ loop.Break();
+ }
+ if_break.Else();
+ {
+ Push(script_context);
+ Push(depth);
+ }
+ loop.EndBody();
+ if_break.End();
+
+ script_context = Pop();
+ } else if (depth_value > 0) {
+ // Unroll the above loop.
+ for (int i = 0; i < depth_value; i++) {
+ script_context = Add<HLoadNamedField>(
+ script_context, nullptr,
+ HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX));
+ }
+ }
+ return script_context;
}
void Then();
void Else();
void End();
+ void EndUnreachable();
void Deopt(Deoptimizer::DeoptReason reason);
void ThenDeopt(Deoptimizer::DeoptReason reason) {
HInstruction* BuildGetNativeContext(HValue* closure);
HInstruction* BuildGetNativeContext();
HInstruction* BuildGetScriptContext(int context_index);
+ // Builds a loop version if |depth| is specified or unrolls the loop to
+ // |depth_value| iterations otherwise.
+ HValue* BuildGetParentContext(HValue* depth, int depth_value);
+
HInstruction* BuildGetArrayFunction();
HValue* BuildArrayBufferViewFieldAccessor(HValue* object,
HValue* checked_object,
Variable* var = proxy->var();
DCHECK(var->IsUnallocatedOrGlobalSlot() ||
(var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
- __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
- __ mov(LoadDescriptor::NameRegister(), var->name());
- __ mov(LoadDescriptor::SlotRegister(),
- Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
- // Inside typeof use a regular load, not a contextual load, to avoid
- // a reference error.
- CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ if (var->IsGlobalSlot()) {
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index();
+ int depth = scope()->ContextChainLength(var->scope());
+ __ mov(LoadGlobalViaContextDescriptor::DepthRegister(),
+ Immediate(Smi::FromInt(depth)));
+ __ mov(LoadGlobalViaContextDescriptor::SlotRegister(),
+ Immediate(Smi::FromInt(slot_index)));
+ __ mov(LoadGlobalViaContextDescriptor::NameRegister(), var->name());
+ LoadGlobalViaContextStub stub(isolate(), depth);
+ __ CallStub(&stub);
+
+ } else {
+ __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+ __ mov(LoadDescriptor::NameRegister(), var->name());
+ __ mov(LoadDescriptor::SlotRegister(),
+ Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
+ // Inside typeof use a regular load, not a contextual load, to avoid
+ // a reference error.
+ CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ }
}
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocatedOrGlobalSlot()) {
+ if (var->IsUnallocated()) {
// Global var, const, or let.
__ mov(StoreDescriptor::NameRegister(), var->name());
__ mov(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
CallStoreIC();
+ } else if (var->IsGlobalSlot()) {
+ // Global var, const, or let.
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index() + 1;
+ int depth = scope()->ContextChainLength(var->scope());
+ __ mov(StoreGlobalViaContextDescriptor::DepthRegister(),
+ Immediate(Smi::FromInt(depth)));
+ __ mov(StoreGlobalViaContextDescriptor::SlotRegister(),
+ Immediate(Smi::FromInt(slot_index)));
+ __ mov(StoreGlobalViaContextDescriptor::NameRegister(), var->name());
+ DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(eax));
+ StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+ __ CallStub(&stub);
+
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
const Register StoreTransitionDescriptor::MapRegister() { return ebx; }
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return edx; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return ebx; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return ecx; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return edx; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return ebx; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return ecx; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return eax; }
+
+
const Register ElementTransitionAndStoreDescriptor::MapRegister() {
return ebx;
}
}
+Type::FunctionType*
+LoadGlobalViaContextDescriptor::BuildCallInterfaceDescriptorFunctionType(
+ Isolate* isolate, int paramater_count) {
+ Type::FunctionType* function = Type::FunctionType::New(
+ AnyTagged(), Type::Undefined(), 3, isolate->interface_descriptor_zone());
+ function->InitParameter(0, SmiType());
+ function->InitParameter(1, SmiType());
+ function->InitParameter(2, AnyTagged());
+ return function;
+}
+
+
+void LoadGlobalViaContextDescriptor::InitializePlatformSpecific(
+ CallInterfaceDescriptorData* data) {
+ Register registers[] = {DepthRegister(), SlotRegister(), NameRegister()};
+ data->InitializePlatformSpecific(arraysize(registers), registers);
+}
+
+
+Type::FunctionType*
+StoreGlobalViaContextDescriptor::BuildCallInterfaceDescriptorFunctionType(
+ Isolate* isolate, int paramater_count) {
+ Type::FunctionType* function = Type::FunctionType::New(
+ AnyTagged(), Type::Undefined(), 5, isolate->interface_descriptor_zone());
+ function->InitParameter(0, SmiType());
+ function->InitParameter(1, SmiType());
+ function->InitParameter(2, AnyTagged());
+ function->InitParameter(3, AnyTagged());
+ return function;
+}
+
+
+void StoreGlobalViaContextDescriptor::InitializePlatformSpecific(
+ CallInterfaceDescriptorData* data) {
+ Register registers[] = {DepthRegister(), SlotRegister(), NameRegister(),
+ ValueRegister()};
+ data->InitializePlatformSpecific(arraysize(registers), registers);
+}
+
+
void ElementTransitionAndStoreDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {ValueRegister(), MapRegister(), NameRegister(),
V(ApiGetter) \
V(ArgumentsAccessRead) \
V(StoreArrayLiteralElement) \
+ V(LoadGlobalViaContext) \
+ V(StoreGlobalViaContext) \
V(MathPowTagged) \
V(MathPowInteger) \
V(ContextOnly) \
};
+class LoadGlobalViaContextDescriptor : public CallInterfaceDescriptor {
+ public:
+ DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(LoadGlobalViaContextDescriptor,
+ CallInterfaceDescriptor)
+
+ static const Register DepthRegister();
+ static const Register SlotRegister();
+ static const Register NameRegister();
+};
+
+
+class StoreGlobalViaContextDescriptor : public CallInterfaceDescriptor {
+ public:
+ DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(StoreGlobalViaContextDescriptor,
+ CallInterfaceDescriptor)
+
+ static const Register DepthRegister();
+ static const Register SlotRegister();
+ static const Register NameRegister();
+ static const Register ValueRegister();
+};
+
+
class TransitionElementsKindDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(TransitionElementsKindDescriptor, CallInterfaceDescriptor)
Variable* var = proxy->var();
DCHECK(var->IsUnallocatedOrGlobalSlot() ||
(var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
- __ lw(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
- __ li(LoadDescriptor::NameRegister(), Operand(var->name()));
- __ li(LoadDescriptor::SlotRegister(),
- Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
- // Inside typeof use a regular load, not a contextual load, to avoid
- // a reference error.
- CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ if (var->IsGlobalSlot()) {
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index();
+ int depth = scope()->ContextChainLength(var->scope());
+ __ li(LoadGlobalViaContextDescriptor::DepthRegister(),
+ Operand(Smi::FromInt(depth)));
+ __ li(LoadGlobalViaContextDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(slot_index)));
+ __ li(LoadGlobalViaContextDescriptor::NameRegister(), Operand(var->name()));
+ LoadGlobalViaContextStub stub(isolate(), depth);
+ __ CallStub(&stub);
+
+ } else {
+ __ lw(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+ __ li(LoadDescriptor::NameRegister(), Operand(var->name()));
+ __ li(LoadDescriptor::SlotRegister(),
+ Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+ // Inside typeof use a regular load, not a contextual load, to avoid
+ // a reference error.
+ CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ }
}
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocatedOrGlobalSlot()) {
+ if (var->IsUnallocated()) {
// Global var, const, or let.
__ mov(StoreDescriptor::ValueRegister(), result_register());
__ li(StoreDescriptor::NameRegister(), Operand(var->name()));
if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
CallStoreIC();
+ } else if (var->IsGlobalSlot()) {
+ // Global var, const, or let.
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index() + 1;
+ int depth = scope()->ContextChainLength(var->scope());
+ __ li(StoreGlobalViaContextDescriptor::DepthRegister(),
+ Operand(Smi::FromInt(depth)));
+ __ li(StoreGlobalViaContextDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(slot_index)));
+ __ li(StoreGlobalViaContextDescriptor::NameRegister(),
+ Operand(var->name()));
+ __ mov(StoreGlobalViaContextDescriptor::ValueRegister(), result_register());
+ StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+ __ CallStub(&stub);
+
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
const Register StoreTransitionDescriptor::MapRegister() { return a3; }
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return a1; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return a2; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return a3; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return a1; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return a2; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return a3; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return a0; }
+
+
const Register ElementTransitionAndStoreDescriptor::MapRegister() { return a3; }
Variable* var = proxy->var();
DCHECK(var->IsUnallocatedOrGlobalSlot() ||
(var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
- __ ld(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
- __ li(LoadDescriptor::NameRegister(), Operand(var->name()));
- __ li(LoadDescriptor::SlotRegister(),
- Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
- // Inside typeof use a regular load, not a contextual load, to avoid
- // a reference error.
- CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ if (var->IsGlobalSlot()) {
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index();
+ int depth = scope()->ContextChainLength(var->scope());
+ __ li(LoadGlobalViaContextDescriptor::DepthRegister(),
+ Operand(Smi::FromInt(depth)));
+ __ li(LoadGlobalViaContextDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(slot_index)));
+ __ li(LoadGlobalViaContextDescriptor::NameRegister(), Operand(var->name()));
+ LoadGlobalViaContextStub stub(isolate(), depth);
+ __ CallStub(&stub);
+
+ } else {
+ __ ld(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+ __ li(LoadDescriptor::NameRegister(), Operand(var->name()));
+ __ li(LoadDescriptor::SlotRegister(),
+ Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+ // Inside typeof use a regular load, not a contextual load, to avoid
+ // a reference error.
+ CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ }
}
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocatedOrGlobalSlot()) {
+ if (var->IsUnallocated()) {
// Global var, const, or let.
__ mov(StoreDescriptor::ValueRegister(), result_register());
__ li(StoreDescriptor::NameRegister(), Operand(var->name()));
if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
CallStoreIC();
+ } else if (var->IsGlobalSlot()) {
+ // Global var, const, or let.
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index() + 1;
+ int depth = scope()->ContextChainLength(var->scope());
+ __ li(StoreGlobalViaContextDescriptor::DepthRegister(),
+ Operand(Smi::FromInt(depth)));
+ __ li(StoreGlobalViaContextDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(slot_index)));
+ __ li(StoreGlobalViaContextDescriptor::NameRegister(),
+ Operand(var->name()));
+ __ mov(StoreGlobalViaContextDescriptor::ValueRegister(), result_register());
+ StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+ __ CallStub(&stub);
+
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
const Register StoreTransitionDescriptor::MapRegister() { return a3; }
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return a1; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return a2; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return a3; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return a1; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return a2; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return a3; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return a0; }
+
+
const Register ElementTransitionAndStoreDescriptor::MapRegister() { return a3; }
Variable* var = proxy->var();
DCHECK(var->IsUnallocatedOrGlobalSlot() ||
(var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
- __ LoadP(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
- __ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
- __ mov(LoadDescriptor::SlotRegister(),
- Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
- // Inside typeof use a regular load, not a contextual load, to avoid
- // a reference error.
- CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ if (var->IsGlobalSlot()) {
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index();
+ int depth = scope()->ContextChainLength(var->scope());
+ __ mov(LoadGlobalViaContextDescriptor::DepthRegister(),
+ Operand(Smi::FromInt(depth)));
+ __ mov(LoadGlobalViaContextDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(slot_index)));
+ __ mov(LoadGlobalViaContextDescriptor::NameRegister(),
+ Operand(var->name()));
+ LoadGlobalViaContextStub stub(isolate(), depth);
+ __ CallStub(&stub);
+
+ } else {
+ __ LoadP(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+ __ mov(LoadDescriptor::NameRegister(), Operand(var->name()));
+ __ mov(LoadDescriptor::SlotRegister(),
+ Operand(SmiFromSlot(proxy->VariableFeedbackSlot())));
+ // Inside typeof use a regular load, not a contextual load, to avoid
+ // a reference error.
+ CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ }
}
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocatedOrGlobalSlot()) {
+ if (var->IsUnallocated()) {
// Global var, const, or let.
__ mov(StoreDescriptor::NameRegister(), Operand(var->name()));
__ LoadP(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
CallStoreIC();
+ } else if (var->IsGlobalSlot()) {
+ // Global var, const, or let.
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index() + 1;
+ int depth = scope()->ContextChainLength(var->scope());
+ __ mov(StoreGlobalViaContextDescriptor::DepthRegister(),
+ Operand(Smi::FromInt(depth)));
+ __ mov(StoreGlobalViaContextDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(slot_index)));
+ __ mov(StoreGlobalViaContextDescriptor::NameRegister(),
+ Operand(var->name()));
+ DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(r3));
+ StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+ __ CallStub(&stub);
+
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
const Register StoreTransitionDescriptor::MapRegister() { return r6; }
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return r4; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return r5; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return r3; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return r4; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return r5; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return r6; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return r3; }
+
+
const Register ElementTransitionAndStoreDescriptor::MapRegister() { return r6; }
}
+RUNTIME_FUNCTION(Runtime_LoadGlobalViaContext) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 3);
+ CONVERT_ARG_HANDLE_CHECKED(Context, script_context, 0);
+ CONVERT_SMI_ARG_CHECKED(index, 1);
+ CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
+ DCHECK(script_context->IsScriptContext());
+ DCHECK(script_context->get(index)->IsPropertyCell());
+
+ Handle<GlobalObject> global(script_context->global_object());
+
+ LookupIterator it(global, name, LookupIterator::OWN);
+ if (LookupIterator::DATA == it.state()) {
+ // Now update cell in the script context.
+ Handle<PropertyCell> cell = it.GetPropertyCell();
+ script_context->set(index, *cell);
+ } else {
+ // This is not a fast case, so keep this access in a slow mode.
+ // Store empty_property_cell here to release the outdated property cell.
+ script_context->set(index, isolate->heap()->empty_property_cell());
+ }
+
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it));
+
+ return *result;
+}
+
+
+RUNTIME_FUNCTION(Runtime_StoreGlobalViaContext) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 5);
+ CONVERT_ARG_HANDLE_CHECKED(Context, script_context, 0);
+ CONVERT_SMI_ARG_CHECKED(index, 1);
+ CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
+ CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
+ CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode_arg, 4);
+ DCHECK(script_context->IsScriptContext());
+ DCHECK(script_context->get(index)->IsPropertyCell());
+ LanguageMode language_mode = language_mode_arg;
+
+ Handle<GlobalObject> global(script_context->global_object());
+
+ LookupIterator it(global, name, LookupIterator::OWN);
+ if (LookupIterator::DATA == it.state()) {
+ // Now update cell in the script context.
+ Handle<PropertyCell> cell = it.GetPropertyCell();
+ script_context->set(index, *cell);
+ } else {
+ // This is not a fast case, so keep this access in a slow mode.
+ // Store empty_property_cell here to release the outdated property cell.
+ script_context->set(index, isolate->heap()->empty_property_cell());
+ }
+
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ Object::SetProperty(&it, value, language_mode,
+ Object::CERTAINLY_NOT_STORE_FROM_KEYED));
+
+ return *result;
+}
+
+
RUNTIME_FUNCTION(Runtime_GetProperty) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
F(GetPropertyStrong, 2, 1) \
F(KeyedGetProperty, 2, 1) \
F(KeyedGetPropertyStrong, 2, 1) \
+ F(LoadGlobalViaContext, 3, 1) \
+ F(StoreGlobalViaContext, 5, 1) \
F(AddNamedProperty, 4, 1) \
F(SetProperty, 4, 1) \
F(AddElement, 3, 1) \
namespace v8 {
namespace internal {
-// TODO(ishell): remove this once compiler support is landed.
-bool enable_context_globals = false;
-
// ----------------------------------------------------------------------------
// Implementation of LocalsMap
//
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;
+ if (var->IsUnallocated()) {
+ if (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;
+ } else {
+ // There must be only DYNAMIC_GLOBAL in the script scope.
+ DCHECK(!is_script_scope() || DYNAMIC_GLOBAL == var->mode());
+ }
}
}
AllocateNonParameterLocal(isolate, vars[i].var());
}
- if (enable_context_globals) {
+ if (FLAG_global_var_shortcuts) {
for (int i = 0; i < var_count; i++) {
AllocateDeclaredGlobal(isolate, vars[i].var());
}
Variable* var = proxy->var();
DCHECK(var->IsUnallocatedOrGlobalSlot() ||
(var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
- __ Move(LoadDescriptor::NameRegister(), var->name());
- __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
- __ Move(LoadDescriptor::SlotRegister(),
- SmiFromSlot(proxy->VariableFeedbackSlot()));
- // Inside typeof use a regular load, not a contextual load, to avoid
- // a reference error.
- CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ if (var->IsGlobalSlot()) {
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index();
+ int depth = scope()->ContextChainLength(var->scope());
+ __ Move(LoadGlobalViaContextDescriptor::DepthRegister(),
+ Smi::FromInt(depth));
+ __ Move(LoadGlobalViaContextDescriptor::SlotRegister(),
+ Smi::FromInt(slot_index));
+ __ Move(LoadGlobalViaContextDescriptor::NameRegister(), var->name());
+ LoadGlobalViaContextStub stub(isolate(), depth);
+ __ CallStub(&stub);
+
+ } else {
+ __ Move(LoadDescriptor::NameRegister(), var->name());
+ __ movp(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+ __ Move(LoadDescriptor::SlotRegister(),
+ SmiFromSlot(proxy->VariableFeedbackSlot()));
+ // Inside typeof use a regular load, not a contextual load, to avoid
+ // a reference error.
+ CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ }
}
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocatedOrGlobalSlot()) {
+ if (var->IsUnallocated()) {
// Global var, const, or let.
__ Move(StoreDescriptor::NameRegister(), var->name());
__ movp(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
CallStoreIC();
+ } else if (var->IsGlobalSlot()) {
+ // Global var, const, or let.
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index() + 1;
+ int depth = scope()->ContextChainLength(var->scope());
+ __ Move(StoreGlobalViaContextDescriptor::DepthRegister(),
+ Smi::FromInt(depth));
+ __ Move(StoreGlobalViaContextDescriptor::SlotRegister(),
+ Smi::FromInt(slot_index));
+ __ Move(StoreGlobalViaContextDescriptor::NameRegister(), var->name());
+ DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(rax));
+ StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+ __ CallStub(&stub);
+
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
const Register StoreTransitionDescriptor::MapRegister() { return rbx; }
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return rdx; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return rbx; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return rcx; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return rdx; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return rbx; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return rcx; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return rax; }
+
+
const Register ElementTransitionAndStoreDescriptor::MapRegister() {
return rbx;
}
Variable* var = proxy->var();
DCHECK(var->IsUnallocatedOrGlobalSlot() ||
(var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL));
- __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
- __ mov(LoadDescriptor::NameRegister(), var->name());
- __ mov(LoadDescriptor::SlotRegister(),
- Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
- // Inside typeof use a regular load, not a contextual load, to avoid
- // a reference error.
- CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ if (var->IsGlobalSlot()) {
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index();
+ int depth = scope()->ContextChainLength(var->scope());
+ __ mov(LoadGlobalViaContextDescriptor::DepthRegister(),
+ Immediate(Smi::FromInt(depth)));
+ __ mov(LoadGlobalViaContextDescriptor::SlotRegister(),
+ Immediate(Smi::FromInt(slot_index)));
+ __ mov(LoadGlobalViaContextDescriptor::NameRegister(), var->name());
+ LoadGlobalViaContextStub stub(isolate(), depth);
+ __ CallStub(&stub);
+
+ } else {
+ __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
+ __ mov(LoadDescriptor::NameRegister(), var->name());
+ __ mov(LoadDescriptor::SlotRegister(),
+ Immediate(SmiFromSlot(proxy->VariableFeedbackSlot())));
+ // Inside typeof use a regular load, not a contextual load, to avoid
+ // a reference error.
+ CallLoadIC(typeof_state == NOT_INSIDE_TYPEOF ? CONTEXTUAL : NOT_CONTEXTUAL);
+ }
}
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorICSlot slot) {
- if (var->IsUnallocatedOrGlobalSlot()) {
+ if (var->IsUnallocated()) {
// Global var, const, or let.
__ mov(StoreDescriptor::NameRegister(), var->name());
__ mov(StoreDescriptor::ReceiverRegister(), GlobalObjectOperand());
if (FLAG_vector_stores) EmitLoadStoreICSlot(slot);
CallStoreIC();
+ } else if (var->IsGlobalSlot()) {
+ // Global var, const, or let.
+ DCHECK(var->index() > 0);
+ DCHECK(var->IsStaticGlobalObjectProperty());
+ // Each var occupies two slots in the context: for reads and writes.
+ int slot_index = var->index() + 1;
+ int depth = scope()->ContextChainLength(var->scope());
+ __ mov(StoreGlobalViaContextDescriptor::DepthRegister(),
+ Immediate(Smi::FromInt(depth)));
+ __ mov(StoreGlobalViaContextDescriptor::SlotRegister(),
+ Immediate(Smi::FromInt(slot_index)));
+ __ mov(StoreGlobalViaContextDescriptor::NameRegister(), var->name());
+ DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(eax));
+ StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+ __ CallStub(&stub);
+
} else if (var->mode() == LET && op != Token::INIT_LET) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
const Register StoreTransitionDescriptor::MapRegister() { return ebx; }
+const Register LoadGlobalViaContextDescriptor::DepthRegister() { return edx; }
+const Register LoadGlobalViaContextDescriptor::SlotRegister() { return ebx; }
+const Register LoadGlobalViaContextDescriptor::NameRegister() { return ecx; }
+
+
+const Register StoreGlobalViaContextDescriptor::DepthRegister() { return edx; }
+const Register StoreGlobalViaContextDescriptor::SlotRegister() { return ebx; }
+const Register StoreGlobalViaContextDescriptor::NameRegister() { return ecx; }
+const Register StoreGlobalViaContextDescriptor::ValueRegister() { return eax; }
+
+
const Register ElementTransitionAndStoreDescriptor::MapRegister() {
return ebx;
}
Unique<Name> name = Unique<Name>::CreateUninitialized(
isolate()->factory()->InternalizeUtf8String(string));
const Operator* op = javascript()->LoadGlobal(name, feedback);
- Node* load = graph()->NewNode(op, global, vector, context);
+ Node* load = graph()->NewNode(op, context, global, vector, context);
if (mode == JSTypeFeedbackSpecializer::kDeoptimizationEnabled) {
for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op);
i++) {
for (size_t i = 0; i < arraysize(names); i++) {
Unique<Name> name = Unique<Name>::CreateImmovable(names[i]);
Reduction r = Reduce(graph()->NewNode(
- javascript()->LoadGlobal(name, feedback), global, vector, context,
- EmptyFrameState(), EmptyFrameState(), effect, control));
+ javascript()->LoadGlobal(name, feedback), context, global, vector,
+ context, EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), matches[i]);