summaryrefslogtreecommitdiff
path: root/deps/v8/src/api/api-natives.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/api/api-natives.cc')
-rw-r--r--deps/v8/src/api/api-natives.cc728
1 files changed, 728 insertions, 0 deletions
diff --git a/deps/v8/src/api/api-natives.cc b/deps/v8/src/api/api-natives.cc
new file mode 100644
index 0000000000..c22b7c47f9
--- /dev/null
+++ b/deps/v8/src/api/api-natives.cc
@@ -0,0 +1,728 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/api/api-natives.h"
+
+#include "src/api/api-inl.h"
+#include "src/execution/isolate-inl.h"
+#include "src/execution/message-template.h"
+#include "src/objects/api-callbacks.h"
+#include "src/objects/hash-table-inl.h"
+#include "src/objects/lookup.h"
+#include "src/objects/property-cell.h"
+#include "src/objects/templates.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+class InvokeScope {
+ public:
+ explicit InvokeScope(Isolate* isolate)
+ : isolate_(isolate), save_context_(isolate) {}
+ ~InvokeScope() {
+ bool has_exception = isolate_->has_pending_exception();
+ if (has_exception) {
+ isolate_->ReportPendingMessages();
+ } else {
+ isolate_->clear_pending_message();
+ }
+ }
+
+ private:
+ Isolate* isolate_;
+ SaveContext save_context_;
+};
+
+MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
+ Handle<ObjectTemplateInfo> data,
+ Handle<JSReceiver> new_target,
+ bool is_hidden_prototype,
+ bool is_prototype);
+
+MaybeHandle<JSFunction> InstantiateFunction(
+ Isolate* isolate, Handle<FunctionTemplateInfo> data,
+ MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
+
+MaybeHandle<Object> Instantiate(
+ Isolate* isolate, Handle<Object> data,
+ MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
+ if (data->IsFunctionTemplateInfo()) {
+ return InstantiateFunction(
+ isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name);
+ } else if (data->IsObjectTemplateInfo()) {
+ return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
+ Handle<JSReceiver>(), false, false);
+ } else {
+ return data;
+ }
+}
+
+MaybeHandle<Object> DefineAccessorProperty(
+ Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
+ Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
+ bool force_instantiate) {
+ DCHECK(!getter->IsFunctionTemplateInfo() ||
+ !FunctionTemplateInfo::cast(*getter).do_not_cache());
+ DCHECK(!setter->IsFunctionTemplateInfo() ||
+ !FunctionTemplateInfo::cast(*setter).do_not_cache());
+ if (getter->IsFunctionTemplateInfo()) {
+ if (force_instantiate ||
+ FunctionTemplateInfo::cast(*getter).BreakAtEntry()) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, getter,
+ InstantiateFunction(isolate,
+ Handle<FunctionTemplateInfo>::cast(getter)),
+ Object);
+ }
+ }
+ if (setter->IsFunctionTemplateInfo()) {
+ if (force_instantiate ||
+ FunctionTemplateInfo::cast(*setter).BreakAtEntry()) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, setter,
+ InstantiateFunction(isolate,
+ Handle<FunctionTemplateInfo>::cast(setter)),
+ Object);
+ }
+ }
+ RETURN_ON_EXCEPTION(
+ isolate,
+ JSObject::DefineAccessor(object, name, getter, setter, attributes),
+ Object);
+ return object;
+}
+
+MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
+ Handle<JSObject> object,
+ Handle<Name> name,
+ Handle<Object> prop_data,
+ PropertyAttributes attributes) {
+ Handle<Object> value;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
+ Instantiate(isolate, prop_data, name), Object);
+
+ LookupIterator it = LookupIterator::PropertyOrElement(
+ isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
+
+#ifdef DEBUG
+ Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+ DCHECK(maybe.IsJust());
+ if (it.IsFound()) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
+ Object);
+ }
+#endif
+
+ MAYBE_RETURN_NULL(Object::AddDataProperty(&it, value, attributes,
+ Just(ShouldThrow::kThrowOnError),
+ StoreOrigin::kNamed));
+ return value;
+}
+
+void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
+ Handle<Map> old_map(object->map(), isolate);
+ // Copy map so it won't interfere constructor's initial map.
+ Handle<Map> new_map = Map::Copy(isolate, old_map, "DisableAccessChecks");
+ new_map->set_is_access_check_needed(false);
+ JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
+}
+
+void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
+ Handle<Map> old_map(object->map(), isolate);
+ // Copy map so it won't interfere constructor's initial map.
+ Handle<Map> new_map = Map::Copy(isolate, old_map, "EnableAccessChecks");
+ new_map->set_is_access_check_needed(true);
+ new_map->set_may_have_interesting_symbols(true);
+ JSObject::MigrateToMap(object, new_map);
+}
+
+class AccessCheckDisableScope {
+ public:
+ AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
+ : isolate_(isolate),
+ disabled_(obj->map().is_access_check_needed()),
+ obj_(obj) {
+ if (disabled_) {
+ DisableAccessChecks(isolate_, obj_);
+ }
+ }
+ ~AccessCheckDisableScope() {
+ if (disabled_) {
+ EnableAccessChecks(isolate_, obj_);
+ }
+ }
+
+ private:
+ Isolate* isolate_;
+ const bool disabled_;
+ Handle<JSObject> obj_;
+};
+
+Object GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
+ Handle<Context> native_context = isolate->native_context();
+ DCHECK(!native_context.is_null());
+ switch (intrinsic) {
+#define GET_INTRINSIC_VALUE(name, iname) \
+ case v8::k##name: \
+ return native_context->iname();
+ V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
+#undef GET_INTRINSIC_VALUE
+ }
+ return Object();
+}
+
+template <typename TemplateInfoT>
+MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
+ Handle<TemplateInfoT> data,
+ bool is_hidden_prototype) {
+ HandleScope scope(isolate);
+ // Disable access checks while instantiating the object.
+ AccessCheckDisableScope access_check_scope(isolate, obj);
+
+ // Walk the inheritance chain and copy all accessors to current object.
+ int max_number_of_properties = 0;
+ TemplateInfoT info = *data;
+ while (!info.is_null()) {
+ Object props = info.property_accessors();
+ if (!props.IsUndefined(isolate)) {
+ max_number_of_properties += TemplateList::cast(props).length();
+ }
+ info = info.GetParent(isolate);
+ }
+
+ if (max_number_of_properties > 0) {
+ int valid_descriptors = 0;
+ // Use a temporary FixedArray to accumulate unique accessors.
+ Handle<FixedArray> array =
+ isolate->factory()->NewFixedArray(max_number_of_properties);
+
+ for (Handle<TemplateInfoT> temp(*data, isolate); !temp->is_null();
+ temp = handle(temp->GetParent(isolate), isolate)) {
+ // Accumulate accessors.
+ Object maybe_properties = temp->property_accessors();
+ if (!maybe_properties.IsUndefined(isolate)) {
+ valid_descriptors = AccessorInfo::AppendUnique(
+ isolate, handle(maybe_properties, isolate), array,
+ valid_descriptors);
+ }
+ }
+
+ // Install accumulated accessors.
+ for (int i = 0; i < valid_descriptors; i++) {
+ Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)), isolate);
+ Handle<Name> name(Name::cast(accessor->name()), isolate);
+ JSObject::SetAccessor(obj, name, accessor,
+ accessor->initial_property_attributes())
+ .Assert();
+ }
+ }
+
+ Object maybe_property_list = data->property_list();
+ if (maybe_property_list.IsUndefined(isolate)) return obj;
+ Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
+ isolate);
+ if (properties->length() == 0) return obj;
+
+ int i = 0;
+ for (int c = 0; c < data->number_of_properties(); c++) {
+ auto name = handle(Name::cast(properties->get(i++)), isolate);
+ Object bit = properties->get(i++);
+ if (bit.IsSmi()) {
+ PropertyDetails details(Smi::cast(bit));
+ PropertyAttributes attributes = details.attributes();
+ PropertyKind kind = details.kind();
+
+ if (kind == kData) {
+ auto prop_data = handle(properties->get(i++), isolate);
+ RETURN_ON_EXCEPTION(
+ isolate,
+ DefineDataProperty(isolate, obj, name, prop_data, attributes),
+ JSObject);
+ } else {
+ auto getter = handle(properties->get(i++), isolate);
+ auto setter = handle(properties->get(i++), isolate);
+ RETURN_ON_EXCEPTION(
+ isolate,
+ DefineAccessorProperty(isolate, obj, name, getter, setter,
+ attributes, is_hidden_prototype),
+ JSObject);
+ }
+ } else {
+ // Intrinsic data property --- Get appropriate value from the current
+ // context.
+ PropertyDetails details(Smi::cast(properties->get(i++)));
+ PropertyAttributes attributes = details.attributes();
+ DCHECK_EQ(kData, details.kind());
+
+ v8::Intrinsic intrinsic =
+ static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++)));
+ auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
+
+ RETURN_ON_EXCEPTION(
+ isolate,
+ DefineDataProperty(isolate, obj, name, prop_data, attributes),
+ JSObject);
+ }
+ }
+ return obj;
+}
+
+// Whether or not to cache every instance: when we materialize a getter or
+// setter from an lazy AccessorPair, we rely on this cache to be able to always
+// return the same getter or setter. However, objects will be cloned anyways,
+// so it's not observable if we didn't cache an instance. Furthermore, a badly
+// behaved embedder might create an unlimited number of objects, so we limit
+// the cache for those cases.
+enum class CachingMode { kLimited, kUnlimited };
+
+MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
+ int serial_number,
+ CachingMode caching_mode) {
+ DCHECK_LE(1, serial_number);
+ if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
+ Handle<FixedArray> fast_cache =
+ isolate->fast_template_instantiations_cache();
+ Handle<Object> object{fast_cache->get(serial_number - 1), isolate};
+ if (object->IsUndefined(isolate)) return {};
+ return Handle<JSObject>::cast(object);
+ }
+ if (caching_mode == CachingMode::kUnlimited ||
+ (serial_number <= TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
+ Handle<SimpleNumberDictionary> slow_cache =
+ isolate->slow_template_instantiations_cache();
+ int entry = slow_cache->FindEntry(isolate, serial_number);
+ if (entry != SimpleNumberDictionary::kNotFound) {
+ return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
+ }
+ }
+ return {};
+}
+
+void CacheTemplateInstantiation(Isolate* isolate, int serial_number,
+ CachingMode caching_mode,
+ Handle<JSObject> object) {
+ DCHECK_LE(1, serial_number);
+ if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
+ Handle<FixedArray> fast_cache =
+ isolate->fast_template_instantiations_cache();
+ Handle<FixedArray> new_cache =
+ FixedArray::SetAndGrow(isolate, fast_cache, serial_number - 1, object);
+ if (*new_cache != *fast_cache) {
+ isolate->native_context()->set_fast_template_instantiations_cache(
+ *new_cache);
+ }
+ } else if (caching_mode == CachingMode::kUnlimited ||
+ (serial_number <=
+ TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
+ Handle<SimpleNumberDictionary> cache =
+ isolate->slow_template_instantiations_cache();
+ auto new_cache =
+ SimpleNumberDictionary::Set(isolate, cache, serial_number, object);
+ if (*new_cache != *cache) {
+ isolate->native_context()->set_slow_template_instantiations_cache(
+ *new_cache);
+ }
+ }
+}
+
+void UncacheTemplateInstantiation(Isolate* isolate, int serial_number,
+ CachingMode caching_mode) {
+ DCHECK_LE(1, serial_number);
+ if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
+ Handle<FixedArray> fast_cache =
+ isolate->fast_template_instantiations_cache();
+ DCHECK(!fast_cache->get(serial_number - 1).IsUndefined(isolate));
+ fast_cache->set_undefined(serial_number - 1);
+ } else if (caching_mode == CachingMode::kUnlimited ||
+ (serial_number <=
+ TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
+ Handle<SimpleNumberDictionary> cache =
+ isolate->slow_template_instantiations_cache();
+ int entry = cache->FindEntry(isolate, serial_number);
+ DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
+ cache = SimpleNumberDictionary::DeleteEntry(isolate, cache, entry);
+ isolate->native_context()->set_slow_template_instantiations_cache(*cache);
+ }
+}
+
+bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo info,
+ JSReceiver new_target) {
+ DisallowHeapAllocation no_gc;
+
+ if (!new_target.IsJSFunction()) return false;
+ JSFunction fun = JSFunction::cast(new_target);
+ if (fun.shared().function_data() != info.constructor()) return false;
+ if (info.immutable_proto()) return false;
+ return fun.context().native_context() == isolate->raw_native_context();
+}
+
+MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
+ Handle<ObjectTemplateInfo> info,
+ Handle<JSReceiver> new_target,
+ bool is_hidden_prototype,
+ bool is_prototype) {
+ Handle<JSFunction> constructor;
+ int serial_number = Smi::ToInt(info->serial_number());
+ if (!new_target.is_null()) {
+ if (IsSimpleInstantiation(isolate, *info, *new_target)) {
+ constructor = Handle<JSFunction>::cast(new_target);
+ } else {
+ // Disable caching for subclass instantiation.
+ serial_number = 0;
+ }
+ }
+ // Fast path.
+ Handle<JSObject> result;
+ if (serial_number) {
+ if (ProbeInstantiationsCache(isolate, serial_number, CachingMode::kLimited)
+ .ToHandle(&result)) {
+ return isolate->factory()->CopyJSObject(result);
+ }
+ }
+
+ if (constructor.is_null()) {
+ Object maybe_constructor_info = info->constructor();
+ if (maybe_constructor_info.IsUndefined(isolate)) {
+ constructor = isolate->object_function();
+ } else {
+ // Enter a new scope. Recursion could otherwise create a lot of handles.
+ HandleScope scope(isolate);
+ Handle<FunctionTemplateInfo> cons_templ(
+ FunctionTemplateInfo::cast(maybe_constructor_info), isolate);
+ Handle<JSFunction> tmp_constructor;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
+ InstantiateFunction(isolate, cons_templ),
+ JSObject);
+ constructor = scope.CloseAndEscape(tmp_constructor);
+ }
+
+ if (new_target.is_null()) new_target = constructor;
+ }
+
+ Handle<JSObject> object;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, object,
+ JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
+ JSObject);
+
+ if (is_prototype) JSObject::OptimizeAsPrototype(object);
+
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result,
+ ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject);
+ if (info->immutable_proto()) {
+ JSObject::SetImmutableProto(object);
+ }
+ if (!is_prototype) {
+ // Keep prototypes in slow-mode. Let them be lazily turned fast later on.
+ // TODO(dcarney): is this necessary?
+ JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
+ // Don't cache prototypes.
+ if (serial_number) {
+ CacheTemplateInstantiation(isolate, serial_number, CachingMode::kLimited,
+ result);
+ result = isolate->factory()->CopyJSObject(result);
+ }
+ }
+
+ return result;
+}
+
+namespace {
+MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
+ Object function_template) {
+ // Enter a new scope. Recursion could otherwise create a lot of handles.
+ HandleScope scope(isolate);
+ Handle<JSFunction> parent_instance;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, parent_instance,
+ InstantiateFunction(
+ isolate,
+ handle(FunctionTemplateInfo::cast(function_template), isolate)),
+ JSFunction);
+ Handle<Object> instance_prototype;
+ // TODO(cbruni): decide what to do here.
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, instance_prototype,
+ JSObject::GetProperty(isolate, parent_instance,
+ isolate->factory()->prototype_string()),
+ JSFunction);
+ return scope.CloseAndEscape(instance_prototype);
+}
+} // namespace
+
+MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
+ Handle<FunctionTemplateInfo> data,
+ MaybeHandle<Name> maybe_name) {
+ int serial_number = Smi::ToInt(data->serial_number());
+ if (serial_number) {
+ Handle<JSObject> result;
+ if (ProbeInstantiationsCache(isolate, serial_number,
+ CachingMode::kUnlimited)
+ .ToHandle(&result)) {
+ return Handle<JSFunction>::cast(result);
+ }
+ }
+ Handle<Object> prototype;
+ if (!data->remove_prototype()) {
+ Object prototype_templ = data->GetPrototypeTemplate();
+ if (prototype_templ.IsUndefined(isolate)) {
+ Object protoype_provider_templ = data->GetPrototypeProviderTemplate();
+ if (protoype_provider_templ.IsUndefined(isolate)) {
+ prototype = isolate->factory()->NewJSObject(isolate->object_function());
+ } else {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, prototype,
+ GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
+ }
+ } else {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, prototype,
+ InstantiateObject(
+ isolate,
+ handle(ObjectTemplateInfo::cast(prototype_templ), isolate),
+ Handle<JSReceiver>(), false, true),
+ JSFunction);
+ }
+ Object parent = data->GetParentTemplate();
+ if (!parent.IsUndefined(isolate)) {
+ Handle<Object> parent_prototype;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
+ GetInstancePrototype(isolate, parent),
+ JSFunction);
+ CHECK(parent_prototype->IsHeapObject());
+ JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
+ Handle<HeapObject>::cast(parent_prototype));
+ }
+ }
+ InstanceType function_type =
+ (!data->needs_access_check() &&
+ data->GetNamedPropertyHandler().IsUndefined(isolate) &&
+ data->GetIndexedPropertyHandler().IsUndefined(isolate))
+ ? JS_API_OBJECT_TYPE
+ : JS_SPECIAL_API_OBJECT_TYPE;
+
+ Handle<JSFunction> function = ApiNatives::CreateApiFunction(
+ isolate, data, prototype, function_type, maybe_name);
+ if (serial_number) {
+ // Cache the function.
+ CacheTemplateInstantiation(isolate, serial_number, CachingMode::kUnlimited,
+ function);
+ }
+ MaybeHandle<JSObject> result =
+ ConfigureInstance(isolate, function, data, false);
+ if (result.is_null()) {
+ // Uncache on error.
+ if (serial_number) {
+ UncacheTemplateInstantiation(isolate, serial_number,
+ CachingMode::kUnlimited);
+ }
+ return MaybeHandle<JSFunction>();
+ }
+ return function;
+}
+
+void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
+ int length, Handle<Object>* data) {
+ Object maybe_list = templ->property_list();
+ Handle<TemplateList> list;
+ if (maybe_list.IsUndefined(isolate)) {
+ list = TemplateList::New(isolate, length);
+ } else {
+ list = handle(TemplateList::cast(maybe_list), isolate);
+ }
+ templ->set_number_of_properties(templ->number_of_properties() + 1);
+ for (int i = 0; i < length; i++) {
+ Handle<Object> value =
+ data[i].is_null()
+ ? Handle<Object>::cast(isolate->factory()->undefined_value())
+ : data[i];
+ list = TemplateList::Add(isolate, list, value);
+ }
+ templ->set_property_list(*list);
+}
+
+} // namespace
+
+MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
+ Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
+ Isolate* isolate = data->GetIsolate();
+ InvokeScope invoke_scope(isolate);
+ return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
+}
+
+MaybeHandle<JSObject> ApiNatives::InstantiateObject(
+ Isolate* isolate, Handle<ObjectTemplateInfo> data,
+ Handle<JSReceiver> new_target) {
+ InvokeScope invoke_scope(isolate);
+ return ::v8::internal::InstantiateObject(isolate, data, new_target, false,
+ false);
+}
+
+MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
+ Handle<ObjectTemplateInfo> data) {
+ Isolate* isolate = data->GetIsolate();
+ InvokeScope invoke_scope(isolate);
+
+ Handle<FunctionTemplateInfo> constructor(
+ FunctionTemplateInfo::cast(data->constructor()), isolate);
+ Handle<Map> object_map = isolate->factory()->NewMap(
+ JS_SPECIAL_API_OBJECT_TYPE,
+ JSObject::kHeaderSize +
+ data->embedder_field_count() * kEmbedderDataSlotSize,
+ TERMINAL_FAST_ELEMENTS_KIND);
+ object_map->SetConstructor(*constructor);
+ object_map->set_is_access_check_needed(true);
+ object_map->set_may_have_interesting_symbols(true);
+
+ Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(object_map);
+ JSObject::ForceSetPrototype(object, isolate->factory()->null_value());
+
+ return object;
+}
+
+void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
+ Handle<Name> name, Handle<Object> value,
+ PropertyAttributes attributes) {
+ PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
+ auto details_handle = handle(details.AsSmi(), isolate);
+ Handle<Object> data[] = {name, details_handle, value};
+ AddPropertyToPropertyList(isolate, info, arraysize(data), data);
+}
+
+void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
+ Handle<Name> name, v8::Intrinsic intrinsic,
+ PropertyAttributes attributes) {
+ auto value = handle(Smi::FromInt(intrinsic), isolate);
+ auto intrinsic_marker = isolate->factory()->true_value();
+ PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
+ auto details_handle = handle(details.AsSmi(), isolate);
+ Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
+ AddPropertyToPropertyList(isolate, info, arraysize(data), data);
+}
+
+void ApiNatives::AddAccessorProperty(Isolate* isolate,
+ Handle<TemplateInfo> info,
+ Handle<Name> name,
+ Handle<FunctionTemplateInfo> getter,
+ Handle<FunctionTemplateInfo> setter,
+ PropertyAttributes attributes) {
+ PropertyDetails details(kAccessor, attributes, PropertyCellType::kNoCell);
+ auto details_handle = handle(details.AsSmi(), isolate);
+ Handle<Object> data[] = {name, details_handle, getter, setter};
+ AddPropertyToPropertyList(isolate, info, arraysize(data), data);
+}
+
+void ApiNatives::AddNativeDataProperty(Isolate* isolate,
+ Handle<TemplateInfo> info,
+ Handle<AccessorInfo> property) {
+ Object maybe_list = info->property_accessors();
+ Handle<TemplateList> list;
+ if (maybe_list.IsUndefined(isolate)) {
+ list = TemplateList::New(isolate, 1);
+ } else {
+ list = handle(TemplateList::cast(maybe_list), isolate);
+ }
+ list = TemplateList::Add(isolate, list, property);
+ info->set_property_accessors(*list);
+}
+
+Handle<JSFunction> ApiNatives::CreateApiFunction(
+ Isolate* isolate, Handle<FunctionTemplateInfo> obj,
+ Handle<Object> prototype, InstanceType type, MaybeHandle<Name> maybe_name) {
+ Handle<SharedFunctionInfo> shared =
+ FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
+ maybe_name);
+ // To simplify things, API functions always have shared name.
+ DCHECK(shared->HasSharedName());
+
+ Handle<JSFunction> result =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ shared, isolate->native_context());
+
+ if (obj->remove_prototype()) {
+ DCHECK(prototype.is_null());
+ DCHECK(result->shared().IsApiFunction());
+ DCHECK(!result->IsConstructor());
+ DCHECK(!result->has_prototype_slot());
+ return result;
+ }
+
+ // Down from here is only valid for API functions that can be used as a
+ // constructor (don't set the "remove prototype" flag).
+ DCHECK(result->has_prototype_slot());
+
+ if (obj->read_only_prototype()) {
+ result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
+ }
+
+ if (prototype->IsTheHole(isolate)) {
+ prototype = isolate->factory()->NewFunctionPrototype(result);
+ } else if (obj->GetPrototypeProviderTemplate().IsUndefined(isolate)) {
+ JSObject::AddProperty(isolate, Handle<JSObject>::cast(prototype),
+ isolate->factory()->constructor_string(), result,
+ DONT_ENUM);
+ }
+
+ int embedder_field_count = 0;
+ bool immutable_proto = false;
+ if (!obj->GetInstanceTemplate().IsUndefined(isolate)) {
+ Handle<ObjectTemplateInfo> GetInstanceTemplate = Handle<ObjectTemplateInfo>(
+ ObjectTemplateInfo::cast(obj->GetInstanceTemplate()), isolate);
+ embedder_field_count = GetInstanceTemplate->embedder_field_count();
+ immutable_proto = GetInstanceTemplate->immutable_proto();
+ }
+
+ // JS_FUNCTION_TYPE requires information about the prototype slot.
+ DCHECK_NE(JS_FUNCTION_TYPE, type);
+ int instance_size = JSObject::GetHeaderSize(type) +
+ kEmbedderDataSlotSize * embedder_field_count;
+
+ Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
+ TERMINAL_FAST_ELEMENTS_KIND);
+ JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
+
+ // Mark as undetectable if needed.
+ if (obj->undetectable()) {
+ // We only allow callable undetectable receivers here, since this whole
+ // undetectable business is only to support document.all, which is both
+ // undetectable and callable. If we ever see the need to have an object
+ // that is undetectable but not callable, we need to update the types.h
+ // to allow encoding this.
+ CHECK(!obj->GetInstanceCallHandler().IsUndefined(isolate));
+ map->set_is_undetectable(true);
+ }
+
+ // Mark as needs_access_check if needed.
+ if (obj->needs_access_check()) {
+ map->set_is_access_check_needed(true);
+ map->set_may_have_interesting_symbols(true);
+ }
+
+ // Set interceptor information in the map.
+ if (!obj->GetNamedPropertyHandler().IsUndefined(isolate)) {
+ map->set_has_named_interceptor(true);
+ map->set_may_have_interesting_symbols(true);
+ }
+ if (!obj->GetIndexedPropertyHandler().IsUndefined(isolate)) {
+ map->set_has_indexed_interceptor(true);
+ }
+
+ // Mark instance as callable in the map.
+ if (!obj->GetInstanceCallHandler().IsUndefined(isolate)) {
+ map->set_is_callable(true);
+ map->set_is_constructor(!obj->undetectable());
+ }
+
+ if (immutable_proto) map->set_is_immutable_proto(true);
+
+ return result;
+}
+
+} // namespace internal
+} // namespace v8