use a hash table for the function cache as blink is leaking functiontemplates
BUG= Review URL: https://codereview.chromium.org/988283003 Cr-Commit-Position: refs/heads/master@{#27066}
This commit is contained in:
parent
d18bfa1130
commit
d7f25f557c
@ -207,36 +207,33 @@ MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
|
||||
}
|
||||
|
||||
|
||||
void InstallInCache(Isolate* isolate, int serial_number,
|
||||
Handle<JSFunction> function) {
|
||||
void CacheFunction(Isolate* isolate, Handle<Smi> serial_number,
|
||||
Handle<JSFunction> function) {
|
||||
auto cache = isolate->function_cache();
|
||||
if (cache->length() <= serial_number) {
|
||||
int new_size;
|
||||
if (isolate->next_serial_number() < 50) {
|
||||
new_size = 100;
|
||||
} else {
|
||||
new_size = 3 * isolate->next_serial_number() / 2;
|
||||
}
|
||||
cache = FixedArray::CopySize(cache, new_size);
|
||||
isolate->native_context()->set_function_cache(*cache);
|
||||
}
|
||||
cache->set(serial_number, *function);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
|
||||
Handle<FunctionTemplateInfo> data,
|
||||
Handle<Name> name) {
|
||||
int serial_number = Smi::cast(data->serial_number())->value();
|
||||
auto serial_number = handle(Smi::cast(data->serial_number()), isolate);
|
||||
// Probe cache.
|
||||
if (!data->do_not_cache()) {
|
||||
auto cache = isolate->function_cache();
|
||||
// Fast case: see if the function has already been instantiated
|
||||
if (serial_number < cache->length()) {
|
||||
Handle<Object> element = FixedArray::get(cache, serial_number);
|
||||
if (element->IsJSFunction()) {
|
||||
return Handle<JSFunction>::cast(element);
|
||||
}
|
||||
Object* element = cache->Lookup(serial_number);
|
||||
if (element->IsJSFunction()) {
|
||||
return handle(JSFunction::cast(element), isolate);
|
||||
}
|
||||
}
|
||||
// Enter a new scope. Recursion could otherwise create a lot of handles.
|
||||
@ -279,15 +276,14 @@ MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
|
||||
function->shared()->set_name(*name);
|
||||
}
|
||||
if (!data->do_not_cache()) {
|
||||
// Cache the function to limit recursion.
|
||||
InstallInCache(isolate, serial_number, function);
|
||||
// Cache the function.
|
||||
CacheFunction(isolate, serial_number, function);
|
||||
}
|
||||
auto result = ConfigureInstance(isolate, function, data);
|
||||
if (result.is_null()) {
|
||||
// uncache on error.
|
||||
// Uncache on error.
|
||||
if (!data->do_not_cache()) {
|
||||
auto cache = isolate->function_cache();
|
||||
cache->set(serial_number, isolate->heap()->undefined_value());
|
||||
UncacheFunction(isolate, serial_number);
|
||||
}
|
||||
return MaybeHandle<JSFunction>();
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ namespace internal {
|
||||
|
||||
class ApiNatives {
|
||||
public:
|
||||
static const int kInitialFunctionCacheSize = 256;
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<JSFunction> InstantiateFunction(
|
||||
Handle<FunctionTemplateInfo> data);
|
||||
|
||||
|
@ -2117,7 +2117,9 @@ bool Genesis::InstallNatives() {
|
||||
|
||||
InstallNativeFunctions();
|
||||
|
||||
native_context()->set_function_cache(heap()->empty_fixed_array());
|
||||
auto function_cache =
|
||||
ObjectHashTable::New(isolate(), ApiNatives::kInitialFunctionCacheSize);
|
||||
native_context()->set_function_cache(*function_cache);
|
||||
|
||||
// Store the map for the string prototype after the natives has been compiled
|
||||
// and the String function has been set up.
|
||||
|
@ -140,7 +140,7 @@ enum BindingFlags {
|
||||
V(MAKE_MESSAGE_FUN_INDEX, JSFunction, make_message_fun) \
|
||||
V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \
|
||||
V(CONFIGURE_GLOBAL_INDEX, JSFunction, configure_global_fun) \
|
||||
V(FUNCTION_CACHE_INDEX, FixedArray, function_cache) \
|
||||
V(FUNCTION_CACHE_INDEX, ObjectHashTable, function_cache) \
|
||||
V(JSFUNCTION_RESULT_CACHES_INDEX, FixedArray, jsfunction_result_caches) \
|
||||
V(NORMALIZED_MAP_CACHE_INDEX, Object, normalized_map_cache) \
|
||||
V(RUNTIME_CONTEXT_INDEX, Context, runtime_context) \
|
||||
|
@ -20038,15 +20038,15 @@ THREADED_TEST(FunctionNew) {
|
||||
env->Global()->Set(v8_str("func"), func);
|
||||
Local<Value> result = CompileRun("func();");
|
||||
CHECK(v8::Integer::New(isolate, 17)->Equals(result));
|
||||
// Verify function not cached
|
||||
int serial_number =
|
||||
i::Smi::cast(v8::Utils::OpenHandle(*func)
|
||||
->shared()->get_api_func_data()->serial_number())->value();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
i::Handle<i::FixedArray> cache(i_isolate->native_context()->function_cache());
|
||||
if (serial_number < cache->length()) {
|
||||
CHECK(cache->get(serial_number)->IsUndefined());
|
||||
}
|
||||
// Verify function not cached
|
||||
auto serial_number = handle(i::Smi::cast(v8::Utils::OpenHandle(*func)
|
||||
->shared()
|
||||
->get_api_func_data()
|
||||
->serial_number()),
|
||||
i_isolate);
|
||||
auto cache = i_isolate->function_cache();
|
||||
CHECK(cache->Lookup(serial_number)->IsTheHole());
|
||||
// Verify that each Function::New creates a new function instance
|
||||
Local<Object> data2 = v8::Object::New(isolate);
|
||||
function_new_expected_env = data2;
|
||||
|
Loading…
Reference in New Issue
Block a user