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

Side by Side Diff: src/builtins/builtins-forin.cc

Issue 2752143004: [refactor] Separate generated builtins and C++ builtins into separate files (Closed)
Patch Set: tentative gcmole fix Created 3 years, 9 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 unified diff | Download patch
« no previous file with comments | « src/builtins/builtins-date-gen.cc ('k') | src/builtins/builtins-forin-gen.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/builtins/builtins-forin.h"
6
7 #include "src/builtins/builtins-utils.h"
8 #include "src/builtins/builtins.h"
9 #include "src/code-factory.h"
10 #include "src/code-stub-assembler.h"
11 #include "src/counters.h"
12 #include "src/keys.h"
13 #include "src/lookup.h"
14 #include "src/objects-inl.h"
15 #include "src/property-descriptor.h"
16
17 namespace v8 {
18 namespace internal {
19
20 typedef compiler::Node Node;
21
22 Node* ForInBuiltinsAssembler::ForInFilter(Node* key, Node* object,
23 Node* context) {
24 Label return_undefined(this, Label::kDeferred), return_to_name(this),
25 end(this);
26
27 Variable var_result(this, MachineRepresentation::kTagged);
28
29 Node* has_property =
30 HasProperty(object, key, context, Runtime::kForInHasProperty);
31
32 Branch(WordEqual(has_property, BooleanConstant(true)), &return_to_name,
33 &return_undefined);
34
35 Bind(&return_to_name);
36 {
37 var_result.Bind(ToName(context, key));
38 Goto(&end);
39 }
40
41 Bind(&return_undefined);
42 {
43 var_result.Bind(UndefinedConstant());
44 Goto(&end);
45 }
46
47 Bind(&end);
48 return var_result.value();
49 }
50
51 std::tuple<Node*, Node*, Node*> ForInBuiltinsAssembler::EmitForInPrepare(
52 Node* object, Node* context, Label* call_runtime,
53 Label* nothing_to_iterate) {
54 Label use_cache(this);
55 CSA_ASSERT(this, IsJSReceiver(object));
56
57 CheckEnumCache(object, &use_cache, nothing_to_iterate, call_runtime);
58
59 Bind(&use_cache);
60 Node* map = LoadMap(object);
61 Node* enum_length = EnumLength(map);
62 GotoIf(WordEqual(enum_length, SmiConstant(0)), nothing_to_iterate);
63 Node* descriptors = LoadMapDescriptors(map);
64 Node* cache_offset =
65 LoadObjectField(descriptors, DescriptorArray::kEnumCacheOffset);
66 Node* enum_cache = LoadObjectField(
67 cache_offset, DescriptorArray::kEnumCacheBridgeCacheOffset);
68
69 return std::make_tuple(map, enum_cache, enum_length);
70 }
71
72 Node* ForInBuiltinsAssembler::EnumLength(Node* map) {
73 CSA_ASSERT(this, IsMap(map));
74 Node* bitfield_3 = LoadMapBitField3(map);
75 Node* enum_length = DecodeWordFromWord32<Map::EnumLengthBits>(bitfield_3);
76 return SmiTag(enum_length);
77 }
78
79 void ForInBuiltinsAssembler::CheckPrototypeEnumCache(Node* receiver, Node* map,
80 Label* use_cache,
81 Label* use_runtime) {
82 Variable current_js_object(this, MachineRepresentation::kTagged, receiver);
83 Variable current_map(this, MachineRepresentation::kTagged, map);
84
85 // These variables are updated in the loop below.
86 Variable* loop_vars[2] = {&current_js_object, &current_map};
87 Label loop(this, 2, loop_vars), next(this);
88
89 Goto(&loop);
90 // Check that there are no elements. |current_js_object| contains
91 // the current JS object we've reached through the prototype chain.
92 Bind(&loop);
93 {
94 Label if_elements(this), if_no_elements(this);
95 Node* elements = LoadElements(current_js_object.value());
96 Node* empty_fixed_array = LoadRoot(Heap::kEmptyFixedArrayRootIndex);
97 // Check that there are no elements.
98 Branch(WordEqual(elements, empty_fixed_array), &if_no_elements,
99 &if_elements);
100 Bind(&if_elements);
101 {
102 // Second chance, the object may be using the empty slow element
103 // dictionary.
104 Node* slow_empty_dictionary =
105 LoadRoot(Heap::kEmptySlowElementDictionaryRootIndex);
106 Branch(WordNotEqual(elements, slow_empty_dictionary), use_runtime,
107 &if_no_elements);
108 }
109
110 Bind(&if_no_elements);
111 {
112 // Update map prototype.
113 current_js_object.Bind(LoadMapPrototype(current_map.value()));
114 Branch(WordEqual(current_js_object.value(), NullConstant()), use_cache,
115 &next);
116 }
117 }
118
119 Bind(&next);
120 {
121 // For all objects but the receiver, check that the cache is empty.
122 current_map.Bind(LoadMap(current_js_object.value()));
123 Node* enum_length = EnumLength(current_map.value());
124 Node* zero_constant = SmiConstant(Smi::kZero);
125 Branch(WordEqual(enum_length, zero_constant), &loop, use_runtime);
126 }
127 }
128
129 void ForInBuiltinsAssembler::CheckEnumCache(Node* receiver, Label* use_cache,
130 Label* nothing_to_iterate,
131 Label* use_runtime) {
132 Node* map = LoadMap(receiver);
133
134 Label check_empty_prototype(this),
135 check_dict_receiver(this, Label::kDeferred);
136
137 // Check if the enum length field is properly initialized, indicating that
138 // there is an enum cache.
139 {
140 Node* invalid_enum_cache_sentinel =
141 SmiConstant(Smi::FromInt(kInvalidEnumCacheSentinel));
142 Node* enum_length = EnumLength(map);
143 Branch(WordEqual(enum_length, invalid_enum_cache_sentinel),
144 &check_dict_receiver, &check_empty_prototype);
145 }
146
147 // Check that there are no elements on the fast |receiver| and its prototype
148 // chain.
149 Bind(&check_empty_prototype);
150 CheckPrototypeEnumCache(receiver, map, use_cache, use_runtime);
151
152 Label dict_loop(this);
153 Bind(&check_dict_receiver);
154 {
155 // Avoid runtime-call for empty dictionary receivers.
156 GotoIfNot(IsDictionaryMap(map), use_runtime);
157 Node* properties = LoadProperties(receiver);
158 Node* length = LoadFixedArrayElement(
159 properties, NameDictionary::kNumberOfElementsIndex);
160 GotoIfNot(WordEqual(length, SmiConstant(0)), use_runtime);
161 // Check that there are no elements on the |receiver| and its prototype
162 // chain. Given that we do not create an EnumCache for dict-mode objects,
163 // directly jump to |nothing_to_iterate| if there are no elements and no
164 // properties on the |receiver|.
165 CheckPrototypeEnumCache(receiver, map, nothing_to_iterate, use_runtime);
166 }
167 }
168
169 TF_BUILTIN(ForInFilter, ForInBuiltinsAssembler) {
170 typedef ForInFilterDescriptor Descriptor;
171
172 Node* key = Parameter(Descriptor::kKey);
173 Node* object = Parameter(Descriptor::kObject);
174 Node* context = Parameter(Descriptor::kContext);
175
176 Return(ForInFilter(key, object, context));
177 }
178
179 TF_BUILTIN(ForInNext, ForInBuiltinsAssembler) {
180 typedef ForInNextDescriptor Descriptor;
181
182 Label filter(this);
183 Node* object = Parameter(Descriptor::kObject);
184 Node* cache_array = Parameter(Descriptor::kCacheArray);
185 Node* cache_type = Parameter(Descriptor::kCacheType);
186 Node* index = Parameter(Descriptor::kIndex);
187 Node* context = Parameter(Descriptor::kContext);
188
189 Node* key = LoadFixedArrayElement(cache_array, SmiUntag(index));
190 Node* map = LoadMap(object);
191 GotoIfNot(WordEqual(map, cache_type), &filter);
192 Return(key);
193 Bind(&filter);
194 Return(ForInFilter(key, object, context));
195 }
196
197 TF_BUILTIN(ForInPrepare, ForInBuiltinsAssembler) {
198 typedef ForInPrepareDescriptor Descriptor;
199
200 Label call_runtime(this), nothing_to_iterate(this);
201 Node* object = Parameter(Descriptor::kObject);
202 Node* context = Parameter(Descriptor::kContext);
203
204 Node* cache_type;
205 Node* cache_array;
206 Node* cache_length;
207 std::tie(cache_type, cache_array, cache_length) =
208 EmitForInPrepare(object, context, &call_runtime, &nothing_to_iterate);
209
210 Return(cache_type, cache_array, cache_length);
211
212 Bind(&call_runtime);
213 TailCallRuntime(Runtime::kForInPrepare, context, object);
214
215 Bind(&nothing_to_iterate);
216 {
217 Node* zero = SmiConstant(0);
218 Return(zero, zero, zero);
219 }
220 }
221 } // namespace internal
222 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins-date-gen.cc ('k') | src/builtins/builtins-forin-gen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698