OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 // | |
5 // Tests the public sampling API in include/v8.h | |
6 | |
7 #include <string> | |
8 | |
9 #include "include/v8.h" | |
10 | |
11 #include "src/v8.h" | |
alph
2014/09/08 12:47:40
style: no need for extra lines between includes.
gholap
2014/09/08 23:57:38
Done.
| |
12 | |
13 #include "src/base/platform/platform.h" | |
14 | |
15 #include "test/cctest/cctest.h" | |
16 | |
17 using v8::Local; | |
18 | |
19 namespace { | |
20 // Sampler thread waits on this semaphore. | |
21 v8::base::Semaphore* sampler_semaphore = new v8::base::Semaphore(0); | |
22 | |
23 // V8 thread (the JavaScript code) waits on this semaphore. | |
24 v8::base::Semaphore* v8_semaphore = new v8::base::Semaphore(0); | |
25 | |
26 // The JavaScript calls this function when on full stack depth. | |
27 void SignalAndWaitForSampler( | |
28 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
29 // Tell the sampler that it can take a sample now. | |
30 sampler_semaphore->Signal(); | |
31 | |
32 // Wait for the sampler to finish collecting a sample. | |
33 v8_semaphore->Wait(); | |
34 } | |
35 } | |
36 | |
37 | |
38 // A thread which collects samples from v8. | |
39 class V8_FINAL SamplerThread : public v8::base::Thread { | |
40 public: | |
41 explicit SamplerThread(v8::Isolate* isolate) | |
42 : Thread(v8::base::Thread::Options("sampler-api-tester")), | |
43 isolate_(isolate) { | |
44 } | |
45 | |
46 virtual ~SamplerThread() {} | |
47 | |
48 virtual void Run() { | |
49 sampler_semaphore->Wait(); // Wait for JS to reach full stack depth. | |
50 isolate_->GetSample(&sample); | |
51 v8_semaphore->Signal(); // Tell JS that sample collection is done. | |
52 } | |
53 | |
54 v8::Sample sample; | |
55 | |
56 private: | |
57 v8::Isolate* isolate_; | |
58 }; | |
59 | |
60 | |
61 // A JavaScript function which takes stack depth | |
62 // (minimum value 2) as an argument. | |
63 // When at the bottom of the recursion, | |
64 // the JavaScript code calls into C++ test code, | |
65 // waiting for the sampler to take a sample. | |
66 static const char* sampler_api_test_function = "function func(depth) {" | |
67 " if (depth == 2) SignalAndWaitForSampler();" | |
68 " else return func(depth - 1);" | |
69 "}"; | |
70 | |
71 | |
72 TEST(StackDepthIsConsistent) { | |
73 v8::Isolate* isolate = CcTest::isolate(); | |
74 v8::HandleScope scope(isolate); | |
75 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); | |
76 global->Set( | |
77 v8::String::NewFromUtf8(isolate, "SignalAndWaitForSampler"), | |
78 v8::FunctionTemplate::New(isolate, SignalAndWaitForSampler)); | |
79 | |
80 LocalContext env(isolate, NULL, global); | |
81 std::string source(sampler_api_test_function); | |
82 source.append("func(8);"); | |
83 Local<v8::Script> script = v8::Script::Compile( | |
84 v8::String::NewFromUtf8(isolate, source.c_str())); | |
85 SamplerThread sampler(isolate); | |
86 | |
87 sampler.Start(); | |
88 script->Run(); | |
89 sampler.Join(); | |
90 | |
91 CHECK_EQ(8, sampler.sample.size()); | |
92 } | |
93 | |
94 | |
95 TEST(StackDepthDoesNotExceedMaxValue) { | |
96 v8::Isolate* isolate = CcTest::isolate(); | |
97 v8::HandleScope scope(isolate); | |
98 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); | |
99 global->Set( | |
100 v8::String::NewFromUtf8(isolate, "SignalAndWaitForSampler"), | |
101 v8::FunctionTemplate::New(isolate, SignalAndWaitForSampler)); | |
102 | |
103 LocalContext env(isolate, NULL, global); | |
104 std::string source(sampler_api_test_function); | |
105 source.append("func(300);"); | |
106 Local<v8::Script> script = v8::Script::Compile( | |
107 v8::String::NewFromUtf8(isolate, source.c_str())); | |
108 SamplerThread sampler(isolate); | |
109 | |
110 sampler.Start(); | |
111 script->Run(); | |
112 sampler.Join(); | |
113 | |
114 int MAX_SIZE = v8::Sample::kMaxSize; | |
115 CHECK_EQ(MAX_SIZE, sampler.sample.size()); | |
116 } | |
117 | |
118 | |
119 namespace { | |
120 std::vector<v8::JitCodeEvent> inner_funcs; | |
121 std::vector<v8::JitCodeEvent> outer_funcs; | |
122 | |
123 void TestJitCodeEventHandler(const v8::JitCodeEvent* event) { | |
124 if (event->type != v8::JitCodeEvent::CODE_ADDED) return; | |
125 std::string name(event->name.str, event->name.len); | |
126 if (name.find("test_sampler_api_inner") != std::string::npos) | |
127 inner_funcs.push_back(*event); | |
128 if (name.find("test_sampler_api_outer") != std::string::npos) | |
129 outer_funcs.push_back(*event); | |
130 } | |
131 } | |
132 | |
133 | |
134 // Note: The argumnets.callee stuff is there so that the | |
135 // functions are not optimized away. | |
136 static const char* sampler_api_test_script = | |
137 "function test_sampler_api_inner() {" | |
138 " SignalAndWaitForSampler();" | |
139 " return arguments.callee.toString();" | |
140 "}" | |
141 "function test_sampler_api_outer() {" | |
142 " return test_sampler_api_inner() + arguments.callee.toString();" | |
143 "}" | |
144 "test_sampler_api_outer();"; | |
145 | |
146 | |
147 // The captured sample should have three pc values. | |
148 // They should fall in the range where the compiled code | |
149 // The expected stack is: | |
150 // bottom of stack [{anon script}, outer, inner] top of stack | |
151 // ^ ^ ^ | |
152 // sample.stack indices 2 1 0 | |
153 TEST(StackFramesConsistent) { | |
154 v8::Isolate* isolate = CcTest::isolate(); | |
155 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, | |
156 TestJitCodeEventHandler); | |
157 v8::HandleScope scope(isolate); | |
158 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); | |
159 global->Set( | |
160 v8::String::NewFromUtf8(isolate, "SignalAndWaitForSampler"), | |
161 v8::FunctionTemplate::New(isolate, SignalAndWaitForSampler)); | |
162 | |
163 LocalContext env(isolate, NULL, global); | |
164 Local<v8::Script> script = v8::Script::Compile( | |
165 v8::String::NewFromUtf8(isolate, sampler_api_test_script)); | |
166 SamplerThread sampler(isolate); | |
167 | |
168 sampler.Start(); | |
169 script->Run(); | |
170 sampler.Join(); | |
171 | |
172 CHECK_EQ(3, sampler.sample.size()); | |
173 | |
174 bool stack_top_is_inner = false; | |
175 bool below_inner_is_outer = false; | |
176 | |
177 for (unsigned i = 0; i < inner_funcs.size(); i++) { | |
178 void* start_addr = inner_funcs[i].code_start; | |
179 void* end_addr = reinterpret_cast<void*>((int64_t)inner_funcs[i].code_start | |
180 + inner_funcs[i].code_len); | |
181 if ((*sampler.sample.begin() >= start_addr) && | |
182 (*sampler.sample.begin() < end_addr)) | |
183 stack_top_is_inner = true; | |
184 } | |
185 | |
186 for (unsigned i = 0; i < outer_funcs.size(); i++) { | |
187 void* start_addr = outer_funcs[i].code_start; | |
188 void* end_addr = reinterpret_cast<void*>((int64_t)outer_funcs[i].code_start | |
189 + outer_funcs[i].code_len); | |
190 if ((*(sampler.sample.begin() + 1) >= start_addr) && | |
191 (*(sampler.sample.begin() + 1) < end_addr)) | |
192 below_inner_is_outer = true; | |
193 } | |
194 | |
195 CHECK_EQ(true, stack_top_is_inner); | |
196 CHECK_EQ(true, below_inner_is_outer); | |
197 } | |
OLD | NEW |