blob: cfc4de2aa1c6cd8fa8d73318a1337997a91704ad [file] [log] [blame]
#include "vmkit/safepoint.h"
#include "j3/j3method.h"
#include "j3/j3class.h"
#include "j3/j3classloader.h"
#include "j3/j3constants.h"
#include "j3/j3.h"
#include "j3/j3mangler.h"
#include "j3/j3thread.h"
#include "j3/j3codegen.h"
#include "j3/j3trampoline.h"
#include "j3/j3attribute.h"
#include "j3/j3reader.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/Linker.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include <vector>
using namespace j3;
J3Method::J3Method(uint16_t access, J3Class* cl, const vmkit::Name* name, J3Signature* signature) {
_access = access;
_cl = cl;
_name = name;
_signature = signature;
_index = -1;
}
J3Attributes* J3Method::codeAttributes() {
if(!_codeAttributes) {
J3* vm = J3Thread::get()->vm();
J3Attribute* codeAttr = attributes()->lookup(vm->codeAttribute);
if(codeAttr) {
J3Reader reader(cl()->bytes());
reader.seek(codeAttr->offset()+8, reader.SeekSet);
reader.seek(reader.readU4(), reader.SeekCur);
reader.seek(reader.readU2()*8, reader.SeekCur);
_codeAttributes = cl()->readAttributes(&reader);
}
}
return _codeAttributes;
}
vmkit::CompilationUnit* J3Method::unit() {
return cl()->loader();
}
uint64_t J3Method::inlineWeight() {
if(J3Thread::get()->vm()->options()->enableInlining)
return vmkit::Symbol::inlineWeight();
else
return (uint64_t)-1;
}
uint32_t J3Method::interfaceIndex() {
return cl()->loader()->interfaceIndex(this);
}
uint32_t J3Method::index() {
return _index;
}
void J3Method::markCompiled(llvm::Function* llvmFunction, void* fnPtr) {
_llvmFunction = llvmFunction;
_fnPtr = fnPtr;
}
void* J3Method::fnPtr() {
return _fnPtr;
}
J3Signature::function_t J3Method::cxxCaller() {
return signature()->caller(access());
}
void J3Method::aotSnapshot(llvm::Linker* linker) {
if(_llvmFunction) {
std::string err;
linker->linkInModule(_llvmFunction->getParent(), llvm::Linker::DestroySource, &err);
}
}
void J3Method::ensureCompiled(uint32_t mode) {
if(((mode & J3CodeGen::WithMethod) && !fnPtr()) || ((mode & J3CodeGen::WithCaller) && !cxxCaller())) {
//fprintf(stderr, "materializing: %s::%s%s\n", cl()->name()->cStr(), name()->cStr(), signature()->name()->cStr());
J3CodeGen::translate(this, mode | cl()->loader()->compilationMode());
}
}
void* J3Method::functionPointerOrStaticTrampoline() {
if(fnPtr())
return fnPtr();
if(!_staticTrampoline)
_staticTrampoline = J3Trampoline::buildStaticTrampoline(cl()->loader()->allocator(), this);
return _staticTrampoline;
}
void* J3Method::functionPointerOrVirtualTrampoline() {
if(fnPtr())
return fnPtr();
if(!_virtualTrampoline)
_virtualTrampoline = J3Trampoline::buildVirtualTrampoline(cl()->loader()->allocator(), this);
return _virtualTrampoline;
}
void* J3Method::getSymbolAddress() {
return functionPointerOrStaticTrampoline();
}
void J3Method::setIndex(uint32_t index) {
_index = index;
}
void J3Method::postInitialise(uint32_t access, J3Attributes* attributes) {
if((access & J3Cst::ACC_STATIC) != (_access & J3Cst::ACC_STATIC))
J3::classFormatError(cl(), "trying to modify the static flag of %s", cl()->name()->cStr());
_access = access;
_attributes = attributes;
}
J3Method* J3Method::resolve(J3ObjectHandle* obj) {
J3* vm = J3Thread::get()->vm();
if(vm->options()->debugLinking)
fprintf(stderr, "virtual linking %s::%s\n", cl()->name()->cStr(), name()->cStr());
vmkit::Names* n = vm->names();
return obj->vt()->type()->asObjectType()->findMethod(0, name(), signature());
}
J3Value J3Method::internalInvoke(J3Value* args) {
#if 1
return cxxCaller()(fnPtr(), args);
#else
J3Value res;
try {
res = cxxCaller()(fnPtr(), args);
} catch(void* e) {
fprintf(stderr, " catch exception %p during the execution of %s::%s%s\n",
e, cl()->name()->cStr(), name()->cStr(), signature()->name()->cStr());
throw e;
}
return res;
#endif
}
J3Value J3Method::internalInvoke(J3ObjectHandle* handle, J3Value* inArgs) {
cl()->initialise();
ensureCompiled(J3CodeGen::WithMethod | J3CodeGen::WithCaller); /* force the generation of the code and thus of the functionType */
J3Value* reIn;
if(handle) {
uint32_t n = signature()->functionType(J3Cst::ACC_STATIC)->getNumParams();
reIn = (J3Value*)alloca((n+1)*sizeof(J3Value));
reIn[0].valObject = handle;
memcpy(reIn+1, inArgs, n*sizeof(J3Value));
} else
reIn = inArgs;
return internalInvoke(reIn);
}
J3Value J3Method::internalInvoke(J3ObjectHandle* handle, va_list va) {
cl()->initialise();
ensureCompiled(J3CodeGen::WithMethod | J3CodeGen::WithCaller); /* force the generation of the code and thus of the functionType */
llvm::FunctionType* fType = signature()->functionType(J3Cst::ACC_STATIC); /* static signature for va */
J3Value* args = (J3Value*)alloca(sizeof(J3Value)*(fType->getNumParams() + 1));
J3* vm = J3Thread::get()->vm();
uint32_t i = 0;
if(handle)
args[i++].valObject = handle;
for(llvm::FunctionType::param_iterator cur=fType->param_begin(); cur!=fType->param_end(); cur++, i++) {
llvm::Type* t = *cur;
if(0) {}
#define doIt(id, ctype, lt, scale) \
else if(t == vm->type##id->llvmType()) \
args[i].val##id = va_arg(va, ctype);
onJavaPrimitives(doIt)
else
args[i].valObject = va_arg(va, J3ObjectHandle*);
#undef doIt
}
return internalInvoke(args);
}
J3Value J3Method::invokeStatic(J3Value* args) {
return internalInvoke(0, args);
}
J3Value J3Method::invokeStatic(va_list va) {
return internalInvoke(0, va);
}
J3Value J3Method::invokeSpecial(J3ObjectHandle* handle, J3Value* args) {
return internalInvoke(handle, args);
}
J3Value J3Method::invokeSpecial(J3ObjectHandle* handle, va_list va) {
return internalInvoke(handle, va);
}
J3Value J3Method::invokeVirtual(J3ObjectHandle* handle, J3Value* args) {
return resolve(handle)->internalInvoke(handle, args);
}
J3Value J3Method::invokeVirtual(J3ObjectHandle* handle, va_list va) {
return resolve(handle)->internalInvoke(handle, va);
}
J3Value J3Method::invokeStatic(...) {
va_list va;
va_start(va, this);
J3Value res = invokeStatic(va);
va_end(va);
return res;
}
J3Value J3Method::invokeSpecial(J3ObjectHandle* handle, ...) {
va_list va;
va_start(va, this);
J3Value res = invokeSpecial(handle, va);
va_end(va);
return res;
}
J3Value J3Method::invokeVirtual(J3ObjectHandle* handle, ...) {
va_list va;
va_start(va, this);
J3Value res = invokeVirtual(handle, va);
va_end(va);
return res;
}
void J3Method::buildLLVMNames(J3Class* from) {
const char* prefix = "stub_";
uint32_t plen = 5;
J3Mangler mangler(from);
mangler.mangle(mangler.j3Id)->mangle(cl()->name(), name())->mangle(signature());
uint32_t length = mangler.length() + plen;
_llvmAllNames = (char*)cl()->loader()->allocator()->allocate(length + 1);
memcpy(_llvmAllNames, prefix, plen);
memcpy(_llvmAllNames+plen, mangler.cStr(), mangler.length());
_llvmAllNames[length] = 0;
}
char* J3Method::llvmFunctionName(J3Class* from) {
if(!_llvmAllNames)
buildLLVMNames(from ? from : cl());
return _llvmAllNames + 5;
}
char* J3Method::llvmStubName(J3Class* from) {
if(!_llvmAllNames)
buildLLVMNames(from ? from : cl());
return _llvmAllNames + 0;
}
void J3Method::dump() {
printf("Method: %s %s::%s\n", signature()->name()->cStr(), cl()->name()->cStr(), name()->cStr());
}
void J3Method::registerNative(void* fnPtr) {
if(_nativeFnPtr)
J3::noSuchMethodError("unable to dynamically modify a native function", cl(), name(), signature());
_nativeFnPtr = fnPtr;
}
J3Method* J3Method::nativeMethod(J3ObjectHandle* handle) {
J3* vm = J3Thread::get()->vm();
if(handle->vt()->type() == vm->constructorClass) {
J3Class* cl = J3ObjectType::nativeClass(handle->getObject(vm->constructorClassClass))->asClass();
uint32_t slot = handle->getInteger(vm->constructorClassSlot);
J3Method* res = cl->methods()[slot];
if(res->name() != vm->initName)
J3::internalError("nativeName with a java.lang.reflect.Constructor with a non-constructot method");
return res;
} else
J3::internalError("implement me: nativeMethod with method");
}
J3ObjectHandle* J3Method::javaMethod() {
if(!_javaMethod) {
cl()->lock();
if(!_javaMethod) {
J3ObjectHandle* prev = J3Thread::get()->tell();
J3* vm = J3Thread::get()->vm();
uint32_t nbIns = signature()->nbIns();
J3ObjectHandle* parameters = J3ObjectHandle::doNewArray(vm->classClass->getArray(), nbIns);
for(uint32_t i=0; i<nbIns; i++)
parameters->setObjectAt(i, signature()->javaIns(i)->javaClass(0));
J3Attribute* exceptionAttribute = attributes()->lookup(vm->exceptionsAttribute);
J3ObjectHandle* exceptions;
if(exceptionAttribute)
J3::internalError("implement me: excp");
else
exceptions = J3ObjectHandle::doNewArray(vm->classClass->getArray(), 0);
J3ObjectHandle* annotations = cl()->asClass()->extractAttribute(attributes()->lookup(vm->annotationsAttribute));
J3ObjectHandle* paramAnnotations = cl()->asClass()->extractAttribute(attributes()->lookup(vm->paramAnnotationsAttribute));
if(name() == vm->initName) {
_javaMethod = cl()->loader()->globalReferences()->add(J3ObjectHandle::doNewObject(vm->constructorClass));
vm->constructorClassInit->invokeSpecial(_javaMethod,
cl()->javaClass(0),
parameters,
exceptions,
access(),
slot(),
vm->nameToString(signature()->name(), 0),
annotations,
paramAnnotations);
} else {
J3ObjectHandle* annotationDefault = cl()->asClass()->extractAttribute(attributes()->lookup(vm->annotationDefaultAttribute));
_javaMethod = cl()->loader()->globalReferences()->add(J3ObjectHandle::doNewObject(vm->methodClass));
vm->methodClassInit->invokeSpecial(_javaMethod,
cl()->javaClass(0),
vm->nameToString(name(), 0),
parameters,
signature()->javaOut()->javaClass(0),
exceptions,
access(),
slot(),
vm->nameToString(signature()->name(), 0),
annotations,
paramAnnotations,
annotationDefault);
}
J3Thread::get()->restore(prev);
}
cl()->unlock();
}
return _javaMethod;
}