| Index: src/api-natives.cc
|
| diff --git a/src/api-natives.cc b/src/api-natives.cc
|
| index cd9f0ddd5d239887c9f5f94b6059d4e86dcbe2dd..ecbe4dc1bf5e8ccf60a1fd9923bc1bd3eb9c4093 100644
|
| --- a/src/api-natives.cc
|
| +++ b/src/api-natives.cc
|
| @@ -15,6 +15,24 @@ 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,
|
| @@ -153,30 +171,6 @@ 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(data->GetIsolate())
|
| - ? 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();
|
| - Isolate* isolate = data->GetIsolate();
|
| - if (maybe_ctor->IsUndefined(isolate)) 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(isolate)) {
|
| - return ObjectTemplateInfo::cast(maybe_obj);
|
| - }
|
| - }
|
| -}
|
|
|
| template <typename TemplateInfoT>
|
| MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
|
| @@ -198,7 +192,7 @@ MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
|
| max_number_of_properties += props_array.length();
|
| }
|
| }
|
| - info = GetParent(info);
|
| + info = info->GetParent(isolate);
|
| }
|
|
|
| if (max_number_of_properties > 0) {
|
| @@ -215,7 +209,7 @@ MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
|
| valid_descriptors =
|
| AccessorInfo::AppendUnique(props, array, valid_descriptors);
|
| }
|
| - info = GetParent(info);
|
| + info = info->GetParent(isolate);
|
| }
|
|
|
| // Install accumulated accessors.
|
| @@ -234,9 +228,9 @@ MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
|
| int i = 0;
|
| for (int c = 0; c < data->number_of_properties(); c++) {
|
| auto name = handle(Name::cast(properties.get(i++)), isolate);
|
| - auto bit = handle(properties.get(i++), isolate);
|
| + Object* bit = properties.get(i++);
|
| if (bit->IsSmi()) {
|
| - PropertyDetails details(Smi::cast(*bit));
|
| + PropertyDetails details(Smi::cast(bit));
|
| PropertyAttributes attributes = details.attributes();
|
| PropertyKind kind = details.kind();
|
|
|
| @@ -272,24 +266,80 @@ MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
|
| return obj;
|
| }
|
|
|
| -void CacheTemplateInstantiation(Isolate* isolate, uint32_t serial_number,
|
| +MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
|
| + int serial_number) {
|
| + 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 {
|
| + Handle<UnseededNumberDictionary> slow_cache =
|
| + isolate->slow_template_instantiations_cache();
|
| + int entry = slow_cache->FindEntry(serial_number);
|
| + if (entry == UnseededNumberDictionary::kNotFound) {
|
| + return MaybeHandle<JSObject>();
|
| + }
|
| + return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
|
| + }
|
| +}
|
| +
|
| +void CacheTemplateInstantiation(Isolate* isolate, int serial_number,
|
| Handle<JSObject> object) {
|
| - auto cache = isolate->template_instantiations_cache();
|
| - auto new_cache =
|
| - UnseededNumberDictionary::AtNumberPut(cache, serial_number, object);
|
| - isolate->native_context()->set_template_instantiations_cache(*new_cache);
|
| + 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 {
|
| + Handle<UnseededNumberDictionary> cache =
|
| + isolate->slow_template_instantiations_cache();
|
| + auto new_cache =
|
| + UnseededNumberDictionary::AtNumberPut(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) {
|
| + 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 {
|
| + Handle<UnseededNumberDictionary> cache =
|
| + isolate->slow_template_instantiations_cache();
|
| + int entry = cache->FindEntry(serial_number);
|
| + DCHECK(entry != UnseededNumberDictionary::kNotFound);
|
| + Handle<Object> result =
|
| + UnseededNumberDictionary::DeleteProperty(cache, entry);
|
| + USE(result);
|
| + DCHECK(result->IsTrue(isolate));
|
| + auto new_cache = UnseededNumberDictionary::Shrink(cache, entry);
|
| + isolate->native_context()->set_slow_template_instantiations_cache(
|
| + *new_cache);
|
| + }
|
| }
|
|
|
| -void UncacheTemplateInstantiation(Isolate* isolate, uint32_t serial_number) {
|
| - auto cache = isolate->template_instantiations_cache();
|
| - int entry = cache->FindEntry(serial_number);
|
| - DCHECK(entry != UnseededNumberDictionary::kNotFound);
|
| - Handle<Object> result =
|
| - UnseededNumberDictionary::DeleteProperty(cache, entry);
|
| - USE(result);
|
| - DCHECK(result->IsTrue(isolate));
|
| - auto new_cache = UnseededNumberDictionary::Shrink(cache, entry);
|
| - isolate->native_context()->set_template_instantiations_cache(*new_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->context()->native_context();
|
| }
|
|
|
| MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
|
| @@ -297,15 +347,9 @@ MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
|
| Handle<JSReceiver> new_target,
|
| bool is_hidden_prototype) {
|
| Handle<JSFunction> constructor;
|
| - uint32_t serial_number =
|
| - static_cast<uint32_t>(Smi::cast(info->serial_number())->value());
|
| + int serial_number = Smi::cast(info->serial_number())->value();
|
| if (!new_target.is_null()) {
|
| - if (new_target->IsJSFunction() &&
|
| - JSFunction::cast(*new_target)->shared()->function_data() ==
|
| - info->constructor() &&
|
| - JSFunction::cast(*new_target)->context()->native_context() ==
|
| - isolate->context()->native_context() &&
|
| - !info->immutable_proto()) {
|
| + if (IsSimpleInstantiation(isolate, *info, *new_target)) {
|
| constructor = Handle<JSFunction>::cast(new_target);
|
| } else {
|
| // Disable caching for subclass instantiation.
|
| @@ -315,27 +359,25 @@ MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
|
| // Fast path.
|
| Handle<JSObject> result;
|
| if (serial_number) {
|
| - // Probe cache.
|
| - auto cache = isolate->template_instantiations_cache();
|
| - int entry = cache->FindEntry(serial_number);
|
| - if (entry != UnseededNumberDictionary::kNotFound) {
|
| - Object* boilerplate = cache->ValueAt(entry);
|
| - result = handle(JSObject::cast(boilerplate), isolate);
|
| + if (ProbeInstantiationsCache(isolate, serial_number).ToHandle(&result)) {
|
| return isolate->factory()->CopyJSObject(result);
|
| }
|
| }
|
| - // Enter a new scope. Recursion could otherwise create a lot of handles.
|
| - HandleScope scope(isolate);
|
|
|
| if (constructor.is_null()) {
|
| - Handle<Object> cons(info->constructor(), isolate);
|
| - if (cons->IsUndefined(isolate)) {
|
| + Object* maybe_constructor_info = info->constructor();
|
| + if (maybe_constructor_info->IsUndefined(isolate)) {
|
| constructor = isolate->object_function();
|
| } else {
|
| - auto cons_templ = Handle<FunctionTemplateInfo>::cast(cons);
|
| - ASSIGN_RETURN_ON_EXCEPTION(isolate, constructor,
|
| + // 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;
|
| @@ -357,46 +399,43 @@ MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
|
| CacheTemplateInstantiation(isolate, serial_number, result);
|
| result = isolate->factory()->CopyJSObject(result);
|
| }
|
| - return scope.CloseAndEscape(result);
|
| + return result;
|
| }
|
|
|
|
|
| MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
|
| Handle<FunctionTemplateInfo> data,
|
| Handle<Name> name) {
|
| - uint32_t serial_number =
|
| - static_cast<uint32_t>(Smi::cast(data->serial_number())->value());
|
| + int serial_number = Smi::cast(data->serial_number())->value();
|
| if (serial_number) {
|
| - // Probe cache.
|
| - auto cache = isolate->template_instantiations_cache();
|
| - int entry = cache->FindEntry(serial_number);
|
| - if (entry != UnseededNumberDictionary::kNotFound) {
|
| - Object* element = cache->ValueAt(entry);
|
| - return handle(JSFunction::cast(element), isolate);
|
| + Handle<JSObject> result;
|
| + if (ProbeInstantiationsCache(isolate, serial_number).ToHandle(&result)) {
|
| + return Handle<JSFunction>::cast(result);
|
| }
|
| }
|
| - // Enter a new scope. Recursion could otherwise create a lot of handles.
|
| - HandleScope scope(isolate);
|
| Handle<JSObject> prototype;
|
| if (!data->remove_prototype()) {
|
| - auto prototype_templ = handle(data->prototype_template(), isolate);
|
| + Object* prototype_templ = data->prototype_template();
|
| if (prototype_templ->IsUndefined(isolate)) {
|
| prototype = isolate->factory()->NewJSObject(isolate->object_function());
|
| } else {
|
| ASSIGN_RETURN_ON_EXCEPTION(
|
| isolate, prototype,
|
| - InstantiateObject(isolate,
|
| - Handle<ObjectTemplateInfo>::cast(prototype_templ),
|
| - Handle<JSReceiver>(), data->hidden_prototype()),
|
| + InstantiateObject(
|
| + isolate,
|
| + handle(ObjectTemplateInfo::cast(prototype_templ), isolate),
|
| + Handle<JSReceiver>(), data->hidden_prototype()),
|
| JSFunction);
|
| }
|
| - auto parent = handle(data->parent_template(), isolate);
|
| + Object* parent = data->parent_template();
|
| if (!parent->IsUndefined(isolate)) {
|
| + // 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(parent)),
|
| + InstantiateFunction(
|
| + isolate, handle(FunctionTemplateInfo::cast(parent), isolate)),
|
| JSFunction);
|
| // TODO(dcarney): decide what to do here.
|
| Handle<Object> parent_prototype;
|
| @@ -410,7 +449,7 @@ MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
|
| MaybeHandle<JSFunction>());
|
| }
|
| }
|
| - auto function = ApiNatives::CreateApiFunction(
|
| + Handle<JSFunction> function = ApiNatives::CreateApiFunction(
|
| isolate, data, prototype, ApiNatives::JavaScriptObjectType);
|
| if (!name.is_null() && name->IsString()) {
|
| function->shared()->set_name(*name);
|
| @@ -419,7 +458,7 @@ MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
|
| // Cache the function.
|
| CacheTemplateInstantiation(isolate, serial_number, function);
|
| }
|
| - auto result =
|
| + MaybeHandle<JSObject> result =
|
| ConfigureInstance(isolate, function, data, data->hidden_prototype());
|
| if (result.is_null()) {
|
| // Uncache on error.
|
| @@ -428,29 +467,10 @@ MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
|
| }
|
| return MaybeHandle<JSFunction>();
|
| }
|
| - return scope.CloseAndEscape(function);
|
| + return function;
|
| }
|
|
|
|
|
| -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_;
|
| -};
|
| -
|
| -
|
| void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
|
| int length, Handle<Object>* data) {
|
| auto list = handle(templ->property_list(), isolate);
|
|
|