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(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 Loading... | |
| 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 |
| OLD | NEW |