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

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

Issue 2532483002: [stubs] Port FastFunctionBindStub to TF (Closed)
Patch Set: Fix function length 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/compiler.h" 9 #include "src/compiler.h"
9 #include "src/string-builder.h" 10 #include "src/string-builder.h"
10 11
11 namespace v8 { 12 namespace v8 {
12 namespace internal { 13 namespace internal {
13 14
14 namespace { 15 namespace {
15 16
16 // ES6 section 19.2.1.1.1 CreateDynamicFunction 17 // ES6 section 19.2.1.1.1 CreateDynamicFunction
17 MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate, 18 MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate,
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 &it, name, it.property_attributes())); 249 &it, name, it.property_attributes()));
249 } 250 }
250 return *function; 251 return *function;
251 } 252 }
252 253
253 } // namespace 254 } // namespace
254 255
255 // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args ) 256 // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args )
256 BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); } 257 BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); }
257 258
259 void Builtins::Generate_FastFunctionPrototypeBind(
260 compiler::CodeAssemblerState* state) {
261 using compiler::Node;
262 typedef CodeStubAssembler::Label Label;
263 typedef CodeStubAssembler::Variable Variable;
264
265 CodeStubAssembler assembler(state);
266 Label slow(&assembler);
267
268 Node* argc = assembler.Parameter(1);
Igor Sheludko 2016/12/01 11:50:41 1) BuiltinDescriptor::kArgumentsCount? 2) argc is
danno 2016/12/01 15:43:33 Done.
269 Node* context = assembler.Parameter(2);
Igor Sheludko 2016/12/01 11:50:40 BuiltinDescriptor::kContext
danno 2016/12/01 15:43:33 Done.
270 Node* new_target = assembler.Parameter(0);
Igor Sheludko 2016/12/01 11:50:40 BuiltinDescriptor::kNewTarget
danno 2016/12/01 15:43:33 Done.
271
272 CodeStubArguments args(&assembler, argc);
273
274 // Check that receiver has instance type of JS_FUNCTION_TYPE
275 Node* receiver = args.GetReceiver();
276 assembler.GotoIf(assembler.TaggedIsSmi(receiver), &slow);
277
278 Node* receiver_map = assembler.LoadMap(receiver);
279 Node* instance_type = assembler.LoadMapInstanceType(receiver_map);
280 assembler.GotoIf(
281 assembler.Word32NotEqual(instance_type,
282 assembler.Int32Constant(JS_FUNCTION_TYPE)),
283 &slow);
284
285 // Disallow binding of slow-mode functions. We need to figure out whether the
286 // length and name property are in the original state.
287 assembler.Comment("Disallow binding of slow-mode functions");
288 Node* bit_field3 = assembler.LoadObjectField(
289 receiver_map, Map::kBitField3Offset, MachineType::Uint32());
290 int mask = static_cast<int>(Map::DictionaryMap::kMask);
291 Node* mask_node = assembler.Int32Constant(mask);
292 Node* test = assembler.Word32And(bit_field3, mask_node);
293 assembler.GotoIf(assembler.Word32Equal(test, mask_node), &slow);
Igor Sheludko 2016/12/01 11:50:40 You can use IsDictionaryMap(receiver_map) here.
danno 2016/12/01 15:43:33 Done.
294
295 // Check whether the length and name properties are still present as
296 // AccessorInfo objects. In that case, their value can be recomputed even if
297 // the actual value on the object changes.
298 assembler.Comment("Check descriptor array length");
299 Node* descriptors =
300 assembler.LoadObjectField(receiver_map, Map::kDescriptorsOffset);
301 CodeStubAssembler::ParameterMode mode = assembler.OptimalParameterMode();
Igor Sheludko 2016/12/01 11:50:40 descriptors_length is not used anywhere else so yo
danno 2016/12/01 15:43:32 Done.
302 Node* descriptors_length = assembler.UntagParameter(
303 assembler.LoadFixedArrayBaseLength(descriptors), mode);
304 assembler.GotoIf(
305 assembler.IntPtrLessThanOrEqual(descriptors_length,
Igor Sheludko 2016/12/01 11:50:40 I prefer to use unsigned comparisons for lengths.
danno 2016/12/01 15:43:33 Acknowledged.
306 assembler.IntPtrOrSmiConstant(1, mode)),
307 &slow);
308
309 // Check whether the length and name properties are still present as
310 // AccessorInfo objects. In that case, their value can be recomputed even if
311 // the actual value on the object changes.
312 assembler.Comment("Check name and length properties");
313 const int length_index = JSFunction::kLengthDescriptorIndex;
314 Node* maybe_length = assembler.LoadFixedArrayElement(
315 descriptors,
316 assembler.Int32Constant(DescriptorArray::ToKeyIndex(length_index)));
Igor Sheludko 2016/12/01 11:50:40 Use IntPtrConstant() and pass INTPTR_PARAMETERS mo
danno 2016/12/01 15:43:33 Done.
317 assembler.GotoIf(
318 assembler.WordNotEqual(
319 maybe_length, assembler.HeapConstant(
Igor Sheludko 2016/12/01 11:50:40 LoadRoot
danno 2016/12/01 15:43:33 Done.
320 assembler.isolate()->factory()->length_string())),
321 &slow);
322
323 Node* maybe_length_accessor = assembler.LoadFixedArrayElement(
324 descriptors,
325 assembler.Int32Constant(DescriptorArray::ToValueIndex(length_index)));
326 assembler.GotoIf(assembler.TaggedIsSmi(maybe_length_accessor), &slow);
327 Node* length_value_map = assembler.LoadMap(maybe_length_accessor);
328 assembler.GotoIf(
Igor Sheludko 2016/12/01 11:50:40 GotoUnless(IsAccessorInfoMap(length_value_map), ..
danno 2016/12/01 15:43:33 Done.
329 assembler.WordNotEqual(
330 length_value_map,
331 assembler.HeapConstant(
332 assembler.isolate()->factory()->accessor_info_map())),
333 &slow);
334
335 const int name_index = JSFunction::kNameDescriptorIndex;
336 Node* maybe_name = assembler.LoadFixedArrayElement(
337 descriptors,
338 assembler.Int32Constant(DescriptorArray::ToKeyIndex(name_index)));
Igor Sheludko 2016/12/01 11:50:40 Same here.
danno 2016/12/01 15:43:33 Done.
339 assembler.GotoIf(
340 assembler.WordNotEqual(
341 maybe_name, assembler.HeapConstant(
Igor Sheludko 2016/12/01 11:50:40 LoadRoot.
danno 2016/12/01 15:43:33 Done.
342 assembler.isolate()->factory()->name_string())),
343 &slow);
344
345 Node* maybe_name_accessor = assembler.LoadFixedArrayElement(
346 descriptors,
347 assembler.Int32Constant(DescriptorArray::ToValueIndex(name_index)));
Igor Sheludko 2016/12/01 11:50:40 Same here.
danno 2016/12/01 15:43:33 Done.
348 assembler.GotoIf(assembler.TaggedIsSmi(maybe_name_accessor), &slow);
349 Node* name_value_map = assembler.LoadMap(maybe_name_accessor);
350 assembler.GotoIf(
Igor Sheludko 2016/12/01 11:50:40 Same here.
danno 2016/12/01 15:43:33 Done.
351 assembler.WordNotEqual(
352 name_value_map,
353 assembler.HeapConstant(
354 assembler.isolate()->factory()->accessor_info_map())),
355 &slow);
356
357 // Choose the right bound function map based on whether the target is
358 // constructable.
359 assembler.Comment("Choose the right bound function map");
360 Variable bound_function_map(&assembler, MachineRepresentation::kTagged);
361 Label with_constructor(&assembler);
362 CodeStubAssembler::VariableList vars({&bound_function_map}, assembler.zone());
363 Label map_done(&assembler, vars);
364 Node* bit_field = assembler.LoadObjectField(
Igor Sheludko 2016/12/01 11:50:40 LoadMapBitField
danno 2016/12/01 15:43:32 Done.
365 receiver_map, Map::kBitFieldOffset, MachineType::Pointer());
366 mask = static_cast<int>(1 << Map::kIsConstructor);
367 mask_node = assembler.IntPtrConstant(mask);
368 Node* bits = assembler.WordAnd(bit_field, mask_node);
369 Node* native_context = assembler.LoadNativeContext(context);
370 assembler.GotoIf(assembler.Word32Equal(bits, mask_node), &with_constructor);
Igor Sheludko 2016/12/01 11:50:40 IsSetWord32(bit_field, mask)
danno 2016/12/01 15:43:33 Done.
371
372 bound_function_map.Bind(assembler.LoadContextElement(
373 native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
374 assembler.Goto(&map_done);
375
376 assembler.Bind(&with_constructor);
377 bound_function_map.Bind(assembler.LoadContextElement(
378 native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
379 assembler.Goto(&map_done);
380
381 assembler.Bind(&map_done);
382
383 // Verify that __proto__ matches that of a the target bound function.
384 assembler.Comment("Verify that __proto__ matches target bound function");
385 Node* prototype = assembler.LoadMapPrototype(receiver_map);
386 Node* expected_prototype =
387 assembler.LoadMapPrototype(bound_function_map.value());
388 assembler.GotoIf(assembler.WordNotEqual(prototype, expected_prototype),
389 &slow);
390
391 // Allocate the arguments array.
392 assembler.Comment("Allocate the arguments array");
393 Variable argument_array(&assembler, MachineRepresentation::kTagged);
394 Label empty_arguments(&assembler);
395 Label arguments_done(&assembler, &argument_array);
396 assembler.GotoIf(
397 assembler.IntPtrLessThanOrEqual(argc, assembler.IntPtrConstant(1)),
Igor Sheludko 2016/12/01 11:50:40 I'd use unsigned comparison.
danno 2016/12/01 15:43:33 Done.
398 &empty_arguments);
399 Node* one = assembler.IntPtrConstant(1);
Igor Sheludko 2016/12/01 11:50:40 Please either use this in the whole function or in
danno 2016/12/01 15:43:33 Done.
400 Node* elements_length = assembler.IntPtrSub(argc, one);
401 Node* elements = assembler.AllocateFixedArray(
402 FAST_ELEMENTS, elements_length, CodeStubAssembler::INTPTR_PARAMETERS);
403 Variable index(&assembler, MachineType::PointerRepresentation());
404 index.Bind(assembler.IntPtrConstant(0));
405 CodeStubAssembler::VariableList foreach_vars({&index}, assembler.zone());
406 args.ForEach(
407 foreach_vars,
408 [elements, &index](CodeStubAssembler* assembler, compiler::Node* arg) {
409 assembler->StoreFixedArrayElement(elements, index.value(), arg,
410 SKIP_WRITE_BARRIER, 0,
Igor Sheludko 2016/12/01 11:50:40 I don't think we can skip WB here.
danno 2016/12/01 15:43:33 Done.
411 CodeStubAssembler::INTPTR_PARAMETERS);
412 assembler->Increment(index);
413 },
414 one);
415 argument_array.Bind(elements);
416 assembler.Goto(&arguments_done);
417
418 assembler.Bind(&empty_arguments);
419 argument_array.Bind(assembler.LoadRoot(Heap::kEmptyFixedArrayRootIndex));
Igor Sheludko 2016/12/01 11:50:40 EmptyFixedArrayConstant() BTW, feel free to add m
danno 2016/12/01 15:43:33 Done.
420 assembler.Goto(&arguments_done);
421
422 assembler.Bind(&arguments_done);
423
424 // Determine bound receiver.
425 assembler.Comment("Determine bound receiver");
426 Variable bound_receiver(&assembler, MachineRepresentation::kTagged);
427 Label has_receiver(&assembler);
428 Label receiver_done(&assembler, &bound_receiver);
429 assembler.GotoIf(assembler.WordNotEqual(argc, assembler.IntPtrConstant(0)),
430 &has_receiver);
431 bound_receiver.Bind(assembler.LoadRoot(Heap::kUndefinedValueRootIndex));
Igor Sheludko 2016/12/01 11:50:40 UndefinedConstant()
danno 2016/12/01 15:43:33 Done.
432 assembler.Goto(&receiver_done);
433
434 assembler.Bind(&has_receiver);
435 bound_receiver.Bind(args.AtIndex(0));
436 assembler.Goto(&receiver_done);
437
438 assembler.Bind(&receiver_done);
439
440 // Allocate the resulting bound function.
441 assembler.Comment("Allocate the resulting bound function");
442 Node* bound_function = assembler.Allocate(JSBoundFunction::kSize);
443 assembler.StoreMapNoWriteBarrier(bound_function, bound_function_map.value());
Igor Sheludko 2016/12/01 11:50:40 We can't skip this WB. The incremental part of the
Igor Sheludko 2016/12/01 13:46:07 Please ignore this. I was wrong here...
danno 2016/12/01 15:43:32 Acknowledged.
danno 2016/12/01 15:43:33 Done.
444 assembler.StoreObjectFieldNoWriteBarrier(
Igor Sheludko 2016/12/01 11:50:40 We can't skip WB here.
Igor Sheludko 2016/12/01 13:46:07 ... and here ...
445 bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver);
446 assembler.StoreObjectFieldNoWriteBarrier(bound_function,
Igor Sheludko 2016/12/01 11:50:40 and here
Igor Sheludko 2016/12/01 13:46:07 ... and here ...
danno 2016/12/01 15:43:32 Acknowledged.
447 JSBoundFunction::kBoundThisOffset,
448 bound_receiver.value());
449 assembler.StoreObjectFieldNoWriteBarrier(
Igor Sheludko 2016/12/01 11:50:40 This one we could probably skip if arguments_array
Igor Sheludko 2016/12/01 13:46:07 ... and here.
danno 2016/12/01 15:43:33 Acknowledged.
450 bound_function, JSBoundFunction::kBoundArgumentsOffset,
451 argument_array.value());
452 Node* empty_fixed_array = assembler.LoadRoot(Heap::kEmptyFixedArrayRootIndex);
Igor Sheludko 2016/12/01 11:50:40 EmptyFixedArrayConstant();
danno 2016/12/01 15:43:33 Done.
453 assembler.StoreObjectFieldNoWriteBarrier(
454 bound_function, JSObject::kPropertiesOffset, empty_fixed_array);
455 assembler.StoreObjectFieldNoWriteBarrier(
456 bound_function, JSObject::kElementsOffset, empty_fixed_array);
457
458 args.PopAndReturn(bound_function);
459 assembler.Bind(&slow);
460
461 Node* target = assembler.LoadFromFrame(
462 StandardFrameConstants::kFunctionOffset, MachineType::TaggedPointer());
463 assembler.TailCallStub(
464 CodeFactory::FunctionPrototypeBind(assembler.isolate()), context, target,
465 new_target, argc);
Igor Sheludko 2016/12/01 11:50:39 Note: this |argc| must be Int32 again.
danno 2016/12/01 15:43:33 Done.
466 }
467
258 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub 468 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub
259 // can tailcall to the builtin directly. 469 // can tailcall to the builtin directly.
260 RUNTIME_FUNCTION(Runtime_FunctionBind) { 470 RUNTIME_FUNCTION(Runtime_FunctionBind) {
261 DCHECK_EQ(2, args.length()); 471 DCHECK_EQ(2, args.length());
262 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); 472 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]);
263 // Rewrap the arguments as builtins arguments. 473 // Rewrap the arguments as builtins arguments.
264 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; 474 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver;
265 BuiltinArguments caller_args(argc, incoming->arguments() + 1); 475 BuiltinArguments caller_args(argc, incoming->arguments() + 1);
266 return DoFunctionBind(isolate, caller_args); 476 return DoFunctionBind(isolate, caller_args);
267 } 477 }
(...skipping 21 matching lines...) Expand all
289 499
290 Node* f = assembler.Parameter(0); 500 Node* f = assembler.Parameter(0);
291 Node* v = assembler.Parameter(1); 501 Node* v = assembler.Parameter(1);
292 Node* context = assembler.Parameter(4); 502 Node* context = assembler.Parameter(4);
293 Node* result = assembler.OrdinaryHasInstance(context, f, v); 503 Node* result = assembler.OrdinaryHasInstance(context, f, v);
294 assembler.Return(result); 504 assembler.Return(result);
295 } 505 }
296 506
297 } // namespace internal 507 } // namespace internal
298 } // namespace v8 508 } // 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