Merge pull request #263 from joshuawarner32/compiler-types

Introduce stronger typing in compiler
This commit is contained in:
Joel Dice 2014-06-01 20:08:44 -06:00
commit 86648ea054
26 changed files with 4049 additions and 2859 deletions

View File

@ -11,6 +11,8 @@
#ifndef AVIAN_CODEGEN_ARCHITECTURE_H #ifndef AVIAN_CODEGEN_ARCHITECTURE_H
#define AVIAN_CODEGEN_ARCHITECTURE_H #define AVIAN_CODEGEN_ARCHITECTURE_H
#include "ir.h"
namespace vm { namespace vm {
class Zone; class Zone;
} }
@ -57,6 +59,8 @@ virtual int returnHigh() = 0;
virtual int virtualCallTarget() = 0; virtual int virtualCallTarget() = 0;
virtual int virtualCallIndex() = 0; virtual int virtualCallIndex() = 0;
virtual ir::TargetInfo targetInfo() = 0;
virtual bool bigEndian() = 0; virtual bool bigEndian() = 0;
virtual uintptr_t maximumImmediateJump() = 0; virtual uintptr_t maximumImmediateJump() = 0;

View File

@ -12,8 +12,10 @@
#define AVIAN_CODEGEN_COMPILER_H #define AVIAN_CODEGEN_COMPILER_H
#include <avian/system/system.h> #include <avian/system/system.h>
#include <avian/util/slice.h>
#include "avian/zone.h" #include "avian/zone.h"
#include "assembler.h" #include "assembler.h"
#include "ir.h"
namespace avian { namespace avian {
namespace codegen { namespace codegen {
@ -33,35 +35,22 @@ class Compiler {
virtual intptr_t getThunk(lir::TernaryOperation op, unsigned size, virtual intptr_t getThunk(lir::TernaryOperation op, unsigned size,
unsigned resultSize, bool* threadParameter) = 0; unsigned resultSize, bool* threadParameter) = 0;
}; };
static const unsigned Aligned = 1 << 0; static const unsigned Aligned = 1 << 0;
static const unsigned NoReturn = 1 << 1; static const unsigned NoReturn = 1 << 1;
static const unsigned TailJump = 1 << 2; static const unsigned TailJump = 1 << 2;
static const unsigned LongJumpOrCall = 1 << 3; static const unsigned LongJumpOrCall = 1 << 3;
enum OperandType {
ObjectType,
AddressType,
IntegerType,
FloatType,
VoidType
};
class Operand { };
class State { }; class State { };
class Subroutine { };
virtual State* saveState() = 0; virtual State* saveState() = 0;
virtual void restoreState(State* state) = 0; virtual void restoreState(State* state) = 0;
virtual Subroutine* startSubroutine() = 0;
virtual void returnFromSubroutine(Subroutine* subroutine, Operand* address)
= 0;
virtual void linkSubroutine(Subroutine* subroutine) = 0;
virtual void init(unsigned logicalCodeSize, unsigned parameterFootprint, virtual void init(unsigned logicalCodeSize, unsigned parameterFootprint,
unsigned localFootprint, unsigned alignedFrameSize) = 0; unsigned localFootprint, unsigned alignedFrameSize) = 0;
virtual void extendLogicalCode(unsigned more) = 0;
virtual void visitLogicalIp(unsigned logicalIp) = 0; virtual void visitLogicalIp(unsigned logicalIp) = 0;
virtual void startLogicalIp(unsigned logicalIp) = 0; virtual void startLogicalIp(unsigned logicalIp) = 0;
@ -70,73 +59,82 @@ class Compiler {
virtual Promise* poolAppend(intptr_t value) = 0; virtual Promise* poolAppend(intptr_t value) = 0;
virtual Promise* poolAppendPromise(Promise* value) = 0; virtual Promise* poolAppendPromise(Promise* value) = 0;
virtual Operand* constant(int64_t value, OperandType type) = 0; virtual ir::Value* constant(int64_t value, ir::Type type) = 0;
virtual Operand* promiseConstant(Promise* value, OperandType type) = 0; virtual ir::Value* promiseConstant(Promise* value, ir::Type type) = 0;
virtual Operand* address(Promise* address) = 0; virtual ir::Value* address(ir::Type type, Promise* address) = 0;
virtual Operand* memory(Operand* base, virtual ir::Value* memory(ir::Value* base,
OperandType type, ir::Type type,
int displacement = 0, int displacement = 0,
Operand* index = 0, ir::Value* index = 0) = 0;
unsigned scale = 1) = 0;
virtual Operand* register_(int number) = 0; virtual ir::Value* threadRegister() = 0;
virtual void push(unsigned footprint) = 0; virtual void push(ir::Type type, ir::Value* value) = 0;
virtual void push(unsigned footprint, Operand* value) = 0; virtual void save(ir::Type type, ir::Value* value) = 0;
virtual void save(unsigned footprint, Operand* value) = 0; virtual ir::Value* pop(ir::Type type) = 0;
virtual Operand* pop(unsigned footprint) = 0; virtual void pushed(ir::Type type) = 0;
virtual void pushed() = 0;
virtual void popped(unsigned footprint) = 0; virtual void popped(unsigned footprint) = 0;
virtual unsigned topOfStack() = 0; virtual unsigned topOfStack() = 0;
virtual Operand* peek(unsigned footprint, unsigned index) = 0; virtual ir::Value* peek(unsigned footprint, unsigned index) = 0;
virtual Operand* call(Operand* address, virtual ir::Value* call(ir::Value* address,
unsigned flags, unsigned flags,
TraceHandler* traceHandler, TraceHandler* traceHandler,
unsigned resultSize, ir::Type resultType,
OperandType resultType, unsigned argumentCount,
unsigned argumentCount, ...) = 0;
...) = 0;
virtual Operand* stackCall(Operand* address, virtual ir::Value* stackCall(ir::Value* address,
unsigned flags, unsigned flags,
TraceHandler* traceHandler, TraceHandler* traceHandler,
unsigned resultSize, ir::Type resultType,
OperandType resultType, util::Slice<ir::Value*> arguments) = 0;
unsigned argumentFootprint) = 0;
virtual void return_(unsigned size, Operand* value) = 0; virtual void return_(ir::Value* value) = 0;
virtual void return_() = 0;
virtual void initLocal(unsigned size, unsigned index, OperandType type) = 0; virtual void initLocal(unsigned index, ir::Type type) = 0;
virtual void initLocalsFromLogicalIp(unsigned logicalIp) = 0; virtual void initLocalsFromLogicalIp(unsigned logicalIp) = 0;
virtual void storeLocal(unsigned footprint, Operand* src, virtual void storeLocal(ir::Value* src, unsigned index) = 0;
unsigned index) = 0; virtual ir::Value* loadLocal(ir::Type type, unsigned index) = 0;
virtual Operand* loadLocal(unsigned footprint, unsigned index) = 0;
virtual void saveLocals() = 0; virtual void saveLocals() = 0;
virtual void checkBounds(Operand* object, unsigned lengthOffset, virtual void checkBounds(ir::Value* object,
Operand* index, intptr_t handler) = 0; unsigned lengthOffset,
ir::Value* index,
intptr_t handler) = 0;
virtual void store(unsigned srcSize, Operand* src, unsigned dstSize, virtual ir::Value* truncateThenExtend(ir::SignExtendMode signExtend,
Operand* dst) = 0; ir::Type extendType,
virtual Operand* load(unsigned srcSize, unsigned srcSelectSize, Operand* src, ir::Type truncateType,
unsigned dstSize) = 0; ir::Value* src) = 0;
virtual Operand* loadz(unsigned size, unsigned srcSelectSize, Operand* src,
unsigned dstSize) = 0;
virtual ir::Value* truncate(ir::Type type, ir::Value* src) = 0;
virtual void condJump(lir::TernaryOperation type, unsigned size, Operand* a, Operand* b, Operand* address) = 0; virtual void store(ir::Value* src, ir::Value* dst) = 0;
virtual ir::Value* load(ir::SignExtendMode signExtend,
ir::Value* src,
ir::Type dstType) = 0;
virtual void jmp(Operand* address) = 0; virtual void condJump(lir::TernaryOperation op,
virtual void exit(Operand* address) = 0; ir::Value* a,
ir::Value* b,
ir::Value* address) = 0;
virtual Operand* binaryOp(lir::TernaryOperation type, unsigned size, Operand* a, Operand* b) = 0; virtual void jmp(ir::Value* address) = 0;
virtual Operand* unaryOp(lir::BinaryOperation type, unsigned size, Operand* a) = 0; virtual void exit(ir::Value* address) = 0;
virtual void nullaryOp(lir::Operation type) = 0;
virtual Operand* f2f(unsigned aSize, unsigned resSize, Operand* a) = 0; virtual ir::Value* binaryOp(lir::TernaryOperation op,
virtual Operand* f2i(unsigned aSize, unsigned resSize, Operand* a) = 0; ir::Type type,
virtual Operand* i2f(unsigned aSize, unsigned resSize, Operand* a) = 0; ir::Value* a,
ir::Value* b) = 0;
virtual ir::Value* unaryOp(lir::BinaryOperation op,
ir::Value* a) = 0;
virtual void nullaryOp(lir::Operation op) = 0;
virtual ir::Value* f2f(ir::Type resType, ir::Value* a) = 0;
virtual ir::Value* f2i(ir::Type resType, ir::Value* a) = 0;
virtual ir::Value* i2f(ir::Type resType, ir::Value* a) = 0;
virtual void compile(uintptr_t stackOverflowHandler, virtual void compile(uintptr_t stackOverflowHandler,
unsigned stackLimitOffset) = 0; unsigned stackLimitOffset) = 0;

157
include/avian/codegen/ir.h Normal file
View File

@ -0,0 +1,157 @@
/* Copyright (c) 2008-2014, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#ifndef AVIAN_CODEGEN_IR_H
#define AVIAN_CODEGEN_IR_H
namespace avian {
namespace codegen {
namespace ir {
class TargetInfo {
public:
unsigned pointerSize;
explicit TargetInfo(unsigned pointerSize) : pointerSize(pointerSize)
{
}
};
class Type {
public:
enum Flavor {
// A GC-visiible reference
Object,
// GC-invisible types
Integer,
Float,
Address,
// Represents individual halves of two-word types
// (double/long on 32-bit systems)
// TODO: remove when possible
Half,
// Represents the lack of a return value
// TODO: remove when possible
Void,
};
typedef int16_t TypeDesc;
#define TY_DESC(flavor, size) ((flavor & 0xff) | ((size & 0xff) << 8))
// TODO: once we upgrade to c++11, these should become plain constants (rather
// than function calls).
// The constructor will need to be declared 'constexpr'.
static inline Type void_()
{
return TY_DESC(Void, 0);
}
static inline Type object()
{
return TY_DESC(Object, -1);
}
static inline Type iptr()
{
return TY_DESC(Integer, -1);
}
static inline Type i1()
{
return TY_DESC(Integer, 1);
}
static inline Type i2()
{
return TY_DESC(Integer, 2);
}
static inline Type i4()
{
return TY_DESC(Integer, 4);
}
static inline Type i8()
{
return TY_DESC(Integer, 8);
}
static inline Type f4()
{
return TY_DESC(Float, 4);
}
static inline Type f8()
{
return TY_DESC(Float, 8);
}
static inline Type addr()
{
return TY_DESC(Address, -1);
}
#undef TY_DESC
private:
TypeDesc desc;
friend class Types;
// TODO: once we move to c++11, declare this 'constexpr', to allow
// compile-time constants of this type.
/* constexpr */ Type(TypeDesc desc) : desc(desc)
{
}
public:
inline Flavor flavor() const
{
return (Flavor)(desc & 0xff);
}
// If the size isn't known without inspecting the TargetInfo, returns -1.
// Otherwise, matches size(TargetInfo).
inline int rawSize() const
{
return desc >> 8;
}
inline unsigned size(const TargetInfo& t) const
{
int s = rawSize();
if (s < 0) {
return t.pointerSize;
}
return (unsigned)s;
}
inline bool operator==(const Type& other) const
{
return desc == other.desc;
}
inline bool operator!=(const Type& other) const
{
return !(*this == other);
}
};
enum SignExtendMode { SignExtend, ZeroExtend };
enum CallingConvention { NativeCallingConvention, AvianCallingConvention };
class Value {
public:
ir::Type type;
Value(ir::Type type) : type(type)
{
}
};
} // namespace ir
} // namespace codegen
} // namespace avian
#endif // AVIAN_CODEGEN_IR_H

