diff --git a/src/accessors.cc b/src/accessors.cc index 74238eb168..73665fa036 100644 --- a/src/accessors.cc +++ b/src/accessors.cc @@ -664,29 +664,10 @@ Handle Accessors::ScriptEvalFromFunctionNameInfo( // Accessors::FunctionPrototype // -static Handle GetFunctionPrototype(Isolate* isolate, - Handle function) { - if (!function->has_prototype()) { - Handle proto = isolate->factory()->NewFunctionPrototype(function); - JSFunction::SetPrototype(function, proto); - } - return Handle(function->prototype(), isolate); -} - - -MUST_USE_RESULT static MaybeHandle SetFunctionPrototype( - Isolate* isolate, Handle function, Handle value) { - JSFunction::SetPrototype(function, value); - DCHECK(function->prototype() == *value); - return function; -} - - MaybeHandle Accessors::FunctionSetPrototype(Handle function, Handle prototype) { - DCHECK(function->IsConstructor()); - Isolate* isolate = function->GetIsolate(); - return SetFunctionPrototype(isolate, function, prototype); + JSFunction::SetPrototype(function, prototype); + return function; } @@ -697,7 +678,7 @@ void Accessors::FunctionPrototypeGetter( HandleScope scope(isolate); Handle function = Handle::cast(Utils::OpenHandle(*info.Holder())); - Handle result = GetFunctionPrototype(isolate, function); + Handle result = JSFunction::GetPrototype(isolate, function); info.GetReturnValue().Set(Utils::ToLocal(result)); } @@ -711,9 +692,7 @@ void Accessors::FunctionPrototypeSetter( Handle value = Utils::OpenHandle(*val); Handle object = Handle::cast(Utils::OpenHandle(*info.Holder())); - if (SetFunctionPrototype(isolate, object, value).is_null()) { - isolate->OptionalRescheduleException(false); - } + JSFunction::SetPrototype(object, value); } diff --git a/src/api-natives.cc b/src/api-natives.cc index f09f42d5f0..fdf2c81d87 100644 --- a/src/api-natives.cc +++ b/src/api-natives.cc @@ -371,43 +371,12 @@ MaybeHandle InstantiateFunction(Isolate* isolate, return handle(JSFunction::cast(element), isolate); } } + // Enter a new scope. Recursion could otherwise create a lot of handles. HandleScope scope(isolate); - Handle prototype; - if (!data->remove_prototype()) { - auto prototype_templ = handle(data->prototype_template(), isolate); - if (prototype_templ->IsUndefined(isolate)) { - prototype = isolate->factory()->NewJSObject(isolate->object_function()); - } else { - ASSIGN_RETURN_ON_EXCEPTION( - isolate, prototype, - InstantiateObject(isolate, - Handle::cast(prototype_templ), - Handle(), data->hidden_prototype()), - JSFunction); - } - auto parent = handle(data->parent_template(), isolate); - if (!parent->IsUndefined(isolate)) { - Handle parent_instance; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, parent_instance, - InstantiateFunction(isolate, - Handle::cast(parent)), - JSFunction); - // TODO(dcarney): decide what to do here. - Handle parent_prototype; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, parent_prototype, - JSObject::GetProperty(parent_instance, - isolate->factory()->prototype_string()), - JSFunction); - MAYBE_RETURN(JSObject::SetPrototype(prototype, parent_prototype, false, - Object::THROW_ON_ERROR), - MaybeHandle()); - } - } - auto function = ApiNatives::CreateApiFunction( - isolate, data, prototype, ApiNatives::JavaScriptObjectType); + + auto function = + ApiNatives::CreateApiFunction(isolate, data, JS_API_OBJECT_TYPE); if (!name.is_null() && name->IsString()) { function->shared()->set_name(*name); } @@ -533,20 +502,17 @@ void ApiNatives::AddNativeDataProperty(Isolate* isolate, array.add(isolate, property); } - Handle ApiNatives::CreateApiFunction( - Isolate* isolate, Handle obj, - Handle prototype, ApiInstanceType instance_type) { + Isolate* isolate, Handle obj, InstanceType type) { Handle shared = FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj); + DCHECK(shared->IsApiFunction()); Handle result = isolate->factory()->NewFunctionFromSharedFunctionInfo( shared, isolate->native_context()); if (obj->remove_prototype()) { result->set_map(*isolate->sloppy_function_without_prototype_map()); - DCHECK(prototype.is_null()); - DCHECK(result->shared()->IsApiFunction()); DCHECK(!result->has_initial_map()); DCHECK(!result->has_prototype()); DCHECK(!result->IsConstructor()); @@ -556,78 +522,81 @@ Handle ApiNatives::CreateApiFunction( // Down from here is only valid for API functions that can be used as a // constructor (don't set the "remove prototype" flag). - if (obj->read_only_prototype()) { - result->set_map(*isolate->sloppy_function_with_readonly_prototype_map()); - } - - if (prototype->IsTheHole(isolate)) { + // Set up function.prototype. + Handle prototype; + auto prototype_templ = handle(obj->prototype_template(), isolate); + if (type != JS_API_OBJECT_TYPE || prototype_templ->IsUndefined(isolate)) { prototype = isolate->factory()->NewFunctionPrototype(result); } else { + prototype = internal::InstantiateObject( + isolate, Handle::cast(prototype_templ), + Handle(), obj->hidden_prototype()) + .ToHandleChecked(); + JSObject::AddProperty(Handle::cast(prototype), isolate->factory()->constructor_string(), result, DONT_ENUM); } + // Set up function.prototype.__proto__. + auto parent = handle(obj->parent_template(), isolate); + if (!parent->IsUndefined(isolate)) { + Handle parent_instance = + internal::InstantiateFunction( + isolate, Handle::cast(parent)) + .ToHandleChecked(); + Handle parent_prototype = + JSFunction::GetPrototype(isolate, parent_instance); + CHECK(JSObject::SetPrototype(prototype, parent_prototype, false, + Object::THROW_ON_ERROR) + .IsJust()); + } + if (obj->read_only_prototype()) { + result->set_map(*isolate->sloppy_function_with_readonly_prototype_map()); + } + + // Set up the function's initial map. int internal_field_count = 0; if (!obj->instance_template()->IsUndefined(isolate)) { - Handle instance_template = Handle( + Handle instance_template( ObjectTemplateInfo::cast(obj->instance_template())); internal_field_count = Smi::cast(instance_template->internal_field_count())->value(); } - // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing - // JSObject::GetHeaderSize. int instance_size = kPointerSize * internal_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 { + switch (type) { + case JS_API_OBJECT_TYPE: + if (obj->needs_access_check() || + !obj->named_property_handler()->IsUndefined(isolate) || + !obj->indexed_property_handler()->IsUndefined(isolate)) { type = JS_SPECIAL_API_OBJECT_TYPE; } instance_size += JSObject::kHeaderSize; break; - case GlobalObjectType: - type = JS_GLOBAL_OBJECT_TYPE; + case JS_GLOBAL_OBJECT_TYPE: instance_size += JSGlobalObject::kSize; break; - case GlobalProxyType: - type = JS_GLOBAL_PROXY_TYPE; + case JS_GLOBAL_PROXY_TYPE: instance_size += JSGlobalProxy::kSize; break; default: UNREACHABLE(); - type = JS_OBJECT_TYPE; // Keep the compiler happy. break; } Handle map = isolate->factory()->NewMap(type, instance_size, FAST_HOLEY_SMI_ELEMENTS); - JSFunction::SetInitialMap(result, map, Handle::cast(prototype)); + JSFunction::SetInitialMap(result, map, prototype); - // Mark as undetectable if needed. - if (obj->undetectable()) { - map->set_is_undetectable(); - } - - // Mark as needs_access_check if needed. - if (obj->needs_access_check()) { - map->set_is_access_check_needed(true); - } - - // Set interceptor information in the map. + if (obj->undetectable()) map->set_is_undetectable(); + if (obj->needs_access_check()) map->set_is_access_check_needed(true); if (!obj->named_property_handler()->IsUndefined(isolate)) { map->set_has_named_interceptor(); } if (!obj->indexed_property_handler()->IsUndefined(isolate)) { map->set_has_indexed_interceptor(); } - - // Mark instance as callable in the map. if (!obj->instance_call_handler()->IsUndefined(isolate)) { map->set_is_callable(); map->set_is_constructor(true); diff --git a/src/api-natives.h b/src/api-natives.h index 66901fe965..a75d27a903 100644 --- a/src/api-natives.h +++ b/src/api-natives.h @@ -6,6 +6,7 @@ #define V8_API_NATIVES_H_ #include "src/handles.h" +#include "src/objects.h" #include "src/property-details.h" namespace v8 { @@ -26,16 +27,9 @@ class ApiNatives { Handle data, Handle new_target = Handle()); - enum ApiInstanceType { - JavaScriptObjectType, - GlobalObjectType, - GlobalProxyType - }; - static Handle CreateApiFunction(Isolate* isolate, Handle obj, - Handle prototype, - ApiInstanceType instance_type); + InstanceType type); static void AddDataProperty(Isolate* isolate, Handle info, Handle name, Handle value, diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 4e3c62cfbf..1474d520c8 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1012,23 +1012,13 @@ Handle Genesis::CreateNewGlobals( if (js_global_object_template.is_null()) { Handle name = Handle(heap()->empty_string()); Handle code = isolate()->builtins()->Illegal(); - Handle prototype = - factory()->NewFunctionPrototype(isolate()->object_function()); js_global_object_function = factory()->NewFunction( - name, code, prototype, JS_GLOBAL_OBJECT_TYPE, JSGlobalObject::kSize); -#ifdef DEBUG - LookupIterator it(prototype, factory()->constructor_string(), - LookupIterator::OWN_SKIP_INTERCEPTOR); - Handle value = Object::GetProperty(&it).ToHandleChecked(); - DCHECK(it.IsFound()); - DCHECK_EQ(*isolate()->object_function(), *value); -#endif + name, code, JS_GLOBAL_OBJECT_TYPE, JSGlobalObject::kSize); } else { Handle js_global_object_constructor( FunctionTemplateInfo::cast(js_global_object_template->constructor())); js_global_object_function = ApiNatives::CreateApiFunction( - isolate(), js_global_object_constructor, factory()->the_hole_value(), - ApiNatives::GlobalObjectType); + isolate(), js_global_object_constructor, JS_GLOBAL_OBJECT_TYPE); } js_global_object_function->initial_map()->set_is_prototype_map(true); @@ -1049,8 +1039,7 @@ Handle Genesis::CreateNewGlobals( Handle global_constructor( FunctionTemplateInfo::cast(data->constructor())); global_proxy_function = ApiNatives::CreateApiFunction( - isolate(), global_constructor, factory()->the_hole_value(), - ApiNatives::GlobalProxyType); + isolate(), global_constructor, JS_GLOBAL_PROXY_TYPE); } Handle global_name = factory()->global_string(); global_proxy_function->shared()->set_instance_class_name(*global_name); @@ -2923,10 +2912,10 @@ bool Genesis::InstallNatives(GlobalContextType context_type) { // objects, that JavaScript code may not access. Handle opaque_reference_fun = factory()->NewFunction( factory()->empty_string(), isolate()->builtins()->Illegal(), - isolate()->initial_object_prototype(), JS_VALUE_TYPE, JSValue::kSize); + JS_VALUE_TYPE, JSValue::kSize); Handle prototype = factory()->NewJSObject(isolate()->object_function(), TENURED); - Accessors::FunctionSetPrototype(opaque_reference_fun, prototype).Assert(); + JSFunction::SetPrototype(opaque_reference_fun, prototype); native_context()->set_opaque_reference_function(*opaque_reference_fun); } @@ -2952,11 +2941,6 @@ bool Genesis::InstallNatives(GlobalContextType context_type) { if (!CallUtilsFunction(isolate(), "PostNatives")) return false; - auto template_instantiations_cache = UnseededNumberDictionary::New( - isolate(), ApiNatives::kInitialFunctionCacheSize); - native_context()->set_template_instantiations_cache( - *template_instantiations_cache); - // Store the map for the %ObjectPrototype% after the natives has been compiled // and the Object function has been set up. Handle object_function(native_context()->object_function()); @@ -3873,6 +3857,14 @@ Genesis::Genesis(Isolate* isolate, CreateStrictModeFunctionMaps(empty_function); CreateIteratorMaps(empty_function); CreateAsyncFunctionMaps(empty_function); + + // Set up the template instantiations cache before creating the globals, + // since they may want to use the cache. + auto template_instantiations_cache = UnseededNumberDictionary::New( + isolate, ApiNatives::kInitialFunctionCacheSize); + native_context()->set_template_instantiations_cache( + *template_instantiations_cache); + Handle global_object = CreateNewGlobals(global_proxy_template, global_proxy); HookUpGlobalProxy(global_object, global_proxy); diff --git a/src/factory.cc b/src/factory.cc index e197494e6b..09c4ec3789 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1276,36 +1276,23 @@ Handle Factory::NewFunctionWithoutPrototype(Handle name, } -Handle Factory::NewFunction(Handle name, Handle code, - Handle prototype, - bool is_strict) { - Handle map = is_strict ? isolate()->strict_function_map() - : isolate()->sloppy_function_map(); - Handle result = NewFunction(map, name, code); - result->set_prototype_or_initial_map(*prototype); - return result; -} - - Handle Factory::NewFunction(Handle name, Handle code, Handle prototype, InstanceType type, int instance_size, bool is_strict) { // Allocate the function - Handle function = NewFunction(name, code, prototype, is_strict); + Handle map = is_strict ? isolate()->strict_function_map() + : isolate()->sloppy_function_map(); + Handle function = NewFunction(map, name, code); + DCHECK(prototype->IsTheHole(isolate()) || prototype->IsNull(isolate()) || + prototype->IsJSReceiver()); + function->set_prototype_or_initial_map(*prototype); + // TODO(verwaest): Do we need to eagerly allocate the map here? ElementsKind elements_kind = type == JS_ARRAY_TYPE ? FAST_SMI_ELEMENTS : FAST_HOLEY_SMI_ELEMENTS; Handle initial_map = NewMap(type, instance_size, elements_kind); - // TODO(littledan): Why do we have this is_generator test when - // NewFunctionPrototype already handles finding an appropriately - // shared prototype? - if (!function->shared()->is_resumable()) { - if (prototype->IsTheHole(isolate())) { - prototype = NewFunctionPrototype(function); - } - } - + prototype = JSFunction::GetPrototype(isolate(), function); JSFunction::SetInitialMap(function, initial_map, Handle::cast(prototype)); diff --git a/src/factory.h b/src/factory.h index f8b91a913d..75eff9cbd3 100644 --- a/src/factory.h +++ b/src/factory.h @@ -506,9 +506,6 @@ class Factory final { Handle NewUninitializedJSGlobalProxy(); - Handle NewFunction(Handle name, Handle code, - Handle prototype, - bool is_strict = false); Handle NewFunction(Handle name); Handle NewFunctionWithoutPrototype(Handle name, Handle code, diff --git a/src/objects.cc b/src/objects.cc index 943474a55a..eca07b3193 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -5357,6 +5357,17 @@ MaybeHandle JSBoundFunction::GetName(Isolate* isolate, return factory->NewConsString(prefix, Handle::cast(target_name)); } +// static +Handle JSFunction::GetPrototype(Isolate* isolate, + Handle function) { + DCHECK(function->IsConstructor() || function->shared()->is_generator()); + if (!function->has_prototype()) { + Handle proto = isolate->factory()->NewFunctionPrototype(function); + JSFunction::SetPrototype(function, proto); + } + return handle(function->prototype(), isolate); +} + // static Handle JSFunction::GetName(Isolate* isolate, Handle function) { diff --git a/src/objects.h b/src/objects.h index 91bfaf2c26..d256fc4740 100644 --- a/src/objects.h +++ b/src/objects.h @@ -7514,9 +7514,11 @@ class JSFunction: public JSObject { inline Context* native_context(); static Handle GetName(Isolate* isolate, Handle function); - static MaybeHandle GetLength(Isolate* isolate, - Handle function); + static MUST_USE_RESULT MaybeHandle GetLength( + Isolate* isolate, Handle function); static Handle GetFunctionRealm(Handle function); + static Handle GetPrototype(Isolate* isolate, + Handle function); // [code]: The generated code object for this function. Executed // when the function is invoked, e.g. foo() or new foo(). See