Line data Source code
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/zone/zone-list-inl.h" // TODO(mstarzinger): Temporary cycle breaker.
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 124 : TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
15 31 : Label slow(this);
16 :
17 : // TODO(ishell): use constants from Descriptor once the JSFunction linkage
18 : // arguments are reordered.
19 : Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
20 : Node* context = Parameter(BuiltinDescriptor::kContext);
21 : Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
22 :
23 93 : CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
24 :
25 : // Check that receiver has instance type of JS_FUNCTION_TYPE
26 62 : Node* receiver = args.GetReceiver();
27 62 : GotoIf(TaggedIsSmi(receiver), &slow);
28 :
29 62 : Node* receiver_map = LoadMap(receiver);
30 : {
31 62 : Node* instance_type = LoadMapInstanceType(receiver_map);
32 : GotoIfNot(
33 : Word32Or(InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE),
34 93 : InstanceTypeEqual(instance_type, JS_BOUND_FUNCTION_TYPE)),
35 62 : &slow);
36 : }
37 :
38 : // Disallow binding of slow-mode functions. We need to figure out whether the
39 : // length and name property are in the original state.
40 31 : Comment("Disallow binding of slow-mode functions");
41 62 : GotoIf(IsDictionaryMap(receiver_map), &slow);
42 :
43 : // Check whether the length and name properties are still present as
44 : // AccessorInfo objects. In that case, their value can be recomputed even if
45 : // the actual value on the object changes.
46 31 : Comment("Check descriptor array length");
47 62 : Node* descriptors = LoadMapDescriptors(receiver_map);
48 62 : Node* descriptors_length = LoadFixedArrayBaseLength(descriptors);
49 93 : GotoIf(SmiLessThanOrEqual(descriptors_length, SmiConstant(1)), &slow);
50 :
51 : // Check whether the length and name properties are still present as
52 : // AccessorInfo objects. In that case, their value can be recomputed even if
53 : // the actual value on the object changes.
54 31 : Comment("Check name and length properties");
55 : {
56 : const int length_index = JSFunction::kLengthDescriptorIndex;
57 : Node* maybe_length = LoadFixedArrayElement(
58 31 : descriptors, DescriptorArray::ToKeyIndex(length_index));
59 31 : GotoIf(WordNotEqual(maybe_length, LoadRoot(Heap::klength_stringRootIndex)),
60 31 : &slow);
61 :
62 : Node* maybe_length_accessor = LoadFixedArrayElement(
63 31 : descriptors, DescriptorArray::ToValueIndex(length_index));
64 62 : GotoIf(TaggedIsSmi(maybe_length_accessor), &slow);
65 62 : Node* length_value_map = LoadMap(maybe_length_accessor);
66 62 : GotoIfNot(IsAccessorInfoMap(length_value_map), &slow);
67 :
68 : const int name_index = JSFunction::kNameDescriptorIndex;
69 : Node* maybe_name = LoadFixedArrayElement(
70 31 : descriptors, DescriptorArray::ToKeyIndex(name_index));
71 31 : GotoIf(WordNotEqual(maybe_name, LoadRoot(Heap::kname_stringRootIndex)),
72 31 : &slow);
73 :
74 : Node* maybe_name_accessor = LoadFixedArrayElement(
75 31 : descriptors, DescriptorArray::ToValueIndex(name_index));
76 62 : GotoIf(TaggedIsSmi(maybe_name_accessor), &slow);
77 62 : Node* name_value_map = LoadMap(maybe_name_accessor);
78 62 : GotoIfNot(IsAccessorInfoMap(name_value_map), &slow);
79 : }
80 :
81 : // Choose the right bound function map based on whether the target is
82 : // constructable.
83 31 : Comment("Choose the right bound function map");
84 62 : VARIABLE(bound_function_map, MachineRepresentation::kTagged);
85 : {
86 : Label with_constructor(this);
87 31 : VariableList vars({&bound_function_map}, zone());
88 62 : Node* native_context = LoadNativeContext(context);
89 :
90 31 : Label map_done(this, vars);
91 62 : GotoIf(IsConstructorMap(receiver_map), &with_constructor);
92 :
93 : bound_function_map.Bind(LoadContextElement(
94 62 : native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
95 31 : Goto(&map_done);
96 :
97 31 : BIND(&with_constructor);
98 : bound_function_map.Bind(LoadContextElement(
99 62 : native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
100 31 : Goto(&map_done);
101 :
102 62 : BIND(&map_done);
103 : }
104 :
105 : // Verify that __proto__ matches that of a the target bound function.
106 31 : Comment("Verify that __proto__ matches target bound function");
107 62 : Node* prototype = LoadMapPrototype(receiver_map);
108 93 : Node* expected_prototype = LoadMapPrototype(bound_function_map.value());
109 62 : GotoIf(WordNotEqual(prototype, expected_prototype), &slow);
110 :
111 : // Allocate the arguments array.
112 31 : Comment("Allocate the arguments array");
113 62 : VARIABLE(argument_array, MachineRepresentation::kTagged);
114 : {
115 : Label empty_arguments(this);
116 31 : Label arguments_done(this, &argument_array);
117 93 : GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments);
118 : Node* elements_length =
119 124 : ChangeUint32ToWord(Unsigned(Int32Sub(argc, Int32Constant(1))));
120 : Node* elements =
121 : AllocateFixedArray(PACKED_ELEMENTS, elements_length, INTPTR_PARAMETERS,
122 31 : kAllowLargeObjectAllocation);
123 62 : VARIABLE(index, MachineType::PointerRepresentation());
124 62 : index.Bind(IntPtrConstant(0));
125 31 : VariableList foreach_vars({&index}, zone());
126 : args.ForEach(foreach_vars,
127 31 : [this, elements, &index](Node* arg) {
128 31 : StoreFixedArrayElement(elements, index.value(), arg);
129 31 : Increment(&index);
130 31 : },
131 93 : IntPtrConstant(1));
132 31 : argument_array.Bind(elements);
133 31 : Goto(&arguments_done);
134 :
135 31 : BIND(&empty_arguments);
136 62 : argument_array.Bind(EmptyFixedArrayConstant());
137 31 : Goto(&arguments_done);
138 :
139 62 : BIND(&arguments_done);
140 : }
141 :
142 : // Determine bound receiver.
143 31 : Comment("Determine bound receiver");
144 62 : VARIABLE(bound_receiver, MachineRepresentation::kTagged);
145 : {
146 : Label has_receiver(this);
147 31 : Label receiver_done(this, &bound_receiver);
148 93 : GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver);
149 62 : bound_receiver.Bind(UndefinedConstant());
150 31 : Goto(&receiver_done);
151 :
152 31 : BIND(&has_receiver);
153 62 : bound_receiver.Bind(args.AtIndex(0));
154 31 : Goto(&receiver_done);
155 :
156 62 : BIND(&receiver_done);
157 : }
158 :
159 : // Allocate the resulting bound function.
160 31 : Comment("Allocate the resulting bound function");
161 : {
162 31 : Node* bound_function = Allocate(JSBoundFunction::kSize);
163 31 : StoreMapNoWriteBarrier(bound_function, bound_function_map.value());
164 : StoreObjectFieldNoWriteBarrier(
165 31 : bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver);
166 : StoreObjectFieldNoWriteBarrier(bound_function,
167 : JSBoundFunction::kBoundThisOffset,
168 31 : bound_receiver.value());
169 : StoreObjectFieldNoWriteBarrier(bound_function,
170 : JSBoundFunction::kBoundArgumentsOffset,
171 31 : argument_array.value());
172 62 : Node* empty_fixed_array = EmptyFixedArrayConstant();
173 : StoreObjectFieldNoWriteBarrier(
174 31 : bound_function, JSObject::kPropertiesOrHashOffset, empty_fixed_array);
175 : StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset,
176 31 : empty_fixed_array);
177 :
178 31 : args.PopAndReturn(bound_function);
179 : }
180 :
181 31 : BIND(&slow);
182 : Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
183 31 : MachineType::TaggedPointer());
184 : TailCallStub(CodeFactory::FunctionPrototypeBind(isolate()), context, target,
185 93 : new_target, argc);
186 31 : }
187 :
188 : // ES6 #sec-function.prototype-@@hasinstance
189 93 : TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) {
190 : Node* context = Parameter(Descriptor::kContext);
191 : Node* f = Parameter(Descriptor::kReceiver);
192 : Node* v = Parameter(Descriptor::kV);
193 31 : Node* result = OrdinaryHasInstance(context, f, v);
194 31 : Return(result);
195 31 : }
196 :
197 : } // namespace internal
198 : } // namespace v8
|