1/*
2 * Copyright (c) 2016, 2019, 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#ifndef SHARE_JFR_WRITERS_JFRWRITERHOST_INLINE_HPP
26#define SHARE_JFR_WRITERS_JFRWRITERHOST_INLINE_HPP
27
28#include "classfile/javaClasses.hpp"
29#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
30#include "jfr/recorder/service/jfrOptionSet.hpp"
31#include "jfr/writers/jfrEncoding.hpp"
32#include "jfr/writers/jfrWriterHost.hpp"
33#include "memory/resourceArea.hpp"
34#include "oops/oop.hpp"
35#include "oops/symbol.hpp"
36#include "oops/typeArrayOop.inline.hpp"
37
38inline bool compressed_integers() {
39 static const bool comp_integers = JfrOptionSet::compressed_integers();
40 return comp_integers;
41}
42
43template <typename BE, typename IE, typename WriterPolicyImpl >
44template <typename T>
45inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded(T value) {
46 write_padded(&value, 1);
47}
48
49template <typename BE, typename IE, typename WriterPolicyImpl >
50template <typename T>
51inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded(const T* value, size_t len) {
52 assert(value != NULL, "invariant");
53 assert(len > 0, "invariant");
54 u1* const pos = ensure_size(sizeof(T) * len);
55 if (pos) {
56 this->set_current_pos(write_padded(value, len, pos));
57 }
58}
59
60template <typename BE, typename IE, typename WriterPolicyImpl >
61template <typename T>
62inline u1* WriterHost<BE, IE, WriterPolicyImpl>::write_padded(const T* value, size_t len, u1* pos) {
63 assert(value != NULL, "invariant");
64 assert(len > 0, "invariant");
65 assert(pos != NULL, "invariant");
66 return _compressed_integers ? IE::write_padded(value, len, pos) : BE::write_padded(value, len, pos);
67}
68
69template <typename BE, typename IE, typename WriterPolicyImpl >
70template <typename T>
71inline void WriterHost<BE, IE, WriterPolicyImpl>::write(const T* value, size_t len) {
72 assert(value != NULL, "invariant");
73 assert(len > 0, "invariant");
74 u1* const pos = ensure_size(sizeof(T) * len);
75 if (pos) {
76 this->set_current_pos(write(value, len, pos));
77 }
78}
79
80template <typename BE, typename IE, typename WriterPolicyImpl >
81template <typename T>
82inline u1* WriterHost<BE, IE, WriterPolicyImpl>::write(const T* value, size_t len, u1* pos) {
83 assert(value != NULL, "invariant");
84 assert(len > 0, "invariant");
85 assert(pos != NULL, "invariant");
86 return _compressed_integers ? IE::write(value, len, pos) : BE::write(value, len, pos);
87}
88
89template <typename BE, typename IE, typename WriterPolicyImpl>
90void WriterHost<BE, IE, WriterPolicyImpl>::write_utf8(const char* value) {
91 if (NULL == value) {
92 // only write encoding byte indicating NULL string
93 write<u1>(NULL_STRING);
94 return;
95 }
96 write<u1>(UTF8); // designate encoding
97 const jint len = MIN2<jint>(max_jint, (jint)strlen(value));
98 write(len);
99 if (len > 0) {
100 be_write(value, len);
101 }
102}
103
104template <typename BE, typename IE, typename WriterPolicyImpl>
105void WriterHost<BE, IE, WriterPolicyImpl>::write_utf16(const jchar* value, jint len) {
106 assert(value != NULL, "invariant");
107 write((u1)UTF16); // designate encoding
108 write(len);
109 if (len > 0) {
110 write(value, len);
111 }
112}
113
114template <typename BE, typename IE, typename WriterPolicyImpl >
115template <typename T>
116inline void WriterHost<BE, IE, WriterPolicyImpl>::be_write(T value) {
117 u1* const pos = ensure_size(sizeof(T));
118 if (pos) {
119 this->set_current_pos(BE::be_write(&value, 1, pos));
120 }
121}
122
123template <typename BE, typename IE, typename WriterPolicyImpl >
124template <typename T>
125inline void WriterHost<BE, IE, WriterPolicyImpl>::be_write(const T* value, size_t len) {
126 assert(value != NULL, "invariant");
127 assert(len > 0, "invariant");
128 u1* const pos = ensure_size(sizeof(T) * len);
129 if (pos) {
130 this->set_current_pos(BE::be_write(value, len, pos));
131 }
132}
133
134template <typename BE, typename IE, typename WriterPolicyImpl >
135template <typename StorageType>
136inline WriterHost<BE, IE, WriterPolicyImpl>::WriterHost(StorageType* storage, Thread* thread) :
137 WriterPolicyImpl(storage, thread),
138 _compressed_integers(compressed_integers()) {
139}
140
141template <typename BE, typename IE, typename WriterPolicyImpl >
142template <typename StorageType>
143inline WriterHost<BE, IE, WriterPolicyImpl>::WriterHost(StorageType* storage, size_t size) :
144 WriterPolicyImpl(storage, size),
145 _compressed_integers(compressed_integers()) {
146}
147
148template <typename BE, typename IE, typename WriterPolicyImpl >
149inline WriterHost<BE, IE, WriterPolicyImpl>::WriterHost(Thread* thread) :
150 WriterPolicyImpl(thread),
151 _compressed_integers(compressed_integers()) {
152}
153
154// Extra size added as a safety cushion when dimensioning memory.
155// With varint encoding, the worst case is
156// associated with writing negative values.
157// For example, writing a negative s1 (-1)
158// will encode as 0xff 0x0f (2 bytes).
159// In this example, the sizeof(T) == 1 and length == 1,
160// but the implementation will need to dimension
161// 2 bytes for the encoding.
162// Hopefully, negative values should be relatively rare.
163static const size_t size_safety_cushion = 1;
164
165template <typename BE, typename IE, typename WriterPolicyImpl>
166inline u1* WriterHost<BE, IE, WriterPolicyImpl>::ensure_size(size_t requested) {
167 if (!this->is_valid()) {
168 // cancelled
169 return NULL;
170 }
171 if (this->available_size() < requested + size_safety_cushion) {
172 if (!this->accommodate(this->used_size(), requested + size_safety_cushion)) {
173 this->cancel();
174 return NULL;
175 }
176 }
177 assert(requested + size_safety_cushion <= this->available_size(), "invariant");
178 return this->current_pos();
179}
180
181template <typename BE, typename IE, typename WriterPolicyImpl>
182template <typename T>
183inline void WriterHost<BE, IE, WriterPolicyImpl>::write(T value) {
184 write(&value, 1);
185}
186
187template <typename BE, typename IE, typename WriterPolicyImpl>
188inline void WriterHost<BE, IE, WriterPolicyImpl>::write(bool value) {
189 be_write((u1)value);
190}
191
192template <typename BE, typename IE, typename WriterPolicyImpl>
193inline void WriterHost<BE, IE, WriterPolicyImpl>::write(float value) {
194 be_write(*(u4*)&(value));
195}
196
197template <typename BE, typename IE, typename WriterPolicyImpl>
198inline void WriterHost<BE, IE, WriterPolicyImpl>::write(double value) {
199 be_write(*(u8*)&(value));
200}
201
202template <typename BE, typename IE, typename WriterPolicyImpl>
203inline void WriterHost<BE, IE, WriterPolicyImpl>::write(const char* value) {
204 // UTF-8, max_jint len
205 write_utf8(value);
206}
207
208template <typename BE, typename IE, typename WriterPolicyImpl>
209inline void WriterHost<BE, IE, WriterPolicyImpl>::write(char* value) {
210 write(const_cast<const char*>(value));
211}
212
213template <typename BE, typename IE, typename WriterPolicyImpl>
214inline void WriterHost<BE, IE, WriterPolicyImpl>::write(jstring string) {
215 if (string == NULL) {
216 write<u1>(NULL_STRING);
217 return;
218 }
219 const oop string_oop = JNIHandles::resolve_external_guard(string);
220 assert(string_oop != NULL, "invariant");
221 const size_t length = (size_t)java_lang_String::length(string_oop);
222 if (0 == length) {
223 write<u1>(EMPTY_STRING);
224 return;
225 }
226 const bool is_latin1_encoded = java_lang_String::is_latin1(string_oop);
227 const typeArrayOop value = java_lang_String::value(string_oop);
228 assert(value != NULL, "invariant");
229 if (is_latin1_encoded) {
230 write<u1>(LATIN1);
231 write<u4>((u4)length);
232 be_write(value->byte_at_addr(0), length);
233 } else {
234 write<u1>(UTF16);
235 write<u4>((u4)length);
236 write(value->char_at_addr(0), length);
237 }
238}
239
240template <typename Writer, typename T>
241inline void tag_write(Writer* w, const T* t) {
242 assert(w != NULL, "invariant");
243 const traceid id = t == NULL ? 0 : JfrTraceId::use(t);
244 w->write(id);
245}
246
247template <typename BE, typename IE, typename WriterPolicyImpl>
248void WriterHost<BE, IE, WriterPolicyImpl>::write(const ClassLoaderData* cld) {
249 tag_write(this, cld);
250}
251
252template <typename BE, typename IE, typename WriterPolicyImpl>
253void WriterHost<BE, IE, WriterPolicyImpl>::write(const Klass* klass) {
254 tag_write(this, klass);
255}
256
257template <typename BE, typename IE, typename WriterPolicyImpl>
258void WriterHost<BE, IE, WriterPolicyImpl>::write(const Method* method) {
259 tag_write(this, method);
260}
261
262template <typename BE, typename IE, typename WriterPolicyImpl>
263void WriterHost<BE, IE, WriterPolicyImpl>::write(const ModuleEntry* module) {
264 tag_write(this, module);
265}
266
267template <typename BE, typename IE, typename WriterPolicyImpl>
268void WriterHost<BE, IE, WriterPolicyImpl>::write(const PackageEntry* package) {
269 tag_write(this, package);
270}
271
272template <typename BE, typename IE, typename WriterPolicyImpl>
273void WriterHost<BE, IE, WriterPolicyImpl>::write(const Symbol* symbol) {
274 ResourceMark rm;
275 write_utf8(symbol != NULL ? symbol->as_C_string() : NULL);
276}
277
278template <typename BE, typename IE, typename WriterPolicyImpl>
279void WriterHost<BE, IE, WriterPolicyImpl>::write(const Ticks& time) {
280 write((uintptr_t)JfrTime::is_ft_enabled() ? time.ft_value() : time.value());
281}
282
283template <typename BE, typename IE, typename WriterPolicyImpl>
284void WriterHost<BE, IE, WriterPolicyImpl>::write(const Tickspan& time) {
285 write((uintptr_t)JfrTime::is_ft_enabled() ? time.ft_value() : time.value());
286}
287
288template <typename BE, typename IE, typename WriterPolicyImpl>
289void WriterHost<BE, IE, WriterPolicyImpl>::write(const JfrTicks& time) {
290 write((uintptr_t)time.value());
291}
292
293template <typename BE, typename IE, typename WriterPolicyImpl>
294void WriterHost<BE, IE, WriterPolicyImpl>::write(const JfrTickspan& time) {
295 write((uintptr_t)time.value());
296}
297
298template <typename BE, typename IE, typename WriterPolicyImpl>
299void WriterHost<BE, IE, WriterPolicyImpl>::bytes(const void* buf, size_t len) {
300 u1* const pos = this->ensure_size(len);
301 if (pos != NULL) {
302 WriterPolicyImpl::bytes(pos, buf, len); // WriterPolicyImpl responsible for position update
303 }
304}
305
306// UTF-8 for use with classfile/bytecodes
307template <typename BE, typename IE, typename WriterPolicyImpl>
308inline void WriterHost<BE, IE, WriterPolicyImpl>::write_utf8_u2_len(const char* value) {
309 u2 len = 0;
310 if (value != NULL) {
311 len = MIN2<u2>(max_jushort, (u2)strlen(value));
312 }
313 write(len);
314 if (len > 0) {
315 be_write(value, len);
316 }
317}
318
319template <typename BE, typename IE, typename WriterPolicyImpl>
320inline int64_t WriterHost<BE, IE, WriterPolicyImpl>::reserve(size_t size) {
321 if (ensure_size(size) != NULL) {
322 const int64_t reserved_offset = this->current_offset();
323 this->set_current_pos(size);
324 return reserved_offset;
325 }
326 this->cancel();
327 return 0;
328}
329
330template <typename BE, typename IE, typename WriterPolicyImpl>
331template <typename T>
332inline void WriterHost<BE, IE, WriterPolicyImpl>::write_padded_at_offset(T value, int64_t offset) {
333 if (this->is_valid()) {
334 const int64_t current = this->current_offset();
335 this->seek(offset);
336 write_padded(value);
337 this->seek(current); // restore
338 }
339}
340
341template <typename BE, typename IE, typename WriterPolicyImpl>
342template <typename T>
343inline void WriterHost<BE, IE, WriterPolicyImpl>::write_at_offset(T value, int64_t offset) {
344 if (this->is_valid()) {
345 const int64_t current = this->current_offset();
346 this->seek(offset);
347 write(value);
348 this->seek(current); // restore
349 }
350}
351
352template <typename BE, typename IE, typename WriterPolicyImpl>
353template <typename T>
354inline void WriterHost<BE, IE, WriterPolicyImpl>::write_be_at_offset(T value, int64_t offset) {
355 if (this->is_valid()) {
356 const int64_t current = this->current_offset();
357 this->seek(offset);
358 be_write(value);
359 this->seek(current); // restore
360 }
361}
362
363#endif // SHARE_JFR_WRITERS_JFRWRITERHOST_INLINE_HPP
364