v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
builtins-api.cc
Go to the documentation of this file.
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
11#include "src/logging/log.h"
17
18namespace v8 {
19namespace internal {
20
21namespace {
22
23// Returns true if the function can legally be called with this receiver,
24// otherwise false.
25// TODO(ishell): CallOptimization duplicates this logic, merge.
26bool IsCompatibleReceiver(Isolate* isolate, Tagged<FunctionTemplateInfo> info,
28 RCS_SCOPE(isolate, RuntimeCallCounterId::kGetCompatibleReceiver);
29 Tagged<Object> recv_type = info->signature();
30 // No signature, so function can be called with any receiver.
31 if (!IsFunctionTemplateInfo(recv_type)) return true;
32 // A Proxy cannot have been created from the signature template.
33 if (!IsJSObject(receiver)) return false;
34
35 Tagged<JSObject> js_obj_receiver = Cast<JSObject>(receiver);
38
39 // Check the receiver.
40 if (signature->IsTemplateFor(js_obj_receiver)) return true;
41
42 // The JSGlobalProxy might have a hidden prototype.
43 if (V8_UNLIKELY(IsJSGlobalProxy(js_obj_receiver))) {
44 Tagged<HeapObject> prototype = js_obj_receiver->map()->prototype();
45 if (!IsNull(prototype, isolate)) {
46 Tagged<JSObject> js_obj_prototype = Cast<JSObject>(prototype);
47 if (signature->IsTemplateFor(js_obj_prototype)) return true;
48 }
49 }
50 return false;
51}
52
53// argv and argc are the same as those passed to FunctionCallbackInfo:
54// - argc is the number of arguments excluding the receiver
55// - argv is the array arguments. The receiver is stored at argv[-1].
56template <bool is_construct>
57V8_WARN_UNUSED_RESULT MaybeHandle<Object> HandleApiCallHelper(
58 Isolate* isolate, DirectHandle<HeapObject> new_target,
59 DirectHandle<FunctionTemplateInfo> fun_data, DirectHandle<Object> receiver,
60 Address* argv, int argc) {
61 Handle<JSReceiver> js_receiver;
62 if (is_construct) {
63 DCHECK(IsTheHole(*receiver, isolate));
64 if (IsUndefined(fun_data->GetInstanceTemplate(), isolate)) {
66 ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate),
68 FunctionTemplateInfo::SetInstanceTemplate(
69 isolate, fun_data, Utils::OpenDirectHandle(*templ));
70 }
71 DirectHandle<ObjectTemplateInfo> instance_template(
72 Cast<ObjectTemplateInfo>(fun_data->GetInstanceTemplate()), isolate);
74 isolate, js_receiver,
75 ApiNatives::InstantiateObject(isolate, instance_template,
77 argv[BuiltinArguments::kReceiverArgsIndex] = js_receiver->ptr();
78 } else {
79 DCHECK(IsJSReceiver(*receiver));
80 js_receiver = indirect_handle(Cast<JSReceiver>(receiver), isolate);
81
82 if (!fun_data->accept_any_receiver() && IsAccessCheckNeeded(*js_receiver)) {
83 // Proxies never need access checks.
84 DCHECK(IsJSObject(*js_receiver));
85 DirectHandle<JSObject> js_object = Cast<JSObject>(js_receiver);
86 if (!isolate->MayAccess(isolate->native_context(), js_object)) {
87 RETURN_ON_EXCEPTION(isolate,
88 isolate->ReportFailedAccessCheck(js_object));
90 }
91 }
92
93 if (!IsCompatibleReceiver(isolate, *fun_data, *js_receiver)) {
94 // This function cannot be called with the given receiver. Abort!
95 THROW_NEW_ERROR(isolate,
96 NewTypeError(MessageTemplate::kIllegalInvocation));
97 }
98 }
99
100 if (fun_data->has_callback(isolate)) {
101 FunctionCallbackArguments custom(isolate, *fun_data, *new_target, argv,
102 argc);
103 DirectHandle<Object> result =
104 custom.CallOrConstruct(*fun_data, is_construct);
105
107 if (result.is_null()) {
108 if (is_construct) return js_receiver;
109 return isolate->factory()->undefined_value();
110 }
111 // Rebox the result.
112 {
114 Tagged<Object> raw_result = *result;
115 DCHECK(Is<JSAny>(raw_result));
116 if (!is_construct || IsJSReceiver(raw_result))
117 return handle(raw_result, isolate);
118 }
119 }
120
121 return js_receiver;
122}
123
124} // anonymous namespace
125
126BUILTIN(HandleApiConstruct) {
127 HandleScope scope(isolate);
130 DCHECK(!IsUndefined(*new_target, isolate));
132 args.target()->shared()->api_func_data(), isolate);
133 int argc = args.length() - 1;
134 Address* argv = args.address_of_first_argument();
136 isolate, HandleApiCallHelper<true>(isolate, new_target, fun_data,
137 receiver, argv, argc));
138}
139
140namespace {
141
142class RelocatableArguments : public Relocatable {
143 public:
144 RelocatableArguments(Isolate* isolate, size_t length, Address* arguments)
145 : Relocatable(isolate), length_(length), arguments_(arguments) {
146 DCHECK_LT(0, length_);
147 }
148
149 RelocatableArguments(const RelocatableArguments&) = delete;
150 RelocatableArguments& operator=(const RelocatableArguments&) = delete;
151
152 inline void IterateInstance(RootVisitor* v) override {
153 v->VisitRootPointers(Root::kRelocatable, nullptr,
154 FullObjectSlot(&arguments_[0]),
155 FullObjectSlot(&arguments_[length_]));
156 }
157
158 private:
159 size_t length_;
161};
162
163} // namespace
164
166 Isolate* isolate, bool is_construct,
170 RCS_SCOPE(isolate, RuntimeCallCounterId::kInvokeApiFunction);
171
172 // Do proper receiver conversion for non-strict mode api functions.
173 if (!is_construct && !IsJSReceiver(*receiver)) {
176 }
177
178 // We assume that all lazy accessor pairs have been instantiated when setting
179 // a break point on any API function.
180 DCHECK(!Cast<FunctionTemplateInfo>(function)->BreakAtEntry(isolate));
181
182 int argc = static_cast<int>(args.size());
183 base::SmallVector<Address, 32> argv(argc + 1);
184 argv[0] = (*receiver).ptr();
185 for (int i = 0; i < argc; ++i) {
186 argv[i + 1] = (*args[i]).ptr();
187 }
188
189 RelocatableArguments arguments(isolate, argv.size(), argv.data());
190 if (is_construct) {
191 return HandleApiCallHelper<true>(isolate, new_target, function, receiver,
192 argv.data() + 1, argc);
193 }
194 return HandleApiCallHelper<false>(isolate, new_target, function, receiver,
195 argv.data() + 1, argc);
196}
197
198// Helper function to handle calls to non-function objects created through the
199// API. The object can be called as either a constructor (using new) or just as
200// a function (without new).
203 bool is_construct_call,
206
207 // Get the object called.
209
210 // Set the new target.
212 if (is_construct_call) {
213 // TODO(adamk): This should be passed through in args instead of
214 // being patched in here. We need to set a non-undefined value
215 // for v8::FunctionCallbackInfo::IsConstructCall() to get the
216 // right answer.
217 new_target = obj;
218 } else {
219 new_target = ReadOnlyRoots(isolate).undefined_value();
220 }
221
222 // Get the invocation callback from the function descriptor that was
223 // used to create the called object.
224 DCHECK(obj->map()->is_callable());
225 Tagged<JSFunction> constructor =
226 Cast<JSFunction>(obj->map()->GetConstructor());
227 DCHECK(constructor->shared()->IsApiFunction());
228 Tagged<Object> handler =
229 constructor->shared()->api_func_data()->GetInstanceCallHandler();
230 DCHECK(!IsUndefined(handler, isolate));
232 DCHECK(templ->is_object_template_call_handler());
233 DCHECK(templ->has_callback(isolate));
234
235 // Get the data for the call and perform the callback.
237 {
238 HandleScope scope(isolate);
239 FunctionCallbackArguments custom(isolate, templ, new_target,
240 args.address_of_first_argument(),
241 args.length() - 1);
242 DirectHandle<Object> result_handle =
243 custom.CallOrConstruct(templ, is_construct_call);
244 if (result_handle.is_null()) {
245 result = ReadOnlyRoots(isolate).undefined_value();
246 } else {
247 result = *result_handle;
248 }
249 // Check for exceptions and return result.
251 }
252 return result;
253}
254
255// Handle calls to non-function objects created through the API. This delegate
256// function is used when the call is a normal function call.
257BUILTIN(HandleApiCallAsFunctionDelegate) {
260}
261
262// Handle calls to non-function objects created through the API. This delegate
263// function is used when the call is a construct call.
264BUILTIN(HandleApiCallAsConstructorDelegate) {
265 isolate->CountUsage(
268}
269
270} // namespace internal
271} // namespace v8
Address * arguments_
#define BUILTIN(name)
@ kDocumentAllLegacyCall
Definition v8-isolate.h:610
@ kDocumentAllLegacyConstruct
Definition v8-isolate.h:611
static Local< ObjectTemplate > New(Isolate *isolate, Local< FunctionTemplate > constructor=Local< FunctionTemplate >())
Definition api.cc:1376
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
Definition api.h:279
size_t size() const
static V8_WARN_UNUSED_RESULT MaybeHandle< JSObject > InstantiateObject(Isolate *isolate, DirectHandle< ObjectTemplateInfo > data, DirectHandle< JSReceiver > new_target={})
static constexpr int kReceiverArgsIndex
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > InvokeApiFunction(Isolate *isolate, bool is_construct, DirectHandle< FunctionTemplateInfo > function, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args, DirectHandle< HeapObject > new_target)
V8_INLINE bool is_null() const
Definition handles.h:693
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSReceiver > ConvertReceiver(Isolate *isolate, DirectHandle< Object > object)
Definition objects.cc:305
#define RETURN_FAILURE_IF_EXCEPTION(isolate)
Definition isolate.h:205
#define RETURN_ON_EXCEPTION(isolate, call)
Definition isolate.h:395
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:291
#define THROW_NEW_ERROR(isolate, call)
Definition isolate.h:307
#define RETURN_EXCEPTION_IF_EXCEPTION(isolate)
Definition isolate.h:235
#define RETURN_RESULT_OR_FAILURE(isolate, call)
Definition isolate.h:264
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
DirectHandle< Object > new_target
Definition execution.cc:75
bool is_construct
Definition execution.cc:82
TNode< Object > receiver
ZoneVector< RpoNumber > & result
const int length_
Definition mul-fft.cc:473
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
bool Is(IndirectHandle< U > value)
Definition handles-inl.h:51
Tagged(T object) -> Tagged< T >
V8_INLINE IndirectHandle< T > indirect_handle(DirectHandle< T > handle)
Definition handles.h:757
kInterpreterTrampolineOffset Tagged< HeapObject >
static V8_WARN_UNUSED_RESULT Tagged< Object > HandleApiCallAsFunctionOrConstructorDelegate(Isolate *isolate, bool is_construct_call, BuiltinArguments args)
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset IsNull(value)||IsJSProxy(value)||IsWasmObject(value)||(IsJSObject(value) &&(HeapLayout
Definition map-inl.h:70
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Local< T > Handle
v8::Local< T > ToApiHandle(v8::internal::DirectHandle< v8::internal::Object > obj)
Definition api.h:297
#define RCS_SCOPE(...)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
#define V8_UNLIKELY(condition)
Definition v8config.h:660