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