blob: e42760d4d2cc02363cc33d9efdf25d3e4df1ee66 [file] [log] [blame]
Ben Murdochf91f0612016-11-29 16:50:11 +00001// 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
Rubin Xu7bc1b612021-02-16 09:38:50 +00005#include "src/api/api-arguments-inl.h"
6#include "src/api/api-natives.h"
7#include "src/builtins/builtins-utils-inl.h"
Ben Murdochf91f0612016-11-29 16:50:11 +00008#include "src/builtins/builtins.h"
Rubin Xu7bc1b612021-02-16 09:38:50 +00009#include "src/logging/counters.h"
10#include "src/logging/log.h"
11#include "src/objects/objects-inl.h"
12#include "src/objects/prototype.h"
13#include "src/objects/templates.h"
14#include "src/objects/visitors.h"
Ben Murdochf91f0612016-11-29 16:50:11 +000015
16namespace v8 {
17namespace internal {
18
19namespace {
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.
Rubin Xu7bc1b612021-02-16 09:38:50 +000024JSReceiver GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo info,
25 JSReceiver receiver) {
26 Object recv_type = info.signature();
Ben Murdochf91f0612016-11-29 16:50:11 +000027 // No signature, return holder.
Rubin Xu7bc1b612021-02-16 09:38:50 +000028 if (!recv_type.IsFunctionTemplateInfo()) return receiver;
29 // A Proxy cannot have been created from the signature template.
30 if (!receiver.IsJSObject()) return JSReceiver();
Ben Murdochf91f0612016-11-29 16:50:11 +000031
Rubin Xu7bc1b612021-02-16 09:38:50 +000032 JSObject js_obj_receiver = JSObject::cast(receiver);
33 FunctionTemplateInfo signature = FunctionTemplateInfo::cast(recv_type);
34
35 // Check the receiver.
36 if (signature.IsTemplateFor(js_obj_receiver)) return receiver;
37
38 // The JSGlobalProxy might have a hidden prototype.
39 if (V8_UNLIKELY(js_obj_receiver.IsJSGlobalProxy())) {
40 HeapObject prototype = js_obj_receiver.map().prototype();
41 if (!prototype.IsNull(isolate)) {
42 JSObject js_obj_prototype = JSObject::cast(prototype);
43 if (signature.IsTemplateFor(js_obj_prototype)) return js_obj_prototype;
44 }
Ben Murdochf91f0612016-11-29 16:50:11 +000045 }
Rubin Xu7bc1b612021-02-16 09:38:50 +000046 return JSReceiver();
Ben Murdochf91f0612016-11-29 16:50:11 +000047}
48
49template <bool is_construct>
Rubin Xu7bc1b612021-02-16 09:38:50 +000050V8_WARN_UNUSED_RESULT MaybeHandle<Object> HandleApiCallHelper(
Ben Murdochf91f0612016-11-29 16:50:11 +000051 Isolate* isolate, Handle<HeapObject> function,
52 Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
53 Handle<Object> receiver, BuiltinArguments args) {
Rubin Xu7bc1b612021-02-16 09:38:50 +000054 Handle<JSReceiver> js_receiver;
55 JSReceiver raw_holder;
Ben Murdochf91f0612016-11-29 16:50:11 +000056 if (is_construct) {
57 DCHECK(args.receiver()->IsTheHole(isolate));
Rubin Xu7bc1b612021-02-16 09:38:50 +000058 if (fun_data->GetInstanceTemplate().IsUndefined(isolate)) {
Ben Murdochf91f0612016-11-29 16:50:11 +000059 v8::Local<ObjectTemplate> templ =
60 ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate),
61 ToApiHandle<v8::FunctionTemplate>(fun_data));
Rubin Xu7bc1b612021-02-16 09:38:50 +000062 FunctionTemplateInfo::SetInstanceTemplate(isolate, fun_data,
63 Utils::OpenHandle(*templ));
Ben Murdochf91f0612016-11-29 16:50:11 +000064 }
65 Handle<ObjectTemplateInfo> instance_template(
Rubin Xu7bc1b612021-02-16 09:38:50 +000066 ObjectTemplateInfo::cast(fun_data->GetInstanceTemplate()), isolate);
Ben Murdochf91f0612016-11-29 16:50:11 +000067 ASSIGN_RETURN_ON_EXCEPTION(
68 isolate, js_receiver,
Rubin Xu7bc1b612021-02-16 09:38:50 +000069 ApiNatives::InstantiateObject(isolate, instance_template,
Ben Murdochf91f0612016-11-29 16:50:11 +000070 Handle<JSReceiver>::cast(new_target)),
71 Object);
Rubin Xu7bc1b612021-02-16 09:38:50 +000072 args.set_at(0, *js_receiver);
Ben Murdochf91f0612016-11-29 16:50:11 +000073 DCHECK_EQ(*js_receiver, *args.receiver());
74
75 raw_holder = *js_receiver;
76 } else {
77 DCHECK(receiver->IsJSReceiver());
Rubin Xu7bc1b612021-02-16 09:38:50 +000078 js_receiver = Handle<JSReceiver>::cast(receiver);
Ben Murdochf91f0612016-11-29 16:50:11 +000079
80 if (!fun_data->accept_any_receiver() &&
Rubin Xu7bc1b612021-02-16 09:38:50 +000081 js_receiver->IsAccessCheckNeeded()) {
82 // Proxies never need access checks.
83 DCHECK(js_receiver->IsJSObject());
84 Handle<JSObject> js_obj_receiver = Handle<JSObject>::cast(js_receiver);
85 if (!isolate->MayAccess(handle(isolate->context(), isolate),
86 js_obj_receiver)) {
87 isolate->ReportFailedAccessCheck(js_obj_receiver);
88 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
89 return isolate->factory()->undefined_value();
90 }
Ben Murdochf91f0612016-11-29 16:50:11 +000091 }
92
93 raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);
94
Rubin Xu7bc1b612021-02-16 09:38:50 +000095 if (raw_holder.is_null()) {
Ben Murdochf91f0612016-11-29 16:50:11 +000096 // This function cannot be called with the given receiver. Abort!
97 THROW_NEW_ERROR(
98 isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
99 }
100 }
101
Rubin Xu7bc1b612021-02-16 09:38:50 +0000102 Object raw_call_data = fun_data->call_code(kAcquireLoad);
103 if (!raw_call_data.IsUndefined(isolate)) {
104 DCHECK(raw_call_data.IsCallHandlerInfo());
105 CallHandlerInfo call_data = CallHandlerInfo::cast(raw_call_data);
106 Object data_obj = call_data.data();
Ben Murdochf91f0612016-11-29 16:50:11 +0000107
Rubin Xu7bc1b612021-02-16 09:38:50 +0000108 FunctionCallbackArguments custom(
109 isolate, data_obj, *function, raw_holder, *new_target,
110 args.address_of_first_argument(), args.length() - 1);
111 Handle<Object> result = custom.Call(call_data);
Ben Murdochf91f0612016-11-29 16:50:11 +0000112
113 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
114 if (result.is_null()) {
115 if (is_construct) return js_receiver;
116 return isolate->factory()->undefined_value();
117 }
118 // Rebox the result.
119 result->VerifyApiCallResultType();
Rubin Xu7bc1b612021-02-16 09:38:50 +0000120 if (!is_construct || result->IsJSReceiver())
121 return handle(*result, isolate);
Ben Murdochf91f0612016-11-29 16:50:11 +0000122 }
123
124 return js_receiver;
125}
126
127} // anonymous namespace
128
129BUILTIN(HandleApiCall) {
130 HandleScope scope(isolate);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000131 Handle<JSFunction> function = args.target();
Ben Murdochf91f0612016-11-29 16:50:11 +0000132 Handle<Object> receiver = args.receiver();
133 Handle<HeapObject> new_target = args.new_target();
Rubin Xu7bc1b612021-02-16 09:38:50 +0000134 Handle<FunctionTemplateInfo> fun_data(function->shared().get_api_func_data(),
Ben Murdochf91f0612016-11-29 16:50:11 +0000135 isolate);
136 if (new_target->IsJSReceiver()) {
137 RETURN_RESULT_OR_FAILURE(
138 isolate, HandleApiCallHelper<true>(isolate, function, new_target,
139 fun_data, receiver, args));
140 } else {
141 RETURN_RESULT_OR_FAILURE(
142 isolate, HandleApiCallHelper<false>(isolate, function, new_target,
143 fun_data, receiver, args));
144 }
145}
146
147namespace {
148
149class RelocatableArguments : public BuiltinArguments, public Relocatable {
150 public:
Rubin Xu7bc1b612021-02-16 09:38:50 +0000151 RelocatableArguments(Isolate* isolate, int length, Address* arguments)
Ben Murdochf91f0612016-11-29 16:50:11 +0000152 : BuiltinArguments(length, arguments), Relocatable(isolate) {}
153
Rubin Xu7bc1b612021-02-16 09:38:50 +0000154 inline void IterateInstance(RootVisitor* v) override {
Ben Murdochf91f0612016-11-29 16:50:11 +0000155 if (length() == 0) return;
Rubin Xu7bc1b612021-02-16 09:38:50 +0000156 v->VisitRootPointers(Root::kRelocatable, nullptr, first_slot(),
157 last_slot() + 1);
Ben Murdochf91f0612016-11-29 16:50:11 +0000158 }
159
160 private:
161 DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
162};
163
164} // namespace
165
166MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
167 bool is_construct,
168 Handle<HeapObject> function,
169 Handle<Object> receiver,
170 int argc, Handle<Object> args[],
171 Handle<HeapObject> new_target) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000172 RuntimeCallTimerScope timer(isolate,
173 RuntimeCallCounterId::kInvokeApiFunction);
Ben Murdochf91f0612016-11-29 16:50:11 +0000174 DCHECK(function->IsFunctionTemplateInfo() ||
175 (function->IsJSFunction() &&
Rubin Xu7bc1b612021-02-16 09:38:50 +0000176 JSFunction::cast(*function).shared().IsApiFunction()));
Ben Murdochf91f0612016-11-29 16:50:11 +0000177
178 // Do proper receiver conversion for non-strict mode api functions.
179 if (!is_construct && !receiver->IsJSReceiver()) {
180 if (function->IsFunctionTemplateInfo() ||
Rubin Xu7bc1b612021-02-16 09:38:50 +0000181 is_sloppy(JSFunction::cast(*function).shared().language_mode())) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000182 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
183 Object::ConvertReceiver(isolate, receiver),
184 Object);
185 }
186 }
187
Rubin Xu7bc1b612021-02-16 09:38:50 +0000188 // We assume that all lazy accessor pairs have been instantiated when setting
189 // a break point on any API function.
190 DCHECK_IMPLIES(function->IsFunctionTemplateInfo(),
191 !Handle<FunctionTemplateInfo>::cast(function)->BreakAtEntry());
192
Ben Murdochf91f0612016-11-29 16:50:11 +0000193 Handle<FunctionTemplateInfo> fun_data =
194 function->IsFunctionTemplateInfo()
195 ? Handle<FunctionTemplateInfo>::cast(function)
Rubin Xu7bc1b612021-02-16 09:38:50 +0000196 : handle(JSFunction::cast(*function).shared().get_api_func_data(),
Ben Murdochf91f0612016-11-29 16:50:11 +0000197 isolate);
198 // Construct BuiltinArguments object:
199 // new target, function, arguments reversed, receiver.
200 const int kBufferSize = 32;
Rubin Xu7bc1b612021-02-16 09:38:50 +0000201 Address small_argv[kBufferSize];
202 Address* argv;
Ben Murdochf91f0612016-11-29 16:50:11 +0000203 const int frame_argc = argc + BuiltinArguments::kNumExtraArgsWithReceiver;
204 if (frame_argc <= kBufferSize) {
205 argv = small_argv;
206 } else {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000207 argv = new Address[frame_argc];
Ben Murdochf91f0612016-11-29 16:50:11 +0000208 }
Rubin Xu7bc1b612021-02-16 09:38:50 +0000209 argv[BuiltinArguments::kNewTargetOffset] = new_target->ptr();
210 argv[BuiltinArguments::kTargetOffset] = function->ptr();
211 argv[BuiltinArguments::kArgcOffset] = Smi::FromInt(frame_argc).ptr();
212 argv[BuiltinArguments::kPaddingOffset] =
213 ReadOnlyRoots(isolate).the_hole_value().ptr();
214 int cursor = BuiltinArguments::kNumExtraArgs;
215 argv[cursor++] = receiver->ptr();
Ben Murdochf91f0612016-11-29 16:50:11 +0000216 for (int i = 0; i < argc; ++i) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000217 argv[cursor++] = args[i]->ptr();
Ben Murdochf91f0612016-11-29 16:50:11 +0000218 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000219 MaybeHandle<Object> result;
220 {
221 RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
222 if (is_construct) {
223 result = HandleApiCallHelper<true>(isolate, function, new_target,
224 fun_data, receiver, arguments);
225 } else {
226 result = HandleApiCallHelper<false>(isolate, function, new_target,
227 fun_data, receiver, arguments);
228 }
229 }
230 if (argv != small_argv) delete[] argv;
231 return result;
232}
233
234// Helper function to handle calls to non-function objects created through the
235// API. The object can be called as either a constructor (using new) or just as
236// a function (without new).
Rubin Xu7bc1b612021-02-16 09:38:50 +0000237V8_WARN_UNUSED_RESULT static Object HandleApiCallAsFunctionOrConstructor(
Ben Murdochf91f0612016-11-29 16:50:11 +0000238 Isolate* isolate, bool is_construct_call, BuiltinArguments args) {
239 Handle<Object> receiver = args.receiver();
240
241 // Get the object called.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000242 JSObject obj = JSObject::cast(*receiver);
Ben Murdochf91f0612016-11-29 16:50:11 +0000243
244 // Set the new target.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000245 HeapObject new_target;
Ben Murdochf91f0612016-11-29 16:50:11 +0000246 if (is_construct_call) {
247 // TODO(adamk): This should be passed through in args instead of
248 // being patched in here. We need to set a non-undefined value
249 // for v8::FunctionCallbackInfo::IsConstructCall() to get the
250 // right answer.
251 new_target = obj;
252 } else {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000253 new_target = ReadOnlyRoots(isolate).undefined_value();
Ben Murdochf91f0612016-11-29 16:50:11 +0000254 }
255
256 // Get the invocation callback from the function descriptor that was
257 // used to create the called object.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000258 DCHECK(obj.map().is_callable());
259 JSFunction constructor = JSFunction::cast(obj.map().GetConstructor());
260 DCHECK(constructor.shared().IsApiFunction());
261 Object handler =
262 constructor.shared().get_api_func_data().GetInstanceCallHandler();
263 DCHECK(!handler.IsUndefined(isolate));
264 CallHandlerInfo call_data = CallHandlerInfo::cast(handler);
Ben Murdochf91f0612016-11-29 16:50:11 +0000265
266 // Get the data for the call and perform the callback.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000267 Object result;
Ben Murdochf91f0612016-11-29 16:50:11 +0000268 {
269 HandleScope scope(isolate);
270 LOG(isolate, ApiObjectAccess("call non-function", obj));
Rubin Xu7bc1b612021-02-16 09:38:50 +0000271 FunctionCallbackArguments custom(
272 isolate, call_data.data(), constructor, obj, new_target,
273 args.address_of_first_argument(), args.length() - 1);
274 Handle<Object> result_handle = custom.Call(call_data);
Ben Murdochf91f0612016-11-29 16:50:11 +0000275 if (result_handle.is_null()) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000276 result = ReadOnlyRoots(isolate).undefined_value();
Ben Murdochf91f0612016-11-29 16:50:11 +0000277 } else {
278 result = *result_handle;
279 }
280 }
281 // Check for exceptions and return result.
282 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
283 return result;
284}
285
286// Handle calls to non-function objects created through the API. This delegate
287// function is used when the call is a normal function call.
288BUILTIN(HandleApiCallAsFunction) {
289 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
290}
291
292// Handle calls to non-function objects created through the API. This delegate
293// function is used when the call is a construct call.
294BUILTIN(HandleApiCallAsConstructor) {
295 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
296}
297
298} // namespace internal
299} // namespace v8