• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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