Index: test/cctest/test-api.cc |
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc |
index 1b6359b40d09670145639d0946d27db33bd0bf2a..319164c71e051229e4b71883f6a447cd8ca47b42 100644 |
--- a/test/cctest/test-api.cc |
+++ b/test/cctest/test-api.cc |
@@ -8059,7 +8059,7 @@ static int GetGlobalObjectsCount() { |
} |
-static int GetSurvivingGlobalObjectsCount() { |
+static void CheckSurvivingGlobalObjectsCount(int expected) { |
// We need to collect all garbage twice to be sure that everything |
// has been collected. This is because inline caches are cleared in |
// the first garbage collection but some of the maps have already |
@@ -8069,9 +8069,9 @@ static int GetSurvivingGlobalObjectsCount() { |
i::Heap::CollectAllGarbage(false); |
int count = GetGlobalObjectsCount(); |
#ifdef DEBUG |
- if (count > 0) i::Heap::TracePathToGlobal(); |
+ if (count != expected) i::Heap::TracePathToGlobal(); |
#endif |
- return count; |
+ CHECK_EQ(expected, count); |
} |
@@ -8080,25 +8080,23 @@ TEST(DontLeakGlobalObjects) { |
v8::V8::Initialize(); |
- int count = GetSurvivingGlobalObjectsCount(); |
- |
for (int i = 0; i < 5; i++) { |
{ v8::HandleScope scope; |
LocalContext context; |
} |
- CHECK_EQ(count, GetSurvivingGlobalObjectsCount()); |
+ CheckSurvivingGlobalObjectsCount(0); |
{ v8::HandleScope scope; |
LocalContext context; |
v8_compile("Date")->Run(); |
} |
- CHECK_EQ(count, GetSurvivingGlobalObjectsCount()); |
+ CheckSurvivingGlobalObjectsCount(0); |
{ v8::HandleScope scope; |
LocalContext context; |
v8_compile("/aaa/")->Run(); |
} |
- CHECK_EQ(count, GetSurvivingGlobalObjectsCount()); |
+ CheckSurvivingGlobalObjectsCount(0); |
{ v8::HandleScope scope; |
const char* extension_list[] = { "v8/gc" }; |
@@ -8106,7 +8104,7 @@ TEST(DontLeakGlobalObjects) { |
LocalContext context(&extensions); |
v8_compile("gc();")->Run(); |
} |
- CHECK_EQ(count, GetSurvivingGlobalObjectsCount()); |
+ CheckSurvivingGlobalObjectsCount(0); |
} |
} |
@@ -11443,3 +11441,141 @@ TEST(BooleanCheckMultipleContexts) { |
ExpectString(code, ""); |
} |
} |
+ |
+ |
+TEST(DontDeleteCellLoadIC) { |
+ const char* function_code = |
+ "function readCell() { while (true) { return cell; } }"; |
+ |
+ { |
+ // Run the code twice in the first context to initialize the load |
+ // IC for a don't delete cell. |
+ v8::HandleScope scope; |
+ LocalContext context1; |
+ CompileRun("var cell = \"first\";"); |
+ ExpectBoolean("delete cell", false); |
+ CompileRun(function_code); |
+ ExpectString("readCell()", "first"); |
+ ExpectString("readCell()", "first"); |
+ } |
+ |
+ { |
+ // Use a deletable cell in the second context. |
+ v8::HandleScope scope; |
+ LocalContext context2; |
+ CompileRun("cell = \"second\";"); |
+ CompileRun(function_code); |
+ ExpectString("readCell()", "second"); |
+ ExpectBoolean("delete cell", true); |
+ ExpectString("(function() {" |
+ " try {" |
+ " return readCell();" |
+ " } catch(e) {" |
+ " return e.toString();" |
+ " }" |
+ "})()", |
+ "ReferenceError: cell is not defined"); |
+ CompileRun("cell = \"new_second\";"); |
+ i::Heap::CollectAllGarbage(true); |
+ ExpectString("readCell()", "new_second"); |
+ ExpectString("readCell()", "new_second"); |
+ } |
+} |
+ |
+ |
+TEST(DontDeleteCellLoadICForceDelete) { |
+ const char* function_code = |
+ "function readCell() { while (true) { return cell; } }"; |
+ |
+ // Run the code twice to initialize the load IC for a don't delete |
+ // cell. |
+ v8::HandleScope scope; |
+ LocalContext context; |
+ CompileRun("var cell = \"value\";"); |
+ ExpectBoolean("delete cell", false); |
+ CompileRun(function_code); |
+ ExpectString("readCell()", "value"); |
+ ExpectString("readCell()", "value"); |
+ |
+ // Delete the cell using the API and check the inlined code works |
+ // correctly. |
+ CHECK(context->Global()->ForceDelete(v8_str("cell"))); |
+ ExpectString("(function() {" |
+ " try {" |
+ " return readCell();" |
+ " } catch(e) {" |
+ " return e.toString();" |
+ " }" |
+ "})()", |
+ "ReferenceError: cell is not defined"); |
+} |
+ |
+ |
+TEST(DontDeleteCellLoadICAPI) { |
+ const char* function_code = |
+ "function readCell() { while (true) { return cell; } }"; |
+ |
+ // Run the code twice to initialize the load IC for a don't delete |
+ // cell created using the API. |
+ v8::HandleScope scope; |
+ LocalContext context; |
+ context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete); |
+ ExpectBoolean("delete cell", false); |
+ CompileRun(function_code); |
+ ExpectString("readCell()", "value"); |
+ ExpectString("readCell()", "value"); |
+ |
+ // Delete the cell using the API and check the inlined code works |
+ // correctly. |
+ CHECK(context->Global()->ForceDelete(v8_str("cell"))); |
+ ExpectString("(function() {" |
+ " try {" |
+ " return readCell();" |
+ " } catch(e) {" |
+ " return e.toString();" |
+ " }" |
+ "})()", |
+ "ReferenceError: cell is not defined"); |
+} |
+ |
+ |
+TEST(GlobalLoadICGC) { |
+ const char* function_code = |
+ "function readCell() { while (true) { return cell; } }"; |
+ |
+ // Check inline load code for a don't delete cell is cleared during |
+ // GC. |
+ { |
+ v8::HandleScope scope; |
+ LocalContext context; |
+ CompileRun("var cell = \"value\";"); |
+ ExpectBoolean("delete cell", false); |
+ CompileRun(function_code); |
+ ExpectString("readCell()", "value"); |
+ ExpectString("readCell()", "value"); |
+ } |
+ { |
+ v8::HandleScope scope; |
+ LocalContext context2; |
+ // Hold the code object in the second context. |
+ CompileRun(function_code); |
+ CheckSurvivingGlobalObjectsCount(1); |
+ } |
+ |
+ // Check inline load code for a deletable cell is cleared during GC. |
+ { |
+ v8::HandleScope scope; |
+ LocalContext context; |
+ CompileRun("cell = \"value\";"); |
+ CompileRun(function_code); |
+ ExpectString("readCell()", "value"); |
+ ExpectString("readCell()", "value"); |
+ } |
+ { |
+ v8::HandleScope scope; |
+ LocalContext context2; |
+ // Hold the code object in the second context. |
+ CompileRun(function_code); |
+ CheckSurvivingGlobalObjectsCount(1); |
+ } |
+} |