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