Line data Source code
1 : // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 : // Redistribution and use in source and binary forms, with or without
3 : // modification, are permitted provided that the following conditions are
4 : // met:
5 : //
6 : // * Redistributions of source code must retain the above copyright
7 : // notice, this list of conditions and the following disclaimer.
8 : // * Redistributions in binary form must reproduce the above
9 : // copyright notice, this list of conditions and the following
10 : // disclaimer in the documentation and/or other materials provided
11 : // with the distribution.
12 : // * Neither the name of Google Inc. nor the names of its
13 : // contributors may be used to endorse or promote products derived
14 : // from this software without specific prior written permission.
15 : //
16 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : //
28 : // Tests of logging functions from log.h
29 :
30 : #ifdef __linux__
31 : #include <pthread.h>
32 : #include <signal.h>
33 : #include <unistd.h>
34 : #include <cmath>
35 : #endif // __linux__
36 :
37 : #include "src/api.h"
38 : #include "src/log-utils.h"
39 : #include "src/log.h"
40 : #include "src/objects-inl.h"
41 : #include "src/profiler/cpu-profiler.h"
42 : #include "src/snapshot/natives.h"
43 : #include "src/utils.h"
44 : #include "src/v8.h"
45 : #include "src/v8threads.h"
46 : #include "src/version.h"
47 : #include "src/vm-state-inl.h"
48 : #include "test/cctest/cctest.h"
49 :
50 : using v8::internal::Address;
51 : using v8::internal::EmbeddedVector;
52 : using v8::internal::Logger;
53 : using v8::internal::StrLength;
54 :
55 : namespace {
56 :
57 :
58 : #define SETUP_FLAGS() \
59 : bool saved_log = i::FLAG_log; \
60 : bool saved_prof = i::FLAG_prof; \
61 : i::FLAG_log = true; \
62 : i::FLAG_prof = true; \
63 : i::FLAG_logfile = i::Log::kLogToTemporaryFile; \
64 : i::FLAG_logfile_per_isolate = false
65 :
66 6895 : static const char* StrNStr(const char* s1, const char* s2, size_t n) {
67 6895 : CHECK_EQ(s1[n], '\0');
68 6895 : return strstr(s1, s2);
69 : }
70 :
71 : // Look for a log line which starts with {prefix} and ends with {suffix}.
72 70 : static const char* FindLogLine(i::Vector<const char>* log, const char* prefix,
73 : const char* suffix) {
74 : const char* start = log->start();
75 70 : const char* end = start + log->length();
76 70 : CHECK_EQ(end[0], '\0');
77 70 : size_t prefixLength = strlen(prefix);
78 : // Loop through the input until we find /{prefix}[^\n]+{suffix}/.
79 2385 : while (start < end) {
80 2315 : const char* prefixResult = StrNStr(start, prefix, (end - start));
81 2315 : if (!prefixResult) return NULL;
82 : const char* suffixResult =
83 2295 : StrNStr(prefixResult, suffix, (end - prefixResult));
84 2295 : if (!suffixResult) return NULL;
85 : // Check that there are no newlines in between the {prefix} and the {suffix}
86 : // results.
87 : const char* newlineResult =
88 2285 : StrNStr(prefixResult, "\n", (end - prefixResult));
89 2285 : if (!newlineResult) return prefixResult;
90 2280 : if (newlineResult > suffixResult) return prefixResult;
91 2245 : start = prefixResult + prefixLength;
92 : }
93 : return NULL;
94 : }
95 :
96 : class ScopedLoggerInitializer {
97 : public:
98 42 : ScopedLoggerInitializer(bool saved_log, bool saved_prof, v8::Isolate* isolate)
99 : : saved_log_(saved_log),
100 : saved_prof_(saved_prof),
101 : temp_file_(nullptr),
102 : isolate_(isolate),
103 : isolate_scope_(isolate),
104 : scope_(isolate),
105 21 : env_(v8::Context::New(isolate)),
106 84 : logger_(reinterpret_cast<i::Isolate*>(isolate)->logger()) {
107 21 : env_->Enter();
108 21 : }
109 :
110 42 : ~ScopedLoggerInitializer() {
111 21 : env_->Exit();
112 21 : logger_->TearDown();
113 21 : if (temp_file_ != nullptr) fclose(temp_file_);
114 21 : i::FLAG_prof = saved_prof_;
115 21 : i::FLAG_log = saved_log_;
116 : log_.Dispose();
117 21 : }
118 :
119 : v8::Local<v8::Context>& env() { return env_; }
120 :
121 : v8::Isolate* isolate() { return isolate_; }
122 :
123 : Logger* logger() { return logger_; }
124 :
125 1 : v8::Local<v8::String> GetLogString() {
126 : return v8::String::NewFromUtf8(isolate_, log_.start(),
127 2 : v8::NewStringType::kNormal, log_.length())
128 2 : .ToLocalChecked();
129 : }
130 :
131 32 : void StopLogging() {
132 16 : bool exists = false;
133 16 : log_ = i::ReadFile(StopLoggingGetTempFile(), &exists, true);
134 16 : CHECK(exists);
135 16 : }
136 :
137 : const char* FindLine(const char* prefix, const char* suffix) {
138 25 : return FindLogLine(&log_, prefix, suffix);
139 : }
140 :
141 11 : void LogCompiledFunctions() { logger_->LogCompiledFunctions(); }
142 :
143 : void StringEvent(const char* name, const char* value) {
144 2 : logger_->StringEvent(name, value);
145 : }
146 :
147 : private:
148 16 : FILE* StopLoggingGetTempFile() {
149 16 : temp_file_ = logger_->TearDown();
150 16 : CHECK(temp_file_);
151 16 : fflush(temp_file_);
152 16 : rewind(temp_file_);
153 16 : return temp_file_;
154 : }
155 :
156 : const bool saved_log_;
157 : const bool saved_prof_;
158 : FILE* temp_file_;
159 : v8::Isolate* isolate_;
160 : v8::Isolate::Scope isolate_scope_;
161 : v8::HandleScope scope_;
162 : v8::Local<v8::Context> env_;
163 : Logger* logger_;
164 : i::Vector<const char> log_;
165 :
166 : DISALLOW_COPY_AND_ASSIGN(ScopedLoggerInitializer);
167 : };
168 :
169 : } // namespace
170 :
171 23723 : TEST(FindLogLine) {
172 : const char* string =
173 : "prefix1, stuff, suffix1\n"
174 : "prefix2, stuff\n, suffix2\n"
175 : "prefix3suffix3\n"
176 : "prefix4 suffix4";
177 : // Make sure the vector contains the terminating \0 character.
178 : i::Vector<const char> log(string, strlen(string));
179 5 : CHECK(FindLogLine(&log, "prefix1", "suffix1"));
180 5 : CHECK(FindLogLine(&log, "prefix1", "suffix1"));
181 5 : CHECK(!FindLogLine(&log, "prefix2", "suffix2"));
182 5 : CHECK(!FindLogLine(&log, "prefix1", "suffix2"));
183 5 : CHECK(!FindLogLine(&log, "prefix1", "suffix3"));
184 5 : CHECK(FindLogLine(&log, "prefix3", "suffix3"));
185 5 : CHECK(FindLogLine(&log, "prefix4", "suffix4"));
186 5 : CHECK(!FindLogLine(&log, "prefix4", "suffix4XXXXXXXXXXXX"));
187 5 : CHECK(!FindLogLine(&log, "prefix4XXXXXXXXXXXXXXXXXXXXXXxxx", "suffix4"));
188 5 : CHECK(!FindLogLine(&log, "suffix", "suffix5XXXXXXXXXXXXXXXXXXXX"));
189 5 : }
190 :
191 : // BUG(913). Need to implement support for profiling multiple VM threads.
192 : #if 0
193 :
194 : namespace {
195 :
196 : class LoopingThread : public v8::internal::Thread {
197 : public:
198 : explicit LoopingThread(v8::internal::Isolate* isolate)
199 : : v8::internal::Thread(isolate),
200 : semaphore_(new v8::internal::Semaphore(0)),
201 : run_(true) {
202 : }
203 :
204 : virtual ~LoopingThread() { delete semaphore_; }
205 :
206 : void Run() {
207 : self_ = pthread_self();
208 : RunLoop();
209 : }
210 :
211 : void SendSigProf() { pthread_kill(self_, SIGPROF); }
212 :
213 : void Stop() { run_ = false; }
214 :
215 : bool WaitForRunning() { return semaphore_->Wait(1000000); }
216 :
217 : protected:
218 : bool IsRunning() { return run_; }
219 :
220 : virtual void RunLoop() = 0;
221 :
222 : void SetV8ThreadId() {
223 : v8_thread_id_ = v8::V8::GetCurrentThreadId();
224 : }
225 :
226 : void SignalRunning() { semaphore_->Signal(); }
227 :
228 : private:
229 : v8::internal::Semaphore* semaphore_;
230 : bool run_;
231 : pthread_t self_;
232 : int v8_thread_id_;
233 : };
234 :
235 :
236 : class LoopingJsThread : public LoopingThread {
237 : public:
238 : explicit LoopingJsThread(v8::internal::Isolate* isolate)
239 : : LoopingThread(isolate) { }
240 : void RunLoop() {
241 : v8::Locker locker;
242 : CHECK_NOT_NULL(CcTest::i_isolate());
243 : CHECK_GT(CcTest::i_isolate()->thread_manager()->CurrentId(), 0);
244 : SetV8ThreadId();
245 : while (IsRunning()) {
246 : v8::HandleScope scope;
247 : v8::Persistent<v8::Context> context = v8::Context::New();
248 : CHECK(!context.IsEmpty());
249 : {
250 : v8::Context::Scope context_scope(context);
251 : SignalRunning();
252 : CompileRun(
253 : "var j; for (var i=0; i<10000; ++i) { j = Math.sin(i); }");
254 : }
255 : context.Dispose();
256 : i::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(1));
257 : }
258 : }
259 : };
260 :
261 :
262 : class LoopingNonJsThread : public LoopingThread {
263 : public:
264 : explicit LoopingNonJsThread(v8::internal::Isolate* isolate)
265 : : LoopingThread(isolate) { }
266 : void RunLoop() {
267 : v8::Locker locker;
268 : v8::Unlocker unlocker;
269 : // Now thread has V8's id, but will not run VM code.
270 : CHECK_NOT_NULL(CcTest::i_isolate());
271 : CHECK_GT(CcTest::i_isolate()->thread_manager()->CurrentId(), 0);
272 : double i = 10;
273 : SignalRunning();
274 : while (IsRunning()) {
275 : i = std::sin(i);
276 : i::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(1));
277 : }
278 : }
279 : };
280 :
281 :
282 : class TestSampler : public v8::internal::Sampler {
283 : public:
284 : explicit TestSampler(v8::internal::Isolate* isolate)
285 : : Sampler(isolate, 0, true, true),
286 : semaphore_(new v8::internal::Semaphore(0)),
287 : was_sample_stack_called_(false) {
288 : }
289 :
290 : ~TestSampler() { delete semaphore_; }
291 :
292 : void SampleStack(v8::internal::TickSample*) {
293 : was_sample_stack_called_ = true;
294 : }
295 :
296 : void Tick(v8::internal::TickSample*) { semaphore_->Signal(); }
297 :
298 : bool WaitForTick() { return semaphore_->Wait(1000000); }
299 :
300 : void Reset() { was_sample_stack_called_ = false; }
301 :
302 : bool WasSampleStackCalled() { return was_sample_stack_called_; }
303 :
304 : private:
305 : v8::internal::Semaphore* semaphore_;
306 : bool was_sample_stack_called_;
307 : };
308 :
309 :
310 : } // namespace
311 :
312 : TEST(ProfMultipleThreads) {
313 : TestSampler* sampler = nullptr;
314 : {
315 : v8::Locker locker;
316 : sampler = new TestSampler(CcTest::i_isolate());
317 : sampler->Start();
318 : CHECK(sampler->IsActive());
319 : }
320 :
321 : LoopingJsThread jsThread(CcTest::i_isolate());
322 : jsThread.Start();
323 : LoopingNonJsThread nonJsThread(CcTest::i_isolate());
324 : nonJsThread.Start();
325 :
326 : CHECK(!sampler->WasSampleStackCalled());
327 : jsThread.WaitForRunning();
328 : jsThread.SendSigProf();
329 : CHECK(sampler->WaitForTick());
330 : CHECK(sampler->WasSampleStackCalled());
331 : sampler->Reset();
332 : CHECK(!sampler->WasSampleStackCalled());
333 : nonJsThread.WaitForRunning();
334 : nonJsThread.SendSigProf();
335 : CHECK(!sampler->WaitForTick());
336 : CHECK(!sampler->WasSampleStackCalled());
337 : sampler->Stop();
338 :
339 : jsThread.Stop();
340 : nonJsThread.Stop();
341 : jsThread.Join();
342 : nonJsThread.Join();
343 :
344 : delete sampler;
345 : }
346 :
347 : #endif // __linux__
348 :
349 :
350 : // Test for issue http://crbug.com/23768 in Chromium.
351 : // Heap can contain scripts with already disposed external sources.
352 : // We need to verify that LogCompiledFunctions doesn't crash on them.
353 : namespace {
354 :
355 : class SimpleExternalString : public v8::String::ExternalStringResource {
356 : public:
357 5 : explicit SimpleExternalString(const char* source)
358 5 : : utf_source_(StrLength(source)) {
359 230 : for (int i = 0; i < utf_source_.length(); ++i)
360 335 : utf_source_[i] = source[i];
361 5 : }
362 5 : virtual ~SimpleExternalString() {}
363 30 : virtual size_t length() const { return utf_source_.length(); }
364 25 : virtual const uint16_t* data() const { return utf_source_.start(); }
365 : private:
366 : i::ScopedVector<uint16_t> utf_source_;
367 : };
368 :
369 : } // namespace
370 :
371 23723 : TEST(Issue23768) {
372 5 : v8::HandleScope scope(CcTest::isolate());
373 5 : v8::Local<v8::Context> env = v8::Context::New(CcTest::isolate());
374 5 : env->Enter();
375 :
376 5 : SimpleExternalString source_ext_str("(function ext() {})();");
377 : v8::Local<v8::String> source =
378 5 : v8::String::NewExternalTwoByte(CcTest::isolate(), &source_ext_str)
379 5 : .ToLocalChecked();
380 : // Script needs to have a name in order to trigger InitLineEnds execution.
381 : v8::Local<v8::String> origin =
382 : v8::String::NewFromUtf8(CcTest::isolate(), "issue-23768-test",
383 5 : v8::NewStringType::kNormal)
384 10 : .ToLocalChecked();
385 5 : v8::Local<v8::Script> evil_script = CompileWithOrigin(source, origin);
386 5 : CHECK(!evil_script.IsEmpty());
387 10 : CHECK(!evil_script->Run(env).IsEmpty());
388 : i::Handle<i::ExternalTwoByteString> i_source(
389 : i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
390 : // This situation can happen if source was an external string disposed
391 : // by its owner.
392 : i_source->set_resource(nullptr);
393 :
394 : // Must not crash.
395 10 : CcTest::i_isolate()->logger()->LogCompiledFunctions();
396 5 : }
397 :
398 :
399 0 : static void ObjMethod1(const v8::FunctionCallbackInfo<v8::Value>& args) {
400 0 : }
401 :
402 :
403 23723 : TEST(LogCallbacks) {
404 5 : SETUP_FLAGS();
405 : v8::Isolate::CreateParams create_params;
406 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
407 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
408 : {
409 5 : ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
410 :
411 : v8::Local<v8::FunctionTemplate> obj = v8::Local<v8::FunctionTemplate>::New(
412 10 : isolate, v8::FunctionTemplate::New(isolate));
413 5 : obj->SetClassName(v8_str("Obj"));
414 5 : v8::Local<v8::ObjectTemplate> proto = obj->PrototypeTemplate();
415 5 : v8::Local<v8::Signature> signature = v8::Signature::New(isolate, obj);
416 : proto->Set(v8_str("method1"),
417 : v8::FunctionTemplate::New(isolate, ObjMethod1,
418 : v8::Local<v8::Value>(), signature),
419 15 : static_cast<v8::PropertyAttribute>(v8::DontDelete));
420 :
421 : logger.env()
422 : ->Global()
423 : ->Set(logger.env(), v8_str("Obj"),
424 20 : obj->GetFunction(logger.env()).ToLocalChecked())
425 10 : .FromJust();
426 : CompileRun("Obj.prototype.method1.toString();");
427 :
428 5 : logger.LogCompiledFunctions();
429 :
430 5 : logger.StopLogging();
431 :
432 : Address ObjMethod1_entry = reinterpret_cast<Address>(ObjMethod1);
433 : #if USES_FUNCTION_DESCRIPTORS
434 : ObjMethod1_entry = *FUNCTION_ENTRYPOINT_ADDRESS(ObjMethod1_entry);
435 : #endif
436 : i::EmbeddedVector<char, 100> ref_data;
437 : i::SNPrintF(ref_data, ",0x%" V8PRIxPTR ",1,\"method1\"",
438 5 : reinterpret_cast<intptr_t>(ObjMethod1_entry));
439 10 : CHECK(logger.FindLine("code-creation,Callback,-2,", ref_data.start()));
440 : }
441 5 : isolate->Dispose();
442 5 : }
443 :
444 :
445 0 : static void Prop1Getter(v8::Local<v8::String> property,
446 : const v8::PropertyCallbackInfo<v8::Value>& info) {
447 0 : }
448 :
449 0 : static void Prop1Setter(v8::Local<v8::String> property,
450 : v8::Local<v8::Value> value,
451 : const v8::PropertyCallbackInfo<void>& info) {
452 0 : }
453 :
454 0 : static void Prop2Getter(v8::Local<v8::String> property,
455 : const v8::PropertyCallbackInfo<v8::Value>& info) {
456 0 : }
457 :
458 :
459 23723 : TEST(LogAccessorCallbacks) {
460 5 : SETUP_FLAGS();
461 : v8::Isolate::CreateParams create_params;
462 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
463 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
464 : {
465 5 : ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
466 :
467 : v8::Local<v8::FunctionTemplate> obj = v8::Local<v8::FunctionTemplate>::New(
468 10 : isolate, v8::FunctionTemplate::New(isolate));
469 5 : obj->SetClassName(v8_str("Obj"));
470 5 : v8::Local<v8::ObjectTemplate> inst = obj->InstanceTemplate();
471 5 : inst->SetAccessor(v8_str("prop1"), Prop1Getter, Prop1Setter);
472 5 : inst->SetAccessor(v8_str("prop2"), Prop2Getter);
473 :
474 5 : logger.logger()->LogAccessorCallbacks();
475 :
476 5 : logger.StopLogging();
477 :
478 : Address Prop1Getter_entry = reinterpret_cast<Address>(Prop1Getter);
479 : #if USES_FUNCTION_DESCRIPTORS
480 : Prop1Getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop1Getter_entry);
481 : #endif
482 : EmbeddedVector<char, 100> prop1_getter_record;
483 : i::SNPrintF(prop1_getter_record, ",0x%" V8PRIxPTR ",1,\"get prop1\"",
484 5 : reinterpret_cast<intptr_t>(Prop1Getter_entry));
485 10 : CHECK(logger.FindLine("code-creation,Callback,-2,",
486 : prop1_getter_record.start()));
487 :
488 : Address Prop1Setter_entry = reinterpret_cast<Address>(Prop1Setter);
489 : #if USES_FUNCTION_DESCRIPTORS
490 : Prop1Setter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop1Setter_entry);
491 : #endif
492 : EmbeddedVector<char, 100> prop1_setter_record;
493 : i::SNPrintF(prop1_setter_record, ",0x%" V8PRIxPTR ",1,\"set prop1\"",
494 5 : reinterpret_cast<intptr_t>(Prop1Setter_entry));
495 10 : CHECK(logger.FindLine("code-creation,Callback,-2,",
496 : prop1_setter_record.start()));
497 :
498 : Address Prop2Getter_entry = reinterpret_cast<Address>(Prop2Getter);
499 : #if USES_FUNCTION_DESCRIPTORS
500 : Prop2Getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop2Getter_entry);
501 : #endif
502 : EmbeddedVector<char, 100> prop2_getter_record;
503 : i::SNPrintF(prop2_getter_record, ",0x%" V8PRIxPTR ",1,\"get prop2\"",
504 5 : reinterpret_cast<intptr_t>(Prop2Getter_entry));
505 10 : CHECK(logger.FindLine("code-creation,Callback,-2,",
506 5 : prop2_getter_record.start()));
507 : }
508 5 : isolate->Dispose();
509 5 : }
510 :
511 : // Test that logging of code create / move events is equivalent to traversal of
512 : // a resulting heap.
513 23719 : TEST(EquivalenceOfLoggingAndTraversal) {
514 : // This test needs to be run on a "clean" V8 to ensure that snapshot log
515 : // is loaded. This is always true when running using tools/test.py because
516 : // it launches a new cctest instance for every test. To be sure that launching
517 : // cctest manually also works, please be sure that no tests below
518 : // are using V8.
519 :
520 : // Start with profiling to capture all code events from the beginning.
521 1 : SETUP_FLAGS();
522 : v8::Isolate::CreateParams create_params;
523 1 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
524 1 : v8::Isolate* isolate = v8::Isolate::New(create_params);
525 : {
526 1 : ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
527 :
528 : // Compile and run a function that creates other functions.
529 : CompileRun(
530 : "(function f(obj) {\n"
531 : " obj.test =\n"
532 : " (function a(j) { return function b() { return j; } })(100);\n"
533 : "})(this);");
534 1 : logger.logger()->StopProfiler();
535 : reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage(
536 1 : i::Heap::kMakeHeapIterableMask, i::GarbageCollectionReason::kTesting);
537 1 : logger.StringEvent("test-logging-done", "");
538 :
539 : // Iterate heap to find compiled functions, will write to log.
540 1 : logger.LogCompiledFunctions();
541 1 : logger.StringEvent("test-traversal-done", "");
542 :
543 1 : logger.StopLogging();
544 :
545 1 : v8::Local<v8::String> log_str = logger.GetLogString();
546 : logger.env()
547 : ->Global()
548 3 : ->Set(logger.env(), v8_str("_log"), log_str)
549 2 : .FromJust();
550 :
551 : // Load the Test snapshot's sources, see log-eq-of-logging-and-traversal.js
552 : i::Vector<const char> source =
553 1 : i::NativesCollection<i::TEST>::GetScriptsSource();
554 : v8::Local<v8::String> source_str =
555 : v8::String::NewFromUtf8(isolate, source.start(),
556 2 : v8::NewStringType::kNormal, source.length())
557 1 : .ToLocalChecked();
558 2 : v8::TryCatch try_catch(isolate);
559 : v8::Local<v8::Script> script = CompileWithOrigin(source_str, "");
560 1 : if (script.IsEmpty()) {
561 0 : v8::String::Utf8Value exception(isolate, try_catch.Exception());
562 0 : printf("compile: %s\n", *exception);
563 0 : CHECK(false);
564 : }
565 : v8::Local<v8::Value> result;
566 2 : if (!script->Run(logger.env()).ToLocal(&result)) {
567 0 : v8::String::Utf8Value exception(isolate, try_catch.Exception());
568 0 : printf("run: %s\n", *exception);
569 0 : CHECK(false);
570 : }
571 : // The result either be the "true" literal or problem description.
572 1 : if (!result->IsTrue()) {
573 0 : v8::Local<v8::String> s = result->ToString(logger.env()).ToLocalChecked();
574 0 : i::ScopedVector<char> data(s->Utf8Length() + 1);
575 0 : CHECK(data.start());
576 0 : s->WriteUtf8(data.start());
577 : printf("%s\n", data.start());
578 : // Make sure that our output is written prior crash due to CHECK failure.
579 0 : fflush(stdout);
580 0 : CHECK(false);
581 1 : }
582 : }
583 1 : isolate->Dispose();
584 1 : }
585 :
586 :
587 23723 : TEST(LogVersion) {
588 5 : SETUP_FLAGS();
589 : v8::Isolate::CreateParams create_params;
590 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
591 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
592 : {
593 5 : ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
594 5 : logger.StopLogging();
595 :
596 : i::EmbeddedVector<char, 100> ref_data;
597 : i::SNPrintF(ref_data, "%d,%d,%d,%d,%d", i::Version::GetMajor(),
598 : i::Version::GetMinor(), i::Version::GetBuild(),
599 10 : i::Version::GetPatch(), i::Version::IsCandidate());
600 10 : CHECK(logger.FindLine("v8-version,", ref_data.start()));
601 : }
602 5 : isolate->Dispose();
603 5 : }
604 :
605 :
606 : // https://crbug.com/539892
607 : // CodeCreateEvents with really large names should not crash.
608 23723 : TEST(Issue539892) {
609 10 : class : public i::CodeEventLogger {
610 : public:
611 0 : void CodeMoveEvent(i::AbstractCode* from, Address to) override {}
612 0 : void CodeDisableOptEvent(i::AbstractCode* code,
613 0 : i::SharedFunctionInfo* shared) override {}
614 :
615 : private:
616 2630 : void LogRecordedBuffer(i::AbstractCode* code, i::SharedFunctionInfo* shared,
617 2630 : const char* name, int length) override {}
618 : } code_event_logger;
619 5 : SETUP_FLAGS();
620 : v8::Isolate::CreateParams create_params;
621 5 : create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
622 5 : v8::Isolate* isolate = v8::Isolate::New(create_params);
623 :
624 : {
625 5 : ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
626 5 : logger.logger()->addCodeEventListener(&code_event_logger);
627 :
628 : // Function with a really large name.
629 : const char* source_text =
630 : "(function "
631 : "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
632 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
633 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
634 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
635 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
636 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
637 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
638 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
639 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
640 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
641 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
642 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
643 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
644 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
645 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
646 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
647 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac"
648 : "(){})();";
649 :
650 : CompileRun(source_text);
651 :
652 : // Must not crash.
653 10 : logger.LogCompiledFunctions();
654 : }
655 5 : isolate->Dispose();
656 71159 : }
|