| OLD | NEW | 
|---|
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 
| 2 // | 2 // | 
| 3 // Tests of logging functions from log.h | 3 // Tests of logging functions from log.h | 
| 4 | 4 | 
| 5 #ifdef ENABLE_LOGGING_AND_PROFILING | 5 #ifdef ENABLE_LOGGING_AND_PROFILING | 
| 6 | 6 | 
| 7 #include "v8.h" | 7 #include "v8.h" | 
| 8 | 8 | 
| 9 #include "log.h" | 9 #include "log.h" | 
| 10 #include "cctest.h" | 10 #include "cctest.h" | 
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 124 static bool Consume(const char* str, char** buf) { | 124 static bool Consume(const char* str, char** buf) { | 
| 125   if (IsStringEqualTo(str, *buf)) { | 125   if (IsStringEqualTo(str, *buf)) { | 
| 126     *buf += strlen(str); | 126     *buf += strlen(str); | 
| 127     return true; | 127     return true; | 
| 128   } | 128   } | 
| 129   return false; | 129   return false; | 
| 130 } | 130 } | 
| 131 | 131 | 
| 132 | 132 | 
| 133 static void ParseAddress(char* start, Address* min_addr, Address* max_addr) { | 133 static void ParseAddress(char* start, Address* min_addr, Address* max_addr) { | 
| 134   Address addr = reinterpret_cast<Address>(strtoll(start, NULL, 16)); | 134   Address addr = reinterpret_cast<Address>(strtoul(start, NULL, 16));  // NOLINT | 
| 135   if (addr < *min_addr) *min_addr = addr; | 135   if (addr < *min_addr) *min_addr = addr; | 
| 136   if (addr > *max_addr) *max_addr = addr; | 136   if (addr > *max_addr) *max_addr = addr; | 
| 137 } | 137 } | 
| 138 | 138 | 
| 139 | 139 | 
| 140 static Address ConsumeAddress( | 140 static Address ConsumeAddress( | 
| 141     char** start, Address min_addr, Address max_addr) { | 141     char** start, Address min_addr, Address max_addr) { | 
| 142   char* end_ptr; | 142   char* end_ptr; | 
| 143   Address addr = reinterpret_cast<Address>(strtoll(*start, &end_ptr, 16)); | 143   Address addr = | 
|  | 144       reinterpret_cast<Address>(strtoul(*start, &end_ptr, 16));  // NOLINT | 
| 144   CHECK_GE(addr, min_addr); | 145   CHECK_GE(addr, min_addr); | 
| 145   CHECK_GE(max_addr, addr); | 146   CHECK_GE(max_addr, addr); | 
| 146   *start = end_ptr; | 147   *start = end_ptr; | 
| 147   return addr; | 148   return addr; | 
| 148 } | 149 } | 
| 149 | 150 | 
| 150 | 151 | 
| 151 namespace { | 152 namespace { | 
| 152 | 153 | 
| 153 // A code entity is a pointer to a position of code-creation event in buffer log | 154 // A code entity is a pointer to a position of code-creation event in buffer log | 
| 154 // offset to a point where entity size begins, i.e.: '255,"func"\n'. This makes | 155 // offset to a point where entity size begins, i.e.: '255,"func"\n'. This makes | 
| 155 // comparing code entities pretty easy. | 156 // comparing code entities pretty easy. | 
| 156 typedef char* CodeEntityInfo; | 157 typedef char* CodeEntityInfo; | 
| 157 | 158 | 
| 158 // A structure used to return log parsing results. | 159 // A structure used to return log parsing results. | 
| 159 class ParseLogResult { | 160 class ParseLogResult { | 
| 160  public: | 161  public: | 
| 161   ParseLogResult() | 162   ParseLogResult() | 
| 162       : min_addr(reinterpret_cast<Address>(-1)), | 163       : min_addr(reinterpret_cast<Address>(-1)), | 
| 163         max_addr(reinterpret_cast<Address>(0)), | 164         max_addr(reinterpret_cast<Address>(0)), | 
| 164         entities_map(NULL), entities(NULL), | 165         entities_map(NULL), entities(NULL), | 
| 165         max_entities(0) {}; | 166         max_entities(0) {} | 
| 166 | 167 | 
| 167   ~ParseLogResult() { | 168   ~ParseLogResult() { | 
| 168     // See allocation code below. | 169     // See allocation code below. | 
| 169     if (entities_map != NULL) { | 170     if (entities_map != NULL) { | 
| 170       i::DeleteArray(entities_map - 1); | 171       i::DeleteArray(entities_map - 1); | 
| 171     } | 172     } | 
| 172     i::DeleteArray(entities); | 173     i::DeleteArray(entities); | 
| 173   } | 174   } | 
| 174 | 175 | 
| 175   void AllocateEntities() { | 176   void AllocateEntities() { | 
| 176     // Make sure that the test doesn't operate on a bogus log. | 177     // Make sure that the test doesn't operate on a bogus log. | 
| 177     CHECK_GT(max_entities, 0); | 178     CHECK_GT(max_entities, 0); | 
| 178     CHECK_GT(min_addr, 0); | 179     CHECK_GT(min_addr, 0); | 
| 179     CHECK_GT(max_addr, min_addr); | 180     CHECK_GT(max_addr, min_addr); | 
| 180 | 181 | 
| 181     entities = i::NewArray<CodeEntityInfo>(max_entities); | 182     entities = i::NewArray<CodeEntityInfo>(max_entities); | 
| 182     for (int i = 0; i < max_entities; ++i) { | 183     for (int i = 0; i < max_entities; ++i) { | 
| 183       entities[i] = NULL; | 184       entities[i] = NULL; | 
| 184     } | 185     } | 
| 185     // We're adding fake items at [-1] and [size + 1] to simplify | 186     // We're adding fake items at [-1] and [size + 1] to simplify | 
| 186     // comparison code. | 187     // comparison code. | 
| 187     const int map_length = max_addr - min_addr + 1 + 2; // 2 fakes. | 188     const int map_length = max_addr - min_addr + 1 + 2;  // 2 fakes. | 
| 188     entities_map = i::NewArray<int>(map_length); | 189     entities_map = i::NewArray<int>(map_length); | 
| 189     for (int i = 0; i < map_length; ++i) { | 190     for (int i = 0; i < map_length; ++i) { | 
| 190       entities_map[i] = -1; | 191       entities_map[i] = -1; | 
| 191     } | 192     } | 
| 192     entities_map += 1; // Hide the -1 item, this is compensated on delete. | 193     entities_map += 1;  // Hide the -1 item, this is compensated on delete. | 
| 193   } | 194   } | 
| 194 | 195 | 
| 195   // Minimal code entity address. | 196   // Minimal code entity address. | 
| 196   Address min_addr; | 197   Address min_addr; | 
| 197   // Maximal code entity address. | 198   // Maximal code entity address. | 
| 198   Address max_addr; | 199   Address max_addr; | 
| 199   // Memory map of entities start addresses. Biased by min_addr. | 200   // Memory map of entities start addresses. Biased by min_addr. | 
| 200   int* entities_map; | 201   int* entities_map; | 
| 201   // An array of code entities. | 202   // An array of code entities. | 
| 202   CodeEntityInfo* entities; | 203   CodeEntityInfo* entities; | 
| 203   // Maximal entities count. Actual entities count can be lower, | 204   // Maximal entities count. Actual entities count can be lower, | 
| 204   // empty entity slots are pointing to NULL. | 205   // empty entity slots are pointing to NULL. | 
| 205   int max_entities; | 206   int max_entities; | 
| 206 }; | 207 }; | 
| 207 | 208 | 
| 208 } // namespace | 209 }  // namespace | 
| 209 | 210 | 
| 210 | 211 | 
| 211 typedef void (*ParserBlock)(char* start, char* end, ParseLogResult* result); | 212 typedef void (*ParserBlock)(char* start, char* end, ParseLogResult* result); | 
| 212 | 213 | 
| 213 static void ParserCycle( | 214 static void ParserCycle( | 
| 214     char* start, char* end, ParseLogResult* result, | 215     char* start, char* end, ParseLogResult* result, | 
| 215     ParserBlock block_creation, ParserBlock block_delete, | 216     ParserBlock block_creation, ParserBlock block_delete, | 
| 216     ParserBlock block_move) { | 217     ParserBlock block_move) { | 
| 217 | 218 | 
| 218   const char* code_creation = "code-creation,"; | 219   const char* code_creation = "code-creation,"; | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
| 249 | 250 | 
| 250 static void Pass1CodeDelete(char* start, char* end, ParseLogResult* result) { | 251 static void Pass1CodeDelete(char* start, char* end, ParseLogResult* result) { | 
| 251   ParseAddress(start, &result->min_addr, &result->max_addr); | 252   ParseAddress(start, &result->min_addr, &result->max_addr); | 
| 252 } | 253 } | 
| 253 | 254 | 
| 254 | 255 | 
| 255 static void Pass1CodeMove(char* start, char* end, ParseLogResult* result) { | 256 static void Pass1CodeMove(char* start, char* end, ParseLogResult* result) { | 
| 256   // Skip old address. | 257   // Skip old address. | 
| 257   while (start < end && *start != ',') ++start; | 258   while (start < end && *start != ',') ++start; | 
| 258   CHECK_GT(end, start); | 259   CHECK_GT(end, start); | 
| 259   ++start; // Skip ','. | 260   ++start;  // Skip ','. | 
| 260   ParseAddress(start, &result->min_addr, &result->max_addr); | 261   ParseAddress(start, &result->min_addr, &result->max_addr); | 
| 261 } | 262 } | 
| 262 | 263 | 
| 263 | 264 | 
| 264 static void Pass2CodeCreation(char* start, char* end, ParseLogResult* result) { | 265 static void Pass2CodeCreation(char* start, char* end, ParseLogResult* result) { | 
| 265   Address addr = ConsumeAddress(&start, result->min_addr, result->max_addr); | 266   Address addr = ConsumeAddress(&start, result->min_addr, result->max_addr); | 
| 266   CHECK_GT(end, start); | 267   CHECK_GT(end, start); | 
| 267   ++start; // Skip ','. | 268   ++start;  // Skip ','. | 
| 268 | 269 | 
| 269   int idx = addr - result->min_addr; | 270   int idx = addr - result->min_addr; | 
| 270   result->entities_map[idx] = -1; | 271   result->entities_map[idx] = -1; | 
| 271   for (int i = 0; i < result->max_entities; ++i) { | 272   for (int i = 0; i < result->max_entities; ++i) { | 
| 272     // Find an empty slot and fill it. | 273     // Find an empty slot and fill it. | 
| 273     if (result->entities[i] == NULL) { | 274     if (result->entities[i] == NULL) { | 
| 274       result->entities[i] = start; | 275       result->entities[i] = start; | 
| 275       result->entities_map[idx] = i; | 276       result->entities_map[idx] = i; | 
| 276       break; | 277       break; | 
| 277     } | 278     } | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 289     result->entities[result->entities_map[idx]] = NULL; | 290     result->entities[result->entities_map[idx]] = NULL; | 
| 290     result->entities_map[idx] = -1; | 291     result->entities_map[idx] = -1; | 
| 291   } | 292   } | 
| 292 } | 293 } | 
| 293 | 294 | 
| 294 | 295 | 
| 295 static void Pass2CodeMove(char* start, char* end, ParseLogResult* result) { | 296 static void Pass2CodeMove(char* start, char* end, ParseLogResult* result) { | 
| 296   Address from_addr = ConsumeAddress( | 297   Address from_addr = ConsumeAddress( | 
| 297       &start, result->min_addr, result->max_addr); | 298       &start, result->min_addr, result->max_addr); | 
| 298   CHECK_GT(end, start); | 299   CHECK_GT(end, start); | 
| 299   ++start; // Skip ','. | 300   ++start;  // Skip ','. | 
| 300   Address to_addr = ConsumeAddress(&start, result->min_addr, result->max_addr); | 301   Address to_addr = ConsumeAddress(&start, result->min_addr, result->max_addr); | 
| 301   CHECK_GT(end, start); | 302   CHECK_GT(end, start); | 
| 302 | 303 | 
| 303   int from_idx = from_addr - result->min_addr; | 304   int from_idx = from_addr - result->min_addr; | 
| 304   int to_idx = to_addr - result->min_addr; | 305   int to_idx = to_addr - result->min_addr; | 
| 305   // There can be code moves that are not related to JS code. | 306   // There can be code moves that are not related to JS code. | 
| 306   if (from_idx != to_idx && result->entities_map[from_idx] >= 0) { | 307   if (from_idx != to_idx && result->entities_map[from_idx] >= 0) { | 
| 307     CHECK_EQ(-1, result->entities_map[to_idx]); | 308     CHECK_EQ(-1, result->entities_map[to_idx]); | 
| 308     result->entities_map[to_idx] = result->entities_map[from_idx]; | 309     result->entities_map[to_idx] = result->entities_map[from_idx]; | 
| 309     result->entities_map[from_idx] = -1; | 310     result->entities_map[from_idx] = -1; | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 370   int new_len = StrChrLen(new_s, '\n'); | 371   int new_len = StrChrLen(new_s, '\n'); | 
| 371   // If reference is anonymous (""), it's OK to have anything in new. | 372   // If reference is anonymous (""), it's OK to have anything in new. | 
| 372   if (ref_len == 2) return true; | 373   if (ref_len == 2) return true; | 
| 373   // A special case for ErrorPrototype. Haven't yet figured out why they | 374   // A special case for ErrorPrototype. Haven't yet figured out why they | 
| 374   // are different. | 375   // are different. | 
| 375   const char* error_prototype = "\"ErrorPrototype"; | 376   const char* error_prototype = "\"ErrorPrototype"; | 
| 376   if (IsStringEqualTo(error_prototype, ref_s) | 377   if (IsStringEqualTo(error_prototype, ref_s) | 
| 377       && IsStringEqualTo(error_prototype, new_s)) { | 378       && IsStringEqualTo(error_prototype, new_s)) { | 
| 378     return true; | 379     return true; | 
| 379   } | 380   } | 
|  | 381   // Built-in objects have problems too. | 
|  | 382   const char* built_ins[] = { | 
|  | 383       "\"Boolean\"", "\"Function\"", "\"Number\"", | 
|  | 384       "\"Object\"", "\"Script\"", "\"String\"" | 
|  | 385   }; | 
|  | 386   for (size_t i = 0; i < sizeof(built_ins) / sizeof(*built_ins); ++i) { | 
|  | 387     if (IsStringEqualTo(built_ins[i], new_s)) { | 
|  | 388       return true; | 
|  | 389     } | 
|  | 390   } | 
| 380   return ref_len == new_len && strncmp(ref_s, new_s, ref_len) == 0; | 391   return ref_len == new_len && strncmp(ref_s, new_s, ref_len) == 0; | 
| 381 } | 392 } | 
| 382 | 393 | 
| 383 | 394 | 
| 384 static bool AreEntitiesEqual(CodeEntityInfo ref_e, CodeEntityInfo new_e) { | 395 static bool AreEntitiesEqual(CodeEntityInfo ref_e, CodeEntityInfo new_e) { | 
| 385   if (ref_e == NULL && new_e != NULL) return true; | 396   if (ref_e == NULL && new_e != NULL) return true; | 
| 386   if (ref_e != NULL && new_e != NULL) { | 397   if (ref_e != NULL && new_e != NULL) { | 
| 387     return AreFuncSizesEqual(ref_e, new_e) && AreFuncNamesEqual(ref_e, new_e); | 398     return AreFuncSizesEqual(ref_e, new_e) && AreFuncNamesEqual(ref_e, new_e); | 
| 388   } | 399   } | 
| 389   if (ref_e != NULL && new_e == NULL) { | 400   if (ref_e != NULL && new_e == NULL) { | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
| 403   i::FLAG_logfile = "*"; | 414   i::FLAG_logfile = "*"; | 
| 404   i::FLAG_log = true; | 415   i::FLAG_log = true; | 
| 405   i::FLAG_log_code = true; | 416   i::FLAG_log_code = true; | 
| 406 | 417 | 
| 407   // Make sure objects move. | 418   // Make sure objects move. | 
| 408   bool saved_always_compact = i::FLAG_always_compact; | 419   bool saved_always_compact = i::FLAG_always_compact; | 
| 409   if (!i::FLAG_never_compact) { | 420   if (!i::FLAG_never_compact) { | 
| 410     i::FLAG_always_compact = true; | 421     i::FLAG_always_compact = true; | 
| 411   } | 422   } | 
| 412 | 423 | 
| 413   v8::Persistent<v8::Context> env = v8::Context::New(); |  | 
| 414   v8::HandleScope scope; | 424   v8::HandleScope scope; | 
|  | 425   v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>(); | 
|  | 426   v8::Persistent<v8::Context> env = v8::Context::New( | 
|  | 427       0, v8::Handle<v8::ObjectTemplate>(), global_object); | 
| 415   env->Enter(); | 428   env->Enter(); | 
| 416 | 429 | 
| 417   // Compile and run a function that creates other functions. | 430   // Compile and run a function that creates other functions. | 
| 418   v8::Script::Compile(v8::String::New( | 431   v8::Local<v8::Script> script = v8::Script::Compile(v8::String::New( | 
| 419       "(function f() {\n" | 432       "(function f(obj) {\n" | 
| 420       "  var rets = [];\n" | 433       "  obj.test =\n" | 
| 421       "  for (var i = 0; i < 100; ++i) {\n" | 434       "    (function a(j) { return function b() { return j; } })(100);\n" | 
| 422       "    rets.push((function inc(n) { return n + 1; })(i));\n" | 435       "})(this);")); | 
| 423       "  }\n" | 436   script->Run(); | 
| 424       "})();"))->Run(); |  | 
| 425   i::Heap::CollectAllGarbage(); | 437   i::Heap::CollectAllGarbage(); | 
| 426 | 438 | 
| 427   i::EmbeddedVector<char,204800> buffer; | 439   i::EmbeddedVector<char, 204800> buffer; | 
| 428   int log_size; | 440   int log_size; | 
| 429   ParseLogResult ref_result; | 441   ParseLogResult ref_result; | 
| 430 | 442 | 
| 431   // Retrieve the log. | 443   // Retrieve the log. | 
| 432   { | 444   { | 
| 433     // Make sure that no GCs occur prior to LogCompiledFunctions call. | 445     // Make sure that no GCs occur prior to LogCompiledFunctions call. | 
| 434     i::AssertNoAllocation no_alloc; | 446     i::AssertNoAllocation no_alloc; | 
| 435 | 447 | 
| 436     log_size = Logger::GetLogLines(0, buffer.start(), buffer.length()); | 448     log_size = Logger::GetLogLines(0, buffer.start(), buffer.length()); | 
| 437     CHECK_GT(log_size, 0); | 449     CHECK_GT(log_size, 0); | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 470           new_item != -1 ? new_result.entities[new_item] : NULL; | 482           new_item != -1 ? new_result.entities[new_item] : NULL; | 
| 471       const bool equal = AreEntitiesEqual(ref_entity, new_entity); | 483       const bool equal = AreEntitiesEqual(ref_entity, new_entity); | 
| 472       if (!equal) results_equal = false; | 484       if (!equal) results_equal = false; | 
| 473       PrintCodeEntitiesInfo( | 485       PrintCodeEntitiesInfo( | 
| 474           equal, ref_inc != 0 ? ref_addr : new_addr, | 486           equal, ref_inc != 0 ? ref_addr : new_addr, | 
| 475           ref_entity, new_entity); | 487           ref_entity, new_entity); | 
| 476     } | 488     } | 
| 477     ref_idx += ref_inc; | 489     ref_idx += ref_inc; | 
| 478     new_idx += new_inc; | 490     new_idx += new_inc; | 
| 479   } | 491   } | 
|  | 492   // Make sure that all log data is written prior crash due to CHECK failure. | 
|  | 493   fflush(stdout); | 
| 480   CHECK(results_equal); | 494   CHECK(results_equal); | 
| 481 | 495 | 
| 482   env->Exit(); | 496   env->Exit(); | 
| 483   v8::V8::Dispose(); | 497   v8::V8::Dispose(); | 
| 484   i::FLAG_always_compact = saved_always_compact; | 498   i::FLAG_always_compact = saved_always_compact; | 
| 485 } | 499 } | 
| 486 | 500 | 
| 487 | 501 | 
| 488 #endif  // ENABLE_LOGGING_AND_PROFILING | 502 #endif  // ENABLE_LOGGING_AND_PROFILING | 
| OLD | NEW | 
|---|