| #include "j3/j3codegenexception.h" |
| #include "j3/j3codegen.h" |
| #include "j3/j3reader.h" |
| #include "j3/j3method.h" |
| #include "j3/j3class.h" |
| #include "j3/j3.h" |
| |
| #include "vmkit/allocator.h" |
| #include "vmkit/names.h" |
| |
| #include "llvm/IR/Function.h" |
| |
| using namespace j3; |
| |
| void J3ExceptionEntry::dump(uint32_t i) { |
| fprintf(stderr, " entry[%d]: %d %d %d %d\n", i, startPC, endPC, handlerPC, catchType); |
| } |
| |
| void J3ExceptionNode::addEntry(J3CodeGen* codeGen, J3ExceptionEntry* entry) { |
| if(!nbEntries) { |
| landingPad = codeGen->newBB("landing-pad"); |
| curCheck = landingPad; |
| codeGen->builder.SetInsertPoint(landingPad); |
| |
| llvm::LandingPadInst *caughtResult = codeGen->builder.CreateLandingPad(codeGen->vm->typeGXXException, |
| codeGen->funcGXXPersonality, |
| 1, |
| "landing-pad"); |
| |
| caughtResult->addClause(codeGen->gvTypeInfo); |
| |
| if(codeGen->vm->options()->debugExecute) { |
| char buf[256]; |
| snprintf(buf, 256, " catching exceptions in %s::%s\n", codeGen->cl->name()->cStr(), codeGen->method->name()->cStr()); |
| codeGen->builder.CreateCall2(codeGen->funcEchoDebugExecute, |
| codeGen->builder.getInt32(1), |
| codeGen->buildString(buf)); |
| } |
| |
| llvm::Value* excp = codeGen->builder.CreateBitCast(codeGen->builder.CreateCall(codeGen->funcCXABeginCatch, |
| codeGen->builder.CreateExtractValue(caughtResult, 0)), |
| codeGen->vm->typeJ3ObjectPtr); |
| |
| codeGen->builder.CreateCall(codeGen->funcCXAEndCatch); |
| |
| codeGen->stack.topStack = 0; |
| codeGen->stack.push(excp); |
| } |
| |
| entries[nbEntries++] = entry; |
| |
| if(curCheck) { /* = 0 if I already have a finally */ |
| codeGen->builder.SetInsertPoint(curCheck); |
| |
| if(entry->catchType) { |
| curCheck = codeGen->newBB("next-exception-check"); |
| codeGen->stack.metaStack[0] = codeGen->vm->typeJ3ObjectPtr; |
| codeGen->stack.topStack = 1; |
| llvm::CallInst* is = codeGen->isAssignableTo(codeGen->stack.top(0), |
| codeGen->cl->classAt(entry->catchType)); |
| codeGen->builder.CreateCondBr(is, entry->bb, curCheck); |
| } else { |
| codeGen->builder.CreateBr(entry->bb); |
| curCheck = 0; |
| } |
| } |
| } |
| |
| void J3ExceptionNode::close(J3CodeGen* codeGen) { |
| if(curCheck) { |
| codeGen->builder.SetInsertPoint(curCheck); |
| |
| if(codeGen->vm->options()->debugExecute) { |
| char buf[256]; |
| snprintf(buf, 256, " exceptions not catched in %s::%s, rethrowing\n", |
| codeGen->cl->name()->cStr(), codeGen->method->name()->cStr()); |
| codeGen->builder.CreateCall2(codeGen->funcEchoDebugExecute, |
| codeGen->builder.getInt32(1), |
| codeGen->buildString(buf)); |
| } |
| |
| codeGen->stack.metaStack[0] = codeGen->vm->typeJ3ObjectPtr; |
| codeGen->stack.topStack = 1; |
| codeGen->builder.CreateCall(codeGen->funcThrowException, |
| codeGen->builder.CreateBitCast(codeGen->stack.pop(), |
| codeGen->funcThrowException->getFunctionType()->getParamType(0))); |
| codeGen->builder.CreateBr(codeGen->bbRet); |
| } |
| } |
| |
| J3ExceptionNode** J3ExceptionTable::newNode(uint32_t pos, uint32_t pc) { |
| J3ExceptionNode* res = &_exceptionNodes[nbNodes++]; |
| res->pc = pc; |
| res->entries = (J3ExceptionEntry**)codeGen->allocator->allocate(sizeof(J3ExceptionEntry*)*nbEntries); |
| nodes[pos] = res; |
| if(pos > 1) { |
| for(uint32_t i=0; i<nodes[pos-1]->nbEntries; i++) |
| res->addEntry(codeGen, nodes[pos-1]->entries[i]); |
| } |
| return nodes+pos; |
| } |
| |
| J3ExceptionNode** J3ExceptionTable::findPos(uint32_t pc) { |
| for(uint32_t i=0; i<nbNodes; i++) { |
| if(nodes[i]->pc == pc) |
| return nodes+i; |
| if(pc < nodes[i]->pc) { |
| memmove(nodes+i+1, nodes+i, (nbNodes-i)*sizeof(J3ExceptionNode*)); |
| return newNode(i, pc); |
| } |
| } |
| return newNode(nbNodes, pc); |
| } |
| |
| void J3ExceptionTable::read(J3Reader* reader, uint32_t codeLength) { |
| nbEntries = reader->readU2(); |
| entries = (J3ExceptionEntry*)codeGen->allocator->allocate(sizeof(J3ExceptionEntry)*nbEntries); |
| _exceptionNodes = (J3ExceptionNode*)codeGen->allocator->allocate(sizeof(J3ExceptionNode)*(nbEntries*2 + 2)); |
| nodes = (J3ExceptionNode**)codeGen->allocator->allocate(sizeof(J3ExceptionNode*)*(nbEntries*2 + 2)); |
| nbNodes = 0; |
| |
| newNode(nbNodes, 0); |
| for(uint32_t i=0; i<nbEntries; i++) { |
| entries[i].startPC = reader->readU2(); |
| entries[i].endPC = reader->readU2(); |
| entries[i].handlerPC = reader->readU2(); |
| entries[i].catchType = reader->readU2(); |
| entries[i].bb = codeGen->forwardBranch("exception-handler", entries[i].handlerPC, 0, 0); |
| codeGen->opInfos[entries[i].handlerPC].topStack = -1; |
| |
| J3ExceptionNode** cur = findPos(entries[i].startPC); |
| J3ExceptionNode** end = findPos(entries[i].endPC); |
| |
| for(; cur<end; cur++) |
| (*cur)->addEntry(codeGen, entries+i); |
| } |
| newNode(nbNodes, codeLength); |
| |
| for(uint32_t i=0; i<nbNodes; i++) |
| nodes[i]->close(codeGen); |
| } |
| |
| void J3ExceptionTable::dump(bool verbose) { |
| if(nbEntries) { |
| fprintf(stderr, " ExceptionTable of %s::%s%s:\n", |
| codeGen->method->cl()->name()->cStr(), |
| codeGen->method->name()->cStr(), |
| codeGen->method->signature()->name()->cStr()); |
| |
| if(verbose) { |
| for(uint32_t i=0; i<nbEntries; i++) |
| entries[i].dump(i); |
| } |
| |
| for(uint32_t i=0; i<nbNodes; i++) { |
| fprintf(stderr, " at pc %d:\n", nodes[i]->pc); |
| for(uint32_t j=0; j<nodes[i]->nbEntries; j++) |
| fprintf(stderr, " catch %d at %d\n", nodes[i]->entries[j]->catchType, nodes[i]->entries[j]->handlerPC); |
| } |
| } |
| } |
| |