Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/shared/Util.java
41161 views
1
/*
2
* Copyright (c) 2013, 2021, 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
package vm.runtime.defmeth.shared;
25
26
import vm.runtime.defmeth.shared.data.Clazz;
27
import java.io.PrintWriter;
28
import java.lang.instrument.ClassFileTransformer;
29
import java.lang.instrument.IllegalClassFormatException;
30
import java.lang.instrument.Instrumentation;
31
import java.lang.instrument.UnmodifiableClassException;
32
import java.security.ProtectionDomain;
33
import java.util.ArrayList;
34
import java.util.Arrays;
35
import java.util.List;
36
import java.util.regex.Matcher;
37
import java.util.regex.Pattern;
38
import nsk.share.Pair;
39
import nsk.share.TestFailure;
40
import vm.runtime.defmeth.shared.data.method.param.*;
41
42
43
/**
44
* Utility class with auxiliary miscellaneous methods.
45
*/
46
public class Util {
47
public static class Transformer {
48
private static Instrumentation inst;
49
50
public static void premain(String agentArgs, Instrumentation inst) {
51
Transformer.inst = inst;
52
53
/*
54
inst.addTransformer(new ClassFileTransformer() {
55
@Override
56
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
57
System.out.println("Retransform (initial): " + className);
58
return classfileBuffer;
59
}
60
});
61
*/
62
}
63
}
64
65
/**
66
* Concatenate {@code strings} array interleaving with {@code sep} in between.
67
*
68
* @param sep
69
* @param strings
70
* @return
71
*/
72
public static String intersperse(String sep, String... strings) {
73
StringBuilder sb = new StringBuilder();
74
if (strings.length == 0) {
75
return "";
76
} else if (strings.length == 1) {
77
return strings[0];
78
} else {
79
sb.append(strings[0]);
80
81
for (int i=1; i<strings.length; i++) {
82
sb.append(sep).append(strings[i]);
83
}
84
85
return sb.toString();
86
}
87
}
88
89
/**
90
* Construct array of names for an array of {@code Clazz} instances.
91
*
92
* @param clazzes
93
* @return
94
*/
95
public static String[] asStrings(Clazz[] clazzes) {
96
String[] result = new String[clazzes.length];
97
for (int i = 0; i < clazzes.length; i++) {
98
result[i] = clazzes[i].intlName();
99
}
100
101
return result;
102
}
103
104
/**
105
* Get the name of the test currently being executed
106
*
107
* @return name of the test being executed
108
*/
109
public static String getTestName() {
110
// Hack: examine stack trace and extract test method's name from there
111
try {
112
throw new Exception();
113
} catch (Exception e) {
114
for (StackTraceElement elem : e.getStackTrace()) {
115
String className = elem.getClassName();
116
String methodName = elem.getMethodName();
117
118
if (className.startsWith("vm.runtime.defmeth.") &&
119
methodName.startsWith("test")) {
120
return String.format("%s.%s",
121
className.replaceAll(".*\\.", ""), methodName);
122
}
123
}
124
125
return "Unknown";
126
}
127
}
128
129
/**
130
* Pretty-print {@code byte[] classFile} to stdout.
131
*
132
* @param classFile
133
*/
134
public static void printClassFile(byte[] classFile) {
135
int flags = jdk.internal.org.objectweb.asm.ClassReader.SKIP_DEBUG;
136
137
classFile = classFile.clone();
138
139
jdk.internal.org.objectweb.asm.ClassReader cr =
140
new jdk.internal.org.objectweb.asm.ClassReader(classFile);
141
142
cr.accept(new jdk.internal.org.objectweb.asm.util.TraceClassVisitor(new PrintWriter(System.out)), flags);
143
}
144
145
/**
146
* Print ASM version (sequence of calls to ASM API to produce same class file)
147
* of {@code classFile} to stdout.
148
*
149
* @param classFile
150
*/
151
public static void asmifyClassFile(byte[] classFile) {
152
int flags = jdk.internal.org.objectweb.asm.ClassReader.SKIP_DEBUG;
153
154
jdk.internal.org.objectweb.asm.ClassReader cr =
155
new jdk.internal.org.objectweb.asm.ClassReader(classFile);
156
157
//cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), flags);
158
cr.accept(new jdk.internal.org.objectweb.asm.util.TraceClassVisitor(null,
159
new jdk.internal.org.objectweb.asm.util.ASMifier(),
160
new PrintWriter(System.out)), flags);
161
}
162
163
/**
164
* Parse method descriptor and split it into parameter types names and
165
* return type name.
166
*
167
* @param desc
168
* @return {@code Pair} of parameter types names and
169
*/
170
public static Pair<String[],String> parseDesc(String desc) {
171
Pattern p = Pattern.compile("\\((.*)\\)(.*)");
172
Matcher m = p.matcher(desc);
173
174
if (m.matches()) {
175
String opts = m.group(1);
176
String returnVal = m.group(2);
177
178
return Pair.of(parseParams(opts), returnVal);
179
} else {
180
throw new IllegalArgumentException(desc);
181
}
182
183
}
184
185
/**
186
* Check whether a type isn't Void by it's name.
187
*
188
* @param type return type name
189
* @return
190
*/
191
public static boolean isNonVoid(String type) {
192
return !("V".equals(type));
193
}
194
195
/**
196
* Split a sequence of type names (in VM internal form).
197
*
198
* Example:
199
* "BCD[[ALA;I" => [ "B", "C", "D", "[[A", "LA;", "I" ]
200
*
201
* @param str
202
* @return
203
*/
204
public static String[] parseParams(String str) {
205
List<String> params = new ArrayList<>();
206
207
/* VM basic type notation:
208
B byte signed byte
209
C char Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16
210
D double double-precision floating-point value
211
F float single-precision floating-point value
212
I int integer
213
J long long integer
214
L Classname ; reference an instance of class Classname
215
S short signed short
216
Z boolean true or false
217
[ reference one array dimension
218
*/
219
int i = 0;
220
int start = 0;
221
while (i < str.length()) {
222
char c = str.charAt(i);
223
switch (c) {
224
case 'B': case 'C': case 'D': case 'F':
225
case 'I': case 'J': case 'S': case 'Z':
226
params.add(str.substring(start, i+1));
227
start = i+1;
228
break;
229
case 'L':
230
int k = str.indexOf(';', i);
231
if (k != 1) {
232
params.add(str.substring(start, k+1));
233
start = k+1;
234
i = k;
235
} else {
236
throw new IllegalArgumentException(str);
237
}
238
break;
239
case '[':
240
break;
241
default:
242
throw new IllegalArgumentException(
243
String.format("%d(%d): %c \'%s\'", i, start, c, str));
244
}
245
246
i++;
247
}
248
249
if (start != str.length()) {
250
throw new IllegalArgumentException(str);
251
}
252
253
return params.toArray(new String[0]);
254
}
255
256
/**
257
* Returns default values for different types:
258
* - byte: 0
259
* - short: 0
260
* - int: 0
261
* - long: 0L
262
* - char: \U0000
263
* - boolean: false
264
* - float: 0.0f
265
* - double: 0.0d
266
* - array: null
267
* - Object: null
268
*
269
* @param types
270
* @return
271
*/
272
public static Param[] getDefaultValues(String[] types) {
273
List<Param> values = new ArrayList<>();
274
275
for (String type : types) {
276
switch (type) {
277
case "I": case "B": case "C": case "Z": case "S":
278
values.add(new IntParam(0));
279
break;
280
case "J":
281
values.add(new LongParam(0L));
282
break;
283
case "D":
284
values.add(new DoubleParam(0.0d));
285
break;
286
case "F":
287
values.add(new FloatParam(0.0f));
288
break;
289
default:
290
if (type.startsWith("L") || type.startsWith("[")) {
291
values.add(new NullParam());
292
} else {
293
throw new IllegalArgumentException(Arrays.toString(types));
294
}
295
break;
296
}
297
}
298
299
return values.toArray(new Param[0]);
300
}
301
302
/**
303
* Decode class name from internal VM representation into normal Java name.
304
* Internal class naming convention is extensively used to describe method type (descriptor).
305
*
306
* Examples:
307
* "Ljava/lang/Object" => "java.lang.Object"
308
* "I" => "int"
309
* "[[[C" => "char[][][]"
310
*
311
* @param name
312
* @return
313
*/
314
public static String decodeClassName(String name) {
315
switch (name) {
316
case "Z": return "boolean";
317
case "B": return "byte";
318
case "S": return "short";
319
case "C": return "char";
320
case "I": return "int";
321
case "J": return "long";
322
case "F": return "float";
323
case "D": return "double";
324
default:
325
if (name.startsWith("L")) {
326
// "Ljava/lang/String;" => "java.lang.String"
327
return name.substring(1, name.length()-1).replaceAll("/", ".");
328
} else if (name.startsWith("[")) {
329
// "[[[C" => "char[][][]"
330
return decodeClassName(name.substring(1)) + "[]";
331
} else {
332
throw new IllegalArgumentException(name);
333
}
334
}
335
}
336
337
/**
338
* Decode class name from internal VM format into regular name and resolve it using {@code cl} {@code ClassLoader}.
339
* It is used during conversion of method type from string representation to strongly typed variants (e.g. MethodType).
340
*
341
* @param name
342
* @param cl
343
* @return
344
*/
345
public static Class decodeClass(String name, ClassLoader cl) {
346
switch (name) {
347
case "Z": return boolean.class;
348
case "B": return byte.class;
349
case "S": return short.class;
350
case "C": return char.class;
351
case "I": return int.class;
352
case "J": return long.class;
353
case "F": return float.class;
354
case "D": return double.class;
355
case "V": return void.class;
356
default:
357
if (name.startsWith("L")) {
358
// "Ljava/lang/String;" => "java.lang.String"
359
String decodedName = name.substring(1, name.length()-1).replaceAll("/", ".");
360
try {
361
return cl.loadClass(decodedName);
362
} catch (Exception e) {
363
throw new Error(e);
364
}
365
} else if (name.startsWith("[")) {
366
// "[[[C" => "char[][][]"
367
//return decodeClassName(name.substring(1)) + "[]";
368
throw new UnsupportedOperationException("Resolution of arrays isn't supported yet: "+name);
369
} else {
370
throw new IllegalArgumentException(name);
371
}
372
}
373
}
374
375
/**
376
* Redefine a class with a new version.
377
*
378
* @param clz class for redefinition
379
*/
380
static public void retransformClass(final Class<?> clz, final byte[] classFile) {
381
ClassFileTransformer transformer = new ClassFileTransformer() {
382
@Override
383
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
384
if (clz.getClassLoader() == loader && className.equals(clz.getName())) {
385
if (Constants.TRACE_CLASS_REDEF) System.out.println("RETRANSFORM: " + className);
386
387
return classFile;
388
} else {
389
// leave the class as-is
390
return classfileBuffer;
391
}
392
}
393
};
394
395
Transformer.inst.addTransformer(transformer, true);
396
try {
397
Transformer.inst.retransformClasses(clz);
398
} catch (UnmodifiableClassException e) {
399
throw new TestFailure(e);
400
} finally {
401
Transformer.inst.removeTransformer(transformer);
402
}
403
}
404
405
/**
406
* Redefine a class with a new version (class file in byte array).
407
*
408
* @param clz class for redefinition
409
* @param classFile new version as a byte array
410
* @return false if any errors occurred during class redefinition
411
*/
412
static public void redefineClass(Class<?> clz, byte[] classFile) {
413
if (clz == null) {
414
throw new IllegalArgumentException("clz == null");
415
}
416
417
if (classFile == null || classFile.length == 0) {
418
throw new IllegalArgumentException("Incorrect classFile");
419
}
420
421
if (Constants.TRACE_CLASS_REDEF) System.out.println("REDEFINE: "+clz.getName());
422
423
if (!redefineClassIntl(clz, classFile)) {
424
throw new TestFailure("redefineClass failed: "+clz.getName());
425
}
426
}
427
428
429
native static public boolean redefineClassIntl(Class<?> clz, byte[] classFile);
430
431
/**
432
* Get VM internal name of {@code Class<?> clz}.
433
*
434
* @param clz
435
* @return
436
*/
437
public static String getInternalName(Class<?> clz) {
438
if (!clz.isPrimitive()) {
439
return clz.getName().replaceAll("\\.", "/");
440
} else {
441
throw new UnsupportedOperationException();
442
}
443
}
444
}
445
446