5 #include "src/api-natives.h" 7 #include "src/api-inl.h" 8 #include "src/isolate-inl.h" 9 #include "src/lookup.h" 10 #include "src/message-template.h" 11 #include "src/objects/api-callbacks.h" 12 #include "src/objects/hash-table-inl.h" 13 #include "src/objects/templates.h" 23 explicit InvokeScope(Isolate* isolate)
24 : isolate_(isolate), save_context_(isolate) {}
26 bool has_exception = isolate_->has_pending_exception();
28 isolate_->ReportPendingMessages();
30 isolate_->clear_pending_message();
36 SaveContext save_context_;
39 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
40 Handle<ObjectTemplateInfo> data,
41 Handle<JSReceiver> new_target,
42 bool is_hidden_prototype,
45 MaybeHandle<JSFunction> InstantiateFunction(
46 Isolate* isolate, Handle<FunctionTemplateInfo> data,
47 MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
49 MaybeHandle<Object> Instantiate(
50 Isolate* isolate, Handle<Object> data,
51 MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
52 if (data->IsFunctionTemplateInfo()) {
53 return InstantiateFunction(
54 isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name);
55 }
else if (data->IsObjectTemplateInfo()) {
56 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
57 Handle<JSReceiver>(),
false,
false);
63 MaybeHandle<Object> DefineAccessorProperty(
64 Isolate* isolate, Handle<JSObject>
object, Handle<Name> name,
65 Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
66 bool force_instantiate) {
67 DCHECK(!getter->IsFunctionTemplateInfo() ||
68 !FunctionTemplateInfo::cast(*getter)->do_not_cache());
69 DCHECK(!setter->IsFunctionTemplateInfo() ||
70 !FunctionTemplateInfo::cast(*setter)->do_not_cache());
71 if (force_instantiate) {
72 if (getter->IsFunctionTemplateInfo()) {
73 ASSIGN_RETURN_ON_EXCEPTION(
75 InstantiateFunction(isolate,
76 Handle<FunctionTemplateInfo>::cast(getter)),
79 if (setter->IsFunctionTemplateInfo()) {
80 ASSIGN_RETURN_ON_EXCEPTION(
82 InstantiateFunction(isolate,
83 Handle<FunctionTemplateInfo>::cast(setter)),
87 RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(
object, name, getter,
94 MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
95 Handle<JSObject>
object,
97 Handle<Object> prop_data,
98 PropertyAttributes attributes) {
100 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
101 Instantiate(isolate, prop_data, name), Object);
103 LookupIterator it = LookupIterator::PropertyOrElement(
104 isolate,
object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
107 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
108 DCHECK(maybe.IsJust());
112 NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
117 MAYBE_RETURN_NULL(Object::AddDataProperty(
118 &it, value, attributes, kThrowOnError, StoreOrigin::kNamed));
123 void DisableAccessChecks(Isolate* isolate, Handle<JSObject>
object) {
124 Handle<Map> old_map(object->map(), isolate);
126 Handle<Map> new_map = Map::Copy(isolate, old_map,
"DisableAccessChecks");
127 new_map->set_is_access_check_needed(
false);
128 JSObject::MigrateToMap(Handle<JSObject>::cast(
object), new_map);
132 void EnableAccessChecks(Isolate* isolate, Handle<JSObject>
object) {
133 Handle<Map> old_map(object->map(), isolate);
135 Handle<Map> new_map = Map::Copy(isolate, old_map,
"EnableAccessChecks");
136 new_map->set_is_access_check_needed(
true);
137 new_map->set_may_have_interesting_symbols(
true);
138 JSObject::MigrateToMap(
object, new_map);
142 class AccessCheckDisableScope {
144 AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
146 disabled_(obj->map()->is_access_check_needed()),
149 DisableAccessChecks(isolate_, obj_);
152 ~AccessCheckDisableScope() {
154 EnableAccessChecks(isolate_, obj_);
160 const bool disabled_;
161 Handle<JSObject> obj_;
165 Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
166 Handle<Context> native_context = isolate->native_context();
167 DCHECK(!native_context.is_null());
169 #define GET_INTRINSIC_VALUE(name, iname) \ 171 return native_context->iname(); 172 V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
173 #undef GET_INTRINSIC_VALUE 179 template <
typename TemplateInfoT>
180 MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
181 Handle<TemplateInfoT> data,
182 bool is_hidden_prototype) {
183 HandleScope scope(isolate);
185 AccessCheckDisableScope access_check_scope(isolate, obj);
188 int max_number_of_properties = 0;
189 TemplateInfoT* info = *data;
190 while (info !=
nullptr) {
191 Object* props = info->property_accessors();
192 if (!props->IsUndefined(isolate)) {
193 max_number_of_properties += TemplateList::cast(props)->length();
195 info = info->GetParent(isolate);
198 if (max_number_of_properties > 0) {
199 int valid_descriptors = 0;
201 Handle<FixedArray> array =
202 isolate->factory()->NewFixedArray(max_number_of_properties);
204 for (Handle<TemplateInfoT> temp(*data, isolate); *temp !=
nullptr;
205 temp = handle(temp->GetParent(isolate), isolate)) {
207 Object* maybe_properties = temp->property_accessors();
208 if (!maybe_properties->IsUndefined(isolate)) {
209 valid_descriptors = AccessorInfo::AppendUnique(
210 isolate, handle(maybe_properties, isolate), array,
216 for (
int i = 0;
i < valid_descriptors;
i++) {
217 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(
i)), isolate);
218 Handle<Name> name(Name::cast(accessor->name()), isolate);
219 JSObject::SetAccessor(obj, name, accessor,
220 accessor->initial_property_attributes())
225 Object* maybe_property_list = data->property_list();
226 if (maybe_property_list->IsUndefined(isolate))
return obj;
227 Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
229 if (properties->length() == 0)
return obj;
232 for (
int c = 0; c < data->number_of_properties(); c++) {
233 auto name = handle(Name::cast(properties->get(
i++)), isolate);
234 Object* bit = properties->get(
i++);
236 PropertyDetails details(Smi::cast(bit));
237 PropertyAttributes attributes = details.attributes();
238 PropertyKind kind = details.kind();
241 auto prop_data = handle(properties->get(
i++), isolate);
242 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
243 prop_data, attributes),
246 auto getter = handle(properties->get(
i++), isolate);
247 auto setter = handle(properties->get(
i++), isolate);
249 isolate, DefineAccessorProperty(isolate, obj, name, getter, setter,
250 attributes, is_hidden_prototype),
256 PropertyDetails details(Smi::cast(properties->get(
i++)));
257 PropertyAttributes attributes = details.attributes();
258 DCHECK_EQ(kData, details.kind());
260 v8::Intrinsic intrinsic =
261 static_cast<v8::Intrinsic
>(Smi::ToInt(properties->get(
i++)));
262 auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
264 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
265 prop_data, attributes),
278 enum class CachingMode { kLimited, kUnlimited };
280 MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
282 CachingMode caching_mode) {
283 DCHECK_LE(1, serial_number);
284 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
285 Handle<FixedArray> fast_cache =
286 isolate->fast_template_instantiations_cache();
287 return fast_cache->GetValue<JSObject>(isolate, serial_number - 1);
288 }
else if (caching_mode == CachingMode::kUnlimited ||
290 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
291 Handle<SimpleNumberDictionary> slow_cache =
292 isolate->slow_template_instantiations_cache();
293 int entry = slow_cache->FindEntry(isolate, serial_number);
294 if (entry == SimpleNumberDictionary::kNotFound) {
295 return MaybeHandle<JSObject>();
297 return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
299 return MaybeHandle<JSObject>();
303 void CacheTemplateInstantiation(Isolate* isolate,
int serial_number,
304 CachingMode caching_mode,
305 Handle<JSObject>
object) {
306 DCHECK_LE(1, serial_number);
307 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
308 Handle<FixedArray> fast_cache =
309 isolate->fast_template_instantiations_cache();
310 Handle<FixedArray> new_cache =
311 FixedArray::SetAndGrow(isolate, fast_cache, serial_number - 1,
object);
312 if (*new_cache != *fast_cache) {
313 isolate->native_context()->set_fast_template_instantiations_cache(
316 }
else if (caching_mode == CachingMode::kUnlimited ||
318 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
319 Handle<SimpleNumberDictionary> cache =
320 isolate->slow_template_instantiations_cache();
322 SimpleNumberDictionary::Set(isolate, cache, serial_number,
object);
323 if (*new_cache != *cache) {
324 isolate->native_context()->set_slow_template_instantiations_cache(
330 void UncacheTemplateInstantiation(Isolate* isolate,
int serial_number,
331 CachingMode caching_mode) {
332 DCHECK_LE(1, serial_number);
333 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
334 Handle<FixedArray> fast_cache =
335 isolate->fast_template_instantiations_cache();
336 DCHECK(!fast_cache->get(serial_number - 1)->IsUndefined(isolate));
337 fast_cache->set_undefined(serial_number - 1);
338 }
else if (caching_mode == CachingMode::kUnlimited ||
340 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
341 Handle<SimpleNumberDictionary> cache =
342 isolate->slow_template_instantiations_cache();
343 int entry = cache->FindEntry(isolate, serial_number);
344 DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
345 cache = SimpleNumberDictionary::DeleteEntry(isolate, cache, entry);
346 isolate->native_context()->set_slow_template_instantiations_cache(*cache);
350 bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo* info,
351 JSReceiver* new_target) {
352 DisallowHeapAllocation no_gc;
354 if (!new_target->IsJSFunction())
return false;
355 JSFunction* fun = JSFunction::cast(new_target);
356 if (fun->shared()->function_data() != info->constructor())
return false;
357 if (info->immutable_proto())
return false;
358 return fun->context()->native_context() == isolate->raw_native_context();
361 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
362 Handle<ObjectTemplateInfo> info,
363 Handle<JSReceiver> new_target,
364 bool is_hidden_prototype,
366 Handle<JSFunction> constructor;
367 int serial_number = Smi::ToInt(info->serial_number());
368 if (!new_target.is_null()) {
369 if (IsSimpleInstantiation(isolate, *info, *new_target)) {
370 constructor = Handle<JSFunction>::cast(new_target);
377 Handle<JSObject> result;
379 if (ProbeInstantiationsCache(isolate, serial_number, CachingMode::kLimited)
380 .ToHandle(&result)) {
381 return isolate->factory()->CopyJSObject(result);
385 if (constructor.is_null()) {
386 Object* maybe_constructor_info = info->constructor();
387 if (maybe_constructor_info->IsUndefined(isolate)) {
388 constructor = isolate->object_function();
391 HandleScope scope(isolate);
392 Handle<FunctionTemplateInfo> cons_templ(
393 FunctionTemplateInfo::cast(maybe_constructor_info), isolate);
394 Handle<JSFunction> tmp_constructor;
395 ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
396 InstantiateFunction(isolate, cons_templ),
398 constructor = scope.CloseAndEscape(tmp_constructor);
401 if (new_target.is_null()) new_target = constructor;
404 Handle<JSObject> object;
405 ASSIGN_RETURN_ON_EXCEPTION(
407 JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
410 if (is_prototype) JSObject::OptimizeAsPrototype(
object);
412 ASSIGN_RETURN_ON_EXCEPTION(
414 ConfigureInstance(isolate,
object, info, is_hidden_prototype), JSObject);
415 if (info->immutable_proto()) {
416 JSObject::SetImmutableProto(
object);
421 JSObject::MigrateSlowToFast(result, 0,
"ApiNatives::InstantiateObject");
424 CacheTemplateInstantiation(isolate, serial_number, CachingMode::kLimited,
426 result = isolate->factory()->CopyJSObject(result);
434 MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
435 Object* function_template) {
437 HandleScope scope(isolate);
438 Handle<JSFunction> parent_instance;
439 ASSIGN_RETURN_ON_EXCEPTION(
440 isolate, parent_instance,
443 handle(FunctionTemplateInfo::cast(function_template), isolate)),
445 Handle<Object> instance_prototype;
447 ASSIGN_RETURN_ON_EXCEPTION(
448 isolate, instance_prototype,
449 JSObject::GetProperty(isolate, parent_instance,
450 isolate->factory()->prototype_string()),
452 return scope.CloseAndEscape(instance_prototype);
456 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
457 Handle<FunctionTemplateInfo> data,
458 MaybeHandle<Name> maybe_name) {
459 int serial_number = Smi::ToInt(data->serial_number());
461 Handle<JSObject> result;
462 if (ProbeInstantiationsCache(isolate, serial_number,
463 CachingMode::kUnlimited)
464 .ToHandle(&result)) {
465 return Handle<JSFunction>::cast(result);
468 Handle<Object> prototype;
469 if (!data->remove_prototype()) {
470 Object* prototype_templ = data->GetPrototypeTemplate();
471 if (prototype_templ->IsUndefined(isolate)) {
472 Object* protoype_provider_templ = data->GetPrototypeProviderTemplate();
473 if (protoype_provider_templ->IsUndefined(isolate)) {
474 prototype = isolate->factory()->NewJSObject(isolate->object_function());
476 ASSIGN_RETURN_ON_EXCEPTION(
478 GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
481 ASSIGN_RETURN_ON_EXCEPTION(
485 handle(ObjectTemplateInfo::cast(prototype_templ), isolate),
486 Handle<JSReceiver>(), data->hidden_prototype(),
true),
489 Object* parent = data->GetParentTemplate();
490 if (!parent->IsUndefined(isolate)) {
491 Handle<Object> parent_prototype;
492 ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
493 GetInstancePrototype(isolate, parent),
495 JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
499 InstanceType function_type =
500 (!data->needs_access_check() &&
501 data->GetNamedPropertyHandler()->IsUndefined(isolate) &&
502 data->GetIndexedPropertyHandler()->IsUndefined(isolate))
504 : JS_SPECIAL_API_OBJECT_TYPE;
506 Handle<JSFunction>
function = ApiNatives::CreateApiFunction(
507 isolate, data, prototype, function_type, maybe_name);
510 CacheTemplateInstantiation(isolate, serial_number, CachingMode::kUnlimited,
513 MaybeHandle<JSObject> result =
514 ConfigureInstance(isolate,
function, data, data->hidden_prototype());
515 if (result.is_null()) {
518 UncacheTemplateInstantiation(isolate, serial_number,
519 CachingMode::kUnlimited);
521 return MaybeHandle<JSFunction>();
527 void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
528 int length, Handle<Object>* data) {
529 Object* maybe_list = templ->property_list();
530 Handle<TemplateList> list;
531 if (maybe_list->IsUndefined(isolate)) {
532 list = TemplateList::New(isolate, length);
534 list = handle(TemplateList::cast(maybe_list), isolate);
536 templ->set_number_of_properties(templ->number_of_properties() + 1);
537 for (
int i = 0;
i < length;
i++) {
538 Handle<Object> value =
540 ? Handle<Object>::cast(isolate->factory()->undefined_value())
542 list = TemplateList::Add(isolate, list, value);
544 templ->set_property_list(*list);
549 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
550 Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
551 Isolate* isolate = data->GetIsolate();
552 InvokeScope invoke_scope(isolate);
553 return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
556 MaybeHandle<JSObject> ApiNatives::InstantiateObject(
557 Isolate* isolate, Handle<ObjectTemplateInfo> data,
558 Handle<JSReceiver> new_target) {
559 InvokeScope invoke_scope(isolate);
560 return ::v8::internal::InstantiateObject(isolate, data, new_target,
false,
564 MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
565 Handle<ObjectTemplateInfo> data) {
566 Isolate* isolate = data->GetIsolate();
567 InvokeScope invoke_scope(isolate);
569 Handle<FunctionTemplateInfo> constructor(
570 FunctionTemplateInfo::cast(data->constructor()), isolate);
571 Handle<Map> object_map = isolate->factory()->NewMap(
572 JS_SPECIAL_API_OBJECT_TYPE,
573 JSObject::kHeaderSize +
574 data->embedder_field_count() * kEmbedderDataSlotSize,
575 TERMINAL_FAST_ELEMENTS_KIND);
576 object_map->SetConstructor(*constructor);
577 object_map->set_is_access_check_needed(
true);
578 object_map->set_may_have_interesting_symbols(
true);
580 Handle<JSObject>
object = isolate->factory()->NewJSObjectFromMap(object_map);
581 JSObject::ForceSetPrototype(
object, isolate->factory()->null_value());
586 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
587 Handle<Name> name, Handle<Object> value,
588 PropertyAttributes attributes) {
589 PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
590 auto details_handle = handle(details.AsSmi(), isolate);
591 Handle<Object> data[] = {name, details_handle, value};
592 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
596 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
597 Handle<Name> name, v8::Intrinsic intrinsic,
598 PropertyAttributes attributes) {
599 auto value = handle(Smi::FromInt(intrinsic), isolate);
600 auto intrinsic_marker = isolate->factory()->true_value();
601 PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
602 auto details_handle = handle(details.AsSmi(), isolate);
603 Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
604 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
608 void ApiNatives::AddAccessorProperty(Isolate* isolate,
609 Handle<TemplateInfo> info,
611 Handle<FunctionTemplateInfo> getter,
612 Handle<FunctionTemplateInfo> setter,
613 PropertyAttributes attributes) {
614 PropertyDetails details(kAccessor, attributes, PropertyCellType::kNoCell);
615 auto details_handle = handle(details.AsSmi(), isolate);
616 Handle<Object> data[] = {name, details_handle, getter, setter};
617 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
621 void ApiNatives::AddNativeDataProperty(Isolate* isolate,
622 Handle<TemplateInfo> info,
623 Handle<AccessorInfo> property) {
624 Object* maybe_list = info->property_accessors();
625 Handle<TemplateList> list;
626 if (maybe_list->IsUndefined(isolate)) {
627 list = TemplateList::New(isolate, 1);
629 list = handle(TemplateList::cast(maybe_list), isolate);
631 list = TemplateList::Add(isolate, list, property);
632 info->set_property_accessors(*list);
635 Handle<JSFunction> ApiNatives::CreateApiFunction(
636 Isolate* isolate, Handle<FunctionTemplateInfo> obj,
637 Handle<Object> prototype, InstanceType type, MaybeHandle<Name> maybe_name) {
638 Handle<SharedFunctionInfo> shared =
639 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
642 DCHECK(shared->HasSharedName());
644 Handle<JSFunction> result =
645 isolate->factory()->NewFunctionFromSharedFunctionInfo(
646 shared, isolate->native_context());
648 if (obj->remove_prototype()) {
649 DCHECK(prototype.is_null());
650 DCHECK(result->shared()->IsApiFunction());
651 DCHECK(!result->IsConstructor());
652 DCHECK(!result->has_prototype_slot());
658 DCHECK(result->has_prototype_slot());
660 if (obj->read_only_prototype()) {
661 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
664 if (prototype->IsTheHole(isolate)) {
665 prototype = isolate->factory()->NewFunctionPrototype(result);
666 }
else if (obj->GetPrototypeProviderTemplate()->IsUndefined(isolate)) {
667 JSObject::AddProperty(isolate, Handle<JSObject>::cast(prototype),
668 isolate->factory()->constructor_string(), result,
672 int embedder_field_count = 0;
673 bool immutable_proto =
false;
674 if (!obj->GetInstanceTemplate()->IsUndefined(isolate)) {
675 Handle<ObjectTemplateInfo> GetInstanceTemplate = Handle<ObjectTemplateInfo>(
676 ObjectTemplateInfo::cast(obj->GetInstanceTemplate()), isolate);
677 embedder_field_count = GetInstanceTemplate->embedder_field_count();
678 immutable_proto = GetInstanceTemplate->immutable_proto();
682 DCHECK_NE(JS_FUNCTION_TYPE, type);
683 int instance_size = JSObject::GetHeaderSize(type) +
684 kEmbedderDataSlotSize * embedder_field_count;
686 Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
687 TERMINAL_FAST_ELEMENTS_KIND);
688 JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
691 if (obj->undetectable()) {
697 CHECK(!obj->GetInstanceCallHandler()->IsUndefined(isolate));
698 map->set_is_undetectable(
true);
702 if (obj->needs_access_check()) {
703 map->set_is_access_check_needed(
true);
704 map->set_may_have_interesting_symbols(
true);
708 if (!obj->GetNamedPropertyHandler()->IsUndefined(isolate)) {
709 map->set_has_named_interceptor(
true);
710 map->set_may_have_interesting_symbols(
true);
712 if (!obj->GetIndexedPropertyHandler()->IsUndefined(isolate)) {
713 map->set_has_indexed_interceptor(
true);
717 if (!obj->GetInstanceCallHandler()->IsUndefined(isolate)) {
718 map->set_is_callable(
true);
719 map->set_is_constructor(!obj->undetectable());
722 if (immutable_proto) map->set_is_immutable_proto(
true);