summaryrefslogtreecommitdiff
path: root/chromium/v8/src/builtins/function.tq
blob: 8266714c7befb5235430b929ce95201e0248a389 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// 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 = UnsafeCast<Map>(
            IsConstructor(fn) ?
                context[NativeContextSlot::
                            BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX] :
                context[NativeContextSlot::
                            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