Index: src/api-natives.cc |
diff --git a/src/api-natives.cc b/src/api-natives.cc |
index 73447cec023d16146abf218ead511d629d572246..7fb88a6e46859a12810af78dbfc4c23775e57d04 100644 |
--- a/src/api-natives.cc |
+++ b/src/api-natives.cc |
@@ -148,77 +148,17 @@ |
return nullptr; |
} |
-// Returns parent function template or null. |
-FunctionTemplateInfo* GetParent(FunctionTemplateInfo* data) { |
- Object* parent = data->parent_template(); |
- return parent->IsUndefined() ? nullptr : FunctionTemplateInfo::cast(parent); |
-} |
- |
-// Starting from given object template's constructor walk up the inheritance |
-// chain till a function template that has an instance template is found. |
-ObjectTemplateInfo* GetParent(ObjectTemplateInfo* data) { |
- Object* maybe_ctor = data->constructor(); |
- if (maybe_ctor->IsUndefined()) return nullptr; |
- FunctionTemplateInfo* ctor = FunctionTemplateInfo::cast(maybe_ctor); |
- while (true) { |
- ctor = GetParent(ctor); |
- if (ctor == nullptr) return nullptr; |
- Object* maybe_obj = ctor->instance_template(); |
- if (!maybe_obj->IsUndefined()) return ObjectTemplateInfo::cast(maybe_obj); |
- } |
-} |
- |
-template <typename TemplateInfoT> |
+ |
MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj, |
- Handle<TemplateInfoT> data) { |
- 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) { |
- if (!info->property_accessors()->IsUndefined()) { |
- Object* props = info->property_accessors(); |
- if (!props->IsUndefined()) { |
- Handle<Object> props_handle(props, isolate); |
- NeanderArray props_array(props_handle); |
- max_number_of_properties += props_array.length(); |
- } |
- } |
- info = GetParent(info); |
- } |
- |
- 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); |
- |
- info = *data; |
- while (info != nullptr) { |
- // Accumulate accessors. |
- if (!info->property_accessors()->IsUndefined()) { |
- Handle<Object> props(info->property_accessors(), isolate); |
- valid_descriptors = |
- AccessorInfo::AppendUnique(props, array, valid_descriptors); |
- } |
- info = GetParent(info); |
- } |
- |
- // Install accumulated accessors. |
- for (int i = 0; i < valid_descriptors; i++) { |
- Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i))); |
- JSObject::SetAccessor(obj, accessor).Assert(); |
- } |
- } |
- |
+ Handle<TemplateInfo> data) { |
auto property_list = handle(data->property_list(), isolate); |
if (property_list->IsUndefined()) return obj; |
// TODO(dcarney): just use a FixedArray here. |
NeanderArray properties(property_list); |
if (properties.length() == 0) return obj; |
+ HandleScope scope(isolate); |
+ // Disable access checks while instantiating the object. |
+ AccessCheckDisableScope access_check_scope(isolate, obj); |
int i = 0; |
for (int c = 0; c < data->number_of_properties(); c++) { |
@@ -231,9 +171,6 @@ |
if (kind == kData) { |
auto prop_data = handle(properties.get(i++), isolate); |
- // JSReceivers could cause cross-context leaks therefore they must |
- // never appear as data properties. |
- DCHECK(!prop_data->IsJSReceiver()); |
RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name, |
prop_data, attributes), |
@@ -265,21 +202,6 @@ |
return obj; |
} |
-void CacheTemplateInstantiation(Isolate* isolate, Handle<Smi> serial_number, |
- Handle<JSObject> object) { |
- auto cache = isolate->template_instantiations_cache(); |
- auto new_cache = ObjectHashTable::Put(cache, serial_number, object); |
- isolate->native_context()->set_template_instantiations_cache(*new_cache); |
-} |
- |
-void UncacheTemplateInstantiation(Isolate* isolate, Handle<Smi> serial_number) { |
- auto cache = isolate->template_instantiations_cache(); |
- bool was_present = false; |
- auto new_cache = ObjectHashTable::Remove(cache, serial_number, &was_present); |
- DCHECK(was_present); |
- isolate->native_context()->set_template_instantiations_cache(*new_cache); |
-} |
- |
MaybeHandle<JSObject> InstantiateObject(Isolate* isolate, |
Handle<ObjectTemplateInfo> info) { |
// Enter a new scope. Recursion could otherwise create a lot of handles. |
@@ -295,30 +217,29 @@ |
ASSIGN_RETURN_ON_EXCEPTION( |
isolate, cons, InstantiateFunction(isolate, cons_templ), JSFunction); |
} |
- auto serial_number = handle(Smi::cast(info->serial_number()), isolate); |
- if (serial_number->value()) { |
- // Probe cache. |
- auto cache = isolate->template_instantiations_cache(); |
- Object* boilerplate = cache->Lookup(serial_number); |
- if (boilerplate->IsJSObject()) { |
- result = handle(JSObject::cast(boilerplate), isolate); |
- ASSIGN_RETURN_ON_EXCEPTION(isolate, result, JSObject::DeepCopy(result), |
- JSObject); |
- return scope.CloseAndEscape(result); |
- } |
- } |
auto object = isolate->factory()->NewJSObject(cons); |
ASSIGN_RETURN_ON_EXCEPTION( |
isolate, result, ConfigureInstance(isolate, object, info), JSFunction); |
// TODO(dcarney): is this necessary? |
JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject"); |
- |
- if (serial_number->value()) { |
- CacheTemplateInstantiation(isolate, serial_number, result); |
- ASSIGN_RETURN_ON_EXCEPTION(isolate, result, JSObject::DeepCopy(result), |
- JSObject); |
- } |
return scope.CloseAndEscape(result); |
+} |
+ |
+ |
+void CacheFunction(Isolate* isolate, Handle<Smi> serial_number, |
+ Handle<JSFunction> function) { |
+ auto cache = isolate->function_cache(); |
+ auto new_cache = ObjectHashTable::Put(cache, serial_number, function); |
+ isolate->native_context()->set_function_cache(*new_cache); |
+} |
+ |
+ |
+void UncacheFunction(Isolate* isolate, Handle<Smi> serial_number) { |
+ auto cache = isolate->function_cache(); |
+ bool was_present = false; |
+ auto new_cache = ObjectHashTable::Remove(cache, serial_number, &was_present); |
+ DCHECK(was_present); |
+ isolate->native_context()->set_function_cache(*new_cache); |
} |
@@ -326,9 +247,9 @@ |
Handle<FunctionTemplateInfo> data, |
Handle<Name> name) { |
auto serial_number = handle(Smi::cast(data->serial_number()), isolate); |
- if (serial_number->value()) { |
- // Probe cache. |
- auto cache = isolate->template_instantiations_cache(); |
+ // Probe cache. |
+ if (!data->do_not_cache()) { |
+ auto cache = isolate->function_cache(); |
Object* element = cache->Lookup(serial_number); |
if (element->IsJSFunction()) { |
return handle(JSFunction::cast(element), isolate); |
@@ -373,15 +294,15 @@ |
if (!name.is_null() && name->IsString()) { |
function->shared()->set_name(*name); |
} |
- if (serial_number->value()) { |
+ if (!data->do_not_cache()) { |
// Cache the function. |
- CacheTemplateInstantiation(isolate, serial_number, function); |
+ CacheFunction(isolate, serial_number, function); |
} |
auto result = ConfigureInstance(isolate, function, data); |
if (result.is_null()) { |
// Uncache on error. |
- if (serial_number->value()) { |
- UncacheTemplateInstantiation(isolate, serial_number); |
+ if (!data->do_not_cache()) { |
+ UncacheFunction(isolate, serial_number); |
} |
return MaybeHandle<JSFunction>(); |
} |
@@ -445,12 +366,25 @@ |
} |
+MaybeHandle<FunctionTemplateInfo> ApiNatives::ConfigureInstance( |
+ Isolate* isolate, Handle<FunctionTemplateInfo> desc, |
+ Handle<JSObject> instance) { |
+ // Configure the instance by adding the properties specified by the |
+ // instance template. |
+ if (desc->instance_template()->IsUndefined()) return desc; |
+ InvokeScope invoke_scope(isolate); |
+ Handle<ObjectTemplateInfo> instance_template( |
+ ObjectTemplateInfo::cast(desc->instance_template()), isolate); |
+ RETURN_ON_EXCEPTION(isolate, ::v8::internal::ConfigureInstance( |
+ isolate, instance, instance_template), |
+ FunctionTemplateInfo); |
+ return desc; |
+} |
+ |
+ |
void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info, |
Handle<Name> name, Handle<Object> value, |
PropertyAttributes attributes) { |
- // JSReceivers could cause cross-context leaks therefore they must |
- // never appear as data properties. |
- CHECK(!value->IsJSReceiver()); |
const int kSize = 3; |
PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); |
auto details_handle = handle(details.AsSmi(), isolate); |
@@ -615,6 +549,72 @@ |
map->set_is_constructor(true); |
} |
+ // Recursively copy parent instance templates' accessors, |
+ // 'data' may be modified. |
+ int max_number_of_additional_properties = 0; |
+ int max_number_of_static_properties = 0; |
+ FunctionTemplateInfo* info = *obj; |
+ while (true) { |
+ if (!info->instance_template()->IsUndefined()) { |
+ Object* props = ObjectTemplateInfo::cast(info->instance_template()) |
+ ->property_accessors(); |
+ if (!props->IsUndefined()) { |
+ Handle<Object> props_handle(props, isolate); |
+ NeanderArray props_array(props_handle); |
+ max_number_of_additional_properties += props_array.length(); |
+ } |
+ } |
+ if (!info->property_accessors()->IsUndefined()) { |
+ Object* props = info->property_accessors(); |
+ if (!props->IsUndefined()) { |
+ Handle<Object> props_handle(props, isolate); |
+ NeanderArray props_array(props_handle); |
+ max_number_of_static_properties += props_array.length(); |
+ } |
+ } |
+ Object* parent = info->parent_template(); |
+ if (parent->IsUndefined()) break; |
+ info = FunctionTemplateInfo::cast(parent); |
+ } |
+ |
+ Map::EnsureDescriptorSlack(map, max_number_of_additional_properties); |
+ |
+ // Use a temporary FixedArray to acculumate static accessors |
+ int valid_descriptors = 0; |
+ Handle<FixedArray> array; |
+ if (max_number_of_static_properties > 0) { |
+ array = isolate->factory()->NewFixedArray(max_number_of_static_properties); |
+ } |
+ |
+ while (true) { |
+ // Install instance descriptors |
+ if (!obj->instance_template()->IsUndefined()) { |
+ Handle<ObjectTemplateInfo> instance = Handle<ObjectTemplateInfo>( |
+ ObjectTemplateInfo::cast(obj->instance_template()), isolate); |
+ Handle<Object> props = |
+ Handle<Object>(instance->property_accessors(), isolate); |
+ if (!props->IsUndefined()) { |
+ Map::AppendCallbackDescriptors(map, props); |
+ } |
+ } |
+ // Accumulate static accessors |
+ if (!obj->property_accessors()->IsUndefined()) { |
+ Handle<Object> props = Handle<Object>(obj->property_accessors(), isolate); |
+ valid_descriptors = |
+ AccessorInfo::AppendUnique(props, array, valid_descriptors); |
+ } |
+ // Climb parent chain |
+ Handle<Object> parent = Handle<Object>(obj->parent_template(), isolate); |
+ if (parent->IsUndefined()) break; |
+ obj = Handle<FunctionTemplateInfo>::cast(parent); |
+ } |
+ |
+ // Install accumulated static accessors |
+ for (int i = 0; i < valid_descriptors; i++) { |
+ Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i))); |
+ JSObject::SetAccessor(result, accessor).Assert(); |
+ } |
+ |
DCHECK(result->shared()->IsApiFunction()); |
return result; |
} |