diff options
Diffstat (limited to 'deps/v8/test/cctest/test-compiler.cc')
-rw-r--r-- | deps/v8/test/cctest/test-compiler.cc | 218 |
1 files changed, 198 insertions, 20 deletions
diff --git a/deps/v8/test/cctest/test-compiler.cc b/deps/v8/test/cctest/test-compiler.cc index 76ce276c06..f05056a2de 100644 --- a/deps/v8/test/cctest/test-compiler.cc +++ b/deps/v8/test/cctest/test-compiler.cc @@ -31,6 +31,7 @@ #include "src/v8.h" #include "src/api-inl.h" +#include "src/compilation-cache.h" #include "src/compiler.h" #include "src/disasm.h" #include "src/heap/factory.h" @@ -47,8 +48,7 @@ static Handle<Object> GetGlobalProperty(const char* name) { .ToHandleChecked(); } - -static void SetGlobalProperty(const char* name, Object* value) { +static void SetGlobalProperty(const char* name, Object value) { Isolate* isolate = CcTest::i_isolate(); Handle<Object> object(value, isolate); Handle<String> internalized_name = @@ -59,7 +59,6 @@ static void SetGlobalProperty(const char* name, Object* value) { .Check(); } - static Handle<JSFunction> Compile(const char* source) { Isolate* isolate = CcTest::i_isolate(); Handle<String> source_code = isolate->factory()->NewStringFromUtf8( @@ -155,7 +154,7 @@ TEST(Sum) { TEST(Print) { v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Context> context = CcTest::NewContext(PRINT_EXTENSION); + v8::Local<v8::Context> context = CcTest::NewContext({PRINT_EXTENSION_ID}); v8::Context::Scope context_scope(context); const char* source = "for (n = 0; n < 100; ++n) print(n, 1, 2);"; Handle<JSFunction> fun = Compile(source); @@ -223,7 +222,7 @@ TEST(C2JSFrames) { FLAG_expose_gc = true; v8::HandleScope scope(CcTest::isolate()); v8::Local<v8::Context> context = - CcTest::NewContext(PRINT_EXTENSION | GC_EXTENSION); + CcTest::NewContext({PRINT_EXTENSION_ID, GC_EXTENSION_ID}); v8::Context::Scope context_scope(context); const char* source = "function foo(a) { gc(), print(a); }"; @@ -241,8 +240,8 @@ TEST(C2JSFrames) { .ToHandleChecked(); CHECK(fun1->IsJSFunction()); - Handle<Object> argv[] = {isolate->factory()->InternalizeOneByteString( - STATIC_CHAR_VECTOR("hello"))}; + Handle<Object> argv[] = { + isolate->factory()->InternalizeOneByteString(StaticCharVector("hello"))}; Execution::Call(isolate, Handle<JSFunction>::cast(fun1), global, @@ -315,9 +314,9 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) { Handle<FeedbackVector> feedback_vector(f->feedback_vector(), f->GetIsolate()); CHECK(!feedback_vector->is_empty()); FeedbackSlot slot_for_a(0); - MaybeObject* object = feedback_vector->Get(slot_for_a); + MaybeObject object = feedback_vector->Get(slot_for_a); { - HeapObject* heap_object; + HeapObject heap_object; CHECK(object->GetHeapObjectIfWeak(&heap_object)); CHECK(heap_object->IsJSFunction()); } @@ -329,7 +328,7 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) { CHECK(f->IsOptimized()); object = f->feedback_vector()->Get(slot_for_a); { - HeapObject* heap_object; + HeapObject heap_object; CHECK(object->GetHeapObjectIfWeak(&heap_object)); CHECK(heap_object->IsJSFunction()); } @@ -337,7 +336,7 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) { TEST(FeedbackVectorUnaffectedByScopeChanges) { - if (i::FLAG_always_opt || !i::FLAG_lazy) { + if (i::FLAG_always_opt || !i::FLAG_lazy || i::FLAG_lite_mode) { return; } CcTest::InitializeVM(); @@ -487,8 +486,8 @@ TEST(CompileFunctionInContextArgs) { v8::Local<v8::Object> ext[1]; ext[0] = v8::Local<v8::Object>::Cast( env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()); - v8::ScriptCompiler::Source script_source(v8_str("result = x + b")); - v8::Local<v8::String> arg = v8_str("b"); + v8::ScriptCompiler::Source script_source(v8_str("result = x + abc")); + v8::Local<v8::String> arg = v8_str("abc"); v8::Local<v8::Function> fun = v8::ScriptCompiler::CompileFunctionInContext(env.local(), &script_source, 1, &arg, 1, ext) @@ -498,8 +497,8 @@ TEST(CompileFunctionInContextArgs) { ->ToInt32(env.local()) .ToLocalChecked() ->Value()); - v8::Local<v8::Value> b_value = v8::Number::New(CcTest::isolate(), 42.0); - fun->Call(env.local(), env->Global(), 1, &b_value).ToLocalChecked(); + v8::Local<v8::Value> arg_value = v8::Number::New(CcTest::isolate(), 42.0); + fun->Call(env.local(), env->Global(), 1, &arg_value).ToLocalChecked(); CHECK(env->Global()->Has(env.local(), v8_str("result")).FromJust()); v8::Local<v8::Value> result = env->Global()->Get(env.local(), v8_str("result")).ToLocalChecked(); @@ -516,16 +515,17 @@ TEST(CompileFunctionInContextComments) { v8::Local<v8::Object> ext[1]; ext[0] = v8::Local<v8::Object>::Cast( env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()); - v8::ScriptCompiler::Source script_source( - v8_str("result = /* y + */ x + b // + z")); - v8::Local<v8::String> arg = v8_str("b"); + v8::Local<v8::String> source = + CompileRun("'result = /* y + */ x + a\\u4e00 // + z'").As<v8::String>(); + v8::ScriptCompiler::Source script_source(source); + v8::Local<v8::String> arg = CompileRun("'a\\u4e00'").As<v8::String>(); v8::Local<v8::Function> fun = v8::ScriptCompiler::CompileFunctionInContext(env.local(), &script_source, 1, &arg, 1, ext) .ToLocalChecked(); CHECK(!fun.IsEmpty()); - v8::Local<v8::Value> b_value = v8::Number::New(CcTest::isolate(), 42.0); - fun->Call(env.local(), env->Global(), 1, &b_value).ToLocalChecked(); + v8::Local<v8::Value> arg_value = v8::Number::New(CcTest::isolate(), 42.0); + fun->Call(env.local(), env->Global(), 1, &arg_value).ToLocalChecked(); CHECK(env->Global()->Has(env.local(), v8_str("result")).FromJust()); v8::Local<v8::Value> result = env->Global()->Get(env.local(), v8_str("result")).ToLocalChecked(); @@ -771,6 +771,7 @@ TEST(CompileFunctionInContextFunctionToString) { } TEST(InvocationCount) { + if (FLAG_lite_mode) return; FLAG_allow_natives_syntax = true; FLAG_always_opt = false; CcTest::InitializeVM(); @@ -842,5 +843,182 @@ TEST(DeepEagerCompilation) { } } +TEST(DeepEagerCompilationPeakMemory) { + i::FLAG_always_opt = false; + CcTest::InitializeVM(); + LocalContext env; + v8::HandleScope scope(CcTest::isolate()); + v8::Local<v8::String> source = v8_str( + "function f() {" + " function g1() {" + " function h1() {" + " function i1() {}" + " function i2() {}" + " }" + " function h2() {" + " function i1() {}" + " function i2() {}" + " }" + " }" + " function g2() {" + " function h1() {" + " function i1() {}" + " function i2() {}" + " }" + " function h2() {" + " function i1() {}" + " function i2() {}" + " }" + " }" + "}"); + v8::ScriptCompiler::Source script_source(source); + CcTest::i_isolate()->compilation_cache()->Disable(); + + v8::HeapStatistics heap_statistics; + CcTest::isolate()->GetHeapStatistics(&heap_statistics); + size_t peak_mem_1 = heap_statistics.peak_malloced_memory(); + printf("peak memory after init: %8zu\n", peak_mem_1); + + v8::ScriptCompiler::Compile(env.local(), &script_source, + v8::ScriptCompiler::kNoCompileOptions) + .ToLocalChecked(); + + CcTest::isolate()->GetHeapStatistics(&heap_statistics); + size_t peak_mem_2 = heap_statistics.peak_malloced_memory(); + printf("peak memory after lazy compile: %8zu\n", peak_mem_2); + + v8::ScriptCompiler::Compile(env.local(), &script_source, + v8::ScriptCompiler::kNoCompileOptions) + .ToLocalChecked(); + + CcTest::isolate()->GetHeapStatistics(&heap_statistics); + size_t peak_mem_3 = heap_statistics.peak_malloced_memory(); + printf("peak memory after lazy compile: %8zu\n", peak_mem_3); + + v8::ScriptCompiler::Compile(env.local(), &script_source, + v8::ScriptCompiler::kEagerCompile) + .ToLocalChecked(); + + CcTest::isolate()->GetHeapStatistics(&heap_statistics); + size_t peak_mem_4 = heap_statistics.peak_malloced_memory(); + printf("peak memory after eager compile: %8zu\n", peak_mem_4); + + CHECK_LE(peak_mem_1, peak_mem_2); + CHECK_EQ(peak_mem_2, peak_mem_3); + CHECK_LE(peak_mem_3, peak_mem_4); + // Check that eager compilation does not cause significantly higher (+100%) + // peak memory than lazy compilation. + CHECK_LE(peak_mem_4 - peak_mem_3, peak_mem_3); +} + +// TODO(mslekova): Remove the duplication with test-heap.cc +static int AllocationSitesCount(Heap* heap) { + int count = 0; + for (Object site = heap->allocation_sites_list(); site->IsAllocationSite();) { + AllocationSite cur = AllocationSite::cast(site); + CHECK(cur->HasWeakNext()); + site = cur->weak_next(); + count++; + } + return count; +} + +// This test simulates a specific race-condition if GC is triggered just +// before CompilationDependencies::Commit is finished, and this changes +// the pretenuring decision, thus causing a deoptimization. +TEST(DecideToPretenureDuringCompilation) { + // The test makes use of optimization and relies on deterministic + // compilation. + if (!i::FLAG_opt || i::FLAG_always_opt || + i::FLAG_stress_incremental_marking || i::FLAG_optimize_for_size +#ifdef ENABLE_MINOR_MC + || i::FLAG_minor_mc +#endif + ) + return; + + FLAG_stress_gc_during_compilation = true; + FLAG_allow_natives_syntax = true; + FLAG_allocation_site_pretenuring = true; + FLAG_flush_bytecode = false; + + // We want to trigger exactly 1 optimization. + FLAG_use_osr = false; + + // We'll do manual initialization. + ManualGCScope manual_gc_scope; + v8::Isolate::CreateParams create_params; + + // This setting ensures Heap::MaximumSizeScavenge will return `true`. + // We need to initialize the heap with at least 1 page, while keeping the + // limit low, to ensure the new space fills even on 32-bit architectures. + create_params.constraints.set_max_semi_space_size_in_kb(Page::kPageSize / + 1024); + create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + + isolate->Enter(); + { + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + Heap* heap = i_isolate->heap(); + GlobalHandles* global_handles = i_isolate->global_handles(); + HandleScope handle_scope(i_isolate); + + // The allocation site at the head of the list is ours. + Handle<AllocationSite> site; + { + LocalContext context(isolate); + v8::HandleScope scope(context->GetIsolate()); + + int count = AllocationSitesCount(heap); + CompileRun( + "let arr = [];" + "function foo(shouldKeep) {" + " let local_array = new Array();" + " if (shouldKeep) arr.push(local_array);" + "}" + "function bar(shouldKeep) {" + " for (let i = 0; i < 10000; i++) {" + " foo(shouldKeep);" + " }" + "}" + "bar();"); + + // This number should be >= kPretenureRatio * 10000, + // where 10000 is the number of iterations in `bar`, + // in order to make the ratio in DigestPretenuringFeedback close to 1. + const int memento_found_bump = 8500; + + // One allocation site should have been created. + int new_count = AllocationSitesCount(heap); + CHECK_EQ(new_count, (count + 1)); + site = Handle<AllocationSite>::cast(global_handles->Create( + AllocationSite::cast(heap->allocation_sites_list()))); + site->set_memento_found_count(memento_found_bump); + + CompileRun("%OptimizeFunctionOnNextCall(bar);"); + CompileRun("bar(true);"); + + // The last call should have caused `foo` to bail out of compilation + // due to dependency change (the pretenuring decision in this case). + // This will cause recompilation. + + // Check `bar` can get optimized again, meaning the compiler state is + // recoverable from this point. + CompileRun("%OptimizeFunctionOnNextCall(bar);"); + CompileRun("bar();"); + + Handle<Object> foo_obj = + JSReceiver::GetProperty(i_isolate, i_isolate->global_object(), "bar") + .ToHandleChecked(); + Handle<JSFunction> bar = Handle<JSFunction>::cast(foo_obj); + + CHECK(bar->IsOptimized()); + } + } + isolate->Exit(); + isolate->Dispose(); +} + } // namespace internal } // namespace v8 |