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 sampling API in include/v8.h | |
6 | |
7 #include <string> | |
8 #include "include/v8.h" | |
9 #include "src/v8.h" | |
10 #include "test/cctest/cctest.h" | |
11 | |
12 #if V8_OS_POSIX && !V8_OS_CYGWIN | |
13 #include <ucontext.h> | |
14 #elif V8_OS_WIN || V8_OS_CYGWIN | |
15 #include "src/base/win32-headers.h" | |
16 #endif | |
17 | |
18 using v8::Local; | |
19 | |
20 namespace { | |
21 // The Sample which CollectSample fills up | |
22 v8::Sample* sample; | |
23 | |
24 // The isolate used in the test | |
25 v8::Isolate* isolate; | |
26 | |
27 // Forward declaration | |
28 // (platform specific implementation at the bottom of this file) | |
29 v8::RegisterState GetRegisterState(); | |
30 | |
31 // The JavaScript calls this function when on full stack depth. | |
32 void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
33 isolate->GetSample(GetRegisterState(), sample); | |
34 } | |
35 | |
36 | |
37 // A JavaScript function which takes stack depth | |
38 // (minimum value 2) as an argument. | |
39 // When at the bottom of the recursion, | |
40 // the JavaScript code calls into C++ test code, | |
41 // waiting for the sampler to take a sample. | |
42 static const char* test_function = | |
43 "function func(depth) {" | |
44 " if (depth == 2) CollectSample();" | |
45 " else return func(depth - 1);" | |
46 "}"; | |
47 } | |
alph
2014/09/19 11:43:05
nit:
} // namespace
| |
48 | |
49 | |
50 #define SAMPLER_API_TESTS_BOOTSTRAP() \ | |
51 v8::Sample sample_; \ | |
52 sample = &sample_; \ | |
53 isolate = CcTest::isolate(); \ | |
54 v8::HandleScope scope(isolate); \ | |
55 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); \ | |
56 global->Set(v8::String::NewFromUtf8(isolate, "CollectSample"), \ | |
57 v8::FunctionTemplate::New(isolate, CollectSample)); \ | |
58 LocalContext env(isolate, NULL, global) | |
59 | |
60 | |
61 TEST(StackDepthIsConsistent) { | |
62 SAMPLER_API_TESTS_BOOTSTRAP(); | |
63 | |
64 std::string source(test_function); | |
65 source.append("func(8);"); | |
66 v8::Script::Compile(v8::String::NewFromUtf8(isolate, source.c_str()))->Run(); | |
67 | |
68 CHECK_EQ(8, sample->size()); | |
69 } | |
70 | |
71 | |
72 TEST(StackDepthDoesNotExceedMaxValue) { | |
73 SAMPLER_API_TESTS_BOOTSTRAP(); | |
74 | |
75 std::string source(test_function); | |
76 source.append("func(300);"); | |
77 v8::Script::Compile(v8::String::NewFromUtf8(isolate, source.c_str()))->Run(); | |
78 | |
79 int MAX_SIZE = v8::Sample::kMaxSize; | |
80 CHECK_EQ(MAX_SIZE, sample->size()); | |
81 } | |
82 | |
83 | |
84 namespace { | |
85 std::vector<v8::JitCodeEvent> inner_funcs; | |
86 std::vector<v8::JitCodeEvent> outer_funcs; | |
87 | |
88 void TestJitCodeEventHandler(const v8::JitCodeEvent* event) { | |
89 if (event->type != v8::JitCodeEvent::CODE_ADDED) return; | |
90 std::string name(event->name.str, event->name.len); | |
91 if (name.find("test_sampler_api_inner") != std::string::npos) | |
92 inner_funcs.push_back(*event); | |
93 if (name.find("test_sampler_api_outer") != std::string::npos) | |
94 outer_funcs.push_back(*event); | |
95 } | |
96 | |
97 | |
98 // Note: The arguments.callee stuff is there so that the | |
99 // functions are not optimized away. | |
100 static const char* test_script = | |
101 "function test_sampler_api_inner() {" | |
102 " CollectSample();" | |
103 " return arguments.callee.toString();" | |
104 "}" | |
105 "function test_sampler_api_outer() {" | |
106 " return test_sampler_api_inner() + arguments.callee.toString();" | |
107 "}" | |
108 "test_sampler_api_outer();"; | |
109 } | |
alph
2014/09/19 11:43:05
ditto
| |
110 | |
111 | |
112 // The captured sample should have three pc values. | |
113 // They should fall in the range where the compiled code | |
114 // The expected stack is: | |
115 // bottom of stack [{anon script}, outer, inner] top of stack | |
116 // ^ ^ ^ | |
117 // sample.stack indices 2 1 0 | |
118 TEST(StackFramesConsistent) { | |
119 SAMPLER_API_TESTS_BOOTSTRAP(); | |
120 | |
121 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, | |
122 TestJitCodeEventHandler); | |
123 v8::Script::Compile(v8::String::NewFromUtf8(isolate, test_script))->Run(); | |
124 | |
125 CHECK_EQ(3, sample->size()); | |
126 | |
127 bool stack_top_is_inner = false; | |
128 bool below_inner_is_outer = false; | |
129 | |
130 for (unsigned i = 0; i < inner_funcs.size(); i++) { | |
131 void* start_addr = inner_funcs[i].code_start; | |
132 void* end_addr = reinterpret_cast<void*>( | |
133 (int64_t)inner_funcs[i].code_start + inner_funcs[i].code_len); | |
134 if ((*sample->begin() >= start_addr) && (*sample->begin() < end_addr)) | |
135 stack_top_is_inner = true; | |
136 } | |
137 | |
138 for (unsigned i = 0; i < outer_funcs.size(); i++) { | |
139 void* start_addr = outer_funcs[i].code_start; | |
140 void* end_addr = reinterpret_cast<void*>( | |
141 (int64_t)outer_funcs[i].code_start + outer_funcs[i].code_len); | |
142 if ((*(sample->begin() + 1) >= start_addr) && | |
143 (*(sample->begin() + 1) < end_addr)) | |
144 below_inner_is_outer = true; | |
145 } | |
146 | |
147 CHECK(stack_top_is_inner); | |
148 CHECK(below_inner_is_outer); | |
149 } | |
150 | |
151 | |
152 // Platform specific implementation of GetStackAndFramePointers | |
153 namespace { | |
154 v8::RegisterState GetRegisterState() { | |
155 #if V8_OS_POSIX && !V8_OS_CYGWIN | |
156 ucontext_t context; | |
157 getcontext(&context); | |
158 #elif V8_OS_WIN || V8_OS_CYGWIN | |
159 CONTEXT context; | |
160 memset(&context, 0, sizeof(context)); | |
161 context.ContextFlags = CONTEXT_FULL; | |
162 GetThreadContext(OpenThread(THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | | |
163 THREAD_QUERY_INFORMATION, | |
164 false, GetCurrentThreadId()), | |
165 &context); | |
166 #endif // V8_OS_POSIX && !V8_OS_CYGWIN / V8_OS_WIN || V8_OS_CYGWIN | |
167 return v8::RegisterState(context); | |
168 } | |
169 } | |
alph
2014/09/19 11:43:05
ditto
| |
OLD | NEW |