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 |