summaryrefslogtreecommitdiff
path: root/deps/v8/test/cctest/test-compiler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/cctest/test-compiler.cc')
-rw-r--r--deps/v8/test/cctest/test-compiler.cc218
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