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:
parent
a933b7044a
commit
a7a9ac37d4
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user