| // 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 'JSFunction::kLengthDescriptorIndex'; |
| const kNameDescriptorIndex: |
| constexpr int32 generates 'JSFunction::kNameDescriptorIndex'; |
| const kMinDescriptorsForFastBind: |
| constexpr int31 generates 'JSFunction::kMinDescriptorsForFastBind'; |
| |
| macro CheckAccessor(implicit context: Context)( |
| array: DescriptorArray, index: constexpr int32, name: Name) 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<AccessorInfo>(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.length; |
| try { |
| typeswitch (receiver) { |
| case (fn: JSFunction|JSBoundFunction): { |
| // 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 < |
| kMinDescriptorsForFastBind) { |
| 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<int32>(argc)); |
| } |
| } |
| } // namespace function |