// Copyright 2020 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. namespace function { extern macro OrdinaryHasInstance(Context, Object, Object): JSAny; // ES6 section 19.2.3.6 Function.prototype[@@hasInstance] javascript builtin FunctionPrototypeHasInstance( js-implicit context: NativeContext, receiver: JSAny)(value: JSAny): JSAny { return OrdinaryHasInstance(context, receiver, value); } extern transitioning builtin FunctionPrototypeBind(implicit context: Context)( JSFunction, JSAny, int32): JSAny; const kLengthDescriptorIndex: constexpr int32 generates 'JSFunctionOrBoundFunctionOrWrappedFunction::kLengthDescriptorIndex' ; const kNameDescriptorIndex: constexpr int32 generates 'JSFunctionOrBoundFunctionOrWrappedFunction::kNameDescriptorIndex' ; const kMinDescriptorsForFastBindAndWrap: constexpr int31 generates 'JSFunction::kMinDescriptorsForFastBindAndWrap'; macro CheckAccessor(implicit context: Context)( array: DescriptorArray, index: constexpr int32, name: Name): void labels Slow { const descriptor: DescriptorEntry = array.descriptors[index]; const key: Name|Undefined = descriptor.key; if (!TaggedEqual(key, name)) goto Slow; // The descriptor value must be an AccessorInfo. Cast(descriptor.value) otherwise goto Slow; } // ES6 section 19.2.3.2 Function.prototype.bind transitioning javascript builtin FastFunctionPrototypeBind( js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny, target: JSFunction)(...arguments): JSAny { const argc: intptr = arguments.actual_count; try { typeswitch (receiver) { case (fn: JSFunction|JSBoundFunction|JSWrappedFunction): { // Disallow binding of slow-mode functions. We need to figure out // whether the length and name property are in the original state. Comment('Disallow binding of slow-mode functions'); if (IsDictionaryMap(fn.map)) goto Slow; // Check whether the length and name properties are still present as // AccessorInfo objects. If so, their value can be recomputed even if // the actual value on the object changes. if (fn.map.bit_field3.number_of_own_descriptors < kMinDescriptorsForFastBindAndWrap) { goto Slow; } const descriptors: DescriptorArray = fn.map.instance_descriptors; CheckAccessor( descriptors, kLengthDescriptorIndex, LengthStringConstant()) otherwise Slow; CheckAccessor(descriptors, kNameDescriptorIndex, NameStringConstant()) otherwise Slow; // Choose the right bound function map based on whether the target is // constructable. const boundFunctionMap: Map = IsConstructor(fn) ? *NativeContextSlot( ContextSlot::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX) : *NativeContextSlot(ContextSlot:: BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX); // Verify that prototype matches that of the target bound function. if (fn.map.prototype != boundFunctionMap.prototype) goto Slow; // Allocate the arguments array. const argumentsArray = arguments.length <= 1 ? kEmptyFixedArray : NewFixedArray( arguments.length - 1, ArgumentsIterator{arguments, current: 1}); const boundReceiver: JSAny = arguments[0]; const result = new JSBoundFunction{ map: boundFunctionMap, properties_or_hash: kEmptyFixedArray, elements: kEmptyFixedArray, bound_target_function: fn, bound_this: boundReceiver, bound_arguments: argumentsArray }; return result; } case (JSAny): { goto Slow; } } } label Slow { tail FunctionPrototypeBind( LoadTargetFromFrame(), newTarget, Convert(argc)); } } } // namespace function