| Index: src/api-natives.cc
|
| diff --git a/src/api-natives.cc b/src/api-natives.cc
|
| index 7fb88a6e46859a12810af78dbfc4c23775e57d04..d97dfae0a08d064ef55ec82aac65ca32c1c64d66 100644
|
| --- a/src/api-natives.cc
|
| +++ b/src/api-natives.cc
|
| @@ -148,17 +148,77 @@ Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
|
| 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<TemplateInfo> data) {
|
| + 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();
|
| + }
|
| + }
|
| +
|
| 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++) {
|
| @@ -171,7 +231,6 @@ MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
|
|
|
| if (kind == kData) {
|
| auto prop_data = handle(properties.get(i++), isolate);
|
| -
|
| RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
|
| prop_data, attributes),
|
| JSObject);
|
| @@ -202,6 +261,21 @@ MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
|
| 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.
|
| @@ -217,29 +291,30 @@ MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
|
| 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::DeepCopyApiBoilerplate(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");
|
| - 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);
|
| + if (serial_number->value()) {
|
| + CacheTemplateInstantiation(isolate, serial_number, result);
|
| + ASSIGN_RETURN_ON_EXCEPTION(
|
| + isolate, result, JSObject::DeepCopyApiBoilerplate(result), JSObject);
|
| + }
|
| + return scope.CloseAndEscape(result);
|
| }
|
|
|
|
|
| @@ -247,9 +322,9 @@ MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
|
| Handle<FunctionTemplateInfo> data,
|
| Handle<Name> name) {
|
| auto serial_number = handle(Smi::cast(data->serial_number()), isolate);
|
| - // Probe cache.
|
| - if (!data->do_not_cache()) {
|
| - auto cache = isolate->function_cache();
|
| + if (serial_number->value()) {
|
| + // Probe cache.
|
| + auto cache = isolate->template_instantiations_cache();
|
| Object* element = cache->Lookup(serial_number);
|
| if (element->IsJSFunction()) {
|
| return handle(JSFunction::cast(element), isolate);
|
| @@ -294,15 +369,15 @@ MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
|
| if (!name.is_null() && name->IsString()) {
|
| function->shared()->set_name(*name);
|
| }
|
| - if (!data->do_not_cache()) {
|
| + if (serial_number->value()) {
|
| // Cache the function.
|
| - CacheFunction(isolate, serial_number, function);
|
| + CacheTemplateInstantiation(isolate, serial_number, function);
|
| }
|
| auto result = ConfigureInstance(isolate, function, data);
|
| if (result.is_null()) {
|
| // Uncache on error.
|
| - if (!data->do_not_cache()) {
|
| - UncacheFunction(isolate, serial_number);
|
| + if (serial_number->value()) {
|
| + UncacheTemplateInstantiation(isolate, serial_number);
|
| }
|
| return MaybeHandle<JSFunction>();
|
| }
|
| @@ -366,22 +441,6 @@ MaybeHandle<JSObject> ApiNatives::InstantiateObject(
|
| }
|
|
|
|
|
| -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) {
|
| @@ -549,72 +608,6 @@ Handle<JSFunction> ApiNatives::CreateApiFunction(
|
| 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;
|
| }
|
|
|