OLD | NEW |
1 // Copyright 2007-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2007-2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 8041 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8052 | 8052 |
8053 static int GetGlobalObjectsCount() { | 8053 static int GetGlobalObjectsCount() { |
8054 int count = 0; | 8054 int count = 0; |
8055 i::HeapIterator it; | 8055 i::HeapIterator it; |
8056 for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) | 8056 for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) |
8057 if (object->IsJSGlobalObject()) count++; | 8057 if (object->IsJSGlobalObject()) count++; |
8058 return count; | 8058 return count; |
8059 } | 8059 } |
8060 | 8060 |
8061 | 8061 |
8062 static int GetSurvivingGlobalObjectsCount() { | 8062 static void CheckSurvivingGlobalObjectsCount(int expected) { |
8063 // We need to collect all garbage twice to be sure that everything | 8063 // We need to collect all garbage twice to be sure that everything |
8064 // has been collected. This is because inline caches are cleared in | 8064 // has been collected. This is because inline caches are cleared in |
8065 // the first garbage collection but some of the maps have already | 8065 // the first garbage collection but some of the maps have already |
8066 // been marked at that point. Therefore some of the maps are not | 8066 // been marked at that point. Therefore some of the maps are not |
8067 // collected until the second garbage collection. | 8067 // collected until the second garbage collection. |
8068 i::Heap::CollectAllGarbage(false); | 8068 i::Heap::CollectAllGarbage(false); |
8069 i::Heap::CollectAllGarbage(false); | 8069 i::Heap::CollectAllGarbage(false); |
8070 int count = GetGlobalObjectsCount(); | 8070 int count = GetGlobalObjectsCount(); |
8071 #ifdef DEBUG | 8071 #ifdef DEBUG |
8072 if (count > 0) i::Heap::TracePathToGlobal(); | 8072 if (count != expected) i::Heap::TracePathToGlobal(); |
8073 #endif | 8073 #endif |
8074 return count; | 8074 CHECK_EQ(expected, count); |
8075 } | 8075 } |
8076 | 8076 |
8077 | 8077 |
8078 TEST(DontLeakGlobalObjects) { | 8078 TEST(DontLeakGlobalObjects) { |
8079 // Regression test for issues 1139850 and 1174891. | 8079 // Regression test for issues 1139850 and 1174891. |
8080 | 8080 |
8081 v8::V8::Initialize(); | 8081 v8::V8::Initialize(); |
8082 | 8082 |
8083 int count = GetSurvivingGlobalObjectsCount(); | |
8084 | |
8085 for (int i = 0; i < 5; i++) { | 8083 for (int i = 0; i < 5; i++) { |
8086 { v8::HandleScope scope; | 8084 { v8::HandleScope scope; |
8087 LocalContext context; | 8085 LocalContext context; |
8088 } | 8086 } |
8089 CHECK_EQ(count, GetSurvivingGlobalObjectsCount()); | 8087 CheckSurvivingGlobalObjectsCount(0); |
8090 | 8088 |
8091 { v8::HandleScope scope; | 8089 { v8::HandleScope scope; |
8092 LocalContext context; | 8090 LocalContext context; |
8093 v8_compile("Date")->Run(); | 8091 v8_compile("Date")->Run(); |
8094 } | 8092 } |
8095 CHECK_EQ(count, GetSurvivingGlobalObjectsCount()); | 8093 CheckSurvivingGlobalObjectsCount(0); |
8096 | 8094 |
8097 { v8::HandleScope scope; | 8095 { v8::HandleScope scope; |
8098 LocalContext context; | 8096 LocalContext context; |
8099 v8_compile("/aaa/")->Run(); | 8097 v8_compile("/aaa/")->Run(); |
8100 } | 8098 } |
8101 CHECK_EQ(count, GetSurvivingGlobalObjectsCount()); | 8099 CheckSurvivingGlobalObjectsCount(0); |
8102 | 8100 |
8103 { v8::HandleScope scope; | 8101 { v8::HandleScope scope; |
8104 const char* extension_list[] = { "v8/gc" }; | 8102 const char* extension_list[] = { "v8/gc" }; |
8105 v8::ExtensionConfiguration extensions(1, extension_list); | 8103 v8::ExtensionConfiguration extensions(1, extension_list); |
8106 LocalContext context(&extensions); | 8104 LocalContext context(&extensions); |
8107 v8_compile("gc();")->Run(); | 8105 v8_compile("gc();")->Run(); |
8108 } | 8106 } |
8109 CHECK_EQ(count, GetSurvivingGlobalObjectsCount()); | 8107 CheckSurvivingGlobalObjectsCount(0); |
8110 } | 8108 } |
8111 } | 8109 } |
8112 | 8110 |
8113 | 8111 |
8114 v8::Persistent<v8::Object> some_object; | 8112 v8::Persistent<v8::Object> some_object; |
8115 v8::Persistent<v8::Object> bad_handle; | 8113 v8::Persistent<v8::Object> bad_handle; |
8116 | 8114 |
8117 void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) { | 8115 void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) { |
8118 v8::HandleScope scope; | 8116 v8::HandleScope scope; |
8119 bad_handle = v8::Persistent<v8::Object>::New(some_object); | 8117 bad_handle = v8::Persistent<v8::Object>::New(some_object); |
(...skipping 3316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11436 | 11434 |
11437 { | 11435 { |
11438 // Change the Boolean.prototype in the second context and check | 11436 // Change the Boolean.prototype in the second context and check |
11439 // that the right function gets called. | 11437 // that the right function gets called. |
11440 v8::HandleScope scope; | 11438 v8::HandleScope scope; |
11441 LocalContext context2; | 11439 LocalContext context2; |
11442 CompileRun("Boolean.prototype.toString = function() { return \"\"; }"); | 11440 CompileRun("Boolean.prototype.toString = function() { return \"\"; }"); |
11443 ExpectString(code, ""); | 11441 ExpectString(code, ""); |
11444 } | 11442 } |
11445 } | 11443 } |
| 11444 |
| 11445 |
| 11446 TEST(DontDeleteCellLoadIC) { |
| 11447 const char* function_code = |
| 11448 "function readCell() { while (true) { return cell; } }"; |
| 11449 |
| 11450 { |
| 11451 // Run the code twice in the first context to initialize the load |
| 11452 // IC for a don't delete cell. |
| 11453 v8::HandleScope scope; |
| 11454 LocalContext context1; |
| 11455 CompileRun("var cell = \"first\";"); |
| 11456 ExpectBoolean("delete cell", false); |
| 11457 CompileRun(function_code); |
| 11458 ExpectString("readCell()", "first"); |
| 11459 ExpectString("readCell()", "first"); |
| 11460 } |
| 11461 |
| 11462 { |
| 11463 // Use a deletable cell in the second context. |
| 11464 v8::HandleScope scope; |
| 11465 LocalContext context2; |
| 11466 CompileRun("cell = \"second\";"); |
| 11467 CompileRun(function_code); |
| 11468 ExpectString("readCell()", "second"); |
| 11469 ExpectBoolean("delete cell", true); |
| 11470 ExpectString("(function() {" |
| 11471 " try {" |
| 11472 " return readCell();" |
| 11473 " } catch(e) {" |
| 11474 " return e.toString();" |
| 11475 " }" |
| 11476 "})()", |
| 11477 "ReferenceError: cell is not defined"); |
| 11478 CompileRun("cell = \"new_second\";"); |
| 11479 i::Heap::CollectAllGarbage(true); |
| 11480 ExpectString("readCell()", "new_second"); |
| 11481 ExpectString("readCell()", "new_second"); |
| 11482 } |
| 11483 } |
| 11484 |
| 11485 |
| 11486 TEST(DontDeleteCellLoadICForceDelete) { |
| 11487 const char* function_code = |
| 11488 "function readCell() { while (true) { return cell; } }"; |
| 11489 |
| 11490 // Run the code twice to initialize the load IC for a don't delete |
| 11491 // cell. |
| 11492 v8::HandleScope scope; |
| 11493 LocalContext context; |
| 11494 CompileRun("var cell = \"value\";"); |
| 11495 ExpectBoolean("delete cell", false); |
| 11496 CompileRun(function_code); |
| 11497 ExpectString("readCell()", "value"); |
| 11498 ExpectString("readCell()", "value"); |
| 11499 |
| 11500 // Delete the cell using the API and check the inlined code works |
| 11501 // correctly. |
| 11502 CHECK(context->Global()->ForceDelete(v8_str("cell"))); |
| 11503 ExpectString("(function() {" |
| 11504 " try {" |
| 11505 " return readCell();" |
| 11506 " } catch(e) {" |
| 11507 " return e.toString();" |
| 11508 " }" |
| 11509 "})()", |
| 11510 "ReferenceError: cell is not defined"); |
| 11511 } |
| 11512 |
| 11513 |
| 11514 TEST(DontDeleteCellLoadICAPI) { |
| 11515 const char* function_code = |
| 11516 "function readCell() { while (true) { return cell; } }"; |
| 11517 |
| 11518 // Run the code twice to initialize the load IC for a don't delete |
| 11519 // cell created using the API. |
| 11520 v8::HandleScope scope; |
| 11521 LocalContext context; |
| 11522 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete); |
| 11523 ExpectBoolean("delete cell", false); |
| 11524 CompileRun(function_code); |
| 11525 ExpectString("readCell()", "value"); |
| 11526 ExpectString("readCell()", "value"); |
| 11527 |
| 11528 // Delete the cell using the API and check the inlined code works |
| 11529 // correctly. |
| 11530 CHECK(context->Global()->ForceDelete(v8_str("cell"))); |
| 11531 ExpectString("(function() {" |
| 11532 " try {" |
| 11533 " return readCell();" |
| 11534 " } catch(e) {" |
| 11535 " return e.toString();" |
| 11536 " }" |
| 11537 "})()", |
| 11538 "ReferenceError: cell is not defined"); |
| 11539 } |
| 11540 |
| 11541 |
| 11542 TEST(GlobalLoadICGC) { |
| 11543 const char* function_code = |
| 11544 "function readCell() { while (true) { return cell; } }"; |
| 11545 |
| 11546 // Check inline load code for a don't delete cell is cleared during |
| 11547 // GC. |
| 11548 { |
| 11549 v8::HandleScope scope; |
| 11550 LocalContext context; |
| 11551 CompileRun("var cell = \"value\";"); |
| 11552 ExpectBoolean("delete cell", false); |
| 11553 CompileRun(function_code); |
| 11554 ExpectString("readCell()", "value"); |
| 11555 ExpectString("readCell()", "value"); |
| 11556 } |
| 11557 { |
| 11558 v8::HandleScope scope; |
| 11559 LocalContext context2; |
| 11560 // Hold the code object in the second context. |
| 11561 CompileRun(function_code); |
| 11562 CheckSurvivingGlobalObjectsCount(1); |
| 11563 } |
| 11564 |
| 11565 // Check inline load code for a deletable cell is cleared during GC. |
| 11566 { |
| 11567 v8::HandleScope scope; |
| 11568 LocalContext context; |
| 11569 CompileRun("cell = \"value\";"); |
| 11570 CompileRun(function_code); |
| 11571 ExpectString("readCell()", "value"); |
| 11572 ExpectString("readCell()", "value"); |
| 11573 } |
| 11574 { |
| 11575 v8::HandleScope scope; |
| 11576 LocalContext context2; |
| 11577 // Hold the code object in the second context. |
| 11578 CompileRun(function_code); |
| 11579 CheckSurvivingGlobalObjectsCount(1); |
| 11580 } |
| 11581 } |
OLD | NEW |