Line data Source code
1 : // Copyright 2016 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.h"
6 :
7 : #include "src/api-arguments.h"
8 : #include "src/api-natives.h"
9 : #include "src/builtins/builtins-utils.h"
10 : #include "src/counters.h"
11 : #include "src/log.h"
12 : #include "src/objects-inl.h"
13 : #include "src/prototype.h"
14 : #include "src/visitors.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 :
19 : namespace {
20 :
21 : // Returns the holder JSObject if the function can legally be called with this
22 : // receiver. Returns nullptr if the call is illegal.
23 : // TODO(dcarney): CallOptimization duplicates this logic, merge.
24 14120723 : JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info,
25 : JSObject* receiver) {
26 : Object* recv_type = info->signature();
27 : // No signature, return holder.
28 14120724 : if (!recv_type->IsFunctionTemplateInfo()) return receiver;
29 : FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
30 :
31 : // Check the receiver. Fast path for receivers with no hidden prototypes.
32 9053 : if (signature->IsTemplateFor(receiver)) return receiver;
33 6791 : if (!receiver->map()->has_hidden_prototype()) return nullptr;
34 6244 : for (PrototypeIterator iter(isolate, receiver, kStartAtPrototype,
35 : PrototypeIterator::END_AT_NON_HIDDEN);
36 15 : !iter.IsAtEnd(); iter.Advance()) {
37 6229 : JSObject* current = iter.GetCurrent<JSObject>();
38 6229 : if (signature->IsTemplateFor(current)) return current;
39 : }
40 15 : return nullptr;
41 : }
42 :
43 : template <bool is_construct>
44 14429781 : MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(
45 14427315 : Isolate* isolate, Handle<HeapObject> function,
46 : Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
47 : Handle<Object> receiver, BuiltinArguments args) {
48 : Handle<JSObject> js_receiver;
49 : JSObject* raw_holder;
50 : if (is_construct) {
51 : DCHECK(args.receiver()->IsTheHole(isolate));
52 309049 : if (fun_data->instance_template()->IsUndefined(isolate)) {
53 : v8::Local<ObjectTemplate> templ =
54 : ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate),
55 5238 : ToApiHandle<v8::FunctionTemplate>(fun_data));
56 : fun_data->set_instance_template(*Utils::OpenHandle(*templ));
57 : }
58 : Handle<ObjectTemplateInfo> instance_template(
59 : ObjectTemplateInfo::cast(fun_data->instance_template()), isolate);
60 618098 : ASSIGN_RETURN_ON_EXCEPTION(
61 : isolate, js_receiver,
62 : ApiNatives::InstantiateObject(instance_template,
63 : Handle<JSReceiver>::cast(new_target)),
64 : Object);
65 309049 : args[0] = *js_receiver;
66 : DCHECK_EQ(*js_receiver, *args.receiver());
67 :
68 : raw_holder = *js_receiver;
69 : } else {
70 : DCHECK(receiver->IsJSReceiver());
71 :
72 14120730 : if (!receiver->IsJSObject()) {
73 : // This function cannot be called with the given receiver. Abort!
74 0 : THROW_NEW_ERROR(
75 : isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
76 : }
77 :
78 : js_receiver = Handle<JSObject>::cast(receiver);
79 :
80 14120849 : if (!fun_data->accept_any_receiver() &&
81 : js_receiver->IsAccessCheckNeeded() &&
82 57 : !isolate->MayAccess(handle(isolate->context()), js_receiver)) {
83 7 : isolate->ReportFailedAccessCheck(js_receiver);
84 7 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
85 2 : return isolate->factory()->undefined_value();
86 : }
87 :
88 14120723 : raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);
89 :
90 14120724 : if (raw_holder == nullptr) {
91 : // This function cannot be called with the given receiver. Abort!
92 1154 : THROW_NEW_ERROR(
93 : isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
94 : }
95 : }
96 :
97 : Object* raw_call_data = fun_data->call_code();
98 14429196 : if (!raw_call_data->IsUndefined(isolate)) {
99 : DCHECK(raw_call_data->IsCallHandlerInfo());
100 : CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
101 : Object* callback_obj = call_data->callback();
102 : v8::FunctionCallback callback =
103 : v8::ToCData<v8::FunctionCallback>(callback_obj);
104 : Object* data_obj = call_data->data();
105 :
106 14427258 : LOG(isolate, ApiObjectAccess("call", JSObject::cast(*js_receiver)));
107 :
108 : FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder,
109 : *new_target, &args[0] - 1,
110 28547235 : args.length() - 1);
111 :
112 14427258 : Handle<Object> result = custom.Call(callback);
113 :
114 14427260 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
115 14403577 : if (result.is_null()) {
116 420 : if (is_construct) return js_receiver;
117 6853596 : return isolate->factory()->undefined_value();
118 : }
119 : // Rebox the result.
120 : result->VerifyApiCallResultType();
121 292221 : if (!is_construct || result->IsJSReceiver())
122 7549333 : return handle(*result, isolate);
123 : }
124 :
125 2166 : return js_receiver;
126 : }
127 :
128 : } // anonymous namespace
129 :
130 43249361 : BUILTIN(HandleApiCall) {
131 : HandleScope scope(isolate);
132 : Handle<JSFunction> function = args.target();
133 14416453 : Handle<Object> receiver = args.receiver();
134 : Handle<HeapObject> new_target = args.new_target();
135 : Handle<FunctionTemplateInfo> fun_data(function->shared()->get_api_func_data(),
136 : isolate);
137 14416454 : if (new_target->IsJSReceiver()) {
138 910170 : RETURN_RESULT_OR_FAILURE(
139 : isolate, HandleApiCallHelper<true>(isolate, function, new_target,
140 : fun_data, receiver, args));
141 : } else {
142 42315266 : RETURN_RESULT_OR_FAILURE(
143 : isolate, HandleApiCallHelper<false>(isolate, function, new_target,
144 : fun_data, receiver, args));
145 : }
146 : }
147 :
148 : namespace {
149 :
150 13327 : class RelocatableArguments : public BuiltinArguments, public Relocatable {
151 : public:
152 : RelocatableArguments(Isolate* isolate, int length, Object** arguments)
153 13327 : : BuiltinArguments(length, arguments), Relocatable(isolate) {}
154 :
155 62 : virtual inline void IterateInstance(RootVisitor* v) {
156 124 : if (length() == 0) return;
157 : v->VisitRootPointers(Root::kRelocatable, lowest_address(),
158 186 : highest_address() + 1);
159 : }
160 :
161 : private:
162 : DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
163 : };
164 :
165 : } // namespace
166 :
167 13327 : MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
168 : bool is_construct,
169 : Handle<HeapObject> function,
170 : Handle<Object> receiver,
171 : int argc, Handle<Object> args[],
172 : Handle<HeapObject> new_target) {
173 : DCHECK(function->IsFunctionTemplateInfo() ||
174 : (function->IsJSFunction() &&
175 : JSFunction::cast(*function)->shared()->IsApiFunction()));
176 :
177 : // Do proper receiver conversion for non-strict mode api functions.
178 25875 : if (!is_construct && !receiver->IsJSReceiver()) {
179 458 : if (function->IsFunctionTemplateInfo() ||
180 : is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) {
181 494 : ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
182 : Object::ConvertReceiver(isolate, receiver),
183 : Object);
184 : }
185 : }
186 :
187 : Handle<FunctionTemplateInfo> fun_data =
188 : function->IsFunctionTemplateInfo()
189 : ? Handle<FunctionTemplateInfo>::cast(function)
190 : : handle(JSFunction::cast(*function)->shared()->get_api_func_data(),
191 25453 : isolate);
192 : // Construct BuiltinArguments object:
193 : // new target, function, arguments reversed, receiver.
194 : const int kBufferSize = 32;
195 : Object* small_argv[kBufferSize];
196 : Object** argv;
197 13327 : const int frame_argc = argc + BuiltinArguments::kNumExtraArgsWithReceiver;
198 13327 : if (frame_argc <= kBufferSize) {
199 : argv = small_argv;
200 : } else {
201 0 : argv = new Object*[frame_argc];
202 : }
203 13327 : int cursor = frame_argc - 1;
204 26654 : argv[cursor--] = *receiver;
205 14581 : for (int i = 0; i < argc; ++i) {
206 2508 : argv[cursor--] = *args[i];
207 : }
208 : DCHECK_EQ(cursor, BuiltinArguments::kPaddingOffset);
209 13327 : argv[BuiltinArguments::kPaddingOffset] = isolate->heap()->the_hole_value();
210 13327 : argv[BuiltinArguments::kArgcOffset] = Smi::FromInt(frame_argc);
211 13327 : argv[BuiltinArguments::kTargetOffset] = *function;
212 13327 : argv[BuiltinArguments::kNewTargetOffset] = *new_target;
213 : MaybeHandle<Object> result;
214 : {
215 13327 : RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
216 13327 : if (is_construct) {
217 : result = HandleApiCallHelper<true>(isolate, function, new_target,
218 779 : fun_data, receiver, arguments);
219 : } else {
220 : result = HandleApiCallHelper<false>(isolate, function, new_target,
221 12548 : fun_data, receiver, arguments);
222 : }
223 : }
224 13327 : if (argv != small_argv) delete[] argv;
225 13327 : return result;
226 : }
227 :
228 : // Helper function to handle calls to non-function objects created through the
229 : // API. The object can be called as either a constructor (using new) or just as
230 : // a function (without new).
231 324 : MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
232 324 : Isolate* isolate, bool is_construct_call, BuiltinArguments args) {
233 : Handle<Object> receiver = args.receiver();
234 :
235 : // Get the object called.
236 : JSObject* obj = JSObject::cast(*receiver);
237 :
238 : // Set the new target.
239 : HeapObject* new_target;
240 324 : if (is_construct_call) {
241 : // TODO(adamk): This should be passed through in args instead of
242 : // being patched in here. We need to set a non-undefined value
243 : // for v8::FunctionCallbackInfo::IsConstructCall() to get the
244 : // right answer.
245 : new_target = obj;
246 : } else {
247 234 : new_target = isolate->heap()->undefined_value();
248 : }
249 :
250 : // Get the invocation callback from the function descriptor that was
251 : // used to create the called object.
252 : DCHECK(obj->map()->is_callable());
253 324 : JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
254 : // TODO(ishell): turn this back to a DCHECK.
255 324 : CHECK(constructor->shared()->IsApiFunction());
256 : Object* handler =
257 : constructor->shared()->get_api_func_data()->instance_call_handler();
258 : DCHECK(!handler->IsUndefined(isolate));
259 : // TODO(ishell): remove this debugging code.
260 324 : CHECK(handler->IsCallHandlerInfo());
261 : CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
262 : Object* callback_obj = call_data->callback();
263 : v8::FunctionCallback callback =
264 : v8::ToCData<v8::FunctionCallback>(callback_obj);
265 :
266 : // Get the data for the call and perform the callback.
267 : Object* result;
268 : {
269 : HandleScope scope(isolate);
270 324 : LOG(isolate, ApiObjectAccess("call non-function", obj));
271 :
272 : FunctionCallbackArguments custom(isolate, call_data->data(), constructor,
273 : obj, new_target, &args[0] - 1,
274 324 : args.length() - 1);
275 324 : Handle<Object> result_handle = custom.Call(callback);
276 324 : if (result_handle.is_null()) {
277 24 : result = isolate->heap()->undefined_value();
278 : } else {
279 : result = *result_handle;
280 : }
281 : }
282 : // Check for exceptions and return result.
283 324 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
284 : return result;
285 : }
286 :
287 : // Handle calls to non-function objects created through the API. This delegate
288 : // function is used when the call is a normal function call.
289 468 : BUILTIN(HandleApiCallAsFunction) {
290 234 : return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
291 : }
292 :
293 : // Handle calls to non-function objects created through the API. This delegate
294 : // function is used when the call is a construct call.
295 180 : BUILTIN(HandleApiCallAsConstructor) {
296 90 : return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
297 : }
298 :
299 : } // namespace internal
300 : } // namespace v8
|