5 #include "src/builtins/builtins-utils-gen.h" 6 #include "src/builtins/builtins.h" 7 #include "src/code-stub-assembler.h" 8 #include "src/frame-constants.h" 9 #include "src/objects/api-callbacks.h" 10 #include "src/objects/descriptor-array.h" 15 TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
20 Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);
21 Node* context = Parameter(Descriptor::kContext);
22 Node* new_target = Parameter(Descriptor::kJSNewTarget);
24 CodeStubArguments args(
this, ChangeInt32ToIntPtr(argc));
27 Node* receiver = args.GetReceiver();
28 GotoIf(TaggedIsSmi(receiver), &slow);
30 Node* receiver_map = LoadMap(receiver);
32 Node* instance_type = LoadMapInstanceType(receiver_map);
34 Word32Or(InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE),
35 InstanceTypeEqual(instance_type, JS_BOUND_FUNCTION_TYPE)),
41 Comment(
"Disallow binding of slow-mode functions");
42 GotoIf(IsDictionaryMap(receiver_map), &slow);
47 Comment(
"Check descriptor array length");
48 TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
50 const int min_nof_descriptors = i::Max(JSFunction::kLengthDescriptorIndex,
51 JSFunction::kNameDescriptorIndex);
52 TNode<Int32T> nof_descriptors = LoadNumberOfDescriptors(descriptors);
54 Int32LessThanOrEqual(nof_descriptors, Int32Constant(min_nof_descriptors)),
60 Comment(
"Check name and length properties");
62 const int length_index = JSFunction::kLengthDescriptorIndex;
63 TNode<Name> maybe_length =
64 LoadKeyByDescriptorEntry(descriptors, length_index);
65 GotoIf(WordNotEqual(maybe_length, LoadRoot(RootIndex::klength_string)),
68 TNode<Object> maybe_length_accessor =
69 LoadValueByDescriptorEntry(descriptors, length_index);
70 GotoIf(TaggedIsSmi(maybe_length_accessor), &slow);
71 Node* length_value_map = LoadMap(CAST(maybe_length_accessor));
72 GotoIfNot(IsAccessorInfoMap(length_value_map), &slow);
74 const int name_index = JSFunction::kNameDescriptorIndex;
75 TNode<Name> maybe_name = LoadKeyByDescriptorEntry(descriptors, name_index);
76 GotoIf(WordNotEqual(maybe_name, LoadRoot(RootIndex::kname_string)), &slow);
78 TNode<Object> maybe_name_accessor =
79 LoadValueByDescriptorEntry(descriptors, name_index);
80 GotoIf(TaggedIsSmi(maybe_name_accessor), &slow);
81 TNode<Map> name_value_map = LoadMap(CAST(maybe_name_accessor));
82 GotoIfNot(IsAccessorInfoMap(name_value_map), &slow);
87 Comment(
"Choose the right bound function map");
88 VARIABLE(bound_function_map, MachineRepresentation::kTagged);
90 Label with_constructor(
this);
91 VariableList vars({&bound_function_map}, zone());
92 Node* native_context = LoadNativeContext(context);
94 Label map_done(
this, vars);
95 GotoIf(IsConstructorMap(receiver_map), &with_constructor);
97 bound_function_map.Bind(LoadContextElement(
98 native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
101 BIND(&with_constructor);
102 bound_function_map.Bind(LoadContextElement(
103 native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
110 Comment(
"Verify that __proto__ matches target bound function");
111 Node* prototype = LoadMapPrototype(receiver_map);
112 Node* expected_prototype = LoadMapPrototype(bound_function_map.value());
113 GotoIf(WordNotEqual(prototype, expected_prototype), &slow);
116 Comment(
"Allocate the arguments array");
117 VARIABLE(argument_array, MachineRepresentation::kTagged);
119 Label empty_arguments(
this);
120 Label arguments_done(
this, &argument_array);
121 GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments);
122 TNode<IntPtrT> elements_length =
123 Signed(ChangeUint32ToWord(Unsigned(Int32Sub(argc, Int32Constant(1)))));
124 TNode<FixedArray> elements = CAST(AllocateFixedArray(
125 PACKED_ELEMENTS, elements_length, kAllowLargeObjectAllocation));
126 VARIABLE(index, MachineType::PointerRepresentation());
127 index.Bind(IntPtrConstant(0));
128 VariableList foreach_vars({&index}, zone());
129 args.ForEach(foreach_vars,
130 [
this, elements, &index](Node* arg) {
131 StoreFixedArrayElement(elements, index.value(), arg);
135 argument_array.Bind(elements);
136 Goto(&arguments_done);
138 BIND(&empty_arguments);
139 argument_array.Bind(EmptyFixedArrayConstant());
140 Goto(&arguments_done);
142 BIND(&arguments_done);
146 Comment(
"Determine bound receiver");
147 VARIABLE(bound_receiver, MachineRepresentation::kTagged);
149 Label has_receiver(
this);
150 Label receiver_done(
this, &bound_receiver);
151 GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver);
152 bound_receiver.Bind(UndefinedConstant());
153 Goto(&receiver_done);
156 bound_receiver.Bind(args.AtIndex(0));
157 Goto(&receiver_done);
159 BIND(&receiver_done);
163 Comment(
"Allocate the resulting bound function");
165 Node* bound_function = Allocate(JSBoundFunction::kSize);
166 StoreMapNoWriteBarrier(bound_function, bound_function_map.value());
167 StoreObjectFieldNoWriteBarrier(
168 bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver);
169 StoreObjectFieldNoWriteBarrier(bound_function,
170 JSBoundFunction::kBoundThisOffset,
171 bound_receiver.value());
172 StoreObjectFieldNoWriteBarrier(bound_function,
173 JSBoundFunction::kBoundArgumentsOffset,
174 argument_array.value());
175 Node* empty_fixed_array = EmptyFixedArrayConstant();
176 StoreObjectFieldNoWriteBarrier(
177 bound_function, JSObject::kPropertiesOrHashOffset, empty_fixed_array);
178 StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset,
181 args.PopAndReturn(bound_function);
189 TNode<JSFunction> target = LoadTargetFromFrame();
190 TailCallBuiltin(Builtins::kFunctionPrototypeBind, context, target,
196 TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) {
197 Node* context = Parameter(Descriptor::kContext);
198 Node* f = Parameter(Descriptor::kReceiver);
199 Node* v = Parameter(Descriptor::kV);
200 Node* result = OrdinaryHasInstance(context, f, v);