function.tq 3.85 KB
Newer Older
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
// 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.

69
        const boundFunctionMap: Map =
70
            IsConstructor(fn) ?
71 72 73 74
            *NativeContextSlot(
                ContextSlot::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX) :
            *NativeContextSlot(ContextSlot::
                                    BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX);
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

        // 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