Index: test/cctest/test-compiler.cc |
diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc |
index b7073e748949cf22f3ae8df59a31c4177775cbed..bce3fb239497ec5f95d5f75820413d74ea5567c3 100644 |
--- a/test/cctest/test-compiler.cc |
+++ b/test/cctest/test-compiler.cc |
@@ -406,6 +406,150 @@ |
} |
} |
+// Test that optimized code for different closures is actually shared. |
+TEST(OptimizedCodeSharing2) { |
+ if (FLAG_stress_compaction) return; |
+ FLAG_allow_natives_syntax = true; |
+ FLAG_native_context_specialization = false; |
+ FLAG_turbo_cache_shared_code = true; |
+ const char* flag = "--turbo-filter=*"; |
+ FlagList::SetFlagsFromString(flag, StrLength(flag)); |
+ CcTest::InitializeVM(); |
+ v8::HandleScope scope(CcTest::isolate()); |
+ v8::Local<v8::Script> script = v8_compile( |
+ "function MakeClosure() {" |
+ " return function() { return x; };" |
+ "}"); |
+ Handle<Code> reference_code; |
+ { |
+ LocalContext env; |
+ env->Global() |
+ ->Set(env.local(), v8_str("x"), v8::Integer::New(CcTest::isolate(), 23)) |
+ .FromJust(); |
+ script->GetUnboundScript() |
+ ->BindToCurrentContext() |
+ ->Run(env.local()) |
+ .ToLocalChecked(); |
+ CompileRun( |
+ "var closure0 = MakeClosure();" |
+ "%DebugPrint(closure0());" |
+ "%OptimizeFunctionOnNextCall(closure0);" |
+ "%DebugPrint(closure0());"); |
+ Handle<JSFunction> fun0 = Handle<JSFunction>::cast( |
+ v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
+ env->Global() |
+ ->Get(env.local(), v8_str("closure0")) |
+ .ToLocalChecked()))); |
+ CHECK(fun0->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); |
+ reference_code = handle(fun0->code()); |
+ } |
+ for (int i = 0; i < 3; i++) { |
+ LocalContext env; |
+ env->Global() |
+ ->Set(env.local(), v8_str("x"), v8::Integer::New(CcTest::isolate(), i)) |
+ .FromJust(); |
+ script->GetUnboundScript() |
+ ->BindToCurrentContext() |
+ ->Run(env.local()) |
+ .ToLocalChecked(); |
+ CompileRun( |
+ "var closure0 = MakeClosure();" |
+ "%DebugPrint(closure0());" |
+ "%OptimizeFunctionOnNextCall(closure0);" |
+ "%DebugPrint(closure0());" |
+ "var closure1 = MakeClosure(); closure1();" |
+ "var closure2 = MakeClosure(); closure2();"); |
+ Handle<JSFunction> fun1 = Handle<JSFunction>::cast( |
+ v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
+ env->Global() |
+ ->Get(env.local(), v8_str("closure1")) |
+ .ToLocalChecked()))); |
+ Handle<JSFunction> fun2 = Handle<JSFunction>::cast( |
+ v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
+ env->Global() |
+ ->Get(env.local(), v8_str("closure2")) |
+ .ToLocalChecked()))); |
+ CHECK(fun1->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); |
+ CHECK(fun2->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); |
+ CHECK_EQ(*reference_code, fun1->code()); |
+ CHECK_EQ(*reference_code, fun2->code()); |
+ } |
+} |
+ |
+// Test that optimized code for different closures is actually shared. |
+TEST(OptimizedCodeSharing3) { |
+ if (FLAG_stress_compaction) return; |
+ FLAG_allow_natives_syntax = true; |
+ FLAG_native_context_specialization = false; |
+ FLAG_turbo_cache_shared_code = true; |
+ const char* flag = "--turbo-filter=*"; |
+ FlagList::SetFlagsFromString(flag, StrLength(flag)); |
+ CcTest::InitializeVM(); |
+ v8::HandleScope scope(CcTest::isolate()); |
+ v8::Local<v8::Script> script = v8_compile( |
+ "function MakeClosure() {" |
+ " return function() { return x; };" |
+ "}"); |
+ Handle<Code> reference_code; |
+ { |
+ LocalContext env; |
+ env->Global() |
+ ->Set(env.local(), v8_str("x"), v8::Integer::New(CcTest::isolate(), 23)) |
+ .FromJust(); |
+ script->GetUnboundScript() |
+ ->BindToCurrentContext() |
+ ->Run(env.local()) |
+ .ToLocalChecked(); |
+ CompileRun( |
+ "var closure0 = MakeClosure();" |
+ "%DebugPrint(closure0());" |
+ "%OptimizeFunctionOnNextCall(closure0);" |
+ "%DebugPrint(closure0());"); |
+ Handle<JSFunction> fun0 = Handle<JSFunction>::cast( |
+ v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
+ env->Global() |
+ ->Get(env.local(), v8_str("closure0")) |
+ .ToLocalChecked()))); |
+ CHECK(fun0->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); |
+ reference_code = handle(fun0->code()); |
+ // Evict only the context-dependent entry from the optimized code map. This |
+ // leaves it in a state where only the context-independent entry exists. |
+ fun0->shared()->TrimOptimizedCodeMap(SharedFunctionInfo::kEntryLength); |
+ } |
+ for (int i = 0; i < 3; i++) { |
+ LocalContext env; |
+ env->Global() |
+ ->Set(env.local(), v8_str("x"), v8::Integer::New(CcTest::isolate(), i)) |
+ .FromJust(); |
+ script->GetUnboundScript() |
+ ->BindToCurrentContext() |
+ ->Run(env.local()) |
+ .ToLocalChecked(); |
+ CompileRun( |
+ "var closure0 = MakeClosure();" |
+ "%DebugPrint(closure0());" |
+ "%OptimizeFunctionOnNextCall(closure0);" |
+ "%DebugPrint(closure0());" |
+ "var closure1 = MakeClosure(); closure1();" |
+ "var closure2 = MakeClosure(); closure2();"); |
+ Handle<JSFunction> fun1 = Handle<JSFunction>::cast( |
+ v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
+ env->Global() |
+ ->Get(env.local(), v8_str("closure1")) |
+ .ToLocalChecked()))); |
+ Handle<JSFunction> fun2 = Handle<JSFunction>::cast( |
+ v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
+ env->Global() |
+ ->Get(env.local(), v8_str("closure2")) |
+ .ToLocalChecked()))); |
+ CHECK(fun1->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); |
+ CHECK(fun2->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); |
+ CHECK_EQ(*reference_code, fun1->code()); |
+ CHECK_EQ(*reference_code, fun2->code()); |
+ } |
+} |
+ |
+ |
TEST(CompileFunctionInContext) { |
CcTest::InitializeVM(); |
v8::HandleScope scope(CcTest::isolate()); |