11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_cinamespace function {
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciextern macro OrdinaryHasInstance(Context, Object, Object): JSAny;
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci// ES6 section 19.2.3.6 Function.prototype[@@hasInstance]
101cb0ef41Sopenharmony_cijavascript builtin FunctionPrototypeHasInstance(
111cb0ef41Sopenharmony_ci    js-implicit context: NativeContext, receiver: JSAny)(value: JSAny): JSAny {
121cb0ef41Sopenharmony_ci  return OrdinaryHasInstance(context, receiver, value);
131cb0ef41Sopenharmony_ci}
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ciextern transitioning builtin
161cb0ef41Sopenharmony_ciFunctionPrototypeBind(implicit context: Context)(
171cb0ef41Sopenharmony_ci    JSFunction, JSAny, int32): JSAny;
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciconst kLengthDescriptorIndex: constexpr int32
201cb0ef41Sopenharmony_ci    generates 'JSFunctionOrBoundFunctionOrWrappedFunction::kLengthDescriptorIndex'
211cb0ef41Sopenharmony_ci    ;
221cb0ef41Sopenharmony_ciconst kNameDescriptorIndex: constexpr int32
231cb0ef41Sopenharmony_ci    generates 'JSFunctionOrBoundFunctionOrWrappedFunction::kNameDescriptorIndex'
241cb0ef41Sopenharmony_ci    ;
251cb0ef41Sopenharmony_ciconst kMinDescriptorsForFastBindAndWrap: constexpr int31
261cb0ef41Sopenharmony_ci    generates 'JSFunction::kMinDescriptorsForFastBindAndWrap';
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_cimacro CheckAccessor(implicit context: Context)(
291cb0ef41Sopenharmony_ci    array: DescriptorArray, index: constexpr int32,
301cb0ef41Sopenharmony_ci    name: Name): void labels Slow {
311cb0ef41Sopenharmony_ci  const descriptor: DescriptorEntry = array.descriptors[index];
321cb0ef41Sopenharmony_ci  const key: Name|Undefined = descriptor.key;
331cb0ef41Sopenharmony_ci  if (!TaggedEqual(key, name)) goto Slow;
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  // The descriptor value must be an AccessorInfo.
361cb0ef41Sopenharmony_ci  Cast<AccessorInfo>(descriptor.value) otherwise goto Slow;
371cb0ef41Sopenharmony_ci}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci// ES6 section 19.2.3.2 Function.prototype.bind
401cb0ef41Sopenharmony_citransitioning javascript builtin
411cb0ef41Sopenharmony_ciFastFunctionPrototypeBind(
421cb0ef41Sopenharmony_ci    js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny,
431cb0ef41Sopenharmony_ci    target: JSFunction)(...arguments): JSAny {
441cb0ef41Sopenharmony_ci  const argc: intptr = arguments.actual_count;
451cb0ef41Sopenharmony_ci  try {
461cb0ef41Sopenharmony_ci    typeswitch (receiver) {
471cb0ef41Sopenharmony_ci      case (fn: JSFunction|JSBoundFunction|JSWrappedFunction): {
481cb0ef41Sopenharmony_ci        // Disallow binding of slow-mode functions. We need to figure out
491cb0ef41Sopenharmony_ci        // whether the length and name property are in the original state.
501cb0ef41Sopenharmony_ci        Comment('Disallow binding of slow-mode functions');
511cb0ef41Sopenharmony_ci        if (IsDictionaryMap(fn.map)) goto Slow;
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci        // Check whether the length and name properties are still present as
541cb0ef41Sopenharmony_ci        // AccessorInfo objects. If so, their value can be recomputed even if
551cb0ef41Sopenharmony_ci        // the actual value on the object changes.
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci        if (fn.map.bit_field3.number_of_own_descriptors <
581cb0ef41Sopenharmony_ci            kMinDescriptorsForFastBindAndWrap) {
591cb0ef41Sopenharmony_ci          goto Slow;
601cb0ef41Sopenharmony_ci        }
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci        const descriptors: DescriptorArray = fn.map.instance_descriptors;
631cb0ef41Sopenharmony_ci        CheckAccessor(
641cb0ef41Sopenharmony_ci            descriptors, kLengthDescriptorIndex, LengthStringConstant())
651cb0ef41Sopenharmony_ci            otherwise Slow;
661cb0ef41Sopenharmony_ci        CheckAccessor(descriptors, kNameDescriptorIndex, NameStringConstant())
671cb0ef41Sopenharmony_ci            otherwise Slow;
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci        // Choose the right bound function map based on whether the target is
701cb0ef41Sopenharmony_ci        // constructable.
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci        const boundFunctionMap: Map =
731cb0ef41Sopenharmony_ci            IsConstructor(fn) ?
741cb0ef41Sopenharmony_ci            *NativeContextSlot(
751cb0ef41Sopenharmony_ci                ContextSlot::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX) :
761cb0ef41Sopenharmony_ci            *NativeContextSlot(ContextSlot::
771cb0ef41Sopenharmony_ci                                    BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX);
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci        // Verify that prototype matches that of the target bound function.
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci        if (fn.map.prototype != boundFunctionMap.prototype) goto Slow;
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci        // Allocate the arguments array.
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci        const argumentsArray = arguments.length <= 1 ?
861cb0ef41Sopenharmony_ci            kEmptyFixedArray :
871cb0ef41Sopenharmony_ci            NewFixedArray(
881cb0ef41Sopenharmony_ci                arguments.length - 1, ArgumentsIterator{arguments, current: 1});
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci        const boundReceiver: JSAny = arguments[0];
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci        const result = new JSBoundFunction{
931cb0ef41Sopenharmony_ci          map: boundFunctionMap,
941cb0ef41Sopenharmony_ci          properties_or_hash: kEmptyFixedArray,
951cb0ef41Sopenharmony_ci          elements: kEmptyFixedArray,
961cb0ef41Sopenharmony_ci          bound_target_function: fn,
971cb0ef41Sopenharmony_ci          bound_this: boundReceiver,
981cb0ef41Sopenharmony_ci          bound_arguments: argumentsArray
991cb0ef41Sopenharmony_ci        };
1001cb0ef41Sopenharmony_ci        return result;
1011cb0ef41Sopenharmony_ci      }
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci      case (JSAny): {
1041cb0ef41Sopenharmony_ci        goto Slow;
1051cb0ef41Sopenharmony_ci      }
1061cb0ef41Sopenharmony_ci    }
1071cb0ef41Sopenharmony_ci  } label Slow {
1081cb0ef41Sopenharmony_ci    tail FunctionPrototypeBind(
1091cb0ef41Sopenharmony_ci        LoadTargetFromFrame(), newTarget, Convert<int32>(argc));
1101cb0ef41Sopenharmony_ci  }
1111cb0ef41Sopenharmony_ci}
1121cb0ef41Sopenharmony_ci}  // namespace function
113