| 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 |