OLD | NEW |
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-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
10 #include "src/conversions.h" | 10 #include "src/conversions.h" |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 &it, name, it.property_attributes())); | 265 &it, name, it.property_attributes())); |
266 } | 266 } |
267 return *function; | 267 return *function; |
268 } | 268 } |
269 | 269 |
270 } // namespace | 270 } // namespace |
271 | 271 |
272 // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args ) | 272 // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args ) |
273 BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); } | 273 BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); } |
274 | 274 |
275 void Builtins::Generate_FastFunctionPrototypeBind( | 275 TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) { |
276 compiler::CodeAssemblerState* state) { | 276 Label slow(this); |
277 using compiler::Node; | |
278 typedef CodeStubAssembler::Label Label; | |
279 typedef CodeStubAssembler::Variable Variable; | |
280 | 277 |
281 CodeStubAssembler assembler(state); | 278 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); |
282 Label slow(&assembler); | 279 Node* context = Parameter(BuiltinDescriptor::kContext); |
| 280 Node* new_target = Parameter(BuiltinDescriptor::kNewTarget); |
283 | 281 |
284 Node* argc = assembler.Parameter(BuiltinDescriptor::kArgumentsCount); | 282 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); |
285 Node* context = assembler.Parameter(BuiltinDescriptor::kContext); | |
286 Node* new_target = assembler.Parameter(BuiltinDescriptor::kNewTarget); | |
287 | |
288 CodeStubArguments args(&assembler, assembler.ChangeInt32ToIntPtr(argc)); | |
289 | 283 |
290 // Check that receiver has instance type of JS_FUNCTION_TYPE | 284 // Check that receiver has instance type of JS_FUNCTION_TYPE |
291 Node* receiver = args.GetReceiver(); | 285 Node* receiver = args.GetReceiver(); |
292 assembler.GotoIf(assembler.TaggedIsSmi(receiver), &slow); | 286 GotoIf(TaggedIsSmi(receiver), &slow); |
293 | 287 |
294 Node* receiver_map = assembler.LoadMap(receiver); | 288 Node* receiver_map = LoadMap(receiver); |
295 Node* instance_type = assembler.LoadMapInstanceType(receiver_map); | 289 Node* instance_type = LoadMapInstanceType(receiver_map); |
296 assembler.GotoIf( | 290 GotoIf(Word32NotEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)), &slow); |
297 assembler.Word32NotEqual(instance_type, | |
298 assembler.Int32Constant(JS_FUNCTION_TYPE)), | |
299 &slow); | |
300 | 291 |
301 // Disallow binding of slow-mode functions. We need to figure out whether the | 292 // Disallow binding of slow-mode functions. We need to figure out whether the |
302 // length and name property are in the original state. | 293 // length and name property are in the original state. |
303 assembler.Comment("Disallow binding of slow-mode functions"); | 294 Comment("Disallow binding of slow-mode functions"); |
304 assembler.GotoIf(assembler.IsDictionaryMap(receiver_map), &slow); | 295 GotoIf(IsDictionaryMap(receiver_map), &slow); |
305 | 296 |
306 // Check whether the length and name properties are still present as | 297 // Check whether the length and name properties are still present as |
307 // AccessorInfo objects. In that case, their value can be recomputed even if | 298 // AccessorInfo objects. In that case, their value can be recomputed even if |
308 // the actual value on the object changes. | 299 // the actual value on the object changes. |
309 assembler.Comment("Check descriptor array length"); | 300 Comment("Check descriptor array length"); |
310 Node* descriptors = assembler.LoadMapDescriptors(receiver_map); | 301 Node* descriptors = LoadMapDescriptors(receiver_map); |
311 Node* descriptors_length = assembler.LoadFixedArrayBaseLength(descriptors); | 302 Node* descriptors_length = LoadFixedArrayBaseLength(descriptors); |
312 assembler.GotoIf(assembler.SmiLessThanOrEqual(descriptors_length, | 303 GotoIf(SmiLessThanOrEqual(descriptors_length, SmiConstant(1)), &slow); |
313 assembler.SmiConstant(1)), | |
314 &slow); | |
315 | 304 |
316 // Check whether the length and name properties are still present as | 305 // Check whether the length and name properties are still present as |
317 // AccessorInfo objects. In that case, their value can be recomputed even if | 306 // AccessorInfo objects. In that case, their value can be recomputed even if |
318 // the actual value on the object changes. | 307 // the actual value on the object changes. |
319 assembler.Comment("Check name and length properties"); | 308 Comment("Check name and length properties"); |
320 const int length_index = JSFunction::kLengthDescriptorIndex; | 309 const int length_index = JSFunction::kLengthDescriptorIndex; |
321 Node* maybe_length = assembler.LoadFixedArrayElement( | 310 Node* maybe_length = LoadFixedArrayElement( |
322 descriptors, DescriptorArray::ToKeyIndex(length_index)); | 311 descriptors, DescriptorArray::ToKeyIndex(length_index)); |
323 assembler.GotoIf( | 312 GotoIf(WordNotEqual(maybe_length, LoadRoot(Heap::klength_stringRootIndex)), |
324 assembler.WordNotEqual(maybe_length, | 313 &slow); |
325 assembler.LoadRoot(Heap::klength_stringRootIndex)), | |
326 &slow); | |
327 | 314 |
328 Node* maybe_length_accessor = assembler.LoadFixedArrayElement( | 315 Node* maybe_length_accessor = LoadFixedArrayElement( |
329 descriptors, DescriptorArray::ToValueIndex(length_index)); | 316 descriptors, DescriptorArray::ToValueIndex(length_index)); |
330 assembler.GotoIf(assembler.TaggedIsSmi(maybe_length_accessor), &slow); | 317 GotoIf(TaggedIsSmi(maybe_length_accessor), &slow); |
331 Node* length_value_map = assembler.LoadMap(maybe_length_accessor); | 318 Node* length_value_map = LoadMap(maybe_length_accessor); |
332 assembler.GotoIfNot(assembler.IsAccessorInfoMap(length_value_map), &slow); | 319 GotoIfNot(IsAccessorInfoMap(length_value_map), &slow); |
333 | 320 |
334 const int name_index = JSFunction::kNameDescriptorIndex; | 321 const int name_index = JSFunction::kNameDescriptorIndex; |
335 Node* maybe_name = assembler.LoadFixedArrayElement( | 322 Node* maybe_name = LoadFixedArrayElement( |
336 descriptors, DescriptorArray::ToKeyIndex(name_index)); | 323 descriptors, DescriptorArray::ToKeyIndex(name_index)); |
337 assembler.GotoIf( | 324 GotoIf(WordNotEqual(maybe_name, LoadRoot(Heap::kname_stringRootIndex)), |
338 assembler.WordNotEqual(maybe_name, | 325 &slow); |
339 assembler.LoadRoot(Heap::kname_stringRootIndex)), | |
340 &slow); | |
341 | 326 |
342 Node* maybe_name_accessor = assembler.LoadFixedArrayElement( | 327 Node* maybe_name_accessor = LoadFixedArrayElement( |
343 descriptors, DescriptorArray::ToValueIndex(name_index)); | 328 descriptors, DescriptorArray::ToValueIndex(name_index)); |
344 assembler.GotoIf(assembler.TaggedIsSmi(maybe_name_accessor), &slow); | 329 GotoIf(TaggedIsSmi(maybe_name_accessor), &slow); |
345 Node* name_value_map = assembler.LoadMap(maybe_name_accessor); | 330 Node* name_value_map = LoadMap(maybe_name_accessor); |
346 assembler.GotoIfNot(assembler.IsAccessorInfoMap(name_value_map), &slow); | 331 GotoIfNot(IsAccessorInfoMap(name_value_map), &slow); |
347 | 332 |
348 // Choose the right bound function map based on whether the target is | 333 // Choose the right bound function map based on whether the target is |
349 // constructable. | 334 // constructable. |
350 assembler.Comment("Choose the right bound function map"); | 335 Comment("Choose the right bound function map"); |
351 Variable bound_function_map(&assembler, MachineRepresentation::kTagged); | 336 Variable bound_function_map(this, MachineRepresentation::kTagged); |
352 Label with_constructor(&assembler); | 337 Label with_constructor(this); |
353 CodeStubAssembler::VariableList vars({&bound_function_map}, assembler.zone()); | 338 VariableList vars({&bound_function_map}, zone()); |
354 Node* native_context = assembler.LoadNativeContext(context); | 339 Node* native_context = LoadNativeContext(context); |
355 | 340 |
356 Label map_done(&assembler, vars); | 341 Label map_done(this, vars); |
357 Node* bit_field = assembler.LoadMapBitField(receiver_map); | 342 Node* bit_field = LoadMapBitField(receiver_map); |
358 int mask = static_cast<int>(1 << Map::kIsConstructor); | 343 int mask = static_cast<int>(1 << Map::kIsConstructor); |
359 assembler.GotoIf(assembler.IsSetWord32(bit_field, mask), &with_constructor); | 344 GotoIf(IsSetWord32(bit_field, mask), &with_constructor); |
360 | 345 |
361 bound_function_map.Bind(assembler.LoadContextElement( | 346 bound_function_map.Bind(LoadContextElement( |
362 native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX)); | 347 native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX)); |
363 assembler.Goto(&map_done); | 348 Goto(&map_done); |
364 | 349 |
365 assembler.Bind(&with_constructor); | 350 Bind(&with_constructor); |
366 bound_function_map.Bind(assembler.LoadContextElement( | 351 bound_function_map.Bind(LoadContextElement( |
367 native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX)); | 352 native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX)); |
368 assembler.Goto(&map_done); | 353 Goto(&map_done); |
369 | 354 |
370 assembler.Bind(&map_done); | 355 Bind(&map_done); |
371 | 356 |
372 // Verify that __proto__ matches that of a the target bound function. | 357 // Verify that __proto__ matches that of a the target bound function. |
373 assembler.Comment("Verify that __proto__ matches target bound function"); | 358 Comment("Verify that __proto__ matches target bound function"); |
374 Node* prototype = assembler.LoadMapPrototype(receiver_map); | 359 Node* prototype = LoadMapPrototype(receiver_map); |
375 Node* expected_prototype = | 360 Node* expected_prototype = LoadMapPrototype(bound_function_map.value()); |
376 assembler.LoadMapPrototype(bound_function_map.value()); | 361 GotoIf(WordNotEqual(prototype, expected_prototype), &slow); |
377 assembler.GotoIf(assembler.WordNotEqual(prototype, expected_prototype), | |
378 &slow); | |
379 | 362 |
380 // Allocate the arguments array. | 363 // Allocate the arguments array. |
381 assembler.Comment("Allocate the arguments array"); | 364 Comment("Allocate the arguments array"); |
382 Variable argument_array(&assembler, MachineRepresentation::kTagged); | 365 Variable argument_array(this, MachineRepresentation::kTagged); |
383 Label empty_arguments(&assembler); | 366 Label empty_arguments(this); |
384 Label arguments_done(&assembler, &argument_array); | 367 Label arguments_done(this, &argument_array); |
385 assembler.GotoIf( | 368 GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments); |
386 assembler.Uint32LessThanOrEqual(argc, assembler.Int32Constant(1)), | 369 Node* elements_length = ChangeUint32ToWord(Int32Sub(argc, Int32Constant(1))); |
387 &empty_arguments); | 370 Node* elements = AllocateFixedArray(FAST_ELEMENTS, elements_length); |
388 Node* elements_length = assembler.ChangeUint32ToWord( | 371 Variable index(this, MachineType::PointerRepresentation()); |
389 assembler.Int32Sub(argc, assembler.Int32Constant(1))); | 372 index.Bind(IntPtrConstant(0)); |
390 Node* elements = assembler.AllocateFixedArray(FAST_ELEMENTS, elements_length); | 373 VariableList foreach_vars({&index}, zone()); |
391 Variable index(&assembler, MachineType::PointerRepresentation()); | |
392 index.Bind(assembler.IntPtrConstant(0)); | |
393 CodeStubAssembler::VariableList foreach_vars({&index}, assembler.zone()); | |
394 args.ForEach(foreach_vars, | 374 args.ForEach(foreach_vars, |
395 [&assembler, elements, &index](compiler::Node* arg) { | 375 [this, elements, &index](Node* arg) { |
396 assembler.StoreFixedArrayElement(elements, index.value(), arg); | 376 StoreFixedArrayElement(elements, index.value(), arg); |
397 assembler.Increment(index); | 377 Increment(index); |
398 }, | 378 }, |
399 assembler.IntPtrConstant(1)); | 379 IntPtrConstant(1)); |
400 argument_array.Bind(elements); | 380 argument_array.Bind(elements); |
401 assembler.Goto(&arguments_done); | 381 Goto(&arguments_done); |
402 | 382 |
403 assembler.Bind(&empty_arguments); | 383 Bind(&empty_arguments); |
404 argument_array.Bind(assembler.EmptyFixedArrayConstant()); | 384 argument_array.Bind(EmptyFixedArrayConstant()); |
405 assembler.Goto(&arguments_done); | 385 Goto(&arguments_done); |
406 | 386 |
407 assembler.Bind(&arguments_done); | 387 Bind(&arguments_done); |
408 | 388 |
409 // Determine bound receiver. | 389 // Determine bound receiver. |
410 assembler.Comment("Determine bound receiver"); | 390 Comment("Determine bound receiver"); |
411 Variable bound_receiver(&assembler, MachineRepresentation::kTagged); | 391 Variable bound_receiver(this, MachineRepresentation::kTagged); |
412 Label has_receiver(&assembler); | 392 Label has_receiver(this); |
413 Label receiver_done(&assembler, &bound_receiver); | 393 Label receiver_done(this, &bound_receiver); |
414 assembler.GotoIf(assembler.Word32NotEqual(argc, assembler.Int32Constant(0)), | 394 GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver); |
415 &has_receiver); | 395 bound_receiver.Bind(UndefinedConstant()); |
416 bound_receiver.Bind(assembler.UndefinedConstant()); | 396 Goto(&receiver_done); |
417 assembler.Goto(&receiver_done); | |
418 | 397 |
419 assembler.Bind(&has_receiver); | 398 Bind(&has_receiver); |
420 bound_receiver.Bind(args.AtIndex(0)); | 399 bound_receiver.Bind(args.AtIndex(0)); |
421 assembler.Goto(&receiver_done); | 400 Goto(&receiver_done); |
422 | 401 |
423 assembler.Bind(&receiver_done); | 402 Bind(&receiver_done); |
424 | 403 |
425 // Allocate the resulting bound function. | 404 // Allocate the resulting bound function. |
426 assembler.Comment("Allocate the resulting bound function"); | 405 Comment("Allocate the resulting bound function"); |
427 Node* bound_function = assembler.Allocate(JSBoundFunction::kSize); | 406 Node* bound_function = Allocate(JSBoundFunction::kSize); |
428 assembler.StoreMapNoWriteBarrier(bound_function, bound_function_map.value()); | 407 StoreMapNoWriteBarrier(bound_function, bound_function_map.value()); |
429 assembler.StoreObjectFieldNoWriteBarrier( | 408 StoreObjectFieldNoWriteBarrier( |
430 bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver); | 409 bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver); |
431 assembler.StoreObjectFieldNoWriteBarrier(bound_function, | 410 StoreObjectFieldNoWriteBarrier(bound_function, |
432 JSBoundFunction::kBoundThisOffset, | 411 JSBoundFunction::kBoundThisOffset, |
433 bound_receiver.value()); | 412 bound_receiver.value()); |
434 assembler.StoreObjectFieldNoWriteBarrier( | 413 StoreObjectFieldNoWriteBarrier(bound_function, |
435 bound_function, JSBoundFunction::kBoundArgumentsOffset, | 414 JSBoundFunction::kBoundArgumentsOffset, |
436 argument_array.value()); | 415 argument_array.value()); |
437 Node* empty_fixed_array = assembler.EmptyFixedArrayConstant(); | 416 Node* empty_fixed_array = EmptyFixedArrayConstant(); |
438 assembler.StoreObjectFieldNoWriteBarrier( | 417 StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kPropertiesOffset, |
439 bound_function, JSObject::kPropertiesOffset, empty_fixed_array); | 418 empty_fixed_array); |
440 assembler.StoreObjectFieldNoWriteBarrier( | 419 StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset, |
441 bound_function, JSObject::kElementsOffset, empty_fixed_array); | 420 empty_fixed_array); |
442 | 421 |
443 args.PopAndReturn(bound_function); | 422 args.PopAndReturn(bound_function); |
444 assembler.Bind(&slow); | 423 Bind(&slow); |
445 | 424 |
446 Node* target = assembler.LoadFromFrame( | 425 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, |
447 StandardFrameConstants::kFunctionOffset, MachineType::TaggedPointer()); | 426 MachineType::TaggedPointer()); |
448 assembler.TailCallStub( | 427 TailCallStub(CodeFactory::FunctionPrototypeBind(isolate()), context, target, |
449 CodeFactory::FunctionPrototypeBind(assembler.isolate()), context, target, | 428 new_target, argc); |
450 new_target, argc); | |
451 } | 429 } |
452 | 430 |
453 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub | 431 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub |
454 // can tailcall to the builtin directly. | 432 // can tailcall to the builtin directly. |
455 RUNTIME_FUNCTION(Runtime_FunctionBind) { | 433 RUNTIME_FUNCTION(Runtime_FunctionBind) { |
456 DCHECK_EQ(2, args.length()); | 434 DCHECK_EQ(2, args.length()); |
457 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); | 435 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); |
458 // Rewrap the arguments as builtins arguments. | 436 // Rewrap the arguments as builtins arguments. |
459 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; | 437 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; |
460 BuiltinArguments caller_args(argc, incoming->arguments() + 1); | 438 BuiltinArguments caller_args(argc, incoming->arguments() + 1); |
461 return DoFunctionBind(isolate, caller_args); | 439 return DoFunctionBind(isolate, caller_args); |
462 } | 440 } |
463 | 441 |
464 // ES6 section 19.2.3.5 Function.prototype.toString ( ) | 442 // ES6 section 19.2.3.5 Function.prototype.toString ( ) |
465 BUILTIN(FunctionPrototypeToString) { | 443 BUILTIN(FunctionPrototypeToString) { |
466 HandleScope scope(isolate); | 444 HandleScope scope(isolate); |
467 Handle<Object> receiver = args.receiver(); | 445 Handle<Object> receiver = args.receiver(); |
468 if (receiver->IsJSBoundFunction()) { | 446 if (receiver->IsJSBoundFunction()) { |
469 return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver)); | 447 return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver)); |
470 } else if (receiver->IsJSFunction()) { | 448 } else if (receiver->IsJSFunction()) { |
471 return *JSFunction::ToString(Handle<JSFunction>::cast(receiver)); | 449 return *JSFunction::ToString(Handle<JSFunction>::cast(receiver)); |
472 } | 450 } |
473 THROW_NEW_ERROR_RETURN_FAILURE( | 451 THROW_NEW_ERROR_RETURN_FAILURE( |
474 isolate, NewTypeError(MessageTemplate::kNotGeneric, | 452 isolate, NewTypeError(MessageTemplate::kNotGeneric, |
475 isolate->factory()->NewStringFromAsciiChecked( | 453 isolate->factory()->NewStringFromAsciiChecked( |
476 "Function.prototype.toString"))); | 454 "Function.prototype.toString"))); |
477 } | 455 } |
478 | 456 |
479 // ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V ) | 457 // ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V ) |
480 void Builtins::Generate_FunctionPrototypeHasInstance( | 458 TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) { |
481 compiler::CodeAssemblerState* state) { | 459 Node* f = Parameter(0); |
482 using compiler::Node; | 460 Node* v = Parameter(1); |
483 CodeStubAssembler assembler(state); | 461 Node* context = Parameter(4); |
484 | 462 Node* result = OrdinaryHasInstance(context, f, v); |
485 Node* f = assembler.Parameter(0); | 463 Return(result); |
486 Node* v = assembler.Parameter(1); | |
487 Node* context = assembler.Parameter(4); | |
488 Node* result = assembler.OrdinaryHasInstance(context, f, v); | |
489 assembler.Return(result); | |
490 } | 464 } |
491 | 465 |
492 } // namespace internal | 466 } // namespace internal |
493 } // namespace v8 | 467 } // namespace v8 |
OLD | NEW |