diff --git a/.gitignore b/.gitignore index bf4aaa6e69..aff794f5e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .gdb_history build +*~ \ No newline at end of file diff --git a/makefile b/makefile index 227d5cd4e4..a2ad32ecc6 100644 --- a/makefile +++ b/makefile @@ -4,6 +4,9 @@ name = avian version = 0.1.1 build-arch = $(shell uname -m | sed 's/^i.86$$/i386/') +ifeq ($(build-arch),Power) + build-arch = powerpc +endif build-platform = \ $(shell uname -s | tr [:upper:] [:lower:] \ @@ -90,6 +93,12 @@ ifeq ($(arch),i386) object-format = elf32-i386 pointer-size = 4 endif +ifeq ($(arch),powerpc) + asm = powerpc + object-arch = powerpc + object-format = elf32-powerpc + pointer-size = 4 +endif ifeq ($(platform),darwin) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) @@ -189,6 +198,7 @@ vm-depends = \ $(src)/zone.h \ $(src)/assembler.h \ $(src)/compiler.h \ + $(src)/$(asm).h \ $(src)/heapwalk.h \ $(src)/bootimage.h @@ -230,11 +240,13 @@ ifeq ($(heapdump),true) cflags += -DAVIAN_HEAPDUMP endif +bootimage-mode = $(mode) + bootimage-generator-sources = $(src)/bootimage.cpp bootimage-generator-objects = \ $(call cpp-objects,$(bootimage-generator-sources),$(src),$(native-build)) bootimage-generator = \ - $(build)/$(build-platform)-$(build-arch)-compile-fast/bootimage-generator + $(build)/$(build-platform)-$(build-arch)-compile-$(bootimage-mode)/bootimage-generator bootimage-bin = $(native-build)/bootimage.bin bootimage-object = $(native-build)/bootimage-bin.o @@ -355,6 +367,8 @@ $(test-dep): $(test-sources) @mkdir -p $(dir $(@)) $(javac) -d $(dir $(@)) -bootclasspath $(classpath-build) \ $(shell $(MAKE) -s --no-print-directory $(test-classes)) + $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(dir $(@)) \ + test/Subroutine.java @touch $(@) define compile-object @@ -404,7 +418,7 @@ $(binaryToMacho): $(src)/binaryToMacho.cpp $(classpath-object): $(build)/classpath.jar $(binaryToMacho) @echo "creating $(@)" ifeq ($(platform),darwin) - $(binaryToMacho) $(build)/classpath.jar __TEXT __text \ + $(binaryToMacho) $(asm) $(build)/classpath.jar __TEXT __text \ __binary_classpath_jar_start __binary_classpath_jar_end > $(@) else (wd=$$(pwd); \ @@ -458,9 +472,11 @@ else endif $(strip) $(strip-all) $(@) -$(bootimage-generator): +$(bootimage-generator): make-bootimage-generator + +make-bootimage-generator: (unset MAKEFLAGS && \ - make mode=fast process=compile \ + make mode=$(bootimage-mode) process=compile \ arch=$(build-arch) \ platform=$(build-platform) \ bootimage-generator= \ diff --git a/src/arch.h b/src/arch.h new file mode 100644 index 0000000000..ae613297b6 --- /dev/null +++ b/src/arch.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2008, 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 ARCH_H +#define ARCH_H + +#include "common.h" + +extern "C" void NO_RETURN +vmJump(void* address, void* base, void* stack, void* thread); + +#if (defined __i386__) || (defined __x86_64__) +# include "x86.h" +#elif defined __POWERPC__ +# include "powerpc.h" +#else +# error unsupported architecture +#endif + +#endif//ARCH_H diff --git a/src/assembler.h b/src/assembler.h index 0677178e68..549e7cad2b 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -23,8 +23,6 @@ enum Operation { const unsigned OperationCount = Return + 1; enum UnaryOperation { - Push, - Pop, Call, LongCall, AlignedCall, @@ -35,20 +33,22 @@ enum UnaryOperation { JumpIfLessOrEqual, JumpIfGreaterOrEqual, JumpIfEqual, - JumpIfNotEqual, + JumpIfNotEqual +}; + +const unsigned UnaryOperationCount = JumpIfNotEqual + 1; + +enum BinaryOperation { + Move, + MoveZ, + Compare, Negate }; -const unsigned UnaryOperationCount = Negate + 1; +const unsigned BinaryOperationCount = Negate + 1; -enum BinaryOperation { - LoadAddress, - Move, - MoveZ, - Move4To8, - Swap, +enum TernaryOperation { LongCompare, - Compare, Add, Subtract, Multiply, @@ -62,7 +62,7 @@ enum BinaryOperation { Xor }; -const unsigned BinaryOperationCount = Xor + 1; +const unsigned TernaryOperationCount = Xor + 1; enum OperandType { ConstantOperand, @@ -74,7 +74,6 @@ enum OperandType { const unsigned OperandTypeCount = MemoryOperand + 1; const int NoRegister = -1; -const int AnyRegister = -2; class Promise { public: @@ -105,6 +104,43 @@ class ResolvedPromise: public Promise { int64_t value_; }; +class ShiftMaskPromise: public Promise { + public: + ShiftMaskPromise(Promise* base, unsigned shift, int64_t mask): + base(base), shift(shift), mask(mask) + { } + + virtual int64_t value() { + return (base->value() >> shift) & mask; + } + + virtual bool resolved() { + return base->resolved(); + } + + Promise* base; + unsigned shift; + int64_t mask; +}; + +class CombinedPromise: public Promise { + public: + CombinedPromise(Promise* low, Promise* high): + low(low), high(high) + { } + + virtual int64_t value() { + return low->value() | (high->value() << 32); + } + + virtual bool resolved() { + return low->resolved() and high->resolved(); + } + + Promise* low; + Promise* high; +}; + class ListenPromise: public Promise { public: ListenPromise(System* s, Allocator* allocator): @@ -160,7 +196,8 @@ class DelayedPromise: public ListenPromise { class TraceHandler { public: - virtual void handleTrace(Promise* address) = 0; + virtual void handleTrace(Promise* address, unsigned padIndex, + unsigned padding) = 0; }; class Assembler { @@ -211,46 +248,100 @@ class Assembler { virtual void restore(int r) = 0; }; + class Block { + public: + virtual unsigned resolve(unsigned start, Block* next) = 0; + }; + + class Architecture { + public: + virtual unsigned registerCount() = 0; + + virtual int stack() = 0; + virtual int thread() = 0; + virtual int returnLow() = 0; + virtual int returnHigh() = 0; + + virtual bool condensedAddressing() = 0; + + virtual bool reserved(int register_) = 0; + + virtual unsigned argumentRegisterCount() = 0; + virtual int argumentRegister(unsigned index) = 0; + + virtual void updateCall(UnaryOperation op, bool assertAlignment, + void* returnAddress, void* newTarget) = 0; + + virtual unsigned alignFrameSize(unsigned sizeInWords) = 0; + + virtual void* frameIp(void* stack) = 0; + virtual unsigned frameHeaderSize() = 0; + virtual unsigned frameReturnAddressSize() = 0; + virtual unsigned frameFooterSize() = 0; + virtual void nextFrame(void** stack, void** base) = 0; + + virtual void plan + (UnaryOperation op, + unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, + bool* thunk) = 0; + + virtual void plan + (BinaryOperation op, + unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask, + bool* thunk) = 0; + + virtual void plan + (TernaryOperation op, + unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask, + unsigned cSize, uint8_t* cTypeMask, uint64_t* cRegisterMask, + bool* thunk) = 0; + + virtual void acquire() = 0; + virtual void release() = 0; + }; + virtual void setClient(Client* client) = 0; - virtual unsigned registerCount() = 0; + virtual Architecture* arch() = 0; - virtual int base() = 0; - virtual int stack() = 0; - virtual int thread() = 0; - virtual int returnLow() = 0; - virtual int returnHigh() = 0; - - virtual unsigned argumentRegisterCount() = 0; - virtual int argumentRegister(unsigned index) = 0; - - virtual void plan(UnaryOperation op, unsigned size, uint8_t* typeMask, - uint64_t* registerMask, bool* thunk) = 0; - - virtual void plan(BinaryOperation op, unsigned size, uint8_t* aTypeMask, - uint64_t* aRegisterMask, uint8_t* bTypeMask, - uint64_t* bRegisterMask, bool* thunk) = 0; + virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) = 0; + virtual void pushFrame(unsigned argumentCount, ...) = 0; + virtual void allocateFrame(unsigned footprint) = 0; + virtual void popFrame() = 0; virtual void apply(Operation op) = 0; - virtual void apply(UnaryOperation op, unsigned size, OperandType type, - Operand* operand) = 0; + virtual void apply(UnaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand) = 0; - virtual void apply(BinaryOperation op, unsigned size, OperandType aType, - Operand* a, OperandType bType, Operand* b) = 0; + virtual void apply(BinaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand, + unsigned bSize, OperandType bType, Operand* bOperand) = 0; + + virtual void apply(TernaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand, + unsigned bSize, OperandType bType, Operand* bOperand, + unsigned cSize, OperandType cType, Operand* cOperand) = 0; virtual void writeTo(uint8_t* dst) = 0; - virtual unsigned length() = 0; + virtual Promise* offset() = 0; - virtual void updateCall(UnaryOperation op, bool assertAlignment, - void* returnAddress, void* newTarget) = 0; + virtual Block* endBlock(bool startNew) = 0; + + virtual unsigned length() = 0; virtual void dispose() = 0; }; +Assembler::Architecture* +makeArchitecture(System* system); + Assembler* -makeAssembler(System* system, Allocator* allocator, Zone* zone); +makeAssembler(System* system, Allocator* allocator, Zone* zone, + Assembler::Architecture* architecture); } // namespace vm diff --git a/src/binaryToMacho.cpp b/src/binaryToMacho.cpp index 88259b81cb..c5f55d118a 100644 --- a/src/binaryToMacho.cpp +++ b/src/binaryToMacho.cpp @@ -20,6 +20,8 @@ #include "mach-o/loader.h" #include "mach-o/nlist.h" + + namespace { inline unsigned @@ -29,18 +31,29 @@ pad(unsigned n) } void -writeObject(FILE* out, const uint8_t* data, unsigned size, +writeObject(const char* architecture, + FILE* out, const uint8_t* data, unsigned size, const char* segmentName, const char* sectionName, const char* startName, const char* endName) { unsigned startNameLength = strlen(startName) + 1; unsigned endNameLength = strlen(endName) + 1; + cpu_type_t cpuType; + cpu_subtype_t cpuSubtype; + if (strcmp(architecture, "x86") == 0) { + cpuType = CPU_TYPE_I386; + cpuSubtype = CPU_SUBTYPE_I386_ALL; + } else if (strcmp(architecture, "powerpc") == 0) { + cpuType = CPU_TYPE_POWERPC; + cpuSubtype = CPU_SUBTYPE_POWERPC_ALL; + } + mach_header header = { MH_MAGIC, // magic - CPU_TYPE_I386, // cputype - CPU_SUBTYPE_I386_ALL, // cpusubtype - MH_OBJECT, // filetype + cpuType, + cpuSubtype, + MH_OBJECT, // filetype, 2, // ncmds sizeof(segment_command) + sizeof(section) @@ -142,17 +155,17 @@ writeObject(FILE* out, const uint8_t* data, unsigned size, int main(int argc, const char** argv) { - if (argc != 6) { + if (argc != 7) { fprintf(stderr, - "usage: %s
" - " \n", + "usage: %s " + "
\n", argv[0]); return -1; } uint8_t* data = 0; unsigned size; - int fd = open(argv[1], O_RDONLY); + int fd = open(argv[2], O_RDONLY); if (fd != -1) { struct stat s; int r = fstat(fd, &s); @@ -165,8 +178,11 @@ main(int argc, const char** argv) } if (data) { - writeObject(stdout, data, size, argv[2], argv[3], argv[4], argv[5]); + writeObject + (argv[1], stdout, data, size, argv[3], argv[4], argv[5], argv[6]); + munmap(data, size); + return 0; } else { perror(argv[0]); diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 9291acdfd0..2ff9c6c1bf 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -33,7 +33,8 @@ endsWith(const char* suffix, const char* s, unsigned length) object makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, - unsigned capacity, uintptr_t* codeMap) + unsigned capacity, uintptr_t* codeMap, const char* className, + const char* methodName, const char* methodSpec) { unsigned size = 0; t->m->processor->compileThunks(t, image, code, &size, capacity); @@ -50,7 +51,9 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, unsigned nameSize = 0; const char* name = it.next(&nameSize); - if (endsWith(".class", name, nameSize)) { + if (endsWith(".class", name, nameSize) + and (className == 0 or strncmp(name, className, nameSize - 6) == 0)) + { //fprintf(stderr, "%.*s\n", nameSize - 6, name); object c = resolveClass (t, makeByteArray(t, "%.*s", nameSize - 6, name)); @@ -59,7 +62,19 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); - if (methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) { + if ((methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) + and ((methodName == 0 + or strcmp + (reinterpret_cast + (&byteArrayBody + (t, vm::methodName(t, method), 0)), methodName) == 0) + and (methodSpec == 0 + or strcmp + (reinterpret_cast + (&byteArrayBody + (t, vm::methodSpec(t, method), 0)), methodSpec) + == 0))) + { t->m->processor->compileMethod (t, zone, code, &size, capacity, &constants, &calls, &addresses, method); @@ -255,7 +270,8 @@ offset(object a, uintptr_t* b) } void -writeBootImage(Thread* t, FILE* out) +writeBootImage(Thread* t, FILE* out, const char* className, + const char* methodName, const char* methodSpec) { Zone zone(t->m->system, t->m->heap, 64 * 1024); BootImage image; @@ -267,7 +283,8 @@ writeBootImage(Thread* t, FILE* out) memset(codeMap, 0, codeMapSize(CodeCapacity)); object constants = makeCodeImage - (t, &zone, &image, code, CodeCapacity, codeMap); + (t, &zone, &image, code, CodeCapacity, codeMap, className, methodName, + methodSpec); PROTECT(t, constants); const unsigned HeapCapacity = 32 * 1024 * 1024; @@ -348,8 +365,9 @@ writeBootImage(Thread* t, FILE* out) int main(int ac, const char** av) { - if (ac != 2) { - fprintf(stderr, "usage: %s \n", av[0]); + if (ac < 2 or ac > 5) { + fprintf(stderr, "usage: %s " + "[ [ []]]\n", av[0]); return -1; } @@ -363,7 +381,9 @@ main(int ac, const char** av) enter(t, Thread::ActiveState); enter(t, Thread::IdleState); - writeBootImage(t, stdout); + writeBootImage + (t, stdout, (ac > 2 ? av[2] : 0), (ac > 3 ? av[3] : 0), + (ac > 4 ? av[4] : 0)); return 0; } diff --git a/src/common.h b/src/common.h index e2783c7ef9..0b5fc040a3 100644 --- a/src/common.h +++ b/src/common.h @@ -29,7 +29,7 @@ # define PATH_SEPARATOR ':' #endif -#ifdef __i386__ +#if (defined __i386__) || (defined __POWERPC__) # define LD "d" # define LLD "lld" #ifdef __APPLE__ @@ -62,12 +62,6 @@ # define SO_SUFFIX ".so" #endif -#ifdef __APPLE__ -# define FORCE_ALIGN __attribute__((force_align_arg_pointer)) -#else -# define FORCE_ALIGN -#endif - #define NO_RETURN __attribute__((noreturn)) #define LIKELY(v) __builtin_expect((v) != 0, true) diff --git a/src/compile.S b/src/compile.S index 90416024ee..80c1350384 100644 --- a/src/compile.S +++ b/src/compile.S @@ -10,6 +10,8 @@ #include "types.h" +#define LOCAL(x) .L##x + .text #ifdef __x86_64__ @@ -37,15 +39,15 @@ vmInvoke: // copy arguments into place pushq %rcx movq $0,%r9 - jmp test + jmp LOCAL(test) -loop: +LOCAL(loop): push (%rdx,%r9,8) inc %r9 -test: +LOCAL(test): cmpq %rcx,%r9 - jb loop + jb LOCAL(loop) // call function call *%rsi @@ -97,15 +99,15 @@ vmInvoke: // copy arguments into place movl $0,%ecx mov 16(%ebp),%edx - jmp test + jmp LOCAL(test) -loop: +LOCAL(loop): push (%edx,%ecx,4) inc %ecx -test: +LOCAL(test): cmpl 20(%ebp),%ecx - jb loop + jb LOCAL(loop) // call function call *12(%ebp) @@ -118,20 +120,20 @@ test: // handle return value based on expected type movl 24(%ebp),%ecx -void: +LOCAL(void): cmpl $VOID_TYPE,%ecx - jne int64 - jmp exit + jne LOCAL(int64) + jmp LOCAL(exit) -int64: +LOCAL(int64): cmpl $INT64_TYPE,%ecx - jne int32 - jmp exit + jne LOCAL(int32) + jmp LOCAL(exit) -int32: +LOCAL(int32): movl $0,%edx -exit: +LOCAL(exit): popl %edi popl %esi popl %ebx diff --git a/src/compile.cpp b/src/compile.cpp index 89e1b6d658..85da676149 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -14,7 +14,7 @@ #include "process.h" #include "assembler.h" #include "compiler.h" -#include "x86.h" +#include "arch.h" using namespace vm; @@ -27,7 +27,7 @@ vmCall(); namespace { -const bool DebugCompile = false; +const bool DebugCompile = true; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -35,6 +35,10 @@ const bool DebugFrameMaps = false; const bool CheckArrayBounds = true; +const unsigned MaxNativeCallFootprint = 4; + +const unsigned InitialZoneCapacityInBytes = 64 * 1024; + class MyThread: public Thread { public: class CallTrace { @@ -65,26 +69,31 @@ class MyThread: public Thread { CallTrace* next; }; - MyThread(Machine* m, object javaThread, Thread* parent): + MyThread(Machine* m, object javaThread, MyThread* parent): Thread(m, javaThread, parent), ip(0), base(0), stack(0), trace(0), - reference(0) - { } + reference(0), + arch(parent ? parent->arch : makeArchitecture(m->system)) + { + arch->acquire(); + } void* ip; void* base; void* stack; CallTrace* trace; Reference* reference; + Assembler::Architecture* arch; }; object resolveThisPointer(MyThread* t, void* stack, object method) { - return reinterpret_cast(stack)[methodParameterFootprint(t, method)]; + return reinterpret_cast(stack) + [methodParameterFootprint(t, method) + t->arch->frameFooterSize()]; } object @@ -211,8 +220,8 @@ class MyStackWalker: public Processor::StackWalker { // fprintf(stderr, "state: %d\n", state); switch (state) { case Start: - if (ip_ == 0 and stack) { - ip_ = *static_cast(stack); + if (ip_ == 0) { + ip_ = t->arch->frameIp(stack); } if (trace and trace->nativeMethod) { @@ -229,9 +238,9 @@ class MyStackWalker: public Processor::StackWalker { if (method_) { state = Method; } else if (trace) { - stack = static_cast(trace->stack); - ip_ = (stack ? *static_cast(stack) : 0); + stack = trace->stack; base = trace->base; + ip_ = t->arch->frameIp(stack); trace = trace->next; if (trace and trace->nativeMethod) { @@ -262,9 +271,8 @@ class MyStackWalker: public Processor::StackWalker { void next() { switch (state) { case Method: - stack = static_cast(base) + 1; - ip_ = (stack ? *static_cast(stack) : 0); - base = *static_cast(base); + t->arch->nextFrame(&stack, &base); + ip_ = t->arch->frameIp(stack); break; case NativeMethod: @@ -318,24 +326,63 @@ class MyStackWalker: public Processor::StackWalker { MyProtector protector; }; +unsigned +localSize(MyThread* t, object method) +{ + unsigned size = codeMaxLocals(t, methodCode(t, method)); + if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC)) + == ACC_SYNCHRONIZED) + { + ++ size; + } + return size; +} + +unsigned +alignedFrameSize(MyThread* t, object method) +{ + return t->arch->alignFrameSize + (localSize(t, method) + - methodParameterFootprint(t, method) + + codeMaxStack(t, methodCode(t, method)) + + MaxNativeCallFootprint + - min(MaxNativeCallFootprint, t->arch->argumentRegisterCount())); +} + +unsigned +alignedFrameSizeWithParameters(MyThread* t, object method) +{ + return methodParameterFootprint(t, method) + alignedFrameSize(t, method); +} + int localOffset(MyThread* t, int v, object method) { - int parameterFootprint = methodParameterFootprint(t, method) * BytesPerWord; + int parameterFootprint = methodParameterFootprint(t, method); + int frameSize = alignedFrameSize(t, method); - v *= BytesPerWord; - if (v < parameterFootprint) { - return (parameterFootprint - v - BytesPerWord) + (BytesPerWord * 2); - } else { - return -(v + BytesPerWord - parameterFootprint); - } + int offset = ((v < parameterFootprint) ? + (frameSize + + parameterFootprint + + (t->arch->frameFooterSize() * 2) + + t->arch->frameHeaderSize() + - v - 1) : + (frameSize + + parameterFootprint + + t->arch->frameFooterSize() + - v - 1)) * BytesPerWord; + + assert(t, offset >= 0); + return offset; } inline object* -localObject(MyThread* t, void* base, object method, unsigned index) +localObject(MyThread* t, void* stack, object method, unsigned index) { return reinterpret_cast - (static_cast(base) + localOffset(t, index, method)); + (static_cast(stack) + + localOffset(t, index, method) + + (t->arch->frameReturnAddressSize() * BytesPerWord)); } class PoolElement: public Promise { @@ -367,56 +414,47 @@ class TraceElement: public TraceHandler { bool virtualCall, TraceElement* next): context(context), address(0), + next(next), target(target), - virtualCall(virtualCall), - next(next) + padIndex(0), + padding(0), + virtualCall(virtualCall) { } - virtual void handleTrace(Promise* address) { + virtual void handleTrace(Promise* address, unsigned padIndex, + unsigned padding) + { if (this->address == 0) { this->address = address; + this->padIndex = padIndex; + this->padding = padding; } } Context* context; Promise* address; - object target; - bool virtualCall; TraceElement* next; + object target; + unsigned padIndex; + unsigned padding; + bool virtualCall; uintptr_t map[0]; }; enum Event { - PushEvent, - PopEvent, + PushContextEvent, + PopContextEvent, IpEvent, MarkEvent, ClearEvent, TraceEvent }; -unsigned -localSize(MyThread* t, object method) -{ - unsigned size = codeMaxLocals(t, methodCode(t, method)); - if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC)) - == ACC_SYNCHRONIZED) - { - ++ size; - } - return size; -} - -unsigned -frameSize(MyThread* t, object method) -{ - return localSize(t, method) + codeMaxStack(t, methodCode(t, method)); -} - unsigned frameMapSizeInWords(MyThread* t, object method) { - return ceiling(frameSize(t, method), BitsPerWord) * BytesPerWord; + return ceiling(alignedFrameSizeWithParameters(t, method), BitsPerWord) + * BytesPerWord; } uint16_t* @@ -509,7 +547,7 @@ class Context { abort(t); } - virtual intptr_t getThunk(BinaryOperation op, unsigned size) { + virtual intptr_t getThunk(TernaryOperation op, unsigned size) { switch (op) { case Divide: if (size == 8) { @@ -534,8 +572,8 @@ class Context { Context(MyThread* t, BootContext* bootContext, object method): thread(t), - zone(t->m->system, t->m->heap, 16 * 1024), - assembler(makeAssembler(t->m->system, t->m->heap, &zone)), + zone(t->m->system, t->m->heap, InitialZoneCapacityInBytes), + assembler(makeAssembler(t->m->system, t->m->heap, &zone, t->arch)), client(t), compiler(makeCompiler(t->m->system, assembler, &zone, &client)), method(method), @@ -552,8 +590,8 @@ class Context { Context(MyThread* t): thread(t), - zone(t->m->system, t->m->heap, LikelyPageSizeInBytes), - assembler(makeAssembler(t->m->system, t->m->heap, &zone)), + zone(t->m->system, t->m->heap, InitialZoneCapacityInBytes), + assembler(makeAssembler(t->m->system, t->m->heap, &zone, t->arch)), client(t), compiler(0), method(0), @@ -603,6 +641,7 @@ class Frame { context(context), t(context->thread), c(context->compiler), + subroutine(0), stackMap(stackMap), ip(0), sp(localSize()), @@ -615,31 +654,24 @@ class Frame { context(f->context), t(context->thread), c(context->compiler), + subroutine(f->subroutine), stackMap(stackMap), ip(f->ip), sp(f->sp), level(f->level + 1) { - c->pushState(); - memcpy(stackMap, f->stackMap, codeMaxStack (t, methodCode(t, context->method))); if (level > 1) { - context->eventLog.append(PushEvent); + context->eventLog.append(PushContextEvent); } } ~Frame() { if (t->exception == 0) { - if (level > 0) { - c->saveStack(); - c->popState(); - c->resetStack(); - } - if (level > 1) { - context->eventLog.append(PopEvent); + context->eventLog.append(PopContextEvent); } } } @@ -895,31 +927,43 @@ class Frame { this->ip = ip; } + void pushQuiet(unsigned footprint, Compiler::Operand* o) { + c->push(footprint, o); + } + + void pushLongQuiet(Compiler::Operand* o) { + pushQuiet(2, o); + } + + Compiler::Operand* popQuiet(unsigned footprint) { + return c->pop(footprint); + } + + Compiler::Operand* popLongQuiet() { + Compiler::Operand* r = popQuiet(2); + + return r; + } + void pushInt(Compiler::Operand* o) { - c->push(4, o); + pushQuiet(1, o); pushedInt(); } void pushAddress(Compiler::Operand* o) { - c->push(BytesPerWord, o); + pushQuiet(1, o); pushedInt(); } void pushObject(Compiler::Operand* o) { - c->push(BytesPerWord, o); + pushQuiet(1, o); pushedObject(); } void pushObject() { - c->pushed(1); - pushedObject(); - } + c->pushed(); - void pushLongQuiet(Compiler::Operand* o) { - if (BytesPerWord == 8) { - c->push(8); - } - c->push(8, o); + pushedObject(); } void pushLong(Compiler::Operand* o) { @@ -927,26 +971,20 @@ class Frame { pushedLong(); } - void pop(unsigned count, bool isEvent = true) { + void pop(unsigned count) { popped(count); - c->popped(count, isEvent); + + for (unsigned i = count; i;) { + Compiler::StackElement* s = c->top(); + unsigned footprint = c->footprint(s); + c->popped(footprint); + i -= footprint; + } } Compiler::Operand* popInt() { poppedInt(); - return c->pop(4); - } - - Compiler::Operand* popLongQuiet() { - Compiler::Operand* r = c->pop(8); - if (BytesPerWord == 8) { - c->pop(8); - } - return r; - } - - Compiler::Operand* peekLong(unsigned index) { - return c->peek(8, index); + return popQuiet(1); } Compiler::Operand* popLong() { @@ -956,41 +994,41 @@ class Frame { Compiler::Operand* popObject() { poppedObject(); - return c->pop(BytesPerWord); + return popQuiet(1); } void loadInt(unsigned index) { assert(t, index < localSize()); - pushInt(c->loadLocal(BytesPerWord, index)); + pushInt(c->loadLocal(1, index)); } void loadLong(unsigned index) { assert(t, index < static_cast(localSize() - 1)); - pushLong(c->loadLocal(8, index + 1)); + pushLong(c->loadLocal(2, index)); } void loadObject(unsigned index) { assert(t, index < localSize()); - pushObject(c->loadLocal(BytesPerWord, index)); + pushObject(c->loadLocal(1, index)); } void storeInt(unsigned index) { - c->storeLocal(BytesPerWord, popInt(), index); + c->storeLocal(1, popInt(), index); storedInt(index); } void storeLong(unsigned index) { - c->storeLocal(8, popLong(), index + 1); + c->storeLocal(2, popLong(), index); storedLong(index); } void storeObject(unsigned index) { - c->storeLocal(BytesPerWord, popObject(), index); + c->storeLocal(1, popObject(), index); storedObject(index); } void storeObjectOrAddress(unsigned index) { - c->storeLocal(BytesPerWord, c->pop(BytesPerWord), index); + c->storeLocal(1, popQuiet(1), index); assert(t, sp >= 1); assert(t, sp - 1 >= localSize()); @@ -1004,39 +1042,39 @@ class Frame { } void dup() { - c->push(BytesPerWord, c->peek(BytesPerWord, 0)); + pushQuiet(1, c->peek(1, 0)); dupped(); } void dupX1() { - Compiler::Operand* s0 = c->pop(BytesPerWord); - Compiler::Operand* s1 = c->pop(BytesPerWord); + Compiler::Operand* s0 = popQuiet(1); + Compiler::Operand* s1 = popQuiet(1); - c->push(BytesPerWord, s0); - c->push(BytesPerWord, s1); - c->push(BytesPerWord, s0); + pushQuiet(1, s0); + pushQuiet(1, s1); + pushQuiet(1, s0); duppedX1(); } void dupX2() { - Compiler::Operand* s0 = c->pop(BytesPerWord); + Compiler::Operand* s0 = popQuiet(1); if (get(sp - 2) == Long) { Compiler::Operand* s1 = popLongQuiet(); - c->push(BytesPerWord, s0); + pushQuiet(1, s0); pushLongQuiet(s1); - c->push(BytesPerWord, s0); + pushQuiet(1, s0); } else { - Compiler::Operand* s1 = c->pop(BytesPerWord); - Compiler::Operand* s2 = c->pop(BytesPerWord); + Compiler::Operand* s1 = popQuiet(1); + Compiler::Operand* s2 = popQuiet(1); - c->push(BytesPerWord, s0); - c->push(BytesPerWord, s2); - c->push(BytesPerWord, s1); - c->push(BytesPerWord, s0); + pushQuiet(1, s0); + pushQuiet(1, s2); + pushQuiet(1, s1); + pushQuiet(1, s0); } duppedX2(); @@ -1044,15 +1082,15 @@ class Frame { void dup2() { if (get(sp - 1) == Long) { - pushLongQuiet(peekLong(0)); + pushLongQuiet(c->peek(2, 0)); } else { - Compiler::Operand* s0 = c->pop(BytesPerWord); - Compiler::Operand* s1 = c->pop(BytesPerWord); + Compiler::Operand* s0 = popQuiet(1); + Compiler::Operand* s1 = popQuiet(1); - c->push(BytesPerWord, s1); - c->push(BytesPerWord, s0); - c->push(BytesPerWord, s1); - c->push(BytesPerWord, s0); + pushQuiet(1, s1); + pushQuiet(1, s0); + pushQuiet(1, s1); + pushQuiet(1, s0); } dupped2(); @@ -1061,21 +1099,21 @@ class Frame { void dup2X1() { if (get(sp - 1) == Long) { Compiler::Operand* s0 = popLongQuiet(); - Compiler::Operand* s1 = c->pop(BytesPerWord); + Compiler::Operand* s1 = popQuiet(1); pushLongQuiet(s0); - c->push(BytesPerWord, s1); + pushQuiet(1, s1); pushLongQuiet(s0); } else { - Compiler::Operand* s0 = c->pop(BytesPerWord); - Compiler::Operand* s1 = c->pop(BytesPerWord); - Compiler::Operand* s2 = c->pop(BytesPerWord); + Compiler::Operand* s0 = popQuiet(1); + Compiler::Operand* s1 = popQuiet(1); + Compiler::Operand* s2 = popQuiet(1); - c->push(BytesPerWord, s1); - c->push(BytesPerWord, s0); - c->push(BytesPerWord, s2); - c->push(BytesPerWord, s1); - c->push(BytesPerWord, s0); + pushQuiet(1, s1); + pushQuiet(1, s0); + pushQuiet(1, s2); + pushQuiet(1, s1); + pushQuiet(1, s0); } dupped2X1(); @@ -1092,37 +1130,37 @@ class Frame { pushLongQuiet(s1); pushLongQuiet(s0); } else { - Compiler::Operand* s1 = c->pop(BytesPerWord); - Compiler::Operand* s2 = c->pop(BytesPerWord); + Compiler::Operand* s1 = popQuiet(1); + Compiler::Operand* s2 = popQuiet(1); pushLongQuiet(s0); - c->push(BytesPerWord, s2); - c->push(BytesPerWord, s1); + pushQuiet(1, s2); + pushQuiet(1, s1); pushLongQuiet(s0); } } else { - Compiler::Operand* s0 = c->pop(BytesPerWord); - Compiler::Operand* s1 = c->pop(BytesPerWord); - Compiler::Operand* s2 = c->pop(BytesPerWord); - Compiler::Operand* s3 = c->pop(BytesPerWord); + Compiler::Operand* s0 = popQuiet(1); + Compiler::Operand* s1 = popQuiet(1); + Compiler::Operand* s2 = popQuiet(1); + Compiler::Operand* s3 = popQuiet(1); - c->push(BytesPerWord, s1); - c->push(BytesPerWord, s0); - c->push(BytesPerWord, s3); - c->push(BytesPerWord, s2); - c->push(BytesPerWord, s1); - c->push(BytesPerWord, s0); + pushQuiet(1, s1); + pushQuiet(1, s0); + pushQuiet(1, s3); + pushQuiet(1, s2); + pushQuiet(1, s1); + pushQuiet(1, s0); } dupped2X2(); } void swap() { - Compiler::Operand* s0 = c->pop(BytesPerWord); - Compiler::Operand* s1 = c->pop(BytesPerWord); + Compiler::Operand* s0 = popQuiet(1); + Compiler::Operand* s1 = popQuiet(1); - c->push(BytesPerWord, s0); - c->push(BytesPerWord, s1); + pushQuiet(1, s0); + pushQuiet(1, s1); swapped(); } @@ -1145,6 +1183,7 @@ class Frame { Context* context; MyThread* t; Compiler* c; + Compiler::Subroutine* subroutine; uint8_t* stackMap; unsigned ip; unsigned sp; @@ -1196,9 +1235,9 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, { void* ip = t->ip; void* base = t->base; - void** stack = static_cast(t->stack); + void* stack = t->stack; if (ip == 0) { - ip = *stack; + ip = t->arch->frameIp(stack); } *targetIp = 0; @@ -1213,35 +1252,38 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, unsigned parameterFootprint = methodParameterFootprint(t, method); unsigned localFootprint = localSize(t, method); - stack = static_cast(base) - - (localFootprint - parameterFootprint); + static_cast(stack) + [alignedFrameSize(t, method) - t->arch->frameHeaderSize() + - (localFootprint - parameterFootprint - 1) + + t->arch->frameReturnAddressSize()] + = t->exception; - *(--stack) = t->exception; t->exception = 0; *targetIp = handler; *targetBase = base; - *targetStack = stack; + *targetStack = static_cast(stack) + + t->arch->frameReturnAddressSize(); } else { if (methodFlags(t, method) & ACC_SYNCHRONIZED) { object lock; if (methodFlags(t, method) & ACC_STATIC) { lock = methodClass(t, method); } else { - lock = *localObject(t, base, method, savedTargetIndex(t, method)); + lock = *localObject(t, stack, method, savedTargetIndex(t, method)); } release(t, lock); } - stack = static_cast(base) + 1; - ip = *stack; - base = *static_cast(base); + t->arch->nextFrame(&stack, &base); + ip = t->arch->frameIp(stack); } } else { *targetIp = ip; *targetBase = base; - *targetStack = stack + 1; + *targetStack = static_cast(stack) + + t->arch->frameReturnAddressSize(); } } } @@ -1256,7 +1298,7 @@ unwind(MyThread* t) vmJump(ip, base, stack, t); } -void FORCE_ALIGN +void tryInitClass(MyThread* t, object class_) { initClass(t, class_); @@ -1285,7 +1327,7 @@ methodAddress(Thread* t, object method) } } -void* FORCE_ALIGN +void* findInterfaceMethodFromInstance(MyThread* t, object method, object instance) { if (instance) { @@ -1298,7 +1340,7 @@ findInterfaceMethodFromInstance(MyThread* t, object method, object instance) } } -intptr_t FORCE_ALIGN +intptr_t compareDoublesG(uint64_t bi, uint64_t ai) { double a = bitsToDouble(ai); @@ -1315,7 +1357,7 @@ compareDoublesG(uint64_t bi, uint64_t ai) } } -intptr_t FORCE_ALIGN +intptr_t compareDoublesL(uint64_t bi, uint64_t ai) { double a = bitsToDouble(ai); @@ -1332,7 +1374,7 @@ compareDoublesL(uint64_t bi, uint64_t ai) } } -intptr_t FORCE_ALIGN +intptr_t compareFloatsG(uint32_t bi, uint32_t ai) { float a = bitsToFloat(ai); @@ -1349,7 +1391,7 @@ compareFloatsG(uint32_t bi, uint32_t ai) } } -intptr_t FORCE_ALIGN +intptr_t compareFloatsL(uint32_t bi, uint32_t ai) { float a = bitsToFloat(ai); @@ -1366,151 +1408,151 @@ compareFloatsL(uint32_t bi, uint32_t ai) } } -uint64_t FORCE_ALIGN +uint64_t addDouble(uint64_t b, uint64_t a) { return doubleToBits(bitsToDouble(a) + bitsToDouble(b)); } -uint64_t FORCE_ALIGN +uint64_t subtractDouble(uint64_t b, uint64_t a) { return doubleToBits(bitsToDouble(a) - bitsToDouble(b)); } -uint64_t FORCE_ALIGN +uint64_t multiplyDouble(uint64_t b, uint64_t a) { return doubleToBits(bitsToDouble(a) * bitsToDouble(b)); } -uint64_t FORCE_ALIGN +uint64_t divideDouble(uint64_t b, uint64_t a) { return doubleToBits(bitsToDouble(a) / bitsToDouble(b)); } -uint64_t FORCE_ALIGN +uint64_t moduloDouble(uint64_t b, uint64_t a) { return doubleToBits(fmod(bitsToDouble(a), bitsToDouble(b))); } -uint64_t FORCE_ALIGN +uint64_t negateDouble(uint64_t a) { return doubleToBits(- bitsToDouble(a)); } -uint32_t FORCE_ALIGN +uint32_t doubleToFloat(int64_t a) { return floatToBits(static_cast(bitsToDouble(a))); } -int32_t FORCE_ALIGN +int32_t doubleToInt(int64_t a) { return static_cast(bitsToDouble(a)); } -int64_t FORCE_ALIGN +int64_t doubleToLong(int64_t a) { return static_cast(bitsToDouble(a)); } -uint32_t FORCE_ALIGN +uint32_t addFloat(uint32_t b, uint32_t a) { return floatToBits(bitsToFloat(a) + bitsToFloat(b)); } -uint32_t FORCE_ALIGN +uint32_t subtractFloat(uint32_t b, uint32_t a) { return floatToBits(bitsToFloat(a) - bitsToFloat(b)); } -uint32_t FORCE_ALIGN +uint32_t multiplyFloat(uint32_t b, uint32_t a) { return floatToBits(bitsToFloat(a) * bitsToFloat(b)); } -uint32_t FORCE_ALIGN +uint32_t divideFloat(uint32_t b, uint32_t a) { return floatToBits(bitsToFloat(a) / bitsToFloat(b)); } -uint32_t FORCE_ALIGN +uint32_t moduloFloat(uint32_t b, uint32_t a) { return floatToBits(fmod(bitsToFloat(a), bitsToFloat(b))); } -uint32_t FORCE_ALIGN +uint32_t negateFloat(uint32_t a) { return floatToBits(- bitsToFloat(a)); } -int64_t FORCE_ALIGN +int64_t divideLong(int64_t b, int64_t a) { return a / b; } -int64_t FORCE_ALIGN +int64_t moduloLong(int64_t b, int64_t a) { return a % b; } -uint64_t FORCE_ALIGN +uint64_t floatToDouble(int32_t a) { return doubleToBits(static_cast(bitsToFloat(a))); } -int32_t FORCE_ALIGN +int32_t floatToInt(int32_t a) { return static_cast(bitsToFloat(a)); } -int64_t FORCE_ALIGN +int64_t floatToLong(int32_t a) { return static_cast(bitsToFloat(a)); } -uint64_t FORCE_ALIGN +uint64_t intToDouble(int32_t a) { return doubleToBits(static_cast(a)); } -uint32_t FORCE_ALIGN +uint32_t intToFloat(int32_t a) { return floatToBits(static_cast(a)); } -uint64_t FORCE_ALIGN +uint64_t longToDouble(int64_t a) { return doubleToBits(static_cast(a)); } -uint32_t FORCE_ALIGN +uint32_t longToFloat(int64_t a) { return floatToBits(static_cast(a)); } -object FORCE_ALIGN +object makeBlankObjectArray(MyThread* t, object class_, int32_t length) { if (length >= 0) { @@ -1522,7 +1564,7 @@ makeBlankObjectArray(MyThread* t, object class_, int32_t length) } } -object FORCE_ALIGN +object makeBlankArray(MyThread* t, unsigned type, int32_t length) { if (length >= 0) { @@ -1571,7 +1613,7 @@ makeBlankArray(MyThread* t, unsigned type, int32_t length) } } -uintptr_t FORCE_ALIGN +uintptr_t lookUpAddress(int32_t key, uintptr_t* start, int32_t count, uintptr_t default_) { @@ -1594,7 +1636,7 @@ lookUpAddress(int32_t key, uintptr_t* start, int32_t count, return default_; } -void FORCE_ALIGN +void setMaybeNull(MyThread* t, object o, unsigned offset, object value) { if (LIKELY(o)) { @@ -1605,7 +1647,7 @@ setMaybeNull(MyThread* t, object o, unsigned offset, object value) } } -void FORCE_ALIGN +void acquireMonitorForObject(MyThread* t, object o) { if (LIKELY(o)) { @@ -1616,7 +1658,7 @@ acquireMonitorForObject(MyThread* t, object o) } } -void FORCE_ALIGN +void releaseMonitorForObject(MyThread* t, object o) { if (LIKELY(o)) { @@ -1628,14 +1670,14 @@ releaseMonitorForObject(MyThread* t, object o) } object -makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* stack, +makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* countStack, int32_t dimensions) { PROTECT(t, class_); int32_t counts[dimensions]; for (int i = dimensions - 1; i >= 0; --i) { - counts[i] = stack[dimensions - i - 1]; + counts[i] = countStack[dimensions - i - 1]; if (UNLIKELY(counts[i] < 0)) { object message = makeString(t, "%d", counts[i]); t->exception = makeNegativeArraySizeException(t, message); @@ -1652,11 +1694,13 @@ makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* stack, return array; } -object FORCE_ALIGN +object makeMultidimensionalArray(MyThread* t, object class_, int32_t dimensions, - uintptr_t* stack) + int32_t offset) { - object r = makeMultidimensionalArray2(t, class_, stack, dimensions); + object r = makeMultidimensionalArray2 + (t, class_, static_cast(t->stack) + offset, dimensions); + if (UNLIKELY(t->exception)) { unwind(t); } else { @@ -1685,7 +1729,7 @@ traceSize(Thread* t) + (counter.count * FixedSizeOfTraceElement); } -void NO_RETURN FORCE_ALIGN +void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t) { ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t)); @@ -1697,7 +1741,7 @@ throwArrayIndexOutOfBounds(MyThread* t) unwind(t); } -void NO_RETURN FORCE_ALIGN +void NO_RETURN throw_(MyThread* t, object o) { if (LIKELY(o)) { @@ -1708,7 +1752,7 @@ throw_(MyThread* t, object o) unwind(t); } -void FORCE_ALIGN +void checkCast(MyThread* t, object class_, object o) { if (UNLIKELY(o and not isAssignableFrom(t, class_, objectClass(t, o)))) { @@ -1721,7 +1765,7 @@ checkCast(MyThread* t, object class_, object o) } } -void FORCE_ALIGN +void gcIfNecessary(MyThread* t) { if (UNLIKELY(t->backupHeap)) { @@ -1814,39 +1858,39 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target) object traceTarget = (methodFlags(t, target) & ACC_NATIVE) ? target : 0; - result = c->call + result = c->stackCall (c->promiseConstant(p), 0, frame->trace(traceTarget, false), rSize, - 0); + methodParameterFootprint(t, target)); } else { - result = c->call + result = c->stackCall (c->constant(defaultThunk(t)), Compiler::Aligned, frame->trace(target, false), rSize, - 0); + methodParameterFootprint(t, target)); } } else if (methodAddress(t, target) == defaultThunk(t) or classNeedsInit(t, methodClass(t, target))) { - result = c->call + result = c->stackCall (c->constant(defaultThunk(t)), Compiler::Aligned, frame->trace(target, false), rSize, - 0); + methodParameterFootprint(t, target)); } else { object traceTarget = (methodFlags(t, target) & ACC_NATIVE) ? target : 0; - result = c->call + result = c->stackCall (c->constant(methodAddress(t, target)), 0, frame->trace(traceTarget, false), rSize, - 0); + methodParameterFootprint(t, target)); } } @@ -1868,8 +1912,7 @@ handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) if (methodFlags(t, method) & ACC_STATIC) { lock = frame->append(methodClass(t, method)); } else { - lock = c->memory - (c->base(), localOffset(t, savedTargetIndex(t, method), method)); + lock = c->loadLocal(1, savedTargetIndex(t, method)); } c->call(c->constant(function), @@ -1892,9 +1935,7 @@ handleEntrance(MyThread* t, Frame* frame) // save 'this' pointer in case it is overwritten. unsigned index = savedTargetIndex(t, method); - c->store(BytesPerWord, - c->memory(c->base(), localOffset(t, 0, method)), - c->memory(c->base(), localOffset(t, index, method))); + c->storeLocal(1, c->loadLocal(1, 0), index); frame->set(index, Frame::Object); } @@ -1970,9 +2011,39 @@ exceptionIndex(MyThread* t, object code, unsigned jsrIp, unsigned dstIp) abort(t); } +bool +inTryBlock(MyThread* t, object code, unsigned ip) +{ + object table = codeExceptionHandlerTable(t, code); + if (table) { + unsigned length = exceptionHandlerTableLength(t, table); + for (unsigned i = 0; i < length; ++i) { + ExceptionHandler* eh = exceptionHandlerTableBody(t, table, i); + if (ip >= exceptionHandlerStart(eh) + and ip < exceptionHandlerEnd(eh)) + { + return true; + } + } + } + return false; +} + void compile(MyThread* t, Frame* initialFrame, unsigned ip, - bool exceptionHandler = false) + int exceptionHandlerStart = -1); + +void +saveStateAndCompile(MyThread* t, Frame* initialFrame, unsigned ip) +{ + Compiler::State* state = initialFrame->c->saveState(); + compile(t, initialFrame, ip); + initialFrame->c->restoreState(state); +} + +void +compile(MyThread* t, Frame* initialFrame, unsigned ip, + int exceptionHandlerStart) { uint8_t stackMap [codeMaxStack(t, methodCode(t, initialFrame->context->method))]; @@ -1993,10 +2064,10 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, frame->startLogicalIp(ip); - if (ip == 0) { - handleEntrance(t, frame); - } else if (exceptionHandler) { - exceptionHandler = false; + if (exceptionHandlerStart >= 0) { + c->initLocalsFromLogicalIp(exceptionHandlerStart); + + exceptionHandlerStart = -1; frame->pushObject(); @@ -2024,6 +2095,10 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* index = frame->popInt(); Compiler::Operand* array = frame->popObject(); + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + } + if (CheckArrayBounds) { c->checkBounds(array, ArrayLength, index, aioobThunk(t)); } @@ -2032,29 +2107,35 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case aaload: frame->pushObject (c->load - (BytesPerWord, c->memory(array, ArrayBody, index, BytesPerWord))); + (BytesPerWord, BytesPerWord, + c->memory(array, ArrayBody, index, BytesPerWord))); break; case faload: case iaload: - frame->pushInt(c->load(4, c->memory(array, ArrayBody, index, 4))); + frame->pushInt + (c->load(4, BytesPerWord, c->memory(array, ArrayBody, index, 4))); break; case baload: - frame->pushInt(c->load(1, c->memory(array, ArrayBody, index, 1))); + frame->pushInt + (c->load(1, BytesPerWord, c->memory(array, ArrayBody, index, 1))); break; case caload: - frame->pushInt(c->loadz(2, c->memory(array, ArrayBody, index, 2))); + frame->pushInt + (c->loadz(2, BytesPerWord, c->memory(array, ArrayBody, index, 2))); break; case daload: case laload: - frame->pushLong(c->load(8, c->memory(array, ArrayBody, index, 8))); + frame->pushLong + (c->load(8, 8, c->memory(array, ArrayBody, index, 8))); break; case saload: - frame->pushInt(c->load(2, c->memory(array, ArrayBody, index, 2))); + frame->pushInt + (c->load(2, BytesPerWord, c->memory(array, ArrayBody, index, 2))); break; } } break; @@ -2079,6 +2160,10 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* index = frame->popInt(); Compiler::Operand* array = frame->popObject(); + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + } + if (CheckArrayBounds) { c->checkBounds(array, ArrayLength, index, aioobThunk(t)); } @@ -2166,7 +2251,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case arraylength: { frame->pushInt (c->load - (BytesPerWord, c->memory(frame->popObject(), ArrayLength, 0, 1))); + (BytesPerWord, BytesPerWord, + c->memory(frame->popObject(), ArrayLength, 0, 1))); } break; case astore: @@ -2209,7 +2295,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object class_ = resolveClassInPool(t, codePool(t, code), index - 1); if (UNLIKELY(t->exception)) return; - Compiler::Operand* instance = c->peek(BytesPerWord, 0); + Compiler::Operand* instance = c->peek(1, 0); c->call (c->constant(getThunk(t, checkCastThunk)), @@ -2506,41 +2592,50 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); table = frame->popObject(); + + if (inTryBlock(t, code, ip - 3)) { + c->saveLocals(); + } } switch (fieldCode(t, field)) { case ByteField: case BooleanField: frame->pushInt - (c->load(1, c->memory(table, fieldOffset(t, field), 0, 1))); + (c->load + (1, BytesPerWord, c->memory(table, fieldOffset(t, field), 0, 1))); break; case CharField: frame->pushInt - (c->loadz(2, c->memory(table, fieldOffset(t, field), 0, 1))); + (c->loadz + (2, BytesPerWord, c->memory(table, fieldOffset(t, field), 0, 1))); break; case ShortField: frame->pushInt - (c->load(2, c->memory(table, fieldOffset(t, field), 0, 1))); + (c->load + (2, BytesPerWord, c->memory(table, fieldOffset(t, field), 0, 1))); break; case FloatField: case IntField: frame->pushInt - (c->load(4, c->memory(table, fieldOffset(t, field), 0, 1))); + (c->load + (4, BytesPerWord, c->memory(table, fieldOffset(t, field), 0, 1))); break; case DoubleField: case LongField: frame->pushLong - (c->load(8, c->memory(table, fieldOffset(t, field), 0, 1))); + (c->load(8, 8, c->memory(table, fieldOffset(t, field), 0, 1))); break; case ObjectField: frame->pushObject (c->load - (BytesPerWord, c->memory(table, fieldOffset(t, field), 0, 1))); + (BytesPerWord, BytesPerWord, + c->memory(table, fieldOffset(t, field), 0, 1))); break; default: @@ -2567,11 +2662,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case i2b: { - frame->pushInt(c->load(1, frame->popInt())); + frame->pushInt(c->load(1, BytesPerWord, frame->popInt())); } break; case i2c: { - frame->pushInt(c->loadz(2, frame->popInt())); + frame->pushInt(c->loadz(2, BytesPerWord, frame->popInt())); } break; case i2d: { @@ -2589,11 +2684,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case i2l: - frame->pushLong(c->load4To8(frame->popInt())); + frame->pushLong(c->load(4, 8, frame->popInt())); break; case i2s: { - frame->pushInt(c->load(2, frame->popInt())); + frame->pushInt(c->load(2, BytesPerWord, frame->popInt())); } break; case iadd: { @@ -2658,8 +2753,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } else { c->jne(target); } - - compile(t, frame, newIp); + + saveStateAndCompile(t, frame, newIp); if (UNLIKELY(t->exception)) return; } break; @@ -2699,7 +2794,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, break; } - compile(t, frame, newIp); + saveStateAndCompile(t, frame, newIp); if (UNLIKELY(t->exception)) return; } break; @@ -2738,7 +2833,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, break; } - compile(t, frame, newIp); + saveStateAndCompile(t, frame, newIp); if (UNLIKELY(t->exception)) return; } break; @@ -2757,8 +2852,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } else { c->jne(target); } - - compile(t, frame, newIp); + + saveStateAndCompile(t, frame, newIp); if (UNLIKELY(t->exception)) return; } break; @@ -2766,10 +2861,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint8_t index = codeBody(t, code, ip++); int8_t count = codeBody(t, code, ip++); - Compiler::Operand* a = c->memory - (c->base(), localOffset(t, index, context->method)); - - c->storeLocal(4, c->add(4, c->constant(count), a), index); + c->storeLocal + (1, c->add(4, c->constant(count), c->loadLocal(1, index)), index); } break; case iload: @@ -2835,7 +2928,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, unsigned rSize = resultSize(t, methodReturnCode(t, target)); - Compiler::Operand* result = c->call + Compiler::Operand* result = c->stackCall (c->call (c->constant (getThunk(t, findInterfaceMethodFromInstanceThunk)), @@ -2843,11 +2936,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, frame->trace(0, false), BytesPerWord, 3, c->thread(), frame->append(target), - c->peek(BytesPerWord, instance)), + c->peek(1, instance)), 0, frame->trace(target, true), rSize, - 0); + parameterFootprint); frame->pop(parameterFootprint); @@ -2895,12 +2988,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, unsigned offset = ClassVtable + (methodOffset(t, target) * BytesPerWord); - Compiler::Operand* instance = c->peek - (BytesPerWord, parameterFootprint - 1); + Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); unsigned rSize = resultSize(t, methodReturnCode(t, target)); - Compiler::Operand* result = c->call + Compiler::Operand* result = c->stackCall (c->memory (c->and_ (BytesPerWord, c->constant(PointerMask), @@ -2908,7 +3000,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(target, true), rSize, - 0); + parameterFootprint); frame->pop(parameterFootprint); @@ -3015,21 +3107,22 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, // wasn't already a live value there, which is something we // should verify once we have complete data flow information // (todo). - c->storeLocal(BytesPerWord, c->constant(0), index); + c->storeLocal(1, c->constant(0), index); frame->storedObject(index); } - c->saveStack(); - frame->pushAddress(frame->addressOperand(c->machineIp(ip))); + c->jmp(frame->machineIp(newIp)); - // NB: we assume that the stack will look the same on return - // from the subroutine as at call time. + frame->subroutine = c->startSubroutine(); + compile(t, frame, newIp); if (UNLIKELY(t->exception)) return; - frame->pop(1, false); + frame->poppedInt(); + + c->restoreFromSubroutine(frame->subroutine); } break; case l2d: { @@ -3049,7 +3142,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case l2i: - frame->pushInt(c->load(4, frame->popLong())); + frame->pushInt(c->load(8, BytesPerWord, frame->popLong())); break; case ladd: { @@ -3068,7 +3161,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); - frame->pushInt(c->load(4, c->lcmp(a, b))); + frame->pushInt(c->lcmp(a, b)); } break; case lconst_0: @@ -3198,9 +3291,13 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, 0, BytesPerWord, 4, key, start, c->constant(pairCount), default_)); + Compiler::State* state = c->saveState(); + for (int32_t i = 0; i < pairCount; ++i) { compile(t, frame, ipTable[i]); if (UNLIKELY(t->exception)) return; + + c->restoreState(state); } ip = defaultIp; @@ -3301,13 +3398,21 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (UNLIKELY(t->exception)) return; PROTECT(t, class_); + unsigned offset = alignedFrameSize(t, context->method) + - t->arch->frameHeaderSize() + - (localSize(t, context->method) + - methodParameterFootprint(t, context->method) + - 1) + + t->arch->frameReturnAddressSize() + - c->index(c->top()); + Compiler::Operand* result = c->call (c->constant(getThunk(t, makeMultidimensionalArrayThunk)), 0, frame->trace(0, false), BytesPerWord, 4, c->thread(), frame->append(class_), c->constant(dimensions), - c->stack()); + c->constant(offset)); frame->pop(dimensions); frame->pushObject(result); @@ -3389,6 +3494,10 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, staticTable = classStaticTable(t, fieldClass(t, field)); } else { assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); + + if (inTryBlock(t, code, ip - 3)) { + c->saveLocals(); + } } Compiler::Operand* value; @@ -3464,10 +3573,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case ret: - c->jmp - (c->memory - (c->base(), localOffset - (t, codeBody(t, code, ip), context->method))); + c->jmp(c->loadLocal(1, codeBody(t, code, ip))); + c->endSubroutine(frame->subroutine); return; case return_: @@ -3512,25 +3619,33 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } assert(t, start); - Compiler::Operand* defaultCase = c->label(); - Compiler::Operand* key = frame->popInt(); c->cmp(4, c->constant(bottom), key); - c->jl(defaultCase); + c->jl(frame->machineIp(defaultIp)); + + c->save(1, key); + + saveStateAndCompile(t, frame, defaultIp); c->cmp(4, c->constant(top), key); - c->jg(defaultCase); + c->jg(frame->machineIp(defaultIp)); - c->jmp(c->memory(start, 0, c->sub(4, c->constant(bottom), key), - BytesPerWord)); + c->save(1, key); - c->mark(defaultCase); - c->jmp(frame->machineIp(defaultIp)); + saveStateAndCompile(t, frame, defaultIp); + + c->jmp(c->load(BytesPerWord, BytesPerWord, + c->memory(start, 0, c->sub(4, c->constant(bottom), key), + BytesPerWord))); + + Compiler::State* state = c->saveState(); for (int32_t i = 0; i < top - bottom + 1; ++i) { compile(t, frame, ipTable[i]); if (UNLIKELY(t->exception)) return; + + c->restoreState(state); } ip = defaultIp; @@ -3550,10 +3665,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); uint16_t count = codeReadInt16(t, code, ip); - Compiler::Operand* a = c->memory - (c->base(), localOffset(t, index, context->method)); - - c->storeLocal(4, c->add(4, c->constant(count), a), index); + c->storeLocal + (1, c->add(4, c->constant(count), c->loadLocal(1, index)), index); } break; case iload: { @@ -3573,10 +3686,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case ret: - c->jmp - (c->memory - (c->base(), localOffset - (t, codeReadInt16(t, code, ip), context->method))); + c->jmp(c->loadLocal(1, codeReadInt16(t, code, ip))); + c->endSubroutine(frame->subroutine); return; default: abort(t); @@ -3684,20 +3795,22 @@ translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) } void -printSet(uintptr_t m) +printSet(uintptr_t m, unsigned limit) { - for (unsigned i = 0; i < 16; ++i) { - if ((m >> i) & 1) { - fprintf(stderr, "1"); - } else { - fprintf(stderr, "_"); + if (limit) { + for (unsigned i = 0; i < 16; ++i) { + if ((m >> i) & 1) { + fprintf(stderr, "1"); + } else { + fprintf(stderr, "_"); + } } } } unsigned calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, - unsigned eventIndex) + unsigned stackPadding, unsigned eventIndex) { // for each instruction with more than one predecessor, and for each // stack position, determine if there exists a path to that @@ -3705,6 +3818,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, // stack position (i.e. it is uninitialized or contains primitive // data). + unsigned localSize = ::localSize(t, context->method); unsigned mapSize = frameMapSizeInWords(t, context->method); uintptr_t roots[mapSize]; @@ -3728,11 +3842,12 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, while (eventIndex < length) { Event e = static_cast(context->eventLog.get(eventIndex++)); switch (e) { - case PushEvent: { - eventIndex = calculateFrameMaps(t, context, roots, eventIndex); + case PushContextEvent: { + eventIndex = calculateFrameMaps + (t, context, roots, stackPadding, eventIndex); } break; - case PopEvent: + case PopContextEvent: return eventIndex; case IpEvent: { @@ -3741,7 +3856,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, if (DebugFrameMaps) { fprintf(stderr, " roots at ip %3d: ", ip); - printSet(*roots); + printSet(*roots, mapSize); fprintf(stderr, "\n"); } @@ -3752,7 +3867,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, uintptr_t newRoots = tableRoots[wi] & roots[wi]; if ((eventIndex == length - or context->eventLog.get(eventIndex) == PopEvent) + or context->eventLog.get(eventIndex) == PopContextEvent) and newRoots != tableRoots[wi]) { if (DebugFrameMaps) { @@ -3768,7 +3883,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, if (DebugFrameMaps) { fprintf(stderr, "table roots at ip %3d: ", ip); - printSet(*tableRoots); + printSet(*tableRoots, mapSize); fprintf(stderr, "\n"); } } else { @@ -3780,6 +3895,10 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, unsigned i = context->eventLog.get2(eventIndex); eventIndex += 2; + if (i >= localSize) { + i += stackPadding; + } + markBit(roots, i); } break; @@ -3787,11 +3906,20 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, unsigned i = context->eventLog.get2(eventIndex); eventIndex += 2; + if (i >= localSize) { + i += stackPadding; + } + clearBit(roots, i); } break; case TraceEvent: { TraceElement* te; context->eventLog.get(eventIndex, &te, BytesPerWord); + if (DebugFrameMaps) { + fprintf(stderr, "trace roots at ip %3d: ", ip); + printSet(*roots, mapSize); + fprintf(stderr, "\n"); + } memcpy(te->map, roots, mapSize * BytesPerWord); eventIndex += BytesPerWord; @@ -3824,7 +3952,7 @@ compareTraceElementPointers(const void* va, const void* vb) unsigned frameObjectMapSize(MyThread* t, object method, object map) { - int size = frameSize(t, method); + int size = alignedFrameSizeWithParameters(t, method); return ceiling(intArrayLength(t, map) * size, 32 + size); } @@ -3849,6 +3977,24 @@ finish(MyThread* t, Allocator* allocator, Assembler* a, const char* name) return start; } +void +setBit(MyThread* t, object map, unsigned count, unsigned size, unsigned i, + unsigned j) +{ + unsigned index = ((i * size) + j); + intArrayBody(t, map, count + (index / 32)) + |= static_cast(1) << (index % 32); +} + +void +clearBit(MyThread* t, object map, unsigned count, unsigned size, unsigned i, + unsigned j) +{ + unsigned index = ((i * size) + j); + intArrayBody(t, map, count + (index / 32)) + &= ~(static_cast(1) << (index % 32)); +} + uint8_t* finish(MyThread* t, Allocator* allocator, Context* context) { @@ -3932,7 +4078,7 @@ finish(MyThread* t, Allocator* allocator, Context* context) qsort(elements, context->traceLogCount, sizeof(TraceElement*), compareTraceElementPointers); - unsigned size = frameSize(t, context->method); + unsigned size = alignedFrameSizeWithParameters(t, context->method); object map = makeIntArray (t, context->traceLogCount + ceiling(context->traceLogCount * size, 32), @@ -3947,16 +4093,46 @@ finish(MyThread* t, Allocator* allocator, Context* context) intArrayBody(t, map, i) = static_cast(p->address->value()) - reinterpret_cast(start); - for (unsigned j = 0; j < size; ++j) { - unsigned index = ((i * size) + j); - int32_t* v = &intArrayBody - (t, map, context->traceLogCount + (index / 32)); + if (DebugFrameMaps) { + fprintf(stderr, " orig roots at ip %p: ", reinterpret_cast + (p->address->value())); + printSet(p->map[0], frameMapSizeInWords(t, context->method)); + fprintf(stderr, "\n"); - if (getBit(p->map, j)) { - *v |= static_cast(1) << (index % 32); - } else { - *v &= ~(static_cast(1) << (index % 32)); + fprintf(stderr, "final roots at ip %p: ", reinterpret_cast + (p->address->value())); + } + + for (unsigned j = 0, k = 0; j < size; ++j, ++k) { + if (j == p->padIndex) { + unsigned limit = j + p->padding; + assert(t, limit <= size); + + for (; j < limit; ++j) { + if (DebugFrameMaps) { + fprintf(stderr, "_"); + } + clearBit(t, map, context->traceLogCount, size, i, j); + } + + if (j == size) break; } + + if (getBit(p->map, k)) { + if (DebugFrameMaps) { + fprintf(stderr, "1"); + } + setBit(t, map, context->traceLogCount, size, i, j); + } else { + if (DebugFrameMaps) { + fprintf(stderr, "_"); + } + clearBit(t, map, context->traceLogCount, size, i, j); + } + } + + if (DebugFrameMaps) { + fprintf(stderr, "\n"); } } @@ -3977,11 +4153,11 @@ finish(MyThread* t, Allocator* allocator, Context* context) strcmp (reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)), - "java/lang/String") == 0 and + "Arrays") == 0 and strcmp (reinterpret_cast (&byteArrayBody(t, methodName(t, context->method), 0)), - "compareTo") == 0) + "main") == 0) { asm("int3"); } @@ -4001,13 +4177,15 @@ compile(MyThread* t, Allocator* allocator, Context* context) unsigned footprint = methodParameterFootprint(t, context->method); unsigned locals = localSize(t, context->method); - c->init(codeLength(t, methodCode(t, context->method)), footprint, locals); + c->init(codeLength(t, methodCode(t, context->method)), footprint, locals, + alignedFrameSize(t, context->method)); uint8_t stackMap[codeMaxStack(t, methodCode(t, context->method))]; Frame frame(context, stackMap); unsigned index = 0; if ((methodFlags(t, context->method) & ACC_STATIC) == 0) { + c->initLocal(1, index); frame.set(index++, Frame::Object); } @@ -4019,26 +4197,33 @@ compile(MyThread* t, Allocator* allocator, Context* context) switch (*it.next()) { case 'L': case '[': + c->initLocal(1, index); frame.set(index++, Frame::Object); break; case 'J': case 'D': + c->initLocal(2, index); frame.set(index++, Frame::Long); frame.set(index++, Frame::Long); break; default: + c->initLocal(1, index); frame.set(index++, Frame::Integer); break; } } + handleEntrance(t, &frame); + + Compiler::State* state = c->saveState(); + compile(t, &frame, 0); if (UNLIKELY(t->exception)) return 0; context->dirtyRoots = false; - unsigned eventIndex = calculateFrameMaps(t, context, 0, 0); + unsigned eventIndex = calculateFrameMaps(t, context, 0, 0, 0); object eht = codeExceptionHandlerTable(t, methodCode(t, context->method)); if (eht) { @@ -4052,6 +4237,8 @@ compile(MyThread* t, Allocator* allocator, Context* context) bool progress = false; for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) { + c->restoreState(state); + ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i); unsigned start = exceptionHandlerStart(eh); @@ -4081,10 +4268,10 @@ compile(MyThread* t, Allocator* allocator, Context* context) frame2.set(localSize(t, context->method) + i, Frame::Integer); } - compile(t, &frame2, exceptionHandlerIp(eh), true); + compile(t, &frame2, exceptionHandlerIp(eh), start); if (UNLIKELY(t->exception)) return 0; - eventIndex = calculateFrameMaps(t, context, 0, eventIndex); + eventIndex = calculateFrameMaps(t, context, 0, 0, eventIndex); } } @@ -4094,7 +4281,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) while (context->dirtyRoots) { context->dirtyRoots = false; - calculateFrameMaps(t, context, 0, 0); + calculateFrameMaps(t, context, 0, 0, 0); } return finish(t, allocator, context); @@ -4104,8 +4291,7 @@ void updateCall(MyThread* t, UnaryOperation op, bool assertAlignment, void* returnAddress, void* target) { - Context context(t); - context.assembler->updateCall(op, assertAlignment, returnAddress, target); + t->arch->updateCall(op, assertAlignment, returnAddress, target); } void @@ -4115,7 +4301,7 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, void* compileMethod2(MyThread* t) { - object node = findCallNode(t, *static_cast(t->stack)); + object node = findCallNode(t, t->arch->frameIp(t->stack)); PROTECT(t, node); object target = callNodeTarget(t, node); @@ -4147,7 +4333,7 @@ compileMethod2(MyThread* t) } } -void* FORCE_ALIGN +void* compileMethod(MyThread* t) { void* r = compileMethod2(t); @@ -4202,7 +4388,7 @@ invokeNative2(MyThread* t, object method) types[typeOffset++] = POINTER_TYPE; uintptr_t* sp = static_cast(t->stack) - + methodParameterFootprint(t, method); + + methodParameterFootprint(t, method) + t->arch->frameFooterSize(); if (methodFlags(t, method) & ACC_STATIC) { args[argOffset++] = reinterpret_cast(&class_); @@ -4340,11 +4526,11 @@ invokeNative2(MyThread* t, object method) return result; } -uint64_t FORCE_ALIGN +uint64_t invokeNative(MyThread* t) { if (t->trace->nativeMethod == 0) { - object node = findCallNode(t, *static_cast(t->stack)); + object node = findCallNode(t, t->arch->frameIp(t->stack)); object target = callNodeTarget(t, node); if (callNodeVirtualCall(t, node)) { target = resolveTarget(t, t->stack, target); @@ -4381,7 +4567,8 @@ frameMapIndex(MyThread* t, object method, int32_t offset) int32_t v = intArrayBody(t, map, middle); if (offset == v) { - return (indexSize * 32) + (frameSize(t, method) * middle); + return (indexSize * 32) + + (alignedFrameSizeWithParameters(t, method) * middle); } else if (offset < v) { top = middle; } else { @@ -4393,18 +4580,14 @@ frameMapIndex(MyThread* t, object method, int32_t offset) } void -visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* base, object method, - void* ip, void* calleeBase, unsigned argumentFootprint) +visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* stack, object method, + void* ip, void* calleeStack, unsigned argumentFootprint) { unsigned count; - if (calleeBase) { - unsigned parameterFootprint = methodParameterFootprint(t, method); - unsigned height = static_cast(base) - - static_cast(calleeBase) - 2; - - count = parameterFootprint + height - argumentFootprint; + if (calleeStack) { + count = alignedFrameSizeWithParameters(t, method) - argumentFootprint; } else { - count = frameSize(t, method); + count = alignedFrameSizeWithParameters(t, method); } if (count) { @@ -4418,7 +4601,7 @@ visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* base, object method, if ((intArrayBody(t, map, j / 32) & (static_cast(1) << (j % 32)))) { - v->visit(localObject(t, base, method, i)); + v->visit(localObject(t, stack, method, i)); } } } @@ -4429,13 +4612,13 @@ visitStack(MyThread* t, Heap::Visitor* v) { void* ip = t->ip; void* base = t->base; - void** stack = static_cast(t->stack); - if (ip == 0 and stack) { - ip = *stack; + void* stack = t->stack; + if (ip == 0) { + ip = t->arch->frameIp(stack); } MyThread::CallTrace* trace = t->trace; - void* calleeBase = 0; + void* calleeStack = 0; unsigned argumentFootprint = 0; while (stack) { @@ -4444,24 +4627,19 @@ visitStack(MyThread* t, Heap::Visitor* v) PROTECT(t, method); visitStackAndLocals - (t, v, base, method, ip, calleeBase, argumentFootprint); + (t, v, stack, method, ip, calleeStack, argumentFootprint); - calleeBase = base; + calleeStack = stack; argumentFootprint = methodParameterFootprint(t, method); - stack = static_cast(base) + 1; - if (stack) { - ip = *stack; - } - base = *static_cast(base); + t->arch->nextFrame(&stack, &base); + ip = t->arch->frameIp(stack); } else if (trace) { - calleeBase = 0; + calleeStack = 0; argumentFootprint = 0; + stack = trace->stack; base = trace->base; - stack = static_cast(trace->stack); - if (stack) { - ip = *stack; - } + ip = t->arch->frameIp(stack); trace = trace->next; } else { break; @@ -4469,46 +4647,6 @@ visitStack(MyThread* t, Heap::Visitor* v) } } -void -saveStackAndBase(MyThread* t, Assembler* a) -{ - Assembler::Register base(a->base()); - Assembler::Memory baseDst(a->thread(), difference(&(t->base), t)); - a->apply(Move, BytesPerWord, RegisterOperand, &base, - MemoryOperand, &baseDst); - - Assembler::Register stack(a->stack()); - Assembler::Memory stackDst(a->thread(), difference(&(t->stack), t)); - a->apply(Move, BytesPerWord, RegisterOperand, &stack, - MemoryOperand, &stackDst); -} - -void -pushThread(MyThread*, Assembler* a) -{ - Assembler::Register thread(a->thread()); - - if (a->argumentRegisterCount()) { - Assembler::Register arg(a->argumentRegister(0)); - a->apply(Move, BytesPerWord, RegisterOperand, &thread, - RegisterOperand, &arg); - } else { - a->apply(Push, BytesPerWord, RegisterOperand, &thread); - } -} - -void -popThread(MyThread*, Assembler* a) -{ - if (a->argumentRegisterCount() == 0) { - ResolvedPromise bpwPromise(BytesPerWord); - Assembler::Constant bpw(&bpwPromise); - Assembler::Register stack(a->stack()); - a->apply(Add, BytesPerWord, ConstantOperand, &bpw, - RegisterOperand, &stack); - } -} - class ArgumentList { public: ArgumentList(Thread* t, uintptr_t* array, bool* objectMask, object this_, @@ -4704,7 +4842,8 @@ class SegFaultHandler: public System::SignalHandler { t->ip = *ip; t->base = *base; - t->stack = *stack; + t->stack = static_cast(*stack) + - t->arch->frameReturnAddressSize(); ensure(t, FixedSizeOfNullPointerException + traceSize(t)); @@ -4783,7 +4922,7 @@ class MyProcessor: public Processor { makeThread(Machine* m, object javaThread, Thread* parent) { MyThread* t = new (m->heap->allocate(sizeof(MyThread))) - MyThread(m, javaThread, parent); + MyThread(m, javaThread, static_cast(parent)); t->init(); return t; } @@ -5019,6 +5158,8 @@ class MyProcessor: public Processor { vm::dispose(t, t->reference); } + t->arch->release(); + t->m->heap->free(t, sizeof(*t)); } @@ -5057,7 +5198,7 @@ class MyProcessor: public Processor { if (static_cast(ip) >= thunkStart and static_cast(ip) < thunkEnd) { - target->ip = *static_cast(stack); + target->ip = t->arch->frameIp(stack); target->base = base; target->stack = stack; } @@ -5546,52 +5687,67 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p, ThunkContext defaultContext(t, &zone); { Assembler* a = defaultContext.context.assembler; - - saveStackAndBase(t, a); - pushThread(t, a); + + a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + + Assembler::Register thread(t->arch->thread()); + a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); Assembler::Constant proc(&(defaultContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - popThread(t, a); + a->popFrame(); - Assembler::Register result(a->returnLow()); + Assembler::Register result(t->arch->returnLow()); a->apply(Jump, BytesPerWord, RegisterOperand, &result); + + a->endBlock(false)->resolve(0, 0); } ThunkContext nativeContext(t, &zone); { Assembler* a = nativeContext.context.assembler; - saveStackAndBase(t, a); - pushThread(t, a); + a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + + Assembler::Register thread(t->arch->thread()); + a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); + Assembler::Constant proc(&(nativeContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - popThread(t, a); + a->popFrame(); a->apply(Return); + + a->endBlock(false)->resolve(0, 0); } ThunkContext aioobContext(t, &zone); { Assembler* a = aioobContext.context.assembler; - saveStackAndBase(t, a); - pushThread(t, a); + a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + + Assembler::Register thread(t->arch->thread()); + a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); Assembler::Constant proc(&(aioobContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); + + a->endBlock(false)->resolve(0, 0); } ThunkContext tableContext(t, &zone); { Assembler* a = tableContext.context.assembler; - saveStackAndBase(t, a); + a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); Assembler::Constant proc(&(tableContext.promise)); a->apply(LongJump, BytesPerWord, ConstantOperand, &proc); + + a->endBlock(false)->resolve(0, 0); } p->thunkSize = pad(tableContext.context.assembler->length()); diff --git a/src/compiler.cpp b/src/compiler.cpp index 7e80a91d2e..a9c2443569 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -17,25 +17,52 @@ namespace { const bool DebugAppend = false; const bool DebugCompile = false; -const bool DebugStack = false; -const bool DebugRegisters = false; +const bool DebugResources = false; +const bool DebugFrame = false; +const bool DebugControl = false; +const bool DebugReads = false; +const bool DebugSites = false; +const bool DebugMoves = false; +const bool DebugBuddies = false; + +const int AnyFrameIndex = -2; +const int NoFrameIndex = -1; + +const unsigned StealRegisterReserveCount = 1; +const unsigned ResolveRegisterReserveCount = 2; class Context; class Value; class Stack; class Site; +class ConstantSite; +class AddressSite; class RegisterSite; +class MemorySite; class Event; class PushEvent; class Read; +class MultiRead; +class StubRead; +class Block; +class Snapshot; void NO_RETURN abort(Context*); void -apply(Context* c, UnaryOperation op, unsigned size, Site* a); +apply(Context* c, UnaryOperation op, + unsigned s1Size, Site* s1Low, Site* s1High); void -apply(Context* c, BinaryOperation op, unsigned size, Site* a, Site* b); +apply(Context* c, BinaryOperation op, + unsigned s1Size, Site* s1Low, Site* s1High, + unsigned s2Size, Site* s2Low, Site* s2High); + +void +apply(Context* c, TernaryOperation op, + unsigned s1Size, Site* s1Low, Site* s1High, + unsigned s2Size, Site* s2Low, Site* s2High, + unsigned s3Size, Site* s3Low, Site* s3High); enum ConstantCompare { CompareNone, @@ -44,99 +71,175 @@ enum ConstantCompare { CompareEqual }; +class Cell { + public: + Cell(Cell* next, void* value): next(next), value(value) { } + + Cell* next; + void* value; +}; + +class Local { + public: + Value* value; +}; + +class SiteMask { + public: + SiteMask(): typeMask(~0), registerMask(~0), frameIndex(AnyFrameIndex) { } + + SiteMask(uint8_t typeMask, uint32_t registerMask, int frameIndex): + typeMask(typeMask), registerMask(registerMask), frameIndex(frameIndex) + { } + + uint8_t typeMask; + uint32_t registerMask; + int frameIndex; +}; + class Site { public: Site(): next(0) { } virtual Site* readTarget(Context*, Read*) { return this; } + virtual unsigned toString(Context*, char*, unsigned) = 0; + virtual unsigned copyCost(Context*, Site*) = 0; + + virtual bool match(Context*, const SiteMask&) = 0; - virtual void acquire(Context*, Stack*, unsigned, Value*) { } + virtual void acquire(Context*, Value*) { } - virtual void release(Context*) { } + virtual void release(Context*, Value*) { } - virtual void freeze(Context*) { } + virtual void freeze(Context*, Value*) { } - virtual void thaw(Context*) { } + virtual void thaw(Context*, Value*) { } + + virtual bool frozen(Context*) { return false; } virtual OperandType type(Context*) = 0; - virtual Assembler::Operand* asAssemblerOperand(Context*) = 0; + virtual void asAssemblerOperand(Context*, Site*, Assembler::Operand*) = 0; + + virtual Site* copy(Context*) = 0; + + virtual Site* copyLow(Context*) = 0; + + virtual Site* copyHigh(Context*) = 0; Site* next; }; -class Stack { +class SitePair { public: - Stack(Value* value, unsigned size, unsigned index, Stack* next): - value(value), size(size), index(index), next(next), pushEvent(0), - pushSite(0), pushed(false) - { } - - Value* value; - unsigned size; - unsigned index; - Stack* next; - PushEvent* pushEvent; - Site* pushSite; - bool pushed; + Site* low; + Site* high; }; -class State { +class Stack: public Compiler::StackElement { public: - State(State* next, Stack* stack): + Stack(unsigned index, Value* value, Stack* next): + index(index), value(value), next(next) + { } + + unsigned index; + Value* value; + Stack* next; +}; + +class ForkElement { + public: + Value* value; + MultiRead* read; + bool local; +}; + +class ForkState: public Compiler::State { + public: + ForkState(Stack* stack, Local* locals, Cell* saved, Event* predecessor, + unsigned logicalIp): stack(stack), - next(next) + locals(locals), + saved(saved), + predecessor(predecessor), + logicalIp(logicalIp), + readCount(0) { } Stack* stack; - State* next; + Local* locals; + Cell* saved; + Event* predecessor; + unsigned logicalIp; + unsigned readCount; + ForkElement elements[0]; }; -class Local { +class MySubroutine: public Compiler::Subroutine { public: - Local(unsigned size, unsigned index, Value* value, Site* site, Local* old, - Local* next): - size(size), index(index), reuse(true), value(value), site(site), old(old), - next(next) - { } + MySubroutine(): forkState(0) { } - unsigned size; - unsigned index; - bool reuse; - Value* value; - Site* site; - Local* old; - Local* next; + ForkState* forkState; }; class LogicalInstruction { public: + LogicalInstruction(int index, Stack* stack, Local* locals): + firstEvent(0), lastEvent(0), immediatePredecessor(0), stack(stack), + locals(locals), machineOffset(0), subroutine(0), index(index) + { } + Event* firstEvent; Event* lastEvent; LogicalInstruction* immediatePredecessor; Stack* stack; Local* locals; - unsigned machineOffset; - bool stackSaved; + Promise* machineOffset; + MySubroutine* subroutine; + int index; }; -class Register { +class Resource { public: - Register(int number): - value(0), site(0), number(number), size(0), refCount(0), - freezeCount(0), reserved(false), pushed(false) + Resource(bool reserved = false): + value(0), site(0), freezeCount(0), referenceCount(0), reserved(reserved) { } + virtual void freeze(Context*, Value*) = 0; + + virtual void thaw(Context*, Value*) = 0; + + virtual unsigned toString(Context*, char*, unsigned) = 0; + Value* value; - RegisterSite* site; - int number; - unsigned size; - unsigned refCount; - unsigned freezeCount; + Site* site; + uint8_t freezeCount; + uint8_t referenceCount; bool reserved; - bool pushed; +}; + +class RegisterResource: public Resource { + public: + RegisterResource(bool reserved): + Resource(reserved) + { } + + virtual void freeze(Context*, Value*); + + virtual void thaw(Context*, Value*); + + virtual unsigned toString(Context*, char*, unsigned); +}; + +class FrameResource: public Resource { + public: + virtual void freeze(Context*, Value*); + + virtual void thaw(Context*, Value*); + + virtual unsigned toString(Context*, char*, unsigned); }; class ConstantPoolNode { @@ -147,44 +250,59 @@ class ConstantPoolNode { ConstantPoolNode* next; }; -class Junction { - public: - Junction(unsigned logicalIp, Junction* next): - logicalIp(logicalIp), - next(next) - { } - - unsigned logicalIp; - Junction* next; -}; - class Read { public: - Read(unsigned size, Value* value, Site* target, Read* next, Event* event, - Read* eventNext): - size(size), value(value), target(target), next(next), event(event), - eventNext(eventNext) + Read(): + value(0), event(0), eventNext(0) { } + + virtual bool intersect(SiteMask* mask) = 0; - unsigned size; + virtual bool valid() = 0; + + virtual void append(Context* c, Read* r) = 0; + + virtual Read* next(Context* c) = 0; + Value* value; - Site* target; - Read* next; Event* event; Read* eventNext; }; +int +intersectFrameIndexes(int a, int b) +{ + if (a == NoFrameIndex or b == NoFrameIndex) return NoFrameIndex; + if (a == AnyFrameIndex) return b; + if (b == AnyFrameIndex) return a; + if (a == b) return a; + return NoFrameIndex; +} + +SiteMask +intersect(const SiteMask& a, const SiteMask& b) +{ + return SiteMask(a.typeMask & b.typeMask, a.registerMask & b.registerMask, + intersectFrameIndexes(a.frameIndex, b.frameIndex)); +} + class Value: public Compiler::Operand { public: Value(Site* site, Site* target): - reads(0), lastRead(0), sites(site), source(0), target(target) + reads(0), lastRead(0), sites(site), source(0), target(target), buddy(this), + high(0), home(NoFrameIndex) { } + + virtual void addPredecessor(Context*, Event*) { } Read* reads; Read* lastRead; Site* sites; Site* source; Site* target; + Value* buddy; + Value* high; + int8_t home; }; class Context { @@ -193,60 +311,86 @@ class Context { Compiler::Client* client): system(system), assembler(assembler), + arch(assembler->arch()), zone(zone), client(client), - logicalIp(-1), - state(new (zone->allocate(sizeof(State))) State(0, 0)), + stack(0), + locals(0), + saved(0), + predecessor(0), logicalCode(0), + registerResources + (static_cast + (zone->allocate(sizeof(RegisterResource) * arch->registerCount()))), + frameResources(0), + firstConstant(0), + lastConstant(0), + machineCode(0), + firstEvent(0), + lastEvent(0), + forkState(0), + subroutine(0), + logicalIp(-1), + constantCount(0), logicalCodeLength(0), parameterFootprint(0), localFootprint(0), - registers - (static_cast - (zone->allocate(sizeof(Register*) * assembler->registerCount()))), - firstConstant(0), - lastConstant(0), - constantCount(0), - nextSequence(0), - junctions(0), - machineCode(0), - locals(0), - localTable(0), - stackReset(false), + machineCodeSize(0), + alignedFrameSize(0), + availableRegisterCount(arch->registerCount()), constantCompare(CompareNone) { - for (unsigned i = 0; i < assembler->registerCount(); ++i) { - registers[i] = new (zone->allocate(sizeof(Register))) Register(i); + for (unsigned i = 0; i < arch->registerCount(); ++i) { + new (registerResources + i) RegisterResource(arch->reserved(i)); + if (registerResources[i].reserved) { + -- availableRegisterCount; + } } - - registers[assembler->base()]->reserved = true; - registers[assembler->stack()]->reserved = true; - registers[assembler->thread()]->reserved = true; } System* system; Assembler* assembler; + Assembler::Architecture* arch; Zone* zone; Compiler::Client* client; + Stack* stack; + Local* locals; + Cell* saved; + Event* predecessor; + LogicalInstruction** logicalCode; + RegisterResource* registerResources; + FrameResource* frameResources; + ConstantPoolNode* firstConstant; + ConstantPoolNode* lastConstant; + uint8_t* machineCode; + Event* firstEvent; + Event* lastEvent; + ForkState* forkState; + MySubroutine* subroutine; int logicalIp; - State* state; - LogicalInstruction* logicalCode; + unsigned constantCount; unsigned logicalCodeLength; unsigned parameterFootprint; unsigned localFootprint; - Register** registers; - ConstantPoolNode* firstConstant; - ConstantPoolNode* lastConstant; - unsigned constantCount; - unsigned nextSequence; - Junction* junctions; - uint8_t* machineCode; - Local* locals; - Local** localTable; - bool stackReset; + unsigned machineCodeSize; + unsigned alignedFrameSize; + unsigned availableRegisterCount; ConstantCompare constantCompare; }; +unsigned +RegisterResource::toString(Context* c, char* buffer, unsigned bufferSize) +{ + return snprintf + (buffer, bufferSize, "register %"LD, this - c->registerResources); +} + +unsigned +FrameResource::toString(Context* c, char* buffer, unsigned bufferSize) +{ + return snprintf(buffer, bufferSize, "frame %"LD, this - c->frameResources); +} + class PoolPromise: public Promise { public: PoolPromise(Context* c, int key): c(c), key(key) { } @@ -254,7 +398,7 @@ class PoolPromise: public Promise { virtual int64_t value() { if (resolved()) { return reinterpret_cast - (c->machineCode + pad(c->assembler->length()) + (key * BytesPerWord)); + (c->machineCode + pad(c->machineCodeSize) + (key * BytesPerWord)); } abort(c); @@ -270,27 +414,37 @@ class PoolPromise: public Promise { class CodePromise: public Promise { public: - CodePromise(Context* c, CodePromise* next): c(c), offset(-1), next(next) { } + CodePromise(Context* c, CodePromise* next): + c(c), offset(0), next(next) + { } - CodePromise(Context* c, int offset): c(c), offset(offset), next(0) { } + CodePromise(Context* c, Promise* offset): + c(c), offset(offset), next(0) + { } virtual int64_t value() { if (resolved()) { - return reinterpret_cast(c->machineCode + offset); + return reinterpret_cast(c->machineCode + offset->value()); } abort(c); } virtual bool resolved() { - return c->machineCode != 0 and offset >= 0; + return c->machineCode != 0 and offset and offset->resolved(); } Context* c; - int offset; + Promise* offset; CodePromise* next; }; +unsigned +machineOffset(Context* c, int logicalIp) +{ + return c->logicalCode[logicalIp]->machineOffset->value(); +} + class IpPromise: public Promise { public: IpPromise(Context* c, int logicalIp): @@ -301,7 +455,7 @@ class IpPromise: public Promise { virtual int64_t value() { if (resolved()) { return reinterpret_cast - (c->machineCode + c->logicalCode[logicalIp].machineOffset); + (c->machineCode + machineOffset(c, logicalIp)); } abort(c); @@ -335,58 +489,313 @@ expect(Context* c, bool v) expect(c->system, v); } +unsigned +count(Cell* c) +{ + unsigned count = 0; + while (c) { + ++ count; + c = c->next; + } + return count; +} + +Cell* +cons(Context* c, void* value, Cell* next) +{ + return new (c->zone->allocate(sizeof(Cell))) Cell(next, value); +} + +Cell* +append(Context* c, Cell* first, Cell* second) +{ + if (first) { + if (second) { + Cell* start = cons(c, first->value, second); + Cell* end = start; + for (Cell* cell = first->next; cell; cell = cell->next) { + Cell* n = cons(c, cell->value, second); + end->next = n; + end = n; + } + return start; + } else { + return first; + } + } else { + return second; + } +} + +Cell* +reverseDestroy(Cell* cell) +{ + Cell* previous = 0; + while (cell) { + Cell* next = cell->next; + cell->next = previous; + previous = cell; + cell = next; + } + return previous; +} + +class StubReadPair { + public: + Value* value; + StubRead* read; +}; + +class JunctionState { + public: + JunctionState(unsigned frameFootprint): frameFootprint(frameFootprint) { } + + unsigned frameFootprint; + StubReadPair reads[0]; +}; + +class Link { + public: + Link(Event* predecessor, Link* nextPredecessor, Event* successor, + Link* nextSuccessor, ForkState* forkState): + predecessor(predecessor), nextPredecessor(nextPredecessor), + successor(successor), nextSuccessor(nextSuccessor), forkState(forkState), + junctionState(0) + { } + + Event* predecessor; + Link* nextPredecessor; + Event* successor; + Link* nextSuccessor; + ForkState* forkState; + JunctionState* junctionState; +}; + +Link* +link(Context* c, Event* predecessor, Link* nextPredecessor, Event* successor, + Link* nextSuccessor, ForkState* forkState) +{ + return new (c->zone->allocate(sizeof(Link))) Link + (predecessor, nextPredecessor, successor, nextSuccessor, forkState); +} + +unsigned +countPredecessors(Link* link) +{ + unsigned c = 0; + for (; link; link = link->nextPredecessor) ++ c; + return c; +} + +Link* +lastPredecessor(Link* link) +{ + while (link->nextPredecessor) link = link->nextPredecessor; + return link; +} + +unsigned +countSuccessors(Link* link) +{ + unsigned c = 0; + for (; link; link = link->nextSuccessor) ++ c; + return c; +} + class Event { public: Event(Context* c): - next(0), stack(c->state->stack), locals(c->locals), promises(0), reads(0), - readCount(0), sequence(c->nextSequence++), stackReset(c->stackReset) - { - assert(c, c->logicalIp >= 0); - - LogicalInstruction* i = c->logicalCode + c->logicalIp; - if (i->lastEvent) { - i->lastEvent->next = this; - } else { - i->firstEvent = this; - } - i->lastEvent = this; - - if (c->stackReset) { -// fprintf(stderr, "stack reset\n"); - c->stackReset = false; - } - } - - Event(Context*, unsigned sequence, Stack* stack, Local* locals): - next(0), stack(stack), locals(locals), promises(0), reads(0), readCount(0), - sequence(sequence), stackReset(false) + next(0), stackBefore(c->stack), localsBefore(c->locals), + stackAfter(0), localsAfter(0), promises(0), reads(0), + junctionSites(0), snapshots(0), predecessors(0), successors(0), + visitLinks(0), block(0), logicalInstruction(c->logicalCode[c->logicalIp]), + readCount(0) { } + virtual const char* name() = 0; + virtual void compile(Context* c) = 0; - virtual bool skipMove(unsigned) { return false; } + virtual bool isBranch() { return false; } Event* next; - Stack* stack; - Local* locals; + Stack* stackBefore; + Local* localsBefore; + Stack* stackAfter; + Local* localsAfter; CodePromise* promises; Read* reads; + Site** junctionSites; + Snapshot* snapshots; + Link* predecessors; + Link* successors; + Cell* visitLinks; + Block* block; + LogicalInstruction* logicalInstruction; unsigned readCount; - unsigned sequence; - bool stackReset; }; int -localOffset(Context* c, int v) +frameIndex(Context* c, int index) { - int parameterFootprint = c->parameterFootprint * BytesPerWord; + assert(c, static_cast + (c->alignedFrameSize + c->parameterFootprint - index - 1) + >= 0); - v *= BytesPerWord; - if (v < parameterFootprint) { - return (parameterFootprint - v - BytesPerWord) + (BytesPerWord * 2); - } else { - return -(v + BytesPerWord - parameterFootprint); + return c->alignedFrameSize + c->parameterFootprint - index - 1; +} + +unsigned +frameIndexToOffset(Context* c, unsigned frameIndex) +{ + return ((frameIndex >= c->alignedFrameSize) ? + (frameIndex + + (c->arch->frameFooterSize() * 2) + + c->arch->frameHeaderSize()) : + (frameIndex + + c->arch->frameFooterSize())) * BytesPerWord; +} + +unsigned +offsetToFrameIndex(Context* c, unsigned offset) +{ + unsigned normalizedOffset = offset / BytesPerWord; + + return ((normalizedOffset + >= c->alignedFrameSize + + c->arch->frameFooterSize()) ? + (normalizedOffset + - (c->arch->frameFooterSize() * 2) + - c->arch->frameHeaderSize()) : + (normalizedOffset + - c->arch->frameFooterSize())); +} + +class FrameIterator { + public: + class Element { + public: + Element(Value* value, unsigned localIndex): + value(value), localIndex(localIndex) + { } + + Value* const value; + const unsigned localIndex; + }; + + FrameIterator(Context* c, Stack* stack, Local* locals): + stack(stack), locals(locals), localIndex(c->localFootprint - 1) + { } + + bool hasMore() { + while (stack and stack->value == 0) stack = stack->next; + + while (localIndex >= 0 and locals[localIndex].value == 0) -- localIndex; + + return stack != 0 or localIndex >= 0; } + + Element next(Context* c) { + Value* v; + unsigned li; + if (stack) { + Stack* s = stack; + v = s->value; + li = s->index + c->localFootprint; + stack = stack->next; + } else { + Local* l = locals + localIndex; + v = l->value; + li = localIndex; + -- localIndex; + } + return Element(v, li); + } + + Stack* stack; + Local* locals; + int localIndex; +}; + +int +frameIndex(Context* c, FrameIterator::Element* element) +{ + return frameIndex(c, element->localIndex); +} + +class SiteIterator { + public: + SiteIterator(Value* v, bool includeBuddies = true): + originalValue(v), + currentValue(v), + includeBuddies(includeBuddies), + next_(findNext(&(v->sites))), + previous(0) + { } + + Site** findNext(Site** p) { + if (*p) { + return p; + } else { + if (includeBuddies) { + for (Value* v = currentValue->buddy; + v != originalValue; + v = v->buddy) + { + if (v->sites) { + currentValue = v; + return &(v->sites); + } + } + } + return 0; + } + } + + bool hasMore() { + if (previous) { + next_ = findNext(&((*previous)->next)); + previous = 0; + } + return next_ != 0; + } + + Site* next() { + previous = next_; + return *previous; + } + + void remove(Context* c) { + (*previous)->release(c, originalValue); + *previous = (*previous)->next; + next_ = findNext(previous); + previous = 0; + } + + Value* originalValue; + Value* currentValue; + bool includeBuddies; + Site** next_; + Site** previous; +}; + +bool +hasMoreThanOneSite(Value* v) +{ + SiteIterator it(v); + if (it.hasMore()) { + it.next(); + return it.hasMore(); + } else { + return false; + } +} + +bool +hasSite(Value* v) +{ + SiteIterator it(v); + return it.hasMore(); } bool @@ -399,11 +808,14 @@ findSite(Context*, Value* v, Site* site) } void -addSite(Context* c, Stack* stack, unsigned size, Value* v, Site* s) +addSite(Context* c, Value* v, Site* s) { if (not findSite(c, v, s)) { -// fprintf(stderr, "add site %p (%d) to %p\n", s, s->type(c), v); - s->acquire(c, stack, size, v); + if (DebugSites) { + char buffer[256]; s->toString(c, buffer, 256); + fprintf(stderr, "add site %s to %p\n", buffer, v); + } + s->acquire(c, v); s->next = v->sites; v->sites = s; } @@ -412,70 +824,477 @@ addSite(Context* c, Stack* stack, unsigned size, Value* v, Site* s) void removeSite(Context* c, Value* v, Site* s) { - for (Site** p = &(v->sites); *p;) { - if (s == *p) { -// fprintf(stderr, "remove site %p (%d) from %p\n", s, s->type(c), v); - s->release(c); - *p = (*p)->next; + for (SiteIterator it(v); it.hasMore();) { + if (s == it.next()) { + if (DebugSites) { + char buffer[256]; s->toString(c, buffer, 256); + fprintf(stderr, "remove site %s from %p\n", buffer, v); + } + it.remove(c); break; - } else { - p = &((*p)->next); } } -} - -void -removeMemorySites(Context* c, Value* v) -{ - for (Site** p = &(v->sites); *p;) { - if ((*p)->type(c) == MemoryOperand) { -// fprintf(stderr, "remove site %p (%d) from %p\n", *p, (*p)->type(c), v); - (*p)->release(c); - *p = (*p)->next; - break; - } else { - p = &((*p)->next); - } + if (DebugSites) { + fprintf(stderr, "%p has more: %d\n", v, hasSite(v)); } + assert(c, not findSite(c, v, s)); } void clearSites(Context* c, Value* v) { - for (Site* s = v->sites; s; s = s->next) { - s->release(c); + if (DebugSites) { + fprintf(stderr, "clear sites for %p\n", v); } - v->sites = 0; + for (SiteIterator it(v); it.hasMore();) { + it.next(); + it.remove(c); + } +} + +bool +valid(Read* r) +{ + return r and r->valid(); +} + +Read* +live(Value* v) +{ + Value* p = v; + do { + if (valid(p->reads)) { + return p->reads; + } + p = p->buddy; + } while (p != v); + + return 0; +} + +Read* +liveNext(Context* c, Value* v) +{ + Read* r = v->reads->next(c); + if (valid(r)) return r; + + for (Value* p = v->buddy; p != v; p = p->buddy) { + if (valid(p->reads)) return p->reads; + } + + return 0; } void -nextRead(Context* c, Value* v) +deadBuddy(Context* c, Value* v, Read* r UNUSED) { -// fprintf(stderr, "pop read %p from %p; next: %p\n", v->reads, v, v->reads->next); + assert(c, v->buddy != v); + assert(c, r); - v->reads = v->reads->next; - if (v->reads == 0) { - clearSites(c, v); + if (DebugBuddies) { + fprintf(stderr, "remove dead buddy %p from", v); + for (Value* p = v->buddy; p != v; p = p->buddy) { + fprintf(stderr, " %p", p); + } + fprintf(stderr, "\n"); } + + Value* next = v->buddy; + v->buddy = v; + Value* p = next; + while (p->buddy != v) p = p->buddy; + p->buddy = next; + + for (SiteIterator it(v); it.hasMore();) { + Site* s = it.next(); + it.remove(c); + + addSite(c, next, s); + } +} + +void +popRead(Context* c, Event* e UNUSED, Value* v) +{ + assert(c, e == v->reads->event); + + if (DebugReads) { + fprintf(stderr, "pop read %p from %p next %p event %p (%s)\n", + v->reads, v, v->reads->next(c), e, (e ? e->name() : 0)); + } + + v->reads = v->reads->next(c); + + if (not valid(v->reads)) { + Read* r = live(v); + if (r) { + deadBuddy(c, v, r); + } else { + clearSites(c, v); + } + } +} + +bool +buddies(Value* a, Value* b) +{ + if (a == b) return true; + for (Value* p = a->buddy; p != a; p = p->buddy) { + if (p == b) return true; + } + return false; +} + +void +decrementAvailableRegisterCount(Context* c) +{ + assert(c, c->availableRegisterCount); + -- c->availableRegisterCount; + + if (DebugResources) { + fprintf(stderr, "%d registers available\n", c->availableRegisterCount); + } +} + +void +incrementAvailableRegisterCount(Context* c) +{ + ++ c->availableRegisterCount; + + if (DebugResources) { + fprintf(stderr, "%d registers available\n", c->availableRegisterCount); + } +} + +void +increment(Context* c, RegisterResource* r) +{ + if (not r->reserved) { + if (DebugResources) { + char buffer[256]; r->toString(c, buffer, 256); + fprintf(stderr, "increment %s to %d\n", buffer, r->referenceCount + 1); + } + + ++ r->referenceCount; + + if (r->referenceCount == 1) { + decrementAvailableRegisterCount(c); + } + } +} + +void +decrement(Context* c, Resource* r) +{ + if (not r->reserved) { + if (DebugResources) { + char buffer[256]; r->toString(c, buffer, 256); + fprintf(stderr, "decrement %s to %d\n", buffer, r->referenceCount - 1); + } + + assert(c, r->referenceCount > 0); + + -- r->referenceCount; + + if (r->referenceCount == 0) { + incrementAvailableRegisterCount(c); + } + } +} + +void +freezeResource(Context* c, Resource* r, Value* v) +{ + if (DebugResources) { + char buffer[256]; r->toString(c, buffer, 256); + fprintf(stderr, "%p freeze %s to %d\n", v, buffer, r->freezeCount + 1); + } + + assert(c, r->value == 0 or buddies(r->value, v)); + + ++ r->freezeCount; +} + +void +RegisterResource::freeze(Context* c, Value* v) +{ + if (not reserved) { + freezeResource(c, this, v); + + if (freezeCount == 1) { + decrementAvailableRegisterCount(c); + } + } +} + +void +FrameResource::freeze(Context* c, Value* v) +{ + freezeResource(c, this, v); +} + +void +thawResource(Context* c, Resource* r, Value* v) +{ + if (not r->reserved) { + if (DebugResources) { + char buffer[256]; r->toString(c, buffer, 256); + fprintf(stderr, "%p thaw %s to %d\n", v, buffer, r->freezeCount - 1); + } + + assert(c, r->freezeCount); + assert(c, r->value == 0 or buddies(r->value, v)); + + -- r->freezeCount; + } +} + +void +RegisterResource::thaw(Context* c, Value* v) +{ + if (not reserved) { + thawResource(c, this, v); + + if (freezeCount == 0) { + incrementAvailableRegisterCount(c); + } + } +} + +void +FrameResource::thaw(Context* c, Value* v) +{ + thawResource(c, this, v); +} + +class Target { + public: + static const unsigned Penalty = 10; + static const unsigned Impossible = 20; + + Target(): cost(Impossible) { } + + Target(int index, OperandType type, unsigned cost): + index(index), type(type), cost(cost) + { } + + int16_t index; + OperandType type; + uint8_t cost; +}; + +Target +pickTarget(Context* c, Read* r, bool intersectRead, + unsigned registerReserveCount); + +unsigned +resourceCost(Context* c UNUSED, Value* v, Resource* r) +{ + if (r->reserved or r->freezeCount or r->referenceCount) { + return Target::Impossible; + } else if (r->value) { + assert(c, findSite(c, r->value, r->site)); + + if (v and buddies(r->value, v)) { + return 0; + } else if (hasMoreThanOneSite(r->value)) { + return 2; + } else { + return 4; + } + } else { + return 0; + } +} + +int +pickRegisterTarget(Context* c, Value* v, uint32_t mask, unsigned* cost) +{ + int target = NoRegister; + unsigned bestCost = Target::Impossible; + for (int i = c->arch->registerCount() - 1; i >= 0; --i) { + if ((1 << i) & mask) { + RegisterResource* r = c->registerResources + i; + unsigned myCost = resourceCost(c, v, r); + if ((static_cast(1) << i) == mask) { + *cost = myCost; + return i; + } else if (myCost < bestCost) { + bestCost = myCost; + target = i; + } + } + } + + *cost = bestCost; + return target; +} + +Target +pickRegisterTarget(Context* c, Value* v, uint32_t mask) +{ + unsigned cost; + int number = pickRegisterTarget(c, v, mask, &cost); + return Target(number, RegisterOperand, cost); +} + +unsigned +frameCost(Context* c, Value* v, int frameIndex) +{ + return resourceCost(c, v, c->frameResources + frameIndex) + 1; +} + +Target +pickFrameTarget(Context* c, Value* v) +{ + Target best; + + Value* p = v; + do { + if (p->home >= 0) { + Target mine(p->home, MemoryOperand, frameCost(c, v, p->home)); + if (mine.cost == 0) { + return mine; + } else if (mine.cost < best.cost) { + best = mine; + } + } + p = p->buddy; + } while (p != v); + + return best; +} + +Target +pickTarget(Context* c, Read* read, bool intersectRead, + unsigned registerReserveCount) +{ + SiteMask mask; + read->intersect(&mask); + + unsigned registerPenalty = (c->availableRegisterCount > registerReserveCount + ? 0 : Target::Penalty); + + Target best; + if ((mask.typeMask & (1 << RegisterOperand))) { + Target mine = pickRegisterTarget(c, read->value, mask.registerMask); + + mine.cost += registerPenalty; + + if (mine.cost == 0) { + return mine; + } else if (mine.cost < best.cost) { + best = mine; + } + } + + if ((mask.typeMask & (1 << MemoryOperand)) && mask.frameIndex >= 0) { + Target mine(mask.frameIndex, MemoryOperand, + frameCost(c, read->value, mask.frameIndex)); + if (mine.cost == 0) { + return mine; + } else if (mine.cost < best.cost) { + best = mine; + } + } + + if (intersectRead) { + return best; + } + + { Target mine = pickRegisterTarget(c, read->value, ~0); + + mine.cost += registerPenalty; + + if (mine.cost == 0) { + return mine; + } else if (mine.cost < best.cost) { + best = mine; + } + } + + { Target mine = pickFrameTarget(c, read->value); + if (mine.cost == 0) { + return mine; + } else if (mine.cost < best.cost) { + best = mine; + } + } + + return best; +} + +void +acquire(Context* c, Resource* resource, Value* value, Site* site); + +void +release(Context* c, Resource* resource, Value* value, Site* site); + +ConstantSite* +constantSite(Context* c, Promise* value); + +ShiftMaskPromise* +shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) +{ + return new (c->zone->allocate(sizeof(ShiftMaskPromise))) + ShiftMaskPromise(base, shift, mask); +} + +CombinedPromise* +combinedPromise(Context* c, Promise* low, Promise* high) +{ + return new (c->zone->allocate(sizeof(CombinedPromise))) + CombinedPromise(low, high); } class ConstantSite: public Site { public: ConstantSite(Promise* value): value(value) { } + virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) { + if (value->resolved()) { + return snprintf + (buffer, bufferSize, "constant %"LLD, value->value()); + } else { + return snprintf(buffer, bufferSize, "constant unresolved"); + } + } + virtual unsigned copyCost(Context*, Site* s) { - return (s == this ? 0 : 1); + return (s == this ? 0 : 3); + } + + virtual bool match(Context*, const SiteMask& mask) { + return mask.typeMask & (1 << ConstantOperand); } virtual OperandType type(Context*) { return ConstantOperand; } - virtual Assembler::Operand* asAssemblerOperand(Context*) { - return &value; + virtual void asAssemblerOperand(Context* c, Site* high, + Assembler::Operand* result) + { + Promise* v = value; + if (high) { + v = combinedPromise(c, value, static_cast(high)->value); + } + new (result) Assembler::Constant(v); } - Assembler::Constant value; + virtual Site* copy(Context* c) { + return constantSite(c, value); + } + + virtual Site* copyLow(Context* c) { + return constantSite(c, shiftMaskPromise(c, value, 0, 0xFFFFFFFF)); + } + + virtual Site* copyHigh(Context* c) { + return constantSite(c, shiftMaskPromise(c, value, 32, 0xFFFFFFFF)); + } + + Promise* value; }; ConstantSite* @@ -497,23 +1316,55 @@ constantSite(Context* c, int64_t value) return constantSite(c, resolved(c, value)); } +AddressSite* +addressSite(Context* c, Promise* address); + class AddressSite: public Site { public: AddressSite(Promise* address): address(address) { } + virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) { + if (address->resolved()) { + return snprintf + (buffer, bufferSize, "address %"LLD, address->value()); + } else { + return snprintf(buffer, bufferSize, "address unresolved"); + } + } + virtual unsigned copyCost(Context*, Site* s) { - return (s == this ? 0 : 3); + return (s == this ? 0 : 2); + } + + virtual bool match(Context*, const SiteMask& mask) { + return mask.typeMask & (1 << AddressOperand); } virtual OperandType type(Context*) { return AddressOperand; } - virtual Assembler::Operand* asAssemblerOperand(Context*) { - return &address; + virtual void asAssemblerOperand(Context* c UNUSED, Site* high UNUSED, + Assembler::Operand* result) + { + assert(c, high == 0); + + new (result) Assembler::Address(address); } - Assembler::Address address; + virtual Site* copy(Context* c) { + return addressSite(c, address); + } + + virtual Site* copyLow(Context* c) { + abort(c); + } + + virtual Site* copyHigh(Context* c) { + abort(c); + } + + Promise* address; }; AddressSite* @@ -522,209 +1373,176 @@ addressSite(Context* c, Promise* address) return new (c->zone->allocate(sizeof(AddressSite))) AddressSite(address); } -void -freeze(Register* r) -{ - if (DebugRegisters) { - fprintf(stderr, "freeze %d to %d\n", r->number, r->freezeCount + 1); - } - - ++ r->freezeCount; -} - -void -thaw(Register* r) -{ - if (DebugRegisters) { - fprintf(stderr, "thaw %d to %d\n", r->number, r->freezeCount - 1); - } - - -- r->freezeCount; -} - -Register* -acquire(Context* c, uint32_t mask, Stack* stack, unsigned newSize, - Value* newValue, RegisterSite* newSite); - -void -release(Context* c, Register* r); - -Register* -validate(Context* c, uint32_t mask, Stack* stack, unsigned size, - Value* value, RegisterSite* site, Register* current); +RegisterSite* +freeRegisterSite(Context* c, uint32_t mask = ~0); class RegisterSite: public Site { public: - RegisterSite(uint64_t mask, Register* low = 0, Register* high = 0): - mask(mask), low(low), high(high), register_(NoRegister, NoRegister) + RegisterSite(uint32_t mask, int number): + mask(mask), number(number) { } - void sync(Context* c UNUSED) { - assert(c, low); - - register_.low = low->number; - register_.high = (high? high->number : NoRegister); + virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) { + if (number != NoRegister) { + return snprintf(buffer, bufferSize, "%p register %d", this, number); + } else { + return snprintf(buffer, bufferSize, "%p register unacquired", this); + } } virtual unsigned copyCost(Context* c, Site* s) { - sync(c); + assert(c, number != NoRegister); if (s and (this == s or (s->type(c) == RegisterOperand - and (static_cast(s)->mask - & (static_cast(1) << register_.low)) - and (register_.high == NoRegister - or (static_cast(s)->mask - & (static_cast(1) << (register_.high + 32))))))) + and (static_cast(s)->mask & (1 << number))))) { return 0; } else { - return 2; + return 1; } } - virtual void acquire(Context* c, Stack* stack, unsigned size, Value* v) { - low = ::validate(c, mask, stack, size, v, this, low); - if (size > BytesPerWord) { - ::freeze(low); - high = ::validate(c, mask >> 32, stack, size, v, this, high); - ::thaw(low); + virtual bool match(Context* c UNUSED, const SiteMask& mask) { + assert(c, number != NoRegister); + + if ((mask.typeMask & (1 << RegisterOperand))) { + return ((static_cast(1) << number) & mask.registerMask); + } else { + return false; } } - virtual void release(Context* c) { - assert(c, low); - - ::release(c, low); - if (high) { - ::release(c, high); + virtual void acquire(Context* c, Value* v) { + Target target; + if (number != NoRegister) { + target = Target(number, RegisterOperand, 0); + } else { + target = pickRegisterTarget(c, v, mask); + expect(c, target.cost < Target::Impossible); } + + RegisterResource* resource = c->registerResources + target.index; + ::acquire(c, resource, v, this); + + number = target.index; } - virtual void freeze(Context* c UNUSED) { - assert(c, low); + virtual void release(Context* c, Value* v) { + assert(c, number != NoRegister); - ::freeze(low); - if (high) { - ::freeze(high); - } + ::release(c, c->registerResources + number, v, this); } - virtual void thaw(Context* c UNUSED) { - assert(c, low); + virtual void freeze(Context* c, Value* v) { + assert(c, number != NoRegister); - ::thaw(low); - if (high) { - ::thaw(high); - } + c->registerResources[number].freeze(c, v); + } + + virtual void thaw(Context* c, Value* v) { + assert(c, number != NoRegister); + + c->registerResources[number].thaw(c, v); + } + + virtual bool frozen(Context* c UNUSED) { + assert(c, number != NoRegister); + + return c->registerResources[number].freezeCount != 0; } virtual OperandType type(Context*) { return RegisterOperand; } - virtual Assembler::Operand* asAssemblerOperand(Context* c) { - sync(c); - return ®ister_; + virtual void asAssemblerOperand(Context* c UNUSED, Site* high, + Assembler::Operand* result) + { + assert(c, number != NoRegister); + + int highNumber; + if (high) { + highNumber = static_cast(high)->number; + assert(c, highNumber != NoRegister); + } else { + highNumber = NoRegister; + } + + new (result) Assembler::Register(number, highNumber); } - uint64_t mask; - Register* low; - Register* high; - Assembler::Register register_; + virtual Site* copy(Context* c) { + uint32_t mask; + + if (number != NoRegister) { + mask = 1 << number; + } else { + mask = this->mask; + } + + return freeRegisterSite(c, mask); + } + + virtual Site* copyLow(Context* c) { + abort(c); + } + + virtual Site* copyHigh(Context* c) { + abort(c); + } + + uint32_t mask; + int number; }; RegisterSite* -registerSite(Context* c, int low, int high = NoRegister) +registerSite(Context* c, int number) { - assert(c, low != NoRegister); - assert(c, low < static_cast(c->assembler->registerCount())); - assert(c, high == NoRegister - or high < static_cast(c->assembler->registerCount())); + assert(c, number >= 0); + assert(c, number < static_cast(c->arch->registerCount())); - Register* hr; - if (high == NoRegister) { - hr = 0; - } else { - hr = c->registers[high]; - } return new (c->zone->allocate(sizeof(RegisterSite))) - RegisterSite(~static_cast(0), c->registers[low], hr); + RegisterSite(1 << number, number); } RegisterSite* -freeRegisterSite(Context* c, uint64_t mask = ~static_cast(0)) +freeRegisterSite(Context* c, uint32_t mask) { return new (c->zone->allocate(sizeof(RegisterSite))) - RegisterSite(mask); + RegisterSite(mask, NoRegister); } -RegisterSite* -fixedRegisterSite(Context* c, int low, int high = NoRegister) -{ - uint64_t mask; - if (high == NoRegister) { - mask = (~static_cast(0) << 32) - | (static_cast(1) << low); - } else { - mask = (static_cast(1) << (high + 32)) - | (static_cast(1) << low); - } - - return new (c->zone->allocate(sizeof(RegisterSite))) - RegisterSite(mask); -} - -Register* -increment(Context* c, int i) -{ - Register* r = c->registers[i]; - - if (DebugRegisters) { - fprintf(stderr, "increment %d to %d\n", r->number, r->refCount + 1); - } - - ++ r->refCount; - - return r; -} - -void -decrement(Context* c UNUSED, Register* r) -{ - assert(c, r->refCount > 0); - - if (DebugRegisters) { - fprintf(stderr, "decrement %d to %d\n", r->number, r->refCount - 1); - } - - -- r->refCount; -} +MemorySite* +memorySite(Context* c, int base, int offset = 0, int index = NoRegister, + unsigned scale = 1); class MemorySite: public Site { public: MemorySite(int base, int offset, int index, unsigned scale): - base(0), index(0), value(base, offset, index, scale) + acquired(false), base(base), offset(offset), index(index), scale(scale) { } - void sync(Context* c UNUSED) { - assert(c, base); - - value.base = base->number; - value.index = (index? index->number : NoRegister); + virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) { + if (acquired) { + return snprintf(buffer, bufferSize, "memory %d 0x%x %d %d", + base, offset, index, scale); + } else { + return snprintf(buffer, bufferSize, "memory unacquired"); + } } virtual unsigned copyCost(Context* c, Site* s) { - sync(c); + assert(c, acquired); if (s and (this == s or (s->type(c) == MemoryOperand - and static_cast(s)->value.base == value.base - and static_cast(s)->value.offset == value.offset - and static_cast(s)->value.index == value.index - and static_cast(s)->value.scale == value.scale))) + and static_cast(s)->base == base + and static_cast(s)->offset == offset + and static_cast(s)->index == index + and static_cast(s)->scale == scale))) { return 0; } else { @@ -732,620 +1550,618 @@ class MemorySite: public Site { } } - virtual void acquire(Context* c, Stack*, unsigned, Value*) { - base = increment(c, value.base); - if (value.index != NoRegister) { - index = increment(c, value.index); + virtual bool match(Context* c, const SiteMask& mask) { + assert(c, acquired); + + if (mask.typeMask & (1 << MemoryOperand)) { + if (base == c->arch->stack()) { + assert(c, index == NoRegister); + return mask.frameIndex == AnyFrameIndex + || (mask.frameIndex != NoFrameIndex + && static_cast(frameIndexToOffset(c, mask.frameIndex)) + == offset); + } else { + return true; + } + } else { + return false; } } - virtual void release(Context* c) { - decrement(c, base); - if (index) { - decrement(c, index); + virtual void acquire(Context* c, Value* v) { + increment(c, c->registerResources + base); + if (index != NoRegister) { + increment(c, c->registerResources + index); } + + if (base == c->arch->stack()) { + assert(c, index == NoRegister); + + ::acquire(c, c->frameResources + offsetToFrameIndex(c, offset), v, this); + } + + acquired = true; + } + + virtual void release(Context* c, Value* v) { + if (base == c->arch->stack()) { + assert(c, index == NoRegister); + + ::release(c, c->frameResources + offsetToFrameIndex(c, offset), v, this); + } + + decrement(c, c->registerResources + base); + if (index != NoRegister) { + decrement(c, c->registerResources + index); + } + + acquired = false; + } + + virtual void freeze(Context* c, Value* v) { + if (base == c->arch->stack()) { + c->frameResources[offsetToFrameIndex(c, offset)].freeze(c, v); + } + } + + virtual void thaw(Context* c, Value* v) { + if (base == c->arch->stack()) { + c->frameResources[offsetToFrameIndex(c, offset)].thaw(c, v); + } + } + + virtual bool frozen(Context* c) { + return base == c->arch->stack() + and c->frameResources[offsetToFrameIndex(c, offset)].freezeCount != 0; } virtual OperandType type(Context*) { return MemoryOperand; } - virtual Assembler::Operand* asAssemblerOperand(Context* c) { - sync(c); - return &value; + virtual void asAssemblerOperand(Context* c UNUSED, Site* high UNUSED, + Assembler::Operand* result) + { + assert(c, high == 0 + or (static_cast(high)->base == base + and static_cast(high)->offset + == static_cast(offset + BytesPerWord) + and static_cast(high)->index == index + and static_cast(high)->scale == scale)); + + assert(c, acquired); + + new (result) Assembler::Memory(base, offset, index, scale); } - Register* base; - Register* index; - Assembler::Memory value; + virtual Site* copy(Context* c) { + return memorySite(c, base, offset, index, scale); + } + + virtual Site* copyLow(Context* c) { + return copy(c); + } + + virtual Site* copyHigh(Context* c) { + return memorySite(c, base, offset + BytesPerWord, index, scale); + } + + bool acquired; + int base; + int offset; + int index; + unsigned scale; }; MemorySite* -memorySite(Context* c, int base, int offset = 0, int index = NoRegister, - unsigned scale = 1) +memorySite(Context* c, int base, int offset, int index, unsigned scale) { return new (c->zone->allocate(sizeof(MemorySite))) MemorySite(base, offset, index, scale); } -bool -matchRegister(Context* c UNUSED, Site* s, uint64_t mask) +MemorySite* +frameSite(Context* c, int frameIndex) { - assert(c, s->type(c) == RegisterOperand); - - RegisterSite* r = static_cast(s); - if (r->low) { - r->sync(c); - return ((static_cast(1) << r->register_.low) & mask) - and (r->register_.high == NoRegister - or ((static_cast(1) << (r->register_.high + 32)) & mask)); - } else { - return false; - } + assert(c, frameIndex >= 0); + return memorySite + (c, c->arch->stack(), frameIndexToOffset(c, frameIndex), NoRegister, 0); } -bool -match(Context* c, Site* s, uint8_t typeMask, uint64_t registerMask) +void +move(Context* c, Value* value, Site* src, Site* dst) { - OperandType t = s->type(c); - return ((1 << t) & typeMask) - and (t != RegisterOperand or matchRegister(c, s, registerMask)); + src->freeze(c, value); + + addSite(c, value, dst); + + src->thaw(c, value); + + if (dst->type(c) == MemoryOperand + and (src->type(c) == MemoryOperand + or src->type(c) == AddressOperand)) + { + src->freeze(c, value); + dst->freeze(c, value); + + Site* tmp = freeRegisterSite(c); + addSite(c, value, tmp); + + dst->thaw(c, value); + src->thaw(c, value); + + if (DebugMoves) { + char srcb[256]; src->toString(c, srcb, 256); + char tmpb[256]; tmp->toString(c, tmpb, 256); + fprintf(stderr, "move %s to %s for %p\n", srcb, tmpb, value); + } + + apply(c, Move, BytesPerWord, src, 0, BytesPerWord, tmp, 0); + + src = tmp; + } + + if (DebugMoves) { + char srcb[256]; src->toString(c, srcb, 256); + char dstb[256]; dst->toString(c, dstb, 256); + fprintf(stderr, "move %s to %s for %p\n", srcb, dstb, value); + } + + apply(c, Move, BytesPerWord, src, 0, BytesPerWord, dst, 0); +} + +unsigned +sitesToString(Context* c, Site* sites, char* buffer, unsigned size) +{ + unsigned total = 0; + for (Site* s = sites; s; s = s->next) { + total += s->toString(c, buffer + total, size - total); + + if (s->next) { + assert(c, size > total + 2); + memcpy(buffer + total, ", ", 2); + total += 2; + } + } + + assert(c, size > total); + buffer[total] = 0; + + return total; +} + +unsigned +sitesToString(Context* c, Value* v, char* buffer, unsigned size) +{ + unsigned total = 0; + Value* p = v; + do { + if (total) { + assert(c, size > total + 2); + memcpy(buffer + total, "; ", 2); + total += 2; + } + + if (p->sites) { + total += snprintf(buffer + total, size - total, "%p has ", p); + total += sitesToString(c, p->sites, buffer + total, size - total); + } else { + total += snprintf(buffer + total, size - total, "%p has nothing", p); + } + + p = p->buddy; + } while (p != v); + + return total; } Site* -targetOrNull(Context* c, Read* r) +pickTargetSite(Context* c, Read* read, bool intersectRead = false, + unsigned registerReserveCount = 0) { - Value* v = r->value; - if (v->target) { - return v->target; - } else if (r->target) { - return r->target->readTarget(c, r); + Target target(pickTarget(c, read, intersectRead, registerReserveCount)); + expect(c, target.cost < Target::Impossible); + if (target.type == MemoryOperand) { + return frameSite(c, target.index); } else { - return 0; + return registerSite(c, target.index); } } -Site* -targetOrNull(Context* c, Value* v) +void +steal(Context* c, Resource* r, Value* thief) { - if (v->target) { - return v->target; - } else if (v->reads and v->reads->target) { - return v->reads->target->readTarget(c, v->reads); + if (DebugResources) { + char resourceBuffer[256]; r->toString(c, resourceBuffer, 256); + char siteBuffer[1024]; sitesToString(c, r->value, siteBuffer, 1024); + fprintf(stderr, "%p steal %s from %p (%s)\n", + thief, resourceBuffer, r->value, siteBuffer); } - return 0; + + if (not ((thief and buddies(thief, r->value)) + or hasMoreThanOneSite(r->value))) + { + r->site->freeze(c, r->value); + + move(c, r->value, r->site, pickTargetSite + (c, live(r->value), false, StealRegisterReserveCount)); + + r->site->thaw(c, r->value); + } + + removeSite(c, r->value, r->site); } -class AbstractSite: public Site { +void +acquire(Context* c, Resource* resource, Value* value, Site* site) +{ + assert(c, value); + assert(c, site); + + if (not resource->reserved) { + if (DebugResources) { + char buffer[256]; resource->toString(c, buffer, 256); + fprintf(stderr, "%p acquire %s\n", value, buffer); + } + + if (resource->value) { + assert(c, findSite(c, resource->value, resource->site)); + steal(c, resource, value); + } + + resource->value = value; + resource->site = site; + } +} + +void +release(Context* c, Resource* resource, Value* value UNUSED, Site* site UNUSED) +{ + if (not resource->reserved) { + if (DebugResources) { + char buffer[256]; resource->toString(c, buffer, 256); + fprintf(stderr, "%p release %s\n", resource->value, buffer); + } + + assert(c, resource->value); + assert(c, resource->site); + + assert(c, buddies(resource->value, value)); + assert(c, site == resource->site); + + resource->value = 0; + resource->site = 0; + } +} + +class SingleRead: public Read { public: - virtual unsigned copyCost(Context* c, Site*) { - abort(c); - } - - virtual void copyTo(Context* c, unsigned, Site*) { - abort(c); - } - - virtual OperandType type(Context* c) { - abort(c); - } - - virtual Assembler::Operand* asAssemblerOperand(Context* c) { - abort(c); - } -}; - -class VirtualSite: public AbstractSite { - public: - VirtualSite(Value* value, uint8_t typeMask, uint64_t registerMask): - value(value), registerMask(registerMask), typeMask(typeMask) + SingleRead(const SiteMask& mask): + next_(0), mask(mask) { } - virtual Site* readTarget(Context* c, Read* r) { - if (value) { - Site* s = targetOrNull(c, value); - if (s and match(c, s, typeMask, registerMask)) { - return s; - } - } + virtual bool intersect(SiteMask* mask) { + *mask = ::intersect(*mask, this->mask); - Site* site = 0; - unsigned copyCost = 0xFFFFFFFF; - for (Site* s = r->value->sites; s; s = s->next) { - if (match(c, s, typeMask, registerMask)) { - unsigned v = s->copyCost(c, 0); - if (v < copyCost) { - site = s; - copyCost = v; + return true; + } + + virtual bool valid() { + return true; + } + + virtual void append(Context* c UNUSED, Read* r) { + assert(c, next_ == 0); + next_ = r; + } + + virtual Read* next(Context*) { + return next_; + } + + Read* next_; + SiteMask mask; +}; + +Read* +read(Context* c, const SiteMask& mask) +{ + assert(c, (mask.typeMask != 1 << MemoryOperand) or mask.frameIndex >= 0); + + return new (c->zone->allocate(sizeof(SingleRead))) + SingleRead(mask); +} + +Read* +anyRegisterRead(Context* c) +{ + return read(c, SiteMask(1 << RegisterOperand, ~0, NoFrameIndex)); +} + +Read* +registerOrConstantRead(Context* c) +{ + return read + (c, SiteMask + ((1 << RegisterOperand) | (1 << ConstantOperand), ~0, NoFrameIndex)); +} + +Read* +fixedRegisterRead(Context* c, int number) +{ + return read(c, SiteMask(1 << RegisterOperand, 1 << number, NoFrameIndex)); +} + +class MultiRead: public Read { + public: + MultiRead(): + reads(0), lastRead(0), firstTarget(0), lastTarget(0), visited(false) + { } + + virtual bool intersect(SiteMask* mask) { + bool result = false; + if (not visited) { + visited = true; + for (Cell** cell = &reads; *cell;) { + Read* r = static_cast((*cell)->value); + bool valid = r->intersect(mask); + if (valid) { + result = true; + cell = &((*cell)->next); + } else { + *cell = (*cell)->next; } } + visited = false; } - - if (site) { - return site; - } else { - assert(c, typeMask & (1 << RegisterOperand)); - return freeRegisterSite(c, registerMask); - } + return result; } - Value* value; - uint64_t registerMask; - uint8_t typeMask; + virtual bool valid() { + bool result = false; + if (not visited) { + visited = true; + for (Cell** cell = &reads; *cell;) { + Read* r = static_cast((*cell)->value); + if (r->valid()) { + result = true; + cell = &((*cell)->next); + } else { + *cell = (*cell)->next; + } + } + visited = false; + } + return result; + } + + virtual void append(Context* c, Read* r) { + Cell* cell = cons(c, r, 0); + if (lastRead == 0) { + reads = cell; + } else { + lastRead->next = cell; + } + lastRead = cell; + +// fprintf(stderr, "append %p to %p for %p\n", r, lastTarget, this); + + lastTarget->value = r; + } + + virtual Read* next(Context* c) { + abort(c); + } + + void allocateTarget(Context* c) { + Cell* cell = cons(c, 0, 0); + +// fprintf(stderr, "allocate target for %p: %p\n", this, cell); + + if (lastTarget) { + lastTarget->next = cell; + } else { + firstTarget = cell; + } + lastTarget = cell; + } + + Read* nextTarget() { +// fprintf(stderr, "next target for %p: %p\n", this, firstTarget); + + Read* r = static_cast(firstTarget->value); + firstTarget = firstTarget->next; + return r; + } + + Cell* reads; + Cell* lastRead; + Cell* firstTarget; + Cell* lastTarget; + bool visited; }; -VirtualSite* -virtualSite(Context* c, Value* v = 0, - uint8_t typeMask = ~static_cast(0), - uint64_t registerMask = ~static_cast(0)) +MultiRead* +multiRead(Context* c) { - return new (c->zone->allocate(sizeof(VirtualSite))) - VirtualSite(v, typeMask, registerMask); + return new (c->zone->allocate(sizeof(MultiRead))) MultiRead; } -VirtualSite* -anyRegisterSite(Context* c) -{ - return virtualSite(c, 0, 1 << RegisterOperand, ~static_cast(0)); -} - -VirtualSite* -registerOrConstantSite(Context* c) -{ - return virtualSite(c, 0, (1 << RegisterOperand) | (1 << ConstantOperand), - ~static_cast(0)); -} - -Site* -targetOrRegister(Context* c, Value* v) -{ - Site* s = targetOrNull(c, v); - if (s) { - return s; - } else { - return freeRegisterSite(c); - } -} - -Site* -pick(Context* c, Site* sites, Site* target = 0, unsigned* cost = 0) -{ - Site* site = 0; - unsigned copyCost = 0xFFFFFFFF; - for (Site* s = sites; s; s = s->next) { - unsigned v = s->copyCost(c, target); - if (v < copyCost) { - site = s; - copyCost = v; - } - } - - if (cost) *cost = copyCost; - return site; -} - -unsigned -stackOffset(Context* c) -{ - return c->localFootprint - c->parameterFootprint; -} - -Site* -pushSite(Context* c, unsigned index) -{ - return memorySite - (c, c->assembler->base(), - - (stackOffset(c) + index + 1) * BytesPerWord, NoRegister, 1); -} - -void -pushNow(Context* c, Stack* start, unsigned count) -{ - Stack* segment[count]; - unsigned index = count; - for (Stack* s = start; s and index; s = s->next) { - segment[--index] = s; - } - - for (unsigned i = 0; i < count; ++i) { - Stack* s = segment[i]; - assert(c, not s->pushed); - - if (s->value and s->value->sites) { - Site* source = pick(c, s->value->sites); - - removeMemorySites(c, s->value); - - s->pushSite = pushSite(c, s->index); - addSite(c, 0, s->size * BytesPerWord, s->value, s->pushSite); - - apply(c, Push, s->size * BytesPerWord, source); - } else { - Assembler::Register stack(c->assembler->stack()); - Assembler::Constant offset(resolved(c, s->size * BytesPerWord)); - c->assembler->apply - (Subtract, BytesPerWord, ConstantOperand, &offset, - RegisterOperand, &stack); - } - - if (DebugStack) { - fprintf(stderr, "pushed %p value: %p sites: %p\n", - s, s->value, s->value->sites); - } - - s->pushed = true; - } -} - -void -pushNow(Context* c, Stack* start) -{ - unsigned count = 0; - for (Stack* s = start; s and (not s->pushed); s = s->next) { - ++ count; - } - - pushNow(c, start, count); -} - -bool -trySteal(Context* c, Register* r, Stack* stack) -{ - assert(c, r->refCount == 0); - - Value* v = r->value; - - if (DebugRegisters) { - fprintf(stderr, "try steal %d from %p: next: %p\n", - r->number, v, v->sites->next); - } - - if (v->sites->next == 0) { - unsigned count = 0; - Stack* start = 0; - for (Stack* s = stack; s and (not s->pushed); s = s->next) { - if (start == 0 and s->value == v) { - start = s; - } - if (start) { - ++ count; - } - } - - if (start) { - if (DebugRegisters) { - fprintf(stderr, "push %p\n", v); - } - pushNow(c, start, count); - } else { - if (DebugRegisters) { - fprintf(stderr, "unable to steal %d from %p\n", r->number, v); - } - return false; - } - } - - removeSite(c, v, r->site); - - return true; -} - -bool -used(Context* c, Register* r) -{ - Value* v = r->value; - return v and findSite(c, v, r->site); -} - -bool -usedExclusively(Context* c, Register* r) -{ - return used(c, r) and r->value->sites->next == 0; -} - -unsigned -registerCost(Context* c, Register* r) -{ - if (r->reserved or r->freezeCount) { - return 6; - } - - unsigned cost = 0; - - if (used(c, r)) { - ++ cost; - if (usedExclusively(c, r)) { - cost += 2; - } - } - - if (r->refCount) { - cost += 2; - } - - return cost; -} - -Register* -pickRegister(Context* c, uint32_t mask) -{ - Register* register_ = 0; - unsigned cost = 5; - for (int i = c->assembler->registerCount() - 1; i >= 0; --i) { - if ((1 << i) & mask) { - Register* r = c->registers[i]; - if ((static_cast(1) << i) == mask) { - return r; - } - - unsigned myCost = registerCost(c, r); - if (myCost < cost) { - register_ = r; - cost = myCost; - } - } - } - - expect(c, register_); - - return register_; -} - -void -swap(Context* c, Register* a, Register* b) -{ - assert(c, a != b); - assert(c, a->number != b->number); - - Assembler::Register ar(a->number); - Assembler::Register br(b->number); - c->assembler->apply - (Swap, BytesPerWord, RegisterOperand, &ar, RegisterOperand, &br); - - c->registers[a->number] = b; - c->registers[b->number] = a; - - int t = a->number; - a->number = b->number; - b->number = t; -} - -Register* -replace(Context* c, Stack* stack, Register* r) -{ - uint32_t mask = (r->freezeCount? r->site->mask : ~0); - - freeze(r); - Register* s = acquire(c, mask, stack, r->size, r->value, r->site); - thaw(r); - - if (DebugRegisters) { - fprintf(stderr, "replace %d with %d\n", r->number, s->number); - } - - swap(c, r, s); - - return s; -} - -Register* -acquire(Context* c, uint32_t mask, Stack* stack, unsigned newSize, - Value* newValue, RegisterSite* newSite) -{ - Register* r = pickRegister(c, mask); - - if (r->reserved) return r; - - if (DebugRegisters) { - fprintf(stderr, "acquire %d, value %p, site %p freeze count %d ref count %d used %d used exclusively %d\n", - r->number, newValue, newSite, r->freezeCount, r->refCount, used(c, r), usedExclusively(c, r)); - } - - if (r->refCount) { - r = replace(c, stack, r); - } else { - Value* oldValue = r->value; - if (oldValue - and oldValue != newValue - and findSite(c, oldValue, r->site)) - { - if (not trySteal(c, r, stack)) { - r = replace(c, stack, r); - } - } - } - - r->size = newSize; - r->value = newValue; - r->site = newSite; - - return r; -} - -void -release(Context*, Register* r) -{ - if (DebugRegisters) { - fprintf(stderr, "release %d\n", r->number); - } - - r->size = 0; - r->value = 0; - r->site = 0; -} - -Register* -validate(Context* c, uint32_t mask, Stack* stack, unsigned size, - Value* value, RegisterSite* site, Register* current) -{ - if (current and (mask & (1 << current->number))) { - if (current->reserved or current->value == value) { - return current; - } - - if (current->value == 0) { - current->size = size; - current->value = value; - current->site = site; - return current; - } else { - abort(c); - } - } - - Register* r = acquire(c, mask, stack, size, value, site); - - if (current and current != r) { - release(c, current); - - Assembler::Register rr(r->number); - Assembler::Register cr(current->number); - c->assembler->apply - (Move, BytesPerWord, RegisterOperand, &cr, RegisterOperand, &rr); - } - - return r; -} - -void -apply(Context* c, UnaryOperation op, unsigned size, Site* a) -{ - OperandType type = a->type(c); - Assembler::Operand* operand = a->asAssemblerOperand(c); - - c->assembler->apply(op, size, type, operand); -} - -void -apply(Context* c, BinaryOperation op, unsigned size, Site* a, Site* b) -{ - OperandType aType = a->type(c); - Assembler::Operand* aOperand = a->asAssemblerOperand(c); - - OperandType bType = b->type(c); - Assembler::Operand* bOperand = b->asAssemblerOperand(c); - - c->assembler->apply(op, size, aType, aOperand, bType, bOperand); -} - -void -insertRead(Context* c, Event* event, int sequence, Value* v, - unsigned size, Site* target) -{ - Read* r = new (c->zone->allocate(sizeof(Read))) - Read(size, v, target, 0, event, event->reads); - event->reads = r; - ++ event->readCount; - - // fprintf(stderr, "add read %p to %p\n", r, v); - - if (sequence >= 0) { - for (Read** p = &(v->reads); *p;) { - if ((*p)->event->sequence > static_cast(sequence)) { - r->next = *p; - *p = r; - break; - } else { - p = &((*p)->next); - } - } - } - - if (r->next == 0) { - if (v->lastRead) { - v->lastRead->next = r; - } else { - v->reads = r; - } - v->lastRead = r; - } -} - -void -addRead(Context* c, Value* v, unsigned size, Site* target) -{ - insertRead(c, c->logicalCode[c->logicalIp].lastEvent, -1, v, size, target); -} - -Site* -pushSite(Context*, PushEvent*); - -class PushEvent: public Event { +class StubRead: public Read { public: - PushEvent(Context* c, Stack* s): - Event(c), s(s), active(false) - { - assert(c, s->pushEvent == 0); + StubRead(): + next_(0), read(0), visited(false), valid_(true) + { } - s->pushEvent = this; - addRead(c, s->value, s->size * BytesPerWord, pushSite(c, this)); - } - - virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "PushEvent.compile active: %d\n", active); + virtual bool intersect(SiteMask* mask) { + if (not visited) { + visited = true; + if (read) { + bool valid = read->intersect(mask); + if (not valid) { + read = 0; + } + } + visited = false; } - - if (active) { - pushNow(c, s); - } - - nextRead(c, s->value); + return valid_; } - virtual bool skipMove(unsigned size) { - return active and size >= BytesPerWord; + virtual bool valid() { + return valid_; } - Stack* s; - bool active; + virtual void append(Context* c UNUSED, Read* r) { + assert(c, next_ == 0); + next_ = r; + } + + virtual Read* next(Context*) { + return next_; + } + + Read* next_; + Read* read; + bool visited; + bool valid_; +}; + +StubRead* +stubRead(Context* c) +{ + return new (c->zone->allocate(sizeof(StubRead))) StubRead; +} + +void +asAssemblerOperand(Context* c, Site* low, Site* high, + Assembler::Operand* result) +{ + low->asAssemblerOperand(c, high, result); +} + +class OperandUnion: public Assembler::Operand { + // must be large enough and aligned properly to hold any operand + // type (we'd use an actual union type here, except that classes + // with constructors cannot be used in a union): + uintptr_t padding[4]; }; void -push(Context* c, unsigned size, Value* v); +apply(Context* c, UnaryOperation op, + unsigned s1Size, Site* s1Low, Site* s1High) +{ + assert(c, s1High == 0 or s1Low->type(c) == s1High->type(c)); + + OperandType s1Type = s1Low->type(c); + OperandUnion s1Union; asAssemblerOperand(c, s1Low, s1High, &s1Union); + + c->assembler->apply(op, s1Size, s1Type, &s1Union); +} void -ignore(Context* c, unsigned count) +apply(Context* c, BinaryOperation op, + unsigned s1Size, Site* s1Low, Site* s1High, + unsigned s2Size, Site* s2Low, Site* s2High) { - if (count) { - Assembler::Register stack(c->assembler->stack()); - Assembler::Constant offset(resolved(c, count * BytesPerWord)); - c->assembler->apply - (Add, BytesPerWord, ConstantOperand, &offset, RegisterOperand, &stack); + assert(c, s1High == 0 or s1Low->type(c) == s1High->type(c)); + assert(c, s2High == 0 or s2Low->type(c) == s2High->type(c)); + + OperandType s1Type = s1Low->type(c); + OperandUnion s1Union; asAssemblerOperand(c, s1Low, s1High, &s1Union); + + OperandType s2Type = s2Low->type(c); + OperandUnion s2Union; asAssemblerOperand(c, s2Low, s2High, &s2Union); + + c->assembler->apply(op, s1Size, s1Type, &s1Union, + s2Size, s2Type, &s2Union); +} + +void +apply(Context* c, TernaryOperation op, + unsigned s1Size, Site* s1Low, Site* s1High, + unsigned s2Size, Site* s2Low, Site* s2High, + unsigned s3Size, Site* s3Low, Site* s3High) +{ + assert(c, s1High == 0 or s1Low->type(c) == s1High->type(c)); + assert(c, s2High == 0 or s2Low->type(c) == s2High->type(c)); + assert(c, s3High == 0 or s3Low->type(c) == s3High->type(c)); + + OperandType s1Type = s1Low->type(c); + OperandUnion s1Union; asAssemblerOperand(c, s1Low, s1High, &s1Union); + + OperandType s2Type = s2Low->type(c); + OperandUnion s2Union; asAssemblerOperand(c, s2Low, s2High, &s2Union); + + OperandType s3Type = s3Low->type(c); + OperandUnion s3Union; asAssemblerOperand(c, s3Low, s3High, &s3Union); + + c->assembler->apply(op, s1Size, s1Type, &s1Union, + s2Size, s2Type, &s2Union, + s3Size, s3Type, &s3Union); +} + +void +addRead(Context* c, Event* e, Value* v, Read* r) +{ + if (DebugReads) { + fprintf(stderr, "add read %p to %p last %p event %p (%s)\n", r, v, v->lastRead, e, (e ? e->name() : 0)); + } + + r->value = v; + if (e) { + r->event = e; + r->eventNext = e->reads; + e->reads = r; + ++ e->readCount; + } + + if (v->lastRead) { +// if (DebugReads) { +// fprintf(stderr, "append %p to %p for %p\n", r, v->lastRead, v); +// } + + v->lastRead->append(c, r); + } else { + v->reads = r; + } + v->lastRead = r; +} + +void +clean(Context* c, Value* v, unsigned popIndex) +{ + for (SiteIterator it(v); it.hasMore();) { + Site* s = it.next(); + if (not (s->match(c, SiteMask(1 << MemoryOperand, 0, AnyFrameIndex)) + and offsetToFrameIndex + (c, static_cast(s)->offset) + >= popIndex)) + { + if (false) { + char buffer[256]; s->toString(c, buffer, 256); + fprintf(stderr, "remove %s from %p at %d pop index %d\n", + buffer, v, offsetToFrameIndex + (c, static_cast(s)->offset), popIndex); + } + it.remove(c); + } } } void -cleanStack(Context* c, Stack* stack, Local* locals, Read* reads) +clean(Context* c, Event* e, Stack* stack, Local* locals, Read* reads, + unsigned popIndex) { - for (Local* l = locals; l; l = l->next) { - l->reuse = false; - } - - for (Stack* s = stack; s; s = s->next) { - clearSites(c, s->value); - } - - for (Stack* s = stack; s; s = s->next) { - if (s->pushSite) { - addSite(c, 0, s->size * BytesPerWord, s->value, s->pushSite); - } + for (FrameIterator it(c, stack, locals); it.hasMore();) { + FrameIterator::Element e = it.next(c); + clean(c, e.value, popIndex); } for (Read* r = reads; r; r = r->eventNext) { - nextRead(c, r->value); + popRead(c, e, r->value); } } -void -resetLocals(Context* c) -{ - for (Local* l = c->locals; l; l = l->next) { - c->localTable[l->index] = 0; - } - c->locals = 0; -} - CodePromise* codePromise(Context* c, Event* e) { @@ -1354,109 +2170,185 @@ codePromise(Context* c, Event* e) } CodePromise* -codePromise(Context* c, int offset) +codePromise(Context* c, Promise* offset) { return new (c->zone->allocate(sizeof(CodePromise))) CodePromise(c, offset); } void -appendPush(Context* c, Stack* s); +append(Context* c, Event* e); + +void +saveLocals(Context* c, Event* e) +{ + for (unsigned li = 0; li < c->localFootprint; ++li) { + Local* local = e->localsBefore + li; + if (local->value) { + if (DebugReads) { + fprintf(stderr, "local save read %p at %d of %d\n", + local->value, ::frameIndex(c, li), + c->alignedFrameSize + c->parameterFootprint); + } + + addRead(c, e, local->value, read + (c, SiteMask(1 << MemoryOperand, 0, ::frameIndex(c, li)))); + } + } +} class CallEvent: public Event { public: CallEvent(Context* c, Value* address, unsigned flags, TraceHandler* traceHandler, Value* result, unsigned resultSize, - Stack* argumentStack, unsigned argumentCount): + Stack* argumentStack, unsigned argumentCount, + unsigned stackArgumentFootprint): Event(c), address(address), traceHandler(traceHandler), result(result), + popIndex(0), + padIndex(0), + padding(0), flags(flags), - resultSize(resultSize), - argumentFootprint(0) + resultSize(resultSize) { - uint32_t mask = ~0; + uint32_t registerMask = ~0; Stack* s = argumentStack; unsigned index = 0; - for (unsigned i = 0; i < argumentCount; ++i) { - Site* target; - if (index < c->assembler->argumentRegisterCount()) { - int r = c->assembler->argumentRegister(index); - target = fixedRegisterSite(c, r); - mask &= ~(1 << r); - } else { - target = 0; - s->pushEvent->active = true; - argumentFootprint += s->size; + unsigned frameIndex = 0; + + if (argumentCount) { + while (true) { + Read* target; + if (index < c->arch->argumentRegisterCount()) { + int number = c->arch->argumentRegister(index); + + if (DebugReads) { + fprintf(stderr, "reg %d arg read %p\n", number, s->value); + } + + target = fixedRegisterRead(c, number); + registerMask &= ~(1 << number); + } else { + if (DebugReads) { + fprintf(stderr, "stack %d arg read %p\n", frameIndex, s->value); + } + + target = read(c, SiteMask(1 << MemoryOperand, 0, frameIndex)); + ++ frameIndex; + } + addRead(c, this, s->value, target); + + if ((++ index) < argumentCount) { + s = s->next; + } else { + break; + } } - addRead(c, s->value, s->size * BytesPerWord, target); - index += s->size; - s = s->next; } - addRead(c, address, BytesPerWord, virtualSite - (c, 0, ~0, (static_cast(mask) << 32) | mask)); - - for (Stack* s = stack; s; s = s->next) { - if (s->pushEvent == 0) { - appendPush(c, s); - } - s->pushEvent->active = true; - addRead(c, s->value, s->size * BytesPerWord, virtualSite - (c, 0, ~0, (static_cast(mask) << 32) | mask)); + if (DebugReads) { + fprintf(stderr, "address read %p\n", address); } - resetLocals(c); + addRead(c, this, address, read + (c, SiteMask(~0, registerMask, AnyFrameIndex))); + + int footprint = stackArgumentFootprint; + for (Stack* s = stackBefore; s; s = s->next) { + if (s->value) { + if (footprint > 0) { + if (DebugReads) { + fprintf(stderr, "stack arg read %p at %d of %d\n", + s->value, frameIndex, + c->alignedFrameSize + c->parameterFootprint); + } + + addRead(c, this, s->value, read + (c, SiteMask(1 << MemoryOperand, 0, frameIndex))); + } else { + unsigned logicalIndex = ::frameIndex + (c, s->index + c->localFootprint); + + if (DebugReads) { + fprintf(stderr, "stack save read %p at %d of %d\n", + s->value, logicalIndex, + c->alignedFrameSize + c->parameterFootprint); + } + + addRead(c, this, s->value, read + (c, SiteMask(1 << MemoryOperand, 0, logicalIndex))); + } + } + + -- footprint; + + if (footprint == 0) { + unsigned logicalIndex = ::frameIndex(c, s->index + c->localFootprint); + + assert(c, logicalIndex >= frameIndex); + + padding = logicalIndex - frameIndex; + padIndex = s->index + c->localFootprint; + } + + ++ frameIndex; + } + + popIndex + = c->alignedFrameSize + + c->parameterFootprint + - (stackBefore ? stackBefore->index + 1 - stackArgumentFootprint : 0) + - c->localFootprint; + + assert(c, static_cast(popIndex) >= 0); + + saveLocals(c, this); + } + + virtual const char* name() { + return "CallEvent"; } virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "CallEvent.compile\n"); - } - - pushNow(c, stack); - - UnaryOperation type = ((flags & Compiler::Aligned) ? AlignedCall : Call); - apply(c, type, BytesPerWord, address->source); + apply(c, (flags & Compiler::Aligned) ? AlignedCall : Call, BytesPerWord, + address->source, 0); if (traceHandler) { - traceHandler->handleTrace(codePromise(c, c->assembler->length())); + traceHandler->handleTrace(codePromise(c, c->assembler->offset()), + padIndex, padding); } - cleanStack(c, stack, locals, reads); + clean(c, this, stackBefore, localsBefore, reads, popIndex); - if (resultSize and result->reads) { - addSite(c, 0, resultSize, result, registerSite - (c, c->assembler->returnLow(), - resultSize > BytesPerWord ? - c->assembler->returnHigh() : NoRegister)); - } - - if (argumentFootprint and ((flags & Compiler::NoReturn) == 0)) { - ignore(c, argumentFootprint); + if (resultSize and live(result)) { + addSite(c, result, registerSite(c, c->arch->returnLow())); + if (resultSize > BytesPerWord and live(result->high)) { + addSite(c, result->high, registerSite(c, c->arch->returnHigh())); + } } } Value* address; TraceHandler* traceHandler; Value* result; + unsigned popIndex; + unsigned padIndex; + unsigned padding; unsigned flags; unsigned resultSize; - unsigned argumentFootprint; }; void appendCall(Context* c, Value* address, unsigned flags, TraceHandler* traceHandler, Value* result, unsigned resultSize, - Stack* argumentStack, unsigned argumentCount) + Stack* argumentStack, unsigned argumentCount, + unsigned stackArgumentFootprint) { - if (DebugAppend) { - fprintf(stderr, "appendCall\n"); - } - - new (c->zone->allocate(sizeof(CallEvent))) - CallEvent(c, address, flags, traceHandler, result, - resultSize, argumentStack, argumentCount); + append(c, new (c->zone->allocate(sizeof(CallEvent))) + CallEvent(c, address, flags, traceHandler, result, + resultSize, argumentStack, argumentCount, + stackArgumentFootprint)); } class ReturnEvent: public Event { @@ -1465,28 +2357,24 @@ class ReturnEvent: public Event { Event(c), value(value) { if (value) { - addRead(c, value, size, fixedRegisterSite - (c, c->assembler->returnLow(), - size > BytesPerWord ? - c->assembler->returnHigh() : NoRegister)); + addRead(c, this, value, fixedRegisterRead(c, c->arch->returnLow())); + if (size > BytesPerWord) { + addRead(c, this, value->high, + fixedRegisterRead(c, c->arch->returnHigh())); + } } } + virtual const char* name() { + return "ReturnEvent"; + } + virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "ReturnEvent.compile\n"); + for (Read* r = reads; r; r = r->eventNext) { + popRead(c, this, r->value); } - - if (value) { - nextRead(c, value); - } - - Assembler::Register base(c->assembler->base()); - Assembler::Register stack(c->assembler->stack()); - - c->assembler->apply(Move, BytesPerWord, RegisterOperand, &base, - RegisterOperand, &stack); - c->assembler->apply(Pop, BytesPerWord, RegisterOperand, &base); + + c->assembler->popFrame(); c->assembler->apply(Return); } @@ -1496,120 +2384,279 @@ class ReturnEvent: public Event { void appendReturn(Context* c, unsigned size, Value* value) { - if (DebugAppend) { - fprintf(stderr, "appendReturn\n"); + append(c, new (c->zone->allocate(sizeof(ReturnEvent))) + ReturnEvent(c, size, value)); +} + +void +addBuddy(Value* original, Value* buddy) +{ + buddy->buddy = original; + Value* p = original; + while (p->buddy != original) p = p->buddy; + p->buddy = buddy; + + if (DebugBuddies) { + fprintf(stderr, "add buddy %p to", buddy); + for (Value* p = buddy->buddy; p != buddy; p = p->buddy) { + fprintf(stderr, " %p", p); + } + fprintf(stderr, "\n"); + } +} + +void +maybeMove(Context* c, BinaryOperation type, unsigned srcSize, Value* src, + unsigned dstSize, Value* dst, const SiteMask& dstMask) +{ + Read* read = live(dst); + bool isStore = read == 0; + + Site* target; + if (dst->target) { + target = dst->target; + } else if (isStore) { + return; + } else { + target = pickTargetSite(c, read); } - new (c->zone->allocate(sizeof(ReturnEvent))) ReturnEvent(c, size, value); + unsigned cost = src->source->copyCost(c, target); + + if (srcSize != dstSize) cost = 1; + + if (cost) { + bool useTemporary = ((target->type(c) == MemoryOperand + and src->source->type(c) == MemoryOperand) + or (srcSize != dstSize + and target->type(c) != RegisterOperand)); + + addSite(c, dst, target); + + if (target->match(c, dstMask) and not useTemporary) { + if (DebugMoves) { + char srcb[256]; src->source->toString(c, srcb, 256); + char dstb[256]; target->toString(c, dstb, 256); + fprintf(stderr, "move %s to %s for %p to %p\n", + srcb, dstb, src, dst); + } + + apply(c, type, srcSize, src->source, 0, dstSize, target, 0); + } else { + target->freeze(c, dst); + + assert(c, dstMask.typeMask & (1 << RegisterOperand)); + + Site* tmpTarget = freeRegisterSite(c, dstMask.registerMask); + + addSite(c, dst, tmpTarget); + + if (DebugMoves) { + char srcb[256]; src->source->toString(c, srcb, 256); + char dstb[256]; tmpTarget->toString(c, dstb, 256); + fprintf(stderr, "move %s to %s for %p to %p\n", + srcb, dstb, src, dst); + } + + apply(c, type, srcSize, src->source, 0, dstSize, tmpTarget, 0); + + if (useTemporary or isStore) { + if (DebugMoves) { + char srcb[256]; tmpTarget->toString(c, srcb, 256); + char dstb[256]; target->toString(c, dstb, 256); + fprintf(stderr, "move %s to %s for %p to %p\n", + srcb, dstb, src, dst); + } + + apply(c, Move, dstSize, tmpTarget, 0, dstSize, target, 0); + + if (isStore) { + removeSite(c, dst, tmpTarget); + } + } else { + removeSite(c, dst, target); + } + + target->thaw(c, dst); + } + } else { + target = src->source; + + addBuddy(src, dst); + + if (DebugMoves) { + char dstb[256]; target->toString(c, dstb, 256); + fprintf(stderr, "null move in %s for %p to %p\n", dstb, src, dst); + } + } + + if (isStore) { + removeSite(c, dst, target); + } +} + +Value* +value(Context* c, Site* site = 0, Site* target = 0) +{ + return new (c->zone->allocate(sizeof(Value))) Value(site, target); +} + +void +split(Context* c, Value* v) +{ + assert(c, v->high == 0); + + v->high = value(c); + for (SiteIterator it(v); it.hasMore();) { + Site* s = it.next(); + removeSite(c, v, s); + + addSite(c, v, s->copyLow(c)); + addSite(c, v->high, s->copyHigh(c)); + } +} + +void +maybeSplit(Context* c, Value* v) +{ + if (v->high == 0) { + split(c, v); + } +} + +void +grow(Context* c, Value* v) +{ + assert(c, v->high == 0); + + v->high = value(c); } class MoveEvent: public Event { public: - MoveEvent(Context* c, BinaryOperation type, unsigned size, Value* src, - Value* dst, Site* srcTarget, VirtualSite* dstTarget): - Event(c), type(type), size(size), src(src), dst(dst), dstTarget(dstTarget) + MoveEvent(Context* c, BinaryOperation type, unsigned srcSize, Value* src, + unsigned dstSize, Value* dst, + const SiteMask& srcLowMask, const SiteMask& srcHighMask, + const SiteMask& dstLowMask, const SiteMask& dstHighMask): + Event(c), type(type), srcSize(srcSize), src(src), dstSize(dstSize), + dst(dst), dstLowMask(dstLowMask), dstHighMask(dstHighMask) { - addRead(c, src, size, srcTarget); + addRead(c, this, src, read(c, srcLowMask)); + if (srcSize > BytesPerWord) { + maybeSplit(c, src); + addRead(c, this, src->high, read(c, srcHighMask)); + } + + if (dstSize > BytesPerWord) { + grow(c, dst); + } + } + + virtual const char* name() { + return "MoveEvent"; } virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "MoveEvent.compile\n"); - } + if (srcSize <= BytesPerWord and dstSize <= BytesPerWord) { + maybeMove(c, type, srcSize, src, dstSize, dst, dstLowMask); + } else if (srcSize == dstSize) { + maybeMove(c, Move, BytesPerWord, src, BytesPerWord, dst, dstLowMask); + maybeMove(c, Move, BytesPerWord, src->high, + BytesPerWord, dst->high, dstHighMask); + } else if (srcSize > BytesPerWord) { + assert(c, dstSize == BytesPerWord); - bool isLoad = src->reads->next == 0; - bool isStore = dst->reads == 0; - - Site* target; - unsigned cost; - if (type == Move - and dst->reads - and next == dst->reads->event - and dst->reads->event->skipMove(size)) - { - target = src->source; - cost = 0; + maybeMove(c, Move, BytesPerWord, src, BytesPerWord, dst, dstLowMask); } else { - target = targetOrRegister(c, dst); - cost = src->source->copyCost(c, target); - if (cost == 0 and (isLoad or isStore)) { - target = src->source; - } - } + assert(c, srcSize == BytesPerWord); - assert(c, isLoad or isStore or target != src->source); + if (dst->high->target or live(dst->high)) { + assert(c, dstLowMask.typeMask & (1 << RegisterOperand)); - if (target == src->source) { - removeSite(c, src, target); - } + Site* low = freeRegisterSite(c, dstLowMask.registerMask); - if (not isStore) { - addSite(c, stack, size, dst, target); - } + src->source->freeze(c, src); - if (cost or type != Move) { - if (match(c, target, dstTarget->typeMask, dstTarget->registerMask)) { - apply(c, type, size, src->source, target); - } else { - assert(c, dstTarget->typeMask & (1 << RegisterOperand)); + addSite(c, dst, low); - Site* tmpTarget = freeRegisterSite(c, dstTarget->registerMask); - - addSite(c, stack, size, dst, tmpTarget); - - apply(c, type, size, src->source, tmpTarget); - - if (isStore) { - removeSite(c, dst, tmpTarget); - - apply(c, Move, size, tmpTarget, target); - } else { - removeSite(c, dst, target); + src->source->thaw(c, src); + + if (DebugMoves) { + char srcb[256]; src->source->toString(c, srcb, 256); + char dstb[256]; low->toString(c, dstb, 256); + fprintf(stderr, "move %s to %s for %p\n", + srcb, dstb, src); } + + apply(c, Move, BytesPerWord, src->source, 0, BytesPerWord, low, 0); + + assert(c, dstHighMask.typeMask & (1 << RegisterOperand)); + + Site* high = freeRegisterSite(c, dstHighMask.registerMask); + + low->freeze(c, dst); + + addSite(c, dst->high, high); + + low->thaw(c, dst); + + if (DebugMoves) { + char srcb[256]; low->toString(c, srcb, 256); + char dstb[256]; high->toString(c, dstb, 256); + fprintf(stderr, "extend %s to %s for %p %p\n", + srcb, dstb, dst, dst->high); + } + + apply(c, Move, BytesPerWord, low, 0, dstSize, low, high); + } else { + maybeMove(c, Move, BytesPerWord, src, BytesPerWord, dst, dstLowMask); } } - if (isStore) { - removeSite(c, dst, target); + for (Read* r = reads; r; r = r->eventNext) { + popRead(c, this, r->value); } - - nextRead(c, src); } BinaryOperation type; - unsigned size; + unsigned srcSize; Value* src; + unsigned dstSize; Value* dst; - VirtualSite* dstTarget; + SiteMask dstLowMask; + SiteMask dstHighMask; }; void -appendMove(Context* c, BinaryOperation type, unsigned size, Value* src, - Value* dst) +appendMove(Context* c, BinaryOperation type, unsigned srcSize, Value* src, + unsigned dstSize, Value* dst) { - if (DebugAppend) { - fprintf(stderr, "appendMove\n"); - } - - VirtualSite* srcTarget = virtualSite(c, dst); - VirtualSite* dstTarget = virtualSite(c); bool thunk; + uint8_t srcTypeMask; + uint64_t srcRegisterMask; + uint8_t dstTypeMask; + uint64_t dstRegisterMask; - c->assembler->plan(type, size, - &(srcTarget->typeMask), &(srcTarget->registerMask), - &(dstTarget->typeMask), &(dstTarget->registerMask), - &thunk); + c->arch->plan(type, srcSize, &srcTypeMask, &srcRegisterMask, + dstSize, &dstTypeMask, &dstRegisterMask, + &thunk); - assert(c, not thunk); // todo + assert(c, not thunk); - new (c->zone->allocate(sizeof(MoveEvent))) - MoveEvent(c, type, size, src, dst, srcTarget, dstTarget); + append(c, new (c->zone->allocate(sizeof(MoveEvent))) + MoveEvent + (c, type, srcSize, src, dstSize, dst, + SiteMask(srcTypeMask, srcRegisterMask, AnyFrameIndex), + SiteMask(srcTypeMask, srcRegisterMask >> 32, AnyFrameIndex), + SiteMask(dstTypeMask, dstRegisterMask, AnyFrameIndex), + SiteMask(dstTypeMask, dstRegisterMask >> 32, AnyFrameIndex))); } ConstantSite* findConstantSite(Context* c, Value* v) { - for (Site* s = v->sites; s; s = s->next) { + for (SiteIterator it(v); it.hasMore();) { + Site* s = it.next(); if (s->type(c) == ConstantOperand) { return static_cast(s); } @@ -1620,24 +2667,24 @@ findConstantSite(Context* c, Value* v) class CompareEvent: public Event { public: CompareEvent(Context* c, unsigned size, Value* first, Value* second, - Site* firstTarget, Site* secondTarget): + const SiteMask& firstMask, const SiteMask& secondMask): Event(c), size(size), first(first), second(second) { - addRead(c, first, size, firstTarget); - addRead(c, second, size, secondTarget); + addRead(c, this, first, read(c, firstMask)); + addRead(c, this, second, read(c, secondMask)); + } + + virtual const char* name() { + return "CompareEvent"; } virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "CompareEvent.compile\n"); - } - ConstantSite* firstConstant = findConstantSite(c, first); ConstantSite* secondConstant = findConstantSite(c, second); if (firstConstant and secondConstant) { - int64_t d = firstConstant->value.value->value() - - secondConstant->value.value->value(); + int64_t d = firstConstant->value->value() + - secondConstant->value->value(); if (d < 0) { c->constantCompare = CompareLess; @@ -1649,11 +2696,11 @@ class CompareEvent: public Event { } else { c->constantCompare = CompareNone; - apply(c, Compare, size, first->source, second->source); + apply(c, Compare, size, first->source, 0, size, second->source, 0); } - nextRead(c, first); - nextRead(c, second); + popRead(c, this, first); + popRead(c, this, second); } unsigned size; @@ -1664,198 +2711,525 @@ class CompareEvent: public Event { void appendCompare(Context* c, unsigned size, Value* first, Value* second) { - VirtualSite* firstTarget = virtualSite(c); - VirtualSite* secondTarget = virtualSite(c); bool thunk; + uint8_t firstTypeMask; + uint64_t firstRegisterMask; + uint8_t secondTypeMask; + uint64_t secondRegisterMask; - c->assembler->plan(Compare, size, - &(firstTarget->typeMask), &(firstTarget->registerMask), - &(secondTarget->typeMask), &(secondTarget->registerMask), - &thunk); + c->arch->plan(Compare, size, &firstTypeMask, &firstRegisterMask, + size, &secondTypeMask, &secondRegisterMask, + &thunk); assert(c, not thunk); // todo - if (DebugAppend) { - fprintf(stderr, "appendCompare\n"); + append(c, new (c->zone->allocate(sizeof(CompareEvent))) + CompareEvent + (c, size, first, second, + SiteMask(firstTypeMask, firstRegisterMask, AnyFrameIndex), + SiteMask(secondTypeMask, secondRegisterMask, AnyFrameIndex))); +} + +void +preserve(Context* c, Value* v, Site* s, Read* r) +{ + s->freeze(c, v); + + move(c, v, s, pickTargetSite(c, r)); + + s->thaw(c, v); +} + +void +maybePreserve(Context* c, Value* v, Site* s) +{ + Read* r = liveNext(c, v); + if (r and not hasMoreThanOneSite(v)) { + preserve(c, v, s, r); } +} - new (c->zone->allocate(sizeof(CompareEvent))) - CompareEvent(c, size, first, second, firstTarget, secondTarget); +Site* +getTarget(Context* c, Value* value, Value* result, const SiteMask& resultMask) +{ + if (c->arch->condensedAddressing()) { + Site* s = value->source; + + maybePreserve(c, value, s); + + removeSite(c, value, s); + + s->freeze(c, value); + + return s; + } else { + SingleRead r(resultMask); + Site* s = pickTargetSite(c, &r); + + addSite(c, result, s); + + return s; + } +} + +Site* +source(Value* v) +{ + return v ? v->source : 0; } void -preserve(Context* c, Stack* stack, unsigned size, Value* v, Site* s, - Read* read) +freezeSource(Context* c, unsigned size, Value* v) { - assert(c, v->sites == s); - Site* r = targetOrNull(c, read); - if (r == 0 or r == s) r = freeRegisterSite(c); - addSite(c, stack, size, v, r); - apply(c, Move, size, s, r); + v->source->freeze(c, v); + if (size > BytesPerWord) { + v->high->source->freeze(c, v->high); + } } void -maybePreserve(Context* c, Stack* stack, unsigned size, Value* v, Site* s) +thawSource(Context* c, unsigned size, Value* v) { - if (v->reads->next and v->sites->next == 0) { - preserve(c, stack, size, v, s, v->reads->next); + v->source->thaw(c, v); + if (size > BytesPerWord) { + v->high->source->thaw(c, v->high); } } class CombineEvent: public Event { public: - CombineEvent(Context* c, BinaryOperation type, unsigned size, Value* first, - Value* second, Value* result, Site* firstTarget, - Site* secondTarget): - Event(c), type(type), size(size), first(first), second(second), - result(result) + CombineEvent(Context* c, TernaryOperation type, + unsigned firstSize, Value* first, + unsigned secondSize, Value* second, + unsigned resultSize, Value* result, + const SiteMask& firstLowMask, + const SiteMask& firstHighMask, + const SiteMask& secondLowMask, + const SiteMask& secondHighMask, + const SiteMask& resultLowMask, + const SiteMask& resultHighMask): + Event(c), type(type), firstSize(firstSize), first(first), + secondSize(secondSize), second(second), resultSize(resultSize), + result(result), resultLowMask(resultLowMask), + resultHighMask(resultHighMask) { - // todo: we should really specify the sizes of each operand - // seperately for binary operations. The following is a hack - // until then. - unsigned firstSize; - switch (type) { - case ShiftLeft: - case ShiftRight: - case UnsignedShiftRight: - firstSize = 4; - break; - - default: - firstSize = size; - break; + addRead(c, this, first, read(c, firstLowMask)); + if (firstSize > BytesPerWord) { + addRead(c, this, first->high, read(c, firstHighMask)); } - addRead(c, first, firstSize, firstTarget); - addRead(c, second, size, secondTarget); + addRead(c, this, second, read(c, secondLowMask)); + if (secondSize > BytesPerWord) { + addRead(c, this, second->high, read(c, secondHighMask)); + } + + if (resultSize > BytesPerWord) { + grow(c, result); + } + } + + virtual const char* name() { + return "CombineEvent"; } virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "CombineEvent.compile\n"); + freezeSource(c, firstSize, first); + + Site* low = getTarget(c, second, result, resultLowMask); + Site* high + = (resultSize > BytesPerWord + ? getTarget(c, second->high, result->high, resultHighMask) + : 0); + +// fprintf(stderr, "combine %p and %p into %p\n", first, second, result); + apply(c, type, firstSize, first->source, source(first->high), + secondSize, second->source, source(second->high), + resultSize, low, high); + + thawSource(c, firstSize, first); + + for (Read* r = reads; r; r = r->eventNext) { + popRead(c, this, r->value); } - maybePreserve(c, stack, size, second, second->source); + if (c->arch->condensedAddressing()) { + low->thaw(c, second); + if (resultSize > BytesPerWord) { + high->thaw(c, second->high); + } - apply(c, type, size, first->source, second->source); - - nextRead(c, first); - nextRead(c, second); - - removeSite(c, second, second->source); - if (result->reads) { - addSite(c, 0, size, result, second->source); + if (live(result)) { + addSite(c, result, low); + if (resultSize > BytesPerWord and live(result->high)) { + addSite(c, result->high, high); + } + } } } - BinaryOperation type; - unsigned size; + TernaryOperation type; + unsigned firstSize; Value* first; + unsigned secondSize; Value* second; + unsigned resultSize; Value* result; + SiteMask resultLowMask; + SiteMask resultHighMask; }; void -appendStackSync(Context* c); +removeBuddy(Context* c, Value* v) +{ + if (v->buddy != v) { + if (DebugBuddies) { + fprintf(stderr, "remove buddy %p from", v); + for (Value* p = v->buddy; p != v; p = p->buddy) { + fprintf(stderr, " %p", p); + } + fprintf(stderr, "\n"); + } + + Value* next = v->buddy; + v->buddy = v; + Value* p = next; + while (p->buddy != v) p = p->buddy; + p->buddy = next; + + if (not live(next)) { + clearSites(c, next); + } + + if (not live(v)) { + clearSites(c, v); + } + } +} + +Site* +copy(Context* c, Site* s) +{ + Site* start = 0; + Site* end = 0; + for (; s; s = s->next) { + Site* n = s->copy(c); + if (end) { + end->next = n; + } else { + start = n; + } + end = n; + } + return start; +} + +class Snapshot { + public: + Snapshot(Context* c, Value* value, Snapshot* next): + value(value), buddy(value->buddy), sites(copy(c, value->sites)), next(next) + { } + + Value* value; + Value* buddy; + Site* sites; + Snapshot* next; +}; + +Snapshot* +snapshot(Context* c, Value* value, Snapshot* next) +{ + if (DebugControl) { + char buffer[256]; sitesToString(c, value->sites, buffer, 256); + fprintf(stderr, "snapshot %p buddy %p sites %s\n", + value, value->buddy, buffer); + } + + return new (c->zone->allocate(sizeof(Snapshot))) Snapshot(c, value, next); +} + +Snapshot* +makeSnapshots(Context* c, Value* value, Snapshot* next) +{ + next = snapshot(c, value, next); + for (Value* p = value->buddy; p != value; p = p->buddy) { + next = snapshot(c, p, next); + } + return next; +} + +Stack* +stack(Context* c, Value* value, Stack* next) +{ + return new (c->zone->allocate(sizeof(Stack))) + Stack(next ? next->index + 1 : 0, value, next); +} Value* -value(Context* c, Site* site = 0, Site* target = 0) +maybeBuddy(Context* c, Value* v); + +Value* +push(Context* c, unsigned footprint, Value* v) { - return new (c->zone->allocate(sizeof(Value))) Value(site, target); + assert(c, footprint); + + Value* high; + if (footprint > 1) { + assert(c, footprint == 2); + + if (BytesPerWord == 4 and v->high == 0) { + split(c, v); + } + + high = push(c, 1, v->high); + } else if (v) { + high = v->high; + } else { + high = 0; + } + + if (v) { + v = maybeBuddy(c, v); + v->high = high; + } + + Stack* s = stack(c, v, c->stack); + + if (DebugFrame) { + fprintf(stderr, "push %p\n", v); + } + + if (v) { + v->home = frameIndex(c, s->index + c->localFootprint); + } + c->stack = s; + + return v; +} + +Value* +pop(Context* c, unsigned footprint) +{ + assert(c, footprint); + + Stack* s = c->stack; + assert(c, s->value == 0 or s->value->home >= 0); + + if (DebugFrame) { + fprintf(stderr, "pop %p\n", s->value); + } + + c->stack = s->next; + + if (footprint > 1) { + assert(c, footprint == 2); + assert(c, s->value->high == s->next->value + and ((BytesPerWord == 8) xor (s->value->high != 0))); + + pop(c, 1); + } + + return s->value; +} + +Value* +storeLocal(Context* c, unsigned footprint, Value* v, unsigned index, bool copy) +{ + assert(c, index + footprint <= c->localFootprint); + + if (copy) { + unsigned sizeInBytes = sizeof(Local) * c->localFootprint; + Local* newLocals = static_cast(c->zone->allocate(sizeInBytes)); + memcpy(newLocals, c->locals, sizeInBytes); + c->locals = newLocals; + } + + Value* high; + if (footprint > 1) { + assert(c, footprint == 2); + + if (BytesPerWord == 4) { + assert(c, v->high); + + high = storeLocal(c, 1, v->high, index, false); + } else { + high = 0; + } + + ++ index; + } else { + high = v->high; + } + + v = maybeBuddy(c, v); + v->high = high; + + Local* local = c->locals + index; + local->value = v; + + if (DebugFrame) { + fprintf(stderr, "store local %p at %d\n", local->value, index); + } + + local->value->home = frameIndex(c, index); + + return v; +} + +Value* +loadLocal(Context* c, unsigned footprint UNUSED, unsigned index) +{ + assert(c, index + footprint <= c->localFootprint); + + if (footprint > 1) { + assert(c, footprint == 2); + + ++ index; + } + + assert(c, c->locals[index].value); + assert(c, c->locals[index].value->home >= 0); + + if (DebugFrame) { + fprintf(stderr, "load local %p at %d\n", c->locals[index].value, index); + } + + return c->locals[index].value; } void -appendCombine(Context* c, BinaryOperation type, unsigned size, Value* first, - Value* second, Value* result) +appendCombine(Context* c, TernaryOperation type, + unsigned firstSize, Value* first, + unsigned secondSize, Value* second, + unsigned resultSize, Value* result) { - VirtualSite* firstTarget = virtualSite(c); - VirtualSite* secondTarget = virtualSite(c, result); bool thunk; + uint8_t firstTypeMask; + uint64_t firstRegisterMask; + uint8_t secondTypeMask; + uint64_t secondRegisterMask; + uint8_t resultTypeMask; + uint64_t resultRegisterMask; - c->assembler->plan(type, size, - &(firstTarget->typeMask), &(firstTarget->registerMask), - &(secondTarget->typeMask), &(secondTarget->registerMask), - &thunk); + c->arch->plan(type, firstSize, &firstTypeMask, &firstRegisterMask, + secondSize, &secondTypeMask, &secondRegisterMask, + resultSize, &resultTypeMask, &resultRegisterMask, + &thunk); if (thunk) { - secondTarget->value = 0; + Stack* oldStack = c->stack; - Stack* oldStack = c->state->stack; + ::push(c, ceiling(secondSize, BytesPerWord), second); + ::push(c, ceiling(firstSize, BytesPerWord), first); - ::push(c, size, second); - ::push(c, size, first); + Stack* argumentStack = c->stack; + c->stack = oldStack; - Stack* argumentStack = c->state->stack; - c->state->stack = oldStack; - - appendCall(c, value(c, constantSite(c, c->client->getThunk(type, size))), - 0, 0, result, size, argumentStack, 2); + appendCall + (c, value(c, constantSite(c, c->client->getThunk(type, resultSize))), + 0, 0, result, resultSize, argumentStack, + ceiling(secondSize, BytesPerWord) + ceiling(firstSize, BytesPerWord), + 0); } else { - if (DebugAppend) { - fprintf(stderr, "appendCombine\n"); - } - - firstTarget->typeMask &= ~(1 << MemoryOperand); - secondTarget->typeMask &= ~(1 << MemoryOperand); - - new (c->zone->allocate(sizeof(CombineEvent))) - CombineEvent(c, type, size, first, second, result, firstTarget, - secondTarget); + append + (c, new (c->zone->allocate(sizeof(CombineEvent))) + CombineEvent + (c, type, + firstSize, first, + secondSize, second, + resultSize, result, + SiteMask(firstTypeMask, firstRegisterMask, AnyFrameIndex), + SiteMask(firstTypeMask, firstRegisterMask >> 32, AnyFrameIndex), + SiteMask(secondTypeMask, secondRegisterMask, AnyFrameIndex), + SiteMask(secondTypeMask, secondRegisterMask >> 32, AnyFrameIndex), + SiteMask(resultTypeMask, resultRegisterMask, AnyFrameIndex), + SiteMask(resultTypeMask, resultRegisterMask >> 32, AnyFrameIndex))); } } class TranslateEvent: public Event { public: - TranslateEvent(Context* c, UnaryOperation type, unsigned size, Value* value, - Value* result, Site* target): - Event(c), type(type), size(size), value(value), result(result) + TranslateEvent(Context* c, BinaryOperation type, unsigned size, Value* value, + Value* result, + const SiteMask& valueLowMask, + const SiteMask& valueHighMask, + const SiteMask& resultLowMask, + const SiteMask& resultHighMask): + Event(c), type(type), size(size), value(value), result(result), + resultLowMask(resultLowMask), resultHighMask(resultHighMask) { - addRead(c, value, size, target); + addRead(c, this, value, read(c, valueLowMask)); + if (size > BytesPerWord) { + addRead(c, this, value->high, read(c, valueHighMask)); + grow(c, result); + } + } + + virtual const char* name() { + return "TranslateEvent"; } virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "TranslateEvent.compile\n"); + Site* low = getTarget(c, value, result, resultLowMask); + Site* high + = (size > BytesPerWord + ? getTarget(c, value->high, result->high, resultHighMask) + : 0); + + apply(c, type, + size, value->source, source(value->high), + size, low, high); + + for (Read* r = reads; r; r = r->eventNext) { + popRead(c, this, r->value); } - maybePreserve(c, stack, size, value, value->source); + if (c->arch->condensedAddressing()) { + low->thaw(c, value); + if (size > BytesPerWord) { + high->thaw(c, value->high); + } - apply(c, type, size, value->source); - - nextRead(c, value); - - removeSite(c, value, value->source); - if (result->reads) { - addSite(c, 0, size, result, value->source); + if (live(result)) { + addSite(c, result, low); + if (size > BytesPerWord and live(result->high)) { + addSite(c, result->high, high); + } + } } } - UnaryOperation type; + BinaryOperation type; unsigned size; Value* value; Value* result; + Read* resultRead; + SiteMask resultLowMask; + SiteMask resultHighMask; }; void -appendTranslate(Context* c, UnaryOperation type, unsigned size, Value* value, +appendTranslate(Context* c, BinaryOperation type, unsigned size, Value* value, Value* result) { - if (DebugAppend) { - fprintf(stderr, "appendTranslate\n"); - } - - VirtualSite* target = virtualSite(c, result); bool thunk; + uint8_t firstTypeMask; + uint64_t firstRegisterMask; + uint8_t resultTypeMask; + uint64_t resultRegisterMask; - c->assembler->plan - (type, size, &(target->typeMask), &(target->registerMask), &thunk); + c->arch->plan(type, size, &firstTypeMask, &firstRegisterMask, + size, &resultTypeMask, &resultRegisterMask, + &thunk); assert(c, not thunk); // todo - target->typeMask &= ~(1 << MemoryOperand); - - new (c->zone->allocate(sizeof(TranslateEvent))) - TranslateEvent(c, type, size, value, result, target); + append(c, new (c->zone->allocate(sizeof(TranslateEvent))) + TranslateEvent + (c, type, size, value, result, + SiteMask(firstTypeMask, firstRegisterMask, AnyFrameIndex), + SiteMask(firstTypeMask, firstRegisterMask >> 32, AnyFrameIndex), + SiteMask(resultTypeMask, resultRegisterMask, AnyFrameIndex), + SiteMask(resultTypeMask, resultRegisterMask >> 32, AnyFrameIndex))); } class MemoryEvent: public Event { @@ -1865,15 +3239,17 @@ class MemoryEvent: public Event { Event(c), base(base), displacement(displacement), index(index), scale(scale), result(result) { - addRead(c, base, BytesPerWord, anyRegisterSite(c)); - if (index) addRead(c, index, BytesPerWord, registerOrConstantSite(c)); + addRead(c, this, base, anyRegisterRead(c)); + if (index) { + addRead(c, this, index, registerOrConstantRead(c)); + } + } + + virtual const char* name() { + return "MemoryEvent"; } virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "MemoryEvent.compile\n"); - } - int indexRegister; int displacement = this->displacement; unsigned scale = this->scale; @@ -1882,31 +3258,39 @@ class MemoryEvent: public Event { if (constant) { indexRegister = NoRegister; - displacement += (constant->value.value->value() * scale); + displacement += (constant->value->value() * scale); scale = 1; } else { assert(c, index->source->type(c) == RegisterOperand); - indexRegister = static_cast - (index->source)->register_.low; + indexRegister = static_cast(index->source)->number; } } else { indexRegister = NoRegister; } assert(c, base->source->type(c) == RegisterOperand); - int baseRegister = static_cast(base->source)->register_.low; + int baseRegister = static_cast(base->source)->number; - nextRead(c, base); + popRead(c, this, base); if (index) { if (BytesPerWord == 8 and indexRegister != NoRegister) { - apply(c, Move4To8, 8, index->source, index->source); + apply(c, Move, 4, index->source, 0, 8, index->source, 0); } - nextRead(c, index); + popRead(c, this, index); } - result->target = memorySite + Site* site = memorySite (c, baseRegister, displacement, indexRegister, scale); - addSite(c, 0, 0, result, result->target); + + result->target = site; + addSite(c, result, site); + + if (result->high) { + Site* high = site->copyHigh(c); + + result->high->target = high; + addSite(c, result->high, high); + } } Value* base; @@ -1920,128 +3304,8 @@ void appendMemory(Context* c, Value* base, int displacement, Value* index, unsigned scale, Value* result) { - if (DebugAppend) { - fprintf(stderr, "appendMemory\n"); - } - - new (c->zone->allocate(sizeof(MemoryEvent))) - MemoryEvent(c, base, displacement, index, scale, result); -} - -Stack* -stack(Context* c, Value* value, unsigned size, unsigned index, Stack* next) -{ - return new (c->zone->allocate(sizeof(Stack))) - Stack(value, size, index, next); -} - -void -resetStack(Context* c) -{ - unsigned i = 0; - Stack* p = 0; - for (Stack* s = c->state->stack; s; s = s->next) { - Stack* n = stack(c, value(c), s->size, s->index, 0); - n->value->sites = n->pushSite = pushSite(c, s->index); - n->pushed = true; - - if (p) { - p->next = n; - } else { - c->state->stack = n; - } - p = n; - - i += s->size; - } - - resetLocals(c); - - c->stackReset = true; -} - -void -popNow(Context* c, Stack* stack, unsigned count, bool ignore) -{ - Stack* s = stack; - unsigned ignored = 0; - for (unsigned i = count; i and s;) { - if (s->pushed) { - removeSite(c, s->value, s->pushSite); - s->pushSite = 0; - s->pushed = false; - - Value* v = s->value; - if (v->reads and v->sites == 0 and (not ignore)) { - ::ignore(c, ignored); - - Site* target = targetOrRegister(c, v); - - if (DebugStack) { - fprintf(stderr, "pop %p value: %p target: %p\n", - s, s->value, target); - } - - addSite(c, stack, s->size * BytesPerWord, v, target); - - apply(c, Pop, BytesPerWord * s->size, target); - } else { - if (DebugStack) { - fprintf(stderr, "ignore %p value: %p\n", s, v); - } - - ignored += s->size; - } - } else { - if (DebugStack) { - fprintf(stderr, "%p not pushed\n", s); - } - } - - i -= s->size; - s = s->next; - } - - ::ignore(c, ignored); -} - -class StackSyncEvent: public Event { - public: - StackSyncEvent(Context* c): - Event(c) - { - for (Stack* s = stack; s; s = s->next) { - if (s->pushEvent) s->pushEvent->active = true; - addRead(c, s->value, s->size * BytesPerWord, 0); - } - } - - StackSyncEvent(Context* c, unsigned sequence, Stack* stack, Local* locals): - Event(c, sequence, stack, locals) - { - for (Stack* s = stack; s; s = s->next) { - if (s->pushEvent) s->pushEvent->active = true; - insertRead(c, this, sequence, s->value, s->size * BytesPerWord, 0); - } - } - - virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "StackSyncEvent.compile\n"); - } - - cleanStack(c, stack, locals, reads); - } -}; - -void -appendStackSync(Context* c) -{ - if (DebugAppend) { - fprintf(stderr, "appendStackSync\n"); - } - - new (c->zone->allocate(sizeof(StackSyncEvent))) StackSyncEvent(c); + append(c, new (c->zone->allocate(sizeof(MemoryEvent))) + MemoryEvent(c, base, displacement, index, scale, result)); } class BranchEvent: public Event { @@ -2049,14 +3313,16 @@ class BranchEvent: public Event { BranchEvent(Context* c, UnaryOperation type, Value* address): Event(c), type(type), address(address) { - addRead(c, address, BytesPerWord, 0); + address->addPredecessor(c, this); + + addRead(c, this, address, read(c, SiteMask(~0, ~0, AnyFrameIndex))); + } + + virtual const char* name() { + return "BranchEvent"; } virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "BranchEvent.compile\n"); - } - bool jump; UnaryOperation type = this->type; if (type != Jump) { @@ -2114,12 +3380,14 @@ class BranchEvent: public Event { } if (jump) { - apply(c, type, BytesPerWord, address->source); + apply(c, type, BytesPerWord, address->source, 0); } - nextRead(c, address); + popRead(c, this, address); } + virtual bool isBranch() { return true; } + UnaryOperation type; Value* address; }; @@ -2127,172 +3395,8 @@ class BranchEvent: public Event { void appendBranch(Context* c, UnaryOperation type, Value* address) { - appendStackSync(c); - - if (DebugAppend) { - fprintf(stderr, "appendBranch\n"); - } - - new (c->zone->allocate(sizeof(BranchEvent))) BranchEvent(c, type, address); - - resetStack(c); -} - -class PushSite: public AbstractSite { - public: - PushSite(PushEvent* event): event(event) { } - - virtual Site* readTarget(Context* c, Read* r) { - if (r->next and (not event->active)) { - return targetOrNull(c, r->next); - } else { - return 0; - } - } - - PushEvent* event; -}; - -Site* -pushSite(Context* c, PushEvent* e) -{ - return new (c->zone->allocate(sizeof(PushSite))) PushSite(e); -} - -void -appendPush(Context* c, Stack* s) -{ - if (DebugAppend) { - fprintf(stderr, "appendPush\n"); - } - - new (c->zone->allocate(sizeof(PushEvent))) PushEvent(c, s); -} - -void -appendPush(Context* c) -{ - appendPush(c, c->state->stack); -} - -class PopEvent: public Event { - public: - PopEvent(Context* c, unsigned count, bool ignore): - Event(c), count(count), ignore(ignore) - { } - - virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "PopEvent.compile\n"); - } - - popNow(c, stack, count, ignore); - } - - unsigned count; - bool ignore; -}; - -void -appendPop(Context* c, unsigned count, bool ignore) -{ - if (DebugAppend) { - fprintf(stderr, "appendPop\n"); - } - - new (c->zone->allocate(sizeof(PopEvent))) PopEvent(c, count, ignore); -} - -class ClobberLocalEvent: public Event { - public: - ClobberLocalEvent(Context* c, unsigned size, Local* local): - Event(c), size(size), local(local) - { } - - virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "ClobberLocalEvent.compile\n"); - } - - for (Local* l = local; l; l = l->old) { - Value* v = l->value; - Site* s = l->site; - if (v->reads - and v->sites->next == 0 - and v->sites == s) - { - preserve(c, stack, size, v, s, v->reads); - } - removeSite(c, v, s); - } - } - - unsigned size; - Local* local; -}; - -void -appendClobberLocal(Context* c, unsigned size, Local* local) -{ - if (DebugAppend) { - fprintf(stderr, "appendClobberLocal\n"); - } - - new (c->zone->allocate(sizeof(ClobberLocalEvent))) - ClobberLocalEvent(c, size, local); -} - -class LocalEvent: public Event { - public: - LocalEvent(Context* c, unsigned size, Local* local): - Event(c), size(size), local(local) - { - if (local->old) { - addRead(c, local->old->value, size, 0); - } - } - - virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "LocalEvent.compile\n"); - } - - Site* sites = 0; - if (local->old) { - Value* v = local->old->value; - if (local->old->reuse and v->reads->next == 0) { - sites = v->sites; - } - - nextRead(c, v); - } - - Value* v = local->value; - if (v->reads) { - for (Site* s = sites; s;) { - Site* t = s->next; - if (s->type(c) != MemoryOperand) { - addSite(c, 0, size, v, s); - } - s = t; - } - - addSite(c, 0, size, v, local->site); - } - } - - unsigned size; - Local* local; -}; - -void -appendLocal(Context* c, unsigned size, Local* local) -{ - if (DebugAppend) { - fprintf(stderr, "appendLocal\n"); - } - - new (c->zone->allocate(sizeof(LocalEvent))) LocalEvent(c, size, local); + append(c, new (c->zone->allocate(sizeof(BranchEvent))) + BranchEvent(c, type, address)); } class BoundsCheckEvent: public Event { @@ -2302,27 +3406,29 @@ class BoundsCheckEvent: public Event { Event(c), object(object), lengthOffset(lengthOffset), index(index), handler(handler) { - addRead(c, object, BytesPerWord, anyRegisterSite(c)); - addRead(c, index, BytesPerWord, registerOrConstantSite(c)); + addRead(c, this, object, anyRegisterRead(c)); + addRead(c, this, index, registerOrConstantRead(c)); + } + + virtual const char* name() { + return "BoundsCheckEvent"; } virtual void compile(Context* c) { - if (DebugCompile) { - fprintf(stderr, "BoundsCheckEvent.compile\n"); - } - Assembler* a = c->assembler; ConstantSite* constant = findConstantSite(c, index); - CodePromise* nextPromise = codePromise(c, -1); + CodePromise* nextPromise = codePromise + (c, static_cast(0)); CodePromise* outOfBoundsPromise = 0; if (constant) { - expect(c, constant->value.value->value() >= 0); + expect(c, constant->value->value() >= 0); } else { - outOfBoundsPromise = codePromise(c, -1); + outOfBoundsPromise = codePromise(c, static_cast(0)); - apply(c, Compare, 4, constantSite(c, resolved(c, 0)), index->source); + apply(c, Compare, 4, constantSite(c, resolved(c, 0)), 0, + 4, index->source, 0); Assembler::Constant outOfBoundsConstant(outOfBoundsPromise); a->apply @@ -2330,29 +3436,26 @@ class BoundsCheckEvent: public Event { } assert(c, object->source->type(c) == RegisterOperand); - int base = static_cast(object->source)->register_.low; + MemorySite length(static_cast(object->source)->number, + lengthOffset, NoRegister, 1); + length.acquired = true; - Site* length = memorySite(c, base, lengthOffset); - length->acquire(c, 0, 0, 0); - - apply(c, Compare, 4, index->source, length); - - length->release(c); + apply(c, Compare, 4, index->source, 0, 4, &length, 0); Assembler::Constant nextConstant(nextPromise); a->apply(JumpIfGreater, BytesPerWord, ConstantOperand, &nextConstant); if (constant == 0) { - outOfBoundsPromise->offset = a->length(); + outOfBoundsPromise->offset = a->offset(); } Assembler::Constant handlerConstant(resolved(c, handler)); a->apply(Call, BytesPerWord, ConstantOperand, &handlerConstant); - nextPromise->offset = a->length(); + nextPromise->offset = a->offset(); - nextRead(c, object); - nextRead(c, index); + popRead(c, this, object); + popRead(c, this, index); } Value* object; @@ -2365,98 +3468,893 @@ void appendBoundsCheck(Context* c, Value* object, unsigned lengthOffset, Value* index, intptr_t handler) { - if (DebugAppend) { - fprintf(stderr, "appendBoundsCheck\n"); + append(c, new (c->zone->allocate(sizeof(BoundsCheckEvent))) + BoundsCheckEvent(c, object, lengthOffset, index, handler)); +} + +class FrameSiteEvent: public Event { + public: + FrameSiteEvent(Context* c, Value* value, int index): + Event(c), value(value), index(index) + { } + + virtual const char* name() { + return "FrameSiteEvent"; } - new (c->zone->allocate(sizeof(BoundsCheckEvent))) BoundsCheckEvent - (c, object, lengthOffset, index, handler); + virtual void compile(Context* c) { + if (live(value)) { + addSite(c, value, frameSite(c, index)); + } + } + + Value* value; + int index; +}; + +void +appendFrameSite(Context* c, Value* value, int index) +{ + append(c, new (c->zone->allocate(sizeof(FrameSiteEvent))) + FrameSiteEvent(c, value, index)); +} + +unsigned +frameFootprint(Context* c, Stack* s) +{ + return c->localFootprint + (s ? (s->index + 1) : 0); +} + +void +visit(Context* c, Link* link) +{ +// fprintf(stderr, "visit link from %d to %d fork %p junction %p\n", +// link->predecessor->logicalInstruction->index, +// link->successor->logicalInstruction->index, +// link->forkState, +// link->junctionState); + + ForkState* forkState = link->forkState; + if (forkState) { + for (unsigned i = 0; i < forkState->readCount; ++i) { + ForkElement* p = forkState->elements + i; + Value* v = p->value; + v->reads = p->read->nextTarget(); +// fprintf(stderr, "next read %p for %p from %p\n", v->reads, v, p->read); + if (not live(v)) { + clearSites(c, v); + } + } + } + + JunctionState* junctionState = link->junctionState; + if (junctionState) { + for (unsigned i = 0; i < junctionState->frameFootprint; ++i) { + StubReadPair* p = junctionState->reads + i; + + if (p->value and p->value->reads) { + assert(c, p->value->reads == p->read); + popRead(c, 0, p->value); + } + } + } +} + +class BuddyEvent: public Event { + public: + BuddyEvent(Context* c, Value* original, Value* buddy): + Event(c), original(original), buddy(buddy) + { + addRead(c, this, original, read(c, SiteMask(~0, ~0, AnyFrameIndex))); + } + + virtual const char* name() { + return "BuddyEvent"; + } + + virtual void compile(Context* c) { +// fprintf(stderr, "original %p buddy %p\n", original, buddy); + assert(c, hasSite(original)); + + addBuddy(original, buddy); + + popRead(c, this, original); + } + + Value* original; + Value* buddy; +}; + +void +appendBuddy(Context* c, Value* original, Value* buddy) +{ + append(c, new (c->zone->allocate(sizeof(BuddyEvent))) + BuddyEvent(c, original, buddy)); +} + +class SaveLocalsEvent: public Event { + public: + SaveLocalsEvent(Context* c): + Event(c) + { + saveLocals(c, this); + } + + virtual const char* name() { + return "SaveLocalsEvent"; + } + + virtual void compile(Context* c) { + for (Read* r = reads; r; r = r->eventNext) { + popRead(c, this, r->value); + } + } +}; + +void +appendSaveLocals(Context* c) +{ + append(c, new (c->zone->allocate(sizeof(SaveLocalsEvent))) + SaveLocalsEvent(c)); +} + +class DummyEvent: public Event { + public: + DummyEvent(Context* c): + Event(c) + { } + + virtual const char* name() { + return "DummyEvent"; + } + + virtual void compile(Context*) { } +}; + +void +appendDummy(Context* c) +{ + Stack* stack = c->stack; + Local* locals = c->locals; + LogicalInstruction* i = c->logicalCode[c->logicalIp]; + + c->stack = i->stack; + c->locals = i->locals; + + append(c, new (c->zone->allocate(sizeof(DummyEvent))) DummyEvent(c)); + + c->stack = stack; + c->locals = locals; +} + +void +append(Context* c, Event* e) +{ + LogicalInstruction* i = c->logicalCode[c->logicalIp]; + if (c->stack != i->stack or c->locals != i->locals) { + appendDummy(c); + } + + if (DebugAppend) { + fprintf(stderr, " -- append %s at %d with %d stack before\n", + e->name(), e->logicalInstruction->index, c->stack ? + c->stack->index + 1 : 0); + } + + if (c->lastEvent) { + c->lastEvent->next = e; + } else { + c->firstEvent = e; + } + c->lastEvent = e; + + Event* p = c->predecessor; + if (p) { + if (DebugAppend) { + fprintf(stderr, "%d precedes %d\n", p->logicalInstruction->index, + e->logicalInstruction->index); + } + + Link* link = ::link(c, p, e->predecessors, e, p->successors, c->forkState); + e->predecessors = link; + p->successors = link; + } + c->forkState = 0; + + c->predecessor = e; + + if (e->logicalInstruction->firstEvent == 0) { + e->logicalInstruction->firstEvent = e; + } + e->logicalInstruction->lastEvent = e; +} + +bool +acceptMatch(Context* c, Site* s, Read*, const SiteMask& mask) +{ + return s->match(c, mask); +} + +bool +isHome(Value* v, int frameIndex) +{ + Value* p = v; + do { + if (p->home == frameIndex) { + return true; + } + p = p->buddy; + } while (p != v); + + return false; +} + +bool +acceptForResolve(Context* c, Site* s, Read* read, const SiteMask& mask) +{ + if (acceptMatch(c, s, read, mask) and (not s->frozen(c))) { + if (s->type(c) == RegisterOperand) { + return c->availableRegisterCount > ResolveRegisterReserveCount; + } else { + assert(c, s->match(c, SiteMask(1 << MemoryOperand, 0, AnyFrameIndex))); + + return isHome(read->value, offsetToFrameIndex + (c, static_cast(s)->offset)); + } + } else { + return false; + } } Site* -readSource(Context* c, Stack* stack, Read* r) +pickSourceSite(Context* c, Read* read, Site* target = 0, + unsigned* cost = 0, uint8_t typeMask = ~0, + bool intersectRead = true, bool includeBuddies = true, + bool (*accept)(Context*, Site*, Read*, const SiteMask&) + = acceptMatch) { - if (r->value->sites == 0) { - return 0; + SiteMask mask(typeMask, ~0, AnyFrameIndex); + + if (intersectRead) { + read->intersect(&mask); } - Site* target = (r->target ? r->target->readTarget(c, r) : 0); + Site* site = 0; + unsigned copyCost = 0xFFFFFFFF; + for (SiteIterator it(read->value, includeBuddies); it.hasMore();) { + Site* s = it.next(); + if (accept(c, s, read, mask)) { + unsigned v = s->copyCost(c, target); + if (v < copyCost) { + site = s; + copyCost = v; + } + } + } - unsigned copyCost; - Site* site = pick(c, r->value->sites, target, ©Cost); + if (DebugMoves and site and target) { + char srcb[256]; site->toString(c, srcb, 256); + char dstb[256]; target->toString(c, dstb, 256); + fprintf(stderr, "pick source %s to %s for %p cost %d\n", + srcb, dstb, read->value, copyCost); + } - if (target and copyCost) { - addSite(c, stack, r->size, r->value, target); - apply(c, Move, r->size, site, target); - return target; - } else { + if (cost) *cost = copyCost; + return site; +} + +Site* +readSource(Context* c, Read* r) +{ + if (DebugReads) { + char buffer[1024]; sitesToString(c, r->value, buffer, 1024); + fprintf(stderr, "read source for %p from %s\n", r->value, buffer); + } + + if (not hasSite(r->value)) return 0; + + Site* site = pickSourceSite(c, r); + + if (site) { return site; + } else { + Site* target = pickTargetSite(c, r, true); + unsigned copyCost; + site = pickSourceSite(c, r, target, ©Cost, ~0, false); + assert(c, copyCost); + move(c, r->value, site, target); + return target; } } void -compile(Context* c) +propagateJunctionSites(Context* c, Event* e, Site** sites) { - Assembler* a = c->assembler; - - Assembler::Register base(a->base()); - Assembler::Register stack(a->stack()); - a->apply(Push, BytesPerWord, RegisterOperand, &base); - a->apply(Move, BytesPerWord, RegisterOperand, &stack, - RegisterOperand, &base); - - if (stackOffset(c)) { - Assembler::Constant offset(resolved(c, stackOffset(c) * BytesPerWord)); - a->apply(Subtract, BytesPerWord, ConstantOperand, &offset, - RegisterOperand, &stack); - } - - for (unsigned i = 0; i < c->logicalCodeLength; ++i) { - LogicalInstruction* li = c->logicalCode + i; - if (li->firstEvent) { - li->machineOffset = a->length(); - - if (DebugCompile) { - fprintf(stderr, " -- ip: %d\n", i); - } - - for (Event* e = li->firstEvent; e; e = e->next) { - if (e->stackReset) { -// fprintf(stderr, "stack reset\n"); - for (Stack* s = e->stack; s; s = s->next) { - if (s->value->sites) { - assert(c, s->value->sites->next == 0); - s->value->sites->acquire(c, 0, s->size * BytesPerWord, s->value); - } - } - } - - Site* sites[e->readCount]; - unsigned si = 0; - for (Read* r = e->reads; r; r = r->eventNext) { - r->value->source = readSource(c, e->stack, r); - - if (r->value->source) { - assert(c, si < e->readCount); - sites[si++] = r->value->source; - r->value->source->freeze(c); - } - } - - while (si) { - sites[--si]->thaw(c); - } - - e->compile(c); - - for (CodePromise* p = e->promises; p; p = p->next) { - p->offset = a->length(); - } + for (Link* pl = e->predecessors; pl; pl = pl->nextPredecessor) { + Event* p = pl->predecessor; + if (p->junctionSites == 0) { + p->junctionSites = sites; + for (Link* sl = p->successors; sl; sl = sl->nextSuccessor) { + Event* s = sl->successor; + propagateJunctionSites(c, s, sites); } } } } +void +propagateJunctionSites(Context* c, Event* e) +{ + for (Link* sl = e->successors; sl; sl = sl->nextSuccessor) { + Event* s = sl->successor; + if (s->predecessors->nextPredecessor) { + unsigned size = sizeof(Site*) * frameFootprint(c, e->stackAfter); + Site** junctionSites = static_cast + (c->zone->allocate(size)); + memset(junctionSites, 0, size); + + propagateJunctionSites(c, s, junctionSites); + break; + } + } +} + +class SiteRecord { + public: + SiteRecord(Site* site, Value* value): + site(site), value(value) + { } + + SiteRecord() { } + + Site* site; + Value* value; +}; + +class SiteRecordList { + public: + SiteRecordList(SiteRecord* records, unsigned capacity): + records(records), index(0), capacity(capacity) + { } + + SiteRecord* records; + unsigned index; + unsigned capacity; +}; + +void +freeze(Context* c, SiteRecordList* frozen, Site* s, Value* v) +{ + assert(c, frozen->index < frozen->capacity); + + s->freeze(c, v); + new (frozen->records + (frozen->index ++)) SiteRecord(s, v); +} + +void +thaw(Context* c, SiteRecordList* frozen) +{ + while (frozen->index) { + SiteRecord* sr = frozen->records + (-- frozen->index); + sr->site->thaw(c, sr->value); + } +} + +Site* +acquireSite(Context* c, SiteRecordList* frozen, Site* target, Value* v, + Read* r, bool pickSource) +{ + assert(c, hasSite(v)); + + unsigned copyCost; + Site* source; + if (pickSource) { + source = pickSourceSite(c, r, target, ©Cost, ~0, false); + } else { + copyCost = 0; + source = target; + } + + if (copyCost) { + target = target->copy(c); + move(c, v, source, target); + } else { + target = source; + } + + freeze(c, frozen, target, v); + + return target; +} + +bool +resolveOriginalSites(Context* c, Event* e, SiteRecordList* frozen, + Site** sites) +{ + bool complete = true; + for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { + FrameIterator::Element el = it.next(c); + Value* v = el.value; + Read* r = live(v); + + if (r) { + if (sites[el.localIndex]) { + if (DebugControl) { + char buffer[256]; + sites[el.localIndex]->toString(c, buffer, 256); + fprintf(stderr, "resolve original %s for %p local %d frame %d\n", + buffer, el.value, el.localIndex, frameIndex(c, &el)); + } + + acquireSite(c, frozen, sites[el.localIndex], v, r, true); + } else { + complete = false; + } + } + } + + return complete; +} + +bool +resolveSourceSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites) +{ + bool complete = true; + for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { + FrameIterator::Element el = it.next(c); + Value* v = el.value; + Read* r = live(v); + + if (r and sites[el.localIndex] == 0) { + const uint32_t mask = (1 << RegisterOperand) | (1 << MemoryOperand); + + Site* s = pickSourceSite + (c, r, 0, 0, mask, true, false, acceptForResolve); + if (s == 0) { + s = pickSourceSite(c, r, 0, 0, mask, false, false, acceptForResolve); + } + + if (s) { + if (DebugControl) { + char buffer[256]; s->toString(c, buffer, 256); + fprintf(stderr, "resolve source %s from %p local %d frame %d\n", + buffer, v, el.localIndex, frameIndex(c, &el)); + } + + sites[el.localIndex] = acquireSite(c, frozen, s, v, r, false)->copy(c); + } else { + complete = false; + } + } + } + + return complete; +} + +void +resolveTargetSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites) +{ + for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { + FrameIterator::Element el = it.next(c); + Value* v = el.value; + Read* r = live(v); + + if (r and sites[el.localIndex] == 0) { + const uint32_t mask = (1 << RegisterOperand) | (1 << MemoryOperand); + + bool useTarget = false; + Site* s = pickSourceSite(c, r, 0, 0, mask, true, true, acceptForResolve); + if (s == 0) { + s = pickSourceSite(c, r, 0, 0, mask, false, true, acceptForResolve); + if (s == 0) { + s = pickTargetSite(c, r, false, ResolveRegisterReserveCount); + useTarget = true; + } + } + + if (DebugControl) { + char buffer[256]; s->toString(c, buffer, 256); + fprintf(stderr, "resolve target %s for %p local %d frame %d\n", + buffer, el.value, el.localIndex, frameIndex(c, &el)); + } + + Site* acquired = acquireSite(c, frozen, s, v, r, useTarget)->copy(c); + + sites[el.localIndex] = (useTarget ? s : acquired->copy(c)); + } + } +} + +void +resolveJunctionSites(Context* c, Event* e, SiteRecordList* frozen) +{ + bool complete; + if (e->junctionSites) { + complete = resolveOriginalSites(c, e, frozen, e->junctionSites); + } else { + propagateJunctionSites(c, e); + complete = false; + } + + if (e->junctionSites) { + if (not complete) { + complete = resolveSourceSites(c, e, frozen, e->junctionSites); + if (not complete) { + resolveTargetSites(c, e, frozen, e->junctionSites); + } + } + + if (DebugControl) { + fprintf(stderr, "resolved junction sites %p at %d\n", + e->junctionSites, e->logicalInstruction->index); + } + } +} + +void +resolveBranchSites(Context* c, Event* e, SiteRecordList* frozen) +{ + if (e->successors->nextSuccessor and e->junctionSites == 0) { + unsigned footprint = frameFootprint(c, e->stackAfter); + Site* branchSites[footprint]; + memset(branchSites, 0, sizeof(Site*) * footprint); + + if (not resolveSourceSites(c, e, frozen, branchSites)) { + resolveTargetSites(c, e, frozen, branchSites); + } + } +} + +void +captureBranchSnapshots(Context* c, Event* e) +{ + if (e->successors->nextSuccessor) { + for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { + FrameIterator::Element el = it.next(c); + e->snapshots = makeSnapshots(c, el.value, e->snapshots); + } + + for (Cell* sv = e->successors->forkState->saved; sv; sv = sv->next) { + e->snapshots = makeSnapshots + (c, static_cast(sv->value), e->snapshots); + } + + if (DebugControl) { + fprintf(stderr, "captured snapshots %p at %d\n", + e->snapshots, e->logicalInstruction->index); + } + } +} + +void +populateSiteTables(Context* c, Event* e, SiteRecordList* frozen) +{ + resolveJunctionSites(c, e, frozen); + + resolveBranchSites(c, e, frozen); + + captureBranchSnapshots(c, e); +} + +void +setSites(Context* c, Value* v, Site* s) +{ + assert(c, live(v)); + + for (; s; s = s->next) { + addSite(c, v, s->copy(c)); + } + + if (DebugControl) { + char buffer[256]; sitesToString(c, v->sites, buffer, 256); + fprintf(stderr, "set sites %s for %p\n", buffer, v); + } +} + +void +resetFrame(Context* c, Event* e) +{ + for (FrameIterator it(c, e->stackBefore, e->localsBefore); it.hasMore();) { + FrameIterator::Element el = it.next(c); + clearSites(c, el.value); + } +} + +void +setSites(Context* c, Event* e, Site** sites) +{ + resetFrame(c, e); + + for (FrameIterator it(c, e->stackBefore, e->localsBefore); it.hasMore();) { + FrameIterator::Element el = it.next(c); + if (sites[el.localIndex]) { + if (live(el.value)) { + setSites(c, el.value, sites[el.localIndex]); + } + } + } +} + +void +removeBuddies(Context* c) +{ + for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) { + FrameIterator::Element el = it.next(c); + removeBuddy(c, el.value); + } +} + +void +restore(Context* c, Event* e, Snapshot* snapshots) +{ + for (Snapshot* s = snapshots; s; s = s->next) { +// char buffer[256]; sitesToString(c, s->sites, buffer, 256); +// fprintf(stderr, "restore %p buddy %p sites %s live %p\n", +// s->value, s->value->buddy, buffer, live(s->value)); + + s->value->buddy = s->buddy; + } + + resetFrame(c, e); + + for (Snapshot* s = snapshots; s; s = s->next) { + if (live(s->value)) { + if (live(s->value) and s->sites and s->value->sites == 0) { + setSites(c, s->value, s->sites); + } + } + } +} + +void +populateSources(Context* c, Event* e) +{ + SiteRecord frozenRecords[e->readCount]; + SiteRecordList frozen(frozenRecords, e->readCount); + + for (Read* r = e->reads; r; r = r->eventNext) { + r->value->source = readSource(c, r); + + if (r->value->source) { + if (DebugReads) { + char buffer[256]; r->value->source->toString(c, buffer, 256); + fprintf(stderr, "freeze source %s for %p\n", + buffer, r->value); + } + + freeze(c, &frozen, r->value->source, r->value); + } + } + + thaw(c, &frozen); +} + +void +setStubRead(Context* c, StubReadPair* p, Value* v) +{ + if (v) { + StubRead* r = stubRead(c); + if (DebugReads) { + fprintf(stderr, "add stub read %p to %p\n", r, v); + } + addRead(c, 0, v, r); + + p->value = v; + p->read = r; + } +} + +void +populateJunctionReads(Context* c, Link* link) +{ + JunctionState* state = new + (c->zone->allocate + (sizeof(JunctionState) + + (sizeof(StubReadPair) * frameFootprint(c, c->stack)))) + JunctionState(frameFootprint(c, c->stack)); + + memset(state->reads, 0, sizeof(StubReadPair) * frameFootprint(c, c->stack)); + + link->junctionState = state; + + for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) { + FrameIterator::Element e = it.next(c); + setStubRead(c, state->reads + e.localIndex, e.value); + } +} + +void +updateJunctionReads(Context* c, JunctionState* state) +{ + for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) { + FrameIterator::Element e = it.next(c); + StubReadPair* p = state->reads + e.localIndex; + if (p->value and p->read->read == 0) { + Read* r = live(e.value); + if (r) { + if (DebugReads) { + fprintf(stderr, "stub read %p for %p valid: %p\n", + p->read, p->value, r); + } + p->read->read = r; + } + } + } + + for (unsigned i = 0; i < frameFootprint(c, c->stack); ++i) { + StubReadPair* p = state->reads + i; + if (p->value and p->read->read == 0) { + if (DebugReads) { + fprintf(stderr, "stub read %p for %p invalid\n", p->read, p->value); + } + p->read->valid_ = false; + } + } +} + +LogicalInstruction* +next(Context* c, LogicalInstruction* i) +{ + for (unsigned n = i->index + 1; n < c->logicalCodeLength; ++n) { + i = c->logicalCode[n]; + if (i) return i; + } + return 0; +} + +class Block { + public: + Block(Event* head): + head(head), nextBlock(0), nextInstruction(0), assemblerBlock(0), start(0) + { } + + Event* head; + Block* nextBlock; + LogicalInstruction* nextInstruction; + Assembler::Block* assemblerBlock; + unsigned start; +}; + +Block* +block(Context* c, Event* head) +{ + return new (c->zone->allocate(sizeof(Block))) Block(head); +} + +unsigned +compile(Context* c) +{ + if (c->logicalCode[c->logicalIp]->lastEvent == 0) { + appendDummy(c); + } + + Assembler* a = c->assembler; + + Block* firstBlock = block(c, c->firstEvent); + Block* block = firstBlock; + + a->allocateFrame(c->alignedFrameSize); + + for (Event* e = c->firstEvent; e; e = e->next) { + if (DebugCompile) { + fprintf(stderr, + " -- compile %s at %d with %d preds %d succs %d stack\n", + e->name(), e->logicalInstruction->index, + countPredecessors(e->predecessors), + countSuccessors(e->successors), + e->stackBefore ? e->stackBefore->index + 1 : 0); + } + + e->block = block; + + c->stack = e->stackBefore; + c->locals = e->localsBefore; + + if (e->logicalInstruction->machineOffset == 0) { + e->logicalInstruction->machineOffset = a->offset(); + } + + if (e->predecessors) { + visit(c, lastPredecessor(e->predecessors)); + + Event* first = e->predecessors->predecessor; + if (e->predecessors->nextPredecessor) { + for (Link* pl = e->predecessors; + pl->nextPredecessor; + pl = pl->nextPredecessor) + { + updateJunctionReads(c, pl->junctionState); + } + + if (DebugControl) { + fprintf(stderr, "set sites to junction sites %p at %d\n", + first->junctionSites, first->logicalInstruction->index); + } + + setSites(c, e, first->junctionSites); + removeBuddies(c); + } else if (first->successors->nextSuccessor) { + if (DebugControl) { + fprintf(stderr, "restore snapshots %p at %d\n", + first->snapshots, first->logicalInstruction->index); + } + + restore(c, e, first->snapshots); + } + } + + unsigned footprint = frameFootprint(c, e->stackAfter); + SiteRecord frozenRecords[footprint]; + SiteRecordList frozen(frozenRecords, footprint); + + bool branch = e->isBranch(); + if (branch and e->successors) { + populateSiteTables(c, e, &frozen); + } + + populateSources(c, e); + + thaw(c, &frozen); + + e->compile(c); + + if ((not branch) and e->successors) { + populateSiteTables(c, e, &frozen); + thaw(c, &frozen); + } + + if (e->visitLinks) { + for (Cell* cell = reverseDestroy(e->visitLinks); cell; cell = cell->next) + { + visit(c, static_cast(cell->value)); + } + e->visitLinks = 0; + } + + for (CodePromise* p = e->promises; p; p = p->next) { + p->offset = a->offset(); + } + + LogicalInstruction* nextInstruction = next(c, e->logicalInstruction); + if (e->next == 0 + or (e->next->logicalInstruction != e->logicalInstruction + and (e->next->logicalInstruction != nextInstruction + or e != e->logicalInstruction->lastEvent))) + { + Block* b = e->logicalInstruction->firstEvent->block; + + while (b->nextBlock) { + b = b->nextBlock; + } + + if (b != block) { + b->nextBlock = block; + } + + block->nextInstruction = nextInstruction; + block->assemblerBlock = a->endBlock(e->next != 0); + + if (e->next) { + block = ::block(c, e->next); + } + } + } + + block = firstBlock; + while (block->nextBlock or block->nextInstruction) { + Block* next = block->nextBlock + ? block->nextBlock + : block->nextInstruction->firstEvent->block; + + next->start = block->assemblerBlock->resolve + (block->start, next->assemblerBlock); + + block = next; + } + + return block->assemblerBlock->resolve(block->start, 0); +} + unsigned count(Stack* s) { @@ -2469,112 +4367,88 @@ count(Stack* s) } void -pushState(Context* c) +restore(Context* c, ForkState* state) { - if (DebugAppend) { - unsigned count = 0; for (State* s = c->state; s; s = s->next) ++ count; - fprintf(stderr, "push at level %d\n", count); - count = 0; for (Stack* s = c->state->stack; s; s = s->next) ++ count; - fprintf(stderr, "stack count: %d\n", count); + for (unsigned i = 0; i < state->readCount; ++i) { + ForkElement* p = state->elements + i; + p->value->lastRead = p->read; + p->read->allocateTarget(c); } - - c->state = new (c->zone->allocate(sizeof(State))) - State(c->state, c->state->stack); } void -saveStack(Context* c) +addForkElement(Context* c, Value* v, ForkState* state, unsigned index) { - if (c->logicalIp >= 0 and not c->logicalCode[c->logicalIp].stackSaved) { - c->logicalCode[c->logicalIp].stackSaved = true; - c->logicalCode[c->logicalIp].stack = c->state->stack; - c->logicalCode[c->logicalIp].locals = c->locals; + MultiRead* r = multiRead(c); + if (DebugReads) { + fprintf(stderr, "add multi read %p to %p\n", r, v); + } + addRead(c, 0, v, r); - if (DebugAppend) { - unsigned count = 0; - for (Stack* s = c->state->stack; s; s = s->next) ++ count; - fprintf(stderr, "stack count after ip %d: %d\n", c->logicalIp, count); + ForkElement* p = state->elements + index; + p->value = v; + p->read = r; +} + +ForkState* +saveState(Context* c) +{ + unsigned elementCount = frameFootprint(c, c->stack) + count(c->saved); + + ForkState* state = new + (c->zone->allocate + (sizeof(ForkState) + (sizeof(ForkElement) * elementCount))) + ForkState(c->stack, c->locals, c->saved, c->predecessor, c->logicalIp); + + if (c->predecessor) { + c->forkState = state; + + unsigned count = 0; + + for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) { + FrameIterator::Element e = it.next(c); + addForkElement(c, e.value, state, count++); } + + for (Cell* sv = c->saved; sv; sv = sv->next) { + addForkElement(c, static_cast(sv->value), state, count++); + } + + state->readCount = count; } + + c->saved = 0; + + return state; } void -popState(Context* c) +restoreState(Context* c, ForkState* s) { - c->state = new (c->zone->allocate(sizeof(State))) - State(c->state->next->next, c->state->next->stack); - - if (DebugAppend) { - unsigned count = 0; for (State* s = c->state; s; s = s->next) ++ count; - fprintf(stderr, "pop to level %d\n", count); - count = 0; for (Stack* s = c->state->stack; s; s = s->next) ++ count; - fprintf(stderr, "stack count: %d\n", count); + if (c->logicalCode[c->logicalIp]->lastEvent == 0) { + appendDummy(c); } -} -Stack* -stack(Context* c, Value* value, unsigned size, Stack* next) -{ - return stack(c, value, size, (next ? next->index + next->size : 0), next); -} + c->stack = s->stack; + c->locals = s->locals; + c->predecessor = s->predecessor; + c->logicalIp = s->logicalIp; -void -push(Context* c, unsigned size, Value* v) -{ - assert(c, ceiling(size, BytesPerWord)); - - c->state->stack = stack(c, v, ceiling(size, BytesPerWord), c->state->stack); - - appendPush(c); -} - -void -addLocal(Context* c, unsigned size, unsigned index, Value* newValue) -{ - unsigned sizeInWords = ceiling(size, BytesPerWord); - - c->localTable[index] = c->locals = new (c->zone->allocate(sizeof(Local))) - Local(sizeInWords, index, newValue, memorySite - (c, c->assembler->base(), localOffset(c, index)), - c->localTable[index], c->locals); - - appendLocal(c, sizeInWords * BytesPerWord, c->locals); + if (c->predecessor) { + c->forkState = s; + restore(c, s); + } } Value* -pop(Context* c, unsigned size UNUSED) +maybeBuddy(Context* c, Value* v) { - Stack* s = c->state->stack; - assert(c, ceiling(size, BytesPerWord) == s->size); - - appendPop(c, s->size, false); - - c->state->stack = s->next; - return s->value; -} - -void -updateJunctions(Context* c) -{ - for (Junction* j = c->junctions; j; j = j->next) { - LogicalInstruction* i = c->logicalCode + j->logicalIp; - LogicalInstruction* p = i->immediatePredecessor; - - p->lastEvent = p->lastEvent->next - = new (c->zone->allocate(sizeof(StackSyncEvent))) - StackSyncEvent(c, p->lastEvent->sequence, p->stack, p->locals); - } -} - -void -visit(Context* c, unsigned logicalIp) -{ - assert(c, logicalIp < c->logicalCodeLength); - - if (c->logicalIp >= 0 and (not c->stackReset)) { - assert(c, c->logicalCode[logicalIp].immediatePredecessor == 0); - c->logicalCode[logicalIp].immediatePredecessor - = c->logicalCode + c->logicalIp; + if (v->home >= 0) { + Value* n = value(c); + appendBuddy(c, v, n); + return n; + } else { + return v; } } @@ -2583,31 +4457,33 @@ class Client: public Assembler::Client { Client(Context* c): c(c) { } virtual int acquireTemporary(uint32_t mask) { - int r = pickRegister(c, mask)->number; + unsigned cost; + int r = pickRegisterTarget(c, 0, mask, &cost); + expect(c, cost < Target::Impossible); save(r); - increment(c, r); + increment(c, c->registerResources + r); return r; } virtual void releaseTemporary(int r) { - decrement(c, c->registers[r]); + decrement(c, c->registerResources + r); restore(r); } virtual void save(int r) { - if (c->registers[r]->refCount or c->registers[r]->value) { - Assembler::Register operand(r); - c->assembler->apply(Push, BytesPerWord, RegisterOperand, &operand); - c->registers[r]->pushed = true; + RegisterResource* reg = c->registerResources + r; + + assert(c, reg->referenceCount == 0); + assert(c, reg->freezeCount == 0); + assert(c, not reg->reserved); + + if (reg->value) { + steal(c, reg, 0); } } - virtual void restore(int r) { - if (c->registers[r]->pushed) { - Assembler::Register operand(r); - c->assembler->apply(Pop, BytesPerWord, RegisterOperand, &operand); - c->registers[r]->pushed = false; - } + virtual void restore(int) { + // todo } Context* c; @@ -2622,57 +4498,128 @@ class MyCompiler: public Compiler { assembler->setClient(&client); } - virtual void pushState() { - ::pushState(&c); + virtual State* saveState() { + State* s = ::saveState(&c); + restoreState(s); + return s; } - virtual void popState() { - ::popState(&c); + virtual void restoreState(State* state) { + ::restoreState(&c, static_cast(state)); } - virtual void saveStack() { - ::saveStack(&c); + virtual Subroutine* startSubroutine() { + return c.subroutine = new (c.zone->allocate(sizeof(MySubroutine))) + MySubroutine; } - virtual void resetStack() { - ::resetStack(&c); + virtual void endSubroutine(Subroutine* subroutine) { + static_cast(subroutine)->forkState = ::saveState(&c); + } + + virtual void restoreFromSubroutine(Subroutine* subroutine) { + ::restoreState(&c, static_cast(subroutine)->forkState); } virtual void init(unsigned logicalCodeLength, unsigned parameterFootprint, - unsigned localFootprint) + unsigned localFootprint, unsigned alignedFrameSize) { c.logicalCodeLength = logicalCodeLength; c.parameterFootprint = parameterFootprint; c.localFootprint = localFootprint; + c.alignedFrameSize = alignedFrameSize; - c.logicalCode = static_cast - (c.zone->allocate(sizeof(LogicalInstruction) * logicalCodeLength)); - memset(c.logicalCode, 0, sizeof(LogicalInstruction) * logicalCodeLength); + unsigned frameResourceCount = alignedFrameSize + parameterFootprint; - c.localTable = static_cast - (c.zone->allocate(sizeof(Local*) * localFootprint)); - memset(c.localTable, 0, sizeof(Local*) * localFootprint); + c.frameResources = static_cast + (c.zone->allocate(sizeof(FrameResource) * frameResourceCount)); + + for (unsigned i = 0; i < frameResourceCount; ++i) { + new (c.frameResources + i) FrameResource; + } + + // leave room for logical instruction -1 + unsigned codeSize = sizeof(LogicalInstruction*) + * (logicalCodeLength + 1); + c.logicalCode = static_cast + (c.zone->allocate(codeSize)); + memset(c.logicalCode, 0, codeSize); + c.logicalCode++; + + c.locals = static_cast + (c.zone->allocate(sizeof(Local) * localFootprint)); + + memset(c.locals, 0, sizeof(Local) * localFootprint); + + c.logicalCode[-1] = new + (c.zone->allocate(sizeof(LogicalInstruction))) + LogicalInstruction(-1, c.stack, c.locals); } virtual void visitLogicalIp(unsigned logicalIp) { - visit(&c, logicalIp); + assert(&c, logicalIp < c.logicalCodeLength); - c.stackReset = false; - - if (c.logicalCode[logicalIp].immediatePredecessor) { - c.junctions = new (c.zone->allocate(sizeof(Junction))) - Junction(logicalIp, c.junctions); + if (c.logicalCode[c.logicalIp]->lastEvent == 0) { + appendDummy(&c); } + + Event* e = c.logicalCode[logicalIp]->firstEvent; + + Event* p = c.predecessor; + if (p) { + if (DebugAppend) { + fprintf(stderr, "visit %d pred %d\n", logicalIp, + p->logicalInstruction->index); + } + + p->stackAfter = c.stack; + p->localsAfter = c.locals; + + Link* link = ::link + (&c, p, e->predecessors, e, p->successors, c.forkState); + e->predecessors = link; + p->successors = link; + c.lastEvent->visitLinks = cons(&c, link, c.lastEvent->visitLinks); + + if (DebugAppend) { + fprintf(stderr, "populate junction reads for %d to %d\n", + p->logicalInstruction->index, logicalIp); + } + + populateJunctionReads(&c, link); + } + + if (c.subroutine) { + c.subroutine->forkState + = c.logicalCode[logicalIp]->subroutine->forkState; + c.subroutine = 0; + } + + c.forkState = 0; } virtual void startLogicalIp(unsigned logicalIp) { - if (DebugAppend) { - fprintf(stderr, " -- ip: %d\n", logicalIp); + assert(&c, logicalIp < c.logicalCodeLength); + assert(&c, c.logicalCode[logicalIp] == 0); + + if (c.logicalCode[c.logicalIp]->lastEvent == 0) { + appendDummy(&c); } - visit(&c, logicalIp); + Event* p = c.predecessor; + if (p) { + p->stackAfter = c.stack; + p->localsAfter = c.locals; + } - ::saveStack(&c); + c.logicalCode[logicalIp] = new + (c.zone->allocate(sizeof(LogicalInstruction))) + LogicalInstruction(logicalIp, c.stack, c.locals); + + if (c.subroutine) { + c.logicalCode[logicalIp]->subroutine = c.subroutine; + c.subroutine = 0; + } c.logicalIp = logicalIp; } @@ -2730,85 +4677,98 @@ class MyCompiler: public Compiler { } virtual Operand* stack() { - Site* s = registerSite(&c, c.assembler->stack()); - return value(&c, s, s); - } - - virtual Operand* base() { - Site* s = registerSite(&c, c.assembler->base()); + Site* s = registerSite(&c, c.arch->stack()); return value(&c, s, s); } virtual Operand* thread() { - Site* s = registerSite(&c, c.assembler->thread()); + Site* s = registerSite(&c, c.arch->thread()); return value(&c, s, s); } - virtual Operand* label() { - return value(&c, ::constantSite(&c, static_cast(0))); - } - Promise* machineIp() { - return codePromise(&c, c.logicalCode[c.logicalIp].lastEvent); + return codePromise(&c, c.logicalCode[c.logicalIp]->lastEvent); } - virtual void mark(Operand* label) { - appendStackSync(&c); - ::resetStack(&c); + virtual void push(unsigned footprint UNUSED) { + assert(&c, footprint == 1); - for (Site* s = static_cast(label)->sites; s; s = s->next) { - if (s->type(&c) == ConstantOperand) { - static_cast(s)->value.value = machineIp(); - return; - } - } - abort(&c); + Value* v = value(&c); + Stack* s = ::stack(&c, v, c.stack); + v->home = frameIndex(&c, s->index + c.localFootprint); + c.stack = s; } - virtual void push(unsigned size) { - assert(&c, ceiling(size, BytesPerWord)); - - c.state->stack = ::stack - (&c, value(&c), ceiling(size, BytesPerWord), c.state->stack); + virtual void push(unsigned footprint, Operand* value) { + ::push(&c, footprint, static_cast(value)); } - virtual void push(unsigned size, Operand* value) { - ::push(&c, size, static_cast(value)); - } + virtual void save(unsigned footprint, Operand* value) { + c.saved = cons(&c, static_cast(value), c.saved); + if (BytesPerWord == 4 and footprint > 1) { + assert(&c, footprint == 2); + assert(&c, static_cast(value)->high); - virtual Operand* pop(unsigned size) { - return ::pop(&c, size); - } - - virtual void pushed(unsigned count) { - for (unsigned i = 0; i < count; ++i) { - Value* v = value(&c); - c.state->stack = ::stack(&c, v, 1, c.state->stack); - c.state->stack->pushed = true; - c.state->stack->pushSite - = v->sites = pushSite(&c, c.state->stack->index); + save(1, static_cast(value)->high); } } - virtual void popped(unsigned count, bool isEvent) { - if (isEvent) { - appendPop(&c, count, true); - } - - for (unsigned i = count; i;) { - Stack* s = c.state->stack; - c.state->stack = s->next; - i -= s->size; - } + virtual Operand* pop(unsigned footprint) { + return ::pop(&c, footprint); } - virtual Operand* peek(unsigned size UNUSED, unsigned index) { - Stack* s = c.state->stack; - for (unsigned i = index; i > 0;) { - i -= s->size; + virtual void pushed() { + Value* v = value(&c); + appendFrameSite + (&c, v, frameIndex + (&c, (c.stack ? c.stack->index : 0) + c.localFootprint)); + + Stack* s = ::stack(&c, v, c.stack); + v->home = frameIndex(&c, s->index + c.localFootprint); + c.stack = s; + } + + virtual void popped(unsigned footprint) { + assert(&c, c.stack->value->home >= 0); + + if (footprint > 1) { + assert(&c, footprint == 2); + assert(&c, c.stack->value->high == c.stack->next->value + and ((BytesPerWord == 8) xor (c.stack->value->high != 0))); + + popped(1); + } + + if (DebugFrame) { + fprintf(stderr, "popped %p\n", c.stack->value); + } + + c.stack = c.stack->next; + } + + virtual StackElement* top() { + return c.stack; + } + + virtual unsigned footprint(StackElement* e) { + return (static_cast(e)->next + and (static_cast(e)->next->value + == static_cast(e)->value->high)) ? 2 : 1; + } + + virtual unsigned index(StackElement* e) { + return static_cast(e)->index; + } + + virtual Operand* peek(unsigned footprint UNUSED, unsigned index) { + Stack* s = c.stack; + for (unsigned i = index; i > 0; --i) { s = s->next; } - assert(&c, s->size == ceiling(size, BytesPerWord)); + assert(&c, footprint == 1 or + (c.stack->value->high == c.stack->next->value + and ((BytesPerWord == 8) xor (c.stack->value->high != 0)))); + return s->value; } @@ -2824,13 +4784,14 @@ class MyCompiler: public Compiler { unsigned footprint = 0; unsigned size = BytesPerWord; Value* arguments[argumentCount]; - unsigned argumentSizes[argumentCount]; - unsigned index = 0; + int index = 0; for (unsigned i = 0; i < argumentCount; ++i) { Value* o = va_arg(a, Value*); if (o) { arguments[index] = o; - argumentSizes[index] = size; + if (size > BytesPerWord) { + arguments[++index] = o->high; + } size = BytesPerWord; ++ index; } else { @@ -2841,54 +4802,99 @@ class MyCompiler: public Compiler { va_end(a); - for (Stack* s = c.state->stack; s; s = s->next) { - if (s->pushEvent == 0) { - appendPush(&c, s); - } - s->pushEvent->active = true; - } - - Stack* oldStack = c.state->stack; + Stack* argumentStack = c.stack; + Stack* bottomArgument = 0; for (int i = index - 1; i >= 0; --i) { - ::push(&c, argumentSizes[i], arguments[i]); + argumentStack = ::stack(&c, arguments[i], argumentStack); + + if (i == index - 1) { + bottomArgument = argumentStack; + } } - Stack* argumentStack = c.state->stack; - c.state->stack = oldStack; - Value* result = value(&c); - appendCall(&c, static_cast(address), flags, - traceHandler, result, resultSize, argumentStack, - index); + appendCall(&c, static_cast(address), flags, traceHandler, result, + resultSize, argumentStack, index, 0); return result; } + virtual Operand* stackCall(Operand* address, + unsigned flags, + TraceHandler* traceHandler, + unsigned resultSize, + unsigned argumentFootprint) + { + Value* result = value(&c); + appendCall(&c, static_cast(address), flags, traceHandler, result, + resultSize, c.stack, 0, argumentFootprint); + return result; + } + virtual void return_(unsigned size, Operand* value) { appendReturn(&c, size, static_cast(value)); } - virtual void storeLocal(unsigned size, Operand* src, unsigned index) { - assert(&c, index < c.localFootprint); - - if (c.localTable[index]) { - appendClobberLocal(&c, size, c.localTable[index]); - c.localTable[index] = 0; - } - - store(size, src, memory(base(), localOffset(&c, index))); - - // todo: find out why this doesn't work and fix it: -// addLocal(&c, size, index, static_cast(src)); - } - - virtual Operand* loadLocal(unsigned size, unsigned index) { - assert(&c, index < c.localFootprint); + virtual void initLocal(unsigned footprint, unsigned index) { + assert(&c, index + footprint <= c.localFootprint); Value* v = value(&c); - addLocal(&c, size, index, v); - return v; + + if (footprint > 1) { + assert(&c, footprint == 2); + + if (BytesPerWord == 4) { + initLocal(1, index); + v->high = c.locals[index].value; + } + + ++ index; + } + + if (DebugFrame) { + fprintf(stderr, "init local %p at %d (%d)\n", + v, index, frameIndex(&c, index)); + } + + appendFrameSite(&c, v, frameIndex(&c, index)); + + Local* local = c.locals + index; + local->value = v; + v->home = frameIndex(&c, index); + } + + virtual void initLocalsFromLogicalIp(unsigned logicalIp) { + assert(&c, logicalIp < c.logicalCodeLength); + + unsigned footprint = sizeof(Local) * c.localFootprint; + Local* newLocals = static_cast(c.zone->allocate(footprint)); + memset(newLocals, 0, footprint); + c.locals = newLocals; + + Event* e = c.logicalCode[logicalIp]->firstEvent; + for (unsigned i = 0; i < c.localFootprint; ++i) { + Local* local = e->localsBefore + i; + if (local->value) { + initLocal(1, i); + + if (i > 0 and local->value->high == local[-1].value) { + c.locals[i].value->high = c.locals[i - 1].value; + } + } + } + } + + virtual void storeLocal(unsigned footprint, Operand* src, unsigned index) { + ::storeLocal(&c, footprint, static_cast(src), index, true); + } + + virtual Operand* loadLocal(unsigned footprint, unsigned index) { + return ::loadLocal(&c, footprint, index); + } + + virtual void saveLocals() { + appendSaveLocals(&c); } virtual void checkBounds(Operand* object, unsigned lengthOffset, @@ -2900,31 +4906,29 @@ class MyCompiler: public Compiler { virtual void store(unsigned size, Operand* src, Operand* dst) { appendMove(&c, Move, size, static_cast(src), - static_cast(dst)); + size, static_cast(dst)); } - virtual Operand* load(unsigned size, Operand* src) { + virtual Operand* load(unsigned srcSize, unsigned dstSize, Operand* src) { + assert(&c, dstSize >= BytesPerWord); + Value* dst = value(&c); - appendMove(&c, Move, size, static_cast(src), dst); + appendMove(&c, Move, srcSize, static_cast(src), dstSize, dst); return dst; } - virtual Operand* loadz(unsigned size, Operand* src) { - Value* dst = value(&c); - appendMove(&c, MoveZ, size, static_cast(src), dst); - return dst; - } + virtual Operand* loadz(unsigned srcSize, unsigned dstSize, Operand* src) { + assert(&c, dstSize >= BytesPerWord); - virtual Operand* load4To8(Operand* src) { Value* dst = value(&c); - appendMove(&c, Move4To8, 8, static_cast(src), dst); + appendMove(&c, MoveZ, srcSize, static_cast(src), dstSize, dst); return dst; } virtual Operand* lcmp(Operand* a, Operand* b) { Value* result = value(&c); appendCombine(&c, LongCompare, 8, static_cast(a), - static_cast(b), result); + 8, static_cast(b), 8, result); return result; } @@ -2964,77 +4968,77 @@ class MyCompiler: public Compiler { virtual Operand* add(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); appendCombine(&c, Add, size, static_cast(a), - static_cast(b), result); + size, static_cast(b), size, result); return result; } virtual Operand* sub(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); appendCombine(&c, Subtract, size, static_cast(a), - static_cast(b), result); + size, static_cast(b), size, result); return result; } virtual Operand* mul(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); appendCombine(&c, Multiply, size, static_cast(a), - static_cast(b), result); + size, static_cast(b), size, result); return result; } virtual Operand* div(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); appendCombine(&c, Divide, size, static_cast(a), - static_cast(b), result); + size, static_cast(b), size, result); return result; } virtual Operand* rem(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); appendCombine(&c, Remainder, size, static_cast(a), - static_cast(b), result); + size, static_cast(b), size, result); return result; } virtual Operand* shl(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); - appendCombine(&c, ShiftLeft, size, static_cast(a), - static_cast(b), result); + appendCombine(&c, ShiftLeft, BytesPerWord, static_cast(a), + size, static_cast(b), size, result); return result; } virtual Operand* shr(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); - appendCombine(&c, ShiftRight, size, static_cast(a), - static_cast(b), result); + appendCombine(&c, ShiftRight, BytesPerWord, static_cast(a), + size, static_cast(b), size, result); return result; } virtual Operand* ushr(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); - appendCombine(&c, UnsignedShiftRight, size, static_cast(a), - static_cast(b), result); + appendCombine(&c, UnsignedShiftRight, BytesPerWord, static_cast(a), + size, static_cast(b), size, result); return result; } virtual Operand* and_(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); appendCombine(&c, And, size, static_cast(a), - static_cast(b), result); + size, static_cast(b), size, result); return result; } virtual Operand* or_(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); appendCombine(&c, Or, size, static_cast(a), - static_cast(b), result); + size, static_cast(b), size, result); return result; } virtual Operand* xor_(unsigned size, Operand* a, Operand* b) { Value* result = value(&c); appendCombine(&c, Xor, size, static_cast(a), - static_cast(b), result); + size, static_cast(b), size, result); return result; } @@ -3045,9 +5049,7 @@ class MyCompiler: public Compiler { } virtual unsigned compile() { - updateJunctions(&c); - ::compile(&c); - return c.assembler->length(); + return c.machineCodeSize = ::compile(&c); } virtual unsigned poolSize() { @@ -3061,7 +5063,7 @@ class MyCompiler: public Compiler { int i = 0; for (ConstantPoolNode* n = c.firstConstant; n; n = n->next) { intptr_t* target = reinterpret_cast - (dst + pad(c.assembler->length()) + i); + (dst + pad(c.machineCodeSize) + i); if (n->promise->resolved()) { *target = n->promise->value(); diff --git a/src/compiler.h b/src/compiler.h index 999b31f220..64e2f6f03e 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -22,21 +22,26 @@ class Compiler { class Client { public: virtual intptr_t getThunk(UnaryOperation op, unsigned size) = 0; - virtual intptr_t getThunk(BinaryOperation op, unsigned size) = 0; + virtual intptr_t getThunk(TernaryOperation op, unsigned size) = 0; }; static const unsigned Aligned = 1 << 0; static const unsigned NoReturn = 1 << 1; class Operand { }; + class StackElement { }; + class State { }; + class Subroutine { }; - virtual void pushState() = 0; - virtual void popState() = 0; - virtual void saveStack() = 0; - virtual void resetStack() = 0; + virtual State* saveState() = 0; + virtual void restoreState(State* state) = 0; + + virtual Subroutine* startSubroutine() = 0; + virtual void endSubroutine(Subroutine* subroutine) = 0; + virtual void restoreFromSubroutine(Subroutine* subroutine) = 0; virtual void init(unsigned logicalCodeSize, unsigned parameterFootprint, - unsigned localFootprint) = 0; + unsigned localFootprint, unsigned alignedFrameSize) = 0; virtual void visitLogicalIp(unsigned logicalIp) = 0; virtual void startLogicalIp(unsigned logicalIp) = 0; @@ -55,18 +60,18 @@ class Compiler { unsigned scale = 1) = 0; virtual Operand* stack() = 0; - virtual Operand* base() = 0; virtual Operand* thread() = 0; - virtual Operand* label() = 0; - virtual void mark(Operand* label) = 0; - - virtual void push(unsigned size) = 0; - virtual void push(unsigned size, Operand* value) = 0; - virtual Operand* pop(unsigned size) = 0; - virtual void pushed(unsigned count) = 0; - virtual void popped(unsigned count, bool isEvent) = 0; - virtual Operand* peek(unsigned size, unsigned index) = 0; + virtual void push(unsigned footprint) = 0; + virtual void push(unsigned footprint, Operand* value) = 0; + virtual void save(unsigned footprint, Operand* value) = 0; + virtual Operand* pop(unsigned footprint) = 0; + virtual void pushed() = 0; + virtual void popped(unsigned footprint) = 0; + virtual StackElement* top() = 0; + virtual unsigned footprint(StackElement*) = 0; + virtual unsigned index(StackElement*) = 0; + virtual Operand* peek(unsigned footprint, unsigned index) = 0; virtual Operand* call(Operand* address, unsigned flags, @@ -75,18 +80,27 @@ class Compiler { unsigned argumentCount, ...) = 0; + virtual Operand* stackCall(Operand* address, + unsigned flags, + TraceHandler* traceHandler, + unsigned resultSize, + unsigned argumentFootprint) = 0; + virtual void return_(unsigned size, Operand* value) = 0; - virtual void storeLocal(unsigned size, Operand* src, unsigned index) = 0; - virtual Operand* loadLocal(unsigned size, unsigned index) = 0; + virtual void initLocal(unsigned size, unsigned index) = 0; + virtual void initLocalsFromLogicalIp(unsigned logicalIp) = 0; + virtual void storeLocal(unsigned footprint, Operand* src, + unsigned index) = 0; + virtual Operand* loadLocal(unsigned footprint, unsigned index) = 0; + virtual void saveLocals() = 0; virtual void checkBounds(Operand* object, unsigned lengthOffset, Operand* index, intptr_t handler) = 0; virtual void store(unsigned size, Operand* src, Operand* dst) = 0; - virtual Operand* load(unsigned size, Operand* src) = 0; - virtual Operand* loadz(unsigned size, Operand* src) = 0; - virtual Operand* load4To8(Operand* src) = 0; + virtual Operand* load(unsigned srcSize, unsigned dstSize, Operand* src) = 0; + virtual Operand* loadz(unsigned size, unsigned dstSize, Operand* src) = 0; virtual Operand* lcmp(Operand* a, Operand* b) = 0; virtual void cmp(unsigned size, Operand* a, Operand* b) = 0; virtual void jl(Operand* address) = 0; diff --git a/src/finder.cpp b/src/finder.cpp index d017e4ec4b..ae784eb48c 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -16,14 +16,6 @@ using namespace vm; namespace { -void* -allocate(System* s, unsigned size) -{ - void* p = s->tryAllocate(size); - if (p == 0) s->abort(); - return p; -} - const char* append(System* s, const char* a, const char* b, const char* c) diff --git a/src/machine.cpp b/src/machine.cpp index cd5c552487..fa7cae8707 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2211,7 +2211,7 @@ isAssignableFrom(Thread* t, object a, object b) return false; } -bool FORCE_ALIGN +bool instanceOf(Thread* t, object class_, object o) { if (o == 0) { diff --git a/src/machine.h b/src/machine.h index 25ac00d351..06e3298fea 100644 --- a/src/machine.h +++ b/src/machine.h @@ -145,6 +145,10 @@ struct JavaVMVTable { void* reserved1; void* reserved2; +#if (! TARGET_RT_MAC_CFM) && defined(__ppc__) + void* cfm_vectors[4]; +#endif + jint (JNICALL *DestroyJavaVM) (JavaVM*); @@ -164,6 +168,10 @@ struct JavaVMVTable { jint (JNICALL *AttachCurrentThreadAsDaemon) (JavaVM*, JNIEnv**, void*); + +#if TARGET_RT_MAC_CFM && defined(__ppc__) + void* real_functions[5]; +#endif }; struct JNIEnvVTable { @@ -172,6 +180,10 @@ struct JNIEnvVTable { void* reserved2; void* reserved3; +#if (! TARGET_RT_MAC_CFM) && defined(__ppc__) + void* cfm_vectors[225]; +#endif + jint (JNICALL *GetVersion) (JNIEnv*); @@ -1087,6 +1099,10 @@ struct JNIEnvVTable { jlong (JNICALL *GetDirectBufferCapacity) (JNIEnv*, jobject); + +#if TARGET_RT_MAC_CFM && defined(__ppc__) + void* real_functions[228]; +#endif }; inline int @@ -1526,7 +1542,7 @@ mark(Thread* t, object o, unsigned offset) } } -inline void FORCE_ALIGN +inline void set(Thread* t, object target, unsigned offset, object value) { cast(target, offset) = value; @@ -1736,7 +1752,7 @@ makeExceptionInInitializerError(Thread* t, object cause) return makeExceptionInInitializerError(t, 0, trace, cause); } -inline object FORCE_ALIGN +inline object makeNew(Thread* t, object class_) { assert(t, t->state == Thread::ActiveState); @@ -1751,7 +1767,7 @@ makeNew(Thread* t, object class_) return instance; } -inline object FORCE_ALIGN +inline object makeNewWeakReference(Thread* t, object class_) { assert(t, t->state == Thread::ActiveState); diff --git a/src/posix.cpp b/src/posix.cpp index e92dd23e14..18b38cca99 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -9,9 +9,10 @@ details. */ #ifdef __APPLE__ -#include "CoreFoundation/CoreFoundation.h" -#undef assert +# include "CoreFoundation/CoreFoundation.h" +# undef assert #endif + #include "sys/mman.h" #include "sys/types.h" #include "sys/stat.h" @@ -27,7 +28,7 @@ #include "stdint.h" #include "dirent.h" -#include "x86.h" +#include "arch.h" #include "system.h" #define ACQUIRE(x) MutexResource MAKE_NAME(mutexResource_) (x) @@ -67,34 +68,6 @@ MySystem* system; const int signals[] = { VisitSignal, SegFaultSignal, InterruptSignal }; -#ifdef __x86_64__ -# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP]) -# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_RBP]) -# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP]) -# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX]) -#elif defined __i386__ -# ifdef __APPLE__ -# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) -# define IP_REGISTER(context) (context->uc_mcontext->__ss.__eip) -# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__ebp) -# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp) -# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx) -# else -# define IP_REGISTER(context) (context->uc_mcontext->ss.eip) -# define BASE_REGISTER(context) (context->uc_mcontext->ss.ebp) -# define STACK_REGISTER(context) (context->uc_mcontext->ss.esp) -# define THREAD_REGISTER(context) (context->uc_mcontext->ss.ebx) -# endif -# else -# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP]) -# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP]) -# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP]) -# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_EBX]) -# endif -#else -# error unsupported architecture -#endif - void handleSignal(int signal, siginfo_t* info, void* context); @@ -105,14 +78,6 @@ run(void* r) return 0; } -void* -allocate(System* s, unsigned size) -{ - void* p = s->tryAllocate(size); - if (p == 0) abort(); - return p; -} - void pathOfExecutable(System* s, const char** retBuf, unsigned* size) { diff --git a/src/powerpc.S b/src/powerpc.S new file mode 100644 index 0000000000..80f44bf3d9 --- /dev/null +++ b/src/powerpc.S @@ -0,0 +1,158 @@ +/* Copyright (c) 2008, 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 "types.h" + +.text + +#define BYTES_PER_WORD 4 +#define LOCAL(x) L##x + +#ifdef __APPLE__ +.globl _vmNativeCall +_vmNativeCall: +#else +.globl vmNativeCall +vmNativeCall: +#endif + // save return address + mflr r0 + stw r0,8(r1) + + // r3 aka r13: function + // r4 : stackTotal + // r5 : memoryTable + // r6 : memoryCount + // r7 : gprTable + // r8 : fprTable + // r9 aka r14: returnType + + // r15 : stack frame size + // r16 : temporary + // r17 : temporary + + // save registers used for local variables + stw r13,24(r1) + stw r14,28(r1) + stw r15,32(r1) + stw r16,36(r1) + stw r17,40(r1) + + // allocate stack space + stwux r1,r1,r4 + + // save our argument registers so we can clobber them + mr r13,r3 + mr r14,r9 + + li r16,0 + b LOCAL(test) + +LOCAL(loop): + lwzx r17,r16,r5 + stwx r17,r16,r1 + addi r16,r16,BYTES_PER_WORD + +LOCAL(test): + cmplw r16,r6 + blt LOCAL(loop) + + // do we need to load the floating point registers? + cmpwi r8,0 + beq LOCAL(gpr) + + // yes, we do + lfd f1,0(r8) + lfd f2,8(r8) + lfd f3,16(r8) + lfd f4,24(r8) + lfd f5,32(r8) + lfd f6,40(r8) + lfd f7,48(r8) + lfd f8,56(r8) + lfd f9,64(r8) + lfd f10,72(r8) + lfd f11,80(r8) + lfd f12,88(r8) + lfd f13,96(r8) + +LOCAL(gpr): + // do we need to load the general-purpose registers? + cmpwi r7,0 + beq LOCAL(call) + + // yes, we do + mr r16,r7 + lwz r3,0(r16) + lwz r4,4(r16) + lwz r5,8(r16) + lwz r6,12(r16) + lwz r7,16(r16) + lwz r8,20(r16) + lwz r9,24(r16) + lwz r10,28(r16) + +LOCAL(call): + // load and call function address + mtctr r13 + bctrl + + // handle return value based on expected type + cmpwi r14,VOID_TYPE + bne LOCAL(float) + b LOCAL(exit) + +LOCAL(float): + cmpwi r14,FLOAT_TYPE + beq LOCAL(copy) + cmpwi r14,DOUBLE_TYPE + beq LOCAL(copy) + cmpwi r14,INT64_TYPE + beq LOCAL(exit) + mr r4,r3 + b LOCAL(exit) + +LOCAL(copy): + // move floating point return value to GPRs via memory + stfd f1,8(r1) + lwz r3,8(r1) + lwz r4,12(r1) + b LOCAL(exit) + +LOCAL(exit): + // restore stack pointer + lwz r1,0(r1) + + // restore registers used for local variables + lwz r13,24(r1) + lwz r14,28(r1) + lwz r15,32(r1) + lwz r16,36(r1) + lwz r17,40(r1) + + // load return address + lwz r0,8(r1) + mtlr r0 + + // return + blr + +#ifdef __APPLE__ +.globl _vmJump +_vmJump: +#else +.globl vmJump +vmJump: +#endif + mtlr r3 + mr r13,r4 + mr r1,r5 + mr r14,r6 + blr diff --git a/src/powerpc.cpp b/src/powerpc.cpp new file mode 100644 index 0000000000..2c42461726 --- /dev/null +++ b/src/powerpc.cpp @@ -0,0 +1,1920 @@ +#include "assembler.h" +#include "vector.h" + +using namespace vm; + +#define INDEX1(a, b) ((a) + (UnaryOperationCount * (b))) + +#define CAST1(x) reinterpret_cast(x) + +#define INDEX2(a, b, c) \ + ((a) \ + + (BinaryOperationCount * (b)) \ + + (BinaryOperationCount * OperandTypeCount * (c))) + +#define CAST2(x) reinterpret_cast(x) + +namespace { + +/* + * SIMPLE TYPES + */ +typedef uint8_t byte; +typedef uint16_t hword; +typedef uint32_t word; +typedef uint64_t dword; + +/* + * BITFIELD MASKS + */ +const word MASK_LOW16 0x0ffff; +const word MASK_LOW8 0x0ff; + +/* + * BITFIELD HANDLERS + */ +inline word low32(dword i) { + return (word)(i & 0x0ffffffff); +} +inline word high32(dword i) { + return low32(i >> 32); +} +inline hword low16(dword i) { + return (hword)(i & 0x0ffff); +} +inline hword high16(dword i) { + return low16(i >> 16); +} +inline hword higher16(dword i) { + return low16(i >> 32); +} +inline hword highest16(dword i) { + return low16(i >> 48); +} + +/* + * INSTRUCTION FORMATS + */ +inline word ifD(word op, word rt, word ra, word d) { + return op<<26|rt<<21|ra<<16|d; +} +inline word ifDS(word op, word rt, word ra, word ds, word xo) { + return op<<26|rt<<21|ra<<16|ds<<2|xo; +} +inline word ifI(word op, word li, word aa, word lk) { + return op<<26|li<<2|aa<<1|lk; +} +inline word ifB(word op, word bo, word bi, word bd, word aa, word lk) { + return op<<26|bo<<21|bi<<16|bd<<2|aa<<1|lk; +} +inline word ifSC(word op, word lev) { + return op<<26|lev<<5|2; +} +inline word ifX(word op, word rt, word ra, word rb, word xo, word rc) { + return op<<26|rt<<21|ra<<16|rb<<11|xo<<1|rc; +} +inline word ifXL(word op, word bt, word ba, word bb, word xo, word lk) { + return op<<26|bt<<21|ba<<16|bb<<11|xo<<1|lk; +} +inline word ifXFX(word op, word rt, word spr, word xo) { + return op<<26|rt<<21|spr<<11|xo<<1; +} +inline word ifXFL(word op, word flm, word frb, word xo, word rc) { + return op<<26|flm<<17|frb<<11|xo<<1|rc; +} +inline word ifXS(word op, word rs, word ra, word sh, word xo, word sh2, word rc) { + return op<<26|rs<<21|ra<<16|sh<<11|xo<<2|sh2<<1|rc; +} +inline word ifXO(word op, word rt, word ra, word rb, word oe, word xo, word rc) { + return op<<26|rt<<21|ra<<16|rb<<11|oe<<10|xo<<1|rc; +} +inline word ifA(word op, word frt, word fra, word frb, word frc, word xo, word rc) { + return op<<26|frt<<21|fra<<16|frb<<11|frc<<6|xo<<1|rc; +} +inline word ifM(word op, word rs, word ra, word rb, word mb, word me, word rc) { + return op<<26|rs<<21|ra<<16|rb<<11|mb<<6|me<<1|rc; +} +inline word ifMD(word op, word rs, word ra, word sh, word mb, word xo, word sh2, word rc) { + return op<<26|rs<<21|ra<<16|sh<<11|mb<<5|xo<<2|sh2<<1|rc; +} +inline word ifMDS(word op, word rs, word ra, word rb, word mb, word xo, word rc) { + return op<<26|rs<<21|ra<<16|rb<<11|mb<<5|xo<<1|rc; +} + +/* + * PROGRAMMING MODEL + */ +inline void +enum { + r0, + r1, + r2, + r3, + r4, + r5, + r6, + r7, + r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15, + r16, + r17, + r18, + r19, + r20, + r21, + r22, + r23, + r24, + r25, + r26, + r27, + r28, + r29, + r30, + r31 +}; + +/* + * INSTRUCTIONS + */ +inline void asLbz(Context* c, int rt, int ra, int i) { + int mc = ifD(34, rt, ra, i); + c->code.append4(mc); +} +inline void asLhz(Context* c, int rt, int ra, int i) { + int mc = ifD(40, rt, ra, i); + c->code.append4(mc); +} +inline void asLwz(Context* c, int rt, int ra, int i) { + int mc = ifD(32, rt, ra, i); + c->code.append4(mc); +} +inline void asStb(Context* c, int rs, int ra, int i) { + int mc = ifD(38, rs, ra, i); + c->code.append4(mc); +} +inline void asSth(Context* c, int rs, int ra, int i) { + int mc = ifD(44, rs, ra, i); + c->code.append4(mc); +} +inline void asStw(Context* c, int rs, int ra, int i) { + int mc = ifD(36, rs, ra, i); + c->code.append4(mc); +} +inline void asAdd(Context* c, int rt, int ra, int rb) { + int mc = ifXO(31, rt, ra, rb, 0, 266, 0); + c->code.append4(mc); +} +inline void asAddc(Context* c, int rt, int ra, int rb) { + int mc = ifXO(31, rt, ra, rb, 0, 10, 0); + c->code.append4(mc); +} +inline void asAdde(Context* c, int rt, int ra, int rb) { + int mc = ifXO(31, rt, ra, rb, 0, 138, 0); + c->code.append4(mc); +} +inline void asAddi(Context* c, int rt, int ra, int i) { + int mc = ifD(14, rt, ra, i); + c->code.append4(mc); +} +inline void asAddis(Context* c, int rt, int ra, int i) { + int mc = ifD(15, rt, ra, i); + c->code.append4(mc); +} +inline void asSubf(Context* c, int rt, int ra, int rb) { + int mc = ifXO(31, rt, ra, rb, 0, 40, 0); + c->code.append4(mc); +} +inline void asSubfc(Context* c, int rt, int ra, int rb) { + int mc = ifXO(31, rt, ra, rb, 0, 8, 0); + c->code.append4(mc); +} +inline void asSubfe() { + int mc = ifXO(31, rt, ra, rb, 0, 136, 0); + c->code.append4(mc); +} +inline void asAnd(Context* c, int rt, int ra, int rb) { + int mc = ifX(31, ra, rt, rb, 28, 0); + c->code.append4(mc); +} +inline void asAndi(Context* c, int rt, int ra, int rb) { + int mc = ifD(28, ra, rt, i); + c->code.append4(mc); +} +inline void asAndis(Context* c, int rt, int ra, int rb) { + int mc = ifD(29, ra, rt, i); + c->code.append4(mc); +} +inline void asOr(Context* c, int rt, int ra, int rb) { + int mc = ifX(31, ra, rt, rb, 444, 0); + c->code.append4(mc); +} +inline void asOri(Context* c, int rt, int ra, int i) { + int mc = ifD(24, rt, ra, i); + c->code.append4(mc); +} +inline void asOris(Context* c, int rt, int ra, int i) { + int mc = ifD(25, rt, ra, i); + c->code.append4(mc); +} +inline void asRlwinm(Context* c, int rt, int ra, int i, int mb, int me) { + int mc = ifM(21, ra, rt, i, mb, me, 0); + c->code.append4(mc); +} +inline void asRlwimi(Context* c, int rt, int ra, int i, int mb, int me) { + int mc = ifM(20, ra, rt, sh, mb, me, 0); + c->code.append4(mc); +} +inline void asSlw(Context* c, int rt, int ra, int sh) { + int mc = ifX(31, ra, rt, sh, 21, 0); + c->code.append4(mc); +} +inline void asSld(Context* c, int rt, int ra, int rb) { + int mc = ifX(31, ra, rt, rb, 27, 0); + c->code.append4(mc); +} +inline void asSrw(Context* c, int rt, int ra, int sh) { + int mc = ifX(31, ra, rt, sh, 536, 0); + c->code.append4(mc); +} +inline void asSraw(Context* c, int rt, int ra, int sh) { + int mc = ifX(31, ra, rt, sh, 792, 0); + c->code.append4(mc); +} +inline void asSrawi(Context* c, int rt, int ra, int sh) { + int mc = ifX(31, ra, rt, sh, 824, 0); + c->code.append4(mc); +} + +/* + * PSEUDO-INSTRUCTIONS + */ +inline void asLi(Context* c, int rt, int i) { asOri(c, rt, 0, i); } +inline void asLis(Context* c, int rt, int i) { asOris(c, rt, 0, i); } +inline void asMr(Context* c, int rt, int ra) { asOr(c, rt, ra, ra); } +inline void asSlwi(Context* c, int rt, int ra, int i) { asRlwinm(c, rt, ra, i, 0, 31-i); } +inline void asSrwi(Context* c, int rt, int ra, int i) { asRlwinm(c, rt, ra, 32-i, i, 31); } +inline void asSub(Context* c, int rt, int ra, int rb) { asSubf(c, rt, rb, ra); } +inline void asSubc(Context* c, int rt, int ra, int rb) { asSubfc(c, rt, rb, ra); } +inline void asSubi() { asAddi(c, rt, ra, -i); } + + +ResolvedPromise* +resolved(Context* c, int64_t value) +{ + return new (c->zone->allocate(sizeof(ResolvedPromise))) + ResolvedPromise(value); +} + +class CodePromise: public Promise { + public: + CodePromise(Context* c, unsigned offset): c(c), offset(offset) { } + + virtual int64_t value() { + if (resolved()) { + return reinterpret_cast(c->result + offset); + } + abort(c); + } + + virtual bool resolved() { + return c->result != 0; + } + + Context* c; + unsigned offset; +}; + +CodePromise* +codePromise(Context* c, unsigned offset) +{ + return new (c->zone->allocate(sizeof(CodePromise))) CodePromise(c, offset); +} + +class Task { + public: + Task(Task* next): next(next) { } + + virtual void run(Context* c) = 0; + + Task* next; +}; + +class OffsetTask: public Task { + public: + OffsetTask(Task* next, Promise* promise, unsigned instructionOffset, + unsigned instructionSize): + Task(next), + promise(promise), + instructionOffset(instructionOffset), + instructionSize(instructionSize) + { } + + virtual void run(Context* c) { + uint8_t* instruction = c->result + instructionOffset; + intptr_t v = reinterpret_cast(promise->value()) + - instruction - instructionSize; + + expect(c, isInt32(v)); + + int32_t v4 = v; + memcpy(instruction + instructionSize - 4, &v4, 4); + } + + Promise* promise; + unsigned instructionOffset; + unsigned instructionSize; +}; + +void +appendOffsetTask(Context* c, Promise* promise, int instructionOffset, + unsigned instructionSize) +{ + c->tasks = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask + (c->tasks, promise, instructionOffset, instructionSize); +} + +class ImmediateTask: public Task { + public: + ImmediateTask(Task* next, Promise* promise, unsigned offset): + Task(next), + promise(promise), + offset(offset) + { } + + virtual void run(Context* c) { + intptr_t v = promise->value(); + memcpy(c->result + offset, &v, BytesPerWord); + } + + Promise* promise; + unsigned offset; +}; + +void +appendImmediateTask(Context* c, Promise* promise, unsigned offset) +{ + c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask + (c->tasks, promise, offset); +} + +typedef void (*OperationType)(Context*); +OperationType +Operations[OperationCount]; + +typedef void (*UnaryOperationType)(Context*, unsigned, Assembler::Operand*); +UnaryOperationType +UnaryOperations[UnaryOperationCount * OperandTypeCount]; + +typedef void (*BinaryOperationType) +(Context*, unsigned, Assembler::Operand*, Assembler::Operand*); +BinaryOperationType +BinaryOperations[BinaryOperationCount * OperandTypeCount * OperandTypeCount]; + +void +return_(Context* c) +{ + c->code.append(0xc3); +} + +void +unconditional(Context* c, unsigned jump, Assembler::Constant* a) +{ + appendOffsetTask(c, a->value, c->code.length(), 5); + + c->code.append(jump); + c->code.append4(0); +} + +void +conditional(Context* c, unsigned condition, Assembler::Constant* a) +{ + appendOffsetTask(c, a->value, c->code.length(), 6); + + c->code.append(0x0f); + c->code.append(condition); + c->code.append4(0); +} + +void +moveCR(Context*, unsigned, Assembler::Constant*, Assembler::Register*); + +void +callR(Context*, unsigned, Assembler::Register*); + +void +callC(Context* c, unsigned size UNUSED, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + unconditional(c, 0xe8, a); +} + +void +longCallC(Context* c, unsigned size, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + if (BytesPerWord == 8) { + Assembler::Register r(r10); + moveCR(c, size, a, &r); + callR(c, size, &r); + } else { + callC(c, size, a); + } +} + +void +alignedCallC(Context* c, unsigned size, Assembler::Constant* a) +{ + while ((c->code.length() + 1) % 4) { + c->code.append(0x90); + } + callC(c, size, a); +} + +void +callR(Context* c, unsigned size UNUSED, Assembler::Register* a) +{ + assert(c, size == BytesPerWord); + + if (a->low & 8) rex(c, 0x40, a->low); + c->code.append(0xff); + c->code.append(0xd0 | (a->low & 7)); +} + +void +callM(Context* c, unsigned size UNUSED, Assembler::Memory* a) +{ + assert(c, size == BytesPerWord); + + encode(c, 0xff, 2, a, false); +} + +void +jumpR(Context* c, unsigned size UNUSED, Assembler::Register* a) +{ + assert(c, size == BytesPerWord); + + if (a->low & 8) rex(c, 0x40, a->low); + c->code.append(0xff); + c->code.append(0xe0 | (a->low & 7)); +} + +void +jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + unconditional(c, 0xe9, a); +} + +void +longJumpC(Context* c, unsigned size, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + if (BytesPerWord == 8) { + Assembler::Register r(r10); + moveCR(c, size, a, &r); + jumpR(c, size, &r); + } else { + jumpC(c, size, a); + } +} + +void +jumpM(Context* c, unsigned size UNUSED, Assembler::Memory* a) +{ + assert(c, size == BytesPerWord); + + encode(c, 0xff, 4, a, false); +} + +void +jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + conditional(c, 0x84, a); +} + +void +jumpIfNotEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + conditional(c, 0x85, a); +} + +void +jumpIfGreaterC(Context* c, unsigned size UNUSED, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + conditional(c, 0x8f, a); +} + +void +jumpIfGreaterOrEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + conditional(c, 0x8d, a); +} + +void +jumpIfLessC(Context* c, unsigned size UNUSED, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + conditional(c, 0x8c, a); +} + +void +jumpIfLessOrEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) +{ + assert(c, size == BytesPerWord); + + conditional(c, 0x8e, a); +} + +void +pushR(Context*, unsigned, Assembler::Register*); + +void +pushC(Context* c, unsigned size, Assembler::Constant* a) +{ + if (BytesPerWord == 4 and size == 8) { + int64_t v = a->value->value(); + + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + pushC(c, 4, &ah); + pushC(c, 4, &al); + } else { + if (a->value->resolved()) { + int64_t v = a->value->value(); + if (isInt8(v)) { + c->code.append(0x6a); + c->code.append(v); + } else if (isInt32(v)) { + c->code.append(0x68); + c->code.append4(v); + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, size, a, &tmp); + pushR(c, size, &tmp); + c->client->releaseTemporary(tmp.low); + } + } else { + if (BytesPerWord == 4) { + c->code.append(0x68); + appendImmediateTask(c, a->value, c->code.length()); + c->code.appendAddress(static_cast(0)); + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, size, a, &tmp); + pushR(c, size, &tmp); + c->client->releaseTemporary(tmp.low); + } + } + } +} + +void +moveAR(Context*, unsigned, Assembler::Address*, Assembler::Register* b); + +void +pushA(Context* c, unsigned size, Assembler::Address* a) +{ + assert(c, BytesPerWord == 8 or size == 4); // todo + + Assembler::Register tmp(c->client->acquireTemporary()); + moveAR(c, size, a, &tmp); + pushR(c, size, &tmp); + c->client->releaseTemporary(tmp.low); +} + +void +pushR(Context* c, unsigned size, Assembler::Register* a) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Register ah(a->high); + + pushR(c, 4, &ah); + pushR(c, 4, a); + } else { + c->code.append(0x50 | a->low); + } +} + +void +pushM(Context* c, unsigned size, Assembler::Memory* a) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); + + pushM(c, 4, &ah); + pushM(c, 4, a); + } else { + assert(c, BytesPerWord == 4 or size == 8); + + encode(c, 0xff, 6, a, false); + } +} + +void +move4To8RR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b); + +void +popR(Context* c, unsigned size, Assembler::Register* a) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Register ah(a->high); + + popR(c, 4, a); + popR(c, 4, &ah); + } else { + c->code.append(0x58 | a->low); + if (BytesPerWord == 8 and size == 4) { + move4To8RR(c, 0, a, a); + } + } +} + +void +popM(Context* c, unsigned size, Assembler::Memory* a) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); + + popM(c, 4, a); + popM(c, 4, &ah); + } else { + assert(c, BytesPerWord == 4 or size == 8); + + encode(c, 0x8f, 0, a, false); + } +} + +void +moveRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b); + +void +xorRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b); + +void +negateR(Context* c, unsigned size, Assembler::Register* a) +{ + if (BytesPerWord == 4 and size == 8) { + assert(c, a->low == rax and a->high == rdx); + + ResolvedPromise zeroPromise(0); + Assembler::Constant zero(&zeroPromise); + + Assembler::Register ah(a->high); + + negateR(c, 4, a); + //addCarryCR(c, 4, &zero, &ah); + negateR(c, 4, &ah); + } else { + if (size == 8) rex(c); + c->code.append(0xf7); + c->code.append(0xd8 | a->low); + } +} + +void +leaMR(Context* c, unsigned size, Assembler::Memory* b, Assembler::Register* a) +{ + if (BytesPerWord == 8 and size == 4) { + encode(c, 0x8d, a->low, b, false); + } else { + assert(c, BytesPerWord == 8 or size == 4); + + encode(c, 0x8d, a->low, b, true); + } +} + +void +moveCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + int64_t imm = a->value->value(); + + if(size == 8) { + Assembler::Register bh(b->high); + ResolvedPromise low(low32(imm)); + Assembler::Constant al(&low); + ResolvedPromise high(high32(imm)); + Assembler::Constant ah(&high); + + moveCR(c, 4, &al, b); + moveCR(c, 4, &ah, &bh); + } else { + int rt = b->low; + asLis(c, rt, high16(imm)); + asOri(c, rt, rt, low16(imm)); + } +} + +void +moveCM(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Memory* b) +{ + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, size, a, tmp); + moveRM(c, size, tmp, b); + c->client->releaseTemporary(tmp.low); +} + +void +moveRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if(a->low == b->low) return; // trivial case - and not a NOP in PPC! + + if (size == 8) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + moveRR(c, 4, a, b); + moveRR(c, 4, &ah, &bh); + } else { + asMr(c, b->low, a->low); + } +} + +void +moveRM(Context* c, unsigned size, Assembler::Register* a, Assembler::Memory* b) +{ + Assembler::Register tmp(c->client->acquireTemporary()); + int d = b->offset; + int ra = b->base; + int rs = a->low; + + if(b->index != NoRegister) { + asSlwi(c, tmp, b->index, b->scale); + asAdd(c, tmp, tmp, ra); + ra = tmp; + } + + switch (size) { + case 1: + asStb(c, rs, ra, d); + break; + + case 2: + asSth(c, rs, ra, d); + break; + + case 4: + asStw(c, rs, ra, d); + break; + + case 8: + Assembler::Register ah(a->high); + Assembler::Memory bl(b->base, b->offset + 4, b->index, b->scale); + moveRM(c, 4, a, &bl); + moveRM(c, 4, &ah, b); + break; + + default: abort(c); + } + } + + c->client->releaseTemporary(tmp.low); +} + +void +move4To8RR(Context* c, unsigned, Assembler::Register* a, + Assembler::Register* b) +{ + Assembler::Register bh(b->high); + moveRR(c, 4, a, b); + moveRR(c, 4, a, &bh); + asSrawi(c, bh.low, bh.low, 31); +} + +void +moveMR(Context* c, unsigned size, Assembler::Memory* a, Assembler::Register* b) +{ + int d = a->offset; + int rt = b->low; + int ra = a->base; // register part of the address + + if(a->index != NoRegister) { // include the index in the EA + asSlwi(c, rt, a->index, a->scale); + asAdd(c, rt, rt, ra); + ra = rt + } + + switch (size) { + case 1: + asLbz(c, rt, ra, d); + break; + + case 2: + asLhz(c, rt, ra, d); + break; + + case 4: + asLwz(c, rt, ra, d); + break; + + case 8: + Assembler::Memory al(a->base, a->offset+4, a->index, a->scale); + Assembler::Register bh(b->high); + moveMR(c, 4, &al, b); + moveMR(c, 4, a, &bh); + break; + + default: abort(c); + } +} + +void +moveAR(Context* c, unsigned size, Assembler::Address* a, + Assembler::Register* b) +{ + Assembler::Constant constant(a->address); + Assembler::Memory memory(b->low, 0, -1, 0); + moveCR(c, size, &constant, b); + moveMR(c, size, &memory, b); +} + +void +moveAM(Context* c, unsigned size, Assembler::Address* a, + Assembler::Memory* b) +{ + Assembler::Register tmp(c->client->acquireTemporary()); + moveAR(c, size, a, &tmp); + moveRM(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); +} + +void +moveMM(Context* c, unsigned size, Assembler::Memory* a, + Assembler::Memory* b) +{ + Assembler::Register tmp(c->client->acquireTemporary()); + moveMR(c, size, a, tmp); + moveRM(c, size, tmp, b); + c->client->releaseTemporary(tmp.low); +} + +void +move4To8MR(Context* c, unsigned, Assembler::Memory* a, Assembler::Register* b) +{ + moveMR(c, 4, a, b); + move4To8RR(c, 0, b, b); +} + +void +moveZMR(Context* c, unsigned size, Assembler::Memory* a, + Assembler::Register* b) +{ + moveMR(c, size, a, b); +} + +void +moveZRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + switch(size) { + case 1: + asAndi(c, b->low, a->low, MASK_LOW8); + break; + + case 2: + asAndi(c, b->low, a->low, MASK_LOW16); + break; + + case 4: + moveRR(c, size, a, b); + break; + + case 8: + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + moveZRR(c, 4, a, b); + moveZRR(c, 4, &ah, &bh); + break; + + default: + abort(c); + } +} + +void +swapRR(Context* c, unsigned size, Assembler::Register* a, Assembler::Register* b) +{ + Assembler::Register tmp(c->client->acquireTemporary()); + moveRR(c, size, a, &tmp); + moveRR(c, size, b, a); + moveRR(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); +} + +void +addCM(Context* c, unsigned size UNUSED, Assembler::Constant* a, + Assembler::Memory* b) +{ + Assembler::Register tmp(c->client->acquireTemporary()); + + moveMR(c, 4, b, &tmp); + addCR(c, 4, a, &tmp); + moveRM(c, 4, &tmp, b); + + c->client->releaseTemporary(tmp.low); +} + +void +addCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + int64_t imm = a->value->value(); + + if(imm) { + if(size == 8) { // 64-bit add (PowerPC not conducive to multi-precision constant arithmetic + Assembler::Register tmp(c->client->acquireTemporary(), + c->client->acquireTemporary()); + + moveCR(c, 8, a, tmp); + addRR(c, 8, tmp, b); + + c->client->releaseTemporary(tmp.low); + c->client->releaseTemporary(tmp.high); + } else { // 32-bit add + int rt = b->low; + asAddi(c, rt, rt, low16(imm)); + asAddis(c, rt, rt, high16(imm)); + } + } +} + +void +subtractCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + ResolvedPromise neg(-a->value->value()); + Assembler::Constant aneg(&neg); + addCR(c, size, &aneg, b); +} + +void +subtractRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if(size == 8) { + asSubc(c, b->low, b->low, a->low); + asSubfe(c, b->high, a->high, b->high); + } else + asSub(c, b->low, b->low, a->low); +} + +void +addRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if(size == 8) { + asAddc(c, b->low, b->low, a->low); + asAdde(c, b->high, b->high, a->high); + } else + asAdd(c, b->low, b->low, a->low); +} + +void +addRM(Context* c, unsigned size UNUSED, Assembler::Register* a, + Assembler::Memory* b) +{ + Assembler::Register tmp(c->client->acquireTemporary()); + moveMR(c, size, b, tmp); + addRR(c, size, a, tmp); + moveRM(c, size, tmp, b); + c->client->releaseTemporary(); +} + +void +multiplyRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if (BytesPerWord == 4 and size == 8) { + assert(c, b->high == rdx); + assert(c, b->low != rax); + assert(c, a->low != rax); + assert(c, a->high != rax); + + c->client->save(rax); + + Assembler::Register axdx(rax, rdx); + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + moveRR(c, 4, b, &axdx); + multiplyRR(c, 4, &ah, b); + multiplyRR(c, 4, a, &bh); + addRR(c, 4, &bh, b); + + // mul a->low,%eax%edx + c->code.append(0xf7); + c->code.append(0xe0 | a->low); + + addRR(c, 4, b, &bh); + moveRR(c, 4, &axdx, b); + + c->client->restore(rax); + } else { + if (size == 8) rex(c); + c->code.append(0x0f); + c->code.append(0xaf); + c->code.append(0xc0 | (b->low << 3) | a->low); + } +} + +void +multiplyCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + if (BytesPerWord == 4 and size == 8) { + const uint32_t mask = ~((1 << rax) | (1 << rdx)); + Assembler::Register tmp(c->client->acquireTemporary(mask), + c->client->acquireTemporary(mask)); + + moveCR(c, size, a, &tmp); + multiplyRR(c, size, &tmp, b); + + c->client->releaseTemporary(tmp.low); + c->client->releaseTemporary(tmp.high); + } else { + int64_t v = a->value->value(); + if (v) { + if (isInt32(v)) { + if (size == 8) rex(c); + if (isInt8(v)) { + c->code.append(0x6b); + c->code.append(0xc0 | (b->low << 3) | b->low); + c->code.append(v); + } else { + c->code.append(0x69); + c->code.append(0xc0 | (b->low << 3) | b->low); + c->code.append4(v); + } + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, size, a, &tmp); + multiplyRR(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); + } + } + } +} + +void +divideRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b UNUSED) +{ + assert(c, BytesPerWord == 8 or size == 4); + + assert(c, b->low == rax); + assert(c, a->low != rdx); + + c->client->save(rdx); + + if (size == 8) rex(c); + c->code.append(0x99); // cdq + if (size == 8) rex(c); + c->code.append(0xf7); + c->code.append(0xf8 | a->low); + + c->client->restore(rdx); +} + +void +divideCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + assert(c, BytesPerWord == 8 or size == 4); + + const uint32_t mask = ~((1 << rax) | (1 << rdx)); + Assembler::Register tmp(c->client->acquireTemporary(mask)); + moveCR(c, size, a, &tmp); + divideRR(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); +} + +void +remainderRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + assert(c, BytesPerWord == 8 or size == 4); + + assert(c, b->low == rax); + assert(c, a->low != rdx); + + c->client->save(rdx); + + if (size == 8) rex(c); + c->code.append(0x99); // cdq + if (size == 8) rex(c); + c->code.append(0xf7); + c->code.append(0xf8 | a->low); + + Assembler::Register dx(rdx); + moveRR(c, BytesPerWord, &dx, b); + + c->client->restore(rdx); +} + +void +remainderCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + assert(c, BytesPerWord == 8 or size == 4); + + const uint32_t mask = ~((1 << rax) | (1 << rdx)); + Assembler::Register tmp(c->client->acquireTemporary(mask)); + moveCR(c, size, a, &tmp); + remainderRR(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); +} + +void +andRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + andRR(c, 4, a, b); + andRR(c, 4, &ah, &bh); + } else { + if (size == 8) rex(c); + c->code.append(0x21); + c->code.append(0xc0 | (a->low << 3) | b->low); + } +} + +void +andCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + int64_t v = a->value->value(); + + if (BytesPerWord == 4 and size == 8) { + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + Assembler::Register bh(b->high); + + andCR(c, 4, &al, b); + andCR(c, 4, &ah, &bh); + } else { + if (isInt32(v)) { + if (size == 8) rex(c); + if (isInt8(v)) { + c->code.append(0x83); + c->code.append(0xe0 | b->low); + c->code.append(v); + } else { + c->code.append(0x81); + c->code.append(0xe0 | b->low); + c->code.append4(v); + } + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, size, a, &tmp); + andRR(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); + } + } +} + +void +andCM(Context* c, unsigned size UNUSED, Assembler::Constant* a, + Assembler::Memory* b) +{ + assert(c, BytesPerWord == 8 or size == 4); + + int64_t v = a->value->value(); + + encode(c, isInt8(a->value->value()) ? 0x83 : 0x81, 5, b, true); + if (isInt8(v)) { + c->code.append(v); + } else if (isInt32(v)) { + c->code.append4(v); + } else { + abort(c); + } +} + +void +orRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + orRR(c, 4, a, b); + orRR(c, 4, &ah, &bh); + } else { + if (size == 8) rex(c); + c->code.append(0x09); + c->code.append(0xc0 | (a->low << 3) | b->low); + } +} + +void +orCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + int64_t v = a->value->value(); + if (v) { + if (BytesPerWord == 4 and size == 8) { + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + Assembler::Register bh(b->high); + + orCR(c, 4, &al, b); + orCR(c, 4, &ah, &bh); + } else { + if (isInt32(v)) { + if (size == 8) rex(c); + if (isInt8(v)) { + c->code.append(0x83); + c->code.append(0xc8 | b->low); + c->code.append(v); + } else { + c->code.append(0x81); + c->code.append(0xc8 | b->low); + c->code.append4(v); + } + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, size, a, &tmp); + orRR(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); + } + } + } +} + +void +xorRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + xorRR(c, 4, a, b); + xorRR(c, 4, &ah, &bh); + } else { + if (size == 8) rex(c); + c->code.append(0x31); + c->code.append(0xc0 | (a->low << 3) | b->low); + } +} + +void +xorCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + int64_t v = a->value->value(); + if (v) { + if (BytesPerWord == 4 and size == 8) { + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + Assembler::Register bh(b->high); + + xorCR(c, 4, &al, b); + xorCR(c, 4, &ah, &bh); + } else { + if (isInt32(v)) { + if (size == 8) rex(c); + if (isInt8(v)) { + c->code.append(0x83); + c->code.append(0xf0 | b->low); + c->code.append(v); + } else { + c->code.append(0x81); + c->code.append(0xf0 | b->low); + c->code.append4(v); + } + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, size, a, &tmp); + xorRR(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); + } + } + } +} + +void +compareCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b); + +void +shiftLeftRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if(size == 8) { + } else + asSlw(c, a->low, a->low, b->low); +} + +void +shiftLeftCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + if(size == 8) { + } else + asSlwi(c, b->low, b->low, a->value->value()); +} + +void +shiftRightRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if(size == 8) { + } else + asSraw(c, b->low, b->low, a->low); +} + +void +shiftRightCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + if(size == 8) { + } else + asSrawi(c, b->low, b->low, a->value->value()); +} + +void +unsignedShiftRightRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if(size == 8) { + } else + asSrw(c, b->low, b->low, a->low); +} + +void +unsignedShiftRightCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + if(size == 8) { + } else + asSrwi(c, b->low, b->low, a->value->value()); +} + +void +multiwordCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, + Assembler::Operand* bl, Assembler::Operand* bh, + BinaryOperationType op) +{ + op(c, BytesPerWord, ah, bh); + + // if the high order bits are equal, we compare the low order + // bits; otherwise, we jump past that comparison + c->code.append(0x0f); + c->code.append(0x85); // jne + + unsigned comparisonOffset = c->code.length(); + c->code.append4(0); + + op(c, BytesPerWord, al, bl); + + int32_t comparisonSize = c->code.length() - comparisonOffset - 4; + c->code.set(comparisonOffset, &comparisonSize, 4); +} + +void +compareRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + multiwordCompare(c, a, &ah, b, &bh, CAST2(compareRR)); + } else { + if (size == 8) rex(c); + c->code.append(0x39); + c->code.append(0xc0 | (a->low << 3) | b->low); + } +} + +void +compareAR(Context* c, unsigned size, Assembler::Address* a, + Assembler::Register* b) +{ + assert(c, BytesPerWord == 8 or size == 4); // todo + + Assembler::Register tmp(c->client->acquireTemporary()); + moveAR(c, size, a, &tmp); + compareRR(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); +} + +void +compareCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b) +{ + int64_t v = a->value->value(); + + if (BytesPerWord == 4 and size == 8) { + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + Assembler::Register bh(b->high); + + multiwordCompare(c, &al, &ah, b, &bh, CAST2(compareCR)); + } else { + if (isInt32(v)) { + if (size == 8) rex(c); + if (isInt8(v)) { + c->code.append(0x83); + c->code.append(0xf8 | b->low); + c->code.append(v); + } else { + c->code.append(0x81); + c->code.append(0xf8 | b->low); + c->code.append4(v); + } + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, size, a, &tmp); + compareRR(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); + } + } +} + +void +compareCM(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Memory* b) +{ + int64_t v = a->value->value(); + + if (BytesPerWord == 4 and size == 8) { + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale); + + multiwordCompare(c, &al, &ah, b, &bh, CAST2(compareCM)); + } else { + encode(c, isInt8(v) ? 0x83 : 0x81, 7, b, true); + + if (isInt8(v)) { + c->code.append(v); + } else if (isInt32(v)) { + c->code.append4(v); + } else { + abort(c); + } + } +} + +void +compareRM(Context* c, unsigned size, Assembler::Register* a, + Assembler::Memory* b) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Register ah(a->high); + Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale); + + multiwordCompare(c, a, &ah, b, &bh, CAST2(compareRM)); + } else { + if (BytesPerWord == 8 and size == 4) { + move4To8RR(c, size, a, a); + } + encode(c, 0x39, a->low, b, true); + } +} + +void +compareMR(Context* c, unsigned size, Assembler::Memory* a, + Assembler::Register* b) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); + Assembler::Register bh(b->high); + + multiwordCompare(c, a, &ah, b, &bh, CAST2(compareMR)); + } else { + if (BytesPerWord == 8 and size == 4) { + move4To8RR(c, size, b, b); + } + encode(c, 0x3b, b->low, a, true); + } +} + +void +compareMM(Context* c, unsigned size, Assembler::Memory* a, + Assembler::Memory* b) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); + Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale); + + multiwordCompare(c, a, &ah, b, &bh, CAST2(compareMM)); + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveMR(c, size, a, &tmp); + compareRM(c, size, &tmp, b); + c->client->releaseTemporary(tmp.low); + } +} + +void +compareRC(Context* c, unsigned size, Assembler::Register* a, + Assembler::Constant* b) +{ + if (BytesPerWord == 4 and size == 8) { + Assembler::Register ah(a->high); + + int64_t v = b->value->value(); + + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant bl(&low); + + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant bh(&high); + + multiwordCompare(c, a, &ah, &bl, &bh, CAST2(compareRC)); + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, size, b, &tmp); + compareRR(c, size, a, &tmp); + c->client->releaseTemporary(tmp.low); + } +} + +void +populateTables() +{ + Operations[Return] = return_; + + const int Constant = ConstantOperand; + const int Address = AddressOperand; + const int Register = RegisterOperand; + const int Memory = MemoryOperand; + + UnaryOperations[INDEX1(Call, Constant)] = CAST1(callC); + UnaryOperations[INDEX1(Call, Register)] = CAST1(callR); + UnaryOperations[INDEX1(Call, Memory)] = CAST1(callM); + + UnaryOperations[INDEX1(LongCall, Constant)] = CAST1(longCallC); + + UnaryOperations[INDEX1(AlignedCall, Constant)] = CAST1(alignedCallC); + + UnaryOperations[INDEX1(Jump, Constant)] = CAST1(jumpC); + UnaryOperations[INDEX1(Jump, Register)] = CAST1(jumpR); + UnaryOperations[INDEX1(Jump, Memory)] = CAST1(jumpM); + + UnaryOperations[INDEX1(LongJump, Constant)] = CAST1(longJumpC); + + UnaryOperations[INDEX1(JumpIfEqual, Constant)] = CAST1(jumpIfEqualC); + UnaryOperations[INDEX1(JumpIfNotEqual, Constant)] = CAST1(jumpIfNotEqualC); + UnaryOperations[INDEX1(JumpIfGreater, Constant)] = CAST1(jumpIfGreaterC); + UnaryOperations[INDEX1(JumpIfGreaterOrEqual, Constant)] + = CAST1(jumpIfGreaterOrEqualC); + UnaryOperations[INDEX1(JumpIfLess, Constant)] = CAST1(jumpIfLessC); + UnaryOperations[INDEX1(JumpIfLessOrEqual, Constant)] + = CAST1(jumpIfLessOrEqualC); + + UnaryOperations[INDEX1(Push, Constant)] = CAST1(pushC); + UnaryOperations[INDEX1(Push, Address)] = CAST1(pushA); + UnaryOperations[INDEX1(Push, Register)] = CAST1(pushR); + UnaryOperations[INDEX1(Push, Memory)] = CAST1(pushM); + + UnaryOperations[INDEX1(Pop, Register)] = CAST1(popR); + UnaryOperations[INDEX1(Pop, Memory)] = CAST1(popM); + + UnaryOperations[INDEX1(Negate, Register)] = CAST1(negateR); + + BinaryOperations[INDEX2(LoadAddress, Memory, Register)] = CAST2(leaMR); + + BinaryOperations[INDEX2(Move, Constant, Register)] = CAST2(moveCR); + BinaryOperations[INDEX2(Move, Constant, Memory)] = CAST2(moveCM); + BinaryOperations[INDEX2(Move, Register, Memory)] = CAST2(moveRM); + BinaryOperations[INDEX2(Move, Register, Register)] = CAST2(moveRR); + BinaryOperations[INDEX2(Move, Memory, Register)] = CAST2(moveMR); + BinaryOperations[INDEX2(Move, Address, Register)] = CAST2(moveAR); + BinaryOperations[INDEX2(Move, Address, Memory)] = CAST2(moveAM); + BinaryOperations[INDEX2(Move, Memory, Memory)] = CAST2(moveMM); + + BinaryOperations[INDEX2(Move4To8, Register, Register)] = CAST2(move4To8RR); + BinaryOperations[INDEX2(Move4To8, Memory, Register)] = CAST2(move4To8MR); + + BinaryOperations[INDEX2(MoveZ, Memory, Register)] = CAST2(moveZMR); + BinaryOperations[INDEX2(MoveZ, Register, Register)] = CAST2(moveZRR); + + BinaryOperations[INDEX2(Swap, Register, Register)] = CAST2(swapRR); + + BinaryOperations[INDEX2(Add, Constant, Register)] = CAST2(addCR); + BinaryOperations[INDEX2(Add, Register, Register)] = CAST2(addRR); + BinaryOperations[INDEX2(Add, Register, Memory)] = CAST2(addRM); + BinaryOperations[INDEX2(Add, Constant, Memory)] = CAST2(addCM); + + BinaryOperations[INDEX2(Multiply, Register, Register)] = CAST2(multiplyRR); + BinaryOperations[INDEX2(Multiply, Constant, Register)] = CAST2(multiplyCR); + + BinaryOperations[INDEX2(Divide, Register, Register)] = CAST2(divideRR); + BinaryOperations[INDEX2(Divide, Constant, Register)] = CAST2(divideCR); + + BinaryOperations[INDEX2(Remainder, Constant, Register)] = CAST2(remainderCR); + BinaryOperations[INDEX2(Remainder, Register, Register)] = CAST2(remainderRR); + + BinaryOperations[INDEX2(And, Register, Register)] = CAST2(andRR); + BinaryOperations[INDEX2(And, Constant, Register)] = CAST2(andCR); + BinaryOperations[INDEX2(And, Constant, Memory)] = CAST2(andCM); + + BinaryOperations[INDEX2(Or, Register, Register)] = CAST2(orRR); + BinaryOperations[INDEX2(Or, Constant, Register)] = CAST2(orCR); + + BinaryOperations[INDEX2(Xor, Register, Register)] = CAST2(xorRR); + BinaryOperations[INDEX2(Xor, Constant, Register)] = CAST2(xorCR); + + BinaryOperations[INDEX2(ShiftLeft, Register, Register)] = CAST2(shiftLeftRR); + BinaryOperations[INDEX2(ShiftLeft, Constant, Register)] = CAST2(shiftLeftCR); + + BinaryOperations[INDEX2(ShiftRight, Register, Register)] + = CAST2(shiftRightRR); + BinaryOperations[INDEX2(ShiftRight, Constant, Register)] + = CAST2(shiftRightCR); + + BinaryOperations[INDEX2(UnsignedShiftRight, Register, Register)] + = CAST2(unsignedShiftRightRR); + BinaryOperations[INDEX2(UnsignedShiftRight, Constant, Register)] + = CAST2(unsignedShiftRightCR); + + BinaryOperations[INDEX2(Subtract, Constant, Register)] = CAST2(subtractCR); + BinaryOperations[INDEX2(Subtract, Register, Register)] = CAST2(subtractRR); + + BinaryOperations[INDEX2(Compare, Constant, Register)] = CAST2(compareCR); + BinaryOperations[INDEX2(Compare, Register, Constant)] = CAST2(compareRC); + BinaryOperations[INDEX2(Compare, Register, Register)] = CAST2(compareRR); + BinaryOperations[INDEX2(Compare, Address, Register)] = CAST2(compareAR); + BinaryOperations[INDEX2(Compare, Register, Memory)] = CAST2(compareRM); + BinaryOperations[INDEX2(Compare, Memory, Register)] = CAST2(compareMR); + BinaryOperations[INDEX2(Compare, Constant, Memory)] = CAST2(compareCM); + BinaryOperations[INDEX2(Compare, Memory, Memory)] = CAST2(compareMM); +} + +class MyAssembler: public Assembler { + public: + MyAssembler(System* s, Allocator* a, Zone* zone): c(s, a, zone) { + static bool populated = false; + if (not populated) { + populated = true; + populateTables(); + } + } + + virtual void setClient(Client* client) { + assert(&c, c.client == 0); + c.client = client; + } + + virtual unsigned registerCount() { + return 8;//BytesPerWord == 4 ? 8 : 16; + } + + virtual int base() { + return rbp; + } + + virtual int stack() { + return rsp; + } + + virtual int thread() { + return rbx; + } + + virtual int returnLow() { + return rax; + } + + virtual int returnHigh() { + return (BytesPerWord == 4 ? rdx : NoRegister); + } + + virtual unsigned argumentRegisterCount() { + return (BytesPerWord == 4 ? 0 : 6); + } + + virtual int argumentRegister(unsigned index) { + assert(&c, BytesPerWord == 8); + + switch (index) { + case 0: + return rdi; + case 1: + return rsi; + case 2: + return rdx; + case 3: + return rcx; + case 4: + return r8; + case 5: + return r9; + default: + abort(&c); + } + } + + virtual void plan(UnaryOperation op, unsigned size, uint8_t* typeMask, + uint64_t* registerMask, bool* thunk) + { + if (op == Negate and BytesPerWord == 4 and size == 8) { + *typeMask = 1 << RegisterOperand; + *registerMask = (static_cast(1) << (rdx + 32)) + | (static_cast(1) << rax); + } else { + *typeMask = (1 << RegisterOperand) | (1 << MemoryOperand); + *registerMask = ~static_cast(0); + } + *thunk = false; + } + + virtual void plan(BinaryOperation op, unsigned size, uint8_t* aTypeMask, + uint64_t* aRegisterMask, uint8_t* bTypeMask, + uint64_t* bRegisterMask, bool* thunk) + { + *aTypeMask = ~0; + *aRegisterMask = ~static_cast(0); + + *bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); + *bRegisterMask = ~static_cast(0); + + *thunk = false; + + switch (op) { + case Compare: + if (BytesPerWord == 8 and size != 8) { + *aTypeMask = ~(1 << MemoryOperand); + *bTypeMask = ~(1 << MemoryOperand); + } else { + *bTypeMask = ~(1 << ConstantOperand); + } + break; + + case Move: + if (BytesPerWord == 4 and size == 1) { + const uint32_t mask + = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx); + *aRegisterMask = (static_cast(mask) << 32) | mask; + *bRegisterMask = (static_cast(mask) << 32) | mask; + } + break; + + case Move4To8: + if (BytesPerWord == 4) { + const uint32_t mask = ~((1 << rax) | (1 << rdx)); + *aRegisterMask = (static_cast(mask) << 32) | mask; + *bRegisterMask = (static_cast(1) << (rdx + 32)) + | (static_cast(1) << rax); + } + break; + + case Multiply: + if (BytesPerWord == 4 and size == 8) { + const uint32_t mask = ~((1 << rax) | (1 << rdx)); + *aRegisterMask = (static_cast(mask) << 32) | mask; + *bRegisterMask = (static_cast(1) << (rdx + 32)) | mask; + } + break; + + case Divide: + if (BytesPerWord == 4 and size == 8) { + *bTypeMask = ~0; + *thunk = true; + } else { + *aRegisterMask = ~((1 << rax) | (1 << rdx)); + *bRegisterMask = 1 << rax; + } + break; + + case Remainder: + if (BytesPerWord == 4 and size == 8) { + *bTypeMask = ~0; + *thunk = true; + } else { + *aRegisterMask = ~((1 << rax) | (1 << rdx)); + *bRegisterMask = 1 << rax; + } + break; + + case ShiftLeft: + case ShiftRight: + case UnsignedShiftRight: { + *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); + *aRegisterMask = (~static_cast(0) << 32) + | (static_cast(1) << rcx); + const uint32_t mask = ~(1 << rcx); + *bRegisterMask = (static_cast(mask) << 32) | mask; + } break; + + default: + break; + } + } + + virtual void apply(Operation op) { + Operations[op](&c); + } + + virtual void apply(UnaryOperation op, unsigned size, + OperandType type, Operand* operand) + { + UnaryOperations[INDEX1(op, type)](&c, size, operand); + } + + virtual void apply(BinaryOperation op, unsigned size, + OperandType aType, Operand* a, + OperandType bType, Operand* b) + { + BinaryOperations[INDEX2(op, aType, bType)](&c, size, a, b); + } + + virtual void writeTo(uint8_t* dst) { + c.result = dst; + memcpy(dst, c.code.data, c.code.length()); + + for (Task* t = c.tasks; t; t = t->next) { + t->run(&c); + } + } + + virtual unsigned length() { + return c.code.length(); + } + + virtual void updateCall(void* returnAddress, void* newTarget) { + uint8_t* instruction = static_cast(returnAddress) - 5; + assert(&c, *instruction == 0xE8); + assert(&c, reinterpret_cast(instruction + 1) % 4 == 0); + + int32_t v = static_cast(newTarget) + - static_cast(returnAddress); + memcpy(instruction + 1, &v, 4); + } + + virtual void dispose() { + c.code.dispose(); + } + + Context c; +}; + +} // namespace + +namespace vm { + +Assembler* +makeAssembler(System* system, Allocator* allocator, Zone* zone) +{ + return new (zone->allocate(sizeof(MyAssembler))) + MyAssembler(system, allocator, zone); +} + +} // namespace vm diff --git a/src/powerpc.h b/src/powerpc.h new file mode 100644 index 0000000000..002fca65df --- /dev/null +++ b/src/powerpc.h @@ -0,0 +1,124 @@ +/* Copyright (c) 2008, 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 POWERPC_H +#define POWERPC_H + +#include "types.h" +#include "common.h" + +#ifdef __APPLE__ +# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) +# define IP_REGISTER(context) (context->uc_mcontext->__ss.__srr0) +# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__r13) +# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__r1) +# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__r14) +# else +# define IP_REGISTER(context) (context->uc_mcontext->ss.srr0) +# define BASE_REGISTER(context) (context->uc_mcontext->ss.r13) +# define STACK_REGISTER(context) (context->uc_mcontext->ss.r1) +# define THREAD_REGISTER(context) (context->uc_mcontext->ss.r14) +# endif +#else +# define IP_REGISTER(context) (context->uc_mcontext.gregs[32]) +# define BASE_REGISTER(context) (context->uc_mcontext.gregs[13]) +# define STACK_REGISTER(context) (context->uc_mcontext.gregs[1]) +# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[14]) +#endif + +extern "C" uint64_t +vmNativeCall(void* function, unsigned stackTotal, void* memoryTable, + unsigned memoryCount, void* gprTable, void* fprTable, + unsigned returnType); + +namespace vm { + +inline uint64_t +dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, + unsigned argumentCount, unsigned argumentsSize, + unsigned returnType) +{ + const unsigned LinkageArea = 24; + + const unsigned GprCount = 8; + uintptr_t gprTable[GprCount]; + unsigned gprIndex = 0; + + const unsigned FprCount = 13; + uint64_t fprTable[FprCount]; + unsigned fprIndex = 0; + + uintptr_t stack[argumentsSize / BytesPerWord]; + unsigned stackSkip = 0; + unsigned stackIndex = 0; + + unsigned ai = 0; + for (unsigned ati = 0; ati < argumentCount; ++ ati) { + switch (argumentTypes[ati]) { + case FLOAT_TYPE: { + if (fprIndex < FprCount) { + fprTable[fprIndex++] = arguments[ai]; + ++ gprIndex; + ++ stackSkip; + } else { + stack[stackIndex++] = arguments[ai]; + } + ++ ai; + } break; + + case DOUBLE_TYPE: { + if (fprIndex < FprCount) { + memcpy(fprTable + fprIndex, arguments + ai, 8); + ++ fprIndex; + gprIndex += BytesPerWord / 4; + stackSkip += BytesPerWord / 4; + } else { + memcpy(stack + stackIndex, arguments + ai, 8); + stackIndex += BytesPerWord / 4; + } + ai += BytesPerWord / 4; + } break; + + case INT64_TYPE: { + if (gprIndex + BytesPerWord / 4 <= GprCount) { + memcpy(gprTable + gprIndex, arguments + ai, 8); + gprIndex += BytesPerWord / 4; + stackSkip += BytesPerWord / 4; + } else { + memcpy(stack + stackIndex, arguments + ai, 8); + stackIndex += BytesPerWord / 4; + } + ai += BytesPerWord / 4; + } break; + + default: { + if (gprIndex < GprCount) { + gprTable[gprIndex++] = arguments[ai]; + ++ stackSkip; + } else { + stack[stackIndex++] = arguments[ai]; + } + ++ ai; + } break; + } + } + + return vmNativeCall + (function, + - ((((1 + stackSkip + stackIndex) * BytesPerWord) + LinkageArea + 15) + & -16), + stack, stackIndex * BytesPerWord, + (gprIndex ? gprTable : 0), + (fprIndex ? fprTable : 0), returnType); +} + +} // namespace vm + +#endif//POWERPC_H diff --git a/src/system.h b/src/system.h index 932a5ec4bc..bb16c9be5d 100644 --- a/src/system.h +++ b/src/system.h @@ -143,6 +143,14 @@ class System { virtual void dispose() = 0; }; +inline void* +allocate(System* s, unsigned size) +{ + void* p = s->tryAllocate(size); + if (p == 0) s->abort(); + return p; +} + #define ACQUIRE_MONITOR(t, m) \ System::MonitorResource MAKE_NAME(monitorResource_) (t, m) diff --git a/src/x86.S b/src/x86.S index 4655cb5312..7973a460e8 100644 --- a/src/x86.S +++ b/src/x86.S @@ -10,6 +10,8 @@ #include "types.h" +#define LOCAL(x) .L##x + .text #ifdef __x86_64__ @@ -42,9 +44,9 @@ vmNativeCall: // copy memory arguments into place movq $0,%rcx - jmp test + jmp LOCAL(test) -loop: +LOCAL(loop): movq %rcx,%rax movq %rcx,%rdx addq %rsp,%rdx @@ -53,13 +55,13 @@ loop: movq %rax,(%rdx) addq $8,%rcx -test: +LOCAL(test): cmpq -32(%rbp),%rcx - jb loop + jb LOCAL(loop) // do we need to load the general-purpose registers? cmpq $0,-24(%rbp) - je sse + je LOCAL(sse) // yes, we do movq -24(%rbp),%rax @@ -70,10 +72,10 @@ test: movq 32(%rax),%r8 movq 40(%rax),%r9 -sse: +LOCAL(sse): // do we need to load the SSE registers? cmpq $0,-16(%rbp) - je call + je LOCAL(call) // yes, we do movq -16(%rbp),%rax @@ -86,27 +88,27 @@ sse: movq 48(%rax),%xmm6 movq 64(%rax),%xmm7 -call: +LOCAL(call): call *-48(%rbp) // handle return value based on expected type movq -8(%rbp),%rcx -void: +LOCAL(void): cmpq $VOID_TYPE,%rcx - jne float - jmp exit + jne LOCAL(float) + jmp LOCAL(exit) -float: +LOCAL(float): cmpq $FLOAT_TYPE,%rcx - je copy + je LOCAL(copy) cmpq $DOUBLE_TYPE,%rcx - jne exit + jne LOCAL(exit) -copy: +LOCAL(copy): movq %xmm0,%rax -exit: +LOCAL(exit): movq %rbp,%rsp popq %rbp ret @@ -147,9 +149,9 @@ vmNativeCall: // copy arguments into place movl $0,%ecx - jmp test + jmp LOCAL(test) -loop: +LOCAL(loop): movl %ecx,%eax movl %ecx,%edx addl %esp,%edx @@ -158,9 +160,9 @@ loop: movl %eax,(%edx) addl $4,%ecx -test: +LOCAL(test): cmpl 16(%ebp),%ecx - jb loop + jb LOCAL(loop) // call function call *8(%ebp) @@ -168,31 +170,31 @@ test: // handle return value based on expected type movl 20(%ebp),%ecx -void: +LOCAL(void): cmpl $VOID_TYPE,%ecx - jne int64 - jmp exit + jne LOCAL(int64) + jmp LOCAL(exit) -int64: +LOCAL(int64): cmpl $INT64_TYPE,%ecx - jne float - jmp exit + jne LOCAL(float) + jmp LOCAL(exit) -float: +LOCAL(float): cmpl $FLOAT_TYPE,%ecx - jne double + jne LOCAL(double) fstps 8(%ebp) movl 8(%ebp),%eax - jmp exit + jmp LOCAL(exit) -double: +LOCAL(double): cmpl $DOUBLE_TYPE,%ecx - jne exit + jne LOCAL(exit) fstpl 8(%ebp) movl 8(%ebp),%eax movl 12(%ebp),%edx -exit: +LOCAL(exit): movl %ebp,%esp popl %ebp ret diff --git a/src/x86.cpp b/src/x86.cpp index baa9b23ba5..bcf058d78e 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -11,19 +11,11 @@ #include "assembler.h" #include "vector.h" -using namespace vm; - -#define INDEX1(a, b) ((a) + (UnaryOperationCount * (b))) - #define CAST1(x) reinterpret_cast(x) - -#define INDEX2(a, b, c) \ - ((a) \ - + (BinaryOperationCount * (b)) \ - + (BinaryOperationCount * OperandTypeCount * (c))) - #define CAST2(x) reinterpret_cast(x) +using namespace vm; + namespace { enum { @@ -45,6 +37,8 @@ enum { r15 = 15, }; +const unsigned FrameHeaderSize = 2; + inline bool isInt8(intptr_t v) { @@ -58,11 +52,40 @@ isInt32(intptr_t v) } class Task; +class AlignmentPadding; + +unsigned +padding(AlignmentPadding* p, unsigned index, unsigned offset, + AlignmentPadding* limit); + +class MyBlock: public Assembler::Block { + public: + MyBlock(unsigned offset): + next(0), firstPadding(0), lastPadding(0), offset(offset), start(~0), + size(0) + { } + + virtual unsigned resolve(unsigned start, Assembler::Block* next) { + this->start = start; + this->next = static_cast(next); + + return start + size + padding(firstPadding, start, offset, lastPadding); + } + + MyBlock* next; + AlignmentPadding* firstPadding; + AlignmentPadding* lastPadding; + unsigned offset; + unsigned start; + unsigned size; +}; class Context { public: Context(System* s, Allocator* a, Zone* zone): - s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0) + s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), + firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), + lastBlock(firstBlock) { } System* s; @@ -71,6 +94,29 @@ class Context { Vector code; Task* tasks; uint8_t* result; + MyBlock* firstBlock; + MyBlock* lastBlock; +}; + +typedef void (*OperationType)(Context*); + +typedef void (*UnaryOperationType)(Context*, unsigned, Assembler::Operand*); + +typedef void (*BinaryOperationType) +(Context*, unsigned, Assembler::Operand*, unsigned, Assembler::Operand*); + +class ArchitectureContext { + public: + ArchitectureContext(System* s): s(s) { } + + System* s; + OperationType operations[OperationCount]; + UnaryOperationType unaryOperations[UnaryOperationCount + * OperandTypeCount]; + BinaryOperationType binaryOperations + [(BinaryOperationCount + TernaryOperationCount) + * OperandTypeCount + * OperandTypeCount]; }; inline void NO_RETURN @@ -79,12 +125,24 @@ abort(Context* c) abort(c->s); } +inline void NO_RETURN +abort(ArchitectureContext* c) +{ + abort(c->s); +} + #ifndef NDEBUG inline void assert(Context* c, bool v) { assert(c->s, v); } + +inline void +assert(ArchitectureContext* c, bool v) +{ + assert(c->s, v); +} #endif // not NDEBUG inline void @@ -126,6 +184,36 @@ codePromise(Context* c, unsigned offset) return new (c->zone->allocate(sizeof(CodePromise))) CodePromise(c, offset); } +class Offset: public Promise { + public: + Offset(Context* c, MyBlock* block, unsigned offset, AlignmentPadding* limit): + c(c), block(block), offset(offset), limit(limit) + { } + + virtual bool resolved() { + return block->start != static_cast(~0); + } + + virtual int64_t value() { + assert(c, resolved()); + + return block->start + (offset - block->offset) + + padding(block->firstPadding, block->start, block->offset, limit); + } + + Context* c; + MyBlock* block; + unsigned offset; + AlignmentPadding* limit; +}; + +Promise* +offset(Context* c) +{ + return new (c->zone->allocate(sizeof(Offset))) + Offset(c, c->lastBlock, c->code.length(), c->lastBlock->lastPadding); +} + class Task { public: Task(Task* next): next(next) { } @@ -169,7 +257,7 @@ class OffsetListener: public Promise::Listener { class OffsetTask: public Task { public: - OffsetTask(Task* next, Promise* promise, unsigned instructionOffset, + OffsetTask(Task* next, Promise* promise, Promise* instructionOffset, unsigned instructionSize): Task(next), promise(promise), @@ -180,21 +268,22 @@ class OffsetTask: public Task { virtual void run(Context* c) { if (promise->resolved()) { resolveOffset - (c->s, c->result + instructionOffset, instructionSize, + (c->s, c->result + instructionOffset->value(), instructionSize, promise->value()); } else { new (promise->listen(sizeof(OffsetListener))) - OffsetListener(c->s, c->result + instructionOffset, instructionSize); + OffsetListener(c->s, c->result + instructionOffset->value(), + instructionSize); } } Promise* promise; - unsigned instructionOffset; + Promise* instructionOffset; unsigned instructionSize; }; void -appendOffsetTask(Context* c, Promise* promise, int instructionOffset, +appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, unsigned instructionSize) { c->tasks = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask @@ -238,7 +327,7 @@ class ImmediateListener: public Promise::Listener { class ImmediateTask: public Task { public: - ImmediateTask(Task* next, Promise* promise, unsigned offset, unsigned size, + ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset): Task(next), promise(promise), @@ -249,27 +338,61 @@ class ImmediateTask: public Task { virtual void run(Context* c) { if (promise->resolved()) { - copy(c->s, c->result + offset, promise->value(), size); + copy(c->s, c->result + offset->value(), promise->value(), size); } else { - new (promise->listen(sizeof(ImmediateListener))) - ImmediateListener(c->s, c->result + offset, size, promiseOffset); + new (promise->listen(sizeof(ImmediateListener))) ImmediateListener + (c->s, c->result + offset->value(), size, promiseOffset); } } Promise* promise; - unsigned offset; + Promise* offset; unsigned size; unsigned promiseOffset; }; void -appendImmediateTask(Context* c, Promise* promise, unsigned offset, +appendImmediateTask(Context* c, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset = 0) { c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask (c->tasks, promise, offset, size, promiseOffset); } +class AlignmentPadding { + public: + AlignmentPadding(Context* c): offset(c->code.length()), next(0) { + if (c->lastBlock->firstPadding) { + c->lastBlock->lastPadding->next = this; + } else { + c->lastBlock->firstPadding = this; + } + c->lastBlock->lastPadding = this; + } + + unsigned offset; + AlignmentPadding* next; +}; + +unsigned +padding(AlignmentPadding* p, unsigned start, unsigned offset, + AlignmentPadding* limit) +{ + unsigned padding = 0; + if (limit) { + unsigned index = 0; + for (; p; p = p->next) { + index = p->offset - offset; + while ((start + index + padding + 1) % 4) { + ++ padding; + } + + if (p == limit) break; + } + } + return padding; +} + void encode(Context* c, uint8_t* instruction, unsigned length, int a, int b, int32_t displacement, int index, unsigned scale) @@ -341,19 +464,6 @@ encode2(Context* c, uint16_t instruction, int a, Assembler::Memory* b, encode(c, i, 2, a, b->base, b->offset, b->index, b->scale); } -typedef void (*OperationType)(Context*); -OperationType -Operations[OperationCount]; - -typedef void (*UnaryOperationType)(Context*, unsigned, Assembler::Operand*); -UnaryOperationType -UnaryOperations[UnaryOperationCount * OperandTypeCount]; - -typedef void (*BinaryOperationType) -(Context*, unsigned, Assembler::Operand*, Assembler::Operand*); -BinaryOperationType -BinaryOperations[BinaryOperationCount * OperandTypeCount * OperandTypeCount]; - void return_(Context* c) { @@ -363,7 +473,7 @@ return_(Context* c) void unconditional(Context* c, unsigned jump, Assembler::Constant* a) { - appendOffsetTask(c, a->value, c->code.length(), 5); + appendOffsetTask(c, a->value, offset(c), 5); c->code.append(jump); c->code.append4(0); @@ -372,19 +482,48 @@ unconditional(Context* c, unsigned jump, Assembler::Constant* a) void conditional(Context* c, unsigned condition, Assembler::Constant* a) { - appendOffsetTask(c, a->value, c->code.length(), 6); + appendOffsetTask(c, a->value, offset(c), 6); c->code.append(0x0f); c->code.append(condition); c->code.append4(0); } -void -moveCR(Context*, unsigned, Assembler::Constant*, Assembler::Register*); +inline unsigned +index(UnaryOperation operation, OperandType operand) +{ + return operation + (UnaryOperationCount * operand); +} + +inline unsigned +index(BinaryOperation operation, + OperandType operand1, + OperandType operand2) +{ + return operation + + ((BinaryOperationCount + TernaryOperationCount) * operand1) + + ((BinaryOperationCount + TernaryOperationCount) + * OperandTypeCount * operand2); +} + +inline unsigned +index(TernaryOperation operation, + OperandType operand1, + OperandType operand2) +{ + return BinaryOperationCount + operation + + ((BinaryOperationCount + TernaryOperationCount) * operand1) + + ((BinaryOperationCount + TernaryOperationCount) + * OperandTypeCount * operand2); +} void -moveCR2(Context*, unsigned, Assembler::Constant*, Assembler::Register*, - unsigned promiseOffset); +moveCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b); + +void +moveCR2(Context*, unsigned, Assembler::Constant*, unsigned, + Assembler::Register*, unsigned); void callR(Context*, unsigned, Assembler::Register*); @@ -404,40 +543,13 @@ longCallC(Context* c, unsigned size, Assembler::Constant* a) if (BytesPerWord == 8) { Assembler::Register r(r10); - moveCR2(c, size, a, &r, 11); + moveCR2(c, size, a, size, &r, 11); callR(c, size, &r); } else { callC(c, size, a); } } -void -alignedCallC(Context* c, unsigned size, Assembler::Constant* a) -{ - while ((c->code.length() + 1) % 4) { - c->code.append(0x90); - } - callC(c, size, a); -} - -void -callR(Context* c, unsigned size UNUSED, Assembler::Register* a) -{ - assert(c, size == BytesPerWord); - - if (a->low & 8) rex(c, 0x40, a->low); - c->code.append(0xff); - c->code.append(0xd0 | (a->low & 7)); -} - -void -callM(Context* c, unsigned size UNUSED, Assembler::Memory* a) -{ - assert(c, size == BytesPerWord); - - encode(c, 0xff, 2, a, false); -} - void jumpR(Context* c, unsigned size UNUSED, Assembler::Register* a) { @@ -456,20 +568,6 @@ jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* a) unconditional(c, 0xe9, a); } -void -longJumpC(Context* c, unsigned size, Assembler::Constant* a) -{ - assert(c, size == BytesPerWord); - - if (BytesPerWord == 8) { - Assembler::Register r(r10); - moveCR2(c, size, a, &r, 11); - jumpR(c, size, &r); - } else { - jumpC(c, size, a); - } -} - void jumpM(Context* c, unsigned size UNUSED, Assembler::Memory* a) { @@ -527,64 +625,42 @@ jumpIfLessOrEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a) } void -pushR(Context*, unsigned, Assembler::Register*); - -void -pushC(Context* c, unsigned size, Assembler::Constant* a) +longJumpC(Context* c, unsigned size, Assembler::Constant* a) { - if (BytesPerWord == 4 and size == 8) { - int64_t v = a->value->value(); + assert(c, size == BytesPerWord); - ResolvedPromise low(v & 0xFFFFFFFF); - Assembler::Constant al(&low); - - ResolvedPromise high((v >> 32) & 0xFFFFFFFF); - Assembler::Constant ah(&high); - - pushC(c, 4, &ah); - pushC(c, 4, &al); + if (BytesPerWord == 8) { + Assembler::Register r(r10); + moveCR2(c, size, a, size, &r, 11); + jumpR(c, size, &r); } else { - if (a->value->resolved()) { - int64_t v = a->value->value(); - if (isInt8(v)) { - c->code.append(0x6a); - c->code.append(v); - } else if (isInt32(v)) { - c->code.append(0x68); - c->code.append4(v); - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - pushR(c, size, &tmp); - c->client->releaseTemporary(tmp.low); - } - } else { - if (BytesPerWord == 4) { - c->code.append(0x68); - appendImmediateTask(c, a->value, c->code.length(), BytesPerWord); - c->code.appendAddress(static_cast(0)); - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - pushR(c, size, &tmp); - c->client->releaseTemporary(tmp.low); - } - } + jumpC(c, size, a); } } void -moveAR(Context*, unsigned, Assembler::Address*, Assembler::Register* b); +callR(Context* c, unsigned size UNUSED, Assembler::Register* a) +{ + assert(c, size == BytesPerWord); + + if (a->low & 8) rex(c, 0x40, a->low); + c->code.append(0xff); + c->code.append(0xd0 | (a->low & 7)); +} void -pushA(Context* c, unsigned size, Assembler::Address* a) +callM(Context* c, unsigned size UNUSED, Assembler::Memory* a) { - assert(c, BytesPerWord == 8 or size == 4); // todo - - Assembler::Register tmp(c->client->acquireTemporary()); - moveAR(c, size, a, &tmp); - pushR(c, size, &tmp); - c->client->releaseTemporary(tmp.low); + assert(c, size == BytesPerWord); + + encode(c, 0xff, 2, a, false); +} + +void +alignedCallC(Context* c, unsigned size, Assembler::Constant* a) +{ + new (c->zone->allocate(sizeof(AlignmentPadding))) AlignmentPadding(c); + callC(c, size, a); } void @@ -601,23 +677,8 @@ pushR(Context* c, unsigned size, Assembler::Register* a) } void -pushM(Context* c, unsigned size, Assembler::Memory* a) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); - - pushM(c, 4, &ah); - pushM(c, 4, a); - } else { - assert(c, BytesPerWord == 4 or size == 8); - - encode(c, 0xff, 6, a, false); - } -} - -void -move4To8RR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b); +moveRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize, Assembler::Register* b); void popR(Context* c, unsigned size, Assembler::Register* a) @@ -630,49 +691,14 @@ popR(Context* c, unsigned size, Assembler::Register* a) } else { c->code.append(0x58 | a->low); if (BytesPerWord == 8 and size == 4) { - move4To8RR(c, 0, a, a); + moveRR(c, 4, a, 8, a); } } } void -popM(Context* c, unsigned size, Assembler::Memory* a) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); - - popM(c, 4, a); - popM(c, 4, &ah); - } else { - assert(c, BytesPerWord == 4 or size == 8); - - encode(c, 0x8f, 0, a, false); - } -} - -void -addCarryCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - int64_t v = a->value->value(); - if (isInt8(v)) { - c->code.append(0x83); - c->code.append(0xd0 | b->low); - c->code.append(v); - } else { - abort(c); - } -} - -void -moveRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b); - -void -xorRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b); +addCarryCR(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b); void negateR(Context* c, unsigned size, Assembler::Register* a) @@ -696,22 +722,19 @@ negateR(Context* c, unsigned size, Assembler::Register* a) } void -leaMR(Context* c, unsigned size, Assembler::Memory* b, Assembler::Register* a) +negateRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b UNUSED) { - if (BytesPerWord == 8 and size == 4) { - encode(c, 0x8d, a->low, b, false); - } else { - assert(c, BytesPerWord == 8 or size == 4); + assert(c, aSize == bSize); - encode(c, 0x8d, a->low, b, true); - } + negateR(c, aSize, a); } void -moveCR2(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b, unsigned promiseOffset) +moveCR2(Context* c, unsigned, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b, unsigned promiseOffset) { - if (BytesPerWord == 4 and size == 8) { + if (BytesPerWord == 4 and bSize == 8) { int64_t v = a->value->value(); ResolvedPromise high((v >> 32) & 0xFFFFFFFF); @@ -722,8 +745,8 @@ moveCR2(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register bh(b->high); - moveCR(c, 4, &al, b); - moveCR(c, 4, &ah, &bh); + moveCR(c, 4, &al, 4, b); + moveCR(c, 4, &ah, 4, &bh); } else { rex(c, 0x48, b->low); c->code.append(0xb8 | b->low); @@ -731,37 +754,58 @@ moveCR2(Context* c, unsigned size, Assembler::Constant* a, c->code.appendAddress(a->value->value()); } else { appendImmediateTask - (c, a->value, c->code.length(), BytesPerWord, promiseOffset); + (c, a->value, offset(c), BytesPerWord, promiseOffset); c->code.appendAddress(static_cast(0)); } } } void -moveCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) +moveCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) { - moveCR2(c, size, a, b, 0); + moveCR2(c, aSize, a, bSize, b, 0); } void -moveRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) +swapRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) { - if (BytesPerWord == 4 and size == 8) { + assert(c, aSize == bSize); + assert(c, aSize == BytesPerWord); + + rex(c); + c->code.append(0x87); + c->code.append(0xc0 | (b->low << 3) | a->low); +} + +void +moveRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize, Assembler::Register* b) +{ + if (BytesPerWord == 4 and aSize == 8 and bSize == 8) { Assembler::Register ah(a->high); Assembler::Register bh(b->high); - moveRR(c, 4, a, b); - moveRR(c, 4, &ah, &bh); + if (a->high == b->low) { + if (a->low == b->high) { + swapRR(c, 4, a, 4, b); + } else { + moveRR(c, 4, &ah, 4, &bh); + moveRR(c, 4, a, 4, b); + } + } else { + moveRR(c, 4, a, 4, b); + moveRR(c, 4, &ah, 4, &bh); + } } else { - switch (size) { + switch (aSize) { case 1: if (BytesPerWord == 4 and a->low > rbx) { assert(c, b->low <= rbx); - moveRR(c, BytesPerWord, a, b); - moveRR(c, 1, b, b); + moveRR(c, BytesPerWord, a, BytesPerWord, b); + moveRR(c, 1, b, BytesPerWord, b); } else { rex(c); c->code.append(0x0f); @@ -779,29 +823,92 @@ moveRR(Context* c, unsigned size, Assembler::Register* a, case 8: case 4: - if (a->low != b->low) { - rex(c); - c->code.append(0x89); - c->code.append(0xc0 | (a->low << 3) | b->low); + if (aSize == 4 and bSize == 8) { + if (BytesPerWord == 8) { + rex(c); + c->code.append(0x63); + c->code.append(0xc0 | (b->low << 3) | a->low); + } else { + if (a->low == rax and b->low == rax and b->high == rdx) { + c->code.append(0x99); // cdq + } else { + assert(c, b->low == rax and b->high == rdx); + + moveRR(c, 4, a, 4, b); + moveRR(c, 4, b, 8, b); + } + } + } else { + if (a->low != b->low) { + rex(c); + c->code.append(0x89); + c->code.append(0xc0 | (a->low << 3) | b->low); + } } break; } + } +} + +void +moveMR(Context* c, unsigned aSize, Assembler::Memory* a, + unsigned bSize, Assembler::Register* b) +{ + switch (aSize) { + case 1: + encode2(c, 0x0fbe, b->low, a, true); + break; + + case 2: + encode2(c, 0x0fbf, b->low, a, true); + break; + + case 4: + case 8: + if (aSize == 4 and bSize == 8) { + if (BytesPerWord == 8) { + encode(c, 0x63, b->low, a, true); + } else { + assert(c, b->low == rax and b->high == rdx); + + moveMR(c, 4, a, 4, b); + moveRR(c, 4, b, 8, b); + } + } else { + if (BytesPerWord == 4 and aSize == 8 and bSize == 8) { + Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); + Assembler::Register bh(b->high); + + moveMR(c, 4, a, 4, b); + moveMR(c, 4, &ah, 4, &bh); + } else if (BytesPerWord == 8 and aSize == 4) { + encode(c, 0x63, b->low, a, true); + } else { + encode(c, 0x8b, b->low, a, true); + } + } + break; + + default: abort(c); } } void -moveRM(Context* c, unsigned size, Assembler::Register* a, Assembler::Memory* b) +moveRM(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Memory* b) { - if (BytesPerWord == 4 and size == 8) { + assert(c, aSize == bSize); + + if (BytesPerWord == 4 and aSize == 8) { Assembler::Register ah(a->high); Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale); - moveRM(c, 4, a, b); - moveRM(c, 4, &ah, &bh); - } else if (BytesPerWord == 8 and size == 4) { + moveRM(c, 4, a, 4, b); + moveRM(c, 4, &ah, 4, &bh); + } else if (BytesPerWord == 8 and aSize == 4) { encode(c, 0x89, a->low, b, false); } else { - switch (size) { + switch (aSize) { case 1: if (BytesPerWord == 8) { if (a->low > rbx) { @@ -830,10 +937,30 @@ moveRM(Context* c, unsigned size, Assembler::Register* a, Assembler::Memory* b) } void -moveCM(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Memory* b) +moveAR(Context* c, unsigned aSize, Assembler::Address* a, + unsigned bSize, Assembler::Register* b) { - switch (size) { + assert(c, BytesPerWord == 8 or (aSize == 4 and bSize == 4)); + + Assembler::Constant constant(a->address); + Assembler::Memory memory(b->low, 0, -1, 0); + + moveCR(c, aSize, &constant, bSize, b); + moveMR(c, bSize, &memory, bSize, b); +} + +ShiftMaskPromise* +shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) +{ + return new (c->zone->allocate(sizeof(ShiftMaskPromise))) + ShiftMaskPromise(base, shift, mask); +} + +void +moveCM(Context* c, unsigned aSize UNUSED, Assembler::Constant* a, + unsigned bSize, Assembler::Memory* b) +{ + switch (bSize) { case 1: encode(c, 0xc6, 0, b, false); c->code.append(a->value->value()); @@ -849,7 +976,7 @@ moveCM(Context* c, unsigned size, Assembler::Constant* a, if (a->value->resolved()) { c->code.append4(a->value->value()); } else { - appendImmediateTask(c, a->value, c->code.length(), 4); + appendImmediateTask(c, a->value, offset(c), 4); c->code.append4(0); } break; @@ -861,23 +988,18 @@ moveCM(Context* c, unsigned size, Assembler::Constant* a, c->code.append4(a->value->value()); } else { Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, 8, a, &tmp); - moveRM(c, 8, &tmp, b); + moveCR(c, 8, a, 8, &tmp); + moveRM(c, 8, &tmp, 8, b); c->client->releaseTemporary(tmp.low); } } else { - int64_t v = a->value->value(); - - ResolvedPromise high((v >> 32) & 0xFFFFFFFF); - Assembler::Constant ah(&high); - - ResolvedPromise low(v & 0xFFFFFFFF); - Assembler::Constant al(&low); + Assembler::Constant ah(shiftMaskPromise(c, a->value, 32, 0xFFFFFFFF)); + Assembler::Constant al(shiftMaskPromise(c, a->value, 0, 0xFFFFFFFF)); Assembler::Memory bh(b->base, b->offset + 4, b->index, b->scale); - moveCM(c, 4, &al, b); - moveCM(c, 4, &ah, &bh); + moveCM(c, 4, &al, 4, b); + moveCM(c, 4, &ah, 4, &bh); } } break; @@ -886,145 +1008,10 @@ moveCM(Context* c, unsigned size, Assembler::Constant* a, } void -move4To8CR(Context* c, unsigned, Assembler::Constant* a, - Assembler::Register* b) +moveZRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) { - moveCR(c, 8, a, b); -} - -void -move4To8RR(Context* c, unsigned, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 8) { - rex(c); - c->code.append(0x63); - c->code.append(0xc0 | (b->low << 3) | a->low); - } else { - if (a->low == rax and b->low == rax and b->high == rdx) { - c->code.append(0x99); // cdq - } else { - assert(c, b->low == rax and b->high == rdx); - - moveRR(c, 4, a, b); - move4To8RR(c, 0, b, b); - } - } -} - -void -moveMR(Context* c, unsigned size, Assembler::Memory* a, Assembler::Register* b) -{ - switch (size) { - case 1: - encode2(c, 0x0fbe, b->low, a, true); - break; - - case 2: - encode2(c, 0x0fbf, b->low, a, true); - break; - - case 4: - case 8: - if (BytesPerWord == 4 and size == 8) { - Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); - Assembler::Register bh(b->high); - - moveMR(c, 4, a, b); - moveMR(c, 4, &ah, &bh); - } else if (BytesPerWord == 8 and size == 4) { - encode(c, 0x63, b->low, a, true); - } else { - encode(c, 0x8b, b->low, a, true); - } - break; - - default: abort(c); - } -} - -void -moveAR(Context* c, unsigned size, Assembler::Address* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); // todo - - Assembler::Constant constant(a->address); - Assembler::Memory memory(b->low, 0, -1, 0); - - moveCR(c, size, &constant, b); - moveMR(c, size, &memory, b); -} - -void -moveAM(Context* c, unsigned size, Assembler::Address* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); // todo - - Assembler::Register tmp(c->client->acquireTemporary()); - moveAR(c, size, a, &tmp); - moveRM(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -moveMM(Context* c, unsigned size, Assembler::Memory* a, - Assembler::Memory* b) -{ - if (BytesPerWord == 8 or size <= 4) { - uint32_t mask; - if (BytesPerWord == 4 and size == 1) { - mask = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx); - } else { - mask = ~static_cast(0); - } - - Assembler::Register tmp(c->client->acquireTemporary(mask)); - moveMR(c, size, a, &tmp); - moveRM(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - } else { - Assembler::Register tmp(c->client->acquireTemporary(), - c->client->acquireTemporary()); - moveMR(c, size, a, &tmp); - moveRM(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - c->client->releaseTemporary(tmp.high); - } -} - -void -move4To8MR(Context* c, unsigned, Assembler::Memory* a, Assembler::Register* b) -{ - if (BytesPerWord == 8) { - encode(c, 0x63, b->low, a, true); - } else { - assert(c, b->low == rax and b->high == rdx); - - moveMR(c, 4, a, b); - move4To8RR(c, 0, b, b); - } -} - -void -moveZMR(Context* c, unsigned size, Assembler::Memory* a, - Assembler::Register* b) -{ - switch (size) { - case 2: - encode2(c, 0x0fb7, b->low, a, true); - break; - - default: abort(c); // todo - } -} - -void -moveZRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - switch (size) { + switch (aSize) { case 2: rex(c); c->code.append(0x0f); @@ -1032,48 +1019,75 @@ moveZRR(Context* c, unsigned size, Assembler::Register* a, c->code.append(0xc0 | (b->low << 3) | a->low); break; - default: abort(c); // todo + default: abort(c); } } void -swapRR(Context* c, unsigned, Assembler::Register* a, Assembler::Register* b) +moveZMR(Context* c, unsigned aSize UNUSED, Assembler::Memory* a, + unsigned bSize UNUSED, Assembler::Register* b) { - rex(c); - c->code.append(0x87); - c->code.append(0xc0 | (b->low << 3) | a->low); + assert(c, bSize == BytesPerWord); + assert(c, aSize == 2); + + encode2(c, 0x0fb7, b->low, a, true); } void -addCM(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Memory* b) +addCarryRR(Context* c, unsigned size, Assembler::Register* a, + Assembler::Register* b) { - assert(c, BytesPerWord == 8 or size == 4); // todo + assert(c, BytesPerWord == 8 or size == 4); + + if (size == 8) rex(c); + c->code.append(0x11); + c->code.append(0xc0 | (a->low << 3) | b->low); +} +void +addRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) +{ + assert(c, aSize == bSize); + + if (BytesPerWord == 4 and aSize == 8) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + addRR(c, 4, a, 4, b); + addCarryRR(c, 4, &ah, &bh); + } else { + if (aSize == 8) rex(c); + c->code.append(0x01); + c->code.append(0xc0 | (a->low << 3) | b->low); + } +} + +void +addCarryCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, + Assembler::Register* b) +{ + assert(c, BytesPerWord == 8 or size == 4); + int64_t v = a->value->value(); - unsigned i = (isInt8(v) ? 0x83 : 0x81); - - encode(c, i, 0, b, true); if (isInt8(v)) { + c->code.append(0x83); + c->code.append(0xd0 | b->low); c->code.append(v); - } else if (isInt32(v)) { - c->code.append4(v); } else { abort(c); } } void -addRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b); - -void -addCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) +addCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) { + assert(c, aSize == bSize); + int64_t v = a->value->value(); if (v) { - if (BytesPerWord == 4 and size == 8) { + if (BytesPerWord == 4 and bSize == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); Assembler::Constant ah(&high); @@ -1082,22 +1096,24 @@ addCR(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register bh(b->high); - addCR(c, 4, &al, b); + addCR(c, 4, &al, 4, b); addCarryCR(c, 4, &ah, &bh); } else { - if (size == 8) rex(c); - if (isInt8(v)) { - c->code.append(0x83); - c->code.append(0xc0 | b->low); - c->code.append(v); - } else if (isInt32(v)) { - c->code.append(0x81); - c->code.append(0xc0 | b->low); - c->code.append4(v); + if (isInt32(v)) { + if (bSize == 8) rex(c); + if (isInt8(v)) { + c->code.append(0x83); + c->code.append(0xc0 | b->low); + c->code.append(v); + } else { + c->code.append(0x81); + c->code.append(0xc0 | b->low); + c->code.append4(v); + } } else { Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - addRR(c, size, &tmp, b); + moveCR(c, aSize, a, aSize, &tmp); + addRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } @@ -1121,16 +1137,18 @@ subtractBorrowCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, } void -subtractRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b); +subtractRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize, Assembler::Register* b); void -subtractCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) +subtractCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) { + assert(c, aSize == bSize); + int64_t v = a->value->value(); if (v) { - if (BytesPerWord == 4 and size == 8) { + if (BytesPerWord == 4 and bSize == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); Assembler::Constant ah(&high); @@ -1139,22 +1157,24 @@ subtractCR(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register bh(b->high); - subtractCR(c, 4, &al, b); + subtractCR(c, 4, &al, 4, b); subtractBorrowCR(c, 4, &ah, &bh); } else { - if (size == 8) rex(c); - if (isInt8(v)) { - c->code.append(0x83); - c->code.append(0xe8 | b->low); - c->code.append(v); - } else if (isInt32(v)) { - c->code.append(0x81); - c->code.append(0xe8 | b->low); - c->code.append4(v); + if (isInt32(v)) { + if (bSize == 8) rex(c); + if (isInt8(v)) { + c->code.append(0x83); + c->code.append(0xe8 | b->low); + c->code.append(v); + } else { + c->code.append(0x81); + c->code.append(0xe8 | b->low); + c->code.append4(v); + } } else { Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - subtractRR(c, size, &tmp, b); + moveCR(c, aSize, a, aSize, &tmp); + subtractRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } @@ -1162,7 +1182,7 @@ subtractCR(Context* c, unsigned size, Assembler::Constant* a, } void -subtractBorrowRR(Context* c, unsigned size UNUSED, Assembler::Register* a, +subtractBorrowRR(Context* c, unsigned size, Assembler::Register* a, Assembler::Register* b) { assert(c, BytesPerWord == 8 or size == 4); @@ -1173,227 +1193,52 @@ subtractBorrowRR(Context* c, unsigned size UNUSED, Assembler::Register* a, } void -subtractRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) +subtractRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) { - if (BytesPerWord == 4 and size == 8) { + assert(c, aSize == bSize); + + if (BytesPerWord == 4 and aSize == 8) { Assembler::Register ah(a->high); Assembler::Register bh(b->high); - subtractRR(c, 4, a, b); + subtractRR(c, 4, a, 4, b); subtractBorrowRR(c, 4, &ah, &bh); } else { - if (size == 8) rex(c); + if (aSize == 8) rex(c); c->code.append(0x29); c->code.append(0xc0 | (a->low << 3) | b->low); } } void -addCarryRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) +andRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) { - assert(c, BytesPerWord == 8 or size == 4); - - if (size == 8) rex(c); - c->code.append(0x11); - c->code.append(0xc0 | (a->low << 3) | b->low); -} + assert(c, aSize == bSize); -void -addRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { + if (BytesPerWord == 4 and aSize == 8) { Assembler::Register ah(a->high); Assembler::Register bh(b->high); - addRR(c, 4, a, b); - addCarryRR(c, 4, &ah, &bh); + andRR(c, 4, a, 4, b); + andRR(c, 4, &ah, 4, &bh); } else { - if (size == 8) rex(c); - c->code.append(0x01); - c->code.append(0xc0 | (a->low << 3) | b->low); - } -} - -void -addRM(Context* c, unsigned size UNUSED, Assembler::Register* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - encode(c, 0x01, a->low, b, true); -} - -void -multiplyRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - assert(c, b->high == rdx); - assert(c, b->low != rax); - assert(c, a->low != rax); - assert(c, a->high != rax); - - c->client->save(rax); - - Assembler::Register axdx(rax, rdx); - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - moveRR(c, 4, b, &axdx); - multiplyRR(c, 4, &ah, b); - multiplyRR(c, 4, a, &bh); - addRR(c, 4, &bh, b); - - // mul a->low,%eax%edx - c->code.append(0xf7); - c->code.append(0xe0 | a->low); - - addRR(c, 4, b, &bh); - moveRR(c, 4, &axdx, b); - - c->client->restore(rax); - } else { - if (size == 8) rex(c); - c->code.append(0x0f); - c->code.append(0xaf); - c->code.append(0xc0 | (b->low << 3) | a->low); - } -} - -void -multiplyCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - const uint32_t mask = ~((1 << rax) | (1 << rdx)); - Assembler::Register tmp(c->client->acquireTemporary(mask), - c->client->acquireTemporary(mask)); - - moveCR(c, size, a, &tmp); - multiplyRR(c, size, &tmp, b); - - c->client->releaseTemporary(tmp.low); - c->client->releaseTemporary(tmp.high); - } else { - int64_t v = a->value->value(); - if (v != 1) { - if (isInt32(v)) { - if (size == 8) rex(c); - if (isInt8(v)) { - c->code.append(0x6b); - c->code.append(0xc0 | (b->low << 3) | b->low); - c->code.append(v); - } else { - c->code.append(0x69); - c->code.append(0xc0 | (b->low << 3) | b->low); - c->code.append4(v); - } - } else { - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - multiplyRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); - } - } - } -} - -void -divideRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b UNUSED) -{ - assert(c, BytesPerWord == 8 or size == 4); - - assert(c, b->low == rax); - assert(c, a->low != rdx); - - c->client->save(rdx); - - if (size == 8) rex(c); - c->code.append(0x99); // cdq - if (size == 8) rex(c); - c->code.append(0xf7); - c->code.append(0xf8 | a->low); - - c->client->restore(rdx); -} - -void -divideCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - const uint32_t mask = ~((1 << rax) | (1 << rdx)); - Assembler::Register tmp(c->client->acquireTemporary(mask)); - moveCR(c, size, a, &tmp); - divideRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -remainderRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - assert(c, b->low == rax); - assert(c, a->low != rdx); - - c->client->save(rdx); - - if (size == 8) rex(c); - c->code.append(0x99); // cdq - if (size == 8) rex(c); - c->code.append(0xf7); - c->code.append(0xf8 | a->low); - - Assembler::Register dx(rdx); - moveRR(c, BytesPerWord, &dx, b); - - c->client->restore(rdx); -} - -void -remainderCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - const uint32_t mask = ~((1 << rax) | (1 << rdx)); - Assembler::Register tmp(c->client->acquireTemporary(mask)); - moveCR(c, size, a, &tmp); - remainderRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -andRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - andRR(c, 4, a, b); - andRR(c, 4, &ah, &bh); - } else { - if (size == 8) rex(c); + if (aSize == 8) rex(c); c->code.append(0x21); c->code.append(0xc0 | (a->low << 3) | b->low); } } void -andCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) +andCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) { + assert(c, aSize == bSize); + int64_t v = a->value->value(); - if (BytesPerWord == 4 and size == 8) { + if (BytesPerWord == 4 and bSize == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); Assembler::Constant ah(&high); @@ -1402,11 +1247,11 @@ andCR(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register bh(b->high); - andCR(c, 4, &al, b); - andCR(c, 4, &ah, &bh); + andCR(c, 4, &al, 4, b); + andCR(c, 4, &ah, 4, &bh); } else { if (isInt32(v)) { - if (size == 8) rex(c); + if (bSize == 8) rex(c); if (isInt8(v)) { c->code.append(0x83); c->code.append(0xe0 | b->low); @@ -1418,55 +1263,41 @@ andCR(Context* c, unsigned size, Assembler::Constant* a, } } else { Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - andRR(c, size, &tmp, b); + moveCR(c, aSize, a, aSize, &tmp); + andRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } } void -andCM(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Memory* b) +orRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) { - assert(c, BytesPerWord == 8 or size == 4); + assert(c, aSize == bSize); - int64_t v = a->value->value(); - - encode(c, isInt8(a->value->value()) ? 0x83 : 0x81, 5, b, true); - if (isInt8(v)) { - c->code.append(v); - } else if (isInt32(v)) { - c->code.append4(v); - } else { - abort(c); - } -} - -void -orRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - if (BytesPerWord == 4 and size == 8) { + if (BytesPerWord == 4 and aSize == 8) { Assembler::Register ah(a->high); Assembler::Register bh(b->high); - orRR(c, 4, a, b); - orRR(c, 4, &ah, &bh); + orRR(c, 4, a, 4, b); + orRR(c, 4, &ah, 4, &bh); } else { - if (size == 8) rex(c); + if (aSize == 8) rex(c); c->code.append(0x09); c->code.append(0xc0 | (a->low << 3) | b->low); } } void -orCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) +orCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) { + assert(c, aSize == bSize); + int64_t v = a->value->value(); if (v) { - if (BytesPerWord == 4 and size == 8) { + if (BytesPerWord == 4 and bSize == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); Assembler::Constant ah(&high); @@ -1475,11 +1306,11 @@ orCR(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register bh(b->high); - orCR(c, 4, &al, b); - orCR(c, 4, &ah, &bh); + orCR(c, 4, &al, 4, b); + orCR(c, 4, &ah, 4, &bh); } else { if (isInt32(v)) { - if (size == 8) rex(c); + if (bSize == 8) rex(c); if (isInt8(v)) { c->code.append(0x83); c->code.append(0xc8 | b->low); @@ -1491,8 +1322,8 @@ orCR(Context* c, unsigned size, Assembler::Constant* a, } } else { Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - orRR(c, size, &tmp, b); + moveCR(c, aSize, a, aSize, &tmp); + orRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } @@ -1500,29 +1331,31 @@ orCR(Context* c, unsigned size, Assembler::Constant* a, } void -xorRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) +xorRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) { - if (BytesPerWord == 4 and size == 8) { + if (BytesPerWord == 4 and aSize == 8) { Assembler::Register ah(a->high); Assembler::Register bh(b->high); - xorRR(c, 4, a, b); - xorRR(c, 4, &ah, &bh); + xorRR(c, 4, a, 4, b); + xorRR(c, 4, &ah, 4, &bh); } else { - if (size == 8) rex(c); + if (aSize == 8) rex(c); c->code.append(0x31); c->code.append(0xc0 | (a->low << 3) | b->low); } } void -xorCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) +xorCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) { + assert(c, aSize == bSize); + int64_t v = a->value->value(); if (v) { - if (BytesPerWord == 4 and size == 8) { + if (BytesPerWord == 4 and bSize == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); Assembler::Constant ah(&high); @@ -1531,11 +1364,11 @@ xorCR(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register bh(b->high); - xorCR(c, 4, &al, b); - xorCR(c, 4, &ah, &bh); + xorCR(c, 4, &al, 4, b); + xorCR(c, 4, &ah, 4, &bh); } else { if (isInt32(v)) { - if (size == 8) rex(c); + if (bSize == 8) rex(c); if (isInt8(v)) { c->code.append(0x83); c->code.append(0xf0 | b->low); @@ -1547,8 +1380,8 @@ xorCR(Context* c, unsigned size, Assembler::Constant* a, } } else { Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - xorRR(c, size, &tmp, b); + moveCR(c, aSize, a, aSize, &tmp); + xorRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } @@ -1556,200 +1389,66 @@ xorCR(Context* c, unsigned size, Assembler::Constant* a, } void -doShift(Context* c, void (*shift) - (Context*, unsigned, Assembler::Register*, Assembler::Register*), - int type, unsigned size, Assembler::Constant* a, - Assembler::Register* b) +multiplyRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) { - int64_t v = a->value->value(); + assert(c, aSize == bSize); - if (BytesPerWord == 4 and size == 8) { - c->client->save(rcx); + if (BytesPerWord == 4 and aSize == 8) { + assert(c, b->high == rdx); + assert(c, b->low != rax); + assert(c, a->low != rax); + assert(c, a->high != rax); - Assembler::Register cx(rcx); - moveCR(c, 4, a, &cx); - shift(c, size, &cx, b); - - c->client->restore(rcx); - } else { - if (size == 8) rex(c); - if (v == 1) { - c->code.append(0xd1); - c->code.append(type | b->low); - } else if (isInt8(v)) { - c->code.append(0xc1); - c->code.append(type | b->low); - c->code.append(v); - } else { - abort(c); - } - } -} - -void -compareCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b); - -void -shiftLeftRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, a->low == rcx); - - if (BytesPerWord == 4 and size == 8) { - // shld - c->code.append(0x0f); - c->code.append(0xa5); - c->code.append(0xc0 | (b->low << 3) | b->high); - - // shl - c->code.append(0xd3); - c->code.append(0xe0 | b->low); - - ResolvedPromise promise(32); - Assembler::Constant constant(&promise); - compareCR(c, 4, &constant, a); - - c->code.append(0x0f); - c->code.append(0x8c); // jl - c->code.append4(2 + 2); + c->client->save(rax); + Assembler::Register axdx(rax, rdx); + Assembler::Register ah(a->high); Assembler::Register bh(b->high); - moveRR(c, 4, b, &bh); // 2 bytes - xorRR(c, 4, b, b); // 2 bytes + + moveRR(c, 4, b, 4, &axdx); + multiplyRR(c, 4, &ah, 4, b); + multiplyRR(c, 4, a, 4, &bh); + addRR(c, 4, &bh, 4, b); + + // mul a->low,%eax%edx + c->code.append(0xf7); + c->code.append(0xe0 | a->low); + + addRR(c, 4, b, 4, &bh); + moveRR(c, 4, &axdx, 4, b); + + c->client->restore(rax); } else { - if (size == 8) rex(c); - c->code.append(0xd3); - c->code.append(0xe0 | b->low); + if (aSize == 8) rex(c); + c->code.append(0x0f); + c->code.append(0xaf); + c->code.append(0xc0 | (b->low << 3) | a->low); } } void -shiftLeftCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) +compareRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) { - doShift(c, shiftLeftRR, 0xe0, size, a, b); -} + assert(c, aSize == bSize); + assert(c, BytesPerWord == 8 or aSize == 4); -void -shiftRightRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, a->low == rcx); - - if (BytesPerWord == 4 and size == 8) { - // shrd - c->code.append(0x0f); - c->code.append(0xad); - c->code.append(0xc0 | (b->high << 3) | b->low); - - // sar - c->code.append(0xd3); - c->code.append(0xf8 | b->high); - - ResolvedPromise promise(32); - Assembler::Constant constant(&promise); - compareCR(c, 4, &constant, a); - - c->code.append(0x0f); - c->code.append(0x8c); // jl - c->code.append4(2 + 3); - - Assembler::Register bh(b->high); - moveRR(c, 4, &bh, b); // 2 bytes - - // sar 31,high - c->code.append(0xc1); - c->code.append(0xf8 | b->high); - c->code.append(31); - } else { - if (size == 8) rex(c); - c->code.append(0xd3); - c->code.append(0xf8 | b->low); - } -} - -void -shiftRightCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - doShift(c, shiftRightRR, 0xf8, size, a, b); -} - -void -unsignedShiftRightRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, a->low == rcx); - - if (BytesPerWord == 4 and size == 8) { - // shrd - c->code.append(0x0f); - c->code.append(0xad); - c->code.append(0xc0 | (b->high << 3) | b->low); - - // shr - c->code.append(0xd3); - c->code.append(0xe8 | b->high); - - ResolvedPromise promise(32); - Assembler::Constant constant(&promise); - compareCR(c, 4, &constant, a); - - c->code.append(0x0f); - c->code.append(0x8c); // jl - c->code.append4(2 + 2); - - Assembler::Register bh(b->high); - moveRR(c, 4, &bh, b); // 2 bytes - xorRR(c, 4, &bh, &bh); // 2 bytes - } else { - if (size == 8) rex(c); - c->code.append(0xd3); - c->code.append(0xe8 | b->low); - } -} - -void -unsignedShiftRightCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - doShift(c, unsignedShiftRightRR, 0xe8, size, a, b); -} - -void -compareRR(Context* c, unsigned size, Assembler::Register* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - if (size == 8) rex(c); + if (aSize == 8) rex(c); c->code.append(0x39); c->code.append(0xc0 | (a->low << 3) | b->low); } void -compareAR(Context* c, unsigned size, Assembler::Address* a, - Assembler::Register* b) +compareCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) { - assert(c, BytesPerWord == 8 or size == 4); - - Assembler::Register tmp(c->client->acquireTemporary()); - moveAR(c, size, a, &tmp); - compareRR(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -compareCR(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); + assert(c, aSize == bSize); + assert(c, BytesPerWord == 8 or aSize == 4); if (a->value->resolved() and isInt32(a->value->value())) { int64_t v = a->value->value(); - - if (size == 8) rex(c); + if (aSize == 8) rex(c); if (isInt8(v)) { c->code.append(0x83); c->code.append(0xf8 | b->low); @@ -1761,33 +1460,73 @@ compareCR(Context* c, unsigned size, Assembler::Constant* a, } } else { Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - compareRR(c, size, &tmp, b); + moveCR(c, aSize, a, aSize, &tmp); + compareRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } void -compareRM(Context* c, unsigned size, Assembler::Register* a, - Assembler::Memory* b) +multiplyCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) { - assert(c, BytesPerWord == 8 or size == 4); + assert(c, aSize == bSize); + + if (BytesPerWord == 4 and aSize == 8) { + const uint32_t mask = ~((1 << rax) | (1 << rdx)); + Assembler::Register tmp(c->client->acquireTemporary(mask), + c->client->acquireTemporary(mask)); + + moveCR(c, aSize, a, aSize, &tmp); + multiplyRR(c, aSize, &tmp, bSize, b); + c->client->releaseTemporary(tmp.low); + c->client->releaseTemporary(tmp.high); + } else { + int64_t v = a->value->value(); + if (v != 1) { + if (isInt32(v)) { + if (bSize == 8) rex(c); + if (isInt8(v)) { + c->code.append(0x6b); + c->code.append(0xc0 | (b->low << 3) | b->low); + c->code.append(v); + } else { + c->code.append(0x69); + c->code.append(0xc0 | (b->low << 3) | b->low); + c->code.append4(v); + } + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, aSize, a, aSize, &tmp); + multiplyRR(c, aSize, &tmp, bSize, b); + c->client->releaseTemporary(tmp.low); + } + } + } +} + +void +compareRM(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Memory* b) +{ + assert(c, aSize == bSize); + assert(c, BytesPerWord == 8 or aSize == 4); - if (BytesPerWord == 8 and size == 4) { - move4To8RR(c, size, a, a); + if (BytesPerWord == 8 and aSize == 4) { + moveRR(c, 4, a, 8, a); } encode(c, 0x39, a->low, b, true); } void -compareCM(Context* c, unsigned size, Assembler::Constant* a, - Assembler::Memory* b) +compareCM(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Memory* b) { - assert(c, BytesPerWord == 8 or size == 4); + assert(c, aSize == bSize); + assert(c, BytesPerWord == 8 or aSize == 4); - if (a->value->resolved()) { - int64_t v = a->value->value(); - + if (a->value->resolved()) { + int64_t v = a->value->value(); encode(c, isInt8(v) ? 0x83 : 0x81, 7, b, true); if (isInt8(v)) { @@ -1799,60 +1538,12 @@ compareCM(Context* c, unsigned size, Assembler::Constant* a, } } else { Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, a, &tmp); - compareRM(c, size, &tmp, b); + moveCR(c, aSize, a, bSize, &tmp); + compareRM(c, bSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } -void -compareAM(Context* c, unsigned size, Assembler::Address* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - Assembler::Register tmp(c->client->acquireTemporary()); - moveAR(c, size, a, &tmp); - compareRM(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -compareMR(Context* c, unsigned size, Assembler::Memory* a, - Assembler::Register* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - if (BytesPerWord == 8 and size == 4) { - move4To8RR(c, size, b, b); - } - encode(c, 0x3b, b->low, a, true); -} - -void -compareMM(Context* c, unsigned size, Assembler::Memory* a, - Assembler::Memory* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - Assembler::Register tmp(c->client->acquireTemporary()); - moveMR(c, size, a, &tmp); - compareRM(c, size, &tmp, b); - c->client->releaseTemporary(tmp.low); -} - -void -compareRC(Context* c, unsigned size, Assembler::Register* a, - Assembler::Constant* b) -{ - assert(c, BytesPerWord == 8 or size == 4); - - Assembler::Register tmp(c->client->acquireTemporary()); - moveCR(c, size, b, &tmp); - compareRR(c, size, a, &tmp); - c->client->releaseTemporary(tmp.low); -} - void longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, Assembler::Operand* bl, Assembler::Operand* bh, @@ -1868,7 +1559,7 @@ longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, Assembler::Constant positive(&positivePromise); if (BytesPerWord == 8) { - compare(c, 8, al, bl); + compare(c, 8, al, 8, bl); c->code.append(0x0f); c->code.append(0x8c); // jl @@ -1880,7 +1571,7 @@ longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, unsigned greater = c->code.length(); c->code.append4(0); - move(c, 4, &zero, bl); + move(c, 4, &zero, 4, bl); c->code.append(0xe9); // jmp unsigned nextFirst = c->code.length(); @@ -1889,7 +1580,7 @@ longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, int32_t lessOffset = c->code.length() - less - 4; c->code.set(less, &lessOffset, 4); - move(c, 4, &negative, bl); + move(c, 4, &negative, 4, bl); c->code.append(0xe9); // jmp unsigned nextSecond = c->code.length(); @@ -1898,7 +1589,7 @@ longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, int32_t greaterOffset = c->code.length() - greater - 4; c->code.set(greater, &greaterOffset, 4); - move(c, 4, &positive, bl); + move(c, 4, &positive, 4, bl); int32_t nextFirstOffset = c->code.length() - nextFirst - 4; c->code.set(nextFirst, &nextFirstOffset, 4); @@ -1906,7 +1597,7 @@ longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, int32_t nextSecondOffset = c->code.length() - nextSecond - 4; c->code.set(nextSecond, &nextSecondOffset, 4); } else { - compare(c, 4, ah, bh); + compare(c, 4, ah, 4, bh); c->code.append(0x0f); c->code.append(0x8c); // jl @@ -1918,7 +1609,7 @@ longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, unsigned greater = c->code.length(); c->code.append4(0); - compare(c, 4, al, bl); + compare(c, 4, al, 4, bl); c->code.append(0x0f); c->code.append(0x82); // ja @@ -1930,7 +1621,7 @@ longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, unsigned below = c->code.length(); c->code.append4(0); - move(c, 4, &zero, bl); + move(c, 4, &zero, 4, bl); c->code.append(0xe9); // jmp unsigned nextFirst = c->code.length(); @@ -1942,7 +1633,7 @@ longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, int32_t aboveOffset = c->code.length() - above - 4; c->code.set(above, &aboveOffset, 4); - move(c, 4, &negative, bl); + move(c, 4, &negative, 4, bl); c->code.append(0xe9); // jmp unsigned nextSecond = c->code.length(); @@ -1954,7 +1645,7 @@ longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, int32_t belowOffset = c->code.length() - below - 4; c->code.set(below, &belowOffset, 4); - move(c, 4, &positive, bl); + move(c, 4, &positive, 4, bl); int32_t nextFirstOffset = c->code.length() - nextFirst - 4; c->code.set(nextFirst, &nextFirstOffset, 4); @@ -1965,10 +1656,56 @@ longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, } void -longCompareCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Register* b) +divideRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b UNUSED) { - assert(c, size == 8); + assert(c, BytesPerWord == 8 or aSize == 4); + assert(c, aSize == bSize); + + assert(c, b->low == rax); + assert(c, a->low != rdx); + + c->client->save(rdx); + + if (aSize == 8) rex(c); + c->code.append(0x99); // cdq + if (aSize == 8) rex(c); + c->code.append(0xf7); + c->code.append(0xf8 | a->low); + + c->client->restore(rdx); +} + +void +remainderRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) +{ + assert(c, BytesPerWord == 8 or aSize == 4); + assert(c, aSize == bSize); + + assert(c, b->low == rax); + assert(c, a->low != rdx); + + c->client->save(rdx); + + if (aSize == 8) rex(c); + c->code.append(0x99); // cdq + if (aSize == 8) rex(c); + c->code.append(0xf7); + c->code.append(0xf8 | a->low); + + Assembler::Register dx(rdx); + moveRR(c, BytesPerWord, &dx, BytesPerWord, b); + + c->client->restore(rdx); +} + +void +longCompareCR(Context* c, unsigned aSize UNUSED, Assembler::Constant* a, + unsigned bSize UNUSED, Assembler::Register* b) +{ + assert(c, aSize == 8); + assert(c, bSize == 8); int64_t v = a->value->value(); @@ -1984,10 +1721,11 @@ longCompareCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, } void -longCompareRR(Context* c, unsigned size UNUSED, Assembler::Register* a, - Assembler::Register* b) +longCompareRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a, + unsigned bSize UNUSED, Assembler::Register* b) { - assert(c, size == 8); + assert(c, aSize == 8); + assert(c, bSize == 8); Assembler::Register ah(a->high); Assembler::Register bh(b->high); @@ -1996,147 +1734,261 @@ longCompareRR(Context* c, unsigned size UNUSED, Assembler::Register* a, } void -populateTables() +doShift(Context* c, void (*shift) + (Context*, unsigned, Assembler::Register*, unsigned, + Assembler::Register*), + int type, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) { - Operations[Return] = return_; + int64_t v = a->value->value(); - const int Constant = ConstantOperand; - const int Address = AddressOperand; - const int Register = RegisterOperand; - const int Memory = MemoryOperand; + if (BytesPerWord == 4 and bSize == 8) { + c->client->save(rcx); - UnaryOperations[INDEX1(Call, Constant)] = CAST1(callC); - UnaryOperations[INDEX1(Call, Register)] = CAST1(callR); - UnaryOperations[INDEX1(Call, Memory)] = CAST1(callM); + Assembler::Register cx(rcx); + moveCR(c, 4, a, 4, &cx); + shift(c, aSize, &cx, bSize, b); - UnaryOperations[INDEX1(LongCall, Constant)] = CAST1(longCallC); - - UnaryOperations[INDEX1(AlignedCall, Constant)] = CAST1(alignedCallC); - - UnaryOperations[INDEX1(Jump, Constant)] = CAST1(jumpC); - UnaryOperations[INDEX1(Jump, Register)] = CAST1(jumpR); - UnaryOperations[INDEX1(Jump, Memory)] = CAST1(jumpM); - - UnaryOperations[INDEX1(LongJump, Constant)] = CAST1(longJumpC); - - UnaryOperations[INDEX1(JumpIfEqual, Constant)] = CAST1(jumpIfEqualC); - UnaryOperations[INDEX1(JumpIfNotEqual, Constant)] = CAST1(jumpIfNotEqualC); - UnaryOperations[INDEX1(JumpIfGreater, Constant)] = CAST1(jumpIfGreaterC); - UnaryOperations[INDEX1(JumpIfGreaterOrEqual, Constant)] - = CAST1(jumpIfGreaterOrEqualC); - UnaryOperations[INDEX1(JumpIfLess, Constant)] = CAST1(jumpIfLessC); - UnaryOperations[INDEX1(JumpIfLessOrEqual, Constant)] - = CAST1(jumpIfLessOrEqualC); - - UnaryOperations[INDEX1(Push, Constant)] = CAST1(pushC); - UnaryOperations[INDEX1(Push, Address)] = CAST1(pushA); - UnaryOperations[INDEX1(Push, Register)] = CAST1(pushR); - UnaryOperations[INDEX1(Push, Memory)] = CAST1(pushM); - - UnaryOperations[INDEX1(Pop, Register)] = CAST1(popR); - UnaryOperations[INDEX1(Pop, Memory)] = CAST1(popM); - - UnaryOperations[INDEX1(Negate, Register)] = CAST1(negateR); - - BinaryOperations[INDEX2(LoadAddress, Memory, Register)] = CAST2(leaMR); - - BinaryOperations[INDEX2(Move, Constant, Register)] = CAST2(moveCR); - BinaryOperations[INDEX2(Move, Constant, Memory)] = CAST2(moveCM); - BinaryOperations[INDEX2(Move, Register, Memory)] = CAST2(moveRM); - BinaryOperations[INDEX2(Move, Register, Register)] = CAST2(moveRR); - BinaryOperations[INDEX2(Move, Memory, Register)] = CAST2(moveMR); - BinaryOperations[INDEX2(Move, Address, Register)] = CAST2(moveAR); - BinaryOperations[INDEX2(Move, Address, Memory)] = CAST2(moveAM); - BinaryOperations[INDEX2(Move, Memory, Memory)] = CAST2(moveMM); - - BinaryOperations[INDEX2(Move4To8, Constant, Register)] = CAST2(move4To8CR); - BinaryOperations[INDEX2(Move4To8, Register, Register)] = CAST2(move4To8RR); - BinaryOperations[INDEX2(Move4To8, Memory, Register)] = CAST2(move4To8MR); - - BinaryOperations[INDEX2(MoveZ, Memory, Register)] = CAST2(moveZMR); - BinaryOperations[INDEX2(MoveZ, Register, Register)] = CAST2(moveZRR); - - BinaryOperations[INDEX2(Swap, Register, Register)] = CAST2(swapRR); - - BinaryOperations[INDEX2(Add, Constant, Register)] = CAST2(addCR); - BinaryOperations[INDEX2(Add, Register, Register)] = CAST2(addRR); - BinaryOperations[INDEX2(Add, Register, Memory)] = CAST2(addRM); - BinaryOperations[INDEX2(Add, Constant, Memory)] = CAST2(addCM); - - BinaryOperations[INDEX2(Multiply, Register, Register)] = CAST2(multiplyRR); - BinaryOperations[INDEX2(Multiply, Constant, Register)] = CAST2(multiplyCR); - - BinaryOperations[INDEX2(Divide, Register, Register)] = CAST2(divideRR); - BinaryOperations[INDEX2(Divide, Constant, Register)] = CAST2(divideCR); - - BinaryOperations[INDEX2(Remainder, Constant, Register)] = CAST2(remainderCR); - BinaryOperations[INDEX2(Remainder, Register, Register)] = CAST2(remainderRR); - - BinaryOperations[INDEX2(And, Register, Register)] = CAST2(andRR); - BinaryOperations[INDEX2(And, Constant, Register)] = CAST2(andCR); - BinaryOperations[INDEX2(And, Constant, Memory)] = CAST2(andCM); - - BinaryOperations[INDEX2(Or, Register, Register)] = CAST2(orRR); - BinaryOperations[INDEX2(Or, Constant, Register)] = CAST2(orCR); - - BinaryOperations[INDEX2(Xor, Register, Register)] = CAST2(xorRR); - BinaryOperations[INDEX2(Xor, Constant, Register)] = CAST2(xorCR); - - BinaryOperations[INDEX2(ShiftLeft, Register, Register)] = CAST2(shiftLeftRR); - BinaryOperations[INDEX2(ShiftLeft, Constant, Register)] = CAST2(shiftLeftCR); - - BinaryOperations[INDEX2(ShiftRight, Register, Register)] - = CAST2(shiftRightRR); - BinaryOperations[INDEX2(ShiftRight, Constant, Register)] - = CAST2(shiftRightCR); - - BinaryOperations[INDEX2(UnsignedShiftRight, Register, Register)] - = CAST2(unsignedShiftRightRR); - BinaryOperations[INDEX2(UnsignedShiftRight, Constant, Register)] - = CAST2(unsignedShiftRightCR); - - BinaryOperations[INDEX2(Subtract, Constant, Register)] = CAST2(subtractCR); - BinaryOperations[INDEX2(Subtract, Register, Register)] = CAST2(subtractRR); - - BinaryOperations[INDEX2(LongCompare, Constant, Register)] - = CAST2(longCompareCR); - BinaryOperations[INDEX2(LongCompare, Register, Register)] - = CAST2(longCompareRR); - - BinaryOperations[INDEX2(Compare, Constant, Register)] = CAST2(compareCR); - BinaryOperations[INDEX2(Compare, Register, Constant)] = CAST2(compareRC); - BinaryOperations[INDEX2(Compare, Register, Register)] = CAST2(compareRR); - BinaryOperations[INDEX2(Compare, Address, Register)] = CAST2(compareAR); - BinaryOperations[INDEX2(Compare, Address, Memory)] = CAST2(compareAM); - BinaryOperations[INDEX2(Compare, Register, Memory)] = CAST2(compareRM); - BinaryOperations[INDEX2(Compare, Memory, Register)] = CAST2(compareMR); - BinaryOperations[INDEX2(Compare, Constant, Memory)] = CAST2(compareCM); - BinaryOperations[INDEX2(Compare, Memory, Memory)] = CAST2(compareMM); -} - -class MyAssembler: public Assembler { - public: - MyAssembler(System* s, Allocator* a, Zone* zone): c(s, a, zone) { - static bool populated = false; - if (not populated) { - populated = true; - populateTables(); + c->client->restore(rcx); + } else { + if (bSize == 8) rex(c); + if (v == 1) { + c->code.append(0xd1); + c->code.append(type | b->low); + } else if (isInt8(v)) { + c->code.append(0xc1); + c->code.append(type | b->low); + c->code.append(v); + } else { + abort(c); } } +} - virtual void setClient(Client* client) { - assert(&c, c.client == 0); - c.client = client; +void +shiftLeftRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize, Assembler::Register* b) +{ + assert(c, a->low == rcx); + + if (BytesPerWord == 4 and bSize == 8) { + // shld + c->code.append(0x0f); + c->code.append(0xa5); + c->code.append(0xc0 | (b->low << 3) | b->high); + + // shl + c->code.append(0xd3); + c->code.append(0xe0 | b->low); + + ResolvedPromise promise(32); + Assembler::Constant constant(&promise); + compareCR(c, aSize, &constant, aSize, a); + + c->code.append(0x0f); + c->code.append(0x8c); // jl + c->code.append4(2 + 2); + + Assembler::Register bh(b->high); + moveRR(c, 4, b, 4, &bh); // 2 bytes + xorRR(c, 4, b, 4, b); // 2 bytes + } else { + if (bSize == 8) rex(c); + c->code.append(0xd3); + c->code.append(0xe0 | b->low); + } +} + +void +shiftLeftCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) +{ + doShift(c, shiftLeftRR, 0xe0, aSize, a, bSize, b); +} + +void +shiftRightRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize, Assembler::Register* b) +{ + assert(c, a->low == rcx); + + if (BytesPerWord == 4 and bSize == 8) { + // shrd + c->code.append(0x0f); + c->code.append(0xad); + c->code.append(0xc0 | (b->high << 3) | b->low); + + // sar + c->code.append(0xd3); + c->code.append(0xf8 | b->high); + + ResolvedPromise promise(32); + Assembler::Constant constant(&promise); + compareCR(c, aSize, &constant, aSize, a); + + c->code.append(0x0f); + c->code.append(0x8c); // jl + c->code.append4(2 + 3); + + Assembler::Register bh(b->high); + moveRR(c, 4, &bh, 4, b); // 2 bytes + + // sar 31,high + c->code.append(0xc1); + c->code.append(0xf8 | b->high); + c->code.append(31); + } else { + if (bSize == 8) rex(c); + c->code.append(0xd3); + c->code.append(0xf8 | b->low); + } +} + +void +shiftRightCR(Context* c, unsigned aSize, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) +{ + doShift(c, shiftRightRR, 0xf8, aSize, a, bSize, b); +} + +void +unsignedShiftRightRR(Context* c, unsigned aSize, Assembler::Register* a, + unsigned bSize, Assembler::Register* b) +{ + assert(c, a->low == rcx); + + if (BytesPerWord == 4 and bSize == 8) { + // shrd + c->code.append(0x0f); + c->code.append(0xad); + c->code.append(0xc0 | (b->high << 3) | b->low); + + // shr + c->code.append(0xd3); + c->code.append(0xe8 | b->high); + + ResolvedPromise promise(32); + Assembler::Constant constant(&promise); + compareCR(c, aSize, &constant, aSize, a); + + c->code.append(0x0f); + c->code.append(0x8c); // jl + c->code.append4(2 + 2); + + Assembler::Register bh(b->high); + moveRR(c, 4, &bh, 4, b); // 2 bytes + xorRR(c, 4, &bh, 4, &bh); // 2 bytes + } else { + if (bSize == 8) rex(c); + c->code.append(0xd3); + c->code.append(0xe8 | b->low); + } +} + +void +unsignedShiftRightCR(Context* c, unsigned aSize UNUSED, Assembler::Constant* a, + unsigned bSize, Assembler::Register* b) +{ + doShift(c, unsignedShiftRightRR, 0xe8, aSize, a, bSize, b); +} + +void +populateTables(ArchitectureContext* c) +{ + const OperandType C = ConstantOperand; + const OperandType A = AddressOperand; + const OperandType R = RegisterOperand; + const OperandType M = MemoryOperand; + + OperationType* zo = c->operations; + UnaryOperationType* uo = c->unaryOperations; + BinaryOperationType* bo = c->binaryOperations; + + zo[Return] = return_; + + uo[index(Call, C)] = CAST1(callC); + uo[index(Call, R)] = CAST1(callR); + uo[index(Call, M)] = CAST1(callM); + + uo[index(AlignedCall, C)] = CAST1(alignedCallC); + + uo[index(LongCall, C)] = CAST1(longCallC); + + uo[index(Jump, R)] = CAST1(jumpR); + uo[index(Jump, C)] = CAST1(jumpC); + uo[index(Jump, M)] = CAST1(jumpM); + + uo[index(JumpIfEqual, C)] = CAST1(jumpIfEqualC); + uo[index(JumpIfNotEqual, C)] = CAST1(jumpIfNotEqualC); + uo[index(JumpIfGreater, C)] = CAST1(jumpIfGreaterC); + uo[index(JumpIfGreaterOrEqual, C)] = CAST1(jumpIfGreaterOrEqualC); + uo[index(JumpIfLess, C)] = CAST1(jumpIfLessC); + uo[index(JumpIfLessOrEqual, C)] = CAST1(jumpIfLessOrEqualC); + + uo[index(LongJump, C)] = CAST1(longJumpC); + + bo[index(Negate, R, R)] = CAST2(negateRR); + + bo[index(Move, R, R)] = CAST2(moveRR); + bo[index(Move, C, R)] = CAST2(moveCR); + bo[index(Move, M, R)] = CAST2(moveMR); + bo[index(Move, R, M)] = CAST2(moveRM); + bo[index(Move, C, M)] = CAST2(moveCM); + bo[index(Move, A, R)] = CAST2(moveAR); + + bo[index(MoveZ, R, R)] = CAST2(moveZRR); + bo[index(MoveZ, M, R)] = CAST2(moveZMR); + + bo[index(Compare, R, R)] = CAST2(compareRR); + bo[index(Compare, C, R)] = CAST2(compareCR); + bo[index(Compare, C, M)] = CAST2(compareCM); + bo[index(Compare, R, M)] = CAST2(compareRM); + + bo[index(Add, R, R)] = CAST2(addRR); + bo[index(Add, C, R)] = CAST2(addCR); + + bo[index(Subtract, C, R)] = CAST2(subtractCR); + bo[index(Subtract, R, R)] = CAST2(subtractRR); + + bo[index(And, R, R)] = CAST2(andRR); + bo[index(And, C, R)] = CAST2(andCR); + + bo[index(Or, R, R)] = CAST2(orRR); + bo[index(Or, C, R)] = CAST2(orCR); + + bo[index(Xor, R, R)] = CAST2(xorRR); + bo[index(Xor, C, R)] = CAST2(xorCR); + + bo[index(Multiply, R, R)] = CAST2(multiplyRR); + bo[index(Multiply, C, R)] = CAST2(multiplyCR); + + bo[index(Divide, R, R)] = CAST2(divideRR); + + bo[index(Remainder, R, R)] = CAST2(remainderRR); + + bo[index(LongCompare, C, R)] = CAST2(longCompareCR); + bo[index(LongCompare, R, R)] = CAST2(longCompareRR); + + bo[index(ShiftLeft, R, R)] = CAST2(shiftLeftRR); + bo[index(ShiftLeft, C, R)] = CAST2(shiftLeftCR); + + bo[index(ShiftRight, R, R)] = CAST2(shiftRightRR); + bo[index(ShiftRight, C, R)] = CAST2(shiftRightCR); + + bo[index(UnsignedShiftRight, R, R)] = CAST2(unsignedShiftRightRR); + bo[index(UnsignedShiftRight, C, R)] = CAST2(unsignedShiftRightCR); +} + +class MyArchitecture: public Assembler::Architecture { + public: + MyArchitecture(System* system): c(system), referenceCount(0) { + populateTables(&c); } virtual unsigned registerCount() { return 8;//BytesPerWord == 4 ? 8 : 16; } - virtual int base() { - return rbp; - } - virtual int stack() { return rsp; } @@ -2149,9 +2001,25 @@ class MyAssembler: public Assembler { return rax; } + virtual bool condensedAddressing() { + return true; + } + + virtual bool reserved(int register_) { + switch (register_) { + case rbp: + case rsp: + case rbx: + return true; + + default: + return false; + } + } + virtual int returnHigh() { return (BytesPerWord == 4 ? rdx : NoRegister); - } + } virtual unsigned argumentRegisterCount() { return (BytesPerWord == 4 ? 0 : 6); @@ -2178,133 +2046,6 @@ class MyAssembler: public Assembler { } } - virtual void plan(UnaryOperation op, unsigned size, uint8_t* typeMask, - uint64_t* registerMask, bool* thunk) - { - if (op == Negate and BytesPerWord == 4 and size == 8) { - *typeMask = 1 << RegisterOperand; - *registerMask = (static_cast(1) << (rdx + 32)) - | (static_cast(1) << rax); - } else { - *typeMask = (1 << RegisterOperand) | (1 << MemoryOperand); - *registerMask = ~static_cast(0); - } - *thunk = false; - } - - virtual void plan(BinaryOperation op, unsigned size, uint8_t* aTypeMask, - uint64_t* aRegisterMask, uint8_t* bTypeMask, - uint64_t* bRegisterMask, bool* thunk) - { - *aTypeMask = ~0; - *aRegisterMask = ~static_cast(0); - - *bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); - *bRegisterMask = ~static_cast(0); - - *thunk = false; - - switch (op) { - case Compare: - if (BytesPerWord == 8 and size != 8) { - *aTypeMask = ~(1 << MemoryOperand); - *bTypeMask = ~(1 << MemoryOperand); - } else { - *bTypeMask = ~(1 << ConstantOperand); - } - break; - - case Move: - if (BytesPerWord == 4 and size == 1) { - const uint32_t mask - = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx); - *aRegisterMask = (static_cast(mask) << 32) | mask; - *bRegisterMask = (static_cast(mask) << 32) | mask; - } - break; - - case Move4To8: - if (BytesPerWord == 4) { - const uint32_t mask = ~((1 << rax) | (1 << rdx)); - *aRegisterMask = (static_cast(mask) << 32) | mask; - *bRegisterMask = (static_cast(1) << (rdx + 32)) - | (static_cast(1) << rax); - } - break; - - case Multiply: - if (BytesPerWord == 4 and size == 8) { - const uint32_t mask = ~((1 << rax) | (1 << rdx)); - *aRegisterMask = (static_cast(mask) << 32) | mask; - *bRegisterMask = (static_cast(1) << (rdx + 32)) | mask; - } - break; - - case Divide: - if (BytesPerWord == 4 and size == 8) { - *bTypeMask = ~0; - *thunk = true; - } else { - *aRegisterMask = ~((1 << rax) | (1 << rdx)); - *bRegisterMask = 1 << rax; - } - break; - - case Remainder: - if (BytesPerWord == 4 and size == 8) { - *bTypeMask = ~0; - *thunk = true; - } else { - *aRegisterMask = ~((1 << rax) | (1 << rdx)); - *bRegisterMask = 1 << rax; - } - break; - - case ShiftLeft: - case ShiftRight: - case UnsignedShiftRight: { - *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); - *aRegisterMask = (~static_cast(0) << 32) - | (static_cast(1) << rcx); - const uint32_t mask = ~(1 << rcx); - *bRegisterMask = (static_cast(mask) << 32) | mask; - } break; - - default: - break; - } - } - - virtual void apply(Operation op) { - Operations[op](&c); - } - - virtual void apply(UnaryOperation op, unsigned size, - OperandType type, Operand* operand) - { - UnaryOperations[INDEX1(op, type)](&c, size, operand); - } - - virtual void apply(BinaryOperation op, unsigned size, - OperandType aType, Operand* a, - OperandType bType, Operand* b) - { - BinaryOperations[INDEX2(op, aType, bType)](&c, size, a, b); - } - - virtual void writeTo(uint8_t* dst) { - c.result = dst; - memcpy(dst, c.code.data, c.code.length()); - - for (Task* t = c.tasks; t; t = t->next) { - t->run(&c); - } - } - - virtual unsigned length() { - return c.code.length(); - } - virtual void updateCall(UnaryOperation op UNUSED, bool assertAlignment UNUSED, void* returnAddress, void* newTarget) @@ -2326,7 +2067,6 @@ class MyAssembler: public Assembler { assert(&c, instruction[0] == 0x49 and instruction[1] == 0xBA); assert(&c, instruction[10] == 0x41 and instruction[11] == 0xFF); - assert(&c, (op == LongCall and instruction[12] == 0xD2) or (op == LongJump and instruction[12] == 0xE2)); @@ -2337,22 +2077,364 @@ class MyAssembler: public Assembler { } } + virtual unsigned alignFrameSize(unsigned sizeInWords) { + const unsigned alignment = 16 / BytesPerWord; + return (ceiling(sizeInWords + FrameHeaderSize, alignment) * alignment) + - FrameHeaderSize; + } + + virtual void* frameIp(void* stack) { + return stack ? *static_cast(stack) : 0; + } + + virtual unsigned frameHeaderSize() { + return FrameHeaderSize; + } + + virtual unsigned frameReturnAddressSize() { + return 1; + } + + virtual unsigned frameFooterSize() { + return 0; + } + + virtual void nextFrame(void** stack, void** base) { + assert(&c, *static_cast(*base) != *base); + + *stack = static_cast(*base) + 1; + *base = *static_cast(*base); + } + + virtual void plan + (UnaryOperation, + unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, + bool* thunk) + { + *aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); + *aRegisterMask = ~static_cast(0); + *thunk = false; + } + + virtual void plan + (BinaryOperation op, + unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask, + bool* thunk) + { + *aTypeMask = ~0; + *aRegisterMask = ~static_cast(0); + + *bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); + *bRegisterMask = ~static_cast(0); + + *thunk = false; + + switch (op) { + case Compare: + *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); + *bTypeMask = (1 << RegisterOperand); + break; + + case Negate: + *aTypeMask = (1 << RegisterOperand); + *bTypeMask = (1 << RegisterOperand); + *aRegisterMask = (static_cast(1) << (rdx + 32)) + | (static_cast(1) << rax); + *bRegisterMask = *aRegisterMask; + break; + + case Move: + if (BytesPerWord == 4) { + if (aSize == 4 and bSize == 8) { + const uint32_t mask = ~((1 << rax) | (1 << rdx)); + *aRegisterMask = (static_cast(mask) << 32) | mask; + *bRegisterMask = (static_cast(1) << (rdx + 32)) + | (static_cast(1) << rax); + } else if (aSize == 1) { + const uint32_t mask + = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx); + *aRegisterMask = (static_cast(mask) << 32) | mask; + *bRegisterMask = (static_cast(mask) << 32) | mask; + } + } + break; + + default: + break; + } + } + + virtual void plan + (TernaryOperation op, + unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, + unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask, + bool* thunk) + { + *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); + *aRegisterMask = ~static_cast(0); + + *bTypeMask = (1 << RegisterOperand); + *bRegisterMask = ~static_cast(0); + + *thunk = false; + + switch (op) { + case Multiply: + if (BytesPerWord == 4 and aSize == 8) { + const uint32_t mask = ~((1 << rax) | (1 << rdx)); + *aRegisterMask = (static_cast(mask) << 32) | mask; + *bRegisterMask = (static_cast(1) << (rdx + 32)) | mask; + } + break; + + case Divide: + if (BytesPerWord == 4 and aSize == 8) { + *bTypeMask = ~0; + *thunk = true; + } else { + *aTypeMask = (1 << RegisterOperand); + *aRegisterMask = ~((1 << rax) | (1 << rdx)); + *bRegisterMask = 1 << rax; + } + break; + + case Remainder: + if (BytesPerWord == 4 and aSize == 8) { + *bTypeMask = ~0; + *thunk = true; + } else { + *aTypeMask = (1 << RegisterOperand); + *aRegisterMask = ~((1 << rax) | (1 << rdx)); + *bRegisterMask = 1 << rax; + } + break; + + case ShiftLeft: + case ShiftRight: + case UnsignedShiftRight: { + *aRegisterMask = (~static_cast(0) << 32) + | (static_cast(1) << rcx); + const uint32_t mask = ~(1 << rcx); + *bRegisterMask = (static_cast(mask) << 32) | mask; + } break; + + default: + break; + } + + *cTypeMask = *bTypeMask; + *cRegisterMask = *bRegisterMask; + } + + virtual void acquire() { + ++ referenceCount; + } + + virtual void release() { + if (-- referenceCount == 0) { + c.s->free(this); + } + } + + ArchitectureContext c; + unsigned referenceCount; +}; + +class MyAssembler: public Assembler { + public: + MyAssembler(System* s, Allocator* a, Zone* zone, MyArchitecture* arch): + c(s, a, zone), arch_(arch) + { } + + virtual void setClient(Client* client) { + assert(&c, c.client == 0); + c.client = client; + } + + virtual Architecture* arch() { + return arch_; + } + + virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) { + Register stack(rsp); + Memory stackDst(rbx, stackOffset); + apply(Move, BytesPerWord, RegisterOperand, &stack, + BytesPerWord, MemoryOperand, &stackDst); + + Register base(rbp); + Memory baseDst(rbx, baseOffset); + apply(Move, BytesPerWord, RegisterOperand, &base, + BytesPerWord, MemoryOperand, &baseDst); + } + + virtual void pushFrame(unsigned argumentCount, ...) { + struct { + unsigned size; + OperandType type; + Operand* operand; + } arguments[argumentCount]; + va_list a; va_start(a, argumentCount); + unsigned footprint = 0; + for (unsigned i = 0; i < argumentCount; ++i) { + arguments[i].size = va_arg(a, unsigned); + arguments[i].type = static_cast(va_arg(a, int)); + arguments[i].operand = va_arg(a, Operand*); + footprint += ceiling(arguments[i].size, BytesPerWord); + } + va_end(a); + + allocateFrame(arch_->alignFrameSize(footprint)); + + unsigned offset = 0; + for (unsigned i = 0; i < argumentCount; ++i) { + if (i < arch_->argumentRegisterCount()) { + Register dst(arch_->argumentRegister(i)); + apply(Move, + arguments[i].size, arguments[i].type, arguments[i].operand, + pad(arguments[i].size), RegisterOperand, &dst); + } else { + Memory dst(rsp, offset * BytesPerWord); + apply(Move, + arguments[i].size, arguments[i].type, arguments[i].operand, + pad(arguments[i].size), MemoryOperand, &dst); + offset += ceiling(arguments[i].size, BytesPerWord); + } + } + } + + virtual void allocateFrame(unsigned footprint) { + Register base(rbp); + pushR(&c, BytesPerWord, &base); + + Register stack(rsp); + apply(Move, BytesPerWord, RegisterOperand, &stack, + BytesPerWord, RegisterOperand, &base); + + Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); + apply(Subtract, BytesPerWord, ConstantOperand, &footprintConstant, + BytesPerWord, RegisterOperand, &stack, + BytesPerWord, RegisterOperand, &stack); + } + + virtual void popFrame() { + Register base(rbp); + Register stack(rsp); + apply(Move, BytesPerWord, RegisterOperand, &base, + BytesPerWord, RegisterOperand, &stack); + + popR(&c, BytesPerWord, &base); + } + + virtual void apply(Operation op) { + arch_->c.operations[op](&c); + } + + virtual void apply(UnaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand) + { + arch_->c.unaryOperations[index(op, aType)](&c, aSize, aOperand); + } + + virtual void apply(BinaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand, + unsigned bSize, OperandType bType, Operand* bOperand) + { + arch_->c.binaryOperations[index(op, aType, bType)] + (&c, aSize, aOperand, bSize, bOperand); + } + + virtual void apply(TernaryOperation op, + unsigned aSize, OperandType aType, Operand* aOperand, + unsigned bSize, OperandType bType, Operand* bOperand, + unsigned cSize UNUSED, OperandType cType UNUSED, + Operand*) + { + assert(&c, bSize == cSize); + assert(&c, bType == cType); + + arch_->c.binaryOperations[index(op, aType, bType)] + (&c, aSize, aOperand, bSize, bOperand); + } + + virtual void writeTo(uint8_t* dst) { + c.result = dst; + + for (MyBlock* b = c.firstBlock; b; b = b->next) { + unsigned index = 0; + unsigned padding = 0; + for (AlignmentPadding* p = b->firstPadding; p; p = p->next) { + unsigned size = p->offset - b->offset - index; + + memcpy(dst + b->start + index + padding, + c.code.data + b->offset + index, + size); + + index += size; + + while ((b->start + index + padding + 1) % 4) { + *(dst + b->start + index + padding) = 0x90; + ++ padding; + } + } + + memcpy(dst + b->start + index + padding, + c.code.data + b->offset + index, + b->size - index); + } + + for (Task* t = c.tasks; t; t = t->next) { + t->run(&c); + } + } + + virtual Promise* offset() { + return ::offset(&c); + } + + virtual Block* endBlock(bool startNew) { + MyBlock* b = c.lastBlock; + b->size = c.code.length() - b->offset; + if (startNew) { + c.lastBlock = new (c.zone->allocate(sizeof(MyBlock))) + MyBlock(c.code.length()); + } else { + c.lastBlock = 0; + } + return b; + } + + virtual unsigned length() { + return c.code.length(); + } + virtual void dispose() { c.code.dispose(); } Context c; + MyArchitecture* arch_; }; } // namespace namespace vm { -Assembler* -makeAssembler(System* system, Allocator* allocator, Zone* zone) +Assembler::Architecture* +makeArchitecture(System* system) { - return new (zone->allocate(sizeof(MyAssembler))) - MyAssembler(system, allocator, zone); + return new (allocate(system, sizeof(MyArchitecture))) MyArchitecture(system); } +Assembler* +makeAssembler(System* system, Allocator* allocator, Zone* zone, + Assembler::Architecture* architecture) +{ + return new (zone->allocate(sizeof(MyAssembler))) + MyAssembler(system, allocator, zone, + static_cast(architecture)); +} + + } // namespace vm diff --git a/src/x86.h b/src/x86.h index 3174af4bd3..ae56473882 100644 --- a/src/x86.h +++ b/src/x86.h @@ -12,14 +12,29 @@ #define X86_H #include "types.h" -#include "stdint.h" #include "common.h" -extern "C" void NO_RETURN -vmJump(void* address, void* base, void* stack, void* thread); - #ifdef __i386__ +# ifdef __APPLE__ +# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) +# define IP_REGISTER(context) (context->uc_mcontext->__ss.__eip) +# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__ebp) +# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp) +# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx) +# else +# define IP_REGISTER(context) (context->uc_mcontext->ss.eip) +# define BASE_REGISTER(context) (context->uc_mcontext->ss.ebp) +# define STACK_REGISTER(context) (context->uc_mcontext->ss.esp) +# define THREAD_REGISTER(context) (context->uc_mcontext->ss.ebx) +# endif +# else +# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP]) +# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP]) +# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP]) +# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_EBX]) +# endif + extern "C" uint64_t vmNativeCall(void* function, void* stack, unsigned stackSize, unsigned returnType); @@ -37,6 +52,11 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*, #elif defined __x86_64__ +# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP]) +# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_RBP]) +# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP]) +# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX]) + extern "C" uint64_t vmNativeCall(void* function, void* stack, unsigned stackSize, void* gprTable, void* sseTable, unsigned returnType); @@ -79,7 +99,7 @@ dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes, } } - return vmNativeCall(function, stack, stackIndex * 8, + return vmNativeCall(function, stack, stackIndex * BytesPerWord, (gprIndex ? gprTable : 0), (sseIndex ? sseTable : 0), returnType); } @@ -87,7 +107,7 @@ dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes, } // namespace vm #else -# error unsupported platform +# error unsupported architecture #endif diff --git a/test/Arrays.java b/test/Arrays.java new file mode 100644 index 0000000000..2dd2bcfc30 --- /dev/null +++ b/test/Arrays.java @@ -0,0 +1,58 @@ +public class Arrays { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + public static void main(String[] args) { + { int[] array = new int[0]; + Exception exception = null; + try { + int x = array[0]; + } catch (ArrayIndexOutOfBoundsException e) { + exception = e; + } + + expect(exception != null); + } + + { int[] array = new int[3]; + int i = 0; + array[i++] = 1; + array[i++] = 2; + array[i++] = 3; + + expect(array[--i] == 3); + expect(array[--i] == 2); + expect(array[--i] == 1); + } + + { Object[][] array = new Object[1][1]; + expect(array.length == 1); + expect(array[0].length == 1); + } + + { Object[][] array = new Object[2][3]; + expect(array.length == 2); + expect(array[0].length == 3); + } + + { int j = 0; + byte[] decodeTable = new byte[256]; + for (int i = 'A'; i <= 'Z'; ++i) decodeTable[i] = (byte) j++; + for (int i = 'a'; i <= 'z'; ++i) decodeTable[i] = (byte) j++; + for (int i = '0'; i <= '9'; ++i) decodeTable[i] = (byte) j++; + decodeTable['+'] = (byte) j++; + decodeTable['/'] = (byte) j++; + decodeTable['='] = 0; + + expect(decodeTable['a'] != 0); + } + + { boolean p = true; + int[] array = new int[] { 1, 2 }; + expect(array[0] == array[p ? 0 : 1]); + p = false; + expect(array[1] == array[p ? 0 : 1]); + } + } +} diff --git a/test/Integers.java b/test/Integers.java new file mode 100644 index 0000000000..2eef0d8bcd --- /dev/null +++ b/test/Integers.java @@ -0,0 +1,85 @@ +public class Integers { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + private static int gcd(int m, int n) { + int temp; + m = Math.abs(m); + n = Math.abs(n); + if (m < n) { + temp = m; + m = n; + n = temp; + } + while (n != 0) { + temp = m; + m = n; + n = temp % n; + } + return m; + } + + public static void main(String[] args) { + expect(gcd(12, 4) == 4); + + { int a = 2; + int b = 2; + int c = a + b; + } + + { int a = 2; + int c = a + a; + } + + { int a = -5; + int b = 2; + expect(a >> b == -5 >> 2); + expect(a >>> b == -5 >>> 2); + expect(a << b == -5 << 2); + expect(a + b == -5 + 2); + expect(a - b == -5 - 2); + expect(a * b == -5 * 2); + expect(a / b == -5 / 2); + expect(a % b == -5 % 2); + expect((a & b) == (-5 & 2)); + expect((a | b) == (-5 | 2)); + expect((a ^ b) == (-5 ^ 2)); + expect(-a == 5); + expect(~a == ~-5); + + a = 5; + b = 2; + expect(a >> b == 5 >> 2); + expect(a >>> b == 5 >>> 2); + expect(a << b == 5 << 2); + expect(a + b == 5 + 2); + expect(a - b == 5 - 2); + expect(a * b == 5 * 2); + expect(a / b == 5 / 2); + expect(a % b == 5 % 2); + expect((a & b) == (5 & 2)); + expect((a | b) == (5 | 2)); + expect((a ^ b) == (5 ^ 2)); + expect(-a == -5); + expect(~a == ~5); + } + + { int get_buffer = 2144642881; + int bits_left = 30; + int l = 9; + int code = (((get_buffer >> (bits_left -= (l)))) & ((1<<(l))-1)); + expect(code == 510); + } + + { int width = 8; + int height = 8; + int depth = 24; + int scanlinePad = 4; + + int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1)) + / scanlinePad * scanlinePad; + expect(bytesPerLine == 24); + } + } +} diff --git a/test/Longs.java b/test/Longs.java new file mode 100644 index 0000000000..59da607517 --- /dev/null +++ b/test/Longs.java @@ -0,0 +1,193 @@ +public class Longs { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + public static void putInt(int val, byte[] dst, int offset) { + System.out.println("put " + val); + dst[offset] = (byte)((val >> 24) & 0xff); + dst[offset+1] = (byte)((val >> 16) & 0xff); + dst[offset+2] = (byte)((val >> 8) & 0xff); + dst[offset+3] = (byte)((val ) & 0xff); + } + + public static void putLong(long val, byte[] dst, int offset) { + putInt((int)(val >> 32), dst, offset); + putInt((int)val, dst, offset + 4); + } + + private static long roundUp(long a, long b) { + a += b - 1L; + return a - (a % b); + } + + public static void main(String[] args) { + { long foo = 25214903884L; + int radix = 10; + expect(foo > 0); + foo /= radix; + expect(foo > 0); + } + + expect(roundUp(156, 2) == 156); + expect(((int) roundUp(156, 2)) == 156); + + expect(Long.parseLong("25214903884") == 25214903884L); + + expect(Long.parseLong("-9223372036854775808") == -9223372036854775808L); + + expect(String.valueOf(25214903884L).equals("25214903884")); + + expect(String.valueOf(-9223372036854775808L).equals + ("-9223372036854775808")); + + { long a = -5; + long b = 2; + expect(a >> b == -5L >> 2); + expect(a >>> b == -5L >>> 2); + expect(a << b == -5L << 2); + expect(a + b == -5L + 2L); + expect(a - b == -5L - 2L); + expect(a * b == -5L * 2L); + expect(a / b == -5L / 2L); + expect(a % b == -5L % 2L); + expect((a & b) == (-5L & 2L)); + expect((a | b) == (-5L | 2L)); + expect((a ^ b) == (-5L ^ 2L)); + expect(-a == 5L); + expect(~a == ~-5L); + + a = 5; + b = 2; + expect(a >> b == 5L >> 2); + expect(a >>> b == 5L >>> 2); + expect(a << b == 5L << 2); + expect(a + b == 5L + 2L); + expect(a - b == 5L - 2L); + expect(a * b == 5L * 2L); + expect(a / b == 5L / 2L); + expect(a % b == 5L % 2L); + expect((a & b) == (5L & 2L)); + expect((a | b) == (5L | 2L)); + expect((a ^ b) == (5L ^ 2L)); + expect(-a == -5L); + expect(~a == ~5L); + } + + { long a = -25214903884L; + long b = 2; + expect(a >> b == -25214903884L >> 2); + expect(a >>> b == -25214903884L >>> 2); + expect(a << b == -25214903884L << 2); + expect(a + b == -25214903884L + 2L); + expect(a - b == -25214903884L - 2L); + expect(a * b == -25214903884L * 2L); + expect(a / b == -25214903884L / 2L); + expect(a % b == -25214903884L % 2L); + expect((a & b) == (-25214903884L & 2L)); + expect((a | b) == (-25214903884L | 2L)); + expect((a ^ b) == (-25214903884L ^ 2L)); + expect(-a == 25214903884L); + expect(~a == ~-25214903884L); + + a = 25214903884L; + b = 2; + expect(a >> b == 25214903884L >> 2); + expect(a >>> b == 25214903884L >>> 2); + expect(a << b == 25214903884L << 2); + expect(a + b == 25214903884L + 2L); + expect(a - b == 25214903884L - 2L); + expect(a * b == 25214903884L * 2L); + expect(a / b == 25214903884L / 2L); + expect(a % b == 25214903884L % 2L); + expect((a & b) == (25214903884L & 2L)); + expect((a | b) == (25214903884L | 2L)); + expect((a ^ b) == (25214903884L ^ 2L)); + expect(-a == -25214903884L); + expect(~a == ~25214903884L); + } + + { long b = 2; + expect((-25214903884L) >> b == -25214903884L >> 2); + expect((-25214903884L) >>> b == -25214903884L >>> 2); + expect((-25214903884L) << b == -25214903884L << 2); + expect((-25214903884L) + b == -25214903884L + 2L); + expect((-25214903884L) - b == -25214903884L - 2L); + expect((-25214903884L) * b == -25214903884L * 2L); + expect((-25214903884L) / b == -25214903884L / 2L); + expect((-25214903884L) % b == -25214903884L % 2L); + expect(((-25214903884L) & b) == (-25214903884L & 2L)); + expect(((-25214903884L) | b) == (-25214903884L | 2L)); + expect(((-25214903884L) ^ b) == (-25214903884L ^ 2L)); + + b = 2; + expect(25214903884L >> b == 25214903884L >> 2); + expect(25214903884L >>> b == 25214903884L >>> 2); + expect(25214903884L << b == 25214903884L << 2); + expect(25214903884L + b == 25214903884L + 2L); + expect(25214903884L - b == 25214903884L - 2L); + expect(25214903884L * b == 25214903884L * 2L); + expect(25214903884L / b == 25214903884L / 2L); + expect(25214903884L % b == 25214903884L % 2L); + expect((25214903884L & b) == (25214903884L & 2L)); + expect((25214903884L | b) == (25214903884L | 2L)); + expect((25214903884L ^ b) == (25214903884L ^ 2L)); + } + + { long a = 2L; + expect(a + (-25214903884L) == 2L + (-25214903884L)); + expect(a - (-25214903884L) == 2L - (-25214903884L)); + expect(a * (-25214903884L) == 2L * (-25214903884L)); + expect(a / (-25214903884L) == 2L / (-25214903884L)); + expect(a % (-25214903884L) == 2L % (-25214903884L)); + expect((a & (-25214903884L)) == (2L & (-25214903884L))); + expect((a | (-25214903884L)) == (2L | (-25214903884L))); + expect((a ^ (-25214903884L)) == (2L ^ (-25214903884L))); + + a = 2L; + expect(a + 25214903884L == 2L + 25214903884L); + expect(a - 25214903884L == 2L - 25214903884L); + expect(a * 25214903884L == 2L * 25214903884L); + expect(a / 25214903884L == 2L / 25214903884L); + expect(a % 25214903884L == 2L % 25214903884L); + expect((a & 25214903884L) == (2L & 25214903884L)); + expect((a | 25214903884L) == (2L | 25214903884L)); + expect((a ^ 25214903884L) == (2L ^ 25214903884L)); + } + + { long x = 231; + expect((x >> 32) == 0); + expect((x >>> 32) == 0); + expect((x << 32) == 992137445376L); + + int shift = 32; + expect((x >> shift) == 0); + expect((x >>> shift) == 0); + expect((x << shift) == 992137445376L); + + long y = -231; + expect((y >> 32) == 0xffffffffffffffffL); + expect((y >>> 32) == 0xffffffffL); + } + + expect(Long.valueOf(231L) == 231L); + + { byte[] array = new byte[8]; + putLong(231, array, 0); + expect((array[0] & 0xff) == 0); + expect((array[1] & 0xff) == 0); + expect((array[2] & 0xff) == 0); + expect((array[3] & 0xff) == 0); + expect((array[4] & 0xff) == 0); + expect((array[5] & 0xff) == 0); + expect((array[6] & 0xff) == 0); + expect((array[7] & 0xff) == 231); + } + + java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(8); + buffer.putLong(231); + buffer.flip(); + expect(buffer.getLong() == 231); + } + +} diff --git a/test/Misc.java b/test/Misc.java index 80c6bd7535..d27f96a735 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -51,19 +51,6 @@ public class Misc { } } - public static void putInt(int val, byte[] dst, int offset) { - System.out.println("put " + val); - dst[offset] = (byte)((val >> 24) & 0xff); - dst[offset+1] = (byte)((val >> 16) & 0xff); - dst[offset+2] = (byte)((val >> 8) & 0xff); - dst[offset+3] = (byte)((val ) & 0xff); - } - - public static void putLong(long val, byte[] dst, int offset) { - putInt((int)(val >> 32), dst, offset); - putInt((int)val, dst, offset + 4); - } - public String toString() { return super.toString(); } @@ -91,252 +78,35 @@ public class Misc { return a + b + c; } - private static long roundUp(long a, long b) { - a += b - 1L; - return a - (a % b); + private static Object gimmeNull() { + return null; + } + + private static Object queryDefault(Object default_) { + Object o = gimmeNull(); + return (o == null ? default_ : o); } public static void main(String[] args) { - { long foo = 25214903884L; - int radix = 10; - expect(foo > 0); - foo /= radix; - expect(foo > 0); - } + expect(new String(new byte[] { 99, 111, 109, 46, 101, 99, 111, 118, 97, + 116, 101, 46, 110, 97, 116, 46, 98, 117, + 115, 46, 83, 121, 109, 98, 111, 108 }) + .equals("com.ecovate.nat.bus.Symbol")); - expect(Long.parseLong("25214903884") == 25214903884L); - - expect(Long.parseLong("-9223372036854775808") == -9223372036854775808L); - - expect(String.valueOf(25214903884L).equals("25214903884")); - - expect(String.valueOf(-9223372036854775808L).equals - ("-9223372036854775808")); - - { boolean p = true; - int[] array = new int[] { 1, 2 }; - expect(array[0] == array[p ? 0 : 1]); - p = false; - expect(array[1] == array[p ? 0 : 1]); - } - - expect(roundUp(156, 2) == 156); + expect(queryDefault(new Object()) != null); { Foo foo = new Foo(); int x = foo.a + foo.b + foo.c; bar(foo.a, foo.b, foo.c); } - { int get_buffer = 2144642881; - int bits_left = 30; - int l = 9; - int code = (((get_buffer >> (bits_left -= (l)))) & ((1<<(l))-1)); - expect(code == 510); - } - - { int width = 8; - int height = 8; - int depth = 24; - int scanlinePad = 4; - - int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1)) - / scanlinePad * scanlinePad; - expect(bytesPerLine == 24); - } - - { int a = -5; - int b = 2; - expect(a >> b == -5 >> 2); - expect(a >>> b == -5 >>> 2); - expect(a << b == -5 << 2); - expect(a + b == -5 + 2); - expect(a - b == -5 - 2); - expect(a * b == -5 * 2); - expect(a / b == -5 / 2); - expect(a % b == -5 % 2); - expect((a & b) == (-5 & 2)); - expect((a | b) == (-5 | 2)); - expect((a ^ b) == (-5 ^ 2)); - expect(-a == 5); - expect(~a == ~-5); - - a = 5; - b = 2; - expect(a >> b == 5 >> 2); - expect(a >>> b == 5 >>> 2); - expect(a << b == 5 << 2); - expect(a + b == 5 + 2); - expect(a - b == 5 - 2); - expect(a * b == 5 * 2); - expect(a / b == 5 / 2); - expect(a % b == 5 % 2); - expect((a & b) == (5 & 2)); - expect((a | b) == (5 | 2)); - expect((a ^ b) == (5 ^ 2)); - expect(-a == -5); - expect(~a == ~5); - } - - { long a = -5; - long b = 2; - expect(a >> b == -5L >> 2); - expect(a >>> b == -5L >>> 2); - expect(a << b == -5L << 2); - expect(a + b == -5L + 2L); - expect(a - b == -5L - 2L); - expect(a * b == -5L * 2L); - expect(a / b == -5L / 2L); - expect(a % b == -5L % 2L); - expect((a & b) == (-5L & 2L)); - expect((a | b) == (-5L | 2L)); - expect((a ^ b) == (-5L ^ 2L)); - expect(-a == 5L); - expect(~a == ~-5L); - - a = 5; - b = 2; - expect(a >> b == 5L >> 2); - expect(a >>> b == 5L >>> 2); - expect(a << b == 5L << 2); - expect(a + b == 5L + 2L); - expect(a - b == 5L - 2L); - expect(a * b == 5L * 2L); - expect(a / b == 5L / 2L); - expect(a % b == 5L % 2L); - expect((a & b) == (5L & 2L)); - expect((a | b) == (5L | 2L)); - expect((a ^ b) == (5L ^ 2L)); - expect(-a == -5L); - expect(~a == ~5L); - } - - { long a = -25214903884L; - long b = 2; - expect(a >> b == -25214903884L >> 2); - expect(a >>> b == -25214903884L >>> 2); - expect(a << b == -25214903884L << 2); - expect(a + b == -25214903884L + 2L); - expect(a - b == -25214903884L - 2L); - expect(a * b == -25214903884L * 2L); - expect(a / b == -25214903884L / 2L); - expect(a % b == -25214903884L % 2L); - expect((a & b) == (-25214903884L & 2L)); - expect((a | b) == (-25214903884L | 2L)); - expect((a ^ b) == (-25214903884L ^ 2L)); - expect(-a == 25214903884L); - expect(~a == ~-25214903884L); - - a = 25214903884L; - b = 2; - expect(a >> b == 25214903884L >> 2); - expect(a >>> b == 25214903884L >>> 2); - expect(a << b == 25214903884L << 2); - expect(a + b == 25214903884L + 2L); - expect(a - b == 25214903884L - 2L); - expect(a * b == 25214903884L * 2L); - expect(a / b == 25214903884L / 2L); - expect(a % b == 25214903884L % 2L); - expect((a & b) == (25214903884L & 2L)); - expect((a | b) == (25214903884L | 2L)); - expect((a ^ b) == (25214903884L ^ 2L)); - expect(-a == -25214903884L); - expect(~a == ~25214903884L); - } - - { long b = 2; - expect((-25214903884L) >> b == -25214903884L >> 2); - expect((-25214903884L) >>> b == -25214903884L >>> 2); - expect((-25214903884L) << b == -25214903884L << 2); - expect((-25214903884L) + b == -25214903884L + 2L); - expect((-25214903884L) - b == -25214903884L - 2L); - expect((-25214903884L) * b == -25214903884L * 2L); - expect((-25214903884L) / b == -25214903884L / 2L); - expect((-25214903884L) % b == -25214903884L % 2L); - expect(((-25214903884L) & b) == (-25214903884L & 2L)); - expect(((-25214903884L) | b) == (-25214903884L | 2L)); - expect(((-25214903884L) ^ b) == (-25214903884L ^ 2L)); - - b = 2; - expect(25214903884L >> b == 25214903884L >> 2); - expect(25214903884L >>> b == 25214903884L >>> 2); - expect(25214903884L << b == 25214903884L << 2); - expect(25214903884L + b == 25214903884L + 2L); - expect(25214903884L - b == 25214903884L - 2L); - expect(25214903884L * b == 25214903884L * 2L); - expect(25214903884L / b == 25214903884L / 2L); - expect(25214903884L % b == 25214903884L % 2L); - expect((25214903884L & b) == (25214903884L & 2L)); - expect((25214903884L | b) == (25214903884L | 2L)); - expect((25214903884L ^ b) == (25214903884L ^ 2L)); - } - - { long a = 2L; - expect(a + (-25214903884L) == 2L + (-25214903884L)); - expect(a - (-25214903884L) == 2L - (-25214903884L)); - expect(a * (-25214903884L) == 2L * (-25214903884L)); - expect(a / (-25214903884L) == 2L / (-25214903884L)); - expect(a % (-25214903884L) == 2L % (-25214903884L)); - expect((a & (-25214903884L)) == (2L & (-25214903884L))); - expect((a | (-25214903884L)) == (2L | (-25214903884L))); - expect((a ^ (-25214903884L)) == (2L ^ (-25214903884L))); - - a = 2L; - expect(a + 25214903884L == 2L + 25214903884L); - expect(a - 25214903884L == 2L - 25214903884L); - expect(a * 25214903884L == 2L * 25214903884L); - expect(a / 25214903884L == 2L / 25214903884L); - expect(a % 25214903884L == 2L % 25214903884L); - expect((a & 25214903884L) == (2L & 25214903884L)); - expect((a | 25214903884L) == (2L | 25214903884L)); - expect((a ^ 25214903884L) == (2L ^ 25214903884L)); - } - byte2 = 0; expect(byte2 == 0); - expect(Long.valueOf(231L) == 231L); - - { long x = 231; - expect((x >> 32) == 0); - expect((x >>> 32) == 0); - expect((x << 32) == 992137445376L); - - int shift = 32; - expect((x >> shift) == 0); - expect((x >>> shift) == 0); - expect((x << shift) == 992137445376L); - - long y = -231; - expect((y >> 32) == 0xffffffffffffffffL); - expect((y >>> 32) == 0xffffffffL); - } - - { byte[] array = new byte[8]; - putLong(231, array, 0); - expect((array[0] & 0xff) == 0); - expect((array[1] & 0xff) == 0); - expect((array[2] & 0xff) == 0); - expect((array[3] & 0xff) == 0); - expect((array[4] & 0xff) == 0); - expect((array[5] & 0xff) == 0); - expect((array[6] & 0xff) == 0); - expect((array[7] & 0xff) == 231); - } - - java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(8); - buffer.putLong(231); - buffer.flip(); - expect(buffer.getLong() == 231); - boolean v = Boolean.valueOf("true"); ClassLoader.getSystemClassLoader().toString(); - { int a = 2; - int b = 2; - int c = a + b; - } - { Misc m = new Misc(); m.toString(); @@ -374,33 +144,6 @@ public class Misc { expect(zip() == 47); expect(zup() == 47); - { int[] array = new int[0]; - Exception exception = null; - try { - int x = array[0]; - } catch (ArrayIndexOutOfBoundsException e) { - exception = e; - } - - expect(exception != null); - } - - { int[] array = new int[3]; - int i = 0; - array[i++] = 1; - array[i++] = 2; - array[i++] = 3; - - expect(array[--i] == 3); - expect(array[--i] == 2); - expect(array[--i] == 1); - } - - { Object[][] array = new Object[1][1]; - expect(array.length == 1); - expect(array[0].length == 1); - } - { Object a = new Object(); Object b = new Object(); @@ -421,16 +164,23 @@ public class Misc { foo.a = (foo.a + 1) % foo.array.length; } - { int j = 0; - byte[] decodeTable = new byte[256]; - for (int i = 'A'; i <= 'Z'; ++i) decodeTable[i] = (byte) j++; - for (int i = 'a'; i <= 'z'; ++i) decodeTable[i] = (byte) j++; - for (int i = '0'; i <= '9'; ++i) decodeTable[i] = (byte) j++; - decodeTable['+'] = (byte) j++; - decodeTable['/'] = (byte) j++; - decodeTable['='] = 0; + { boolean foo = false; + boolean iconic = false; + do { + zap(); + iconic = foo ? true : false; + } while (foo); + zap(); + } - expect(decodeTable['a'] != 0); + { int x = 0; + if (x == 0) { + x = 1; + do { + int y = x; + x = 1; + } while (x != 1); + } } } } diff --git a/test/Simple.java b/test/Simple.java new file mode 100644 index 0000000000..ce0c470e95 --- /dev/null +++ b/test/Simple.java @@ -0,0 +1,11 @@ +public class Simple { + public static int size(long v, int radix) { + int size = 0; + for (long n = v; n != 0; n /= radix) ++size; + return size; + } + + public static void main(String[] args) { + size(42, 10); + } +} diff --git a/test/Subroutine.java b/test/Subroutine.java new file mode 100644 index 0000000000..3ad78b00b8 --- /dev/null +++ b/test/Subroutine.java @@ -0,0 +1,42 @@ +public class Subroutine { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + + // This test is intended to cover the jsr and ret instructions. + // However, recent Sun javac versions avoid generating these + // instructions by default, so we must compile this class using + // -source 1.2 -target 1.1 -XDjsrlimit=0. + // + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4381996 + // + private static void test(boolean throw_, boolean predicate) { + int x = 42; + int y = 99; + int a = 0; + try { + try { + int z = x + y; + if (throw_) throw new DummyException(); + if (predicate) { + return; + } + Integer.valueOf(z).toString(); + } finally { + a = x + y; + System.gc(); + } + expect(a == x + y); + } catch (DummyException e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + test(false, false); + test(false, true); + test(true, false); + } + + private static class DummyException extends RuntimeException { } +}