mirror of
https://github.com/corda/corda.git
synced 2025-01-06 05:04:20 +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
|
#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;
|
||||||
|
@ -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
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 "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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
1
makefile
1
makefile
@ -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 \
|
||||||
|
@ -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,
|
||||||
|
@ -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));
|
||||||
|
@ -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
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
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;
|
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 { }
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user