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 |