Index: src/compiler/js-generic-lowering.cc |
diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc |
index 5fe37e5ad68ceebb9a6cf1bced507714fee68437..feb3d03789ded22f9ce5d22fa072f33f2466dfa1 100644 |
--- a/src/compiler/js-generic-lowering.cc |
+++ b/src/compiler/js-generic-lowering.cc |
@@ -558,6 +558,208 @@ void JSGenericLowering::LowerJSCallRuntime(Node* node) { |
} |
+void JSGenericLowering::LowerJSForInDone(Node* node) { |
+ ReplaceWithRuntimeCall(node, Runtime::kForInDone); |
+} |
+ |
+ |
+void JSGenericLowering::LowerJSForInNext(Node* node) { |
+ ReplaceWithRuntimeCall(node, Runtime::kForInNext); |
+} |
+ |
+ |
+void JSGenericLowering::LowerJSForInPrepare(Node* node) { |
+ Node* object = NodeProperties::GetValueInput(node, 0); |
+ Node* context = NodeProperties::GetContextInput(node); |
+ Node* effect = NodeProperties::GetEffectInput(node); |
+ Node* control = NodeProperties::GetControlInput(node); |
+ Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); |
+ |
+ // Get the set of properties to enumerate. |
+ Runtime::Function const* function = |
+ Runtime::FunctionForId(Runtime::kGetPropertyNamesFast); |
+ CallDescriptor const* descriptor = Linkage::GetRuntimeCallDescriptor( |
+ zone(), function->function_id, 1, Operator::kNoProperties); |
+ Node* cache_type = effect = graph()->NewNode( |
+ common()->Call(descriptor), |
+ jsgraph()->CEntryStubConstant(function->result_size), object, |
+ jsgraph()->ExternalConstant( |
+ ExternalReference(function->function_id, isolate())), |
+ jsgraph()->Int32Constant(1), context, frame_state, effect, control); |
+ control = graph()->NewNode(common()->IfSuccess(), cache_type); |
+ |
+ Node* object_map = effect = graph()->NewNode( |
+ machine()->Load(kMachAnyTagged), object, |
+ jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), |
+ effect, control); |
+ Node* cache_type_map = effect = graph()->NewNode( |
+ machine()->Load(kMachAnyTagged), cache_type, |
+ jsgraph()->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), |
+ effect, control); |
+ Node* meta_map = jsgraph()->HeapConstant(isolate()->factory()->meta_map()); |
+ |
+ // If we got a map from the GetPropertyNamesFast runtime call, we can do a |
+ // fast modification check. Otherwise, we got a fixed array, and we have to |
+ // perform a slow check on every iteration. |
+ Node* check0 = |
+ graph()->NewNode(machine()->WordEqual(), cache_type_map, meta_map); |
+ Node* branch0 = |
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control); |
+ |
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); |
+ Node* cache_array_true0; |
+ Node* cache_length_true0; |
+ Node* cache_type_true0; |
+ Node* etrue0; |
+ { |
+ // Enum cache case. |
+ Node* cache_type_enum_length = etrue0 = graph()->NewNode( |
+ machine()->Load(kMachUint32), cache_type, |
+ jsgraph()->IntPtrConstant(Map::kBitField3Offset - kHeapObjectTag), |
+ effect, if_true0); |
+ cache_type_enum_length = |
+ graph()->NewNode(machine()->Word32And(), cache_type_enum_length, |
+ jsgraph()->Uint32Constant(Map::EnumLengthBits::kMask)); |
+ |
+ Node* check1 = |
+ graph()->NewNode(machine()->Word32Equal(), cache_type_enum_length, |
+ jsgraph()->Int32Constant(0)); |
+ Node* branch1 = |
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0); |
+ |
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
+ Node* cache_array_true1; |
+ Node* etrue1; |
+ { |
+ // No properties to enumerate. |
+ cache_array_true1 = |
+ jsgraph()->HeapConstant(isolate()->factory()->empty_fixed_array()); |
+ etrue1 = etrue0; |
+ } |
+ |
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
+ Node* cache_array_false1; |
+ Node* efalse1; |
+ { |
+ // Load the enumeration cache from the instance descriptors of {object}. |
+ Node* object_map_descriptors = efalse1 = graph()->NewNode( |
+ machine()->Load(kMachAnyTagged), object_map, |
+ jsgraph()->IntPtrConstant(Map::kDescriptorsOffset - kHeapObjectTag), |
+ etrue0, if_false1); |
+ Node* object_map_enum_cache = efalse1 = graph()->NewNode( |
+ machine()->Load(kMachAnyTagged), object_map_descriptors, |
+ jsgraph()->IntPtrConstant(DescriptorArray::kEnumCacheOffset - |
+ kHeapObjectTag), |
+ efalse1, if_false1); |
+ cache_array_false1 = efalse1 = graph()->NewNode( |
+ machine()->Load(kMachAnyTagged), object_map_enum_cache, |
+ jsgraph()->IntPtrConstant( |
+ DescriptorArray::kEnumCacheBridgeCacheOffset - kHeapObjectTag), |
+ efalse1, if_false1); |
+ } |
+ |
+ if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
+ etrue0 = |
+ graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0); |
+ cache_array_true0 = |
+ graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_array_true1, |
+ cache_array_false1, if_true0); |
+ |
+ cache_length_true0 = graph()->NewNode( |
+ machine()->WordShl(), |
+ machine()->Is64() |
+ ? graph()->NewNode(machine()->ChangeUint32ToUint64(), |
+ cache_type_enum_length) |
+ : cache_type_enum_length, |
+ jsgraph()->Int32Constant(kSmiShiftSize + kSmiTagSize)); |
+ cache_type_true0 = cache_type; |
+ } |
+ |
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); |
+ Node* cache_array_false0; |
+ Node* cache_length_false0; |
+ Node* cache_type_false0; |
+ Node* efalse0; |
+ { |
+ // FixedArray case. |
+ Node* object_instance_type = efalse0 = graph()->NewNode( |
+ machine()->Load(kMachUint8), object_map, |
+ jsgraph()->IntPtrConstant(Map::kInstanceTypeOffset - kHeapObjectTag), |
+ effect, if_false0); |
+ |
+ STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
+ Node* check1 = graph()->NewNode( |
+ machine()->Uint32LessThanOrEqual(), object_instance_type, |
+ jsgraph()->Uint32Constant(LAST_JS_PROXY_TYPE)); |
+ Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), |
+ check1, if_false0); |
+ |
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
+ Node* cache_type_true1 = jsgraph()->ZeroConstant(); // Zero indicates proxy |
+ |
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
+ Node* cache_type_false1 = jsgraph()->OneConstant(); // One means slow check |
+ |
+ if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); |
+ cache_type_false0 = |
+ graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_type_true1, |
+ cache_type_false1, if_false0); |
+ |
+ cache_array_false0 = cache_type; |
+ cache_length_false0 = efalse0 = graph()->NewNode( |
+ machine()->Load(kMachAnyTagged), cache_array_false0, |
+ jsgraph()->IntPtrConstant(FixedArray::kLengthOffset - kHeapObjectTag), |
+ efalse0, if_false0); |
+ } |
+ |
+ control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); |
+ effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); |
+ Node* cache_array = |
+ graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_array_true0, |
+ cache_array_false0, control); |
+ Node* cache_length = |
+ graph()->NewNode(common()->Phi(kMachAnyTagged, 2), cache_length_true0, |
+ cache_length_false0, control); |
+ cache_type = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), |
+ cache_type_true0, cache_type_false0, control); |
+ |
+ for (auto edge : node->use_edges()) { |
+ if (NodeProperties::IsEffectEdge(edge)) { |
+ edge.UpdateTo(effect); |
+ } else if (NodeProperties::IsControlEdge(edge)) { |
+ Node* const use = edge.from(); |
+ DCHECK_EQ(IrOpcode::kIfSuccess, use->opcode()); |
+ use->ReplaceUses(control); |
+ use->Kill(); |
+ } else { |
+ Node* const use = edge.from(); |
+ DCHECK(NodeProperties::IsValueEdge(edge)); |
+ DCHECK_EQ(IrOpcode::kProjection, use->opcode()); |
+ switch (ProjectionIndexOf(use->op())) { |
+ case 0: |
+ use->ReplaceUses(cache_type); |
+ break; |
+ case 1: |
+ use->ReplaceUses(cache_array); |
+ break; |
+ case 2: |
+ use->ReplaceUses(cache_length); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ use->Kill(); |
+ } |
+ } |
+} |
+ |
+ |
+void JSGenericLowering::LowerJSForInStep(Node* node) { |
+ ReplaceWithRuntimeCall(node, Runtime::kForInStep); |
+} |
+ |
+ |
void JSGenericLowering::LowerJSStackCheck(Node* node) { |
Node* effect = NodeProperties::GetEffectInput(node); |
Node* control = NodeProperties::GetControlInput(node); |