Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/codert_vm/thunkcrt.c
5986 views
1
/*******************************************************************************
2
* Copyright (c) 1991, 2020 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include "j9.h"
24
#include "j9protos.h"
25
#include "jitprotos.h"
26
#include "ut_j9codertvm.h"
27
#include <string.h>
28
29
#undef DEBUG
30
31
/* Note these values must all be odd since the encoded bytes overlay a pointer field in the hash table entry where we use low-tag to indicate an inline encoding */
32
33
#define J9_THUNK_TYPE_VOID 1
34
#define J9_THUNK_TYPE_INT 3
35
#define J9_THUNK_TYPE_LONG 5
36
#define J9_THUNK_TYPE_FLOAT 7
37
#define J9_THUNK_TYPE_DOUBLE 9
38
#define J9_THUNK_TYPE_OBJECT 11
39
#define J9_THUNK_TYPE_UNUSED 13
40
#define J9_THUNK_TYPE_FILL 15
41
42
/* This value should be a multiple of 8 bytes (to maintain pointer alignment).
43
*
44
* Also note that the value must be smaller than 64 (128 types) so that argCount * 2 +
45
* may be stored in the inline argCount byte.
46
*/
47
48
#define J9_THUNK_INLINE_ENCODING_BYTES 8
49
50
/* 4 bits per arg + 4 bits return type, rounded up to nearest byte */
51
52
#define J9_THUNK_ENCODED_SIGNATURE_LENGTH(argCount) ((((U_32) (argCount)) + 1 + 1) / 2)
53
54
/* Encoding format is:
55
*
56
* 1 byte argCount
57
* 128 bytes encoded bytes (up to 255 args + 1 return type)
58
*/
59
60
#define J9_THUNK_MAX_ENCODED_BYTES 129
61
62
typedef struct J9ThunkTableEntry {
63
void * thunkAddress;
64
union {
65
U_8 * outOfLineBytes;
66
U_8 inlineBytes[J9_THUNK_INLINE_ENCODING_BYTES];
67
} encodedSignature;
68
} J9ThunkTableEntry;
69
70
#define J9_THUNK_BYTES_ARE_INLINE(entry) (((UDATA) ((entry)->encodedSignature.outOfLineBytes)) & 1)
71
72
#if defined(J9ZOS390)
73
extern void icallVMprJavaSendVirtual0();
74
extern void icallVMprJavaSendVirtual1();
75
extern void icallVMprJavaSendVirtualJ();
76
extern void icallVMprJavaSendVirtualF();
77
extern void icallVMprJavaSendVirtualD();
78
#if defined(J9VM_ENV_DATA64)
79
extern void icallVMprJavaSendVirtualL();
80
#endif
81
extern void icallVMprJavaSendInvokeExact0();
82
extern void icallVMprJavaSendInvokeExact1();
83
extern void icallVMprJavaSendInvokeExactJ();
84
extern void icallVMprJavaSendInvokeExactF();
85
extern void icallVMprJavaSendInvokeExactD();
86
extern void icallVMprJavaSendInvokeExactL();
87
#else
88
extern void * icallVMprJavaSendVirtual0;
89
extern void * icallVMprJavaSendVirtual1;
90
extern void * icallVMprJavaSendVirtualJ;
91
extern void * icallVMprJavaSendVirtualF;
92
extern void * icallVMprJavaSendVirtualD;
93
#if defined(J9VM_ENV_DATA64)
94
extern void * icallVMprJavaSendVirtualL;
95
#endif
96
extern void * icallVMprJavaSendInvokeExact0;
97
extern void * icallVMprJavaSendInvokeExact1;
98
extern void * icallVMprJavaSendInvokeExactJ;
99
extern void * icallVMprJavaSendInvokeExactF;
100
extern void * icallVMprJavaSendInvokeExactD;
101
extern void * icallVMprJavaSendInvokeExactL;
102
#endif
103
104
static U_8 j9ThunkGetEncodedSignature(J9ThunkTableEntry * entry, U_8 ** encodedSignaturePtr);
105
static UDATA j9ThunkEncodeSignature(char *signatureData, U_8 * encodedSignature);
106
static UDATA j9ThunkTableHash(void *key, void *userData);
107
static UDATA j9ThunkTableEquals(void *leftKey, void *rightKey, void *userData);
108
109
110
void *
111
j9ThunkLookupNameAndSig(void * jitConfig, void *parm)
112
{
113
void * thunkAddress = NULL;
114
J9ROMNameAndSignature *nameAndSignature = (J9ROMNameAndSignature *) parm;
115
116
Trc_Thunk_j9ThunkLookupNameAndSig_Entry();
117
118
thunkAddress = j9ThunkLookupSignature(jitConfig, J9UTF8_LENGTH(J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature)), (char *) J9UTF8_DATA((J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature))));
119
120
if (NULL == thunkAddress) {
121
Trc_Thunk_j9ThunkLookupNameAndSig_Exit_ThunkNotFound();
122
} else {
123
Trc_Thunk_j9ThunkLookupNameAndSig_Exit_Success(thunkAddress);
124
}
125
126
return thunkAddress;
127
}
128
129
UDATA
130
j9ThunkTableAllocate(J9JavaVM * vm)
131
{
132
J9JITConfig * jitConfig = vm->jitConfig;
133
134
if (omrthread_monitor_init_with_name(&jitConfig->thunkHashTableMutex, 0, "JIT thunk table")) {
135
return 1;
136
}
137
138
jitConfig->thunkHashTable = hashTableNew(
139
OMRPORT_FROM_J9PORT(vm->portLibrary), /* portLibrary */
140
J9_GET_CALLSITE(), /* tableName */
141
0, /* tableSize */
142
sizeof(J9ThunkTableEntry), /* entrySize */
143
0, /* entryAlignment */
144
0, /* flags */
145
OMRMEM_CATEGORY_JIT, /* memoryCategory */
146
j9ThunkTableHash, /* hashFn */
147
j9ThunkTableEquals, /* hashEqualFn */
148
NULL, /* printFn */
149
NULL /* functionUserData */
150
);
151
152
return jitConfig->thunkHashTable == NULL;
153
}
154
155
void
156
j9ThunkTableFree(J9JavaVM * vm)
157
{
158
J9JITConfig * jitConfig = vm->jitConfig;
159
160
if (jitConfig->thunkHashTable != NULL) {
161
PORT_ACCESS_FROM_JAVAVM(vm);
162
J9HashTableState state;
163
J9ThunkTableEntry * entry;
164
165
entry = hashTableStartDo(jitConfig->thunkHashTable, &state);
166
while (entry != NULL) {
167
if (!J9_THUNK_BYTES_ARE_INLINE(entry)) {
168
j9mem_free_memory(entry->encodedSignature.outOfLineBytes);
169
}
170
entry = hashTableNextDo(&state);
171
}
172
hashTableFree(jitConfig->thunkHashTable);
173
jitConfig->thunkHashTable = NULL;
174
}
175
176
if (jitConfig->thunkHashTableMutex != NULL) {
177
omrthread_monitor_destroy(jitConfig->thunkHashTableMutex);
178
jitConfig->thunkHashTableMutex = NULL;
179
}
180
}
181
182
static UDATA
183
j9ThunkTableHash(void *key, void *userData)
184
{
185
U_8 * encodedSignature;
186
U_8 argCount;
187
188
argCount = j9ThunkGetEncodedSignature(key, &encodedSignature);
189
return j9crc32(0, encodedSignature + 1, J9_THUNK_ENCODED_SIGNATURE_LENGTH(argCount));
190
}
191
static UDATA
192
j9ThunkTableEquals(void *leftKey, void *rightKey, void *userData)
193
{
194
U_8 * leftSig;
195
U_8 * rightSig;
196
U_8 leftArgCount = j9ThunkGetEncodedSignature(leftKey, &leftSig);
197
U_8 rightArgCount = j9ThunkGetEncodedSignature(rightKey, &rightSig);
198
199
if (leftArgCount != rightArgCount) {
200
return FALSE;
201
}
202
203
return memcmp(leftSig + 1, rightSig + 1, J9_THUNK_ENCODED_SIGNATURE_LENGTH(leftArgCount)) == 0;
204
}
205
void *
206
j9ThunkLookupSignature(void * jitConfig, UDATA signatureLength, char *signatureChars)
207
{
208
J9ThunkTableEntry exemplar;
209
J9ThunkTableEntry * entry;
210
U_8 encodedSignatureArray[J9_THUNK_MAX_ENCODED_BYTES + 1];
211
U_8* encodedSignature = encodedSignatureArray;
212
213
if ((UDATA)encodedSignature & (UDATA)1) {
214
/* J9_THUNK_BYTES_ARE_INLINE() needs encodedSignature to be even */
215
encodedSignature++;
216
}
217
218
j9ThunkEncodeSignature(signatureChars, encodedSignature);
219
exemplar.encodedSignature.outOfLineBytes = encodedSignature;
220
221
omrthread_monitor_enter(((J9JITConfig *) jitConfig)->thunkHashTableMutex);
222
entry = hashTableFind(((J9JITConfig *) jitConfig)->thunkHashTable, &exemplar);
223
omrthread_monitor_exit(((J9JITConfig *) jitConfig)->thunkHashTableMutex);
224
if (entry != NULL ) {
225
return entry->thunkAddress;
226
}
227
228
return NULL;
229
}
230
231
IDATA
232
j9ThunkNewNameAndSig(void * jitConfig, void *parm, void *thunkAddress)
233
{
234
J9ROMNameAndSignature *nameAndSignature = (J9ROMNameAndSignature *) parm;
235
236
return j9ThunkNewSignature(jitConfig, J9UTF8_LENGTH(J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature)), (char *) J9UTF8_DATA((J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature))), thunkAddress);
237
}
238
239
IDATA
240
j9ThunkNewSignature(void * jitConfig, int signatureLength, char *signatureChars, void *thunkAddress)
241
{
242
PORT_ACCESS_FROM_JAVAVM(((J9JITConfig *) jitConfig)->javaVM);
243
J9ThunkTableEntry exemplar;
244
J9ThunkTableEntry * entry;
245
U_8 encodedSignatureArray[J9_THUNK_MAX_ENCODED_BYTES + 1];
246
U_8* encodedSignature = encodedSignatureArray;
247
UDATA length;
248
249
if ((UDATA)encodedSignature & (UDATA)1) {
250
/* J9_THUNK_BYTES_ARE_INLINE() needs encodedSignature to be even */
251
encodedSignature++;
252
}
253
254
length = j9ThunkEncodeSignature(signatureChars, encodedSignature);
255
256
/* J9_THUNK_TYPE_FILL * 0x11 puts J9_THUNK_TYPE_FILL * 0x11 in both nybbles */
257
memset(exemplar.encodedSignature.inlineBytes, J9_THUNK_TYPE_FILL * 0x11, sizeof(exemplar.encodedSignature));
258
259
if (length > J9_THUNK_INLINE_ENCODING_BYTES) {
260
U_8 * allocatedSignature = j9mem_allocate_memory(length, OMRMEM_CATEGORY_JIT);
261
262
#ifdef DEBUG
263
printf("allocating bytes\n");
264
#endif
265
266
if (allocatedSignature == NULL) {
267
return -1;
268
}
269
270
memcpy(allocatedSignature, encodedSignature, length);
271
exemplar.encodedSignature.outOfLineBytes = allocatedSignature;
272
} else {
273
/* Inline encoding bytes must all be odd - multiply argCount by 2 and add 1 to make it odd */
274
encodedSignature[0] = encodedSignature[0] * 2 + 1;
275
276
memcpy(exemplar.encodedSignature.inlineBytes, encodedSignature, length);
277
}
278
exemplar.thunkAddress = thunkAddress;
279
280
omrthread_monitor_enter(((J9JITConfig *) jitConfig)->thunkHashTableMutex);
281
entry = hashTableAdd(((J9JITConfig *) jitConfig)->thunkHashTable, &exemplar);
282
omrthread_monitor_exit(((J9JITConfig *) jitConfig)->thunkHashTableMutex);
283
if (entry == NULL) {
284
if (!J9_THUNK_BYTES_ARE_INLINE(&exemplar)) {
285
j9mem_free_memory(exemplar.encodedSignature.outOfLineBytes);
286
}
287
return -1;
288
} else {
289
if (!J9_THUNK_BYTES_ARE_INLINE(&exemplar)) {
290
if (exemplar.encodedSignature.outOfLineBytes != entry->encodedSignature.outOfLineBytes) {
291
/* Existing entry was found in the table */
292
j9mem_free_memory(exemplar.encodedSignature.outOfLineBytes);
293
}
294
}
295
}
296
297
return 0;
298
}
299
300
/* Returns the total number of bytes used in the encodedSignature buffer */
301
302
static UDATA
303
j9ThunkEncodeSignature(char *signatureData, U_8 * encodedSignature)
304
{
305
U_8 * encodedTypes = encodedSignature + 1;
306
U_8 argCount = 0;
307
U_8 encodedTypeByte = 0;
308
UDATA encodedTypeByteStored = TRUE;
309
UDATA done = FALSE;
310
UDATA totalSize;
311
#ifdef DEBUG
312
char * origSig = signatureData;
313
UDATA i;
314
#endif
315
316
/* Skip opening bracket */
317
++signatureData;
318
319
/* Encode the signature (including return type), considering like types to be identical */
320
321
do {
322
char c = *signatureData++;
323
U_8 encodedType;
324
325
/* Include the return type in the encoding, but do not increment the argCount for it */
326
327
if (c == ')') {
328
done = TRUE;
329
c = *signatureData++;
330
} else {
331
++argCount;
332
}
333
334
/* Consume signature element and convert to canonical type */
335
336
switch (c) {
337
case 'V':
338
encodedType = J9_THUNK_TYPE_VOID;
339
break;
340
case 'F':
341
encodedType = J9_THUNK_TYPE_FLOAT;
342
break;
343
case 'D':
344
encodedType = J9_THUNK_TYPE_DOUBLE;
345
break;
346
case 'J':
347
encodedType = J9_THUNK_TYPE_LONG;
348
break;
349
case '[':
350
while ((c = *signatureData++) == '[') ;
351
/* intentional fall-through */
352
case 'L':
353
if (c == 'L') {
354
while (*signatureData++ != ';') ;
355
}
356
#if defined(J9VM_ENV_DATA64)
357
encodedType = J9_THUNK_TYPE_OBJECT;
358
break;
359
#endif
360
/* intentional fall-through */
361
default:
362
encodedType = J9_THUNK_TYPE_INT;
363
break;
364
}
365
366
/* Store encoded value into nybble */
367
368
encodedTypeByte = (encodedTypeByte << 4) | encodedType;
369
encodedTypeByteStored = !encodedTypeByteStored;
370
if (encodedTypeByteStored) {
371
*encodedTypes++ = encodedTypeByte;
372
}
373
} while (!done);
374
375
/* Store the final byte if necessary */
376
377
if (!encodedTypeByteStored) {
378
*encodedTypes++ = (encodedTypeByte << 4) | J9_THUNK_TYPE_FILL;
379
}
380
381
/* Store arg count and compute total size */
382
383
encodedSignature[0] = argCount;
384
totalSize = encodedTypes - encodedSignature;
385
386
#ifdef DEBUG
387
printf("encode: %.*s -> ", signatureData - origSig, origSig);
388
for (i = 0; i < totalSize; ++i) {
389
printf("%02X", encodedSignature[i]);
390
}
391
printf(" (length %d)\n", totalSize);
392
#endif
393
394
return totalSize;
395
}
396
397
static U_8
398
j9ThunkGetEncodedSignature(J9ThunkTableEntry * entry, U_8 ** encodedSignaturePtr)
399
{
400
U_8 * encodedSignature;
401
U_8 argCount;
402
403
if (J9_THUNK_BYTES_ARE_INLINE(entry)) {
404
encodedSignature = entry->encodedSignature.inlineBytes;
405
/* Inline encoding bytes must all be odd - argCount is stored multiplied by 2 and 1 added to make it odd */
406
argCount = encodedSignature[0] >> 1;
407
} else {
408
encodedSignature = entry->encodedSignature.outOfLineBytes;
409
argCount = encodedSignature[0];
410
}
411
412
*encodedSignaturePtr = encodedSignature;
413
return argCount;
414
}
415
416
void *
417
j9ThunkVMHelperFromSignature(void * jitConfig, UDATA signatureLength, char *signatureChars)
418
{
419
void * helper;
420
421
while ((*signatureChars++) != ')') ;
422
switch (*signatureChars) {
423
case 'V':
424
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtual0);
425
break;
426
case 'F':
427
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtualF);
428
break;
429
case 'D':
430
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtualD);
431
break;
432
case 'J':
433
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtualJ);
434
break;
435
case '[':
436
/* intentional fall-through */
437
case 'L':
438
#if defined(J9VM_ENV_DATA64)
439
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtualL);
440
break;
441
#endif
442
/* intentional fall-through */
443
default:
444
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtual1);
445
break;
446
}
447
448
return helper;
449
}
450
451
void *
452
j9ThunkInvokeExactHelperFromSignature(void * jitConfig, UDATA signatureLength, char *signatureChars)
453
{
454
void * helper;
455
456
while ((*signatureChars++) != ')') ;
457
switch (*signatureChars) {
458
case 'V':
459
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExact0);
460
break;
461
case 'F':
462
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExactF);
463
break;
464
case 'D':
465
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExactD);
466
break;
467
case 'J':
468
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExactJ);
469
break;
470
case '[':
471
/* intentional fall-through */
472
case 'L':
473
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExactL);
474
break;
475
default:
476
helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExact1);
477
break;
478
}
479
480
return helper;
481
}
482
483
void *
484
j9ThunkVMHelperFromNameAndSig(void * jitConfig, void *parm)
485
{
486
J9ROMNameAndSignature *nameAndSignature = (J9ROMNameAndSignature *) parm;
487
488
return j9ThunkVMHelperFromSignature(jitConfig, J9UTF8_LENGTH(J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature)), (char *) J9UTF8_DATA((J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature))));
489
}
490
491