Index: src/code-stubs-hydrogen.cc |
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc |
index d1cabde1bd4cec2fed8110a951c7578361d07dd7..154811c55e441bf349b90a33ea148749095d8873 100644 |
--- a/src/code-stubs-hydrogen.cc |
+++ b/src/code-stubs-hydrogen.cc |
@@ -1605,7 +1605,221 @@ Handle<Code> StoreGlobalStub::GenerateCode() { |
} |
-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); |