v8/src/api-natives.cc
Camillo Bruni 74a663be67 [runtime] Deduplicate the name between SFI and ScopeInfo
With this CL the name of an SFI is either stored directly on the SFI
itself (for uncompiled ones) or on the related ScopeInfo if present.

- Combine scope_info and name field on SFI into name_or_scope_info field
- Change the name of a couple of SFI accessors: name => Name,
  has_shared_name => HasSharedName, set_name => SetName
- Add Runtime::kGetFunctionName due to more complex SFI name accessing

Bug: v8:7066
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: Idcce158446c9447b92d9a15125d086952c6e0824
Reviewed-on: https://chromium-review.googlesource.com/964201
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52001}
2018-03-16 16:49:42 +00:00

738 lines
27 KiB
C++

// 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-natives.h"
#include "src/api.h"
#include "src/isolate-inl.h"
#include "src/lookup.h"
#include "src/messages.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 (force_instantiate) {
if (getter->IsFunctionTemplateInfo()) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, getter,
InstantiateFunction(isolate,
Handle<FunctionTemplateInfo>::cast(getter)),
Object);
}
if (setter->IsFunctionTemplateInfo()) {
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, kThrowOnError,
Object::CERTAINLY_NOT_STORE_FROM_KEYED));
return value;
}
void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
Handle<Map> old_map(object->map());
// Copy map so it won't interfere constructor's initial map.
Handle<Map> new_map = Map::Copy(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());
// Copy map so it won't interfere constructor's initial map.
Handle<Map> new_map = Map::Copy(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 nullptr;
}
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 != nullptr) {
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); *temp != nullptr;
temp = handle(temp->GetParent(isolate), isolate)) {
// Accumulate accessors.
Object* maybe_properties = temp->property_accessors();
if (!maybe_properties->IsUndefined(isolate)) {
valid_descriptors = AccessorInfo::AppendUnique(
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)));
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();
return fast_cache->GetValue<JSObject>(isolate, serial_number - 1);
} else if (caching_mode == CachingMode::kUnlimited ||
(serial_number <=
TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
Handle<SimpleNumberDictionary> slow_cache =
isolate->slow_template_instantiations_cache();
int entry = slow_cache->FindEntry(serial_number);
if (entry == SimpleNumberDictionary::kNotFound) {
return MaybeHandle<JSObject>();
}
return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
} else {
return MaybeHandle<JSObject>();
}
}
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(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(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(serial_number);
DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
cache = SimpleNumberDictionary::DeleteEntry(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), 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(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->prototype_template();
if (prototype_templ->IsUndefined(isolate)) {
Object* protoype_provider_templ = data->prototype_provider_template();
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>(), data->hidden_prototype(), true),
JSFunction);
}
Object* parent = data->parent_template();
if (!parent->IsUndefined(isolate)) {
Handle<Object> parent_prototype;
ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
GetInstancePrototype(isolate, parent),
JSFunction);
JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
parent_prototype);
}
}
Handle<JSFunction> function = ApiNatives::CreateApiFunction(
isolate, data, prototype, ApiNatives::JavaScriptObjectType, maybe_name);
if (serial_number) {
// Cache the function.
CacheTemplateInstantiation(isolate, serial_number, CachingMode::kUnlimited,
function);
}
MaybeHandle<JSObject> result =
ConfigureInstance(isolate, function, data, data->hidden_prototype());
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(
Handle<ObjectTemplateInfo> data, Handle<JSReceiver> new_target) {
Isolate* isolate = data->GetIsolate();
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()));
Handle<Map> object_map = isolate->factory()->NewMap(
JS_SPECIAL_API_OBJECT_TYPE,
JSObject::kHeaderSize + data->embedder_field_count() * kPointerSize,
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, ApiInstanceType instance_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->prototype_provider_template()->IsUndefined(isolate)) {
JSObject::AddProperty(Handle<JSObject>::cast(prototype),
isolate->factory()->constructor_string(), result,
DONT_ENUM);
}
int embedder_field_count = 0;
bool immutable_proto = false;
if (!obj->instance_template()->IsUndefined(isolate)) {
Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
ObjectTemplateInfo::cast(obj->instance_template()));
embedder_field_count = instance_template->embedder_field_count();
immutable_proto = instance_template->immutable_proto();
}
// TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
// JSObject::GetHeaderSize.
int instance_size = kPointerSize * embedder_field_count;
InstanceType type;
switch (instance_type) {
case JavaScriptObjectType:
if (!obj->needs_access_check() &&
obj->named_property_handler()->IsUndefined(isolate) &&
obj->indexed_property_handler()->IsUndefined(isolate)) {
type = JS_API_OBJECT_TYPE;
} else {
type = JS_SPECIAL_API_OBJECT_TYPE;
}
instance_size += JSObject::kHeaderSize;
break;
case GlobalObjectType:
type = JS_GLOBAL_OBJECT_TYPE;
instance_size += JSGlobalObject::kSize;
break;
case GlobalProxyType:
type = JS_GLOBAL_PROXY_TYPE;
instance_size += JSGlobalProxy::kSize;
break;
default:
UNREACHABLE();
break;
}
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->instance_call_handler()->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->named_property_handler()->IsUndefined(isolate)) {
map->set_has_named_interceptor(true);
map->set_may_have_interesting_symbols(true);
}
if (!obj->indexed_property_handler()->IsUndefined(isolate)) {
map->set_has_indexed_interceptor(true);
}
// Mark instance as callable in the map.
if (!obj->instance_call_handler()->IsUndefined(isolate)) {
map->set_is_callable(true);
}
if (immutable_proto) map->set_is_immutable_proto(true);
return result;
}
} // namespace internal
} // namespace v8