blob: 9037affe114d11ef3f0e83e5d33e4dcfb8bab829 [file] [log] [blame]
#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);
}
}
}
}
}