mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
Merge pull request #263 from joshuawarner32/compiler-types
Introduce stronger typing in compiler
This commit is contained in:
commit
86648ea054
@ -11,6 +11,8 @@
|
||||
#ifndef AVIAN_CODEGEN_ARCHITECTURE_H
|
||||
#define AVIAN_CODEGEN_ARCHITECTURE_H
|
||||
|
||||
#include "ir.h"
|
||||
|
||||
namespace vm {
|
||||
class Zone;
|
||||
}
|
||||
@ -57,6 +59,8 @@ virtual int returnHigh() = 0;
|
||||
virtual int virtualCallTarget() = 0;
|
||||
virtual int virtualCallIndex() = 0;
|
||||
|
||||
virtual ir::TargetInfo targetInfo() = 0;
|
||||
|
||||
virtual bool bigEndian() = 0;
|
||||
|
||||
virtual uintptr_t maximumImmediateJump() = 0;
|
||||
|
@ -12,8 +12,10 @@
|
||||
#define AVIAN_CODEGEN_COMPILER_H
|
||||
|
||||
#include <avian/system/system.h>
|
||||
#include <avian/util/slice.h>
|
||||
#include "avian/zone.h"
|
||||
#include "assembler.h"
|
||||
#include "ir.h"
|
||||
|
||||
namespace avian {
|
||||
namespace codegen {
|
||||
@ -33,35 +35,22 @@ class Compiler {
|
||||
virtual intptr_t getThunk(lir::TernaryOperation op, unsigned size,
|
||||
unsigned resultSize, bool* threadParameter) = 0;
|
||||
};
|
||||
|
||||
|
||||
static const unsigned Aligned = 1 << 0;
|
||||
static const unsigned NoReturn = 1 << 1;
|
||||
static const unsigned TailJump = 1 << 2;
|
||||
static const unsigned LongJumpOrCall = 1 << 3;
|
||||
|
||||
enum OperandType {
|
||||
ObjectType,
|
||||
AddressType,
|
||||
IntegerType,
|
||||
FloatType,
|
||||
VoidType
|
||||
};
|
||||
|
||||
class Operand { };
|
||||
class State { };
|
||||
class Subroutine { };
|
||||
|
||||
virtual State* saveState() = 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,
|
||||
unsigned localFootprint, unsigned alignedFrameSize) = 0;
|
||||
|
||||
virtual void extendLogicalCode(unsigned more) = 0;
|
||||
|
||||
virtual void visitLogicalIp(unsigned logicalIp) = 0;
|
||||
virtual void startLogicalIp(unsigned logicalIp) = 0;
|
||||
|
||||
@ -70,73 +59,82 @@ class Compiler {
|
||||
virtual Promise* poolAppend(intptr_t value) = 0;
|
||||
virtual Promise* poolAppendPromise(Promise* value) = 0;
|
||||
|
||||
virtual Operand* constant(int64_t value, OperandType type) = 0;
|
||||
virtual Operand* promiseConstant(Promise* value, OperandType type) = 0;
|
||||
virtual Operand* address(Promise* address) = 0;
|
||||
virtual Operand* memory(Operand* base,
|
||||
OperandType type,
|
||||
int displacement = 0,
|
||||
Operand* index = 0,
|
||||
unsigned scale = 1) = 0;
|
||||
virtual ir::Value* constant(int64_t value, ir::Type type) = 0;
|
||||
virtual ir::Value* promiseConstant(Promise* value, ir::Type type) = 0;
|
||||
virtual ir::Value* address(ir::Type type, Promise* address) = 0;
|
||||
virtual ir::Value* memory(ir::Value* base,
|
||||
ir::Type type,
|
||||
int displacement = 0,
|
||||
ir::Value* index = 0) = 0;
|
||||
|
||||
virtual Operand* register_(int number) = 0;
|
||||
virtual ir::Value* threadRegister() = 0;
|
||||
|
||||
virtual void push(unsigned footprint) = 0;
|
||||
virtual void push(unsigned footprint, Operand* value) = 0;
|
||||
virtual void save(unsigned footprint, Operand* value) = 0;
|
||||
virtual Operand* pop(unsigned footprint) = 0;
|
||||
virtual void pushed() = 0;
|
||||
virtual void push(ir::Type type, ir::Value* value) = 0;
|
||||
virtual void save(ir::Type type, ir::Value* value) = 0;
|
||||
virtual ir::Value* pop(ir::Type type) = 0;
|
||||
virtual void pushed(ir::Type type) = 0;
|
||||
virtual void popped(unsigned footprint) = 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,
|
||||
unsigned flags,
|
||||
TraceHandler* traceHandler,
|
||||
unsigned resultSize,
|
||||
OperandType resultType,
|
||||
unsigned argumentCount,
|
||||
...) = 0;
|
||||
virtual ir::Value* call(ir::Value* address,
|
||||
unsigned flags,
|
||||
TraceHandler* traceHandler,
|
||||
ir::Type resultType,
|
||||
unsigned argumentCount,
|
||||
...) = 0;
|
||||
|
||||
virtual Operand* stackCall(Operand* address,
|
||||
unsigned flags,
|
||||
TraceHandler* traceHandler,
|
||||
unsigned resultSize,
|
||||
OperandType resultType,
|
||||
unsigned argumentFootprint) = 0;
|
||||
virtual ir::Value* stackCall(ir::Value* address,
|
||||
unsigned flags,
|
||||
TraceHandler* traceHandler,
|
||||
ir::Type resultType,
|
||||
util::Slice<ir::Value*> arguments) = 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 storeLocal(unsigned footprint, Operand* src,
|
||||
unsigned index) = 0;
|
||||
virtual Operand* loadLocal(unsigned footprint, unsigned index) = 0;
|
||||
virtual void storeLocal(ir::Value* src, unsigned index) = 0;
|
||||
virtual ir::Value* loadLocal(ir::Type type, unsigned index) = 0;
|
||||
virtual void saveLocals() = 0;
|
||||
|
||||
virtual void checkBounds(Operand* object, unsigned lengthOffset,
|
||||
Operand* index, intptr_t handler) = 0;
|
||||
virtual void checkBounds(ir::Value* object,
|
||||
unsigned lengthOffset,
|
||||
ir::Value* index,
|
||||
intptr_t handler) = 0;
|
||||
|
||||
virtual void store(unsigned srcSize, Operand* src, unsigned dstSize,
|
||||
Operand* dst) = 0;
|
||||
virtual Operand* load(unsigned srcSize, unsigned srcSelectSize, Operand* src,
|
||||
unsigned dstSize) = 0;
|
||||
virtual Operand* loadz(unsigned size, unsigned srcSelectSize, Operand* src,
|
||||
unsigned dstSize) = 0;
|
||||
virtual ir::Value* truncateThenExtend(ir::SignExtendMode signExtend,
|
||||
ir::Type extendType,
|
||||
ir::Type truncateType,
|
||||
ir::Value* src) = 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 exit(Operand* address) = 0;
|
||||
virtual void condJump(lir::TernaryOperation op,
|
||||
ir::Value* a,
|
||||
ir::Value* b,
|
||||
ir::Value* address) = 0;
|
||||
|
||||
virtual Operand* binaryOp(lir::TernaryOperation type, unsigned size, Operand* a, Operand* b) = 0;
|
||||
virtual Operand* unaryOp(lir::BinaryOperation type, unsigned size, Operand* a) = 0;
|
||||
virtual void nullaryOp(lir::Operation type) = 0;
|
||||
virtual void jmp(ir::Value* address) = 0;
|
||||
virtual void exit(ir::Value* address) = 0;
|
||||
|
||||
virtual Operand* f2f(unsigned aSize, unsigned resSize, Operand* a) = 0;
|
||||
virtual Operand* f2i(unsigned aSize, unsigned resSize, Operand* a) = 0;
|
||||
virtual Operand* i2f(unsigned aSize, unsigned resSize, Operand* a) = 0;
|
||||
virtual ir::Value* binaryOp(lir::TernaryOperation op,
|
||||
ir::Type type,
|
||||
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,
|
||||
unsigned stackLimitOffset) = 0;
|
||||
|
157
include/avian/codegen/ir.h
Normal file
157
include/avian/codegen/ir.h
Normal 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
|
32
include/avian/util/assert.h
Normal file
32
include/avian/util/assert.h
Normal 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
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "allocator.h"
|
||||
#include "math.h"
|
||||
#include "assert.h"
|
||||
|
||||
namespace avian {
|
||||
namespace util {
|
||||
@ -33,6 +34,7 @@ class Slice {
|
||||
|
||||
inline T& operator[](size_t index)
|
||||
{
|
||||
ASSERT(index < count);
|
||||
return items[index];
|
||||
}
|
||||
|
||||
@ -51,20 +53,36 @@ class Slice {
|
||||
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);
|
||||
memcpy(ret.items, items, count * sizeof(T));
|
||||
return ret;
|
||||
Slice<T> slice(alloc(a, count));
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
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)
|
||||
{
|
||||
T* newItems = (T*)a->allocate(newCount * sizeof(T));
|
||||
memcpy(newItems, items, min(count, newCount));
|
||||
Slice<T> slice(clone(a, newCount));
|
||||
a->free(items, count);
|
||||
items = newItems;
|
||||
count = newCount;
|
||||
*this = slice;
|
||||
}
|
||||
};
|
||||
|
||||
|
1
makefile
1
makefile
@ -1125,6 +1125,7 @@ embed-objects = $(call cpp-objects,$(embed-sources),$(src),$(build-embed))
|
||||
compiler-sources = \
|
||||
$(src)/codegen/compiler.cpp \
|
||||
$(wildcard $(src)/codegen/compiler/*.cpp) \
|
||||
$(src)/debug-util.cpp \
|
||||
$(src)/codegen/registers.cpp \
|
||||
$(src)/codegen/runtime.cpp \
|
||||
$(src)/codegen/targets.cpp \
|
||||
|
@ -156,7 +156,7 @@ popRead(Context* c, Event* e UNUSED, Value* v)
|
||||
if (valid(nextWord->reads)) {
|
||||
deadWord(c, v);
|
||||
} 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
|
||||
move(Context* c, Value* value, Site* src, Site* dst);
|
||||
|
||||
@ -751,10 +735,14 @@ saveLocals(Context* c, Event* e)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
maybeMove(Context* c, lir::BinaryOperation type, unsigned srcSize,
|
||||
unsigned srcSelectSize, Value* srcValue, unsigned dstSize, Value* dstValue,
|
||||
const SiteMask& dstMask)
|
||||
void maybeMove(Context* c,
|
||||
lir::BinaryOperation op,
|
||||
unsigned srcSize,
|
||||
unsigned srcSelectSize,
|
||||
Value* srcValue,
|
||||
unsigned dstSize,
|
||||
Value* dstValue,
|
||||
const SiteMask& dstMask)
|
||||
{
|
||||
Read* read = live(c, dstValue);
|
||||
bool isStore = read == 0;
|
||||
@ -806,8 +794,14 @@ maybeMove(Context* c, lir::BinaryOperation type, unsigned srcSize,
|
||||
|
||||
srcValue->source->freeze(c, srcValue);
|
||||
|
||||
apply(c, type, min(srcSelectSize, dstSize), srcValue->source, srcValue->source,
|
||||
dstSize, target, target);
|
||||
apply(c,
|
||||
op,
|
||||
min(srcSelectSize, dstSize),
|
||||
srcValue->source,
|
||||
srcValue->source,
|
||||
dstSize,
|
||||
target,
|
||||
target);
|
||||
|
||||
srcValue->source->thaw(c, srcValue);
|
||||
} else {
|
||||
@ -819,9 +813,9 @@ maybeMove(Context* c, lir::BinaryOperation type, unsigned srcSize,
|
||||
bool thunk;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -844,8 +838,14 @@ maybeMove(Context* c, lir::BinaryOperation type, unsigned srcSize,
|
||||
srcb, dstb, srcValue, dstValue);
|
||||
}
|
||||
|
||||
apply(c, type, srcSelectSize, srcValue->source, srcValue->source,
|
||||
dstSize, tmpTarget, tmpTarget);
|
||||
apply(c,
|
||||
op,
|
||||
srcSelectSize,
|
||||
srcValue->source,
|
||||
srcValue->source,
|
||||
dstSize,
|
||||
tmpTarget,
|
||||
tmpTarget);
|
||||
|
||||
tmpTarget->thaw(c, dstValue);
|
||||
|
||||
@ -1214,9 +1214,27 @@ storeLocal(Context* c, unsigned footprint, Value* v, unsigned index, bool copy)
|
||||
return v;
|
||||
}
|
||||
|
||||
Value*
|
||||
loadLocal(Context* c, unsigned footprint, unsigned index)
|
||||
unsigned typeFootprint(Context* c, ir::Type type)
|
||||
{
|
||||
// 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);
|
||||
|
||||
if (footprint > 1) {
|
||||
@ -1237,17 +1255,10 @@ loadLocal(Context* c, unsigned footprint, unsigned index)
|
||||
return c->locals[index].value;
|
||||
}
|
||||
|
||||
Value*
|
||||
register_(Context* c, int number)
|
||||
Value* threadRegister(Context* c)
|
||||
{
|
||||
assert(c, (1 << number) & (c->regFile->generalRegisters.mask
|
||||
| c->regFile->floatRegisters.mask));
|
||||
|
||||
Site* s = registerSite(c, number);
|
||||
lir::ValueType type = ((1 << number) & c->regFile->floatRegisters.mask)
|
||||
? lir::ValueFloat: lir::ValueGeneral;
|
||||
|
||||
return value(c, type, s, s);
|
||||
Site* s = registerSite(c, c->arch->thread());
|
||||
return value(c, ir::Type::addr(), s, s);
|
||||
}
|
||||
|
||||
unsigned
|
||||
@ -1506,8 +1517,8 @@ resolveOriginalSites(Context* c, Event* e, SiteRecordList* frozen,
|
||||
fprintf(stderr, "freeze original %s for %p local %d frame %d\n",
|
||||
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.removeSite(c, s);
|
||||
freeze(c, frozen, s, 0);
|
||||
@ -2129,26 +2140,9 @@ class MyCompiler: public Compiler {
|
||||
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,
|
||||
unsigned localFootprint, unsigned alignedFrameSize)
|
||||
{
|
||||
c.logicalCodeLength = logicalCodeLength;
|
||||
c.parameterFootprint = parameterFootprint;
|
||||
c.localFootprint = localFootprint;
|
||||
c.alignedFrameSize = alignedFrameSize;
|
||||
@ -2167,23 +2161,23 @@ class MyCompiler: public Compiler {
|
||||
c.frameResources[base + c.arch->framePointerOffset()].reserved
|
||||
= UseFramePointer;
|
||||
|
||||
// leave room for logical instruction -1
|
||||
unsigned codeSize = sizeof(LogicalInstruction*) * (logicalCodeLength + 1);
|
||||
c.logicalCode = static_cast<LogicalInstruction**>
|
||||
(c.zone->allocate(codeSize));
|
||||
memset(c.logicalCode, 0, codeSize);
|
||||
c.logicalCode++;
|
||||
c.logicalCode.init(c.zone, logicalCodeLength);
|
||||
|
||||
c.logicalCode[-1] = new (c.zone) LogicalInstruction(-1, c.stack, c.locals);
|
||||
|
||||
c.locals = static_cast<Local*>
|
||||
(c.zone->allocate(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) {
|
||||
assert(&c, logicalIp < c.logicalCodeLength);
|
||||
assert(&c, logicalIp < c.logicalCode.count());
|
||||
|
||||
if (c.logicalCode[c.logicalIp]->lastEvent == 0) {
|
||||
appendDummy(&c);
|
||||
@ -2215,17 +2209,11 @@ class MyCompiler: public Compiler {
|
||||
populateJunctionReads(&c, link);
|
||||
}
|
||||
|
||||
if (c.subroutine) {
|
||||
c.subroutine->forkState
|
||||
= c.logicalCode[logicalIp]->subroutine->forkState;
|
||||
c.subroutine = 0;
|
||||
}
|
||||
|
||||
c.forkState = 0;
|
||||
}
|
||||
|
||||
virtual void startLogicalIp(unsigned logicalIp) {
|
||||
assert(&c, logicalIp < c.logicalCodeLength);
|
||||
assert(&c, logicalIp < c.logicalCode.count());
|
||||
assert(&c, c.logicalCode[logicalIp] == 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);
|
||||
|
||||
bool startSubroutine = c.subroutine != 0;
|
||||
if (startSubroutine) {
|
||||
c.logicalCode[logicalIp]->subroutine = c.subroutine;
|
||||
c.subroutine = 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -2290,71 +2255,82 @@ class MyCompiler: public Compiler {
|
||||
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);
|
||||
}
|
||||
|
||||
virtual Operand* promiseConstant(Promise* value, Compiler::OperandType 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)
|
||||
virtual ir::Value* promiseConstant(Promise* value, ir::Type type)
|
||||
{
|
||||
Value* result = value(&c, valueType(&c, type));
|
||||
return compiler::value(&c, type, compiler::constantSite(&c, value));
|
||||
}
|
||||
|
||||
appendMemory(&c, static_cast<Value*>(base), displacement,
|
||||
static_cast<Value*>(index), scale, result);
|
||||
virtual ir::Value* address(ir::Type type, Promise* address)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
virtual Operand* register_(int number) {
|
||||
return compiler::register_(&c, number);
|
||||
virtual ir::Value* threadRegister()
|
||||
{
|
||||
return compiler::threadRegister(&c);
|
||||
}
|
||||
|
||||
Promise* machineIp() {
|
||||
return c.logicalCode[c.logicalIp]->lastEvent->makeCodePromise(&c);
|
||||
}
|
||||
|
||||
virtual void push(unsigned footprint UNUSED) {
|
||||
assert(&c, footprint == 1);
|
||||
|
||||
Value* v = value(&c, lir::ValueGeneral);
|
||||
Stack* s = compiler::stack(&c, v, c.stack);
|
||||
|
||||
v->home = frameIndex(&c, s->index + c.localFootprint);
|
||||
c.stack = s;
|
||||
virtual void push(ir::Type type, ir::Value* value)
|
||||
{
|
||||
// TODO: once type information is flowed properly, enable this assert.
|
||||
// Some time later, we can remove the parameter.
|
||||
// assert(&c, value->type == type);
|
||||
compiler::push(&c, typeFootprint(&c, type), static_cast<Value*>(value));
|
||||
}
|
||||
|
||||
virtual void push(unsigned footprint, Operand* value) {
|
||||
compiler::push(&c, footprint, static_cast<Value*>(value));
|
||||
}
|
||||
|
||||
virtual void save(unsigned footprint, Operand* value) {
|
||||
virtual void save(ir::Type type, ir::Value* value)
|
||||
{
|
||||
// TODO: once type information is flowed properly, enable this assert.
|
||||
// Some time later, we can remove the parameter.
|
||||
// assert(&c, value->type == type);
|
||||
unsigned footprint = typeFootprint(&c, type);
|
||||
c.saved = cons(&c, static_cast<Value*>(value), c.saved);
|
||||
if (TargetBytesPerWord == 4 and footprint > 1) {
|
||||
assert(&c, footprint == 2);
|
||||
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) {
|
||||
return compiler::pop(&c, footprint);
|
||||
virtual ir::Value* pop(ir::Type type)
|
||||
{
|
||||
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() {
|
||||
Value* v = value(&c, lir::ValueGeneral);
|
||||
virtual void pushed(ir::Type type)
|
||||
{
|
||||
Value* v = value(&c, type);
|
||||
appendFrameSite
|
||||
(&c, v, frameIndex
|
||||
(&c, (c.stack ? c.stack->index : 0) + c.localFootprint));
|
||||
@ -2380,7 +2356,8 @@ class MyCompiler: public Compiler {
|
||||
return c.stack->index;
|
||||
}
|
||||
|
||||
virtual Operand* peek(unsigned footprint, unsigned index) {
|
||||
virtual ir::Value* peek(unsigned footprint, unsigned index)
|
||||
{
|
||||
Stack* s = c.stack;
|
||||
for (unsigned i = index; i > 0; --i) {
|
||||
s = s->next;
|
||||
@ -2416,13 +2393,12 @@ class MyCompiler: public Compiler {
|
||||
return s->value;
|
||||
}
|
||||
|
||||
virtual Operand* call(Operand* address,
|
||||
unsigned flags,
|
||||
TraceHandler* traceHandler,
|
||||
unsigned resultSize,
|
||||
OperandType resultType,
|
||||
unsigned argumentCount,
|
||||
...)
|
||||
virtual ir::Value* call(ir::Value* address,
|
||||
unsigned flags,
|
||||
TraceHandler* traceHandler,
|
||||
ir::Type resultType,
|
||||
unsigned argumentCount,
|
||||
...)
|
||||
{
|
||||
va_list a; va_start(a, argumentCount);
|
||||
|
||||
@ -2430,7 +2406,7 @@ class MyCompiler: public Compiler {
|
||||
|
||||
unsigned footprint = 0;
|
||||
unsigned size = TargetBytesPerWord;
|
||||
RUNTIME_ARRAY(Value*, arguments, argumentCount);
|
||||
RUNTIME_ARRAY(ir::Value*, arguments, argumentCount);
|
||||
int index = 0;
|
||||
for (unsigned i = 0; i < argumentCount; ++i) {
|
||||
Value* o = va_arg(a, Value*);
|
||||
@ -2452,41 +2428,74 @@ class MyCompiler: public Compiler {
|
||||
|
||||
va_end(a);
|
||||
|
||||
Stack* argumentStack = c.stack;
|
||||
for (int i = index - 1; i >= 0; --i) {
|
||||
argumentStack = compiler::stack
|
||||
(&c, RUNTIME_ARRAY_BODY(arguments)[i], argumentStack);
|
||||
Value* result = value(&c, resultType);
|
||||
appendCall(&c,
|
||||
static_cast<Value*>(address),
|
||||
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));
|
||||
appendCall(&c, static_cast<Value*>(address), flags, traceHandler, result,
|
||||
resultSize, argumentStack, index, 0);
|
||||
appendFrameSite(&c, v, frameIndex(&c, index));
|
||||
|
||||
return result;
|
||||
Local* local = c.locals + index;
|
||||
local->value = v;
|
||||
v->home = frameIndex(&c, index);
|
||||
}
|
||||
|
||||
virtual Operand* stackCall(Operand* address,
|
||||
unsigned flags,
|
||||
TraceHandler* traceHandler,
|
||||
unsigned resultSize,
|
||||
OperandType resultType,
|
||||
unsigned argumentFootprint)
|
||||
virtual void initLocal(unsigned index, ir::Type type)
|
||||
{
|
||||
Value* result = value(&c, valueType(&c, resultType));
|
||||
appendCall(&c, static_cast<Value*>(address), flags, traceHandler, result,
|
||||
resultSize, c.stack, 0, argumentFootprint);
|
||||
return result;
|
||||
}
|
||||
unsigned footprint = typeFootprint(&c, type);
|
||||
|
||||
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);
|
||||
|
||||
Value* v = value(&c, valueType(&c, type));
|
||||
Value* v = value(&c, type);
|
||||
|
||||
if (footprint > 1) {
|
||||
assert(&c, footprint == 2);
|
||||
@ -2498,11 +2507,11 @@ class MyCompiler: public Compiler {
|
||||
lowIndex = index;
|
||||
} else {
|
||||
lowIndex = index + 1;
|
||||
highIndex = index;
|
||||
highIndex = index;
|
||||
}
|
||||
|
||||
if (TargetBytesPerWord == 4) {
|
||||
initLocal(1, highIndex, type);
|
||||
initLocalPart(highIndex, type);
|
||||
Value* next = c.locals[highIndex].value;
|
||||
v->nextWord = next;
|
||||
next->nextWord = v;
|
||||
@ -2525,7 +2534,7 @@ class MyCompiler: public Compiler {
|
||||
}
|
||||
|
||||
virtual void initLocalsFromLogicalIp(unsigned logicalIp) {
|
||||
assert(&c, logicalIp < c.logicalCodeLength);
|
||||
assert(&c, logicalIp < c.logicalCode.count());
|
||||
|
||||
unsigned footprint = sizeof(Local) * c.localFootprint;
|
||||
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) {
|
||||
Local* local = e->locals() + i;
|
||||
if (local->value) {
|
||||
initLocal
|
||||
(1, i, local->value->type == lir::ValueGeneral ? IntegerType : FloatType);
|
||||
initLocalPart(i, local->value->type);
|
||||
}
|
||||
}
|
||||
|
||||
linkLocals(&c, e->locals(), newLocals);
|
||||
}
|
||||
|
||||
virtual void storeLocal(unsigned footprint, Operand* src, unsigned index) {
|
||||
compiler::storeLocal(&c, footprint, static_cast<Value*>(src), index, true);
|
||||
virtual void storeLocal(ir::Value* src, unsigned index)
|
||||
{
|
||||
compiler::storeLocal(&c, typeFootprint(&c, src->type), static_cast<Value*>(src), index, true);
|
||||
}
|
||||
|
||||
virtual Operand* loadLocal(unsigned footprint, unsigned index) {
|
||||
return compiler::loadLocal(&c, footprint, index);
|
||||
virtual ir::Value* loadLocal(ir::Type type, unsigned index)
|
||||
{
|
||||
return compiler::loadLocal(&c, type, index);
|
||||
}
|
||||
|
||||
virtual void saveLocals() {
|
||||
int oldIp UNUSED = c.logicalIp;
|
||||
appendSaveLocals(&c);
|
||||
assert(&c, oldIp == c.logicalIp);
|
||||
}
|
||||
|
||||
virtual void checkBounds(Operand* object, unsigned lengthOffset,
|
||||
Operand* index, intptr_t handler)
|
||||
virtual void checkBounds(ir::Value* object,
|
||||
unsigned lengthOffset,
|
||||
ir::Value* index,
|
||||
intptr_t handler)
|
||||
{
|
||||
appendBoundsCheck(&c, static_cast<Value*>(object), lengthOffset,
|
||||
static_cast<Value*>(index), handler);
|
||||
}
|
||||
|
||||
virtual void store(unsigned srcSize, Operand* src, unsigned dstSize,
|
||||
Operand* dst)
|
||||
virtual ir::Value* truncate(ir::Type type, ir::Value* src)
|
||||
{
|
||||
appendMove(&c, lir::Move, srcSize, srcSize, static_cast<Value*>(src),
|
||||
dstSize, static_cast<Value*>(dst));
|
||||
}
|
||||
|
||||
virtual Operand* load(unsigned srcSize, unsigned srcSelectSize, Operand* src,
|
||||
unsigned dstSize)
|
||||
{
|
||||
assert(&c, dstSize >= TargetBytesPerWord);
|
||||
|
||||
Value* dst = value(&c, static_cast<Value*>(src)->type);
|
||||
appendMove(&c, lir::Move, srcSize, srcSelectSize, static_cast<Value*>(src),
|
||||
dstSize, dst);
|
||||
assert(&c, src->type.flavor() == type.flavor());
|
||||
assert(&c, type.flavor() != ir::Type::Float);
|
||||
assert(&c, type.rawSize() < src->type.rawSize());
|
||||
Value* dst = value(&c, type);
|
||||
appendMove(&c,
|
||||
lir::Move,
|
||||
src->type.size(c.targetInfo),
|
||||
src->type.size(c.targetInfo),
|
||||
static_cast<Value*>(src),
|
||||
type.size(c.targetInfo),
|
||||
dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
virtual Operand* loadz(unsigned srcSize, unsigned srcSelectSize,
|
||||
Operand* src, unsigned dstSize)
|
||||
virtual ir::Value* truncateThenExtend(ir::SignExtendMode signExtend,
|
||||
ir::Type extendType,
|
||||
ir::Type truncateType,
|
||||
ir::Value* src)
|
||||
{
|
||||
assert(&c, dstSize >= TargetBytesPerWord);
|
||||
|
||||
Value* dst = value(&c, static_cast<Value*>(src)->type);
|
||||
appendMove(&c, lir::MoveZ, srcSize, srcSelectSize, static_cast<Value*>(src),
|
||||
dstSize, dst);
|
||||
Value* dst = value(&c, extendType);
|
||||
appendMove(&c,
|
||||
signExtend == ir::SignExtend ? lir::Move : lir::MoveZ,
|
||||
TargetBytesPerWord,
|
||||
truncateType.size(c.targetInfo),
|
||||
static_cast<Value*>(src),
|
||||
extendType.size(c.targetInfo) < TargetBytesPerWord
|
||||
? TargetBytesPerWord
|
||||
: extendType.size(c.targetInfo),
|
||||
dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
virtual void condJump(lir::TernaryOperation type, unsigned size, Operand* a, Operand* b,
|
||||
Operand* address)
|
||||
virtual void store(ir::Value* src, ir::Value* dst)
|
||||
{
|
||||
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,
|
||||
(isGeneralBranch(type) and isGeneralValue(a) and isGeneralValue(b))
|
||||
or (isFloatBranch(type) and isFloatValue(a) and isFloatValue(b)));
|
||||
(isGeneralBranch(op) and isGeneralValue(a) and isGeneralValue(b))or(
|
||||
isFloatBranch(op) and isFloatValue(a) and isFloatValue(b)));
|
||||
|
||||
appendBranch(&c, type, size, static_cast<Value*>(a),
|
||||
static_cast<Value*>(b), static_cast<Value*>(address));
|
||||
assert(&c, a->type == b->type);
|
||||
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) {
|
||||
appendJump(&c, lir::Jump, static_cast<Value*>(address));
|
||||
virtual void jmp(ir::Value* addr)
|
||||
{
|
||||
appendJump(&c, lir::Jump, static_cast<Value*>(addr));
|
||||
}
|
||||
|
||||
virtual void exit(Operand* address) {
|
||||
appendJump(&c, lir::Jump, static_cast<Value*>(address), true);
|
||||
virtual void exit(ir::Value* addr)
|
||||
{
|
||||
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,
|
||||
(isGeneralBinaryOp(type) and isGeneralValue(a) and isGeneralValue(b))
|
||||
or (isFloatBinaryOp(type) and isFloatValue(a) and isFloatValue(b)));
|
||||
(isGeneralBinaryOp(op) and isGeneralValue(a) and isGeneralValue(b))
|
||||
or(isFloatBinaryOp(op) and isFloatValue(a) and isFloatValue(b)));
|
||||
|
||||
Value* result = value(&c, static_cast<Value*>(a)->type);
|
||||
|
||||
appendCombine(&c, type, size, static_cast<Value*>(a),
|
||||
size, static_cast<Value*>(b), size, result);
|
||||
Value* result = value(&c, type);
|
||||
|
||||
appendCombine(&c,
|
||||
op,
|
||||
static_cast<Value*>(a),
|
||||
static_cast<Value*>(b),
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual Operand* unaryOp(lir::BinaryOperation type, unsigned size, Operand* a) {
|
||||
assert(&c, (isGeneralUnaryOp(type) and isGeneralValue(a))or(
|
||||
isFloatUnaryOp(type) and isFloatValue(a)));
|
||||
Value* result = value(&c, static_cast<Value*>(a)->type);
|
||||
appendTranslate(&c, type, size, static_cast<Value*>(a), size, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual Operand* f2f(unsigned aSize, unsigned resSize, Operand* a) {
|
||||
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);
|
||||
virtual ir::Value* unaryOp(lir::BinaryOperation op,
|
||||
ir::Value* a)
|
||||
{
|
||||
assert(&c,
|
||||
(isGeneralUnaryOp(op) and isGeneralValue(a))or(isFloatUnaryOp(op)
|
||||
and isFloatValue(a)));
|
||||
Value* result = value(&c, a->type);
|
||||
appendTranslate(
|
||||
&c, op, static_cast<Value*>(a), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual void nullaryOp(lir::Operation type) {
|
||||
appendOperation(&c, type);
|
||||
virtual ir::Value* f2f(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::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,
|
||||
|
@ -17,41 +17,41 @@ namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
Context::Context(vm::System* system, Assembler* assembler, vm::Zone* zone,
|
||||
Compiler::Client* client):
|
||||
system(system),
|
||||
assembler(assembler),
|
||||
arch(assembler->arch()),
|
||||
zone(zone),
|
||||
client(client),
|
||||
stack(0),
|
||||
locals(0),
|
||||
saved(0),
|
||||
predecessor(0),
|
||||
logicalCode(0),
|
||||
regFile(arch->registerFile()),
|
||||
regAlloc(system, arch->registerFile()),
|
||||
registerResources
|
||||
(static_cast<RegisterResource*>
|
||||
(zone->allocate(sizeof(RegisterResource) * regFile->allRegisters.limit))),
|
||||
frameResources(0),
|
||||
acquiredResources(0),
|
||||
firstConstant(0),
|
||||
lastConstant(0),
|
||||
machineCode(0),
|
||||
firstEvent(0),
|
||||
lastEvent(0),
|
||||
forkState(0),
|
||||
subroutine(0),
|
||||
firstBlock(0),
|
||||
logicalIp(-1),
|
||||
constantCount(0),
|
||||
logicalCodeLength(0),
|
||||
parameterFootprint(0),
|
||||
localFootprint(0),
|
||||
machineCodeSize(0),
|
||||
alignedFrameSize(0),
|
||||
availableGeneralRegisterCount(regFile->generalRegisters.limit - regFile->generalRegisters.start)
|
||||
Context::Context(vm::System* system,
|
||||
Assembler* assembler,
|
||||
vm::Zone* zone,
|
||||
Compiler::Client* client)
|
||||
: system(system),
|
||||
assembler(assembler),
|
||||
arch(assembler->arch()),
|
||||
zone(zone),
|
||||
client(client),
|
||||
stack(0),
|
||||
locals(0),
|
||||
saved(0),
|
||||
predecessor(0),
|
||||
regFile(arch->registerFile()),
|
||||
regAlloc(system, arch->registerFile()),
|
||||
registerResources(static_cast<RegisterResource*>(zone->allocate(
|
||||
sizeof(RegisterResource) * regFile->allRegisters.limit))),
|
||||
frameResources(0),
|
||||
acquiredResources(0),
|
||||
firstConstant(0),
|
||||
lastConstant(0),
|
||||
machineCode(0),
|
||||
firstEvent(0),
|
||||
lastEvent(0),
|
||||
forkState(0),
|
||||
firstBlock(0),
|
||||
logicalIp(-1),
|
||||
constantCount(0),
|
||||
parameterFootprint(0),
|
||||
localFootprint(0),
|
||||
machineCodeSize(0),
|
||||
alignedFrameSize(0),
|
||||
availableGeneralRegisterCount(regFile->generalRegisters.limit
|
||||
- regFile->generalRegisters.start),
|
||||
targetInfo(arch->targetInfo())
|
||||
{
|
||||
for (unsigned i = regFile->generalRegisters.start; i < regFile->generalRegisters.limit; ++i) {
|
||||
new (registerResources + i) RegisterResource(arch->reserved(i));
|
||||
|
@ -35,7 +35,6 @@ class FrameResource;
|
||||
class ConstantPoolNode;
|
||||
|
||||
class ForkState;
|
||||
class MySubroutine;
|
||||
class Block;
|
||||
|
||||
template<class T>
|
||||
@ -50,6 +49,48 @@ List<T>* reverseDestroy(List<T>* cell) {
|
||||
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 {
|
||||
public:
|
||||
Context(vm::System* system, Assembler* assembler, vm::Zone* zone,
|
||||
@ -64,7 +105,7 @@ class Context {
|
||||
Local* locals;
|
||||
List<Value*>* saved;
|
||||
Event* predecessor;
|
||||
LogicalInstruction** logicalCode;
|
||||
LogicalCode logicalCode;
|
||||
const RegisterFile* regFile;
|
||||
RegisterAllocator regAlloc;
|
||||
RegisterResource* registerResources;
|
||||
@ -76,16 +117,15 @@ class Context {
|
||||
Event* firstEvent;
|
||||
Event* lastEvent;
|
||||
ForkState* forkState;
|
||||
MySubroutine* subroutine;
|
||||
Block* firstBlock;
|
||||
int logicalIp;
|
||||
unsigned constantCount;
|
||||
unsigned logicalCodeLength;
|
||||
unsigned parameterFootprint;
|
||||
unsigned localFootprint;
|
||||
unsigned machineCodeSize;
|
||||
unsigned alignedFrameSize;
|
||||
unsigned availableGeneralRegisterCount;
|
||||
ir::TargetInfo targetInfo;
|
||||
};
|
||||
|
||||
inline Aborter* getAborter(Context* c) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -113,28 +113,34 @@ Link*
|
||||
link(Context* c, Event* predecessor, Link* nextPredecessor, Event* successor,
|
||||
Link* nextSuccessor, ForkState* forkState);
|
||||
|
||||
void
|
||||
appendCall(Context* c, Value* address, unsigned flags,
|
||||
TraceHandler* traceHandler, Value* result, unsigned resultSize,
|
||||
Stack* argumentStack, unsigned argumentCount,
|
||||
unsigned stackArgumentFootprint);
|
||||
void appendCall(Context* c,
|
||||
Value* address,
|
||||
ir::CallingConvention callingConvention,
|
||||
unsigned flags,
|
||||
TraceHandler* traceHandler,
|
||||
Value* result,
|
||||
util::Slice<ir::Value*> arguments);
|
||||
|
||||
void
|
||||
appendReturn(Context* c, unsigned size, Value* value);
|
||||
void appendReturn(Context* c, Value* value);
|
||||
|
||||
void
|
||||
appendMove(Context* c, lir::BinaryOperation type, unsigned srcSize,
|
||||
unsigned srcSelectSize, Value* src, unsigned dstSize, Value* dst);
|
||||
void appendMove(Context* c,
|
||||
lir::BinaryOperation op,
|
||||
unsigned srcSize,
|
||||
unsigned srcSelectSize,
|
||||
Value* src,
|
||||
unsigned dstSize,
|
||||
Value* dst);
|
||||
|
||||
void
|
||||
appendCombine(Context* c, lir::TernaryOperation type,
|
||||
unsigned firstSize, Value* first,
|
||||
unsigned secondSize, Value* second,
|
||||
unsigned resultSize, Value* result);
|
||||
void appendCombine(Context* c,
|
||||
lir::TernaryOperation op,
|
||||
Value* first,
|
||||
Value* second,
|
||||
Value* result);
|
||||
|
||||
void
|
||||
appendTranslate(Context* c, lir::BinaryOperation type, unsigned firstSize,
|
||||
Value* first, unsigned resultSize, Value* result);
|
||||
void appendTranslate(Context* c,
|
||||
lir::BinaryOperation op,
|
||||
Value* first,
|
||||
Value* result);
|
||||
|
||||
void
|
||||
appendOperation(Context* c, lir::Operation op);
|
||||
@ -143,13 +149,17 @@ void
|
||||
appendMemory(Context* c, Value* base, int displacement, Value* index,
|
||||
unsigned scale, Value* result);
|
||||
|
||||
void
|
||||
appendBranch(Context* c, lir::TernaryOperation type, unsigned size, Value* first,
|
||||
Value* second, Value* address);
|
||||
void appendBranch(Context* c,
|
||||
lir::TernaryOperation op,
|
||||
Value* first,
|
||||
Value* second,
|
||||
Value* address);
|
||||
|
||||
void
|
||||
appendJump(Context* c, lir::UnaryOperation type, Value* address, bool exit = false,
|
||||
bool cleanLocals = false);
|
||||
void appendJump(Context* c,
|
||||
lir::UnaryOperation op,
|
||||
Value* address,
|
||||
bool exit = false,
|
||||
bool cleanLocals = false);
|
||||
|
||||
void
|
||||
appendBoundsCheck(Context* c, Value* object, unsigned lengthOffset,
|
||||
@ -164,6 +174,8 @@ appendSaveLocals(Context* c);
|
||||
void
|
||||
appendDummy(Context* c);
|
||||
|
||||
void appendBuddy(Context* c, Value* original, Value* buddy);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace codegen
|
||||
} // namespace avian
|
||||
|
@ -45,16 +45,18 @@ int frameIndex(Context* c, int localIndex) {
|
||||
unsigned frameIndexToOffset(Context* c, unsigned frameIndex) {
|
||||
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) {
|
||||
assert(c, static_cast<int>
|
||||
((offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize()) >= 0);
|
||||
assert(c, ((offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize())
|
||||
assert(c,
|
||||
static_cast<int>((offset / c->targetInfo.pointerSize)
|
||||
- c->arch->frameFooterSize()) >= 0);
|
||||
assert(c,
|
||||
((offset / c->targetInfo.pointerSize) - c->arch->frameFooterSize())
|
||||
< totalFrameSize(c));
|
||||
|
||||
return (offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize();
|
||||
return (offset / c->targetInfo.pointerSize) - c->arch->frameFooterSize();
|
||||
}
|
||||
|
||||
unsigned frameBase(Context* c) {
|
||||
|
@ -15,14 +15,19 @@ namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
LogicalInstruction::LogicalInstruction(int index, Stack* stack, Local* locals):
|
||||
firstEvent(0), lastEvent(0), immediatePredecessor(0), stack(stack),
|
||||
locals(locals), machineOffset(0), subroutine(0), index(index)
|
||||
LogicalInstruction::LogicalInstruction(int index, Stack* stack, Local* locals)
|
||||
: firstEvent(0),
|
||||
lastEvent(0),
|
||||
immediatePredecessor(0),
|
||||
stack(stack),
|
||||
locals(locals),
|
||||
machineOffset(0),
|
||||
/*subroutine(0), */ index(index)
|
||||
{ }
|
||||
|
||||
LogicalInstruction* LogicalInstruction::next(Context* c) {
|
||||
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];
|
||||
if (i) return i;
|
||||
}
|
||||
|
@ -57,17 +57,9 @@ class LogicalInstruction {
|
||||
Stack* stack;
|
||||
Local* locals;
|
||||
Promise* machineOffset;
|
||||
MySubroutine* subroutine;
|
||||
int index;
|
||||
};
|
||||
|
||||
class MySubroutine: public Compiler::Subroutine {
|
||||
public:
|
||||
MySubroutine(): forkState(0) { }
|
||||
|
||||
ForkState* forkState;
|
||||
};
|
||||
|
||||
class Block {
|
||||
public:
|
||||
Block(Event* head);
|
||||
|
@ -90,9 +90,10 @@ class PoolPromise: public Promise {
|
||||
|
||||
virtual int64_t value() {
|
||||
if (resolved()) {
|
||||
return reinterpret_cast<int64_t>
|
||||
(c->machineCode + vm::pad(c->machineCodeSize, vm::TargetBytesPerWord)
|
||||
+ (key * vm::TargetBytesPerWord));
|
||||
return reinterpret_cast<int64_t>(
|
||||
c->machineCode
|
||||
+ vm::pad(c->machineCodeSize, c->targetInfo.pointerSize)
|
||||
+ (key * c->targetInfo.pointerSize));
|
||||
}
|
||||
|
||||
abort(c);
|
||||
|
@ -215,12 +215,12 @@ pickTarget(Context* c, Read* read, bool intersectRead,
|
||||
Value* value = read->value;
|
||||
|
||||
uint32_t registerMask
|
||||
= (value->type == lir::ValueFloat ? ~0 : c->regFile->generalRegisters.mask);
|
||||
= (isFloatValue(value) ? ~0 : c->regFile->generalRegisters.mask);
|
||||
|
||||
SiteMask mask(~0, registerMask, AnyFrameIndex);
|
||||
read->intersect(&mask);
|
||||
|
||||
if (value->type == lir::ValueFloat) {
|
||||
if (isFloatValue(value)) {
|
||||
uint32_t floatMask = mask.registerMask & c->regFile->floatRegisters.mask;
|
||||
if (floatMask) {
|
||||
mask.registerMask = floatMask;
|
||||
|
@ -52,7 +52,7 @@ SiteIterator::SiteIterator(Context* c, Value* v, bool includeBuddies,
|
||||
Site** SiteIterator::findNext(Site** p) {
|
||||
while (true) {
|
||||
if (*p) {
|
||||
if (pass == 0 or (*p)->registerSize(c) > vm::TargetBytesPerWord) {
|
||||
if (pass == 0 or (*p)->registerSize(c) > c->targetInfo.pointerSize) {
|
||||
return p;
|
||||
} else {
|
||||
p = &((*p)->next);
|
||||
@ -103,14 +103,11 @@ void SiteIterator::remove(Context* c) {
|
||||
previous = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned Site::registerSize(Context*) {
|
||||
return vm::TargetBytesPerWord;
|
||||
unsigned Site::registerSize(Context* c)
|
||||
{
|
||||
return c->targetInfo.pointerSize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Site* constantSite(Context* c, Promise* 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);
|
||||
unsigned size = rs->registerSize(c);
|
||||
if (size > vm::TargetBytesPerWord) {
|
||||
if (size > c->targetInfo.pointerSize) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
return number == rs->number;
|
||||
} else {
|
||||
@ -352,7 +349,7 @@ SiteMask RegisterSite::mask(Context* c UNUSED) {
|
||||
SiteMask RegisterSite::nextWordMask(Context* c, unsigned) {
|
||||
assert(c, number != lir::NoRegister);
|
||||
|
||||
if (registerSize(c) > vm::TargetBytesPerWord) {
|
||||
if (registerSize(c) > c->targetInfo.pointerSize) {
|
||||
return SiteMask
|
||||
(1 << lir::RegisterOperand, number, NoFrameIndex);
|
||||
} else {
|
||||
@ -367,7 +364,7 @@ unsigned RegisterSite::registerSize(Context* c) {
|
||||
if ((1 << number) & c->regFile->floatRegisters.mask) {
|
||||
return c->arch->floatRegisterSize();
|
||||
} 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) {
|
||||
MemorySite* ms = static_cast<MemorySite*>(s);
|
||||
return ms->base == this->base
|
||||
and ((index == 1 and ms->offset == static_cast<int>
|
||||
(this->offset + vm::TargetBytesPerWord))
|
||||
or (index == 0 and this->offset == static_cast<int>
|
||||
(ms->offset + vm::TargetBytesPerWord)))
|
||||
and ms->index == this->index
|
||||
and ms->scale == this->scale;
|
||||
and ((index == 1
|
||||
and ms->offset
|
||||
== static_cast<int>(this->offset
|
||||
+ c->targetInfo.pointerSize))
|
||||
or (index == 0
|
||||
and this->offset
|
||||
== static_cast<int>(ms->offset
|
||||
+ c->targetInfo.pointerSize)))
|
||||
and ms->index == this->index and ms->scale == this->scale;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -551,10 +551,11 @@ void MemorySite::asAssemblerOperand(Context* c UNUSED, Site* high UNUSED,
|
||||
lir::Operand* result)
|
||||
{
|
||||
// todo: endianness?
|
||||
assert(c, high == this
|
||||
assert(c,
|
||||
high == this
|
||||
or (static_cast<MemorySite*>(high)->base == base
|
||||
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)->scale == scale));
|
||||
|
||||
@ -569,7 +570,8 @@ Site* MemorySite::copy(Context* c) {
|
||||
|
||||
Site* MemorySite::copyHalf(Context* c, bool add) {
|
||||
if (add) {
|
||||
return memorySite(c, base, offset + vm::TargetBytesPerWord, index, scale);
|
||||
return memorySite(
|
||||
c, base, offset + c->targetInfo.pointerSize, index, scale);
|
||||
} else {
|
||||
return copy(c);
|
||||
}
|
||||
@ -584,10 +586,13 @@ Site* MemorySite::copyHigh(Context* c) {
|
||||
}
|
||||
|
||||
Site* MemorySite::makeNextWord(Context* c, unsigned index) {
|
||||
return memorySite
|
||||
(c, base, offset + ((index == 1) xor c->arch->bigEndian()
|
||||
? vm::TargetBytesPerWord : -vm::TargetBytesPerWord),
|
||||
this->index, scale);
|
||||
return memorySite(c,
|
||||
base,
|
||||
offset + ((index == 1) xor c->arch->bigEndian()
|
||||
? c->targetInfo.pointerSize
|
||||
: -c->targetInfo.pointerSize),
|
||||
this->index,
|
||||
scale);
|
||||
}
|
||||
|
||||
SiteMask MemorySite::mask(Context* c) {
|
||||
|
@ -17,10 +17,19 @@ namespace avian {
|
||||
namespace codegen {
|
||||
namespace compiler {
|
||||
|
||||
Value::Value(Site* site, Site* target, lir::ValueType type):
|
||||
reads(0), lastRead(0), sites(site), source(0), target(target), buddy(this),
|
||||
nextWord(this), home(NoFrameIndex), type(type), wordIndex(0)
|
||||
{ }
|
||||
Value::Value(Site* site, Site* target, ir::Type type)
|
||||
: ir::Value(type),
|
||||
reads(0),
|
||||
lastRead(0),
|
||||
sites(site),
|
||||
source(0),
|
||||
target(target),
|
||||
buddy(this),
|
||||
nextWord(this),
|
||||
home(NoFrameIndex),
|
||||
wordIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool Value::findSite(Site* site) {
|
||||
for (Site* s = this->sites; s; s = s->next) {
|
||||
@ -106,7 +115,8 @@ bool Value::uniqueSite(Context* c, Site* s) {
|
||||
if (it.hasMore()) {
|
||||
// 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
|
||||
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);
|
||||
Site* p = nit.next();
|
||||
if (nit.hasMore()) {
|
||||
@ -154,8 +164,8 @@ bool Value::hasBuddy(Context* c, Value* b) {
|
||||
}
|
||||
#endif // not NDEBUG
|
||||
|
||||
|
||||
Value* value(Context* c, lir::ValueType type, Site* site, Site* target) {
|
||||
Value* value(Context* c, ir::Type type, Site* site, Site* target)
|
||||
{
|
||||
return new(c->zone) Value(site, target, type);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ const int NoFrameIndex = -1;
|
||||
|
||||
const bool DebugSites = false;
|
||||
|
||||
class Value: public Compiler::Operand {
|
||||
class Value : public ir::Value {
|
||||
public:
|
||||
Read* reads;
|
||||
Read* lastRead;
|
||||
@ -36,10 +36,9 @@ class Value: public Compiler::Operand {
|
||||
Value* buddy;
|
||||
Value* nextWord;
|
||||
int16_t home;
|
||||
lir::ValueType type;
|
||||
uint8_t wordIndex;
|
||||
|
||||
Value(Site* site, Site* target, lir::ValueType type);
|
||||
Value(Site* site, Site* target, ir::Type type);
|
||||
|
||||
bool findSite(Site* site);
|
||||
|
||||
@ -67,15 +66,17 @@ class Value: public Compiler::Operand {
|
||||
|
||||
};
|
||||
|
||||
inline bool isGeneralValue(Compiler::Operand* a) {
|
||||
return static_cast<Value*>(a)->type == lir::ValueGeneral;
|
||||
inline bool isFloatValue(ir::Value* a)
|
||||
{
|
||||
return static_cast<Value*>(a)->type.flavor() == ir::Type::Float;
|
||||
}
|
||||
|
||||
inline bool isFloatValue(Compiler::Operand* a) {
|
||||
return static_cast<Value*>(a)->type == lir::ValueFloat;
|
||||
inline bool isGeneralValue(ir::Value* a)
|
||||
{
|
||||
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 codegen
|
||||
|
@ -180,6 +180,11 @@ class MyArchitecture: public Architecture {
|
||||
return 3;
|
||||
}
|
||||
|
||||
virtual ir::TargetInfo targetInfo()
|
||||
{
|
||||
return ir::TargetInfo(TargetBytesPerWord);
|
||||
}
|
||||
|
||||
virtual bool bigEndian() {
|
||||
return false;
|
||||
}
|
||||
|
@ -204,6 +204,11 @@ class MyArchitecture: public Architecture {
|
||||
return rdx;
|
||||
}
|
||||
|
||||
virtual ir::TargetInfo targetInfo()
|
||||
{
|
||||
return ir::TargetInfo(TargetBytesPerWord);
|
||||
}
|
||||
|
||||
virtual bool bigEndian() {
|
||||
return false;
|
||||
}
|
||||
|
3927
src/compile.cpp
3927
src/compile.cpp
File diff suppressed because it is too large
Load Diff
612
src/debug-util.cpp
Normal file
612
src/debug-util.cpp
Normal 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
24
src/debug-util.h
Normal 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
|
@ -253,6 +253,16 @@ public class Subroutine {
|
||||
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 {
|
||||
test(false, false);
|
||||
test(false, true);
|
||||
@ -311,6 +321,15 @@ public class Subroutine {
|
||||
(null, new Object[0]);
|
||||
|
||||
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 { }
|
||||
|
@ -24,6 +24,7 @@ run make ${flags} process=interpret ${test_target}
|
||||
# bootimage and openjdk builds without openjdk-src don't work:
|
||||
if [ -z "${openjdk}" ]; then
|
||||
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:
|
||||
run make openjdk=$JAVA_HOME ${flags} ${test_target}
|
||||
fi
|
||||
|
Loading…
Reference in New Issue
Block a user