Path: blob/master/runtime/codert_vm/thunkcrt.c
5986 views
/*******************************************************************************1* Copyright (c) 1991, 2020 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* 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-exception20*******************************************************************************/2122#include "j9.h"23#include "j9protos.h"24#include "jitprotos.h"25#include "ut_j9codertvm.h"26#include <string.h>2728#undef DEBUG2930/* 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 */3132#define J9_THUNK_TYPE_VOID 133#define J9_THUNK_TYPE_INT 334#define J9_THUNK_TYPE_LONG 535#define J9_THUNK_TYPE_FLOAT 736#define J9_THUNK_TYPE_DOUBLE 937#define J9_THUNK_TYPE_OBJECT 1138#define J9_THUNK_TYPE_UNUSED 1339#define J9_THUNK_TYPE_FILL 154041/* This value should be a multiple of 8 bytes (to maintain pointer alignment).42*43* Also note that the value must be smaller than 64 (128 types) so that argCount * 2 +44* may be stored in the inline argCount byte.45*/4647#define J9_THUNK_INLINE_ENCODING_BYTES 84849/* 4 bits per arg + 4 bits return type, rounded up to nearest byte */5051#define J9_THUNK_ENCODED_SIGNATURE_LENGTH(argCount) ((((U_32) (argCount)) + 1 + 1) / 2)5253/* Encoding format is:54*55* 1 byte argCount56* 128 bytes encoded bytes (up to 255 args + 1 return type)57*/5859#define J9_THUNK_MAX_ENCODED_BYTES 1296061typedef struct J9ThunkTableEntry {62void * thunkAddress;63union {64U_8 * outOfLineBytes;65U_8 inlineBytes[J9_THUNK_INLINE_ENCODING_BYTES];66} encodedSignature;67} J9ThunkTableEntry;6869#define J9_THUNK_BYTES_ARE_INLINE(entry) (((UDATA) ((entry)->encodedSignature.outOfLineBytes)) & 1)7071#if defined(J9ZOS390)72extern void icallVMprJavaSendVirtual0();73extern void icallVMprJavaSendVirtual1();74extern void icallVMprJavaSendVirtualJ();75extern void icallVMprJavaSendVirtualF();76extern void icallVMprJavaSendVirtualD();77#if defined(J9VM_ENV_DATA64)78extern void icallVMprJavaSendVirtualL();79#endif80extern void icallVMprJavaSendInvokeExact0();81extern void icallVMprJavaSendInvokeExact1();82extern void icallVMprJavaSendInvokeExactJ();83extern void icallVMprJavaSendInvokeExactF();84extern void icallVMprJavaSendInvokeExactD();85extern void icallVMprJavaSendInvokeExactL();86#else87extern void * icallVMprJavaSendVirtual0;88extern void * icallVMprJavaSendVirtual1;89extern void * icallVMprJavaSendVirtualJ;90extern void * icallVMprJavaSendVirtualF;91extern void * icallVMprJavaSendVirtualD;92#if defined(J9VM_ENV_DATA64)93extern void * icallVMprJavaSendVirtualL;94#endif95extern void * icallVMprJavaSendInvokeExact0;96extern void * icallVMprJavaSendInvokeExact1;97extern void * icallVMprJavaSendInvokeExactJ;98extern void * icallVMprJavaSendInvokeExactF;99extern void * icallVMprJavaSendInvokeExactD;100extern void * icallVMprJavaSendInvokeExactL;101#endif102103static U_8 j9ThunkGetEncodedSignature(J9ThunkTableEntry * entry, U_8 ** encodedSignaturePtr);104static UDATA j9ThunkEncodeSignature(char *signatureData, U_8 * encodedSignature);105static UDATA j9ThunkTableHash(void *key, void *userData);106static UDATA j9ThunkTableEquals(void *leftKey, void *rightKey, void *userData);107108109void *110j9ThunkLookupNameAndSig(void * jitConfig, void *parm)111{112void * thunkAddress = NULL;113J9ROMNameAndSignature *nameAndSignature = (J9ROMNameAndSignature *) parm;114115Trc_Thunk_j9ThunkLookupNameAndSig_Entry();116117thunkAddress = j9ThunkLookupSignature(jitConfig, J9UTF8_LENGTH(J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature)), (char *) J9UTF8_DATA((J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature))));118119if (NULL == thunkAddress) {120Trc_Thunk_j9ThunkLookupNameAndSig_Exit_ThunkNotFound();121} else {122Trc_Thunk_j9ThunkLookupNameAndSig_Exit_Success(thunkAddress);123}124125return thunkAddress;126}127128UDATA129j9ThunkTableAllocate(J9JavaVM * vm)130{131J9JITConfig * jitConfig = vm->jitConfig;132133if (omrthread_monitor_init_with_name(&jitConfig->thunkHashTableMutex, 0, "JIT thunk table")) {134return 1;135}136137jitConfig->thunkHashTable = hashTableNew(138OMRPORT_FROM_J9PORT(vm->portLibrary), /* portLibrary */139J9_GET_CALLSITE(), /* tableName */1400, /* tableSize */141sizeof(J9ThunkTableEntry), /* entrySize */1420, /* entryAlignment */1430, /* flags */144OMRMEM_CATEGORY_JIT, /* memoryCategory */145j9ThunkTableHash, /* hashFn */146j9ThunkTableEquals, /* hashEqualFn */147NULL, /* printFn */148NULL /* functionUserData */149);150151return jitConfig->thunkHashTable == NULL;152}153154void155j9ThunkTableFree(J9JavaVM * vm)156{157J9JITConfig * jitConfig = vm->jitConfig;158159if (jitConfig->thunkHashTable != NULL) {160PORT_ACCESS_FROM_JAVAVM(vm);161J9HashTableState state;162J9ThunkTableEntry * entry;163164entry = hashTableStartDo(jitConfig->thunkHashTable, &state);165while (entry != NULL) {166if (!J9_THUNK_BYTES_ARE_INLINE(entry)) {167j9mem_free_memory(entry->encodedSignature.outOfLineBytes);168}169entry = hashTableNextDo(&state);170}171hashTableFree(jitConfig->thunkHashTable);172jitConfig->thunkHashTable = NULL;173}174175if (jitConfig->thunkHashTableMutex != NULL) {176omrthread_monitor_destroy(jitConfig->thunkHashTableMutex);177jitConfig->thunkHashTableMutex = NULL;178}179}180181static UDATA182j9ThunkTableHash(void *key, void *userData)183{184U_8 * encodedSignature;185U_8 argCount;186187argCount = j9ThunkGetEncodedSignature(key, &encodedSignature);188return j9crc32(0, encodedSignature + 1, J9_THUNK_ENCODED_SIGNATURE_LENGTH(argCount));189}190static UDATA191j9ThunkTableEquals(void *leftKey, void *rightKey, void *userData)192{193U_8 * leftSig;194U_8 * rightSig;195U_8 leftArgCount = j9ThunkGetEncodedSignature(leftKey, &leftSig);196U_8 rightArgCount = j9ThunkGetEncodedSignature(rightKey, &rightSig);197198if (leftArgCount != rightArgCount) {199return FALSE;200}201202return memcmp(leftSig + 1, rightSig + 1, J9_THUNK_ENCODED_SIGNATURE_LENGTH(leftArgCount)) == 0;203}204void *205j9ThunkLookupSignature(void * jitConfig, UDATA signatureLength, char *signatureChars)206{207J9ThunkTableEntry exemplar;208J9ThunkTableEntry * entry;209U_8 encodedSignatureArray[J9_THUNK_MAX_ENCODED_BYTES + 1];210U_8* encodedSignature = encodedSignatureArray;211212if ((UDATA)encodedSignature & (UDATA)1) {213/* J9_THUNK_BYTES_ARE_INLINE() needs encodedSignature to be even */214encodedSignature++;215}216217j9ThunkEncodeSignature(signatureChars, encodedSignature);218exemplar.encodedSignature.outOfLineBytes = encodedSignature;219220omrthread_monitor_enter(((J9JITConfig *) jitConfig)->thunkHashTableMutex);221entry = hashTableFind(((J9JITConfig *) jitConfig)->thunkHashTable, &exemplar);222omrthread_monitor_exit(((J9JITConfig *) jitConfig)->thunkHashTableMutex);223if (entry != NULL ) {224return entry->thunkAddress;225}226227return NULL;228}229230IDATA231j9ThunkNewNameAndSig(void * jitConfig, void *parm, void *thunkAddress)232{233J9ROMNameAndSignature *nameAndSignature = (J9ROMNameAndSignature *) parm;234235return j9ThunkNewSignature(jitConfig, J9UTF8_LENGTH(J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature)), (char *) J9UTF8_DATA((J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature))), thunkAddress);236}237238IDATA239j9ThunkNewSignature(void * jitConfig, int signatureLength, char *signatureChars, void *thunkAddress)240{241PORT_ACCESS_FROM_JAVAVM(((J9JITConfig *) jitConfig)->javaVM);242J9ThunkTableEntry exemplar;243J9ThunkTableEntry * entry;244U_8 encodedSignatureArray[J9_THUNK_MAX_ENCODED_BYTES + 1];245U_8* encodedSignature = encodedSignatureArray;246UDATA length;247248if ((UDATA)encodedSignature & (UDATA)1) {249/* J9_THUNK_BYTES_ARE_INLINE() needs encodedSignature to be even */250encodedSignature++;251}252253length = j9ThunkEncodeSignature(signatureChars, encodedSignature);254255/* J9_THUNK_TYPE_FILL * 0x11 puts J9_THUNK_TYPE_FILL * 0x11 in both nybbles */256memset(exemplar.encodedSignature.inlineBytes, J9_THUNK_TYPE_FILL * 0x11, sizeof(exemplar.encodedSignature));257258if (length > J9_THUNK_INLINE_ENCODING_BYTES) {259U_8 * allocatedSignature = j9mem_allocate_memory(length, OMRMEM_CATEGORY_JIT);260261#ifdef DEBUG262printf("allocating bytes\n");263#endif264265if (allocatedSignature == NULL) {266return -1;267}268269memcpy(allocatedSignature, encodedSignature, length);270exemplar.encodedSignature.outOfLineBytes = allocatedSignature;271} else {272/* Inline encoding bytes must all be odd - multiply argCount by 2 and add 1 to make it odd */273encodedSignature[0] = encodedSignature[0] * 2 + 1;274275memcpy(exemplar.encodedSignature.inlineBytes, encodedSignature, length);276}277exemplar.thunkAddress = thunkAddress;278279omrthread_monitor_enter(((J9JITConfig *) jitConfig)->thunkHashTableMutex);280entry = hashTableAdd(((J9JITConfig *) jitConfig)->thunkHashTable, &exemplar);281omrthread_monitor_exit(((J9JITConfig *) jitConfig)->thunkHashTableMutex);282if (entry == NULL) {283if (!J9_THUNK_BYTES_ARE_INLINE(&exemplar)) {284j9mem_free_memory(exemplar.encodedSignature.outOfLineBytes);285}286return -1;287} else {288if (!J9_THUNK_BYTES_ARE_INLINE(&exemplar)) {289if (exemplar.encodedSignature.outOfLineBytes != entry->encodedSignature.outOfLineBytes) {290/* Existing entry was found in the table */291j9mem_free_memory(exemplar.encodedSignature.outOfLineBytes);292}293}294}295296return 0;297}298299/* Returns the total number of bytes used in the encodedSignature buffer */300301static UDATA302j9ThunkEncodeSignature(char *signatureData, U_8 * encodedSignature)303{304U_8 * encodedTypes = encodedSignature + 1;305U_8 argCount = 0;306U_8 encodedTypeByte = 0;307UDATA encodedTypeByteStored = TRUE;308UDATA done = FALSE;309UDATA totalSize;310#ifdef DEBUG311char * origSig = signatureData;312UDATA i;313#endif314315/* Skip opening bracket */316++signatureData;317318/* Encode the signature (including return type), considering like types to be identical */319320do {321char c = *signatureData++;322U_8 encodedType;323324/* Include the return type in the encoding, but do not increment the argCount for it */325326if (c == ')') {327done = TRUE;328c = *signatureData++;329} else {330++argCount;331}332333/* Consume signature element and convert to canonical type */334335switch (c) {336case 'V':337encodedType = J9_THUNK_TYPE_VOID;338break;339case 'F':340encodedType = J9_THUNK_TYPE_FLOAT;341break;342case 'D':343encodedType = J9_THUNK_TYPE_DOUBLE;344break;345case 'J':346encodedType = J9_THUNK_TYPE_LONG;347break;348case '[':349while ((c = *signatureData++) == '[') ;350/* intentional fall-through */351case 'L':352if (c == 'L') {353while (*signatureData++ != ';') ;354}355#if defined(J9VM_ENV_DATA64)356encodedType = J9_THUNK_TYPE_OBJECT;357break;358#endif359/* intentional fall-through */360default:361encodedType = J9_THUNK_TYPE_INT;362break;363}364365/* Store encoded value into nybble */366367encodedTypeByte = (encodedTypeByte << 4) | encodedType;368encodedTypeByteStored = !encodedTypeByteStored;369if (encodedTypeByteStored) {370*encodedTypes++ = encodedTypeByte;371}372} while (!done);373374/* Store the final byte if necessary */375376if (!encodedTypeByteStored) {377*encodedTypes++ = (encodedTypeByte << 4) | J9_THUNK_TYPE_FILL;378}379380/* Store arg count and compute total size */381382encodedSignature[0] = argCount;383totalSize = encodedTypes - encodedSignature;384385#ifdef DEBUG386printf("encode: %.*s -> ", signatureData - origSig, origSig);387for (i = 0; i < totalSize; ++i) {388printf("%02X", encodedSignature[i]);389}390printf(" (length %d)\n", totalSize);391#endif392393return totalSize;394}395396static U_8397j9ThunkGetEncodedSignature(J9ThunkTableEntry * entry, U_8 ** encodedSignaturePtr)398{399U_8 * encodedSignature;400U_8 argCount;401402if (J9_THUNK_BYTES_ARE_INLINE(entry)) {403encodedSignature = entry->encodedSignature.inlineBytes;404/* Inline encoding bytes must all be odd - argCount is stored multiplied by 2 and 1 added to make it odd */405argCount = encodedSignature[0] >> 1;406} else {407encodedSignature = entry->encodedSignature.outOfLineBytes;408argCount = encodedSignature[0];409}410411*encodedSignaturePtr = encodedSignature;412return argCount;413}414415void *416j9ThunkVMHelperFromSignature(void * jitConfig, UDATA signatureLength, char *signatureChars)417{418void * helper;419420while ((*signatureChars++) != ')') ;421switch (*signatureChars) {422case 'V':423helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtual0);424break;425case 'F':426helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtualF);427break;428case 'D':429helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtualD);430break;431case 'J':432helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtualJ);433break;434case '[':435/* intentional fall-through */436case 'L':437#if defined(J9VM_ENV_DATA64)438helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtualL);439break;440#endif441/* intentional fall-through */442default:443helper = J9_BUILDER_SYMBOL(icallVMprJavaSendVirtual1);444break;445}446447return helper;448}449450void *451j9ThunkInvokeExactHelperFromSignature(void * jitConfig, UDATA signatureLength, char *signatureChars)452{453void * helper;454455while ((*signatureChars++) != ')') ;456switch (*signatureChars) {457case 'V':458helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExact0);459break;460case 'F':461helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExactF);462break;463case 'D':464helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExactD);465break;466case 'J':467helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExactJ);468break;469case '[':470/* intentional fall-through */471case 'L':472helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExactL);473break;474default:475helper = J9_BUILDER_SYMBOL(icallVMprJavaSendInvokeExact1);476break;477}478479return helper;480}481482void *483j9ThunkVMHelperFromNameAndSig(void * jitConfig, void *parm)484{485J9ROMNameAndSignature *nameAndSignature = (J9ROMNameAndSignature *) parm;486487return j9ThunkVMHelperFromSignature(jitConfig, J9UTF8_LENGTH(J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature)), (char *) J9UTF8_DATA((J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSignature))));488}489490491