1// Copyright 2020 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5namespace function { 6 7extern macro OrdinaryHasInstance(Context, Object, Object): JSAny; 8 9// ES6 section 19.2.3.6 Function.prototype[@@hasInstance] 10javascript builtin FunctionPrototypeHasInstance( 11 js-implicit context: NativeContext, receiver: JSAny)(value: JSAny): JSAny { 12 return OrdinaryHasInstance(context, receiver, value); 13} 14 15extern transitioning builtin 16FunctionPrototypeBind(implicit context: Context)( 17 JSFunction, JSAny, int32): JSAny; 18 19const kLengthDescriptorIndex: constexpr int32 20 generates 'JSFunctionOrBoundFunctionOrWrappedFunction::kLengthDescriptorIndex' 21 ; 22const kNameDescriptorIndex: constexpr int32 23 generates 'JSFunctionOrBoundFunctionOrWrappedFunction::kNameDescriptorIndex' 24 ; 25const kMinDescriptorsForFastBindAndWrap: constexpr int31 26 generates 'JSFunction::kMinDescriptorsForFastBindAndWrap'; 27 28macro CheckAccessor(implicit context: Context)( 29 array: DescriptorArray, index: constexpr int32, 30 name: Name): void labels Slow { 31 const descriptor: DescriptorEntry = array.descriptors[index]; 32 const key: Name|Undefined = descriptor.key; 33 if (!TaggedEqual(key, name)) goto Slow; 34 35 // The descriptor value must be an AccessorInfo. 36 Cast<AccessorInfo>(descriptor.value) otherwise goto Slow; 37} 38 39// ES6 section 19.2.3.2 Function.prototype.bind 40transitioning javascript builtin 41FastFunctionPrototypeBind( 42 js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny, 43 target: JSFunction)(...arguments): JSAny { 44 const argc: intptr = arguments.actual_count; 45 try { 46 typeswitch (receiver) { 47 case (fn: JSFunction|JSBoundFunction|JSWrappedFunction): { 48 // Disallow binding of slow-mode functions. We need to figure out 49 // whether the length and name property are in the original state. 50 Comment('Disallow binding of slow-mode functions'); 51 if (IsDictionaryMap(fn.map)) goto Slow; 52 53 // Check whether the length and name properties are still present as 54 // AccessorInfo objects. If so, their value can be recomputed even if 55 // the actual value on the object changes. 56 57 if (fn.map.bit_field3.number_of_own_descriptors < 58 kMinDescriptorsForFastBindAndWrap) { 59 goto Slow; 60 } 61 62 const descriptors: DescriptorArray = fn.map.instance_descriptors; 63 CheckAccessor( 64 descriptors, kLengthDescriptorIndex, LengthStringConstant()) 65 otherwise Slow; 66 CheckAccessor(descriptors, kNameDescriptorIndex, NameStringConstant()) 67 otherwise Slow; 68 69 // Choose the right bound function map based on whether the target is 70 // constructable. 71 72 const boundFunctionMap: Map = 73 IsConstructor(fn) ? 74 *NativeContextSlot( 75 ContextSlot::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX) : 76 *NativeContextSlot(ContextSlot:: 77 BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX); 78 79 // Verify that prototype matches that of the target bound function. 80 81 if (fn.map.prototype != boundFunctionMap.prototype) goto Slow; 82 83 // Allocate the arguments array. 84 85 const argumentsArray = arguments.length <= 1 ? 86 kEmptyFixedArray : 87 NewFixedArray( 88 arguments.length - 1, ArgumentsIterator{arguments, current: 1}); 89 90 const boundReceiver: JSAny = arguments[0]; 91 92 const result = new JSBoundFunction{ 93 map: boundFunctionMap, 94 properties_or_hash: kEmptyFixedArray, 95 elements: kEmptyFixedArray, 96 bound_target_function: fn, 97 bound_this: boundReceiver, 98 bound_arguments: argumentsArray 99 }; 100 return result; 101 } 102 103 case (JSAny): { 104 goto Slow; 105 } 106 } 107 } label Slow { 108 tail FunctionPrototypeBind( 109 LoadTargetFromFrame(), newTarget, Convert<int32>(argc)); 110 } 111} 112} // namespace function 113