1 // Copyright 2015 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/api/api-natives.h"
6
7 #include "src/api/api-inl.h"
8 #include "src/common/message-template.h"
9 #include "src/execution/isolate-inl.h"
10 #include "src/objects/api-callbacks.h"
11 #include "src/objects/hash-table-inl.h"
12 #include "src/objects/lookup.h"
13 #include "src/objects/property-cell.h"
14 #include "src/objects/templates.h"
15
16 namespace v8 {
17 namespace internal {
18
19 namespace {
20
21 class InvokeScope {
22 public:
InvokeScope(Isolate * isolate)23 explicit InvokeScope(Isolate* isolate)
24 : isolate_(isolate), save_context_(isolate) {}
~InvokeScope()25 ~InvokeScope() {
26 bool has_exception = isolate_->has_pending_exception();
27 if (has_exception) {
28 isolate_->ReportPendingMessages();
29 } else {
30 isolate_->clear_pending_message();
31 }
32 }
33
34 private:
35 Isolate* isolate_;
36 SaveContext save_context_;
37 };
38
39 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
40 Handle<ObjectTemplateInfo> data,
41 Handle<JSReceiver> new_target,
42 bool is_prototype);
43
44 MaybeHandle<JSFunction> InstantiateFunction(
45 Isolate* isolate, Handle<NativeContext> native_context,
46 Handle<FunctionTemplateInfo> data,
47 MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
48
InstantiateFunction(Isolate * isolate,Handle<FunctionTemplateInfo> data,MaybeHandle<Name> maybe_name=MaybeHandle<Name> ())49 MaybeHandle<JSFunction> InstantiateFunction(
50 Isolate* isolate, Handle<FunctionTemplateInfo> data,
51 MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
52 return InstantiateFunction(isolate, isolate->native_context(), data,
53 maybe_name);
54 }
55
Instantiate(Isolate * isolate,Handle<Object> data,MaybeHandle<Name> maybe_name=MaybeHandle<Name> ())56 MaybeHandle<Object> Instantiate(
57 Isolate* isolate, Handle<Object> data,
58 MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
59 if (data->IsFunctionTemplateInfo()) {
60 return InstantiateFunction(
61 isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name);
62 } else if (data->IsObjectTemplateInfo()) {
63 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
64 Handle<JSReceiver>(), false);
65 } else {
66 return data;
67 }
68 }
69
DefineAccessorProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes,bool force_instantiate)70 MaybeHandle<Object> DefineAccessorProperty(
71 Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
72 Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
73 bool force_instantiate) {
74 DCHECK(!getter->IsFunctionTemplateInfo() ||
75 !FunctionTemplateInfo::cast(*getter).do_not_cache());
76 DCHECK(!setter->IsFunctionTemplateInfo() ||
77 !FunctionTemplateInfo::cast(*setter).do_not_cache());
78 if (getter->IsFunctionTemplateInfo()) {
79 if (force_instantiate ||
80 FunctionTemplateInfo::cast(*getter).BreakAtEntry()) {
81 ASSIGN_RETURN_ON_EXCEPTION(
82 isolate, getter,
83 InstantiateFunction(isolate,
84 Handle<FunctionTemplateInfo>::cast(getter)),
85 Object);
86 }
87 }
88 if (setter->IsFunctionTemplateInfo()) {
89 if (force_instantiate ||
90 FunctionTemplateInfo::cast(*setter).BreakAtEntry()) {
91 ASSIGN_RETURN_ON_EXCEPTION(
92 isolate, setter,
93 InstantiateFunction(isolate,
94 Handle<FunctionTemplateInfo>::cast(setter)),
95 Object);
96 }
97 }
98 RETURN_ON_EXCEPTION(
99 isolate,
100 JSObject::DefineAccessor(object, name, getter, setter, attributes),
101 Object);
102 return object;
103 }
104
DefineDataProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> prop_data,PropertyAttributes attributes)105 MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
106 Handle<JSObject> object,
107 Handle<Name> name,
108 Handle<Object> prop_data,
109 PropertyAttributes attributes) {
110 Handle<Object> value;
111 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
112 Instantiate(isolate, prop_data, name), Object);
113
114 LookupIterator::Key key(isolate, name);
115 LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
116
117 #ifdef DEBUG
118 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
119 DCHECK(maybe.IsJust());
120 if (it.IsFound()) {
121 THROW_NEW_ERROR(
122 isolate,
123 NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
124 Object);
125 }
126 #endif
127
128 MAYBE_RETURN_NULL(Object::AddDataProperty(&it, value, attributes,
129 Just(ShouldThrow::kThrowOnError),
130 StoreOrigin::kNamed));
131 return value;
132 }
133
DisableAccessChecks(Isolate * isolate,Handle<JSObject> object)134 void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
135 Handle<Map> old_map(object->map(), isolate);
136 // Copy map so it won't interfere constructor's initial map.
137 Handle<Map> new_map = Map::Copy(isolate, old_map, "DisableAccessChecks");
138 new_map->set_is_access_check_needed(false);
139 JSObject::MigrateToMap(isolate, Handle<JSObject>::cast(object), new_map);
140 }
141
EnableAccessChecks(Isolate * isolate,Handle<JSObject> object)142 void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
143 Handle<Map> old_map(object->map(), isolate);
144 // Copy map so it won't interfere constructor's initial map.
145 Handle<Map> new_map = Map::Copy(isolate, old_map, "EnableAccessChecks");
146 new_map->set_is_access_check_needed(true);
147 new_map->set_may_have_interesting_symbols(true);
148 JSObject::MigrateToMap(isolate, object, new_map);
149 }
150
151 class AccessCheckDisableScope {
152 public:
AccessCheckDisableScope(Isolate * isolate,Handle<JSObject> obj)153 AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
154 : isolate_(isolate),
155 disabled_(obj->map().is_access_check_needed()),
156 obj_(obj) {
157 if (disabled_) {
158 DisableAccessChecks(isolate_, obj_);
159 }
160 }
~AccessCheckDisableScope()161 ~AccessCheckDisableScope() {
162 if (disabled_) {
163 EnableAccessChecks(isolate_, obj_);
164 }
165 }
166
167 private:
168 Isolate* isolate_;
169 const bool disabled_;
170 Handle<JSObject> obj_;
171 };
172
GetIntrinsic(Isolate * isolate,v8::Intrinsic intrinsic)173 Object GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
174 Handle<Context> native_context = isolate->native_context();
175 DCHECK(!native_context.is_null());
176 switch (intrinsic) {
177 #define GET_INTRINSIC_VALUE(name, iname) \
178 case v8::k##name: \
179 return native_context->iname();
180 V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
181 #undef GET_INTRINSIC_VALUE
182 }
183 return Object();
184 }
185
186 template <typename TemplateInfoT>
ConfigureInstance(Isolate * isolate,Handle<JSObject> obj,Handle<TemplateInfoT> data)187 MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
188 Handle<TemplateInfoT> data) {
189 HandleScope scope(isolate);
190 // Disable access checks while instantiating the object.
191 AccessCheckDisableScope access_check_scope(isolate, obj);
192
193 // Walk the inheritance chain and copy all accessors to current object.
194 int max_number_of_properties = 0;
195 TemplateInfoT info = *data;
196 while (!info.is_null()) {
197 Object props = info.property_accessors();
198 if (!props.IsUndefined(isolate)) {
199 max_number_of_properties += TemplateList::cast(props).length();
200 }
201 info = info.GetParent(isolate);
202 }
203
204 if (max_number_of_properties > 0) {
205 int valid_descriptors = 0;
206 // Use a temporary FixedArray to accumulate unique accessors.
207 Handle<FixedArray> array =
208 isolate->factory()->NewFixedArray(max_number_of_properties);
209
210 for (Handle<TemplateInfoT> temp(*data, isolate); !temp->is_null();
211 temp = handle(temp->GetParent(isolate), isolate)) {
212 // Accumulate accessors.
213 Object maybe_properties = temp->property_accessors();
214 if (!maybe_properties.IsUndefined(isolate)) {
215 valid_descriptors = AccessorInfo::AppendUnique(
216 isolate, handle(maybe_properties, isolate), array,
217 valid_descriptors);
218 }
219 }
220
221 // Install accumulated accessors.
222 for (int i = 0; i < valid_descriptors; i++) {
223 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)), isolate);
224 Handle<Name> name(Name::cast(accessor->name()), isolate);
225 JSObject::SetAccessor(obj, name, accessor,
226 accessor->initial_property_attributes())
227 .Assert();
228 }
229 }
230
231 Object maybe_property_list = data->property_list();
232 if (maybe_property_list.IsUndefined(isolate)) return obj;
233 Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
234 isolate);
235 if (properties->length() == 0) return obj;
236
237 int i = 0;
238 for (int c = 0; c < data->number_of_properties(); c++) {
239 auto name = handle(Name::cast(properties->get(i++)), isolate);
240 Object bit = properties->get(i++);
241 if (bit.IsSmi()) {
242 PropertyDetails details(Smi::cast(bit));
243 PropertyAttributes attributes = details.attributes();
244 PropertyKind kind = details.kind();
245
246 if (kind == kData) {
247 auto prop_data = handle(properties->get(i++), isolate);
248 RETURN_ON_EXCEPTION(
249 isolate,
250 DefineDataProperty(isolate, obj, name, prop_data, attributes),
251 JSObject);
252 } else {
253 auto getter = handle(properties->get(i++), isolate);
254 auto setter = handle(properties->get(i++), isolate);
255 RETURN_ON_EXCEPTION(isolate,
256 DefineAccessorProperty(isolate, obj, name, getter,
257 setter, attributes, false),
258 JSObject);
259 }
260 } else {
261 // Intrinsic data property --- Get appropriate value from the current
262 // context.
263 PropertyDetails details(Smi::cast(properties->get(i++)));
264 PropertyAttributes attributes = details.attributes();
265 DCHECK_EQ(kData, details.kind());
266
267 v8::Intrinsic intrinsic =
268 static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++)));
269 auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
270
271 RETURN_ON_EXCEPTION(
272 isolate,
273 DefineDataProperty(isolate, obj, name, prop_data, attributes),
274 JSObject);
275 }
276 }
277 return obj;
278 }
279
280 // Whether or not to cache every instance: when we materialize a getter or
281 // setter from an lazy AccessorPair, we rely on this cache to be able to always
282 // return the same getter or setter. However, objects will be cloned anyways,
283 // so it's not observable if we didn't cache an instance. Furthermore, a badly
284 // behaved embedder might create an unlimited number of objects, so we limit
285 // the cache for those cases.
286 enum class CachingMode { kLimited, kUnlimited };
287
ProbeInstantiationsCache(Isolate * isolate,Handle<NativeContext> native_context,int serial_number,CachingMode caching_mode)288 MaybeHandle<JSObject> ProbeInstantiationsCache(
289 Isolate* isolate, Handle<NativeContext> native_context, int serial_number,
290 CachingMode caching_mode) {
291 DCHECK_LE(1, serial_number);
292 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
293 FixedArray fast_cache =
294 native_context->fast_template_instantiations_cache();
295 Handle<Object> object{fast_cache.get(serial_number - 1), isolate};
296 if (object->IsUndefined(isolate)) return {};
297 return Handle<JSObject>::cast(object);
298 }
299 if (caching_mode == CachingMode::kUnlimited ||
300 (serial_number <= TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
301 SimpleNumberDictionary slow_cache =
302 native_context->slow_template_instantiations_cache();
303 InternalIndex entry = slow_cache.FindEntry(isolate, serial_number);
304 if (entry.is_found()) {
305 return handle(JSObject::cast(slow_cache.ValueAt(entry)), isolate);
306 }
307 }
308 return {};
309 }
310
CacheTemplateInstantiation(Isolate * isolate,Handle<NativeContext> native_context,int serial_number,CachingMode caching_mode,Handle<JSObject> object)311 void CacheTemplateInstantiation(Isolate* isolate,
312 Handle<NativeContext> native_context,
313 int serial_number, CachingMode caching_mode,
314 Handle<JSObject> object) {
315 DCHECK_LE(1, serial_number);
316 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
317 Handle<FixedArray> fast_cache =
318 handle(native_context->fast_template_instantiations_cache(), isolate);
319 Handle<FixedArray> new_cache =
320 FixedArray::SetAndGrow(isolate, fast_cache, serial_number - 1, object);
321 if (*new_cache != *fast_cache) {
322 native_context->set_fast_template_instantiations_cache(*new_cache);
323 }
324 } else if (caching_mode == CachingMode::kUnlimited ||
325 (serial_number <=
326 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
327 Handle<SimpleNumberDictionary> cache =
328 handle(native_context->slow_template_instantiations_cache(), isolate);
329 auto new_cache =
330 SimpleNumberDictionary::Set(isolate, cache, serial_number, object);
331 if (*new_cache != *cache) {
332 native_context->set_slow_template_instantiations_cache(*new_cache);
333 }
334 }
335 }
336
UncacheTemplateInstantiation(Isolate * isolate,Handle<NativeContext> native_context,int serial_number,CachingMode caching_mode)337 void UncacheTemplateInstantiation(Isolate* isolate,
338 Handle<NativeContext> native_context,
339 int serial_number, CachingMode caching_mode) {
340 DCHECK_LE(1, serial_number);
341 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
342 FixedArray fast_cache =
343 native_context->fast_template_instantiations_cache();
344 DCHECK(!fast_cache.get(serial_number - 1).IsUndefined(isolate));
345 fast_cache.set_undefined(serial_number - 1);
346 } else if (caching_mode == CachingMode::kUnlimited ||
347 (serial_number <=
348 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
349 Handle<SimpleNumberDictionary> cache =
350 handle(native_context->slow_template_instantiations_cache(), isolate);
351 InternalIndex entry = cache->FindEntry(isolate, serial_number);
352 DCHECK(entry.is_found());
353 cache = SimpleNumberDictionary::DeleteEntry(isolate, cache, entry);
354 native_context->set_slow_template_instantiations_cache(*cache);
355 }
356 }
357
IsSimpleInstantiation(Isolate * isolate,ObjectTemplateInfo info,JSReceiver new_target)358 bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo info,
359 JSReceiver new_target) {
360 DisallowHeapAllocation no_gc;
361
362 if (!new_target.IsJSFunction()) return false;
363 JSFunction fun = JSFunction::cast(new_target);
364 if (fun.shared().function_data(kAcquireLoad) != info.constructor())
365 return false;
366 if (info.immutable_proto()) return false;
367 return fun.context().native_context() == isolate->raw_native_context();
368 }
369
InstantiateObject(Isolate * isolate,Handle<ObjectTemplateInfo> info,Handle<JSReceiver> new_target,bool is_prototype)370 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
371 Handle<ObjectTemplateInfo> info,
372 Handle<JSReceiver> new_target,
373 bool is_prototype) {
374 Handle<JSFunction> constructor;
375 int serial_number = info->serial_number();
376 if (!new_target.is_null()) {
377 if (IsSimpleInstantiation(isolate, *info, *new_target)) {
378 constructor = Handle<JSFunction>::cast(new_target);
379 } else {
380 // Disable caching for subclass instantiation.
381 serial_number = 0;
382 }
383 }
384 // Fast path.
385 Handle<JSObject> result;
386 if (serial_number) {
387 if (ProbeInstantiationsCache(isolate, isolate->native_context(),
388 serial_number, CachingMode::kLimited)
389 .ToHandle(&result)) {
390 return isolate->factory()->CopyJSObject(result);
391 }
392 }
393
394 if (constructor.is_null()) {
395 Object maybe_constructor_info = info->constructor();
396 if (maybe_constructor_info.IsUndefined(isolate)) {
397 constructor = isolate->object_function();
398 } else {
399 // Enter a new scope. Recursion could otherwise create a lot of handles.
400 HandleScope scope(isolate);
401 Handle<FunctionTemplateInfo> cons_templ(
402 FunctionTemplateInfo::cast(maybe_constructor_info), isolate);
403 Handle<JSFunction> tmp_constructor;
404 ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
405 InstantiateFunction(isolate, cons_templ),
406 JSObject);
407 constructor = scope.CloseAndEscape(tmp_constructor);
408 }
409
410 if (new_target.is_null()) new_target = constructor;
411 }
412
413 Handle<JSObject> object;
414 ASSIGN_RETURN_ON_EXCEPTION(
415 isolate, object,
416 JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
417 JSObject);
418
419 if (is_prototype) JSObject::OptimizeAsPrototype(object);
420
421 ASSIGN_RETURN_ON_EXCEPTION(
422 isolate, result, ConfigureInstance(isolate, object, info), JSObject);
423 if (info->immutable_proto()) {
424 JSObject::SetImmutableProto(object);
425 }
426 if (!is_prototype) {
427 // Keep prototypes in slow-mode. Let them be lazily turned fast later on.
428 // TODO(dcarney): is this necessary?
429 JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
430 // Don't cache prototypes.
431 if (serial_number) {
432 CacheTemplateInstantiation(isolate, isolate->native_context(),
433 serial_number, CachingMode::kLimited, result);
434 result = isolate->factory()->CopyJSObject(result);
435 }
436 }
437
438 return result;
439 }
440
441 namespace {
GetInstancePrototype(Isolate * isolate,Handle<Object> function_template)442 MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
443 Handle<Object> function_template) {
444 // Enter a new scope. Recursion could otherwise create a lot of handles.
445 HandleScope scope(isolate);
446 Handle<JSFunction> parent_instance;
447 ASSIGN_RETURN_ON_EXCEPTION(
448 isolate, parent_instance,
449 InstantiateFunction(
450 isolate, Handle<FunctionTemplateInfo>::cast(function_template)),
451 JSFunction);
452 Handle<Object> instance_prototype;
453 // TODO(cbruni): decide what to do here.
454 ASSIGN_RETURN_ON_EXCEPTION(
455 isolate, instance_prototype,
456 JSObject::GetProperty(isolate, parent_instance,
457 isolate->factory()->prototype_string()),
458 JSFunction);
459 return scope.CloseAndEscape(instance_prototype);
460 }
461 } // namespace
462
InstantiateFunction(Isolate * isolate,Handle<NativeContext> native_context,Handle<FunctionTemplateInfo> data,MaybeHandle<Name> maybe_name)463 MaybeHandle<JSFunction> InstantiateFunction(
464 Isolate* isolate, Handle<NativeContext> native_context,
465 Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
466 int serial_number = data->serial_number();
467 if (serial_number) {
468 Handle<JSObject> result;
469 if (ProbeInstantiationsCache(isolate, native_context, serial_number,
470 CachingMode::kUnlimited)
471 .ToHandle(&result)) {
472 return Handle<JSFunction>::cast(result);
473 }
474 }
475 Handle<Object> prototype;
476 if (!data->remove_prototype()) {
477 Handle<Object> prototype_templ(data->GetPrototypeTemplate(), isolate);
478 if (prototype_templ->IsUndefined(isolate)) {
479 Handle<Object> protoype_provider_templ(
480 data->GetPrototypeProviderTemplate(), isolate);
481 if (protoype_provider_templ->IsUndefined(isolate)) {
482 prototype = isolate->factory()->NewJSObject(isolate->object_function());
483 } else {
484 ASSIGN_RETURN_ON_EXCEPTION(
485 isolate, prototype,
486 GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
487 }
488 } else {
489 ASSIGN_RETURN_ON_EXCEPTION(
490 isolate, prototype,
491 InstantiateObject(isolate,
492 Handle<ObjectTemplateInfo>::cast(prototype_templ),
493 Handle<JSReceiver>(), true),
494 JSFunction);
495 }
496 Handle<Object> parent(data->GetParentTemplate(), isolate);
497 if (!parent->IsUndefined(isolate)) {
498 Handle<Object> parent_prototype;
499 ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
500 GetInstancePrototype(isolate, parent),
501 JSFunction);
502 CHECK(parent_prototype->IsHeapObject());
503 JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
504 Handle<HeapObject>::cast(parent_prototype));
505 }
506 }
507 InstanceType function_type =
508 (!data->needs_access_check() &&
509 data->GetNamedPropertyHandler().IsUndefined(isolate) &&
510 data->GetIndexedPropertyHandler().IsUndefined(isolate))
511 ? JS_API_OBJECT_TYPE
512 : JS_SPECIAL_API_OBJECT_TYPE;
513
514 Handle<JSFunction> function = ApiNatives::CreateApiFunction(
515 isolate, native_context, data, prototype, function_type, maybe_name);
516 if (serial_number) {
517 // Cache the function.
518 CacheTemplateInstantiation(isolate, native_context, serial_number,
519 CachingMode::kUnlimited, function);
520 }
521 MaybeHandle<JSObject> result = ConfigureInstance(isolate, function, data);
522 if (result.is_null()) {
523 // Uncache on error.
524 if (serial_number) {
525 UncacheTemplateInstantiation(isolate, native_context, serial_number,
526 CachingMode::kUnlimited);
527 }
528 return MaybeHandle<JSFunction>();
529 }
530 return function;
531 }
532
AddPropertyToPropertyList(Isolate * isolate,Handle<TemplateInfo> templ,int length,Handle<Object> * data)533 void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
534 int length, Handle<Object>* data) {
535 Object maybe_list = templ->property_list();
536 Handle<TemplateList> list;
537 if (maybe_list.IsUndefined(isolate)) {
538 list = TemplateList::New(isolate, length);
539 } else {
540 list = handle(TemplateList::cast(maybe_list), isolate);
541 }
542 templ->set_number_of_properties(templ->number_of_properties() + 1);
543 for (int i = 0; i < length; i++) {
544 Handle<Object> value =
545 data[i].is_null()
546 ? Handle<Object>::cast(isolate->factory()->undefined_value())
547 : data[i];
548 list = TemplateList::Add(isolate, list, value);
549 }
550 templ->set_property_list(*list);
551 }
552
553 } // namespace
554
InstantiateFunction(Isolate * isolate,Handle<NativeContext> native_context,Handle<FunctionTemplateInfo> data,MaybeHandle<Name> maybe_name)555 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
556 Isolate* isolate, Handle<NativeContext> native_context,
557 Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
558 InvokeScope invoke_scope(isolate);
559 return ::v8::internal::InstantiateFunction(isolate, native_context, data,
560 maybe_name);
561 }
562
InstantiateFunction(Handle<FunctionTemplateInfo> data,MaybeHandle<Name> maybe_name)563 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
564 Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
565 Isolate* isolate = data->GetIsolate();
566 InvokeScope invoke_scope(isolate);
567 return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
568 }
569
InstantiateObject(Isolate * isolate,Handle<ObjectTemplateInfo> data,Handle<JSReceiver> new_target)570 MaybeHandle<JSObject> ApiNatives::InstantiateObject(
571 Isolate* isolate, Handle<ObjectTemplateInfo> data,
572 Handle<JSReceiver> new_target) {
573 InvokeScope invoke_scope(isolate);
574 return ::v8::internal::InstantiateObject(isolate, data, new_target, false);
575 }
576
InstantiateRemoteObject(Handle<ObjectTemplateInfo> data)577 MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
578 Handle<ObjectTemplateInfo> data) {
579 Isolate* isolate = data->GetIsolate();
580 InvokeScope invoke_scope(isolate);
581
582 Handle<FunctionTemplateInfo> constructor(
583 FunctionTemplateInfo::cast(data->constructor()), isolate);
584 Handle<Map> object_map = isolate->factory()->NewMap(
585 JS_SPECIAL_API_OBJECT_TYPE,
586 JSObject::kHeaderSize +
587 data->embedder_field_count() * kEmbedderDataSlotSize,
588 TERMINAL_FAST_ELEMENTS_KIND);
589 object_map->SetConstructor(*constructor);
590 object_map->set_is_access_check_needed(true);
591 object_map->set_may_have_interesting_symbols(true);
592
593 Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(object_map);
594 JSObject::ForceSetPrototype(object, isolate->factory()->null_value());
595
596 return object;
597 }
598
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)599 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
600 Handle<Name> name, Handle<Object> value,
601 PropertyAttributes attributes) {
602 PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
603 auto details_handle = handle(details.AsSmi(), isolate);
604 Handle<Object> data[] = {name, details_handle, value};
605 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
606 }
607
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,v8::Intrinsic intrinsic,PropertyAttributes attributes)608 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
609 Handle<Name> name, v8::Intrinsic intrinsic,
610 PropertyAttributes attributes) {
611 auto value = handle(Smi::FromInt(intrinsic), isolate);
612 auto intrinsic_marker = isolate->factory()->true_value();
613 PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
614 auto details_handle = handle(details.AsSmi(), isolate);
615 Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
616 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
617 }
618
AddAccessorProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<FunctionTemplateInfo> getter,Handle<FunctionTemplateInfo> setter,PropertyAttributes attributes)619 void ApiNatives::AddAccessorProperty(Isolate* isolate,
620 Handle<TemplateInfo> info,
621 Handle<Name> name,
622 Handle<FunctionTemplateInfo> getter,
623 Handle<FunctionTemplateInfo> setter,
624 PropertyAttributes attributes) {
625 PropertyDetails details(kAccessor, attributes, PropertyCellType::kNoCell);
626 auto details_handle = handle(details.AsSmi(), isolate);
627 Handle<Object> data[] = {name, details_handle, getter, setter};
628 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
629 }
630
AddNativeDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<AccessorInfo> property)631 void ApiNatives::AddNativeDataProperty(Isolate* isolate,
632 Handle<TemplateInfo> info,
633 Handle<AccessorInfo> property) {
634 Object maybe_list = info->property_accessors();
635 Handle<TemplateList> list;
636 if (maybe_list.IsUndefined(isolate)) {
637 list = TemplateList::New(isolate, 1);
638 } else {
639 list = handle(TemplateList::cast(maybe_list), isolate);
640 }
641 list = TemplateList::Add(isolate, list, property);
642 info->set_property_accessors(*list);
643 }
644
CreateApiFunction(Isolate * isolate,Handle<NativeContext> native_context,Handle<FunctionTemplateInfo> obj,Handle<Object> prototype,InstanceType type,MaybeHandle<Name> maybe_name)645 Handle<JSFunction> ApiNatives::CreateApiFunction(
646 Isolate* isolate, Handle<NativeContext> native_context,
647 Handle<FunctionTemplateInfo> obj, Handle<Object> prototype,
648 InstanceType type, MaybeHandle<Name> maybe_name) {
649 Handle<SharedFunctionInfo> shared =
650 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
651 maybe_name);
652 // To simplify things, API functions always have shared name.
653 DCHECK(shared->HasSharedName());
654
655 Handle<JSFunction> result =
656 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
657 native_context);
658
659 if (obj->remove_prototype()) {
660 DCHECK(prototype.is_null());
661 DCHECK(result->shared().IsApiFunction());
662 DCHECK(!result->IsConstructor());
663 DCHECK(!result->has_prototype_slot());
664 return result;
665 }
666
667 // Down from here is only valid for API functions that can be used as a
668 // constructor (don't set the "remove prototype" flag).
669 DCHECK(result->has_prototype_slot());
670
671 if (obj->read_only_prototype()) {
672 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
673 }
674
675 if (prototype->IsTheHole(isolate)) {
676 prototype = isolate->factory()->NewFunctionPrototype(result);
677 } else if (obj->GetPrototypeProviderTemplate().IsUndefined(isolate)) {
678 JSObject::AddProperty(isolate, Handle<JSObject>::cast(prototype),
679 isolate->factory()->constructor_string(), result,
680 DONT_ENUM);
681 }
682
683 int embedder_field_count = 0;
684 bool immutable_proto = false;
685 if (!obj->GetInstanceTemplate().IsUndefined(isolate)) {
686 Handle<ObjectTemplateInfo> GetInstanceTemplate = Handle<ObjectTemplateInfo>(
687 ObjectTemplateInfo::cast(obj->GetInstanceTemplate()), isolate);
688 embedder_field_count = GetInstanceTemplate->embedder_field_count();
689 immutable_proto = GetInstanceTemplate->immutable_proto();
690 }
691
692 // JS_FUNCTION_TYPE requires information about the prototype slot.
693 DCHECK_NE(JS_FUNCTION_TYPE, type);
694 int instance_size = JSObject::GetHeaderSize(type) +
695 kEmbedderDataSlotSize * embedder_field_count;
696
697 Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
698 TERMINAL_FAST_ELEMENTS_KIND);
699 JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
700
701 // Mark as undetectable if needed.
702 if (obj->undetectable()) {
703 // We only allow callable undetectable receivers here, since this whole
704 // undetectable business is only to support document.all, which is both
705 // undetectable and callable. If we ever see the need to have an object
706 // that is undetectable but not callable, we need to update the types.h
707 // to allow encoding this.
708 CHECK(!obj->GetInstanceCallHandler().IsUndefined(isolate));
709 map->set_is_undetectable(true);
710 }
711
712 // Mark as needs_access_check if needed.
713 if (obj->needs_access_check()) {
714 map->set_is_access_check_needed(true);
715 map->set_may_have_interesting_symbols(true);
716 }
717
718 // Set interceptor information in the map.
719 if (!obj->GetNamedPropertyHandler().IsUndefined(isolate)) {
720 map->set_has_named_interceptor(true);
721 map->set_may_have_interesting_symbols(true);
722 }
723 if (!obj->GetIndexedPropertyHandler().IsUndefined(isolate)) {
724 map->set_has_indexed_interceptor(true);
725 }
726
727 // Mark instance as callable in the map.
728 if (!obj->GetInstanceCallHandler().IsUndefined(isolate)) {
729 map->set_is_callable(true);
730 map->set_is_constructor(!obj->undetectable());
731 }
732
733 if (immutable_proto) map->set_is_immutable_proto(true);
734
735 return result;
736 }
737
738 } // namespace internal
739 } // namespace v8
740