1 | /* |
2 | * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | |
25 | #include "precompiled.hpp" |
26 | #include "code/debugInfo.hpp" |
27 | #include "code/debugInfoRec.hpp" |
28 | #include "code/nmethod.hpp" |
29 | #include "memory/universe.hpp" |
30 | #include "oops/oop.inline.hpp" |
31 | #include "runtime/handles.inline.hpp" |
32 | #include "runtime/interfaceSupport.inline.hpp" |
33 | #include "runtime/jniHandles.inline.hpp" |
34 | #include "runtime/thread.hpp" |
35 | |
36 | // Constructors |
37 | |
38 | DebugInfoWriteStream::DebugInfoWriteStream(DebugInformationRecorder* recorder, int initial_size) |
39 | : CompressedWriteStream(initial_size) { |
40 | _recorder = recorder; |
41 | } |
42 | |
43 | // Serializing oops |
44 | |
45 | void DebugInfoWriteStream::write_handle(jobject h) { |
46 | write_int(recorder()->oop_recorder()->find_index(h)); |
47 | } |
48 | |
49 | void DebugInfoWriteStream::write_metadata(Metadata* h) { |
50 | write_int(recorder()->oop_recorder()->find_index(h)); |
51 | } |
52 | |
53 | oop DebugInfoReadStream::read_oop() { |
54 | oop o = code()->oop_at(read_int()); |
55 | assert(oopDesc::is_oop_or_null(o), "oop only" ); |
56 | return o; |
57 | } |
58 | |
59 | ScopeValue* DebugInfoReadStream::read_object_value(bool is_auto_box) { |
60 | int id = read_int(); |
61 | #ifdef ASSERT |
62 | assert(_obj_pool != NULL, "object pool does not exist" ); |
63 | for (int i = _obj_pool->length() - 1; i >= 0; i--) { |
64 | assert(_obj_pool->at(i)->as_ObjectValue()->id() != id, "should not be read twice" ); |
65 | } |
66 | #endif |
67 | ObjectValue* result = is_auto_box ? new AutoBoxObjectValue(id) : new ObjectValue(id); |
68 | // Cache the object since an object field could reference it. |
69 | _obj_pool->push(result); |
70 | result->read_object(this); |
71 | return result; |
72 | } |
73 | |
74 | ScopeValue* DebugInfoReadStream::get_cached_object() { |
75 | int id = read_int(); |
76 | assert(_obj_pool != NULL, "object pool does not exist" ); |
77 | for (int i = _obj_pool->length() - 1; i >= 0; i--) { |
78 | ObjectValue* ov = _obj_pool->at(i)->as_ObjectValue(); |
79 | if (ov->id() == id) { |
80 | return ov; |
81 | } |
82 | } |
83 | ShouldNotReachHere(); |
84 | return NULL; |
85 | } |
86 | |
87 | // Serializing scope values |
88 | |
89 | enum { LOCATION_CODE = 0, CONSTANT_INT_CODE = 1, CONSTANT_OOP_CODE = 2, |
90 | CONSTANT_LONG_CODE = 3, CONSTANT_DOUBLE_CODE = 4, |
91 | OBJECT_CODE = 5, OBJECT_ID_CODE = 6, |
92 | AUTO_BOX_OBJECT_CODE = 7 }; |
93 | |
94 | ScopeValue* ScopeValue::read_from(DebugInfoReadStream* stream) { |
95 | ScopeValue* result = NULL; |
96 | switch(stream->read_int()) { |
97 | case LOCATION_CODE: result = new LocationValue(stream); break; |
98 | case CONSTANT_INT_CODE: result = new ConstantIntValue(stream); break; |
99 | case CONSTANT_OOP_CODE: result = new ConstantOopReadValue(stream); break; |
100 | case CONSTANT_LONG_CODE: result = new ConstantLongValue(stream); break; |
101 | case CONSTANT_DOUBLE_CODE: result = new ConstantDoubleValue(stream); break; |
102 | case OBJECT_CODE: result = stream->read_object_value(false /*is_auto_box*/); break; |
103 | case AUTO_BOX_OBJECT_CODE: result = stream->read_object_value(true /*is_auto_box*/); break; |
104 | case OBJECT_ID_CODE: result = stream->get_cached_object(); break; |
105 | default: ShouldNotReachHere(); |
106 | } |
107 | return result; |
108 | } |
109 | |
110 | // LocationValue |
111 | |
112 | LocationValue::LocationValue(DebugInfoReadStream* stream) { |
113 | _location = Location(stream); |
114 | } |
115 | |
116 | void LocationValue::write_on(DebugInfoWriteStream* stream) { |
117 | stream->write_int(LOCATION_CODE); |
118 | location().write_on(stream); |
119 | } |
120 | |
121 | void LocationValue::print_on(outputStream* st) const { |
122 | location().print_on(st); |
123 | } |
124 | |
125 | // ObjectValue |
126 | |
127 | void ObjectValue::set_value(oop value) { |
128 | _value = Handle(Thread::current(), value); |
129 | } |
130 | |
131 | void ObjectValue::read_object(DebugInfoReadStream* stream) { |
132 | _klass = read_from(stream); |
133 | assert(_klass->is_constant_oop(), "should be constant java mirror oop" ); |
134 | int length = stream->read_int(); |
135 | for (int i = 0; i < length; i++) { |
136 | ScopeValue* val = read_from(stream); |
137 | _field_values.append(val); |
138 | } |
139 | } |
140 | |
141 | void ObjectValue::write_on(DebugInfoWriteStream* stream) { |
142 | if (_visited) { |
143 | stream->write_int(OBJECT_ID_CODE); |
144 | stream->write_int(_id); |
145 | } else { |
146 | _visited = true; |
147 | stream->write_int(is_auto_box() ? AUTO_BOX_OBJECT_CODE : OBJECT_CODE); |
148 | stream->write_int(_id); |
149 | _klass->write_on(stream); |
150 | int length = _field_values.length(); |
151 | stream->write_int(length); |
152 | for (int i = 0; i < length; i++) { |
153 | _field_values.at(i)->write_on(stream); |
154 | } |
155 | } |
156 | } |
157 | |
158 | void ObjectValue::print_on(outputStream* st) const { |
159 | st->print("%s[%d]" , is_auto_box() ? "box_obj" : "obj" , _id); |
160 | } |
161 | |
162 | void ObjectValue::print_fields_on(outputStream* st) const { |
163 | #ifndef PRODUCT |
164 | if (_field_values.length() > 0) { |
165 | _field_values.at(0)->print_on(st); |
166 | } |
167 | for (int i = 1; i < _field_values.length(); i++) { |
168 | st->print(", " ); |
169 | _field_values.at(i)->print_on(st); |
170 | } |
171 | #endif |
172 | } |
173 | |
174 | // ConstantIntValue |
175 | |
176 | ConstantIntValue::ConstantIntValue(DebugInfoReadStream* stream) { |
177 | _value = stream->read_signed_int(); |
178 | } |
179 | |
180 | void ConstantIntValue::write_on(DebugInfoWriteStream* stream) { |
181 | stream->write_int(CONSTANT_INT_CODE); |
182 | stream->write_signed_int(value()); |
183 | } |
184 | |
185 | void ConstantIntValue::print_on(outputStream* st) const { |
186 | st->print("%d" , value()); |
187 | } |
188 | |
189 | // ConstantLongValue |
190 | |
191 | ConstantLongValue::ConstantLongValue(DebugInfoReadStream* stream) { |
192 | _value = stream->read_long(); |
193 | } |
194 | |
195 | void ConstantLongValue::write_on(DebugInfoWriteStream* stream) { |
196 | stream->write_int(CONSTANT_LONG_CODE); |
197 | stream->write_long(value()); |
198 | } |
199 | |
200 | void ConstantLongValue::print_on(outputStream* st) const { |
201 | st->print(JLONG_FORMAT, value()); |
202 | } |
203 | |
204 | // ConstantDoubleValue |
205 | |
206 | ConstantDoubleValue::ConstantDoubleValue(DebugInfoReadStream* stream) { |
207 | _value = stream->read_double(); |
208 | } |
209 | |
210 | void ConstantDoubleValue::write_on(DebugInfoWriteStream* stream) { |
211 | stream->write_int(CONSTANT_DOUBLE_CODE); |
212 | stream->write_double(value()); |
213 | } |
214 | |
215 | void ConstantDoubleValue::print_on(outputStream* st) const { |
216 | st->print("%f" , value()); |
217 | } |
218 | |
219 | // ConstantOopWriteValue |
220 | |
221 | void ConstantOopWriteValue::write_on(DebugInfoWriteStream* stream) { |
222 | #ifdef ASSERT |
223 | { |
224 | // cannot use ThreadInVMfromNative here since in case of JVMCI compiler, |
225 | // thread is already in VM state. |
226 | ThreadInVMfromUnknown tiv; |
227 | assert(JNIHandles::resolve(value()) == NULL || |
228 | Universe::heap()->is_in_reserved(JNIHandles::resolve(value())), |
229 | "Should be in heap" ); |
230 | } |
231 | #endif |
232 | stream->write_int(CONSTANT_OOP_CODE); |
233 | stream->write_handle(value()); |
234 | } |
235 | |
236 | void ConstantOopWriteValue::print_on(outputStream* st) const { |
237 | // using ThreadInVMfromUnknown here since in case of JVMCI compiler, |
238 | // thread is already in VM state. |
239 | ThreadInVMfromUnknown tiv; |
240 | JNIHandles::resolve(value())->print_value_on(st); |
241 | } |
242 | |
243 | |
244 | // ConstantOopReadValue |
245 | |
246 | ConstantOopReadValue::ConstantOopReadValue(DebugInfoReadStream* stream) { |
247 | _value = Handle(Thread::current(), stream->read_oop()); |
248 | assert(_value() == NULL || |
249 | Universe::heap()->is_in_reserved(_value()), "Should be in heap" ); |
250 | } |
251 | |
252 | void ConstantOopReadValue::write_on(DebugInfoWriteStream* stream) { |
253 | ShouldNotReachHere(); |
254 | } |
255 | |
256 | void ConstantOopReadValue::print_on(outputStream* st) const { |
257 | if (value()() != NULL) { |
258 | value()()->print_value_on(st); |
259 | } else { |
260 | st->print_cr("NULL" ); |
261 | } |
262 | } |
263 | |
264 | |
265 | // MonitorValue |
266 | |
267 | MonitorValue::MonitorValue(ScopeValue* owner, Location basic_lock, bool eliminated) { |
268 | _owner = owner; |
269 | _basic_lock = basic_lock; |
270 | _eliminated = eliminated; |
271 | } |
272 | |
273 | MonitorValue::MonitorValue(DebugInfoReadStream* stream) { |
274 | _basic_lock = Location(stream); |
275 | _owner = ScopeValue::read_from(stream); |
276 | _eliminated = (stream->read_bool() != 0); |
277 | } |
278 | |
279 | void MonitorValue::write_on(DebugInfoWriteStream* stream) { |
280 | _basic_lock.write_on(stream); |
281 | _owner->write_on(stream); |
282 | stream->write_bool(_eliminated); |
283 | } |
284 | |
285 | #ifndef PRODUCT |
286 | void MonitorValue::print_on(outputStream* st) const { |
287 | st->print("monitor{" ); |
288 | owner()->print_on(st); |
289 | st->print("," ); |
290 | basic_lock().print_on(st); |
291 | st->print("}" ); |
292 | if (_eliminated) { |
293 | st->print(" (eliminated)" ); |
294 | } |
295 | } |
296 | #endif |
297 | |