Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Unified Diff: src/compiler/js-generic-lowering.cc

Issue 1160983004: [turbofan] First step towards sanitizing for-in and making it optimizable. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Add some comments. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/control-builders.cc ('k') | src/compiler/js-operator.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « src/compiler/control-builders.cc ('k') | src/compiler/js-operator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698