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