Share SharedFunctionInfo between all functions created for a FunctionTemplateInfo

BUG=

Review-Url: https://codereview.chromium.org/2095673002
Cr-Commit-Position: refs/heads/master@{#37252}
This commit is contained in:
verwaest 2016-06-24 06:51:24 -07:00 committed by Commit bot
parent a933b7044a
commit a7a9ac37d4
7 changed files with 114 additions and 107 deletions

View File

@ -537,95 +537,77 @@ void ApiNatives::AddNativeDataProperty(Isolate* isolate,
Handle<JSFunction> ApiNatives::CreateApiFunction(
Isolate* isolate, Handle<FunctionTemplateInfo> obj,
Handle<Object> prototype, ApiInstanceType instance_type) {
Handle<Code> code;
if (obj->call_code()->IsCallHandlerInfo() &&
CallHandlerInfo::cast(obj->call_code())->fast_handler()->IsCode()) {
code = isolate->builtins()->HandleFastApiCall();
} else {
code = isolate->builtins()->HandleApiCall();
}
Handle<Code> construct_stub =
prototype.is_null() ? isolate->builtins()->ConstructedNonConstructable()
: isolate->builtins()->JSConstructStubApi();
obj->set_instantiated(true);
Handle<JSFunction> result;
if (obj->remove_prototype()) {
result = isolate->factory()->NewFunctionWithoutPrototype(
isolate->factory()->empty_string(), code);
} else {
int internal_field_count = 0;
if (!obj->instance_template()->IsUndefined(isolate)) {
Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
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 {
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();
type = JS_OBJECT_TYPE; // Keep the compiler happy.
break;
}
result = isolate->factory()->NewFunction(
isolate->factory()->empty_string(), code, prototype, type,
instance_size, obj->read_only_prototype(), true);
}
result->shared()->set_length(obj->length());
Handle<Object> class_name(obj->class_name(), isolate);
if (class_name->IsString()) {
result->shared()->set_instance_class_name(*class_name);
result->shared()->set_name(*class_name);
}
result->shared()->set_api_func_data(*obj);
result->shared()->set_construct_stub(*construct_stub);
result->shared()->DontAdaptArguments();
Handle<SharedFunctionInfo> shared =
FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj);
Handle<JSFunction> 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());
return result;
}
#ifdef DEBUG
LookupIterator it(handle(JSObject::cast(result->prototype())),
isolate->factory()->constructor_string(),
LookupIterator::OWN_SKIP_INTERCEPTOR);
MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
DCHECK(it.IsFound());
DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
#endif
// Down from here is only valid for API functions that can be used as a
// constructor (don't set the "remove prototype" flag).
Handle<Map> map(result->initial_map());
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 {
JSObject::AddProperty(Handle<JSObject>::cast(prototype),
isolate->factory()->constructor_string(), result,
DONT_ENUM);
}
int internal_field_count = 0;
if (!obj->instance_template()->IsUndefined(isolate)) {
Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
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 {
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();
type = JS_OBJECT_TYPE; // Keep the compiler happy.
break;
}
Handle<Map> map =
isolate->factory()->NewMap(type, instance_size, FAST_HOLEY_SMI_ELEMENTS);
JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
// Mark as undetectable if needed.
if (obj->undetectable()) {
@ -651,7 +633,6 @@ Handle<JSFunction> ApiNatives::CreateApiFunction(
map->set_is_constructor(true);
}
DCHECK(result->shared()->IsApiFunction());
return result;
}

View File

@ -399,12 +399,9 @@ Handle<JSFunction> CreateFunction(Isolate* isolate, Handle<String> name,
Factory* factory = isolate->factory();
Handle<Code> call_code(isolate->builtins()->builtin(call));
Handle<JSObject> prototype;
static const bool kReadOnlyPrototype = false;
static const bool kInstallConstructor = false;
return maybe_prototype.ToHandle(&prototype)
? factory->NewFunction(name, call_code, prototype, type,
instance_size, kReadOnlyPrototype,
kInstallConstructor, strict_function_map)
instance_size, strict_function_map)
: factory->NewFunctionWithoutPrototype(name, call_code,
strict_function_map);
}

View File

@ -1278,16 +1278,9 @@ Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String> name,
Handle<JSFunction> Factory::NewFunction(Handle<String> name, Handle<Code> code,
Handle<Object> prototype,
bool read_only_prototype,
bool is_strict) {
// In strict mode, readonly strict map is only available during bootstrap
DCHECK(!is_strict || !read_only_prototype ||
isolate()->bootstrapper()->IsActive());
Handle<Map> map =
is_strict ? isolate()->strict_function_map()
: read_only_prototype
? isolate()->sloppy_function_with_readonly_prototype_map()
: isolate()->sloppy_function_map();
Handle<Map> map = is_strict ? isolate()->strict_function_map()
: isolate()->sloppy_function_map();
Handle<JSFunction> result = NewFunction(map, name, code);
result->set_prototype_or_initial_map(*prototype);
return result;
@ -1297,12 +1290,9 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name, Handle<Code> code,
Handle<JSFunction> Factory::NewFunction(Handle<String> name, Handle<Code> code,
Handle<Object> prototype,
InstanceType type, int instance_size,
bool read_only_prototype,
bool install_constructor,
bool is_strict) {
// Allocate the function
Handle<JSFunction> function =
NewFunction(name, code, prototype, read_only_prototype, is_strict);
Handle<JSFunction> function = NewFunction(name, code, prototype, is_strict);
ElementsKind elements_kind =
type == JS_ARRAY_TYPE ? FAST_SMI_ELEMENTS : FAST_HOLEY_SMI_ELEMENTS;
@ -1313,9 +1303,6 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name, Handle<Code> code,
if (!function->shared()->is_resumable()) {
if (prototype->IsTheHole(isolate())) {
prototype = NewFunctionPrototype(function);
} else if (install_constructor) {
JSObject::AddProperty(Handle<JSObject>::cast(prototype),
constructor_string(), function, DONT_ENUM);
}
}

View File

@ -508,7 +508,6 @@ class Factory final {
Handle<JSFunction> NewFunction(Handle<String> name, Handle<Code> code,
Handle<Object> prototype,
bool read_only_prototype = false,
bool is_strict = false);
Handle<JSFunction> NewFunction(Handle<String> name);
Handle<JSFunction> NewFunctionWithoutPrototype(Handle<String> name,
@ -526,8 +525,6 @@ class Factory final {
Handle<JSFunction> NewFunction(Handle<String> name, Handle<Code> code,
Handle<Object> prototype, InstanceType type,
int instance_size,
bool read_only_prototype = false,
bool install_constructor = false,
bool is_strict = false);
Handle<JSFunction> NewFunction(Handle<String> name,
Handle<Code> code,

View File

@ -5506,6 +5506,10 @@ bool PrototypeInfo::HasObjectCreateMap() {
return cache->IsWeakCell() && !WeakCell::cast(cache)->cleared();
}
bool FunctionTemplateInfo::instantiated() {
return shared_function_info()->IsSharedFunctionInfo();
}
ACCESSORS(PrototypeInfo, prototype_users, Object, kPrototypeUsersOffset)
ACCESSORS(PrototypeInfo, object_create_map, Object, kObjectCreateMap)
SMI_ACCESSORS(PrototypeInfo, registry_slot, kRegistrySlotOffset)
@ -5562,6 +5566,9 @@ ACCESSORS(FunctionTemplateInfo, instance_call_handler, Object,
kInstanceCallHandlerOffset)
ACCESSORS(FunctionTemplateInfo, access_check_info, Object,
kAccessCheckInfoOffset)
ACCESSORS(FunctionTemplateInfo, shared_function_info, Object,
kSharedFunctionInfoOffset)
SMI_ACCESSORS(FunctionTemplateInfo, flag, kFlagOffset)
ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset)
@ -5667,7 +5674,6 @@ BOOL_ACCESSORS(FunctionTemplateInfo, flag, remove_prototype,
kRemovePrototypeBit)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, do_not_cache,
kDoNotCacheBit)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, instantiated, kInstantiatedBit)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, accept_any_receiver,
kAcceptAnyReceiver)
BOOL_ACCESSORS(SharedFunctionInfo, start_position_and_type, is_named_expression,

View File

@ -986,6 +986,41 @@ bool Object::ToInt32(int32_t* value) {
return false;
}
Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
Isolate* isolate, Handle<FunctionTemplateInfo> info) {
Object* current_info = info->shared_function_info();
if (current_info->IsSharedFunctionInfo()) {
return handle(SharedFunctionInfo::cast(current_info), isolate);
}
Handle<Object> class_name(info->class_name(), isolate);
Handle<String> name = class_name->IsString()
? Handle<String>::cast(class_name)
: isolate->factory()->empty_string();
Handle<Code> code;
if (info->call_code()->IsCallHandlerInfo() &&
CallHandlerInfo::cast(info->call_code())->fast_handler()->IsCode()) {
code = isolate->builtins()->HandleFastApiCall();
} else {
code = isolate->builtins()->HandleApiCall();
}
bool is_constructor = !info->remove_prototype();
Handle<SharedFunctionInfo> result =
isolate->factory()->NewSharedFunctionInfo(name, code, is_constructor);
if (is_constructor) {
result->set_construct_stub(*isolate->builtins()->JSConstructStubApi());
}
result->set_length(info->length());
if (class_name->IsString()) result->set_instance_class_name(*class_name);
result->set_api_func_data(*info);
result->DontAdaptArguments();
DCHECK(result->IsApiFunction());
info->set_shared_function_info(*result);
return result;
}
bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
// There is a constraint on the object; check.
if (!map->IsJSObjectMap()) return false;

View File

@ -10523,6 +10523,7 @@ class FunctionTemplateInfo: public TemplateInfo {
DECL_ACCESSORS(signature, Object)
DECL_ACCESSORS(instance_call_handler, Object)
DECL_ACCESSORS(access_check_info, Object)
DECL_ACCESSORS(shared_function_info, Object)
DECL_INT_ACCESSORS(flag)
inline int length() const;
@ -10537,7 +10538,6 @@ class FunctionTemplateInfo: public TemplateInfo {
DECL_BOOLEAN_ACCESSORS(read_only_prototype)
DECL_BOOLEAN_ACCESSORS(remove_prototype)
DECL_BOOLEAN_ACCESSORS(do_not_cache)
DECL_BOOLEAN_ACCESSORS(instantiated)
DECL_BOOLEAN_ACCESSORS(accept_any_receiver)
DECLARE_CAST(FunctionTemplateInfo)
@ -10562,13 +10562,18 @@ class FunctionTemplateInfo: public TemplateInfo {
static const int kInstanceCallHandlerOffset = kSignatureOffset + kPointerSize;
static const int kAccessCheckInfoOffset =
kInstanceCallHandlerOffset + kPointerSize;
static const int kFlagOffset = kAccessCheckInfoOffset + kPointerSize;
static const int kSharedFunctionInfoOffset =
kAccessCheckInfoOffset + kPointerSize;
static const int kFlagOffset = kSharedFunctionInfoOffset + kPointerSize;
static const int kLengthOffset = kFlagOffset + kPointerSize;
static const int kSize = kLengthOffset + kPointerSize;
static Handle<SharedFunctionInfo> GetOrCreateSharedFunctionInfo(
Isolate* isolate, Handle<FunctionTemplateInfo> info);
// Returns true if |object| is an instance of this function template.
inline bool IsTemplateFor(JSObject* object);
bool IsTemplateFor(Map* map);
inline bool instantiated();
private:
// Bit position in the flag, from least significant bit position.
@ -10578,8 +10583,7 @@ class FunctionTemplateInfo: public TemplateInfo {
static const int kReadOnlyPrototypeBit = 3;
static const int kRemovePrototypeBit = 4;
static const int kDoNotCacheBit = 5;
static const int kInstantiatedBit = 6;
static const int kAcceptAnyReceiver = 7;
static const int kAcceptAnyReceiver = 6;
DISALLOW_IMPLICIT_CONSTRUCTORS(FunctionTemplateInfo);
};