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