Line data Source code
1 : // Copyright 2014 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 : #include "test/cctest/trace-extension.h"
29 :
30 : #include "include/v8-profiler.h"
31 : #include "src/vm-state-inl.h"
32 : #include "test/cctest/cctest.h"
33 :
34 : namespace v8 {
35 : namespace internal {
36 :
37 : const char* TraceExtension::kSource =
38 : "native function trace();"
39 : "native function js_trace();"
40 : "native function js_entry_sp();"
41 : "native function js_entry_sp_level2();";
42 :
43 :
44 96 : v8::Local<v8::FunctionTemplate> TraceExtension::GetNativeFunctionTemplate(
45 : v8::Isolate* isolate, v8::Local<v8::String> name) {
46 96 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
47 96 : if (name->Equals(context, v8::String::NewFromUtf8(isolate, "trace",
48 : v8::NewStringType::kNormal)
49 192 : .ToLocalChecked())
50 192 : .FromJust()) {
51 24 : return v8::FunctionTemplate::New(isolate, TraceExtension::Trace);
52 72 : } else if (name->Equals(context,
53 : v8::String::NewFromUtf8(isolate, "js_trace",
54 : v8::NewStringType::kNormal)
55 144 : .ToLocalChecked())
56 144 : .FromJust()) {
57 24 : return v8::FunctionTemplate::New(isolate, TraceExtension::JSTrace);
58 48 : } else if (name->Equals(context,
59 : v8::String::NewFromUtf8(isolate, "js_entry_sp",
60 : v8::NewStringType::kNormal)
61 96 : .ToLocalChecked())
62 96 : .FromJust()) {
63 24 : return v8::FunctionTemplate::New(isolate, TraceExtension::JSEntrySP);
64 24 : } else if (name->Equals(context,
65 : v8::String::NewFromUtf8(isolate, "js_entry_sp_level2",
66 : v8::NewStringType::kNormal)
67 48 : .ToLocalChecked())
68 48 : .FromJust()) {
69 24 : return v8::FunctionTemplate::New(isolate, TraceExtension::JSEntrySPLevel2);
70 : } else {
71 0 : CHECK(false);
72 : return v8::Local<v8::FunctionTemplate>();
73 : }
74 : }
75 :
76 :
77 12 : Address TraceExtension::GetFP(const v8::FunctionCallbackInfo<v8::Value>& args) {
78 : // Convert frame pointer from encoding as smis in the arguments to a pointer.
79 12 : CHECK_EQ(2, args.Length()); // Ignore second argument on 32-bit platform.
80 : #if defined(V8_HOST_ARCH_32_BIT)
81 : Address fp = *reinterpret_cast<Address*>(*args[0]);
82 : #elif defined(V8_HOST_ARCH_64_BIT)
83 12 : int64_t low_bits = *reinterpret_cast<uint64_t*>(*args[0]) >> 32;
84 12 : int64_t high_bits = *reinterpret_cast<uint64_t*>(*args[1]);
85 12 : Address fp = reinterpret_cast<Address>(high_bits | low_bits);
86 : #else
87 : #error Host architecture is neither 32-bit nor 64-bit.
88 : #endif
89 : printf("Trace: %p\n", static_cast<void*>(fp));
90 12 : return fp;
91 : }
92 :
93 : static struct { v8::TickSample* sample; } trace_env = {nullptr};
94 :
95 18 : void TraceExtension::InitTraceEnv(v8::TickSample* sample) {
96 18 : trace_env.sample = sample;
97 18 : }
98 :
99 :
100 18 : void TraceExtension::DoTrace(Address fp) {
101 : RegisterState regs;
102 18 : regs.fp = fp;
103 : // sp is only used to define stack high bound
104 : regs.sp =
105 18 : reinterpret_cast<Address>(trace_env.sample) - 10240;
106 : trace_env.sample->Init(CcTest::isolate(), regs,
107 18 : v8::TickSample::kSkipCEntryFrame, true);
108 18 : }
109 :
110 :
111 6 : void TraceExtension::Trace(const v8::FunctionCallbackInfo<v8::Value>& args) {
112 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
113 6 : i::VMState<EXTERNAL> state(isolate);
114 : Address address = reinterpret_cast<Address>(
115 : reinterpret_cast<intptr_t>(&TraceExtension::Trace));
116 12 : i::ExternalCallbackScope call_scope(isolate, address);
117 12 : DoTrace(GetFP(args));
118 6 : }
119 :
120 :
121 : // Hide c_entry_fp to emulate situation when sampling is done while
122 : // pure JS code is being executed
123 6 : static void DoTraceHideCEntryFPAddress(Address fp) {
124 : v8::internal::Address saved_c_frame_fp =
125 6 : *(CcTest::i_isolate()->c_entry_fp_address());
126 6 : CHECK(saved_c_frame_fp);
127 6 : *(CcTest::i_isolate()->c_entry_fp_address()) = 0;
128 6 : i::TraceExtension::DoTrace(fp);
129 6 : *(CcTest::i_isolate()->c_entry_fp_address()) = saved_c_frame_fp;
130 6 : }
131 :
132 :
133 6 : void TraceExtension::JSTrace(const v8::FunctionCallbackInfo<v8::Value>& args) {
134 : i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
135 6 : i::VMState<EXTERNAL> state(isolate);
136 : Address address = reinterpret_cast<Address>(
137 : reinterpret_cast<intptr_t>(&TraceExtension::JSTrace));
138 12 : i::ExternalCallbackScope call_scope(isolate, address);
139 12 : DoTraceHideCEntryFPAddress(GetFP(args));
140 6 : }
141 :
142 :
143 48 : Address TraceExtension::GetJsEntrySp() {
144 48 : CHECK(CcTest::i_isolate()->thread_local_top());
145 48 : return CcTest::i_isolate()->js_entry_sp();
146 : }
147 :
148 :
149 12 : void TraceExtension::JSEntrySP(
150 : const v8::FunctionCallbackInfo<v8::Value>& args) {
151 12 : CHECK(GetJsEntrySp());
152 12 : }
153 :
154 :
155 6 : void TraceExtension::JSEntrySPLevel2(
156 6 : const v8::FunctionCallbackInfo<v8::Value>& args) {
157 6 : v8::HandleScope scope(args.GetIsolate());
158 6 : const Address js_entry_sp = GetJsEntrySp();
159 6 : CHECK(js_entry_sp);
160 : CompileRun("js_entry_sp();");
161 6 : CHECK_EQ(js_entry_sp, GetJsEntrySp());
162 6 : }
163 :
164 :
165 : } // namespace internal
166 71154 : } // namespace v8
|