View File

@ -0,0 +1,32 @@
/* Copyright (c) 2008-2013, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#ifndef AVIAN_UTIL_ASSERT_H
#define AVIAN_UTIL_ASSERT_H
#include <stdlib.h>
namespace avian {
namespace util {
#define UNREACHABLE_ ::abort()
// TODO: print msg in debug mode
#define UNREACHABLE(msg) ::abort()
#define ASSERT(that) \
if (!(that)) { \
UNREACHABLE(#that); \
}
} // namespace util
} // namespace avian
#endif // AVIAN_UTIL_ASSERT_H

View File

@ -13,6 +13,7 @@
#include "allocator.h" #include "allocator.h"
#include "math.h" #include "math.h"
#include "assert.h"
namespace avian { namespace avian {
namespace util { namespace util {
@ -33,6 +34,7 @@ class Slice {
inline T& operator[](size_t index) inline T& operator[](size_t index)
{ {
ASSERT(index < count);
return items[index]; return items[index];
} }
@ -51,20 +53,36 @@ class Slice {
return Slice<T>((T*)a->allocate(sizeof(T) * count), count); return Slice<T>((T*)a->allocate(sizeof(T) * count), count);
} }
Slice<T> clone(Allocator* a) static Slice<T> allocAndSet(Allocator* a, size_t count, const T& item)
{ {
Slice<T> ret((T*)a->allocate(count * sizeof(T)), count); Slice<T> slice(alloc(a, count));
memcpy(ret.items, items, count * sizeof(T)); for (size_t i = 0; i < count; i++) {
return ret; slice[i] = item;
}
return slice;
}
Slice<T> clone(Allocator* a, size_t newCount)
{
T* newItems = (T*)a->allocate(newCount * sizeof(T));
memcpy(newItems, items, min(count, newCount) * sizeof(T));
return Slice<T>(newItems, newCount);
}
Slice<T> cloneAndSet(Allocator* a, size_t newCount, const T& item)
{
Slice<T> slice(clone(a, newCount));
for (size_t i = count; i < newCount; i++) {
slice[i] = item;
}
return slice;
} }
void resize(Allocator* a, size_t newCount) void resize(Allocator* a, size_t newCount)
{ {
T* newItems = (T*)a->allocate(newCount * sizeof(T)); Slice<T> slice(clone(a, newCount));
memcpy(newItems, items, min(count, newCount));
a->free(items, count); a->free(items, count);
items = newItems; *this = slice;
count = newCount;
} }
}; };

View File

@ -1125,6 +1125,7 @@ embed-objects = $(call cpp-objects,$(embed-sources),$(src),$(build-embed))
compiler-sources = \ compiler-sources = \
$(src)/codegen/compiler.cpp \ $(src)/codegen/compiler.cpp \
$(wildcard $(src)/codegen/compiler/*.cpp) \ $(wildcard $(src)/codegen/compiler/*.cpp) \
$(src)/debug-util.cpp \
$(src)/codegen/registers.cpp \ $(src)/codegen/registers.cpp \
$(src)/codegen/runtime.cpp \ $(src)/codegen/runtime.cpp \
$(src)/codegen/targets.cpp \ $(src)/codegen/targets.cpp \

View File

@ -156,7 +156,7 @@ popRead(Context* c, Event* e UNUSED, Value* v)
if (valid(nextWord->reads)) { if (valid(nextWord->reads)) {
deadWord(c, v); deadWord(c, v);
} else { } else {
deadWord(c, nextWord); deadWord(c, nextWord);
} }
} }
@ -186,22 +186,6 @@ addBuddy(Value* original, Value* buddy)
} }
} }
lir::ValueType
valueType(Context* c, Compiler::OperandType type)
{
switch (type) {
case Compiler::ObjectType:
case Compiler::AddressType:
case Compiler::IntegerType:
case Compiler::VoidType:
return lir::ValueGeneral;
case Compiler::FloatType:
return lir::ValueFloat;
default:
abort(c);
}
}
void void
move(Context* c, Value* value, Site* src, Site* dst); move(Context* c, Value* value, Site* src, Site* dst);
@ -751,10 +735,14 @@ saveLocals(Context* c, Event* e)
} }
} }
void void maybeMove(Context* c,
maybeMove(Context* c, lir::BinaryOperation type, unsigned srcSize, lir::BinaryOperation op,
unsigned srcSelectSize, Value* srcValue, unsigned dstSize, Value* dstValue, unsigned srcSize,
const SiteMask& dstMask) unsigned srcSelectSize,
Value* srcValue,
unsigned dstSize,
Value* dstValue,
const SiteMask& dstMask)
{ {
Read* read = live(c, dstValue); Read* read = live(c, dstValue);
bool isStore = read == 0; bool isStore = read == 0;
@ -806,8 +794,14 @@ maybeMove(Context* c, lir::BinaryOperation type, unsigned srcSize,
srcValue->source->freeze(c, srcValue); srcValue->source->freeze(c, srcValue);
apply(c, type, min(srcSelectSize, dstSize), srcValue->source, srcValue->source, apply(c,
dstSize, target, target); op,
min(srcSelectSize, dstSize),
srcValue->source,
srcValue->source,
dstSize,
target,
target);
srcValue->source->thaw(c, srcValue); srcValue->source->thaw(c, srcValue);
} else { } else {
@ -819,9 +813,9 @@ maybeMove(Context* c, lir::BinaryOperation type, unsigned srcSize,
bool thunk; bool thunk;
OperandMask src; OperandMask src;
c->arch->planSource(type, dstSize, src, dstSize, &thunk); c->arch->planSource(op, dstSize, src, dstSize, &thunk);
if (srcValue->type == lir::ValueGeneral) { if (isGeneralValue(srcValue)) {
src.registerMask &= c->regFile->generalRegisters.mask; src.registerMask &= c->regFile->generalRegisters.mask;
} }
@ -844,8 +838,14 @@ maybeMove(Context* c, lir::BinaryOperation type, unsigned srcSize,
srcb, dstb, srcValue, dstValue); srcb, dstb, srcValue, dstValue);
} }
apply(c, type, srcSelectSize, srcValue->source, srcValue->source, apply(c,
dstSize, tmpTarget, tmpTarget); op,
srcSelectSize,
srcValue->source,
srcValue->source,
dstSize,
tmpTarget,
tmpTarget);
tmpTarget->thaw(c, dstValue); tmpTarget->thaw(c, dstValue);
@ -1214,9 +1214,27 @@ storeLocal(Context* c, unsigned footprint, Value* v, unsigned index, bool copy)
return v; return v;
} }
Value* unsigned typeFootprint(Context* c, ir::Type type)
loadLocal(Context* c, unsigned footprint, unsigned index)
{ {
// TODO: this function is very Java-specific in nature. Generalize.
switch (type.flavor()) {
case ir::Type::Float:
case ir::Type::Integer:
return type.rawSize() / 4;
case ir::Type::Object:
case ir::Type::Address:
case ir::Type::Half:
return 1;
case ir::Type::Void:
return 0;
default:
abort(c);
}
}
Value* loadLocal(Context* c, ir::Type type, unsigned index)
{
unsigned footprint = typeFootprint(c, type);
assert(c, index + footprint <= c->localFootprint); assert(c, index + footprint <= c->localFootprint);
if (footprint > 1) { if (footprint > 1) {
@ -1237,17 +1255,10 @@ loadLocal(Context* c, unsigned footprint, unsigned index)
return c->locals[index].value; return c->locals[index].value;
} }
Value* Value* threadRegister(Context* c)
register_(Context* c, int number)
{ {
assert(c, (1 << number) & (c->regFile->generalRegisters.mask Site* s = registerSite(c, c->arch->thread());
| c->regFile->floatRegisters.mask)); return value(c, ir::Type::addr(), s, s);
Site* s = registerSite(c, number);
lir::ValueType type = ((1 << number) & c->regFile->floatRegisters.mask)
? lir::ValueFloat: lir::ValueGeneral;
return value(c, type, s, s);
} }
unsigned unsigned
@ -1506,8 +1517,8 @@ resolveOriginalSites(Context* c, Event* e, SiteRecordList* frozen,
fprintf(stderr, "freeze original %s for %p local %d frame %d\n", fprintf(stderr, "freeze original %s for %p local %d frame %d\n",
buffer, v, el.localIndex, el.frameIndex(c)); buffer, v, el.localIndex, el.frameIndex(c));
} }
Value dummy(0, 0, lir::ValueGeneral); Value dummy(0, 0, ir::Type::addr());
dummy.addSite(c, s); dummy.addSite(c, s);
dummy.removeSite(c, s); dummy.removeSite(c, s);
freeze(c, frozen, s, 0); freeze(c, frozen, s, 0);
@ -2129,26 +2140,9 @@ class MyCompiler: public Compiler {
compiler::restoreState(&c, static_cast<ForkState*>(state)); compiler::restoreState(&c, static_cast<ForkState*>(state));
} }
virtual Subroutine* startSubroutine() {
return c.subroutine = new(c.zone) MySubroutine;
}
virtual void returnFromSubroutine(Subroutine* subroutine, Operand* address) {
appendSaveLocals(&c);
appendJump(&c, lir::Jump, static_cast<Value*>(address), false, true);
static_cast<MySubroutine*>(subroutine)->forkState = compiler::saveState(&c);
}
virtual void linkSubroutine(Subroutine* subroutine) {
Local* oldLocals = c.locals;
restoreState(static_cast<MySubroutine*>(subroutine)->forkState);
linkLocals(&c, oldLocals, c.locals);
}
virtual void init(unsigned logicalCodeLength, unsigned parameterFootprint, virtual void init(unsigned logicalCodeLength, unsigned parameterFootprint,
unsigned localFootprint, unsigned alignedFrameSize) unsigned localFootprint, unsigned alignedFrameSize)
{ {
c.logicalCodeLength = logicalCodeLength;
c.parameterFootprint = parameterFootprint; c.parameterFootprint = parameterFootprint;
c.localFootprint = localFootprint; c.localFootprint = localFootprint;
c.alignedFrameSize = alignedFrameSize; c.alignedFrameSize = alignedFrameSize;
@ -2167,23 +2161,23 @@ class MyCompiler: public Compiler {
c.frameResources[base + c.arch->framePointerOffset()].reserved c.frameResources[base + c.arch->framePointerOffset()].reserved
= UseFramePointer; = UseFramePointer;
// leave room for logical instruction -1 c.logicalCode.init(c.zone, logicalCodeLength);
unsigned codeSize = sizeof(LogicalInstruction*) * (logicalCodeLength + 1);
c.logicalCode = static_cast<LogicalInstruction**> c.logicalCode[-1] = new (c.zone) LogicalInstruction(-1, c.stack, c.locals);
(c.zone->allocate(codeSize));
memset(c.logicalCode, 0, codeSize);
c.logicalCode++;
c.locals = static_cast<Local*> c.locals = static_cast<Local*>
(c.zone->allocate(sizeof(Local) * localFootprint)); (c.zone->allocate(sizeof(Local) * localFootprint));
memset(c.locals, 0, sizeof(Local) * localFootprint); memset(c.locals, 0, sizeof(Local) * localFootprint);
}
c.logicalCode[-1] = new(c.zone) LogicalInstruction(-1, c.stack, c.locals); virtual void extendLogicalCode(unsigned more)
{
c.logicalCode.extend(c.zone, more);
} }
virtual void visitLogicalIp(unsigned logicalIp) { virtual void visitLogicalIp(unsigned logicalIp) {
assert(&c, logicalIp < c.logicalCodeLength); assert(&c, logicalIp < c.logicalCode.count());
if (c.logicalCode[c.logicalIp]->lastEvent == 0) { if (c.logicalCode[c.logicalIp]->lastEvent == 0) {
appendDummy(&c); appendDummy(&c);
@ -2215,17 +2209,11 @@ class MyCompiler: public Compiler {
populateJunctionReads(&c, link); populateJunctionReads(&c, link);
} }
if (c.subroutine) {
c.subroutine->forkState
= c.logicalCode[logicalIp]->subroutine->forkState;
c.subroutine = 0;
}
c.forkState = 0; c.forkState = 0;
} }
virtual void startLogicalIp(unsigned logicalIp) { virtual void startLogicalIp(unsigned logicalIp) {
assert(&c, logicalIp < c.logicalCodeLength); assert(&c, logicalIp < c.logicalCode.count());
assert(&c, c.logicalCode[logicalIp] == 0); assert(&c, c.logicalCode[logicalIp] == 0);
if (c.logicalCode[c.logicalIp]->lastEvent == 0) { if (c.logicalCode[c.logicalIp]->lastEvent == 0) {
@ -2240,30 +2228,7 @@ class MyCompiler: public Compiler {
c.logicalCode[logicalIp] = new(c.zone) LogicalInstruction(logicalIp, c.stack, c.locals); c.logicalCode[logicalIp] = new(c.zone) LogicalInstruction(logicalIp, c.stack, c.locals);
bool startSubroutine = c.subroutine != 0;
if (startSubroutine) {
c.logicalCode[logicalIp]->subroutine = c.subroutine;
c.subroutine = 0;
}
c.logicalIp = logicalIp; c.logicalIp = logicalIp;
if (startSubroutine) {
// assume all local variables are initialized on entry to a
// subroutine, since other calls to the subroutine may
// initialize them:
unsigned sizeInBytes = sizeof(Local) * c.localFootprint;
Local* newLocals = static_cast<Local*>(c.zone->allocate(sizeInBytes));
memcpy(newLocals, c.locals, sizeInBytes);
c.locals = newLocals;
for (unsigned li = 0; li < c.localFootprint; ++li) {
Local* local = c.locals + li;
if (local->value == 0) {
initLocal(1, li, IntegerType);
}
}
}
} }
virtual Promise* machineIp(unsigned logicalIp) { virtual Promise* machineIp(unsigned logicalIp) {
@ -2290,71 +2255,82 @@ class MyCompiler: public Compiler {
return p; return p;
} }
virtual Operand* constant(int64_t value, Compiler::OperandType type) { virtual ir::Value* constant(int64_t value, ir::Type type)
{
return promiseConstant(resolvedPromise(&c, value), type); return promiseConstant(resolvedPromise(&c, value), type);
} }
virtual Operand* promiseConstant(Promise* value, Compiler::OperandType type) { virtual ir::Value* promiseConstant(Promise* value, ir::Type type)
return compiler::value
(&c, valueType(&c, type), compiler::constantSite(&c, value));
}
virtual Operand* address(Promise* address) {
return value(&c, lir::ValueGeneral, compiler::addressSite(&c, address));
}
virtual Operand* memory(Operand* base,
OperandType type,
int displacement = 0,
Operand* index = 0,
unsigned scale = 1)
{ {
Value* result = value(&c, valueType(&c, type)); return compiler::value(&c, type, compiler::constantSite(&c, value));
}
appendMemory(&c, static_cast<Value*>(base), displacement, virtual ir::Value* address(ir::Type type, Promise* address)
static_cast<Value*>(index), scale, result); {
return value(&c, type, compiler::addressSite(&c, address));
}
virtual ir::Value* memory(ir::Value* base,
ir::Type type,
int displacement = 0,
ir::Value* index = 0)
{
Value* result = value(&c, type);
appendMemory(&c,
static_cast<Value*>(base),
displacement,
static_cast<Value*>(index),
index == 0 ? 1 : type.size(c.targetInfo),
result);
return result; return result;
} }
virtual Operand* register_(int number) { virtual ir::Value* threadRegister()
return compiler::register_(&c, number); {
return compiler::threadRegister(&c);
} }
Promise* machineIp() { Promise* machineIp() {
return c.logicalCode[c.logicalIp]->lastEvent->makeCodePromise(&c); return c.logicalCode[c.logicalIp]->lastEvent->makeCodePromise(&c);
} }
virtual void push(unsigned footprint UNUSED) { virtual void push(ir::Type type, ir::Value* value)
assert(&c, footprint == 1); {
// TODO: once type information is flowed properly, enable this assert.
Value* v = value(&c, lir::ValueGeneral); // Some time later, we can remove the parameter.
Stack* s = compiler::stack(&c, v, c.stack); // assert(&c, value->type == type);
compiler::push(&c, typeFootprint(&c, type), static_cast<Value*>(value));
v->home = frameIndex(&c, s->index + c.localFootprint);
c.stack = s;
} }
virtual void push(unsigned footprint, Operand* value) { virtual void save(ir::Type type, ir::Value* value)
compiler::push(&c, footprint, static_cast<Value*>(value)); {
} // TODO: once type information is flowed properly, enable this assert.
// Some time later, we can remove the parameter.
virtual void save(unsigned footprint, Operand* value) { // assert(&c, value->type == type);
unsigned footprint = typeFootprint(&c, type);
c.saved = cons(&c, static_cast<Value*>(value), c.saved); c.saved = cons(&c, static_cast<Value*>(value), c.saved);
if (TargetBytesPerWord == 4 and footprint > 1) { if (TargetBytesPerWord == 4 and footprint > 1) {
assert(&c, footprint == 2); assert(&c, footprint == 2);
assert(&c, static_cast<Value*>(value)->nextWord); assert(&c, static_cast<Value*>(value)->nextWord);
save(1, static_cast<Value*>(value)->nextWord); save(ir::Type::i4(), static_cast<Value*>(value)->nextWord);
} }
} }
virtual Operand* pop(unsigned footprint) { virtual ir::Value* pop(ir::Type type)
return compiler::pop(&c, footprint); {
ir::Value* value = compiler::pop(&c, typeFootprint(&c, type));
// TODO: once type information is flowed properly, enable this assert.
// Some time later, we can remove the parameter.
// assert(&c, static_cast<Value*>(value)->type == type);
return value;
} }
virtual void pushed() { virtual void pushed(ir::Type type)
Value* v = value(&c, lir::ValueGeneral); {
Value* v = value(&c, type);
appendFrameSite appendFrameSite
(&c, v, frameIndex (&c, v, frameIndex
(&c, (c.stack ? c.stack->index : 0) + c.localFootprint)); (&c, (c.stack ? c.stack->index : 0) + c.localFootprint));
@ -2380,7 +2356,8 @@ class MyCompiler: public Compiler {
return c.stack->index; return c.stack->index;
} }
virtual Operand* peek(unsigned footprint, unsigned index) { virtual ir::Value* peek(unsigned footprint, unsigned index)
{
Stack* s = c.stack; Stack* s = c.stack;
for (unsigned i = index; i > 0; --i) { for (unsigned i = index; i > 0; --i) {
s = s->next; s = s->next;
@ -2416,13 +2393,12 @@ class MyCompiler: public Compiler {
return s->value; return s->value;
} }
virtual Operand* call(Operand* address, virtual ir::Value* call(ir::Value* address,
unsigned flags, unsigned flags,
TraceHandler* traceHandler, TraceHandler* traceHandler,
unsigned resultSize, ir::Type resultType,
OperandType resultType, unsigned argumentCount,
unsigned argumentCount, ...)
...)
{ {
va_list a; va_start(a, argumentCount); va_list a; va_start(a, argumentCount);
@ -2430,7 +2406,7 @@ class MyCompiler: public Compiler {
unsigned footprint = 0; unsigned footprint = 0;
unsigned size = TargetBytesPerWord; unsigned size = TargetBytesPerWord;
RUNTIME_ARRAY(Value*, arguments, argumentCount); RUNTIME_ARRAY(ir::Value*, arguments, argumentCount);
int index = 0; int index = 0;
for (unsigned i = 0; i < argumentCount; ++i) { for (unsigned i = 0; i < argumentCount; ++i) {
Value* o = va_arg(a, Value*); Value* o = va_arg(a, Value*);
@ -2452,41 +2428,74 @@ class MyCompiler: public Compiler {
va_end(a); va_end(a);
Stack* argumentStack = c.stack; Value* result = value(&c, resultType);
for (int i = index - 1; i >= 0; --i) { appendCall(&c,
argumentStack = compiler::stack static_cast<Value*>(address),
(&c, RUNTIME_ARRAY_BODY(arguments)[i], argumentStack); ir::NativeCallingConvention,
flags,
traceHandler,
result,
util::Slice<ir::Value*>(RUNTIME_ARRAY_BODY(arguments), index));
return result;
}
virtual ir::Value* stackCall(ir::Value* address,
unsigned flags,
TraceHandler* traceHandler,
ir::Type resultType,
Slice<ir::Value*> arguments)
{
Value* result = value(&c, resultType);
Stack* b UNUSED = c.stack;
appendCall(&c,
static_cast<Value*>(address),
ir::AvianCallingConvention,
flags,
traceHandler,
result,
arguments);
assert(&c, c.stack == b);
return result;
}
virtual void return_(ir::Value* a)
{
assert(&c, a);
appendReturn(&c, static_cast<Value*>(a));
}
virtual void return_()
{
appendReturn(&c, 0);
}
void initLocalPart(unsigned index, ir::Type type)
{
Value* v = value(&c, type);
if (DebugFrame) {
fprintf(stderr,
"init local %p at %d (%d)\n",
v,
index,
frameIndex(&c, index));
} }
Value* result = value(&c, valueType(&c, resultType)); appendFrameSite(&c, v, frameIndex(&c, index));
appendCall(&c, static_cast<Value*>(address), flags, traceHandler, result,
resultSize, argumentStack, index, 0);
return result; Local* local = c.locals + index;
local->value = v;
v->home = frameIndex(&c, index);
} }
virtual Operand* stackCall(Operand* address, virtual void initLocal(unsigned index, ir::Type type)
unsigned flags,
TraceHandler* traceHandler,
unsigned resultSize,
OperandType resultType,
unsigned argumentFootprint)
{ {
Value* result = value(&c, valueType(&c, resultType)); unsigned footprint = typeFootprint(&c, type);
appendCall(&c, static_cast<Value*>(address), flags, traceHandler, result,
resultSize, c.stack, 0, argumentFootprint);
return result;
}
virtual void return_(unsigned size, Operand* value) {
appendReturn(&c, size, static_cast<Value*>(value));
}
virtual void initLocal(unsigned footprint, unsigned index, OperandType type)
{
assert(&c, index + footprint <= c.localFootprint); assert(&c, index + footprint <= c.localFootprint);
Value* v = value(&c, valueType(&c, type)); Value* v = value(&c, type);
if (footprint > 1) { if (footprint > 1) {
assert(&c, footprint == 2); assert(&c, footprint == 2);
@ -2498,11 +2507,11 @@ class MyCompiler: public Compiler {
lowIndex = index; lowIndex = index;
} else { } else {
lowIndex = index + 1; lowIndex = index + 1;
highIndex = index; highIndex = index;
} }
if (TargetBytesPerWord == 4) { if (TargetBytesPerWord == 4) {
initLocal(1, highIndex, type); initLocalPart(highIndex, type);
Value* next = c.locals[highIndex].value; Value* next = c.locals[highIndex].value;
v->nextWord = next; v->nextWord = next;
next->nextWord = v; next->nextWord = v;
@ -2525,7 +2534,7 @@ class MyCompiler: public Compiler {
} }
virtual void initLocalsFromLogicalIp(unsigned logicalIp) { virtual void initLocalsFromLogicalIp(unsigned logicalIp) {
assert(&c, logicalIp < c.logicalCodeLength); assert(&c, logicalIp < c.logicalCode.count());
unsigned footprint = sizeof(Local) * c.localFootprint; unsigned footprint = sizeof(Local) * c.localFootprint;
Local* newLocals = static_cast<Local*>(c.zone->allocate(footprint)); Local* newLocals = static_cast<Local*>(c.zone->allocate(footprint));
@ -2536,127 +2545,203 @@ class MyCompiler: public Compiler {
for (int i = 0; i < static_cast<int>(c.localFootprint); ++i) { for (int i = 0; i < static_cast<int>(c.localFootprint); ++i) {
Local* local = e->locals() + i; Local* local = e->locals() + i;
if (local->value) { if (local->value) {
initLocal initLocalPart(i, local->value->type);
(1, i, local->value->type == lir::ValueGeneral ? IntegerType : FloatType);
} }
} }
linkLocals(&c, e->locals(), newLocals); linkLocals(&c, e->locals(), newLocals);
} }
virtual void storeLocal(unsigned footprint, Operand* src, unsigned index) { virtual void storeLocal(ir::Value* src, unsigned index)
compiler::storeLocal(&c, footprint, static_cast<Value*>(src), index, true); {
compiler::storeLocal(&c, typeFootprint(&c, src->type), static_cast<Value*>(src), index, true);
} }
virtual Operand* loadLocal(unsigned footprint, unsigned index) { virtual ir::Value* loadLocal(ir::Type type, unsigned index)
return compiler::loadLocal(&c, footprint, index); {
return compiler::loadLocal(&c, type, index);
} }
virtual void saveLocals() { virtual void saveLocals() {
int oldIp UNUSED = c.logicalIp;
appendSaveLocals(&c); appendSaveLocals(&c);
assert(&c, oldIp == c.logicalIp);
} }
virtual void checkBounds(Operand* object, unsigned lengthOffset, virtual void checkBounds(ir::Value* object,
Operand* index, intptr_t handler) unsigned lengthOffset,
ir::Value* index,
intptr_t handler)
{ {
appendBoundsCheck(&c, static_cast<Value*>(object), lengthOffset, appendBoundsCheck(&c, static_cast<Value*>(object), lengthOffset,
static_cast<Value*>(index), handler); static_cast<Value*>(index), handler);
} }
virtual void store(unsigned srcSize, Operand* src, unsigned dstSize, virtual ir::Value* truncate(ir::Type type, ir::Value* src)
Operand* dst)
{ {
appendMove(&c, lir::Move, srcSize, srcSize, static_cast<Value*>(src), assert(&c, src->type.flavor() == type.flavor());
dstSize, static_cast<Value*>(dst)); assert(&c, type.flavor() != ir::Type::Float);
} assert(&c, type.rawSize() < src->type.rawSize());
Value* dst = value(&c, type);
virtual Operand* load(unsigned srcSize, unsigned srcSelectSize, Operand* src, appendMove(&c,
unsigned dstSize) lir::Move,
{ src->type.size(c.targetInfo),
assert(&c, dstSize >= TargetBytesPerWord); src->type.size(c.targetInfo),
static_cast<Value*>(src),
Value* dst = value(&c, static_cast<Value*>(src)->type); type.size(c.targetInfo),
appendMove(&c, lir::Move, srcSize, srcSelectSize, static_cast<Value*>(src), dst);
dstSize, dst);
return dst; return dst;
} }
virtual Operand* loadz(unsigned srcSize, unsigned srcSelectSize, virtual ir::Value* truncateThenExtend(ir::SignExtendMode signExtend,
Operand* src, unsigned dstSize) ir::Type extendType,
ir::Type truncateType,
ir::Value* src)
{ {
assert(&c, dstSize >= TargetBytesPerWord); Value* dst = value(&c, extendType);
appendMove(&c,
Value* dst = value(&c, static_cast<Value*>(src)->type); signExtend == ir::SignExtend ? lir::Move : lir::MoveZ,
appendMove(&c, lir::MoveZ, srcSize, srcSelectSize, static_cast<Value*>(src), TargetBytesPerWord,
dstSize, dst); truncateType.size(c.targetInfo),
static_cast<Value*>(src),
extendType.size(c.targetInfo) < TargetBytesPerWord
? TargetBytesPerWord
: extendType.size(c.targetInfo),
dst);
return dst; return dst;
} }
virtual void condJump(lir::TernaryOperation type, unsigned size, Operand* a, Operand* b, virtual void store(ir::Value* src, ir::Value* dst)
Operand* address) {
assert(&c, src->type.flavor() == dst->type.flavor());
appendMove(&c,
lir::Move,
src->type.size(c.targetInfo),
src->type.size(c.targetInfo),
static_cast<Value*>(src),
dst->type.size(c.targetInfo),
static_cast<Value*>(dst));
}
virtual ir::Value* load(ir::SignExtendMode signExtend,
ir::Value* src,
ir::Type dstType)
{
assert(&c, src->type.flavor() == dstType.flavor());
Value* dst = value(&c, dstType);
appendMove(&c,
signExtend == ir::SignExtend ? lir::Move : lir::MoveZ,
src->type.size(c.targetInfo),
src->type.size(c.targetInfo),
static_cast<Value*>(src),
dstType.size(c.targetInfo) < TargetBytesPerWord
? TargetBytesPerWord
: dstType.size(c.targetInfo),
dst);
return dst;
}
virtual void condJump(lir::TernaryOperation op,
ir::Value* a,
ir::Value* b,
ir::Value* addr)
{ {
assert(&c, assert(&c,
(isGeneralBranch(type) and isGeneralValue(a) and isGeneralValue(b)) (isGeneralBranch(op) and isGeneralValue(a) and isGeneralValue(b))or(
or (isFloatBranch(type) and isFloatValue(a) and isFloatValue(b))); isFloatBranch(op) and isFloatValue(a) and isFloatValue(b)));
appendBranch(&c, type, size, static_cast<Value*>(a), assert(&c, a->type == b->type);
static_cast<Value*>(b), static_cast<Value*>(address)); assert(&c, addr->type == ir::Type::iptr());
appendBranch(&c,
op,
static_cast<Value*>(a),
static_cast<Value*>(b),
static_cast<Value*>(addr));
} }
virtual void jmp(Operand* address) { virtual void jmp(ir::Value* addr)
appendJump(&c, lir::Jump, static_cast<Value*>(address)); {
appendJump(&c, lir::Jump, static_cast<Value*>(addr));
} }
virtual void exit(Operand* address) { virtual void exit(ir::Value* addr)
appendJump(&c, lir::Jump, static_cast<Value*>(address), true); {
appendJump(&c, lir::Jump, static_cast<Value*>(addr), true);
} }
virtual Operand* binaryOp(lir::TernaryOperation type, unsigned size, Operand* a, Operand* b) { virtual ir::Value* binaryOp(lir::TernaryOperation op,
ir::Type type,
ir::Value* a,
ir::Value* b)
{
assert(&c, assert(&c,
(isGeneralBinaryOp(type) and isGeneralValue(a) and isGeneralValue(b)) (isGeneralBinaryOp(op) and isGeneralValue(a) and isGeneralValue(b))
or (isFloatBinaryOp(type) and isFloatValue(a) and isFloatValue(b))); or(isFloatBinaryOp(op) and isFloatValue(a) and isFloatValue(b)));
Value* result = value(&c, static_cast<Value*>(a)->type); Value* result = value(&c, type);
appendCombine(&c, type, size, static_cast<Value*>(a), appendCombine(&c,
size, static_cast<Value*>(b), size, result); op,
static_cast<Value*>(a),
static_cast<Value*>(b),
result);
return result; return result;
} }
virtual Operand* unaryOp(lir::BinaryOperation type, unsigned size, Operand* a) { virtual ir::Value* unaryOp(lir::BinaryOperation op,
assert(&c, (isGeneralUnaryOp(type) and isGeneralValue(a))or( ir::Value* a)
isFloatUnaryOp(type) and isFloatValue(a))); {
Value* result = value(&c, static_cast<Value*>(a)->type); assert(&c,
appendTranslate(&c, type, size, static_cast<Value*>(a), size, result); (isGeneralUnaryOp(op) and isGeneralValue(a))or(isFloatUnaryOp(op)
return result; and isFloatValue(a)));
} Value* result = value(&c, a->type);
appendTranslate(
virtual Operand* f2f(unsigned aSize, unsigned resSize, Operand* a) { &c, op, static_cast<Value*>(a), result);
assert(&c, static_cast<Value*>(a)->type == lir::ValueFloat);
Value* result = value(&c, lir::ValueFloat);
appendTranslate
(&c, lir::Float2Float, aSize, static_cast<Value*>(a), resSize, result);
return result;
}
virtual Operand* f2i(unsigned aSize, unsigned resSize, Operand* a) {
assert(&c, static_cast<Value*>(a)->type == lir::ValueFloat);
Value* result = value(&c, lir::ValueGeneral);
appendTranslate
(&c, lir::Float2Int, aSize, static_cast<Value*>(a), resSize, result);
return result;
}
virtual Operand* i2f(unsigned aSize, unsigned resSize, Operand* a) {
assert(&c, static_cast<Value*>(a)->type == lir::ValueGeneral);
Value* result = value(&c, lir::ValueFloat);
appendTranslate
(&c, lir::Int2Float, aSize, static_cast<Value*>(a), resSize, result);
return result; return result;
} }
virtual void nullaryOp(lir::Operation type) { virtual ir::Value* f2f(ir::Type resType, ir::Value* a)
appendOperation(&c, type); {
assert(&c, isFloatValue(a));
assert(&c, resType.flavor() == ir::Type::Float);
Value* result = value(&c, resType);
appendTranslate(&c,
lir::Float2Float,
static_cast<Value*>(a),
result);
return result;
}
virtual ir::Value* f2i(ir::Type resType, ir::Value* a)
{
assert(&c, isFloatValue(a));
assert(&c, resType.flavor() != ir::Type::Float);
Value* result = value(&c, resType);
appendTranslate(&c,
lir::Float2Int,
static_cast<Value*>(a),
result);
return result;
}
virtual ir::Value* i2f(ir::Type resType, ir::Value* a)
{
assert(&c, isGeneralValue(a));
assert(&c, resType.flavor() == ir::Type::Float);
Value* result = value(&c, resType);
appendTranslate(&c,
lir::Int2Float,
static_cast<Value*>(a),
result);
return result;
}
virtual void nullaryOp(lir::Operation op)
{
appendOperation(&c, op);
} }
virtual void compile(uintptr_t stackOverflowHandler, virtual void compile(uintptr_t stackOverflowHandler,

View File

@ -17,41 +17,41 @@ namespace avian {
namespace codegen { namespace codegen {
namespace compiler { namespace compiler {
Context::Context(vm::System* system, Assembler* assembler, vm::Zone* zone, Context::Context(vm::System* system,
Compiler::Client* client): Assembler* assembler,
system(system), vm::Zone* zone,
assembler(assembler), Compiler::Client* client)
arch(assembler->arch()), : system(system),
zone(zone), assembler(assembler),
client(client), arch(assembler->arch()),
stack(0), zone(zone),
locals(0), client(client),
saved(0), stack(0),
predecessor(0), locals(0),
logicalCode(0), saved(0),
regFile(arch->registerFile()), predecessor(0),
regAlloc(system, arch->registerFile()), regFile(arch->registerFile()),
registerResources regAlloc(system, arch->registerFile()),
(static_cast<RegisterResource*> registerResources(static_cast<RegisterResource*>(zone->allocate(
(zone->allocate(sizeof(RegisterResource) * regFile->allRegisters.limit))), sizeof(RegisterResource) * regFile->allRegisters.limit))),
frameResources(0), frameResources(0),
acquiredResources(0), acquiredResources(0),
firstConstant(0), firstConstant(0),
lastConstant(0), lastConstant(0),
machineCode(0), machineCode(0),
firstEvent(0), firstEvent(0),
lastEvent(0), lastEvent(0),
forkState(0), forkState(0),
subroutine(0), firstBlock(0),
firstBlock(0), logicalIp(-1),
logicalIp(-1), constantCount(0),
constantCount(0), parameterFootprint(0),
logicalCodeLength(0), localFootprint(0),
parameterFootprint(0), machineCodeSize(0),
localFootprint(0), alignedFrameSize(0),
machineCodeSize(0), availableGeneralRegisterCount(regFile->generalRegisters.limit
alignedFrameSize(0), - regFile->generalRegisters.start),
availableGeneralRegisterCount(regFile->generalRegisters.limit - regFile->generalRegisters.start) targetInfo(arch->targetInfo())
{ {
for (unsigned i = regFile->generalRegisters.start; i < regFile->generalRegisters.limit; ++i) { for (unsigned i = regFile->generalRegisters.start; i < regFile->generalRegisters.limit; ++i) {
new (registerResources + i) RegisterResource(arch->reserved(i)); new (registerResources + i) RegisterResource(arch->reserved(i));

View File

@ -35,7 +35,6 @@ class FrameResource;
class ConstantPoolNode; class ConstantPoolNode;
class ForkState; class ForkState;
class MySubroutine;
class Block; class Block;
template<class T> template<class T>
@ -50,6 +49,48 @@ List<T>* reverseDestroy(List<T>* cell) {
return previous; return previous;
} }
class LogicalCode {
private:
util::Slice<LogicalInstruction*> logicalCode;
public:
LogicalCode() : logicalCode(0, 0)
{
}
void init(vm::Zone* zone, size_t count)
{
// leave room for logical instruction -1
size_t realCount = count + 1;
logicalCode
= util::Slice<LogicalInstruction*>::allocAndSet(zone, realCount, 0);
}
void extend(vm::Zone* zone, size_t more)
{
util::Slice<LogicalInstruction*> newCode
= logicalCode.cloneAndSet(zone, logicalCode.count + more, 0);
for (size_t i = 0; i < logicalCode.count; i++) {
assert((vm::System*)0, logicalCode[i] == newCode[i]);
}
logicalCode = newCode;
}
size_t count()
{
return logicalCode.count - 1;
}
LogicalInstruction*& operator[](int index)
{
// leave room for logical instruction -1
return logicalCode[index + 1];
}
};
class Context { class Context {
public: public:
Context(vm::System* system, Assembler* assembler, vm::Zone* zone, Context(vm::System* system, Assembler* assembler, vm::Zone* zone,
@ -64,7 +105,7 @@ class Context {
Local* locals; Local* locals;
List<Value*>* saved; List<Value*>* saved;
Event* predecessor; Event* predecessor;
LogicalInstruction** logicalCode; LogicalCode logicalCode;
const RegisterFile* regFile; const RegisterFile* regFile;
RegisterAllocator regAlloc; RegisterAllocator regAlloc;
RegisterResource* registerResources; RegisterResource* registerResources;
@ -76,16 +117,15 @@ class Context {
Event* firstEvent; Event* firstEvent;
Event* lastEvent; Event* lastEvent;
ForkState* forkState; ForkState* forkState;
MySubroutine* subroutine;
Block* firstBlock; Block* firstBlock;
int logicalIp; int logicalIp;
unsigned constantCount; unsigned constantCount;
unsigned logicalCodeLength;
unsigned parameterFootprint; unsigned parameterFootprint;
unsigned localFootprint; unsigned localFootprint;
unsigned machineCodeSize; unsigned machineCodeSize;
unsigned alignedFrameSize; unsigned alignedFrameSize;
unsigned availableGeneralRegisterCount; unsigned availableGeneralRegisterCount;
ir::TargetInfo targetInfo;
}; };
inline Aborter* getAborter(Context* c) { inline Aborter* getAborter(Context* c) {

File diff suppressed because it is too large Load Diff

View File

@ -113,28 +113,34 @@ Link*
link(Context* c, Event* predecessor, Link* nextPredecessor, Event* successor, link(Context* c, Event* predecessor, Link* nextPredecessor, Event* successor,
Link* nextSuccessor, ForkState* forkState); Link* nextSuccessor, ForkState* forkState);
void void appendCall(Context* c,
appendCall(Context* c, Value* address, unsigned flags, Value* address,
TraceHandler* traceHandler, Value* result, unsigned resultSize, ir::CallingConvention callingConvention,
Stack* argumentStack, unsigned argumentCount, unsigned flags,
unsigned stackArgumentFootprint); TraceHandler* traceHandler,
Value* result,
util::Slice<ir::Value*> arguments);
void void appendReturn(Context* c, Value* value);
appendReturn(Context* c, unsigned size, Value* value);
void void appendMove(Context* c,
appendMove(Context* c, lir::BinaryOperation type, unsigned srcSize, lir::BinaryOperation op,
unsigned srcSelectSize, Value* src, unsigned dstSize, Value* dst); unsigned srcSize,
unsigned srcSelectSize,
Value* src,
unsigned dstSize,
Value* dst);
void void appendCombine(Context* c,
appendCombine(Context* c, lir::TernaryOperation type, lir::TernaryOperation op,
unsigned firstSize, Value* first, Value* first,
unsigned secondSize, Value* second, Value* second,
unsigned resultSize, Value* result); Value* result);
void void appendTranslate(Context* c,
appendTranslate(Context* c, lir::BinaryOperation type, unsigned firstSize, lir::BinaryOperation op,
Value* first, unsigned resultSize, Value* result); Value* first,
Value* result);
void void
appendOperation(Context* c, lir::Operation op); appendOperation(Context* c, lir::Operation op);
@ -143,13 +149,17 @@ void
appendMemory(Context* c, Value* base, int displacement, Value* index, appendMemory(Context* c, Value* base, int displacement, Value* index,
unsigned scale, Value* result); unsigned scale, Value* result);
void void appendBranch(Context* c,
appendBranch(Context* c, lir::TernaryOperation type, unsigned size, Value* first, lir::TernaryOperation op,
Value* second, Value* address); Value* first,
Value* second,
Value* address);
void void appendJump(Context* c,
appendJump(Context* c, lir::UnaryOperation type, Value* address, bool exit = false, lir::UnaryOperation op,
bool cleanLocals = false); Value* address,
bool exit = false,
bool cleanLocals = false);
void void
appendBoundsCheck(Context* c, Value* object, unsigned lengthOffset, appendBoundsCheck(Context* c, Value* object, unsigned lengthOffset,
@ -164,6 +174,8 @@ appendSaveLocals(Context* c);
void void
appendDummy(Context* c); appendDummy(Context* c);
void appendBuddy(Context* c, Value* original, Value* buddy);
} // namespace compiler } // namespace compiler
} // namespace codegen } // namespace codegen
} // namespace avian } // namespace avian

View File

@ -45,16 +45,18 @@ int frameIndex(Context* c, int localIndex) {
unsigned frameIndexToOffset(Context* c, unsigned frameIndex) { unsigned frameIndexToOffset(Context* c, unsigned frameIndex) {
assert(c, frameIndex < totalFrameSize(c)); assert(c, frameIndex < totalFrameSize(c));
return (frameIndex + c->arch->frameFooterSize()) * vm::TargetBytesPerWord; return (frameIndex + c->arch->frameFooterSize()) * c->targetInfo.pointerSize;
} }
unsigned offsetToFrameIndex(Context* c, unsigned offset) { unsigned offsetToFrameIndex(Context* c, unsigned offset) {
assert(c, static_cast<int> assert(c,
((offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize()) >= 0); static_cast<int>((offset / c->targetInfo.pointerSize)
assert(c, ((offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize()) - c->arch->frameFooterSize()) >= 0);
assert(c,
((offset / c->targetInfo.pointerSize) - c->arch->frameFooterSize())
< totalFrameSize(c)); < totalFrameSize(c));
return (offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize(); return (offset / c->targetInfo.pointerSize) - c->arch->frameFooterSize();
} }
unsigned frameBase(Context* c) { unsigned frameBase(Context* c) {

View File

@ -15,14 +15,19 @@ namespace avian {
namespace codegen { namespace codegen {
namespace compiler { namespace compiler {
LogicalInstruction::LogicalInstruction(int index, Stack* stack, Local* locals): LogicalInstruction::LogicalInstruction(int index, Stack* stack, Local* locals)
firstEvent(0), lastEvent(0), immediatePredecessor(0), stack(stack), : firstEvent(0),
locals(locals), machineOffset(0), subroutine(0), index(index) lastEvent(0),
immediatePredecessor(0),
stack(stack),
locals(locals),
machineOffset(0),
/*subroutine(0), */ index(index)
{ } { }
LogicalInstruction* LogicalInstruction::next(Context* c) { LogicalInstruction* LogicalInstruction::next(Context* c) {
LogicalInstruction* i = this; LogicalInstruction* i = this;
for (unsigned n = i->index + 1; n < c->logicalCodeLength; ++n) { for (size_t n = i->index + 1; n < c->logicalCode.count(); ++n) {
i = c->logicalCode[n]; i = c->logicalCode[n];
if (i) return i; if (i) return i;
} }

View File

@ -57,17 +57,9 @@ class LogicalInstruction {
Stack* stack; Stack* stack;
Local* locals; Local* locals;
Promise* machineOffset; Promise* machineOffset;
MySubroutine* subroutine;
int index; int index;
}; };
class MySubroutine: public Compiler::Subroutine {
public:
MySubroutine(): forkState(0) { }
ForkState* forkState;
};
class Block { class Block {
public: public:
Block(Event* head); Block(Event* head);

View File

@ -90,9 +90,10 @@ class PoolPromise: public Promise {
virtual int64_t value() { virtual int64_t value() {
if (resolved()) { if (resolved()) {
return reinterpret_cast<int64_t> return reinterpret_cast<int64_t>(
(c->machineCode + vm::pad(c->machineCodeSize, vm::TargetBytesPerWord) c->machineCode
+ (key * vm::TargetBytesPerWord)); + vm::pad(c->machineCodeSize, c->targetInfo.pointerSize)
+ (key * c->targetInfo.pointerSize));
} }
abort(c); abort(c);

View File

@ -215,12 +215,12 @@ pickTarget(Context* c, Read* read, bool intersectRead,
Value* value = read->value; Value* value = read->value;
uint32_t registerMask uint32_t registerMask
= (value->type == lir::ValueFloat ? ~0 : c->regFile->generalRegisters.mask); = (isFloatValue(value) ? ~0 : c->regFile->generalRegisters.mask);
SiteMask mask(~0, registerMask, AnyFrameIndex); SiteMask mask(~0, registerMask, AnyFrameIndex);
read->intersect(&mask); read->intersect(&mask);
if (value->type == lir::ValueFloat) { if (isFloatValue(value)) {
uint32_t floatMask = mask.registerMask & c->regFile->floatRegisters.mask; uint32_t floatMask = mask.registerMask & c->regFile->floatRegisters.mask;
if (floatMask) { if (floatMask) {
mask.registerMask = floatMask; mask.registerMask = floatMask;

View File

@ -52,7 +52,7 @@ SiteIterator::SiteIterator(Context* c, Value* v, bool includeBuddies,
Site** SiteIterator::findNext(Site** p) { Site** SiteIterator::findNext(Site** p) {
while (true) { while (true) {
if (*p) { if (*p) {
if (pass == 0 or (*p)->registerSize(c) > vm::TargetBytesPerWord) { if (pass == 0 or (*p)->registerSize(c) > c->targetInfo.pointerSize) {
return p; return p;
} else { } else {
p = &((*p)->next); p = &((*p)->next);
@ -103,14 +103,11 @@ void SiteIterator::remove(Context* c) {
previous = 0; previous = 0;
} }
unsigned Site::registerSize(Context* c)
{
unsigned Site::registerSize(Context*) { return c->targetInfo.pointerSize;
return vm::TargetBytesPerWord;
} }
Site* constantSite(Context* c, Promise* value) { Site* constantSite(Context* c, Promise* value) {
return new(c->zone) ConstantSite(value); return new(c->zone) ConstantSite(value);
} }
@ -250,7 +247,7 @@ bool RegisterSite::matchNextWord(Context* c, Site* s, unsigned) {
RegisterSite* rs = static_cast<RegisterSite*>(s); RegisterSite* rs = static_cast<RegisterSite*>(s);
unsigned size = rs->registerSize(c); unsigned size = rs->registerSize(c);
if (size > vm::TargetBytesPerWord) { if (size > c->targetInfo.pointerSize) {
assert(c, number != lir::NoRegister); assert(c, number != lir::NoRegister);
return number == rs->number; return number == rs->number;
} else { } else {
@ -352,7 +349,7 @@ SiteMask RegisterSite::mask(Context* c UNUSED) {
SiteMask RegisterSite::nextWordMask(Context* c, unsigned) { SiteMask RegisterSite::nextWordMask(Context* c, unsigned) {
assert(c, number != lir::NoRegister); assert(c, number != lir::NoRegister);
if (registerSize(c) > vm::TargetBytesPerWord) { if (registerSize(c) > c->targetInfo.pointerSize) {
return SiteMask return SiteMask
(1 << lir::RegisterOperand, number, NoFrameIndex); (1 << lir::RegisterOperand, number, NoFrameIndex);
} else { } else {
@ -367,7 +364,7 @@ unsigned RegisterSite::registerSize(Context* c) {
if ((1 << number) & c->regFile->floatRegisters.mask) { if ((1 << number) & c->regFile->floatRegisters.mask) {
return c->arch->floatRegisterSize(); return c->arch->floatRegisterSize();
} else { } else {
return vm::TargetBytesPerWord; return c->targetInfo.pointerSize;
} }
} }
@ -469,12 +466,15 @@ bool MemorySite::matchNextWord(Context* c, Site* s, unsigned index) {
if (s->type(c) == lir::MemoryOperand) { if (s->type(c) == lir::MemoryOperand) {
MemorySite* ms = static_cast<MemorySite*>(s); MemorySite* ms = static_cast<MemorySite*>(s);
return ms->base == this->base return ms->base == this->base
and ((index == 1 and ms->offset == static_cast<int> and ((index == 1
(this->offset + vm::TargetBytesPerWord)) and ms->offset
or (index == 0 and this->offset == static_cast<int> == static_cast<int>(this->offset
(ms->offset + vm::TargetBytesPerWord))) + c->targetInfo.pointerSize))
and ms->index == this->index or (index == 0
and ms->scale == this->scale; and this->offset
== static_cast<int>(ms->offset
+ c->targetInfo.pointerSize)))
and ms->index == this->index and ms->scale == this->scale;
} else { } else {
return false; return false;
} }
@ -551,10 +551,11 @@ void MemorySite::asAssemblerOperand(Context* c UNUSED, Site* high UNUSED,
lir::Operand* result) lir::Operand* result)
{ {
// todo: endianness? // todo: endianness?
assert(c, high == this assert(c,
high == this
or (static_cast<MemorySite*>(high)->base == base or (static_cast<MemorySite*>(high)->base == base
and static_cast<MemorySite*>(high)->offset and static_cast<MemorySite*>(high)->offset
== static_cast<int>(offset + vm::TargetBytesPerWord) == static_cast<int>(offset + c->targetInfo.pointerSize)
and static_cast<MemorySite*>(high)->index == index and static_cast<MemorySite*>(high)->index == index
and static_cast<MemorySite*>(high)->scale == scale)); and static_cast<MemorySite*>(high)->scale == scale));
@ -569,7 +570,8 @@ Site* MemorySite::copy(Context* c) {
Site* MemorySite::copyHalf(Context* c, bool add) { Site* MemorySite::copyHalf(Context* c, bool add) {
if (add) { if (add) {
return memorySite(c, base, offset + vm::TargetBytesPerWord, index, scale); return memorySite(
c, base, offset + c->targetInfo.pointerSize, index, scale);
} else { } else {
return copy(c); return copy(c);
} }
@ -584,10 +586,13 @@ Site* MemorySite::copyHigh(Context* c) {
} }
Site* MemorySite::makeNextWord(Context* c, unsigned index) { Site* MemorySite::makeNextWord(Context* c, unsigned index) {
return memorySite return memorySite(c,
(c, base, offset + ((index == 1) xor c->arch->bigEndian() base,
? vm::TargetBytesPerWord : -vm::TargetBytesPerWord), offset + ((index == 1) xor c->arch->bigEndian()
this->index, scale); ? c->targetInfo.pointerSize
: -c->targetInfo.pointerSize),
this->index,
scale);
} }
SiteMask MemorySite::mask(Context* c) { SiteMask MemorySite::mask(Context* c) {

View File

@ -17,10 +17,19 @@ namespace avian {
namespace codegen { namespace codegen {
namespace compiler { namespace compiler {
Value::Value(Site* site, Site* target, lir::ValueType type): Value::Value(Site* site, Site* target, ir::Type type)
reads(0), lastRead(0), sites(site), source(0), target(target), buddy(this), : ir::Value(type),
nextWord(this), home(NoFrameIndex), type(type), wordIndex(0) reads(0),
{ } lastRead(0),
sites(site),
source(0),
target(target),
buddy(this),
nextWord(this),
home(NoFrameIndex),
wordIndex(0)
{
}
bool Value::findSite(Site* site) { bool Value::findSite(Site* site) {
for (Site* s = this->sites; s; s = s->next) { for (Site* s = this->sites; s; s = s->next) {
@ -106,7 +115,8 @@ bool Value::uniqueSite(Context* c, Site* s) {
if (it.hasMore()) { if (it.hasMore()) {
// the site is not this word's only site, but if the site is // the site is not this word's only site, but if the site is
// shared with the next word, it may be that word's only site // shared with the next word, it may be that word's only site
if (this->nextWord != this and s->registerSize(c) > vm::TargetBytesPerWord) { if (this->nextWord != this
and s->registerSize(c) > c->targetInfo.pointerSize) {
SiteIterator nit(c, this->nextWord); SiteIterator nit(c, this->nextWord);
Site* p = nit.next(); Site* p = nit.next();
if (nit.hasMore()) { if (nit.hasMore()) {
@ -154,8 +164,8 @@ bool Value::hasBuddy(Context* c, Value* b) {
} }
#endif // not NDEBUG #endif // not NDEBUG
Value* value(Context* c, ir::Type type, Site* site, Site* target)
Value* value(Context* c, lir::ValueType type, Site* site, Site* target) { {
return new(c->zone) Value(site, target, type); return new(c->zone) Value(site, target, type);
} }

View File

@ -26,7 +26,7 @@ const int NoFrameIndex = -1;
const bool DebugSites = false; const bool DebugSites = false;
class Value: public Compiler::Operand { class Value : public ir::Value {
public: public:
Read* reads; Read* reads;
Read* lastRead; Read* lastRead;
@ -36,10 +36,9 @@ class Value: public Compiler::Operand {
Value* buddy; Value* buddy;
Value* nextWord; Value* nextWord;
int16_t home; int16_t home;
lir::ValueType type;
uint8_t wordIndex; uint8_t wordIndex;
Value(Site* site, Site* target, lir::ValueType type); Value(Site* site, Site* target, ir::Type type);
bool findSite(Site* site); bool findSite(Site* site);
@ -67,15 +66,17 @@ class Value: public Compiler::Operand {
}; };
inline bool isGeneralValue(Compiler::Operand* a) { inline bool isFloatValue(ir::Value* a)
return static_cast<Value*>(a)->type == lir::ValueGeneral; {
return static_cast<Value*>(a)->type.flavor() == ir::Type::Float;
} }
inline bool isFloatValue(Compiler::Operand* a) { inline bool isGeneralValue(ir::Value* a)
return static_cast<Value*>(a)->type == lir::ValueFloat; {
return !isFloatValue(a);
} }
Value* value(Context* c, lir::ValueType type, Site* site = 0, Site* target = 0); Value* value(Context* c, ir::Type type, Site* site = 0, Site* target = 0);
} // namespace compiler } // namespace compiler
} // namespace codegen } // namespace codegen

View File

@ -180,6 +180,11 @@ class MyArchitecture: public Architecture {
return 3; return 3;
} }
virtual ir::TargetInfo targetInfo()
{
return ir::TargetInfo(TargetBytesPerWord);
}
virtual bool bigEndian() { virtual bool bigEndian() {
return false; return false;
} }

View File

@ -204,6 +204,11 @@ class MyArchitecture: public Architecture {
return rdx; return rdx;
} }
virtual ir::TargetInfo targetInfo()
{
return ir::TargetInfo(TargetBytesPerWord);
}
virtual bool bigEndian() { virtual bool bigEndian() {
return false; return false;
} }

File diff suppressed because it is too large Load Diff

612
src/debug-util.cpp Normal file
View File

@ -0,0 +1,612 @@
/* Copyright (c) 2008-2013, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#include <avian/machine.h>
#include "debug-util.h"
namespace avian {
namespace jvm {
namespace debug {
uint16_t read16(uint8_t* code, unsigned& ip)
{
uint16_t a = code[ip++];
uint16_t b = code[ip++];
return (a << 8) | b;
}
uint32_t read32(uint8_t* code, unsigned& ip)
{
uint32_t b = code[ip++];
uint32_t a = code[ip++];
uint32_t c = code[ip++];
uint32_t d = code[ip++];
return (a << 24) | (b << 16) | (c << 8) | d;
}
using namespace vm;
int printInstruction(uint8_t* code, unsigned& ip, const char* prefix)
{
unsigned startIp = ip;
uint8_t instr = code[ip++];
switch (instr) {
case aaload:
return fprintf(stderr, "aaload");
case aastore:
return fprintf(stderr, "aastore");
case aconst_null:
return fprintf(stderr, "aconst_null");
case aload:
return fprintf(stderr, "aload %2d", code[ip++]);
case aload_0:
return fprintf(stderr, "aload_0");
case aload_1:
return fprintf(stderr, "aload_1");
case aload_2:
return fprintf(stderr, "aload_2");
case aload_3:
return fprintf(stderr, "aload_3");
case anewarray:
return fprintf(stderr, "anewarray %4d", read16(code, ip));
case areturn:
return fprintf(stderr, "areturn");
case arraylength:
return fprintf(stderr, "arraylength");
case astore:
return fprintf(stderr, "astore %2d", code[ip++]);
case astore_0:
return fprintf(stderr, "astore_0");
case astore_1:
return fprintf(stderr, "astore_1");
case astore_2:
return fprintf(stderr, "astore_2");
case astore_3:
return fprintf(stderr, "astore_3");
case athrow:
return fprintf(stderr, "athrow");
case baload:
return fprintf(stderr, "baload");
case bastore:
return fprintf(stderr, "bastore");
case bipush:
return fprintf(stderr, "bipush %2d", code[ip++]);
case caload:
return fprintf(stderr, "caload");
case castore:
return fprintf(stderr, "castore");
case checkcast:
return fprintf(stderr, "checkcast %4d", read16(code, ip));
case d2f:
return fprintf(stderr, "d2f");
case d2i:
return fprintf(stderr, "d2i");
case d2l:
return fprintf(stderr, "d2l");
case dadd:
return fprintf(stderr, "dadd");
case daload:
return fprintf(stderr, "daload");
case dastore:
return fprintf(stderr, "dastore");
case dcmpg:
return fprintf(stderr, "dcmpg");
case dcmpl:
return fprintf(stderr, "dcmpl");
case dconst_0:
return fprintf(stderr, "dconst_0");
case dconst_1:
return fprintf(stderr, "dconst_1");
case ddiv:
return fprintf(stderr, "ddiv");
case dmul:
return fprintf(stderr, "dmul");
case dneg:
return fprintf(stderr, "dneg");
case vm::drem:
return fprintf(stderr, "drem");
case dsub:
return fprintf(stderr, "dsub");
case dup:
return fprintf(stderr, "dup");
case dup_x1:
return fprintf(stderr, "dup_x1");
case dup_x2:
return fprintf(stderr, "dup_x2");
case dup2:
return fprintf(stderr, "dup2");
case dup2_x1:
return fprintf(stderr, "dup2_x1");
case dup2_x2:
return fprintf(stderr, "dup2_x2");
case f2d:
return fprintf(stderr, "f2d");
case f2i:
return fprintf(stderr, "f2i");
case f2l:
return fprintf(stderr, "f2l");
case fadd:
return fprintf(stderr, "fadd");
case faload:
return fprintf(stderr, "faload");
case fastore:
return fprintf(stderr, "fastore");
case fcmpg:
return fprintf(stderr, "fcmpg");
case fcmpl:
return fprintf(stderr, "fcmpl");
case fconst_0:
return fprintf(stderr, "fconst_0");
case fconst_1:
return fprintf(stderr, "fconst_1");
case fconst_2:
return fprintf(stderr, "fconst_2");
case fdiv:
return fprintf(stderr, "fdiv");
case fmul:
return fprintf(stderr, "fmul");
case fneg:
return fprintf(stderr, "fneg");
case frem:
return fprintf(stderr, "frem");
case fsub:
return fprintf(stderr, "fsub");
case getfield:
return fprintf(stderr, "getfield %4d", read16(code, ip));
case getstatic:
return fprintf(stderr, "getstatic %4d", read16(code, ip));
case goto_: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "goto %4d", offset + ip - 3);
}
case goto_w: {
int32_t offset = read32(code, ip);
return fprintf(stderr, "goto_w %08x", offset + ip - 5);
}
case i2b:
return fprintf(stderr, "i2b");
case i2c:
return fprintf(stderr, "i2c");
case i2d:
return fprintf(stderr, "i2d");
case i2f:
return fprintf(stderr, "i2f");
case i2l:
return fprintf(stderr, "i2l");
case i2s:
return fprintf(stderr, "i2s");
case iadd:
return fprintf(stderr, "iadd");
case iaload:
return fprintf(stderr, "iaload");
case iand:
return fprintf(stderr, "iand");
case iastore:
return fprintf(stderr, "iastore");
case iconst_m1:
return fprintf(stderr, "iconst_m1");
case iconst_0:
return fprintf(stderr, "iconst_0");
case iconst_1:
return fprintf(stderr, "iconst_1");
case iconst_2:
return fprintf(stderr, "iconst_2");
case iconst_3:
return fprintf(stderr, "iconst_3");
case iconst_4:
return fprintf(stderr, "iconst_4");
case iconst_5:
return fprintf(stderr, "iconst_5");
case idiv:
return fprintf(stderr, "idiv");
case if_acmpeq: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "if_acmpeq %4d", offset + ip - 3);
}
case if_acmpne: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "if_acmpne %4d", offset + ip - 3);
}
case if_icmpeq: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "if_icmpeq %4d", offset + ip - 3);
}
case if_icmpne: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "if_icmpne %4d", offset + ip - 3);
}
case if_icmpgt: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "if_icmpgt %4d", offset + ip - 3);
}
case if_icmpge: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "if_icmpge %4d", offset + ip - 3);
}
case if_icmplt: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "if_icmplt %4d", offset + ip - 3);
}
case if_icmple: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "if_icmple %4d", offset + ip - 3);
}
case ifeq: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "ifeq %4d", offset + ip - 3);
}
case ifne: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "ifne %4d", offset + ip - 3);
}
case ifgt: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "ifgt %4d", offset + ip - 3);
}
case ifge: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "ifge %4d", offset + ip - 3);
}
case iflt: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "iflt %4d", offset + ip - 3);
}
case ifle: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "ifle %4d", offset + ip - 3);
}
case ifnonnull: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "ifnonnull %4d", offset + ip - 3);
}
case ifnull: {
int16_t offset = read16(code, ip);
return fprintf(stderr, "ifnull %4d", offset + ip - 3);
}
case iinc: {
uint8_t a = code[ip++];
uint8_t b = code[ip++];
return fprintf(stderr, "iinc %2d %2d", a, b);
}
case iload:
return fprintf(stderr, "iload %2d", code[ip++]);
case fload:
return fprintf(stderr, "fload %2d", code[ip++]);
case iload_0:
return fprintf(stderr, "iload_0");
case fload_0:
return fprintf(stderr, "fload_0");
case iload_1:
return fprintf(stderr, "iload_1");
case fload_1:
return fprintf(stderr, "fload_1");
case iload_2:
return fprintf(stderr, "iload_2");
case fload_2:
return fprintf(stderr, "fload_2");
case iload_3:
return fprintf(stderr, "iload_3");
case fload_3:
return fprintf(stderr, "fload_3");
case imul:
return fprintf(stderr, "imul");
case ineg:
return fprintf(stderr, "ineg");
case instanceof:
return fprintf(stderr, "instanceof %4d", read16(code, ip));
case invokeinterface:
return fprintf(stderr, "invokeinterface %4d", read16(code, ip));
case invokespecial:
return fprintf(stderr, "invokespecial %4d", read16(code, ip));
case invokestatic:
return fprintf(stderr, "invokestatic %4d", read16(code, ip));
case invokevirtual:
return fprintf(stderr, "invokevirtual %4d", read16(code, ip));
case ior:
return fprintf(stderr, "ior");
case irem:
return fprintf(stderr, "irem");
case ireturn:
return fprintf(stderr, "ireturn");
case freturn:
return fprintf(stderr, "freturn");
case ishl:
return fprintf(stderr, "ishl");
case ishr:
return fprintf(stderr, "ishr");
case istore:
return fprintf(stderr, "istore %2d", code[ip++]);
case fstore:
return fprintf(stderr, "fstore %2d", code[ip++]);
case istore_0:
return fprintf(stderr, "istore_0");
case fstore_0:
return fprintf(stderr, "fstore_0");
case istore_1:
return fprintf(stderr, "istore_1");
case fstore_1:
return fprintf(stderr, "fstore_1");
case istore_2:
return fprintf(stderr, "istore_2");
case fstore_2:
return fprintf(stderr, "fstore_2");
case istore_3:
return fprintf(stderr, "istore_3");
case fstore_3:
return fprintf(stderr, "fstore_3");
case isub:
return fprintf(stderr, "isub");
case iushr:
return fprintf(stderr, "iushr");
case ixor:
return fprintf(stderr, "ixor");
case jsr:
return fprintf(stderr, "jsr %4d", read16(code, ip) + startIp);
case jsr_w:
return fprintf(stderr, "jsr_w %08x", read32(code, ip) + startIp);
case l2d:
return fprintf(stderr, "l2d");
case l2f:
return fprintf(stderr, "l2f");
case l2i:
return fprintf(stderr, "l2i");
case ladd:
return fprintf(stderr, "ladd");
case laload:
return fprintf(stderr, "laload");
case land:
return fprintf(stderr, "land");
case lastore:
return fprintf(stderr, "lastore");
case lcmp:
return fprintf(stderr, "lcmp");
case lconst_0:
return fprintf(stderr, "lconst_0");
case lconst_1:
return fprintf(stderr, "lconst_1");
case ldc:
return fprintf(stderr, "ldc %4d", read16(code, ip));
case ldc_w:
return fprintf(stderr, "ldc_w %08x", read32(code, ip));
case ldc2_w:
return fprintf(stderr, "ldc2_w %4d", read16(code, ip));
case ldiv_:
return fprintf(stderr, "ldiv_");
case lload:
return fprintf(stderr, "lload %2d", code[ip++]);
case dload:
return fprintf(stderr, "dload %2d", code[ip++]);
case lload_0:
return fprintf(stderr, "lload_0");
case dload_0:
return fprintf(stderr, "dload_0");
case lload_1:
return fprintf(stderr, "lload_1");
case dload_1:
return fprintf(stderr, "dload_1");
case lload_2:
return fprintf(stderr, "lload_2");
case dload_2:
return fprintf(stderr, "dload_2");
case lload_3:
return fprintf(stderr, "lload_3");
case dload_3:
return fprintf(stderr, "dload_3");
case lmul:
return fprintf(stderr, "lmul");
case lneg:
return fprintf(stderr, "lneg");
case lookupswitch: {
while (ip & 0x3) {
ip++;
}
int32_t default_ = read32(code, ip) + startIp;
int32_t pairCount = read32(code, ip);
fprintf(
stderr, "lookupswitch default: %d pairCount: %d", default_, pairCount);
for (int i = 0; i < pairCount; i++) {
int32_t k = read32(code, ip);
int32_t d = read32(code, ip) + startIp;
fprintf(stderr, "\n%s key: %2d dest: %d", prefix, k, d);
}
fprintf(stderr, "\n");
fflush(stderr);
return 0;
}
case lor:
return fprintf(stderr, "lor");
case lrem:
return fprintf(stderr, "lrem");
case lreturn:
return fprintf(stderr, "lreturn");
case dreturn:
return fprintf(stderr, "dreturn");
case lshl:
return fprintf(stderr, "lshl");
case lshr:
return fprintf(stderr, "lshr");
case lstore:
return fprintf(stderr, "lstore %2d", code[ip++]);
case dstore:
return fprintf(stderr, "dstore %2d", code[ip++]);
case lstore_0:
return fprintf(stderr, "lstore_0");
case dstore_0:
return fprintf(stderr, "dstore_0");
case lstore_1:
return fprintf(stderr, "lstore_1");
case dstore_1:
return fprintf(stderr, "dstore_1");
case lstore_2:
return fprintf(stderr, "lstore_2");
case dstore_2:
return fprintf(stderr, "dstore_2");
case lstore_3:
return fprintf(stderr, "lstore_3");
case dstore_3:
return fprintf(stderr, "dstore_3");
case lsub:
return fprintf(stderr, "lsub");
case lushr:
return fprintf(stderr, "lushr");
case lxor:
return fprintf(stderr, "lxor");
case monitorenter:
return fprintf(stderr, "monitorenter");
case monitorexit:
return fprintf(stderr, "monitorexit");
case multianewarray: {
unsigned type = read16(code, ip);
return fprintf(stderr, "multianewarray %4d %2d", type, code[ip++]);
}
case new_:
return fprintf(stderr, "new %4d", read16(code, ip));
case newarray:
return fprintf(stderr, "newarray %2d", code[ip++]);
case nop:
return fprintf(stderr, "nop");
case pop_:
return fprintf(stderr, "pop");
case pop2:
return fprintf(stderr, "pop2");
case putfield:
return fprintf(stderr, "putfield %4d", read16(code, ip));
case putstatic:
return fprintf(stderr, "putstatic %4d", read16(code, ip));
case ret:
return fprintf(stderr, "ret %2d", code[ip++]);
case return_:
return fprintf(stderr, "return_");
case saload:
return fprintf(stderr, "saload");
case sastore:
return fprintf(stderr, "sastore");
case sipush:
return fprintf(stderr, "sipush %4d", read16(code, ip));
case swap:
return fprintf(stderr, "swap");
case tableswitch: {
while (ip & 0x3) {
ip++;
}
int32_t default_ = read32(code, ip) + startIp;
int32_t bottom = read32(code, ip);
int32_t top = read32(code, ip);
fprintf(stderr,
"tableswitch default: %d bottom: %d top: %d",
default_,
bottom,
top);
for (int i = 0; i < top - bottom + 1; i++) {
int32_t d = read32(code, ip) + startIp;
fprintf(stderr, "%s key: %d dest: %d", prefix, i + bottom, d);
}
return 0;
}
case wide: {
switch (code[ip++]) {
case aload:
return fprintf(stderr, "wide aload %4d", read16(code, ip));
case astore:
return fprintf(stderr, "wide astore %4d", read16(code, ip));
case iinc:
fprintf(stderr, "wide iinc %4d %4d", read16(code, ip), read16(code, ip));
case iload:
return fprintf(stderr, "wide iload %4d", read16(code, ip));
case istore:
return fprintf(stderr, "wide istore %4d", read16(code, ip));
case lload:
return fprintf(stderr, "wide lload %4d", read16(code, ip));
case lstore:
return fprintf(stderr, "wide lstore %4d", read16(code, ip));
case ret:
return fprintf(stderr, "wide ret %4d", read16(code, ip));
default: {
fprintf(
stderr, "unknown wide instruction %2d %4d", instr, read16(code, ip));
}
}
}
default: {
return fprintf(stderr, "unknown instruction %2d", instr);
}
}
return ip;
}
void disassembleCode(const char* prefix, uint8_t* code, unsigned length)
{
unsigned ip = 0;
while (ip < length) {
fprintf(stderr, "%s%x:\t", prefix, ip);
printInstruction(code, ip, prefix);
fprintf(stderr, "\n");
}
}
} // namespace debug
} // namespace jvm
} // namespace avian

24
src/debug-util.h Normal file
View File

@ -0,0 +1,24 @@
/* Copyright (c) 2008-2013, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#include <stdint.h>
namespace avian {
namespace jvm {
namespace debug {
// print out a single instruction (no newline)
// returns number of characters printed
int printInstruction(uint8_t* code, unsigned& ip, const char* prefix = "");
void disassembleCode(const char* prefix, uint8_t* code, unsigned length);
} // namespace debug
} // namespace jvm
} // namespace avian

View File

@ -253,6 +253,16 @@ public class Subroutine {
return true; return true;
} }
private static int test6(boolean predicate) {
try {
if (predicate) {
return -2;
}
} finally {
return new Throwable().getStackTrace()[0].getLineNumber();
}
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
test(false, false); test(false, false);
test(false, true); test(false, true);
@ -311,6 +321,15 @@ public class Subroutine {
(null, new Object[0]); (null, new Object[0]);
stackMap(new Object()); stackMap(new Object());
{
int f = test6(false);
int t = test6(true);
System.out.println("line: " + f);
expect(f > 0);
expect(f == t);
}
} }
private static class DummyException extends RuntimeException { } private static class DummyException extends RuntimeException { }

View File

@ -24,6 +24,7 @@ run make ${flags} process=interpret ${test_target}
# bootimage and openjdk builds without openjdk-src don't work: # bootimage and openjdk builds without openjdk-src don't work:
if [ -z "${openjdk}" ]; then if [ -z "${openjdk}" ]; then
run make ${flags} bootimage=true ${test_target} run make ${flags} bootimage=true ${test_target}
run make ${flags} mode=debug bootimage=true ${test_target}
# might as well do an openjdk test while we're here: # might as well do an openjdk test while we're here:
run make openjdk=$JAVA_HOME ${flags} ${test_target} run make openjdk=$JAVA_HOME ${flags} ${test_target}
fi fi