| #include <stdio.h> |
| |
| #include "j3/j3.h" |
| #include "j3/j3thread.h" |
| #include "j3/j3reader.h" |
| #include "j3/j3codegen.h" |
| #include "j3/j3class.h" |
| #include "j3/j3constants.h" |
| #include "j3/j3classloader.h" |
| #include "j3/j3method.h" |
| #include "j3/j3mangler.h" |
| #include "j3/j3jni.h" |
| #include "j3/j3object.h" |
| #include "j3/j3field.h" |
| #include "j3/j3attribute.h" |
| #include "j3/j3utf16.h" |
| |
| #include "llvm/ExecutionEngine/ExecutionEngine.h" |
| |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/IR/Argument.h" |
| #include "llvm/IR/Intrinsics.h" |
| |
| #include "llvm/DebugInfo.h" |
| #include "llvm/DIBuilder.h" |
| |
| #define DEBUG_TYPE_INT 0 |
| #define DEBUG_TYPE_FLOAT 1 |
| #define DEBUG_TYPE_OBJECT 2 |
| |
| using namespace j3; |
| |
| void J3CodeGen::echoDebugEnter(uint32_t isLeave, const char* msg, ...) { |
| static __thread uint32_t prof = 0; |
| if(J3Thread::get()->vm()->options()->debugExecute >= 1) { |
| const char* enter = isLeave ? "leaving" : "entering"; |
| va_list va; |
| va_start(va, msg); |
| |
| if(!isLeave) |
| prof += J3Thread::get()->vm()->options()->debugEnterIndent; |
| fprintf(stderr, "%*s", prof, ""); |
| if(isLeave) |
| prof -= J3Thread::get()->vm()->options()->debugEnterIndent; |
| |
| fprintf(stderr, "%s ", enter); |
| vfprintf(stderr, msg, va); |
| va_end(va); |
| } |
| } |
| |
| void J3CodeGen::echoDebugExecute(uint32_t level, const char* msg, ...) { |
| if(level == -1 || J3Thread::get()->vm()->options()->debugExecute >= level) { |
| va_list va; |
| va_start(va, msg); |
| vfprintf(stderr, msg, va); |
| va_end(va); |
| } |
| } |
| |
| void J3CodeGen::echoElement(uint32_t level, uint32_t type, uintptr_t elmt) { |
| if(J3Thread::get()->vm()->options()->debugExecute >= level) { |
| switch(type) { |
| case DEBUG_TYPE_INT: |
| fprintf(stderr, "(long)%lld", (uint64_t)elmt); |
| break; |
| |
| case DEBUG_TYPE_FLOAT: |
| fprintf(stderr, "(double)%lf", *((double*)&elmt)); |
| break; |
| |
| case DEBUG_TYPE_OBJECT: |
| if(elmt) { |
| J3Object* pobj = (J3Object*)elmt; |
| J3* vm = J3Thread::get()->vm(); |
| J3ObjectHandle* prev = J3Thread::get()->tell(); |
| J3ObjectHandle* content = 0; |
| |
| fprintf(stderr, " %p - ", pobj); |
| |
| if(pobj->vt()->type() == vm->typeCharacter->getArray()) |
| content = J3Thread::get()->push(pobj); |
| else if(pobj->vt()->type() == vm->stringClass) { |
| J3ObjectHandle* str = J3Thread::get()->push(pobj); |
| content = str->getObject(vm->stringClassValue); |
| } |
| |
| if(content) { |
| char buf[J3Utf16Decoder::maxSize(content)]; |
| J3Utf16Decoder::decode(content, buf); |
| J3Thread::get()->restore(prev); |
| fprintf(stderr, "%s \"%s\"", pobj->vt()->type()->name()->cStr(), buf); |
| } else |
| fprintf(stderr, "%s@%p", pobj->vt()->type()->name()->cStr(), (void*)elmt); |
| } else |
| fprintf(stderr, "null"); |
| break; |
| } |
| } |
| } |
| |
| void J3CodeGen::genEchoElement(const char* msg, uint32_t idx, llvm::Value* val) { |
| llvm::Type* t = val->getType(); |
| builder.CreateCall3(funcEchoDebugExecute, |
| builder.getInt32(4), |
| buildString(msg), |
| builder.getInt32(idx)); |
| |
| if(t->isIntegerTy()) |
| builder.CreateCall3(funcEchoElement, |
| builder.getInt32(4), |
| builder.getInt32(DEBUG_TYPE_INT), |
| builder.CreateSExtOrBitCast(val, uintPtrTy)); |
| else if(t->isPointerTy()) |
| builder.CreateCall3(funcEchoElement, |
| builder.getInt32(4), |
| builder.getInt32(DEBUG_TYPE_OBJECT), |
| builder.CreatePtrToInt(val, uintPtrTy)); |
| else { |
| val = builder.CreateFPExt(val, builder.getDoubleTy()); |
| llvm::Value* loc = builder.CreateAlloca(val->getType()); |
| builder.CreateStore(val, loc); |
| builder.CreateCall3(funcEchoElement, |
| builder.getInt32(4), |
| builder.getInt32(DEBUG_TYPE_FLOAT), |
| builder.CreateLoad(builder.CreateBitCast(loc, uintPtrTy->getPointerTo()))); |
| } |
| builder.CreateCall2(funcEchoDebugExecute, |
| builder.getInt32(4), |
| buildString("\n")); |
| } |
| |
| void J3CodeGen::genDebugOpcode() { |
| if(vm->options()->genDebugExecute) { |
| llvm::BasicBlock* debug = newBB("debug"); |
| llvm::BasicBlock* after = newBB("after"); |
| builder |
| .CreateCondBr(builder |
| .CreateICmpSGT(builder.CreateLoad(builder |
| .CreateIntToPtr(llvm::ConstantInt::get(uintPtrTy, |
| (uintptr_t)&vm->options()->debugExecute), |
| uintPtrTy->getPointerTo())), |
| llvm::ConstantInt::get(uintPtrTy, 0)), |
| debug, after); |
| builder.SetInsertPoint(debug); |
| |
| if(vm->options()->genDebugExecute > 1) { |
| for(uint32_t i=0; i<stack.topStack; i++) { |
| genEchoElement(" stack[%d]: ", i, stack.at(i, stack.metaStack[i])); |
| } |
| } |
| |
| char buf[256]; |
| snprintf(buf, 256, " [%4d] executing: %-20s in %s::%s", javaPC, |
| J3Cst::opcodeNames[bc], cl->name()->cStr(), method->name()->cStr()); |
| builder.CreateCall3(funcEchoDebugExecute, |
| builder.getInt32(2), |
| buildString("%s\n"), |
| buildString(buf)); |
| |
| builder.CreateBr(after); |
| builder.SetInsertPoint(after); |
| } |
| } |
| |
| void J3CodeGen::genDebugEnterLeave(bool isLeave) { |
| if(vm->options()->genDebugExecute) { |
| if(isLeave) { |
| char buf[256]; |
| snprintf(buf, 256, "%s::%s", cl->name()->cStr(), method->name()->cStr()); |
| builder.CreateCall3(funcEchoDebugEnter, |
| builder.getInt32(1), |
| buildString("%s\n"), |
| buildString(buf)); |
| } else { |
| char buf[256]; |
| snprintf(buf, 256, "%s::%s", cl->name()->cStr(), method->name()->cStr()); |
| builder.CreateCall3(funcEchoDebugEnter, |
| builder.getInt32(0), |
| buildString("%s\n"), |
| buildString(buf)); |
| |
| if(vm->options()->genDebugExecute > 1) { |
| uint32_t i = 0; |
| for(llvm::Function::arg_iterator cur=llvmFunction->arg_begin(); cur!=llvmFunction->arg_end(); cur++) { |
| genEchoElement(" arg[%d]: ", i++, cur); |
| } |
| } |
| } |
| } |
| } |
| |