Chromium Code Reviews| 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.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 Loading... | |
| 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(BuiltinDescriptor::kArgumentsCount); | |
| 269 Node* context = assembler.Parameter(BuiltinDescriptor::kContext); | |
| 270 Node* new_target = assembler.Parameter(BuiltinDescriptor::kNewTarget); | |
| 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 assembler.GotoIf(assembler.IsDictionaryMap(receiver_map), &slow); | |
| 289 | |
| 290 // Check whether the length and name properties are still present as | |
| 291 // AccessorInfo objects. In that case, their value can be recomputed even if | |
| 292 // the actual value on the object changes. | |
| 293 assembler.Comment("Check descriptor array length"); | |
| 294 Node* descriptors = | |
| 295 assembler.LoadObjectField(receiver_map, Map::kDescriptorsOffset); | |
|
Igor Sheludko
2016/12/01 16:17:40
LoadMapDescriptors()
| |
| 296 Node* descriptors_length = assembler.LoadFixedArrayBaseLength(descriptors); | |
| 297 assembler.GotoIf(assembler.SmiLessThanOrEqual(descriptors_length, | |
| 298 assembler.SmiConstant(1)), | |
| 299 &slow); | |
| 300 | |
| 301 // Check whether the length and name properties are still present as | |
| 302 // AccessorInfo objects. In that case, their value can be recomputed even if | |
| 303 // the actual value on the object changes. | |
| 304 assembler.Comment("Check name and length properties"); | |
| 305 const int length_index = JSFunction::kLengthDescriptorIndex; | |
| 306 Node* maybe_length = assembler.LoadFixedArrayElement( | |
| 307 descriptors, | |
| 308 assembler.IntPtrConstant(DescriptorArray::ToKeyIndex(length_index)), | |
|
Igor Sheludko
2016/12/01 16:17:40
The cleanup CL has landed and you can now write he
| |
| 309 CodeStubAssembler::INTPTR_PARAMETERS); | |
| 310 assembler.GotoIf( | |
| 311 assembler.WordNotEqual(maybe_length, | |
| 312 assembler.LoadRoot(Heap::klength_stringRootIndex)), | |
| 313 &slow); | |
| 314 | |
| 315 Node* maybe_length_accessor = assembler.LoadFixedArrayElement( | |
| 316 descriptors, | |
| 317 assembler.Int32Constant(DescriptorArray::ToValueIndex(length_index))); | |
| 318 assembler.GotoIf(assembler.TaggedIsSmi(maybe_length_accessor), &slow); | |
| 319 Node* length_value_map = assembler.LoadMap(maybe_length_accessor); | |
| 320 assembler.GotoUnless(assembler.IsAccessorInfoMap(length_value_map), &slow); | |
| 321 | |
| 322 const int name_index = JSFunction::kNameDescriptorIndex; | |
| 323 Node* maybe_name = assembler.LoadFixedArrayElement( | |
| 324 descriptors, | |
| 325 assembler.IntPtrConstant(DescriptorArray::ToKeyIndex(name_index)), | |
| 326 CodeStubAssembler::INTPTR_PARAMETERS); | |
| 327 assembler.GotoIf( | |
| 328 assembler.WordNotEqual(maybe_name, | |
| 329 assembler.LoadRoot(Heap::kname_stringRootIndex)), | |
| 330 &slow); | |
| 331 | |
| 332 Node* maybe_name_accessor = assembler.LoadFixedArrayElement( | |
| 333 descriptors, | |
| 334 assembler.IntPtrConstant(DescriptorArray::ToValueIndex(name_index)), | |
| 335 CodeStubAssembler::INTPTR_PARAMETERS); | |
| 336 assembler.GotoIf(assembler.TaggedIsSmi(maybe_name_accessor), &slow); | |
| 337 Node* name_value_map = assembler.LoadMap(maybe_name_accessor); | |
| 338 assembler.GotoUnless(assembler.IsAccessorInfoMap(name_value_map), &slow); | |
| 339 | |
| 340 // Choose the right bound function map based on whether the target is | |
| 341 // constructable. | |
| 342 assembler.Comment("Choose the right bound function map"); | |
| 343 Variable bound_function_map(&assembler, MachineRepresentation::kTagged); | |
| 344 Label with_constructor(&assembler); | |
| 345 CodeStubAssembler::VariableList vars({&bound_function_map}, assembler.zone()); | |
| 346 Label map_done(&assembler, vars); | |
| 347 Node* bit_field = assembler.LoadMapBitField(receiver_map); | |
| 348 int mask = static_cast<int>(1 << Map::kIsConstructor); | |
| 349 assembler.GotoIf(assembler.IsSetWord32(bit_field, mask), &with_constructor); | |
| 350 | |
| 351 Node* native_context = assembler.LoadNativeContext(context); | |
| 352 bound_function_map.Bind(assembler.LoadContextElement( | |
| 353 native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX)); | |
| 354 assembler.Goto(&map_done); | |
| 355 | |
| 356 assembler.Bind(&with_constructor); | |
| 357 bound_function_map.Bind(assembler.LoadContextElement( | |
|
Igor Sheludko
2016/12/01 16:17:40
I think native_context is not available in this bl
| |
| 358 native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX)); | |
| 359 assembler.Goto(&map_done); | |
| 360 | |
| 361 assembler.Bind(&map_done); | |
| 362 | |
| 363 // Verify that __proto__ matches that of a the target bound function. | |
| 364 assembler.Comment("Verify that __proto__ matches target bound function"); | |
| 365 Node* prototype = assembler.LoadMapPrototype(receiver_map); | |
| 366 Node* expected_prototype = | |
| 367 assembler.LoadMapPrototype(bound_function_map.value()); | |
| 368 assembler.GotoIf(assembler.WordNotEqual(prototype, expected_prototype), | |
| 369 &slow); | |
| 370 | |
| 371 // Allocate the arguments array. | |
| 372 assembler.Comment("Allocate the arguments array"); | |
| 373 Variable argument_array(&assembler, MachineRepresentation::kTagged); | |
| 374 Label empty_arguments(&assembler); | |
| 375 Label arguments_done(&assembler, &argument_array); | |
| 376 assembler.GotoIf( | |
| 377 assembler.UintPtrLessThanOrEqual(argc, assembler.IntPtrConstant(1)), | |
| 378 &empty_arguments); | |
| 379 Node* elements_length = | |
| 380 assembler.IntPtrSub(argc, assembler.IntPtrConstant(1)); | |
| 381 Node* elements = assembler.AllocateFixedArray( | |
| 382 FAST_ELEMENTS, elements_length, CodeStubAssembler::INTPTR_PARAMETERS); | |
| 383 Variable index(&assembler, MachineType::PointerRepresentation()); | |
| 384 index.Bind(assembler.IntPtrConstant(0)); | |
| 385 CodeStubAssembler::VariableList foreach_vars({&index}, assembler.zone()); | |
| 386 args.ForEach( | |
| 387 foreach_vars, | |
| 388 [elements, &index](CodeStubAssembler* assembler, compiler::Node* arg) { | |
| 389 assembler->StoreFixedArrayElement(elements, index.value(), arg, | |
| 390 UPDATE_WRITE_BARRIER, 0, | |
| 391 CodeStubAssembler::INTPTR_PARAMETERS); | |
| 392 assembler->Increment(index); | |
| 393 }, | |
| 394 assembler.IntPtrConstant(1)); | |
| 395 argument_array.Bind(elements); | |
| 396 assembler.Goto(&arguments_done); | |
| 397 | |
| 398 assembler.Bind(&empty_arguments); | |
| 399 argument_array.Bind(assembler.EmptyFixedArrayConstant()); | |
| 400 assembler.Goto(&arguments_done); | |
| 401 | |
| 402 assembler.Bind(&arguments_done); | |
| 403 | |
| 404 // Determine bound receiver. | |
| 405 assembler.Comment("Determine bound receiver"); | |
| 406 Variable bound_receiver(&assembler, MachineRepresentation::kTagged); | |
| 407 Label has_receiver(&assembler); | |
| 408 Label receiver_done(&assembler, &bound_receiver); | |
| 409 assembler.GotoIf(assembler.WordNotEqual(argc, assembler.IntPtrConstant(0)), | |
| 410 &has_receiver); | |
| 411 bound_receiver.Bind(assembler.UndefinedConstant()); | |
| 412 assembler.Goto(&receiver_done); | |
| 413 | |
| 414 assembler.Bind(&has_receiver); | |
| 415 bound_receiver.Bind(args.AtIndex(0)); | |
| 416 assembler.Goto(&receiver_done); | |
| 417 | |
| 418 assembler.Bind(&receiver_done); | |
| 419 | |
| 420 // Allocate the resulting bound function. | |
| 421 assembler.Comment("Allocate the resulting bound function"); | |
| 422 Node* bound_function = assembler.Allocate(JSBoundFunction::kSize); | |
| 423 assembler.StoreMapNoWriteBarrier(bound_function, bound_function_map.value()); | |
| 424 assembler.StoreObjectFieldNoWriteBarrier( | |
| 425 bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver); | |
| 426 assembler.StoreObjectFieldNoWriteBarrier(bound_function, | |
| 427 JSBoundFunction::kBoundThisOffset, | |
| 428 bound_receiver.value()); | |
| 429 assembler.StoreObjectFieldNoWriteBarrier( | |
| 430 bound_function, JSBoundFunction::kBoundArgumentsOffset, | |
| 431 argument_array.value()); | |
| 432 Node* empty_fixed_array = assembler.EmptyFixedArrayConstant(); | |
| 433 assembler.StoreObjectFieldNoWriteBarrier( | |
| 434 bound_function, JSObject::kPropertiesOffset, empty_fixed_array); | |
| 435 assembler.StoreObjectFieldNoWriteBarrier( | |
| 436 bound_function, JSObject::kElementsOffset, empty_fixed_array); | |
| 437 | |
| 438 args.PopAndReturn(bound_function); | |
| 439 assembler.Bind(&slow); | |
| 440 | |
| 441 Node* target = assembler.LoadFromFrame( | |
| 442 StandardFrameConstants::kFunctionOffset, MachineType::TaggedPointer()); | |
| 443 assembler.TailCallStub( | |
| 444 CodeFactory::FunctionPrototypeBind(assembler.isolate()), context, target, | |
| 445 new_target, argc); | |
| 446 } | |
| 447 | |
| 258 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub | 448 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub |
| 259 // can tailcall to the builtin directly. | 449 // can tailcall to the builtin directly. |
| 260 RUNTIME_FUNCTION(Runtime_FunctionBind) { | 450 RUNTIME_FUNCTION(Runtime_FunctionBind) { |
| 261 DCHECK_EQ(2, args.length()); | 451 DCHECK_EQ(2, args.length()); |
| 262 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); | 452 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); |
| 263 // Rewrap the arguments as builtins arguments. | 453 // Rewrap the arguments as builtins arguments. |
| 264 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; | 454 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; |
| 265 BuiltinArguments caller_args(argc, incoming->arguments() + 1); | 455 BuiltinArguments caller_args(argc, incoming->arguments() + 1); |
| 266 return DoFunctionBind(isolate, caller_args); | 456 return DoFunctionBind(isolate, caller_args); |
| 267 } | 457 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 289 | 479 |
| 290 Node* f = assembler.Parameter(0); | 480 Node* f = assembler.Parameter(0); |
| 291 Node* v = assembler.Parameter(1); | 481 Node* v = assembler.Parameter(1); |
| 292 Node* context = assembler.Parameter(4); | 482 Node* context = assembler.Parameter(4); |
| 293 Node* result = assembler.OrdinaryHasInstance(context, f, v); | 483 Node* result = assembler.OrdinaryHasInstance(context, f, v); |
| 294 assembler.Return(result); | 484 assembler.Return(result); |
| 295 } | 485 } |
| 296 | 486 |
| 297 } // namespace internal | 487 } // namespace internal |
| 298 } // namespace v8 | 488 } // namespace v8 |
| OLD | NEW |