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

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

Issue 2497243002: [stubs] Port builtin for Array.push fast-case from Crankshaft to TF (Closed)
Patch Set: Cleanup Created 4 years, 1 month 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
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/builtins/builtins.h" 5 #include "src/builtins/builtins.h"
6 #include "src/builtins/builtins-utils.h" 6 #include "src/builtins/builtins-utils.h"
7 7
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/contexts.h" 9 #include "src/contexts.h"
10 #include "src/elements.h" 10 #include "src/elements.h"
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 HandleScope handleScope(isolate); 143 HandleScope handleScope(isolate);
144 int argc = args.length() - 1; 144 int argc = args.length() - 1;
145 ScopedVector<Handle<Object>> argv(argc); 145 ScopedVector<Handle<Object>> argv(argc);
146 for (int i = 0; i < argc; ++i) { 146 for (int i = 0; i < argc; ++i) {
147 argv[i] = args.at<Object>(i + 1); 147 argv[i] = args.at<Object>(i + 1);
148 } 148 }
149 RETURN_RESULT_OR_FAILURE( 149 RETURN_RESULT_OR_FAILURE(
150 isolate, 150 isolate,
151 Execution::Call(isolate, function, args.receiver(), argc, argv.start())); 151 Execution::Call(isolate, function, args.receiver(), argc, argv.start()));
152 } 152 }
153 } // namespace
153 154
154 Object* DoArrayPush(Isolate* isolate, BuiltinArguments args) { 155 BUILTIN(ArrayPush) {
155 HandleScope scope(isolate); 156 HandleScope scope(isolate);
156 Handle<Object> receiver = args.receiver(); 157 Handle<Object> receiver = args.receiver();
157 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) { 158 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) {
158 return CallJsIntrinsic(isolate, isolate->array_push(), args); 159 return CallJsIntrinsic(isolate, isolate->array_push(), args);
159 } 160 }
160 // Fast Elements Path 161 // Fast Elements Path
161 int to_add = args.length() - 1; 162 int to_add = args.length() - 1;
162 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 163 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
163 int len = Smi::cast(array->length())->value(); 164 int len = Smi::cast(array->length())->value();
164 if (to_add == 0) return Smi::FromInt(len); 165 if (to_add == 0) return Smi::FromInt(len);
165 166
166 // Currently fixed arrays cannot grow too big, so we should never hit this. 167 // Currently fixed arrays cannot grow too big, so we should never hit this.
167 DCHECK_LE(to_add, Smi::kMaxValue - Smi::cast(array->length())->value()); 168 DCHECK_LE(to_add, Smi::kMaxValue - Smi::cast(array->length())->value());
168 169
169 if (JSArray::HasReadOnlyLength(array)) { 170 if (JSArray::HasReadOnlyLength(array)) {
170 return CallJsIntrinsic(isolate, isolate->array_push(), args); 171 return CallJsIntrinsic(isolate, isolate->array_push(), args);
171 } 172 }
172 173
173 ElementsAccessor* accessor = array->GetElementsAccessor(); 174 ElementsAccessor* accessor = array->GetElementsAccessor();
174 int new_length = accessor->Push(array, &args, to_add); 175 int new_length = accessor->Push(array, &args, to_add);
175 return Smi::FromInt(new_length); 176 return Smi::FromInt(new_length);
176 } 177 }
177 } // namespace
178 178
179 BUILTIN(ArrayPush) { return DoArrayPush(isolate, args); } 179 void Builtins::Generate_FastArrayPush(compiler::CodeAssemblerState* state) {
180 typedef compiler::Node Node;
181 typedef CodeStubAssembler::Label Label;
182 typedef CodeStubAssembler::Variable Variable;
183 CodeStubAssembler assembler(state);
184 Label runtime(&assembler, Label::kDeferred);
180 185
181 // TODO(verwaest): This is a temporary helper until the FastArrayPush stub can 186 Node* argc = assembler.Parameter(1);
182 // tailcall to the builtin directly. 187 Node* context = assembler.Parameter(2);
183 RUNTIME_FUNCTION(Runtime_ArrayPush) { 188 Node* new_target = assembler.Parameter(0);
184 DCHECK_EQ(2, args.length()); 189
185 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); 190 CodeStubArguments args(&assembler, argc);
186 // Rewrap the arguments as builtins arguments. 191 Node* receiver = args.GetReceiver();
187 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; 192
188 BuiltinArguments caller_args(argc, incoming->arguments() + 1); 193 Label fast(&assembler);
189 return DoArrayPush(isolate, caller_args); 194 assembler.BranchIfFastJSArray(
195 receiver, context, CodeStubAssembler::FastJSArrayAccessMode::ANY_ACCESS,
196 &fast, &runtime);
197
198 assembler.Bind(&fast);
199 {
Jakob Kummerow 2016/11/23 17:17:05 nit: this identation level doesn't add anything (e
danno 2016/11/29 14:39:59 Done.
200 // Disallow pushing onto prototypes. It might be the JSArray prototype.
201 // Disallow pushing onto non-extensible objects.
202 assembler.Comment("Disallow pushing onto prototypes");
203 Node* map = assembler.LoadMap(receiver);
204 Node* bit_field2 = assembler.LoadObjectField(map, Map::kBitField2Offset,
Jakob Kummerow 2016/11/23 17:17:05 ... = assembler.LoadMapBitField2(map);
danno 2016/11/29 14:39:59 Done.
205 MachineType::Uint8());
206 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
207 (1 << Map::kIsExtensible);
208 Node* test = assembler.Word32And(bit_field2, assembler.Int32Constant(mask));
209 assembler.GotoIf(
210 assembler.Word32NotEqual(
211 test, assembler.Int32Constant(1 << Map::kIsExtensible)),
212 &runtime);
213
214 // Disallow pushing onto arrays in dictionary named property mode. We need
215 // to figure out whether the length property is still writable.
216 assembler.Comment(
217 "Disallow pushing onto arrays in dictionary named property mode");
218 Node* bit_field3 = assembler.LoadObjectField(map, Map::kBitField3Offset,
Jakob Kummerow 2016/11/23 17:17:05 ... = assembler.LoadMapBitField3(map);
danno 2016/11/29 14:39:59 Done.
219 MachineType::Uint32());
220 mask = static_cast<int>(Map::DictionaryMap::kMask);
221 Node* mask_node = assembler.Int32Constant(mask);
222 test = assembler.Word32And(bit_field3, mask_node);
223 assembler.GotoIf(assembler.Word32Equal(test, mask_node), &runtime);
Jakob Kummerow 2016/11/23 17:17:05 assembler.GotoIf(assembler.IsSetWord32<Map::Dictio
224
225 // Check whether the length property is writable. The length property is the
Jakob Kummerow 2016/11/23 17:17:05 Most excellent point. The KeyedStoreGeneric stub h
danno 2016/11/29 14:39:59 Done.
226 // only default named property on arrays. It's nonconfigurable, hence is
227 // guaranteed to stay the first property.
228 Node* descriptors = assembler.LoadObjectField(map, Map::kDescriptorsOffset);
Jakob Kummerow 2016/11/23 17:17:05 ... = assembler.LoadMapDescriptors(map);
danno 2016/11/29 14:39:59 Done.
229 Node* details = assembler.LoadFixedArrayElement(
230 descriptors,
231 assembler.Int32Constant(DescriptorArray::ToDetailsIndex(0)));
232 mask = READ_ONLY << PropertyDetails::AttributesField::kShift;
233 mask_node = assembler.SmiConstant(Smi::FromInt(mask));
Jakob Kummerow 2016/11/23 17:17:05 nit: s/Smi::FromInt(mask)/mask/
danno 2016/11/29 14:39:59 Done.
234 test = assembler.WordAnd(details, mask_node);
235 assembler.GotoIf(assembler.WordEqual(test, mask_node), &runtime);
236
237 Variable arg_index(&assembler, MachineType::PointerRepresentation());
238 arg_index.Bind(assembler.IntPtrConstant(0));
239 Node* kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2);
240 CodeStubAssembler::VariableList vars({&arg_index}, assembler.zone());
241 Label default_label(&assembler, vars);
Jakob Kummerow 2016/11/23 17:17:05 nit: why not just s/vars/&arg_index/ here and once
danno 2016/11/29 14:39:59 Done.
242 Label smi_transition(&assembler);
243 Label object_push_pre(&assembler);
244 Label object_push(&assembler, vars);
245 Label double_push(&assembler);
246 Label double_transition(&assembler);
247
248 assembler.GotoIf(
249 assembler.IntPtrGreaterThan(
250 kind, assembler.IntPtrConstant(FAST_HOLEY_SMI_ELEMENTS)),
251 &object_push_pre);
252
253 {
254 Node* new_length =
255 assembler.BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver,
256 args, arg_index, &smi_transition);
257 args.PopAndReturn(new_length);
258 }
259
260 // If the argument is not a smi, then use a heavyweight SetProperty to
261 // transition the array for only the single next element. If the argument is
262 // a smi, the failure is due to some other reason and we should fall back on
263 // the most generic implementation for the rest of the array.
264 assembler.Bind(&smi_transition);
265 {
266 Node* arg = args.AtIndex(arg_index.value());
267 assembler.GotoIf(assembler.TaggedIsSmi(arg), &default_label);
268 Node* length = assembler.LoadJSArrayLength(receiver);
269 // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
270 // calling into the runtime to do the elements transition is overkill.
271 assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length,
272 arg, assembler.SmiConstant(Smi::FromInt(STRICT)));
Jakob Kummerow 2016/11/23 17:17:05 nit: s/Smi::FromInt(STRICT)/STRICT/
danno 2016/11/29 14:39:59 Done.
273 assembler.Increment(arg_index);
274 assembler.GotoIfNotNumber(arg, &object_push);
275 assembler.Goto(&double_push);
276 }
277
278 assembler.Bind(&object_push_pre);
279 assembler.Branch(assembler.IntPtrGreaterThan(
280 kind, assembler.IntPtrConstant(FAST_HOLEY_ELEMENTS)),
281 &double_push, &object_push);
282
283 assembler.Bind(&object_push);
284 {
285 Node* new_length = assembler.BuildAppendJSArray(
286 FAST_ELEMENTS, context, receiver, args, arg_index, &default_label);
287 args.PopAndReturn(new_length);
288 }
289
290 assembler.Bind(&double_push);
291 {
292 Node* new_length =
293 assembler.BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver,
294 args, arg_index, &double_transition);
295 args.PopAndReturn(new_length);
296 }
297
298 // If the argument is not a double, then use a heavyweight SetProperty to
299 // transition the array for only the single next element. If the argument is
300 // a double, the failure is due to some other reason and we should fall back
301 // on the most generic implementation for the rest of the array.
302 assembler.Bind(&double_transition);
303 {
304 Node* arg = args.AtIndex(arg_index.value());
305 assembler.GotoIfNumber(arg, &default_label);
306 Node* length = assembler.LoadJSArrayLength(receiver);
307 // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
308 // calling into the runtime to do the elements transition is overkill.
309 assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length,
310 arg, assembler.SmiConstant(Smi::FromInt(STRICT)));
Jakob Kummerow 2016/11/23 17:17:05 nit: s/Smi::FromInt(STRICT)/STRICT/
danno 2016/11/29 14:39:59 Done.
311 assembler.Increment(arg_index);
312 assembler.Goto(&object_push);
313 }
314
315 // Fallback that stores un-processed arguments using the full, heavyweight
316 // SetProperty machinery.
317 assembler.Bind(&default_label);
318 {
319 args.ForEach(
320 [receiver, context, &arg_index](CodeStubAssembler* assembler,
321 Node* arg) {
322 Node* length = assembler->LoadJSArrayLength(receiver);
323 assembler->CallRuntime(
324 Runtime::kSetProperty, context, receiver, length, arg,
325 assembler->SmiConstant(Smi::FromInt(STRICT)));
Jakob Kummerow 2016/11/23 17:17:05 nit: s/Smi::FromInt(STRICT)/STRICT/
danno 2016/11/29 14:39:59 Done.
326 },
327 arg_index.value());
328 args.PopAndReturn(assembler.LoadJSArrayLength(receiver));
329 }
330
331 assembler.Bind(&runtime);
332 {
333 Node* target =
334 assembler.LoadFromFrame(StandardFrameConstants::kFunctionOffset,
335 MachineType::TaggedPointer());
336 assembler.TailCallStub(CodeFactory::ArrayPush(assembler.isolate()),
337 context, target, new_target, argc);
338 }
339 }
190 } 340 }
191 341
192 BUILTIN(ArrayPop) { 342 BUILTIN(ArrayPop) {
193 HandleScope scope(isolate); 343 HandleScope scope(isolate);
194 Handle<Object> receiver = args.receiver(); 344 Handle<Object> receiver = args.receiver();
195 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) { 345 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) {
196 return CallJsIntrinsic(isolate, isolate->array_pop(), args); 346 return CallJsIntrinsic(isolate, isolate->array_pop(), args);
197 } 347 }
198 348
199 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 349 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
(...skipping 1086 matching lines...) Expand 10 before | Expand all | Expand 10 after
1286 Label init_k(&assembler), return_true(&assembler), return_false(&assembler), 1436 Label init_k(&assembler), return_true(&assembler), return_false(&assembler),
1287 call_runtime(&assembler); 1437 call_runtime(&assembler);
1288 1438
1289 Label init_len(&assembler); 1439 Label init_len(&assembler);
1290 1440
1291 index_var.Bind(intptr_zero); 1441 index_var.Bind(intptr_zero);
1292 len_var.Bind(intptr_zero); 1442 len_var.Bind(intptr_zero);
1293 1443
1294 // Take slow path if not a JSArray, if retrieving elements requires 1444 // Take slow path if not a JSArray, if retrieving elements requires
1295 // traversing prototype, or if access checks are required. 1445 // traversing prototype, or if access checks are required.
1296 assembler.BranchIfFastJSArray(array, context, &init_len, &call_runtime); 1446 assembler.BranchIfFastJSArray(
1447 array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
1448 &init_len, &call_runtime);
1297 1449
1298 assembler.Bind(&init_len); 1450 assembler.Bind(&init_len);
1299 { 1451 {
1300 // Handle case where JSArray length is not an Smi in the runtime 1452 // Handle case where JSArray length is not an Smi in the runtime
1301 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); 1453 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset);
1302 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); 1454 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime);
1303 1455
1304 len_var.Bind(assembler.SmiToWord(len)); 1456 len_var.Bind(assembler.SmiToWord(len));
1305 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), 1457 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero),
1306 &return_false, &init_k); 1458 &return_false, &init_k);
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
1727 Label init_k(&assembler), return_found(&assembler), 1879 Label init_k(&assembler), return_found(&assembler),
1728 return_not_found(&assembler), call_runtime(&assembler); 1880 return_not_found(&assembler), call_runtime(&assembler);
1729 1881
1730 Label init_len(&assembler); 1882 Label init_len(&assembler);
1731 1883
1732 index_var.Bind(intptr_zero); 1884 index_var.Bind(intptr_zero);
1733 len_var.Bind(intptr_zero); 1885 len_var.Bind(intptr_zero);
1734 1886
1735 // Take slow path if not a JSArray, if retrieving elements requires 1887 // Take slow path if not a JSArray, if retrieving elements requires
1736 // traversing prototype, or if access checks are required. 1888 // traversing prototype, or if access checks are required.
1737 assembler.BranchIfFastJSArray(array, context, &init_len, &call_runtime); 1889 assembler.BranchIfFastJSArray(
1890 array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
1891 &init_len, &call_runtime);
1738 1892
1739 assembler.Bind(&init_len); 1893 assembler.Bind(&init_len);
1740 { 1894 {
1741 // Handle case where JSArray length is not an Smi in the runtime 1895 // Handle case where JSArray length is not an Smi in the runtime
1742 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); 1896 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset);
1743 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); 1897 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime);
1744 1898
1745 len_var.Bind(assembler.SmiToWord(len)); 1899 len_var.Bind(assembler.SmiToWord(len));
1746 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), 1900 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero),
1747 &return_not_found, &init_k); 1901 &return_not_found, &init_k);
(...skipping 865 matching lines...) Expand 10 before | Expand all | Expand 10 after
2613 Runtime::kThrowIncompatibleMethodReceiver, context, 2767 Runtime::kThrowIncompatibleMethodReceiver, context,
2614 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked( 2768 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked(
2615 "Array Iterator.prototype.next", TENURED)), 2769 "Array Iterator.prototype.next", TENURED)),
2616 iterator); 2770 iterator);
2617 assembler.Return(result); 2771 assembler.Return(result);
2618 } 2772 }
2619 } 2773 }
2620 2774
2621 } // namespace internal 2775 } // namespace internal
2622 } // namespace v8 2776 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-factory.h » ('j') | src/code-stub-assembler.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698