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

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: Fix GC mole Created 4 years 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.h ('k') | src/code-factory.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 Variable arg_index(&assembler, MachineType::PointerRepresentation());
185 Label default_label(&assembler, &arg_index);
186 Label smi_transition(&assembler);
187 Label object_push_pre(&assembler);
188 Label object_push(&assembler, &arg_index);
189 Label double_push(&assembler, &arg_index);
190 Label double_transition(&assembler);
191 Label runtime(&assembler, Label::kDeferred);
180 192
181 // TODO(verwaest): This is a temporary helper until the FastArrayPush stub can 193 Node* argc = assembler.Parameter(1);
182 // tailcall to the builtin directly. 194 Node* context = assembler.Parameter(2);
183 RUNTIME_FUNCTION(Runtime_ArrayPush) { 195 Node* new_target = assembler.Parameter(0);
184 DCHECK_EQ(2, args.length()); 196
185 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); 197 CodeStubArguments args(&assembler, argc);
186 // Rewrap the arguments as builtins arguments. 198 Node* receiver = args.GetReceiver();
187 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; 199 Node* kind = nullptr;
188 BuiltinArguments caller_args(argc, incoming->arguments() + 1); 200
189 return DoArrayPush(isolate, caller_args); 201 Label fast(&assembler);
202 {
203 assembler.BranchIfFastJSArray(
204 receiver, context, CodeStubAssembler::FastJSArrayAccessMode::ANY_ACCESS,
205 &fast, &runtime);
206 }
207
208 assembler.Bind(&fast);
209 {
210 // Disallow pushing onto prototypes. It might be the JSArray prototype.
211 // Disallow pushing onto non-extensible objects.
212 assembler.Comment("Disallow pushing onto prototypes");
213 Node* map = assembler.LoadMap(receiver);
214 Node* bit_field2 = assembler.LoadMapBitField2(map);
215 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
216 (1 << Map::kIsExtensible);
217 Node* test = assembler.Word32And(bit_field2, assembler.Int32Constant(mask));
218 assembler.GotoIf(
219 assembler.Word32NotEqual(
220 test, assembler.Int32Constant(1 << Map::kIsExtensible)),
221 &runtime);
222
223 // Disallow pushing onto arrays in dictionary named property mode. We need
224 // to figure out whether the length property is still writable.
225 assembler.Comment(
226 "Disallow pushing onto arrays in dictionary named property mode");
227 Node* bit_field3 = assembler.LoadMapBitField3(map);
228 assembler.GotoIf(assembler.IsSetWord32<Map::DictionaryMap>(bit_field3),
229 &runtime);
230
231 // Check whether the length property is writable. The length property is the
232 // only default named property on arrays. It's nonconfigurable, hence is
233 // guaranteed to stay the first property.
234 Node* descriptors = assembler.LoadMapDescriptors(map);
235 Node* details = assembler.LoadFixedArrayElement(
236 descriptors,
237 assembler.Int32Constant(DescriptorArray::ToDetailsIndex(0)));
238 mask = READ_ONLY << PropertyDetails::AttributesField::kShift;
239 Node* mask_node = assembler.SmiConstant(mask);
240 test = assembler.WordAnd(details, mask_node);
241 assembler.GotoIf(assembler.WordEqual(test, mask_node), &runtime);
242
243 arg_index.Bind(assembler.IntPtrConstant(0));
244 kind = assembler.DecodeWord32<Map::ElementsKindBits>(bit_field2);
245
246 assembler.GotoIf(
247 assembler.IntPtrGreaterThan(
248 kind, assembler.IntPtrConstant(FAST_HOLEY_SMI_ELEMENTS)),
249 &object_push_pre);
250
251 Node* new_length = assembler.BuildAppendJSArray(
252 FAST_SMI_ELEMENTS, context, receiver, args, arg_index, &smi_transition);
253 args.PopAndReturn(new_length);
254 }
255
256 // If the argument is not a smi, then use a heavyweight SetProperty to
257 // transition the array for only the single next element. If the argument is
258 // a smi, the failure is due to some other reason and we should fall back on
259 // the most generic implementation for the rest of the array.
260 assembler.Bind(&smi_transition);
261 {
262 Node* arg = args.AtIndex(arg_index.value());
263 assembler.GotoIf(assembler.TaggedIsSmi(arg), &default_label);
264 Node* length = assembler.LoadJSArrayLength(receiver);
265 // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
266 // calling into the runtime to do the elements transition is overkill.
267 assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
268 assembler.SmiConstant(STRICT));
269 assembler.Increment(arg_index);
270 assembler.GotoIfNotNumber(arg, &object_push);
271 assembler.Goto(&double_push);
272 }
273
274 assembler.Bind(&object_push_pre);
275 {
276 assembler.Branch(assembler.IntPtrGreaterThan(
277 kind, assembler.IntPtrConstant(FAST_HOLEY_ELEMENTS)),
278 &double_push, &object_push);
279 }
280
281 assembler.Bind(&object_push);
282 {
283 Node* new_length = assembler.BuildAppendJSArray(
284 FAST_ELEMENTS, context, receiver, args, arg_index, &default_label);
285 args.PopAndReturn(new_length);
286 }
287
288 assembler.Bind(&double_push);
289 {
290 Node* new_length =
291 assembler.BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver,
292 args, arg_index, &double_transition);
293 args.PopAndReturn(new_length);
294 }
295
296 // If the argument is not a double, then use a heavyweight SetProperty to
297 // transition the array for only the single next element. If the argument is
298 // a double, the failure is due to some other reason and we should fall back
299 // on the most generic implementation for the rest of the array.
300 assembler.Bind(&double_transition);
301 {
302 Node* arg = args.AtIndex(arg_index.value());
303 assembler.GotoIfNumber(arg, &default_label);
304 Node* length = assembler.LoadJSArrayLength(receiver);
305 // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
306 // calling into the runtime to do the elements transition is overkill.
307 assembler.CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
308 assembler.SmiConstant(STRICT));
309 assembler.Increment(arg_index);
310 assembler.Goto(&object_push);
311 }
312
313 // Fallback that stores un-processed arguments using the full, heavyweight
314 // SetProperty machinery.
315 assembler.Bind(&default_label);
316 {
317 args.ForEach(
318 [receiver, context, &arg_index](CodeStubAssembler* assembler,
319 Node* arg) {
320 Node* length = assembler->LoadJSArrayLength(receiver);
321 assembler->CallRuntime(Runtime::kSetProperty, context, receiver,
322 length, arg, assembler->SmiConstant(STRICT));
323 },
324 arg_index.value());
325 args.PopAndReturn(assembler.LoadJSArrayLength(receiver));
326 }
327
328 assembler.Bind(&runtime);
329 {
330 Node* target = assembler.LoadFromFrame(
331 StandardFrameConstants::kFunctionOffset, MachineType::TaggedPointer());
332 assembler.TailCallStub(CodeFactory::ArrayPush(assembler.isolate()), context,
333 target, new_target, argc);
334 }
190 } 335 }
191 336
192 BUILTIN(ArrayPop) { 337 BUILTIN(ArrayPop) {
193 HandleScope scope(isolate); 338 HandleScope scope(isolate);
194 Handle<Object> receiver = args.receiver(); 339 Handle<Object> receiver = args.receiver();
195 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) { 340 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) {
196 return CallJsIntrinsic(isolate, isolate->array_pop(), args); 341 return CallJsIntrinsic(isolate, isolate->array_pop(), args);
197 } 342 }
198 343
199 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 344 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
(...skipping 1087 matching lines...) Expand 10 before | Expand all | Expand 10 after
1287 Label init_k(&assembler), return_true(&assembler), return_false(&assembler), 1432 Label init_k(&assembler), return_true(&assembler), return_false(&assembler),
1288 call_runtime(&assembler); 1433 call_runtime(&assembler);
1289 1434
1290 Label init_len(&assembler); 1435 Label init_len(&assembler);
1291 1436
1292 index_var.Bind(intptr_zero); 1437 index_var.Bind(intptr_zero);
1293 len_var.Bind(intptr_zero); 1438 len_var.Bind(intptr_zero);
1294 1439
1295 // Take slow path if not a JSArray, if retrieving elements requires 1440 // Take slow path if not a JSArray, if retrieving elements requires
1296 // traversing prototype, or if access checks are required. 1441 // traversing prototype, or if access checks are required.
1297 assembler.BranchIfFastJSArray(array, context, &init_len, &call_runtime); 1442 assembler.BranchIfFastJSArray(
1443 array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
1444 &init_len, &call_runtime);
1298 1445
1299 assembler.Bind(&init_len); 1446 assembler.Bind(&init_len);
1300 { 1447 {
1301 // Handle case where JSArray length is not an Smi in the runtime 1448 // Handle case where JSArray length is not an Smi in the runtime
1302 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); 1449 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset);
1303 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); 1450 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime);
1304 1451
1305 len_var.Bind(assembler.SmiToWord(len)); 1452 len_var.Bind(assembler.SmiToWord(len));
1306 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), 1453 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero),
1307 &return_false, &init_k); 1454 &return_false, &init_k);
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
1728 Label init_k(&assembler), return_found(&assembler), 1875 Label init_k(&assembler), return_found(&assembler),
1729 return_not_found(&assembler), call_runtime(&assembler); 1876 return_not_found(&assembler), call_runtime(&assembler);
1730 1877
1731 Label init_len(&assembler); 1878 Label init_len(&assembler);
1732 1879
1733 index_var.Bind(intptr_zero); 1880 index_var.Bind(intptr_zero);
1734 len_var.Bind(intptr_zero); 1881 len_var.Bind(intptr_zero);
1735 1882
1736 // Take slow path if not a JSArray, if retrieving elements requires 1883 // Take slow path if not a JSArray, if retrieving elements requires
1737 // traversing prototype, or if access checks are required. 1884 // traversing prototype, or if access checks are required.
1738 assembler.BranchIfFastJSArray(array, context, &init_len, &call_runtime); 1885 assembler.BranchIfFastJSArray(
1886 array, context, CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ,
1887 &init_len, &call_runtime);
1739 1888
1740 assembler.Bind(&init_len); 1889 assembler.Bind(&init_len);
1741 { 1890 {
1742 // Handle case where JSArray length is not an Smi in the runtime 1891 // Handle case where JSArray length is not an Smi in the runtime
1743 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset); 1892 Node* len = assembler.LoadObjectField(array, JSArray::kLengthOffset);
1744 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime); 1893 assembler.GotoUnless(assembler.TaggedIsSmi(len), &call_runtime);
1745 1894
1746 len_var.Bind(assembler.SmiToWord(len)); 1895 len_var.Bind(assembler.SmiToWord(len));
1747 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero), 1896 assembler.Branch(assembler.WordEqual(len_var.value(), intptr_zero),
1748 &return_not_found, &init_k); 1897 &return_not_found, &init_k);
(...skipping 864 matching lines...) Expand 10 before | Expand all | Expand 10 after
2613 Runtime::kThrowIncompatibleMethodReceiver, context, 2762 Runtime::kThrowIncompatibleMethodReceiver, context,
2614 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked( 2763 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked(
2615 "Array Iterator.prototype.next", TENURED)), 2764 "Array Iterator.prototype.next", TENURED)),
2616 iterator); 2765 iterator);
2617 assembler.Return(result); 2766 assembler.Return(result);
2618 } 2767 }
2619 } 2768 }
2620 2769
2621 } // namespace internal 2770 } // namespace internal
2622 } // namespace v8 2771 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698