V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
builtins-function-gen.cc
1 // Copyright 2017 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 
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"
11 
12 namespace v8 {
13 namespace internal {
14 
15 TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
16  Label slow(this);
17 
18  // TODO(ishell): use constants from Descriptor once the JSFunction linkage
19  // arguments are reordered.
20  Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);
21  Node* context = Parameter(Descriptor::kContext);
22  Node* new_target = Parameter(Descriptor::kJSNewTarget);
23 
24  CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
25 
26  // Check that receiver has instance type of JS_FUNCTION_TYPE
27  Node* receiver = args.GetReceiver();
28  GotoIf(TaggedIsSmi(receiver), &slow);
29 
30  Node* receiver_map = LoadMap(receiver);
31  {
32  Node* instance_type = LoadMapInstanceType(receiver_map);
33  GotoIfNot(
34  Word32Or(InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE),
35  InstanceTypeEqual(instance_type, JS_BOUND_FUNCTION_TYPE)),
36  &slow);
37  }
38 
39  // Disallow binding of slow-mode functions. We need to figure out whether the
40  // length and name property are in the original state.
41  Comment("Disallow binding of slow-mode functions");
42  GotoIf(IsDictionaryMap(receiver_map), &slow);
43 
44  // Check whether the length and name properties are still present as
45  // AccessorInfo objects. In that case, their value can be recomputed even if
46  // the actual value on the object changes.
47  Comment("Check descriptor array length");
48  TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
49  // Minimum descriptor array length required for fast path.
50  const int min_nof_descriptors = i::Max(JSFunction::kLengthDescriptorIndex,
51  JSFunction::kNameDescriptorIndex);
52  TNode<Int32T> nof_descriptors = LoadNumberOfDescriptors(descriptors);
53  GotoIf(
54  Int32LessThanOrEqual(nof_descriptors, Int32Constant(min_nof_descriptors)),
55  &slow);
56 
57  // Check whether the length and name properties are still present as
58  // AccessorInfo objects. In that case, their value can be recomputed even if
59  // the actual value on the object changes.
60  Comment("Check name and length properties");
61  {
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)),
66  &slow);
67 
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);
73 
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);
77 
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);
83  }
84 
85  // Choose the right bound function map based on whether the target is
86  // constructable.
87  Comment("Choose the right bound function map");
88  VARIABLE(bound_function_map, MachineRepresentation::kTagged);
89  {
90  Label with_constructor(this);
91  VariableList vars({&bound_function_map}, zone());
92  Node* native_context = LoadNativeContext(context);
93 
94  Label map_done(this, vars);
95  GotoIf(IsConstructorMap(receiver_map), &with_constructor);
96 
97  bound_function_map.Bind(LoadContextElement(
98  native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
99  Goto(&map_done);
100 
101  BIND(&with_constructor);
102  bound_function_map.Bind(LoadContextElement(
103  native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
104  Goto(&map_done);
105 
106  BIND(&map_done);
107  }
108 
109  // Verify that __proto__ matches that of a the target bound function.
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);
114 
115  // Allocate the arguments array.
116  Comment("Allocate the arguments array");
117  VARIABLE(argument_array, MachineRepresentation::kTagged);
118  {
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);
132  Increment(&index);
133  },
134  IntPtrConstant(1));
135  argument_array.Bind(elements);
136  Goto(&arguments_done);
137 
138  BIND(&empty_arguments);
139  argument_array.Bind(EmptyFixedArrayConstant());
140  Goto(&arguments_done);
141 
142  BIND(&arguments_done);
143  }
144 
145  // Determine bound receiver.
146  Comment("Determine bound receiver");
147  VARIABLE(bound_receiver, MachineRepresentation::kTagged);
148  {
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);
154 
155  BIND(&has_receiver);
156  bound_receiver.Bind(args.AtIndex(0));
157  Goto(&receiver_done);
158 
159  BIND(&receiver_done);
160  }
161 
162  // Allocate the resulting bound function.
163  Comment("Allocate the resulting bound function");
164  {
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,
179  empty_fixed_array);
180 
181  args.PopAndReturn(bound_function);
182  }
183 
184  BIND(&slow);
185  {
186  // We are not using Parameter(Descriptor::kJSTarget) and loading the value
187  // from the current frame here in order to reduce register pressure on the
188  // fast path.
189  TNode<JSFunction> target = LoadTargetFromFrame();
190  TailCallBuiltin(Builtins::kFunctionPrototypeBind, context, target,
191  new_target, argc);
192  }
193 }
194 
195 // ES6 #sec-function.prototype-@@hasinstance
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);
201  Return(result);
202 }
203 
204 } // namespace internal
205 } // namespace v8
Definition: libplatform.h:13