2012-05-11 23:43:27 +00:00
|
|
|
/* Copyright (c) 2008-2012, Avian Contributors
|
2008-02-19 18:06:52 +00:00
|
|
|
|
|
|
|
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. */
|
|
|
|
|
2008-02-12 00:20:32 +00:00
|
|
|
#include "compiler.h"
|
2008-02-11 17:21:41 +00:00
|
|
|
#include "assembler.h"
|
2011-08-30 01:00:17 +00:00
|
|
|
#include "target.h"
|
2007-12-08 23:22:13 +00:00
|
|
|
|
|
|
|
using namespace vm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
namespace local {
|
|
|
|
|
2009-10-05 14:25:12 +00:00
|
|
|
const bool DebugAppend = false;
|
|
|
|
const bool DebugCompile = false;
|
|
|
|
const bool DebugResources = false;
|
2009-02-01 23:21:55 +00:00
|
|
|
const bool DebugFrame = false;
|
2009-10-05 14:25:12 +00:00
|
|
|
const bool DebugControl = false;
|
|
|
|
const bool DebugReads = false;
|
|
|
|
const bool DebugSites = false;
|
2009-02-01 23:21:55 +00:00
|
|
|
const bool DebugMoves = false;
|
2009-01-11 22:53:51 +00:00
|
|
|
const bool DebugBuddies = false;
|
2008-04-19 21:52:45 +00:00
|
|
|
|
2008-08-23 18:04:36 +00:00
|
|
|
const int AnyFrameIndex = -2;
|
|
|
|
const int NoFrameIndex = -1;
|
|
|
|
|
2009-03-17 00:00:51 +00:00
|
|
|
const unsigned StealRegisterReserveCount = 2;
|
2009-10-10 21:03:23 +00:00
|
|
|
|
|
|
|
// this should be equal to the largest number of registers used by a
|
|
|
|
// compare instruction:
|
2011-08-30 01:00:17 +00:00
|
|
|
const unsigned ResolveRegisterReserveCount = (TargetBytesPerWord == 8 ? 2 : 4);
|
2009-02-08 23:20:28 +00:00
|
|
|
|
2009-11-28 18:17:17 +00:00
|
|
|
const unsigned RegisterCopyCost = 1;
|
|
|
|
const unsigned AddressCopyCost = 2;
|
|
|
|
const unsigned ConstantCopyCost = 3;
|
|
|
|
const unsigned MemoryCopyCost = 4;
|
|
|
|
const unsigned CopyPenalty = 10;
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
class Context;
|
2008-04-16 20:58:21 +00:00
|
|
|
class Value;
|
2008-04-17 22:07:32 +00:00
|
|
|
class Stack;
|
|
|
|
class Site;
|
2008-10-12 00:23:08 +00:00
|
|
|
class ConstantSite;
|
|
|
|
class AddressSite;
|
2008-05-15 23:19:23 +00:00
|
|
|
class RegisterSite;
|
2008-09-28 21:56:12 +00:00
|
|
|
class MemorySite;
|
2008-04-17 22:07:32 +00:00
|
|
|
class Event;
|
2008-04-18 03:47:42 +00:00
|
|
|
class PushEvent;
|
2008-04-18 00:39:41 +00:00
|
|
|
class Read;
|
2008-09-13 21:09:26 +00:00
|
|
|
class MultiRead;
|
2008-09-22 14:28:18 +00:00
|
|
|
class StubRead;
|
2008-08-30 20:12:27 +00:00
|
|
|
class Block;
|
2008-11-01 22:16:18 +00:00
|
|
|
class Snapshot;
|
2007-12-09 22:45:43 +00:00
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
void NO_RETURN abort(Context*);
|
2008-03-15 23:54:20 +00:00
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
void
|
2008-08-16 17:45:36 +00:00
|
|
|
apply(Context* c, UnaryOperation op,
|
2009-01-25 22:03:38 +00:00
|
|
|
unsigned s1Size, Site* s1Low, Site* s1High);
|
2008-04-17 22:07:32 +00:00
|
|
|
|
|
|
|
void
|
2008-08-16 17:45:36 +00:00
|
|
|
apply(Context* c, BinaryOperation op,
|
2009-01-25 22:03:38 +00:00
|
|
|
unsigned s1Size, Site* s1Low, Site* s1High,
|
|
|
|
unsigned s2Size, Site* s2Low, Site* s2High);
|
2008-08-16 17:45:36 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
apply(Context* c, TernaryOperation op,
|
2009-01-25 22:03:38 +00:00
|
|
|
unsigned s1Size, Site* s1Low, Site* s1High,
|
|
|
|
unsigned s2Size, Site* s2Low, Site* s2High,
|
|
|
|
unsigned s3Size, Site* s3Low, Site* s3High);
|
2008-04-17 22:07:32 +00:00
|
|
|
|
2008-08-23 18:04:36 +00:00
|
|
|
class Cell {
|
|
|
|
public:
|
|
|
|
Cell(Cell* next, void* value): next(next), value(value) { }
|
|
|
|
|
|
|
|
Cell* next;
|
|
|
|
void* value;
|
|
|
|
};
|
|
|
|
|
2008-09-24 00:01:42 +00:00
|
|
|
class Local {
|
|
|
|
public:
|
|
|
|
Value* value;
|
2009-01-25 22:03:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
2008-09-24 00:01:42 +00:00
|
|
|
};
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
class Site {
|
|
|
|
public:
|
|
|
|
Site(): next(0) { }
|
|
|
|
|
2008-05-12 13:54:47 +00:00
|
|
|
virtual Site* readTarget(Context*, Read*) { return this; }
|
2008-04-17 02:55:38 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
virtual unsigned toString(Context*, char*, unsigned) = 0;
|
2008-10-04 17:26:35 +00:00
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
virtual unsigned copyCost(Context*, Site*) = 0;
|
2008-08-23 18:04:36 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual bool match(Context*, const SiteMask&) = 0;
|
2009-08-11 19:46:51 +00:00
|
|
|
|
|
|
|
virtual bool loneMatch(Context*, const SiteMask&) = 0;
|
2009-10-04 19:56:48 +00:00
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual bool matchNextWord(Context*, Site*, unsigned) = 0;
|
2008-04-16 20:58:21 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void acquire(Context*, Value*) { }
|
2008-04-17 02:55:38 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void release(Context*, Value*) { }
|
2008-04-19 00:19:45 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void freeze(Context*, Value*) { }
|
2008-05-12 13:54:47 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void thaw(Context*, Value*) { }
|
2008-05-12 13:54:47 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual bool frozen(Context*) { return false; }
|
2009-01-04 20:35:09 +00:00
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
virtual OperandType type(Context*) = 0;
|
2008-04-16 20:58:21 +00:00
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
virtual void asAssemblerOperand(Context*, Site*, Assembler::Operand*) = 0;
|
2008-04-16 20:58:21 +00:00
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
virtual Site* copy(Context*) = 0;
|
2008-10-04 17:26:35 +00:00
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
virtual Site* copyLow(Context*) = 0;
|
|
|
|
|
|
|
|
virtual Site* copyHigh(Context*) = 0;
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual Site* makeNextWord(Context*, unsigned) = 0;
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
virtual SiteMask mask(Context*) = 0;
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual SiteMask nextWordMask(Context*, unsigned) = 0;
|
2009-10-04 19:56:48 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
virtual unsigned registerSize(Context*) { return TargetBytesPerWord; }
|
2009-10-04 19:56:48 +00:00
|
|
|
|
|
|
|
virtual unsigned registerMask(Context*) { return 0; }
|
2009-09-26 19:43:44 +00:00
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
virtual bool isVolatile(Context*) { return false; }
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
Site* next;
|
|
|
|
};
|
|
|
|
|
2009-05-15 02:08:01 +00:00
|
|
|
class Stack {
|
2008-11-07 00:39:38 +00:00
|
|
|
public:
|
2009-01-25 22:03:38 +00:00
|
|
|
Stack(unsigned index, Value* value, Stack* next):
|
|
|
|
index(index), value(value), next(next)
|
2008-11-07 00:39:38 +00:00
|
|
|
{ }
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
unsigned index;
|
2008-11-07 00:39:38 +00:00
|
|
|
Value* value;
|
2009-01-25 22:03:38 +00:00
|
|
|
Stack* next;
|
2008-11-07 00:39:38 +00:00
|
|
|
};
|
|
|
|
|
2008-11-02 20:35:35 +00:00
|
|
|
class ForkElement {
|
2008-09-22 14:28:18 +00:00
|
|
|
public:
|
|
|
|
Value* value;
|
|
|
|
MultiRead* read;
|
2008-11-02 20:35:35 +00:00
|
|
|
bool local;
|
2008-09-22 14:28:18 +00:00
|
|
|
};
|
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
class ForkState: public Compiler::State {
|
2008-04-17 22:07:32 +00:00
|
|
|
public:
|
2009-01-25 22:03:38 +00:00
|
|
|
ForkState(Stack* stack, Local* locals, Cell* saved, Event* predecessor,
|
2008-10-14 00:18:18 +00:00
|
|
|
unsigned logicalIp):
|
2008-04-27 21:58:29 +00:00
|
|
|
stack(stack),
|
2008-07-05 20:21:13 +00:00
|
|
|
locals(locals),
|
2008-11-07 00:39:38 +00:00
|
|
|
saved(saved),
|
2008-09-20 23:42:46 +00:00
|
|
|
predecessor(predecessor),
|
|
|
|
logicalIp(logicalIp),
|
|
|
|
readCount(0)
|
2008-04-17 22:07:32 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
Stack* stack;
|
2008-09-24 00:01:42 +00:00
|
|
|
Local* locals;
|
2009-01-25 22:03:38 +00:00
|
|
|
Cell* saved;
|
2008-09-20 23:42:46 +00:00
|
|
|
Event* predecessor;
|
|
|
|
unsigned logicalIp;
|
|
|
|
unsigned readCount;
|
2008-11-02 20:35:35 +00:00
|
|
|
ForkElement elements[0];
|
2008-04-17 22:07:32 +00:00
|
|
|
};
|
|
|
|
|
2008-11-14 00:59:21 +00:00
|
|
|
class MySubroutine: public Compiler::Subroutine {
|
|
|
|
public:
|
|
|
|
MySubroutine(): forkState(0) { }
|
|
|
|
|
|
|
|
ForkState* forkState;
|
|
|
|
};
|
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
class LogicalInstruction {
|
|
|
|
public:
|
2008-09-24 00:01:42 +00:00
|
|
|
LogicalInstruction(int index, Stack* stack, Local* locals):
|
2008-09-15 02:28:42 +00:00
|
|
|
firstEvent(0), lastEvent(0), immediatePredecessor(0), stack(stack),
|
2008-11-14 00:59:21 +00:00
|
|
|
locals(locals), machineOffset(0), subroutine(0), index(index)
|
2008-09-07 20:12:11 +00:00
|
|
|
{ }
|
2008-09-07 01:37:12 +00:00
|
|
|
|
2008-04-19 07:03:59 +00:00
|
|
|
Event* firstEvent;
|
2008-04-17 22:07:32 +00:00
|
|
|
Event* lastEvent;
|
2008-04-20 19:35:36 +00:00
|
|
|
LogicalInstruction* immediatePredecessor;
|
|
|
|
Stack* stack;
|
2008-09-24 00:01:42 +00:00
|
|
|
Local* locals;
|
2008-09-09 00:31:19 +00:00
|
|
|
Promise* machineOffset;
|
2008-11-14 00:59:21 +00:00
|
|
|
MySubroutine* subroutine;
|
2008-08-30 20:12:27 +00:00
|
|
|
int index;
|
2008-04-17 22:07:32 +00:00
|
|
|
};
|
|
|
|
|
2009-01-03 00:44:47 +00:00
|
|
|
class Resource {
|
2008-04-17 22:07:32 +00:00
|
|
|
public:
|
2009-01-03 21:34:45 +00:00
|
|
|
Resource(bool reserved = false):
|
2011-03-27 20:15:05 +00:00
|
|
|
value(0), site(0), previousAcquired(0), nextAcquired(0), freezeCount(0),
|
|
|
|
referenceCount(0), reserved(reserved)
|
2009-01-03 00:44:47 +00:00
|
|
|
{ }
|
|
|
|
|
2009-01-11 18:48:02 +00:00
|
|
|
virtual void freeze(Context*, Value*) = 0;
|
|
|
|
|
|
|
|
virtual void thaw(Context*, Value*) = 0;
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
virtual unsigned toString(Context*, char*, unsigned) = 0;
|
2009-01-03 00:44:47 +00:00
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
Value* value;
|
2008-12-24 20:35:43 +00:00
|
|
|
Site* site;
|
2011-03-27 20:15:05 +00:00
|
|
|
Resource* previousAcquired;
|
|
|
|
Resource* nextAcquired;
|
2009-01-03 21:34:45 +00:00
|
|
|
uint8_t freezeCount;
|
|
|
|
uint8_t referenceCount;
|
|
|
|
bool reserved;
|
2008-09-28 21:56:12 +00:00
|
|
|
};
|
|
|
|
|
2009-01-03 00:44:47 +00:00
|
|
|
class RegisterResource: public Resource {
|
2008-09-28 21:56:12 +00:00
|
|
|
public:
|
2009-01-03 00:44:47 +00:00
|
|
|
RegisterResource(bool reserved):
|
2009-01-03 21:34:45 +00:00
|
|
|
Resource(reserved)
|
2009-01-03 00:44:47 +00:00
|
|
|
{ }
|
|
|
|
|
2009-01-11 18:48:02 +00:00
|
|
|
virtual void freeze(Context*, Value*);
|
|
|
|
|
|
|
|
virtual void thaw(Context*, Value*);
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
virtual unsigned toString(Context* c, char* buffer, unsigned bufferSize) {
|
|
|
|
return vm::snprintf(buffer, bufferSize, "register %d", index(c));
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned index(Context*);
|
2009-01-03 00:44:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class FrameResource: public Resource {
|
2009-01-11 18:48:02 +00:00
|
|
|
public:
|
|
|
|
virtual void freeze(Context*, Value*);
|
|
|
|
|
|
|
|
virtual void thaw(Context*, Value*);
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
virtual unsigned toString(Context* c, char* buffer, unsigned bufferSize) {
|
|
|
|
return vm::snprintf(buffer, bufferSize, "frame %d", index(c));
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned index(Context*);
|
2008-04-17 22:07:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class ConstantPoolNode {
|
|
|
|
public:
|
|
|
|
ConstantPoolNode(Promise* promise): promise(promise), next(0) { }
|
|
|
|
|
|
|
|
Promise* promise;
|
|
|
|
ConstantPoolNode* next;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Read {
|
|
|
|
public:
|
2009-01-25 22:03:38 +00:00
|
|
|
Read():
|
|
|
|
value(0), event(0), eventNext(0)
|
2008-04-17 22:07:32 +00:00
|
|
|
{ }
|
2008-07-05 20:21:13 +00:00
|
|
|
|
2009-08-05 00:28:34 +00:00
|
|
|
virtual bool intersect(SiteMask* mask, unsigned depth = 0) = 0;
|
2009-04-08 00:55:43 +00:00
|
|
|
|
2009-11-30 15:10:34 +00:00
|
|
|
virtual Value* high(Context* c) { abort(c); }
|
2009-10-04 19:56:48 +00:00
|
|
|
|
2009-04-08 00:55:43 +00:00
|
|
|
virtual Value* successor() = 0;
|
2008-07-05 20:21:13 +00:00
|
|
|
|
|
|
|
virtual bool valid() = 0;
|
2008-08-30 20:12:27 +00:00
|
|
|
|
2008-09-13 21:09:26 +00:00
|
|
|
virtual void append(Context* c, Read* r) = 0;
|
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual Read* next(Context* c) = 0;
|
|
|
|
|
2008-08-28 22:43:35 +00:00
|
|
|
Value* value;
|
|
|
|
Event* event;
|
|
|
|
Read* eventNext;
|
2008-04-17 22:07:32 +00:00
|
|
|
};
|
|
|
|
|
2008-08-28 22:43:35 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
SiteMask
|
|
|
|
intersect(const SiteMask& a, const SiteMask& b)
|
|
|
|
{
|
|
|
|
return SiteMask(a.typeMask & b.typeMask, a.registerMask & b.registerMask,
|
|
|
|
intersectFrameIndexes(a.frameIndex, b.frameIndex));
|
|
|
|
}
|
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
class Value: public Compiler::Operand {
|
|
|
|
public:
|
2009-08-10 19:20:23 +00:00
|
|
|
Value(Site* site, Site* target, ValueType type):
|
2008-11-01 19:14:13 +00:00
|
|
|
reads(0), lastRead(0), sites(site), source(0), target(target), buddy(this),
|
2009-10-10 22:07:30 +00:00
|
|
|
nextWord(this), home(NoFrameIndex), type(type), wordIndex(0)
|
2008-04-17 22:07:32 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
Read* reads;
|
|
|
|
Read* lastRead;
|
|
|
|
Site* sites;
|
|
|
|
Site* source;
|
2008-04-19 20:41:31 +00:00
|
|
|
Site* target;
|
2008-11-01 19:14:13 +00:00
|
|
|
Value* buddy;
|
2009-10-10 22:07:30 +00:00
|
|
|
Value* nextWord;
|
2011-03-26 00:27:02 +00:00
|
|
|
int16_t home;
|
2009-08-06 16:14:31 +00:00
|
|
|
ValueType type;
|
2009-10-10 22:07:30 +00:00
|
|
|
uint8_t wordIndex;
|
2008-04-17 22:07:32 +00:00
|
|
|
};
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
uint32_t
|
|
|
|
registerMask(Assembler::Architecture* arch)
|
|
|
|
{
|
|
|
|
return arch->generalRegisterMask() | arch->floatRegisterMask();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
maskStart(uint32_t mask)
|
|
|
|
{
|
|
|
|
for (int i = 0; i <= 31; ++i) {
|
|
|
|
if (mask & (1 << i)) return i;
|
|
|
|
}
|
|
|
|
return 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
maskLimit(uint32_t mask)
|
|
|
|
{
|
|
|
|
for (int i = 31; i >= 0; --i) {
|
|
|
|
if (mask & (1 << i)) return i + 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
class Context {
|
|
|
|
public:
|
2008-05-31 22:14:27 +00:00
|
|
|
Context(System* system, Assembler* assembler, Zone* zone,
|
|
|
|
Compiler::Client* client):
|
2008-04-17 22:07:32 +00:00
|
|
|
system(system),
|
|
|
|
assembler(assembler),
|
2008-08-23 18:04:36 +00:00
|
|
|
arch(assembler->arch()),
|
2008-04-17 22:07:32 +00:00
|
|
|
zone(zone),
|
2008-05-31 22:14:27 +00:00
|
|
|
client(client),
|
2008-09-13 21:09:26 +00:00
|
|
|
stack(0),
|
|
|
|
locals(0),
|
2008-11-07 00:39:38 +00:00
|
|
|
saved(0),
|
2008-09-20 23:42:46 +00:00
|
|
|
predecessor(0),
|
2008-04-17 22:07:32 +00:00
|
|
|
logicalCode(0),
|
2009-09-26 19:43:44 +00:00
|
|
|
registerStart(maskStart(registerMask(arch))),
|
|
|
|
registerLimit(maskLimit(registerMask(arch))),
|
|
|
|
generalRegisterStart(maskStart(arch->generalRegisterMask())),
|
|
|
|
generalRegisterLimit(maskLimit(arch->generalRegisterMask())),
|
|
|
|
floatRegisterStart(maskStart(arch->floatRegisterMask())),
|
|
|
|
floatRegisterLimit(maskLimit(arch->floatRegisterMask())),
|
2009-01-03 00:44:47 +00:00
|
|
|
registerResources
|
|
|
|
(static_cast<RegisterResource*>
|
2009-09-26 19:43:44 +00:00
|
|
|
(zone->allocate(sizeof(RegisterResource) * registerLimit))),
|
2008-09-28 21:56:12 +00:00
|
|
|
frameResources(0),
|
2011-03-27 20:15:05 +00:00
|
|
|
acquiredResources(0),
|
2008-04-17 22:07:32 +00:00
|
|
|
firstConstant(0),
|
|
|
|
lastConstant(0),
|
2008-08-30 20:12:27 +00:00
|
|
|
machineCode(0),
|
|
|
|
firstEvent(0),
|
2008-09-07 01:37:12 +00:00
|
|
|
lastEvent(0),
|
2008-10-14 00:18:18 +00:00
|
|
|
forkState(0),
|
2008-11-14 00:59:21 +00:00
|
|
|
subroutine(0),
|
2011-02-28 06:03:13 +00:00
|
|
|
firstBlock(0),
|
2008-08-30 20:12:27 +00:00
|
|
|
logicalIp(-1),
|
2008-04-17 22:07:32 +00:00
|
|
|
constantCount(0),
|
2008-08-30 20:12:27 +00:00
|
|
|
logicalCodeLength(0),
|
|
|
|
parameterFootprint(0),
|
|
|
|
localFootprint(0),
|
2008-09-23 21:18:41 +00:00
|
|
|
machineCodeSize(0),
|
2008-09-28 19:00:52 +00:00
|
|
|
alignedFrameSize(0),
|
2009-10-07 00:50:32 +00:00
|
|
|
availableGeneralRegisterCount(generalRegisterLimit - generalRegisterStart)
|
2008-04-17 22:07:32 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
for (unsigned i = generalRegisterStart; i < generalRegisterLimit; ++i) {
|
2009-01-03 00:44:47 +00:00
|
|
|
new (registerResources + i) RegisterResource(arch->reserved(i));
|
2009-09-26 19:43:44 +00:00
|
|
|
|
2009-01-11 18:48:02 +00:00
|
|
|
if (registerResources[i].reserved) {
|
2009-09-26 19:43:44 +00:00
|
|
|
-- availableGeneralRegisterCount;
|
2009-01-11 18:48:02 +00:00
|
|
|
}
|
2008-05-12 13:54:47 +00:00
|
|
|
}
|
2009-09-26 19:43:44 +00:00
|
|
|
for (unsigned i = floatRegisterStart; i < floatRegisterLimit; ++i) {
|
|
|
|
new (registerResources + i) RegisterResource(arch->reserved(i));
|
|
|
|
}
|
2008-04-17 22:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* system;
|
|
|
|
Assembler* assembler;
|
2008-08-23 18:04:36 +00:00
|
|
|
Assembler::Architecture* arch;
|
2008-04-17 22:07:32 +00:00
|
|
|
Zone* zone;
|
2008-05-31 22:14:27 +00:00
|
|
|
Compiler::Client* client;
|
2008-09-13 21:09:26 +00:00
|
|
|
Stack* stack;
|
2008-09-24 00:01:42 +00:00
|
|
|
Local* locals;
|
2009-01-25 22:03:38 +00:00
|
|
|
Cell* saved;
|
2008-09-20 23:42:46 +00:00
|
|
|
Event* predecessor;
|
2008-08-16 17:45:36 +00:00
|
|
|
LogicalInstruction** logicalCode;
|
2009-09-26 19:43:44 +00:00
|
|
|
uint8_t registerStart;
|
|
|
|
uint8_t registerLimit;
|
|
|
|
uint8_t generalRegisterStart;
|
|
|
|
uint8_t generalRegisterLimit;
|
|
|
|
uint8_t floatRegisterStart;
|
|
|
|
uint8_t floatRegisterLimit;
|
2009-01-03 00:44:47 +00:00
|
|
|
RegisterResource* registerResources;
|
2008-09-28 21:56:12 +00:00
|
|
|
FrameResource* frameResources;
|
2011-03-27 20:15:05 +00:00
|
|
|
Resource* acquiredResources;
|
2008-04-17 22:07:32 +00:00
|
|
|
ConstantPoolNode* firstConstant;
|
|
|
|
ConstantPoolNode* lastConstant;
|
2008-08-30 20:12:27 +00:00
|
|
|
uint8_t* machineCode;
|
|
|
|
Event* firstEvent;
|
2008-09-07 01:37:12 +00:00
|
|
|
Event* lastEvent;
|
2008-10-14 00:18:18 +00:00
|
|
|
ForkState* forkState;
|
2008-11-14 00:59:21 +00:00
|
|
|
MySubroutine* subroutine;
|
2011-02-28 06:03:13 +00:00
|
|
|
Block* firstBlock;
|
2008-08-30 20:12:27 +00:00
|
|
|
int logicalIp;
|
2008-04-17 22:07:32 +00:00
|
|
|
unsigned constantCount;
|
2008-08-30 20:12:27 +00:00
|
|
|
unsigned logicalCodeLength;
|
|
|
|
unsigned parameterFootprint;
|
|
|
|
unsigned localFootprint;
|
2008-09-23 21:18:41 +00:00
|
|
|
unsigned machineCodeSize;
|
2008-09-28 19:00:52 +00:00
|
|
|
unsigned alignedFrameSize;
|
2009-09-26 19:43:44 +00:00
|
|
|
unsigned availableGeneralRegisterCount;
|
2008-04-17 22:07:32 +00:00
|
|
|
};
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
unsigned
|
2009-09-26 19:43:44 +00:00
|
|
|
RegisterResource::index(Context* c)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
return this - c->registerResources;
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
unsigned
|
2009-09-26 19:43:44 +00:00
|
|
|
FrameResource::index(Context* c)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
return this - c->frameResources;
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
2008-04-18 17:00:55 +00:00
|
|
|
class PoolPromise: public Promise {
|
|
|
|
public:
|
|
|
|
PoolPromise(Context* c, int key): c(c), key(key) { }
|
|
|
|
|
|
|
|
virtual int64_t value() {
|
|
|
|
if (resolved()) {
|
2011-08-30 01:00:17 +00:00
|
|
|
return reinterpret_cast<int64_t>
|
2011-09-01 03:18:00 +00:00
|
|
|
(c->machineCode + pad(c->machineCodeSize, TargetBytesPerWord)
|
2011-08-30 01:00:17 +00:00
|
|
|
+ (key * TargetBytesPerWord));
|
2008-04-18 17:00:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool resolved() {
|
|
|
|
return c->machineCode != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Context* c;
|
|
|
|
int key;
|
|
|
|
};
|
|
|
|
|
|
|
|
class CodePromise: public Promise {
|
|
|
|
public:
|
2008-08-30 20:12:27 +00:00
|
|
|
CodePromise(Context* c, CodePromise* next):
|
|
|
|
c(c), offset(0), next(next)
|
|
|
|
{ }
|
2008-04-18 17:00:55 +00:00
|
|
|
|
2008-09-09 00:31:19 +00:00
|
|
|
CodePromise(Context* c, Promise* offset):
|
2008-08-30 20:12:27 +00:00
|
|
|
c(c), offset(offset), next(0)
|
|
|
|
{ }
|
2008-04-18 17:00:55 +00:00
|
|
|
|
|
|
|
virtual int64_t value() {
|
|
|
|
if (resolved()) {
|
2008-08-30 20:12:27 +00:00
|
|
|
return reinterpret_cast<intptr_t>(c->machineCode + offset->value());
|
2008-04-18 17:00:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool resolved() {
|
2008-08-30 20:12:27 +00:00
|
|
|
return c->machineCode != 0 and offset and offset->resolved();
|
2008-04-18 17:00:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Context* c;
|
2008-09-09 00:31:19 +00:00
|
|
|
Promise* offset;
|
2008-04-18 17:00:55 +00:00
|
|
|
CodePromise* next;
|
|
|
|
};
|
|
|
|
|
2008-09-07 20:12:11 +00:00
|
|
|
unsigned
|
|
|
|
machineOffset(Context* c, int logicalIp)
|
|
|
|
{
|
2008-09-22 14:28:18 +00:00
|
|
|
return c->logicalCode[logicalIp]->machineOffset->value();
|
2008-09-07 20:12:11 +00:00
|
|
|
}
|
|
|
|
|
2008-04-18 17:00:55 +00:00
|
|
|
class IpPromise: public Promise {
|
|
|
|
public:
|
|
|
|
IpPromise(Context* c, int logicalIp):
|
|
|
|
c(c),
|
|
|
|
logicalIp(logicalIp)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual int64_t value() {
|
|
|
|
if (resolved()) {
|
|
|
|
return reinterpret_cast<intptr_t>
|
2008-09-07 20:12:11 +00:00
|
|
|
(c->machineCode + machineOffset(c, logicalIp));
|
2008-04-18 17:00:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool resolved() {
|
2011-03-15 23:17:26 +00:00
|
|
|
return c->machineCode != 0
|
|
|
|
and c->logicalCode[logicalIp]->machineOffset->resolved();
|
2008-04-18 17:00:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Context* c;
|
|
|
|
int logicalIp;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline void NO_RETURN
|
|
|
|
abort(Context* c)
|
|
|
|
{
|
|
|
|
abort(c->system);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
inline void
|
|
|
|
assert(Context* c, bool v)
|
|
|
|
{
|
|
|
|
assert(c->system, v);
|
|
|
|
}
|
|
|
|
#endif // not NDEBUG
|
|
|
|
|
|
|
|
inline void
|
|
|
|
expect(Context* c, bool v)
|
|
|
|
{
|
|
|
|
expect(c->system, v);
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
unsigned
|
|
|
|
count(Cell* c)
|
|
|
|
{
|
|
|
|
unsigned count = 0;
|
|
|
|
while (c) {
|
|
|
|
++ count;
|
|
|
|
c = c->next;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2008-09-07 20:12:11 +00:00
|
|
|
Cell*
|
|
|
|
cons(Context* c, void* value, Cell* next)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new (c->zone) Cell(next, value);
|
2008-09-07 20:12:11 +00:00
|
|
|
}
|
|
|
|
|
2008-10-15 00:45:31 +00:00
|
|
|
Cell*
|
|
|
|
reverseDestroy(Cell* cell)
|
|
|
|
{
|
|
|
|
Cell* previous = 0;
|
|
|
|
while (cell) {
|
|
|
|
Cell* next = cell->next;
|
|
|
|
cell->next = previous;
|
|
|
|
previous = cell;
|
|
|
|
cell = next;
|
|
|
|
}
|
|
|
|
return previous;
|
|
|
|
}
|
|
|
|
|
2008-09-22 14:28:18 +00:00
|
|
|
class StubReadPair {
|
|
|
|
public:
|
|
|
|
Value* value;
|
|
|
|
StubRead* read;
|
|
|
|
};
|
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
class JunctionState {
|
2008-04-18 17:00:55 +00:00
|
|
|
public:
|
2008-12-15 14:35:19 +00:00
|
|
|
JunctionState(unsigned frameFootprint): frameFootprint(frameFootprint) { }
|
2008-04-18 17:00:55 +00:00
|
|
|
|
2008-12-15 14:35:19 +00:00
|
|
|
unsigned frameFootprint;
|
2008-10-14 00:18:18 +00:00
|
|
|
StubReadPair reads[0];
|
|
|
|
};
|
2008-09-07 01:37:12 +00:00
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
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)
|
|
|
|
{ }
|
2008-09-15 02:28:42 +00:00
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
Event* predecessor;
|
|
|
|
Link* nextPredecessor;
|
|
|
|
Event* successor;
|
|
|
|
Link* nextSuccessor;
|
|
|
|
ForkState* forkState;
|
|
|
|
JunctionState* junctionState;
|
|
|
|
};
|
2008-09-15 02:28:42 +00:00
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
Link*
|
|
|
|
link(Context* c, Event* predecessor, Link* nextPredecessor, Event* successor,
|
|
|
|
Link* nextSuccessor, ForkState* forkState)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) Link
|
2008-10-14 00:18:18 +00:00
|
|
|
(predecessor, nextPredecessor, successor, nextSuccessor, forkState);
|
|
|
|
}
|
2008-04-18 17:00:55 +00:00
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
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), stackBefore(c->stack), localsBefore(c->locals),
|
|
|
|
stackAfter(0), localsAfter(0), promises(0), reads(0),
|
2008-11-01 22:16:18 +00:00
|
|
|
junctionSites(0), snapshots(0), predecessors(0), successors(0),
|
2008-10-15 00:45:31 +00:00
|
|
|
visitLinks(0), block(0), logicalInstruction(c->logicalCode[c->logicalIp]),
|
2008-10-14 00:18:18 +00:00
|
|
|
readCount(0)
|
|
|
|
{ }
|
2008-04-18 17:00:55 +00:00
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual const char* name() = 0;
|
2008-04-18 17:00:55 +00:00
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
virtual void compile(Context* c) = 0;
|
2008-08-30 20:12:27 +00:00
|
|
|
|
2008-10-08 00:08:13 +00:00
|
|
|
virtual bool isBranch() { return false; }
|
|
|
|
|
2009-04-26 02:54:36 +00:00
|
|
|
virtual bool allExits() { return false; }
|
2009-04-26 01:51:33 +00:00
|
|
|
|
2008-04-18 17:00:55 +00:00
|
|
|
Event* next;
|
2008-10-04 17:26:35 +00:00
|
|
|
Stack* stackBefore;
|
|
|
|
Local* localsBefore;
|
|
|
|
Stack* stackAfter;
|
|
|
|
Local* localsAfter;
|
2008-04-18 17:00:55 +00:00
|
|
|
CodePromise* promises;
|
|
|
|
Read* reads;
|
2008-08-30 20:12:27 +00:00
|
|
|
Site** junctionSites;
|
2008-11-01 22:16:18 +00:00
|
|
|
Snapshot* snapshots;
|
2008-10-14 00:18:18 +00:00
|
|
|
Link* predecessors;
|
|
|
|
Link* successors;
|
2008-10-15 00:45:31 +00:00
|
|
|
Cell* visitLinks;
|
2008-08-30 20:12:27 +00:00
|
|
|
Block* block;
|
|
|
|
LogicalInstruction* logicalInstruction;
|
2008-05-15 14:29:19 +00:00
|
|
|
unsigned readCount;
|
2008-04-18 17:00:55 +00:00
|
|
|
};
|
|
|
|
|
2009-02-26 03:49:42 +00:00
|
|
|
unsigned
|
2009-04-19 22:36:11 +00:00
|
|
|
totalFrameSize(Context* c)
|
2009-02-26 03:49:42 +00:00
|
|
|
{
|
2009-04-19 22:36:11 +00:00
|
|
|
return c->alignedFrameSize
|
|
|
|
+ c->arch->frameHeaderSize()
|
|
|
|
+ c->arch->argumentFootprint(c->parameterFootprint);
|
2009-02-26 03:49:42 +00:00
|
|
|
}
|
|
|
|
|
2008-05-19 04:31:52 +00:00
|
|
|
int
|
2009-04-19 22:36:11 +00:00
|
|
|
frameIndex(Context* c, int localIndex)
|
2008-05-19 04:31:52 +00:00
|
|
|
{
|
2009-04-19 22:36:11 +00:00
|
|
|
assert(c, localIndex >= 0);
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-04-22 01:39:25 +00:00
|
|
|
int index = c->alignedFrameSize + c->parameterFootprint - localIndex - 1;
|
2009-04-19 22:36:11 +00:00
|
|
|
|
|
|
|
if (localIndex < static_cast<int>(c->parameterFootprint)) {
|
|
|
|
index += c->arch->frameHeaderSize();
|
|
|
|
} else {
|
|
|
|
index -= c->arch->frameFooterSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(c, index >= 0);
|
2009-04-22 01:39:25 +00:00
|
|
|
assert(c, static_cast<unsigned>(index) < totalFrameSize(c));
|
2009-04-19 22:36:11 +00:00
|
|
|
|
|
|
|
return index;
|
2008-05-19 04:31:52 +00:00
|
|
|
}
|
|
|
|
|
2008-10-25 02:12:02 +00:00
|
|
|
unsigned
|
|
|
|
frameIndexToOffset(Context* c, unsigned frameIndex)
|
2008-09-28 21:56:12 +00:00
|
|
|
{
|
2009-04-22 01:39:25 +00:00
|
|
|
assert(c, frameIndex < totalFrameSize(c));
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
return (frameIndex + c->arch->frameFooterSize()) * TargetBytesPerWord;
|
2008-10-25 02:12:02 +00:00
|
|
|
}
|
2008-09-28 21:56:12 +00:00
|
|
|
|
2008-10-25 02:12:02 +00:00
|
|
|
unsigned
|
|
|
|
offsetToFrameIndex(Context* c, unsigned offset)
|
|
|
|
{
|
2009-04-22 01:39:25 +00:00
|
|
|
assert(c, static_cast<int>
|
2011-08-30 01:00:17 +00:00
|
|
|
((offset / TargetBytesPerWord) - c->arch->frameFooterSize()) >= 0);
|
|
|
|
assert(c, ((offset / TargetBytesPerWord) - c->arch->frameFooterSize())
|
2009-04-22 01:39:25 +00:00
|
|
|
< totalFrameSize(c));
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
return (offset / TargetBytesPerWord) - c->arch->frameFooterSize();
|
2008-09-28 21:56:12 +00:00
|
|
|
}
|
|
|
|
|
2009-04-22 01:39:25 +00:00
|
|
|
unsigned
|
|
|
|
frameBase(Context* c)
|
|
|
|
{
|
2009-05-27 01:02:39 +00:00
|
|
|
return c->alignedFrameSize
|
|
|
|
- c->arch->frameReturnAddressSize()
|
2009-04-22 01:39:25 +00:00
|
|
|
- c->arch->frameFooterSize()
|
|
|
|
+ c->arch->frameHeaderSize();
|
|
|
|
}
|
|
|
|
|
2008-11-01 19:14:13 +00:00
|
|
|
class FrameIterator {
|
|
|
|
public:
|
|
|
|
class Element {
|
|
|
|
public:
|
2009-01-25 22:03:38 +00:00
|
|
|
Element(Value* value, unsigned localIndex):
|
|
|
|
value(value), localIndex(localIndex)
|
2008-11-01 19:14:13 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
Value* const value;
|
|
|
|
const unsigned localIndex;
|
|
|
|
};
|
|
|
|
|
2009-10-26 23:59:20 +00:00
|
|
|
FrameIterator(Context* c, Stack* stack, Local* locals,
|
|
|
|
bool includeEmpty = false):
|
|
|
|
stack(stack), locals(locals), localIndex(c->localFootprint - 1),
|
|
|
|
includeEmpty(includeEmpty)
|
2008-11-01 19:14:13 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
bool hasMore() {
|
2009-10-26 23:59:20 +00:00
|
|
|
if (not includeEmpty) {
|
|
|
|
while (stack and stack->value == 0) stack = stack->next;
|
2009-01-30 01:36:19 +00:00
|
|
|
|
2009-10-26 23:59:20 +00:00
|
|
|
while (localIndex >= 0 and locals[localIndex].value == 0) -- localIndex;
|
|
|
|
}
|
2008-11-01 19:14:13 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2009-01-25 22:03:38 +00:00
|
|
|
return Element(v, li);
|
2008-11-01 19:14:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Stack* stack;
|
|
|
|
Local* locals;
|
|
|
|
int localIndex;
|
2009-10-26 23:59:20 +00:00
|
|
|
bool includeEmpty;
|
2008-11-01 19:14:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
frameIndex(Context* c, FrameIterator::Element* element)
|
|
|
|
{
|
2009-01-25 22:03:38 +00:00
|
|
|
return frameIndex(c, element->localIndex);
|
2008-11-01 19:14:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class SiteIterator {
|
|
|
|
public:
|
2009-10-04 19:56:48 +00:00
|
|
|
SiteIterator(Context* c, Value* v, bool includeBuddies = true,
|
2009-10-24 23:18:56 +00:00
|
|
|
bool includeNextWord = true):
|
2009-09-26 19:43:44 +00:00
|
|
|
c(c),
|
2008-11-01 19:14:13 +00:00
|
|
|
originalValue(v),
|
|
|
|
currentValue(v),
|
2008-11-02 20:35:35 +00:00
|
|
|
includeBuddies(includeBuddies),
|
2009-10-24 23:18:56 +00:00
|
|
|
includeNextWord(includeNextWord),
|
2009-09-26 19:43:44 +00:00
|
|
|
pass(0),
|
2008-11-01 19:14:13 +00:00
|
|
|
next_(findNext(&(v->sites))),
|
|
|
|
previous(0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
Site** findNext(Site** p) {
|
2009-09-26 19:43:44 +00:00
|
|
|
while (true) {
|
2009-10-04 19:56:48 +00:00
|
|
|
if (*p) {
|
2011-08-30 01:00:17 +00:00
|
|
|
if (pass == 0 or (*p)->registerSize(c) > TargetBytesPerWord) {
|
2009-10-04 19:56:48 +00:00
|
|
|
return p;
|
|
|
|
} else {
|
|
|
|
p = &((*p)->next);
|
|
|
|
}
|
2009-09-26 19:43:44 +00:00
|
|
|
} else {
|
|
|
|
if (includeBuddies) {
|
|
|
|
Value* v = currentValue->buddy;
|
|
|
|
if (v != originalValue) {
|
2008-11-02 20:35:35 +00:00
|
|
|
currentValue = v;
|
2009-09-26 19:43:44 +00:00
|
|
|
p = &(v->sites);
|
|
|
|
continue;
|
2008-11-02 20:35:35 +00:00
|
|
|
}
|
2008-11-01 19:14:13 +00:00
|
|
|
}
|
2009-09-26 19:43:44 +00:00
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
if (includeNextWord and pass == 0) {
|
2009-10-10 22:07:30 +00:00
|
|
|
Value* v = originalValue->nextWord;
|
2009-09-26 19:43:44 +00:00
|
|
|
if (v != originalValue) {
|
|
|
|
pass = 1;
|
|
|
|
originalValue = v;
|
|
|
|
currentValue = v;
|
|
|
|
p = &(v->sites);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2008-11-01 19:14:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hasMore() {
|
|
|
|
if (previous) {
|
|
|
|
next_ = findNext(&((*previous)->next));
|
|
|
|
previous = 0;
|
|
|
|
}
|
|
|
|
return next_ != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Site* next() {
|
|
|
|
previous = next_;
|
|
|
|
return *previous;
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove(Context* c) {
|
2009-01-25 22:03:38 +00:00
|
|
|
(*previous)->release(c, originalValue);
|
2008-11-01 19:14:13 +00:00
|
|
|
*previous = (*previous)->next;
|
|
|
|
next_ = findNext(previous);
|
|
|
|
previous = 0;
|
|
|
|
}
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
Context* c;
|
2008-11-01 19:14:13 +00:00
|
|
|
Value* originalValue;
|
|
|
|
Value* currentValue;
|
2008-11-02 20:35:35 +00:00
|
|
|
bool includeBuddies;
|
2009-10-24 23:18:56 +00:00
|
|
|
bool includeNextWord;
|
2009-09-26 19:43:44 +00:00
|
|
|
uint8_t pass;
|
2008-11-01 19:14:13 +00:00
|
|
|
Site** next_;
|
|
|
|
Site** previous;
|
|
|
|
};
|
|
|
|
|
2008-11-01 22:16:18 +00:00
|
|
|
bool
|
2009-09-26 19:43:44 +00:00
|
|
|
hasSite(Context* c, Value* v)
|
2008-11-01 22:16:18 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
SiteIterator it(c, v);
|
2008-11-01 22:16:18 +00:00
|
|
|
return it.hasMore();
|
|
|
|
}
|
|
|
|
|
2008-04-18 00:39:41 +00:00
|
|
|
bool
|
|
|
|
findSite(Context*, Value* v, Site* site)
|
|
|
|
{
|
|
|
|
for (Site* s = v->sites; s; s = s->next) {
|
|
|
|
if (s == site) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
bool
|
|
|
|
uniqueSite(Context* c, Value* v, Site* s)
|
|
|
|
{
|
|
|
|
SiteIterator it(c, v);
|
2009-10-10 23:46:43 +00:00
|
|
|
Site* p UNUSED = it.next();
|
2009-10-10 22:07:30 +00:00
|
|
|
if (it.hasMore()) {
|
|
|
|
// the site is not this word's only site, but if the site is
|
|
|
|
// shared with the next word, it may be that word's only site
|
2011-08-30 01:00:17 +00:00
|
|
|
if (v->nextWord != v and s->registerSize(c) > TargetBytesPerWord) {
|
2009-10-10 22:07:30 +00:00
|
|
|
SiteIterator nit(c, v->nextWord);
|
|
|
|
Site* p = nit.next();
|
|
|
|
if (nit.hasMore()) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return p == s;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(c, p == s);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-12 13:54:47 +00:00
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
addSite(Context* c, Value* v, Site* s)
|
2008-04-19 00:19:45 +00:00
|
|
|
{
|
|
|
|
if (not findSite(c, v, s)) {
|
2008-12-12 01:09:36 +00:00
|
|
|
if (DebugSites) {
|
|
|
|
char buffer[256]; s->toString(c, buffer, 256);
|
|
|
|
fprintf(stderr, "add site %s to %p\n", buffer, v);
|
|
|
|
}
|
2009-01-25 22:03:38 +00:00
|
|
|
s->acquire(c, v);
|
2008-05-12 13:54:47 +00:00
|
|
|
s->next = v->sites;
|
|
|
|
v->sites = s;
|
2008-04-19 00:19:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-18 00:39:41 +00:00
|
|
|
void
|
2008-04-19 07:03:59 +00:00
|
|
|
removeSite(Context* c, Value* v, Site* s)
|
2008-04-18 00:39:41 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
for (SiteIterator it(c, v); it.hasMore();) {
|
2008-11-01 19:14:13 +00:00
|
|
|
if (s == it.next()) {
|
2008-12-12 01:09:36 +00:00
|
|
|
if (DebugSites) {
|
|
|
|
char buffer[256]; s->toString(c, buffer, 256);
|
|
|
|
fprintf(stderr, "remove site %s from %p\n", buffer, v);
|
|
|
|
}
|
2008-11-01 19:14:13 +00:00
|
|
|
it.remove(c);
|
2008-04-30 15:44:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-12-12 01:09:36 +00:00
|
|
|
if (DebugSites) {
|
2009-09-26 19:43:44 +00:00
|
|
|
fprintf(stderr, "%p has more: %d\n", v, hasSite(c, v));
|
2008-12-12 01:09:36 +00:00
|
|
|
}
|
|
|
|
assert(c, not findSite(c, v, s));
|
2008-04-30 15:44:17 +00:00
|
|
|
}
|
|
|
|
|
2008-04-19 07:03:59 +00:00
|
|
|
void
|
|
|
|
clearSites(Context* c, Value* v)
|
|
|
|
{
|
2008-12-12 01:09:36 +00:00
|
|
|
if (DebugSites) {
|
|
|
|
fprintf(stderr, "clear sites for %p\n", v);
|
|
|
|
}
|
2009-09-26 19:43:44 +00:00
|
|
|
for (SiteIterator it(c, v); it.hasMore();) {
|
2008-11-01 22:16:18 +00:00
|
|
|
it.next();
|
|
|
|
it.remove(c);
|
2008-04-19 07:03:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-05 20:21:13 +00:00
|
|
|
bool
|
|
|
|
valid(Read* r)
|
|
|
|
{
|
|
|
|
return r and r->valid();
|
|
|
|
}
|
|
|
|
|
2012-06-02 15:06:22 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
|
|
|
bool
|
|
|
|
hasBuddy(Context* c, Value* a, Value* b)
|
|
|
|
{
|
|
|
|
if (a == b) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
for (Value* p = a->buddy; p != a; p = p->buddy) {
|
|
|
|
if (p == b) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (++i > 1000) {
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // not NDEBUG
|
|
|
|
|
2008-11-01 22:16:18 +00:00
|
|
|
Read*
|
2010-11-26 19:36:43 +00:00
|
|
|
live(Context* c UNUSED, Value* v)
|
2008-07-05 20:21:13 +00:00
|
|
|
{
|
2010-11-26 19:36:43 +00:00
|
|
|
assert(c, hasBuddy(c, v->buddy, v));
|
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
Value* p = v;
|
|
|
|
do {
|
|
|
|
if (valid(p->reads)) {
|
|
|
|
return p->reads;
|
|
|
|
}
|
|
|
|
p = p->buddy;
|
|
|
|
} while (p != v);
|
2008-11-01 19:14:13 +00:00
|
|
|
|
2008-11-01 22:16:18 +00:00
|
|
|
return 0;
|
2008-11-01 19:14:13 +00:00
|
|
|
}
|
|
|
|
|
2008-11-01 22:16:18 +00:00
|
|
|
Read*
|
2008-11-01 19:14:13 +00:00
|
|
|
liveNext(Context* c, Value* v)
|
|
|
|
{
|
2010-11-26 19:36:43 +00:00
|
|
|
assert(c, hasBuddy(c, v->buddy, v));
|
|
|
|
|
2008-11-01 22:16:18 +00:00
|
|
|
Read* r = v->reads->next(c);
|
|
|
|
if (valid(r)) return r;
|
2008-11-01 19:14:13 +00:00
|
|
|
|
|
|
|
for (Value* p = v->buddy; p != v; p = p->buddy) {
|
2008-11-01 22:16:18 +00:00
|
|
|
if (valid(p->reads)) return p->reads;
|
2008-11-01 19:14:13 +00:00
|
|
|
}
|
|
|
|
|
2008-11-01 22:16:18 +00:00
|
|
|
return 0;
|
2008-07-05 20:21:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
unsigned
|
|
|
|
sitesToString(Context* c, Value* v, char* buffer, unsigned size);
|
|
|
|
|
|
|
|
void
|
|
|
|
deadWord(Context* c, Value* v)
|
|
|
|
{
|
|
|
|
Value* nextWord = v->nextWord;
|
|
|
|
assert(c, nextWord != v);
|
|
|
|
|
2009-11-03 21:14:27 +00:00
|
|
|
for (SiteIterator it(c, v, true, false); it.hasMore();) {
|
2009-10-24 23:18:56 +00:00
|
|
|
Site* s = it.next();
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (s->registerSize(c) > TargetBytesPerWord) {
|
2009-10-24 23:18:56 +00:00
|
|
|
it.remove(c);
|
|
|
|
addSite(c, nextWord, s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
void
|
2009-02-08 20:21:35 +00:00
|
|
|
deadBuddy(Context* c, Value* v, Read* r UNUSED)
|
2009-01-11 22:53:51 +00:00
|
|
|
{
|
|
|
|
assert(c, v->buddy != v);
|
|
|
|
assert(c, r);
|
|
|
|
|
|
|
|
if (DebugBuddies) {
|
2009-01-11 23:24:25 +00:00
|
|
|
fprintf(stderr, "remove dead buddy %p from", v);
|
2009-01-11 22:53:51 +00:00
|
|
|
for (Value* p = v->buddy; p != v; p = p->buddy) {
|
|
|
|
fprintf(stderr, " %p", p);
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
assert(c, v->buddy);
|
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
Value* next = v->buddy;
|
|
|
|
v->buddy = v;
|
|
|
|
Value* p = next;
|
|
|
|
while (p->buddy != v) p = p->buddy;
|
|
|
|
p->buddy = next;
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
assert(c, p->buddy);
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
for (SiteIterator it(c, v, false, false); it.hasMore();) {
|
2009-01-11 22:53:51 +00:00
|
|
|
Site* s = it.next();
|
|
|
|
it.remove(c);
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
addSite(c, next, s);
|
2009-01-11 22:53:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-19 00:19:45 +00:00
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
popRead(Context* c, Event* e UNUSED, Value* v)
|
2008-04-19 00:19:45 +00:00
|
|
|
{
|
2008-09-25 00:48:32 +00:00
|
|
|
assert(c, e == v->reads->event);
|
|
|
|
|
2008-12-12 01:09:36 +00:00
|
|
|
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));
|
|
|
|
}
|
2008-04-19 07:03:59 +00:00
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
v->reads = v->reads->next(c);
|
2009-01-11 22:53:51 +00:00
|
|
|
|
|
|
|
if (not valid(v->reads)) {
|
2009-10-24 23:18:56 +00:00
|
|
|
Value* nextWord = v->nextWord;
|
|
|
|
if (nextWord != v) {
|
|
|
|
if (valid(nextWord->reads)) {
|
|
|
|
deadWord(c, v);
|
|
|
|
} else {
|
|
|
|
deadWord(c, nextWord);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-26 19:36:43 +00:00
|
|
|
Read* r = live(c, v);
|
2009-01-11 22:53:51 +00:00
|
|
|
if (r) {
|
|
|
|
deadBuddy(c, v, r);
|
|
|
|
} else {
|
|
|
|
clearSites(c, v);
|
|
|
|
}
|
2008-04-19 00:19:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
void
|
2009-09-26 19:43:44 +00:00
|
|
|
decrementAvailableGeneralRegisterCount(Context* c)
|
2009-02-08 23:20:28 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
assert(c, c->availableGeneralRegisterCount);
|
|
|
|
-- c->availableGeneralRegisterCount;
|
2009-08-06 16:14:31 +00:00
|
|
|
|
2009-02-08 23:20:28 +00:00
|
|
|
if (DebugResources) {
|
2009-09-26 19:43:44 +00:00
|
|
|
fprintf(stderr, "%d registers available\n",
|
|
|
|
c->availableGeneralRegisterCount);
|
2009-02-08 23:20:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-09-26 19:43:44 +00:00
|
|
|
incrementAvailableGeneralRegisterCount(Context* c)
|
2009-02-08 23:20:28 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
++ c->availableGeneralRegisterCount;
|
2009-02-08 23:20:28 +00:00
|
|
|
|
|
|
|
if (DebugResources) {
|
2009-09-26 19:43:44 +00:00
|
|
|
fprintf(stderr, "%d registers available\n",
|
|
|
|
c->availableGeneralRegisterCount);
|
2009-02-08 23:20:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
increment(Context* c, RegisterResource* r)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-01-04 01:17:51 +00:00
|
|
|
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);
|
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
++ r->referenceCount;
|
2009-02-08 23:20:28 +00:00
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
if (r->referenceCount == 1
|
|
|
|
and ((1 << r->index(c)) & c->arch->generalRegisterMask()))
|
|
|
|
{
|
|
|
|
decrementAvailableGeneralRegisterCount(c);
|
2009-02-08 23:20:28 +00:00
|
|
|
}
|
2009-01-04 01:17:51 +00:00
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-09-26 19:43:44 +00:00
|
|
|
decrement(Context* c, RegisterResource* r)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-01-04 01:17:51 +00:00
|
|
|
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);
|
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
assert(c, r->referenceCount > 0);
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
-- r->referenceCount;
|
2009-02-08 23:20:28 +00:00
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
if (r->referenceCount == 0
|
|
|
|
and ((1 << r->index(c)) & c->arch->generalRegisterMask()))
|
|
|
|
{
|
|
|
|
incrementAvailableGeneralRegisterCount(c);
|
2009-02-08 23:20:28 +00:00
|
|
|
}
|
2009-01-04 01:17:51 +00:00
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-01-11 18:48:02 +00:00
|
|
|
freezeResource(Context* c, Resource* r, Value* v)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-01-11 18:48:02 +00:00
|
|
|
if (DebugResources) {
|
|
|
|
char buffer[256]; r->toString(c, buffer, 256);
|
|
|
|
fprintf(stderr, "%p freeze %s to %d\n", v, buffer, r->freezeCount + 1);
|
|
|
|
}
|
2009-01-04 01:17:51 +00:00
|
|
|
|
2009-01-11 18:48:02 +00:00
|
|
|
++ r->freezeCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RegisterResource::freeze(Context* c, Value* v)
|
|
|
|
{
|
|
|
|
if (not reserved) {
|
|
|
|
freezeResource(c, this, v);
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
if (freezeCount == 1
|
|
|
|
and ((1 << index(c)) & c->arch->generalRegisterMask()))
|
|
|
|
{
|
|
|
|
decrementAvailableGeneralRegisterCount(c);
|
2009-01-11 18:48:02 +00:00
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-01-11 18:48:02 +00:00
|
|
|
FrameResource::freeze(Context* c, Value* v)
|
|
|
|
{
|
|
|
|
freezeResource(c, this, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
thawResource(Context* c, Resource* r, Value* v)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-01-04 01:17:51 +00:00
|
|
|
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);
|
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
assert(c, r->freezeCount);
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
-- r->freezeCount;
|
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-11 18:48:02 +00:00
|
|
|
void
|
|
|
|
RegisterResource::thaw(Context* c, Value* v)
|
|
|
|
{
|
|
|
|
if (not reserved) {
|
|
|
|
thawResource(c, this, v);
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
if (freezeCount == 0
|
|
|
|
and ((1 << index(c)) & c->arch->generalRegisterMask()))
|
|
|
|
{
|
|
|
|
incrementAvailableGeneralRegisterCount(c);
|
2009-01-11 18:48:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FrameResource::thaw(Context* c, Value* v)
|
|
|
|
{
|
|
|
|
thawResource(c, this, v);
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
class Target {
|
|
|
|
public:
|
2009-04-26 18:19:16 +00:00
|
|
|
static const unsigned MinimumRegisterCost = 0;
|
|
|
|
static const unsigned MinimumFrameCost = 1;
|
|
|
|
static const unsigned StealPenalty = 2;
|
|
|
|
static const unsigned StealUniquePenalty = 4;
|
2009-11-28 18:17:17 +00:00
|
|
|
static const unsigned IndirectMovePenalty = 4;
|
2009-04-26 18:19:16 +00:00
|
|
|
static const unsigned LowRegisterPenalty = 10;
|
2009-02-08 20:21:35 +00:00
|
|
|
static const unsigned Impossible = 20;
|
2009-01-03 21:34:45 +00:00
|
|
|
|
|
|
|
Target(): cost(Impossible) { }
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
Target(int index, OperandType type, unsigned cost):
|
|
|
|
index(index), type(type), cost(cost)
|
2009-01-03 21:34:45 +00:00
|
|
|
{ }
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
int16_t index;
|
|
|
|
OperandType type;
|
2009-01-03 21:34:45 +00:00
|
|
|
uint8_t cost;
|
|
|
|
};
|
|
|
|
|
2009-08-10 19:20:23 +00:00
|
|
|
ValueType
|
2009-09-20 21:43:32 +00:00
|
|
|
valueType(Context* c, Compiler::OperandType type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case Compiler::ObjectType:
|
|
|
|
case Compiler::AddressType:
|
|
|
|
case Compiler::IntegerType:
|
|
|
|
case Compiler::VoidType:
|
2009-08-10 19:20:23 +00:00
|
|
|
return ValueGeneral;
|
2009-09-20 21:43:32 +00:00
|
|
|
case Compiler::FloatType:
|
2009-08-10 19:20:23 +00:00
|
|
|
return ValueFloat;
|
|
|
|
default:
|
2009-09-20 21:43:32 +00:00
|
|
|
abort(c);
|
2009-08-10 19:20:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-28 18:17:17 +00:00
|
|
|
class CostCalculator {
|
|
|
|
public:
|
|
|
|
virtual unsigned cost(Context* c, uint8_t typeMask, uint32_t registerMask,
|
|
|
|
int frameIndex) = 0;
|
|
|
|
};
|
2009-01-03 21:34:45 +00:00
|
|
|
|
|
|
|
unsigned
|
2009-11-28 18:17:17 +00:00
|
|
|
resourceCost(Context* c, Value* v, Resource* r, uint8_t typeMask,
|
|
|
|
uint32_t registerMask, int frameIndex,
|
|
|
|
CostCalculator* costCalculator)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
|
|
|
if (r->reserved or r->freezeCount or r->referenceCount) {
|
|
|
|
return Target::Impossible;
|
2009-11-28 18:17:17 +00:00
|
|
|
} else {
|
|
|
|
unsigned baseCost = costCalculator ? costCalculator->cost
|
|
|
|
(c, typeMask, registerMask, frameIndex) : 0;
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-11-28 18:17:17 +00:00
|
|
|
if (r->value) {
|
|
|
|
assert(c, findSite(c, r->value, r->site));
|
|
|
|
|
|
|
|
if (v and buddies(r->value, v)) {
|
|
|
|
return baseCost;
|
|
|
|
} else if (uniqueSite(c, r->value, r->site)) {
|
|
|
|
return baseCost + Target::StealUniquePenalty;
|
|
|
|
} else {
|
|
|
|
return baseCost = Target::StealPenalty;
|
|
|
|
}
|
2009-10-10 22:07:30 +00:00
|
|
|
} else {
|
2009-11-28 18:17:17 +00:00
|
|
|
return baseCost;
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
bool
|
|
|
|
pickRegisterTarget(Context* c, int i, Value* v, uint32_t mask, int* target,
|
2009-11-28 18:17:17 +00:00
|
|
|
unsigned* cost, CostCalculator* costCalculator = 0)
|
2009-09-26 19:43:44 +00:00
|
|
|
{
|
|
|
|
if ((1 << i) & mask) {
|
|
|
|
RegisterResource* r = c->registerResources + i;
|
2009-11-28 18:17:17 +00:00
|
|
|
unsigned myCost = resourceCost
|
|
|
|
(c, v, r, 1 << RegisterOperand, 1 << i, NoFrameIndex, costCalculator)
|
|
|
|
+ Target::MinimumRegisterCost;
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
if ((static_cast<uint32_t>(1) << i) == mask) {
|
|
|
|
*cost = myCost;
|
|
|
|
return true;
|
|
|
|
} else if (myCost < *cost) {
|
|
|
|
*cost = myCost;
|
|
|
|
*target = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
int
|
2009-11-28 18:17:17 +00:00
|
|
|
pickRegisterTarget(Context* c, Value* v, uint32_t mask, unsigned* cost,
|
|
|
|
CostCalculator* costCalculator = 0)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
|
|
|
int target = NoRegister;
|
2009-09-26 19:43:44 +00:00
|
|
|
*cost = Target::Impossible;
|
|
|
|
|
|
|
|
if (mask & c->arch->generalRegisterMask()) {
|
|
|
|
for (int i = c->generalRegisterLimit - 1;
|
|
|
|
i >= c->generalRegisterStart; --i)
|
|
|
|
{
|
2009-11-28 18:17:17 +00:00
|
|
|
if (pickRegisterTarget(c, i, v, mask, &target, cost, costCalculator)) {
|
2009-09-26 19:43:44 +00:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mask & c->arch->floatRegisterMask()) {
|
|
|
|
for (int i = c->floatRegisterStart;
|
|
|
|
i < static_cast<int>(c->floatRegisterLimit); ++i)
|
|
|
|
{
|
2009-11-28 18:17:17 +00:00
|
|
|
if (pickRegisterTarget(c, i, v, mask, &target, cost, costCalculator)) {
|
2009-01-03 21:34:45 +00:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
|
|
|
Target
|
2009-11-28 18:17:17 +00:00
|
|
|
pickRegisterTarget(Context* c, Value* v, uint32_t mask,
|
|
|
|
CostCalculator* costCalculator = 0)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-01-25 22:03:38 +00:00
|
|
|
unsigned cost;
|
2009-11-28 18:17:17 +00:00
|
|
|
int number = pickRegisterTarget(c, v, mask, &cost, costCalculator);
|
2009-01-25 22:03:38 +00:00
|
|
|
return Target(number, RegisterOperand, cost);
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
2009-11-28 18:17:17 +00:00
|
|
|
frameCost(Context* c, Value* v, int frameIndex, CostCalculator* costCalculator)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-11-28 18:17:17 +00:00
|
|
|
return resourceCost
|
|
|
|
(c, v, c->frameResources + frameIndex, 1 << MemoryOperand, 0, frameIndex,
|
|
|
|
costCalculator)
|
2009-04-26 18:19:16 +00:00
|
|
|
+ Target::MinimumFrameCost;
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Target
|
2009-11-28 18:17:17 +00:00
|
|
|
pickFrameTarget(Context* c, Value* v, CostCalculator* costCalculator)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
|
|
|
Target best;
|
|
|
|
|
|
|
|
Value* p = v;
|
|
|
|
do {
|
|
|
|
if (p->home >= 0) {
|
2009-11-28 18:17:17 +00:00
|
|
|
Target mine
|
|
|
|
(p->home, MemoryOperand, frameCost(c, v, p->home, costCalculator));
|
|
|
|
|
2009-04-26 18:19:16 +00:00
|
|
|
if (mine.cost == Target::MinimumFrameCost) {
|
2009-01-03 21:34:45 +00:00
|
|
|
return mine;
|
|
|
|
} else if (mine.cost < best.cost) {
|
|
|
|
best = mine;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p = p->buddy;
|
|
|
|
} while (p != v);
|
|
|
|
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
2009-03-17 02:03:59 +00:00
|
|
|
Target
|
2009-11-28 18:17:17 +00:00
|
|
|
pickAnyFrameTarget(Context* c, Value* v, CostCalculator* costCalculator)
|
2009-03-17 02:03:59 +00:00
|
|
|
{
|
|
|
|
Target best;
|
|
|
|
|
2009-04-19 22:36:11 +00:00
|
|
|
unsigned count = totalFrameSize(c);
|
2009-03-17 02:03:59 +00:00
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
2009-11-28 18:17:17 +00:00
|
|
|
Target mine(i, MemoryOperand, frameCost(c, v, i, costCalculator));
|
2009-04-26 18:19:16 +00:00
|
|
|
if (mine.cost == Target::MinimumFrameCost) {
|
2009-03-17 02:03:59 +00:00
|
|
|
return mine;
|
|
|
|
} else if (mine.cost < best.cost) {
|
|
|
|
best = mine;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
Target
|
2009-04-08 00:55:43 +00:00
|
|
|
pickTarget(Context* c, Value* value, const SiteMask& mask,
|
2009-11-28 18:17:17 +00:00
|
|
|
unsigned registerPenalty, Target best,
|
|
|
|
CostCalculator* costCalculator)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-04-05 21:42:10 +00:00
|
|
|
if (mask.typeMask & (1 << RegisterOperand)) {
|
2009-11-28 18:17:17 +00:00
|
|
|
Target mine = pickRegisterTarget
|
|
|
|
(c, value, mask.registerMask, costCalculator);
|
2009-02-08 20:21:35 +00:00
|
|
|
|
|
|
|
mine.cost += registerPenalty;
|
2009-04-26 18:19:16 +00:00
|
|
|
if (mine.cost == Target::MinimumRegisterCost) {
|
2009-01-03 21:34:45 +00:00
|
|
|
return mine;
|
|
|
|
} else if (mine.cost < best.cost) {
|
|
|
|
best = mine;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
if (mask.typeMask & (1 << MemoryOperand)) {
|
|
|
|
if (mask.frameIndex >= 0) {
|
|
|
|
Target mine(mask.frameIndex, MemoryOperand,
|
2009-11-28 18:17:17 +00:00
|
|
|
frameCost(c, value, mask.frameIndex, costCalculator));
|
2009-10-04 19:56:48 +00:00
|
|
|
if (mine.cost == Target::MinimumFrameCost) {
|
|
|
|
return mine;
|
|
|
|
} else if (mine.cost < best.cost) {
|
|
|
|
best = mine;
|
|
|
|
}
|
|
|
|
} else if (mask.frameIndex == AnyFrameIndex) {
|
2009-11-28 18:17:17 +00:00
|
|
|
Target mine = pickFrameTarget(c, value, costCalculator);
|
2009-10-04 19:56:48 +00:00
|
|
|
if (mine.cost == Target::MinimumFrameCost) {
|
|
|
|
return mine;
|
|
|
|
} else if (mine.cost < best.cost) {
|
|
|
|
best = mine;
|
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-08 00:55:43 +00:00
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
|
|
|
Target
|
|
|
|
pickTarget(Context* c, Read* read, bool intersectRead,
|
2009-11-28 18:17:17 +00:00
|
|
|
unsigned registerReserveCount, CostCalculator* costCalculator)
|
2009-04-08 00:55:43 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
unsigned registerPenalty
|
|
|
|
= (c->availableGeneralRegisterCount > registerReserveCount
|
|
|
|
? 0 : Target::LowRegisterPenalty);
|
2009-04-08 00:55:43 +00:00
|
|
|
|
2009-10-04 22:10:36 +00:00
|
|
|
Value* value = read->value;
|
|
|
|
|
2009-11-30 22:08:59 +00:00
|
|
|
uint32_t registerMask
|
|
|
|
= (value->type == ValueFloat ? ~0 : c->arch->generalRegisterMask());
|
2009-10-04 22:10:36 +00:00
|
|
|
|
|
|
|
SiteMask mask(~0, registerMask, AnyFrameIndex);
|
2009-04-08 00:55:43 +00:00
|
|
|
read->intersect(&mask);
|
|
|
|
|
2009-11-30 22:08:59 +00:00
|
|
|
if (value->type == ValueFloat) {
|
|
|
|
uint32_t floatMask = mask.registerMask & c->arch->floatRegisterMask();
|
|
|
|
if (floatMask) {
|
|
|
|
mask.registerMask = floatMask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-08 00:55:43 +00:00
|
|
|
Target best;
|
|
|
|
|
|
|
|
Value* successor = read->successor();
|
|
|
|
if (successor) {
|
2010-11-26 19:36:43 +00:00
|
|
|
Read* r = live(c, successor);
|
2009-04-08 00:55:43 +00:00
|
|
|
if (r) {
|
|
|
|
SiteMask intersection = mask;
|
|
|
|
if (r->intersect(&intersection)) {
|
2009-11-28 18:17:17 +00:00
|
|
|
best = pickTarget
|
|
|
|
(c, value, intersection, registerPenalty, best, costCalculator);
|
|
|
|
|
2009-04-26 18:19:16 +00:00
|
|
|
if (best.cost <= Target::MinimumFrameCost) {
|
2009-04-08 00:55:43 +00:00
|
|
|
return best;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-05-27 01:02:39 +00:00
|
|
|
|
2009-11-28 18:17:17 +00:00
|
|
|
best = pickTarget(c, value, mask, registerPenalty, best, costCalculator);
|
2009-04-26 18:19:16 +00:00
|
|
|
if (best.cost <= Target::MinimumFrameCost) {
|
2009-04-08 00:55:43 +00:00
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
2009-02-14 20:26:39 +00:00
|
|
|
if (intersectRead) {
|
2009-09-26 19:43:44 +00:00
|
|
|
if (best.cost == Target::Impossible) {
|
|
|
|
fprintf(stderr, "mask type %d reg %d frame %d\n",
|
|
|
|
mask.typeMask, mask.registerMask, mask.frameIndex);
|
2009-10-19 16:31:34 +00:00
|
|
|
abort(c);
|
2009-09-26 19:43:44 +00:00
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
2009-11-28 18:17:17 +00:00
|
|
|
{ Target mine = pickRegisterTarget(c, value, registerMask, costCalculator);
|
2009-02-08 20:21:35 +00:00
|
|
|
|
|
|
|
mine.cost += registerPenalty;
|
|
|
|
|
2009-04-26 18:19:16 +00:00
|
|
|
if (mine.cost == Target::MinimumRegisterCost) {
|
2009-01-03 21:34:45 +00:00
|
|
|
return mine;
|
|
|
|
} else if (mine.cost < best.cost) {
|
|
|
|
best = mine;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-28 18:17:17 +00:00
|
|
|
{ Target mine = pickFrameTarget(c, value, costCalculator);
|
2009-04-26 18:19:16 +00:00
|
|
|
if (mine.cost == Target::MinimumFrameCost) {
|
2009-01-03 21:34:45 +00:00
|
|
|
return mine;
|
|
|
|
} else if (mine.cost < best.cost) {
|
|
|
|
best = mine;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-26 18:19:16 +00:00
|
|
|
if (best.cost >= Target::StealUniquePenalty
|
2009-09-26 19:43:44 +00:00
|
|
|
and c->availableGeneralRegisterCount == 0)
|
2009-04-26 18:19:16 +00:00
|
|
|
{
|
2009-03-17 02:03:59 +00:00
|
|
|
// there are no free registers left, so moving from memory to
|
|
|
|
// memory isn't an option - try harder to find an available frame
|
|
|
|
// site:
|
2009-11-28 18:17:17 +00:00
|
|
|
best = pickAnyFrameTarget(c, value, costCalculator);
|
2009-03-17 02:03:59 +00:00
|
|
|
assert(c, best.cost <= 3);
|
|
|
|
}
|
|
|
|
|
2009-10-19 16:31:34 +00:00
|
|
|
if (best.cost == Target::Impossible) {
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
acquire(Context* c, Resource* resource, Value* value, Site* site);
|
2009-01-03 21:34:45 +00:00
|
|
|
|
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
release(Context* c, Resource* resource, Value* value, Site* site);
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
ConstantSite*
|
|
|
|
constantSite(Context* c, Promise* value);
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
ShiftMaskPromise*
|
|
|
|
shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) ShiftMaskPromise(base, shift, mask);
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CombinedPromise*
|
|
|
|
combinedPromise(Context* c, Promise* low, Promise* high)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) CombinedPromise(low, high);
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
class ConstantSite: public Site {
|
|
|
|
public:
|
|
|
|
ConstantSite(Promise* value): value(value) { }
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) {
|
2009-01-25 22:03:38 +00:00
|
|
|
if (value->resolved()) {
|
2009-08-27 00:26:44 +00:00
|
|
|
return vm::snprintf
|
2012-06-01 23:57:42 +00:00
|
|
|
(buffer, bufferSize, "constant %" LLD, value->value());
|
2008-10-04 17:26:35 +00:00
|
|
|
} else {
|
2009-08-27 00:26:44 +00:00
|
|
|
return vm::snprintf(buffer, bufferSize, "constant unresolved");
|
2008-10-04 17:26:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-18 18:36:57 +00:00
|
|
|
virtual unsigned copyCost(Context*, Site* s) {
|
2009-11-28 18:17:17 +00:00
|
|
|
return (s == this ? 0 : ConstantCopyCost);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual bool match(Context*, const SiteMask& mask) {
|
|
|
|
return mask.typeMask & (1 << ConstantOperand);
|
2008-08-23 18:04:36 +00:00
|
|
|
}
|
|
|
|
|
2009-08-11 19:46:51 +00:00
|
|
|
virtual bool loneMatch(Context*, const SiteMask&) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual bool matchNextWord(Context* c, Site* s, unsigned) {
|
2009-10-04 19:56:48 +00:00
|
|
|
return s->type(c) == ConstantOperand;
|
|
|
|
}
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
virtual OperandType type(Context*) {
|
2008-04-17 22:07:32 +00:00
|
|
|
return ConstantOperand;
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
virtual void asAssemblerOperand(Context* c, Site* high,
|
|
|
|
Assembler::Operand* result)
|
|
|
|
{
|
|
|
|
Promise* v = value;
|
2009-09-26 19:43:44 +00:00
|
|
|
if (high != this) {
|
2009-02-01 23:10:56 +00:00
|
|
|
v = combinedPromise(c, value, static_cast<ConstantSite*>(high)->value);
|
|
|
|
}
|
|
|
|
new (result) Assembler::Constant(v);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
virtual Site* copy(Context* c) {
|
2009-01-25 22:03:38 +00:00
|
|
|
return constantSite(c, value);
|
2008-10-12 00:23:08 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual Site* makeNextWord(Context* c, unsigned) {
|
2009-10-04 19:56:48 +00:00
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
virtual SiteMask mask(Context*) {
|
|
|
|
return SiteMask(1 << ConstantOperand, 0, NoFrameIndex);
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual SiteMask nextWordMask(Context*, unsigned) {
|
|
|
|
return SiteMask(1 << ConstantOperand, 0, NoFrameIndex);
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
Promise* value;
|
2008-04-16 20:58:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ConstantSite*
|
|
|
|
constantSite(Context* c, Promise* value)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) ConstantSite(value);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ResolvedPromise*
|
|
|
|
resolved(Context* c, int64_t value)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) ResolvedPromise(value);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ConstantSite*
|
|
|
|
constantSite(Context* c, int64_t value)
|
|
|
|
{
|
|
|
|
return constantSite(c, resolved(c, value));
|
|
|
|
}
|
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
AddressSite*
|
|
|
|
addressSite(Context* c, Promise* address);
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
class AddressSite: public Site {
|
|
|
|
public:
|
|
|
|
AddressSite(Promise* address): address(address) { }
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) {
|
2009-01-25 22:03:38 +00:00
|
|
|
if (address->resolved()) {
|
2009-08-27 00:26:44 +00:00
|
|
|
return vm::snprintf
|
2012-06-01 23:57:42 +00:00
|
|
|
(buffer, bufferSize, "address %" LLD, address->value());
|
2008-10-04 17:26:35 +00:00
|
|
|
} else {
|
2009-08-27 00:26:44 +00:00
|
|
|
return vm::snprintf(buffer, bufferSize, "address unresolved");
|
2008-10-04 17:26:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-18 18:36:57 +00:00
|
|
|
virtual unsigned copyCost(Context*, Site* s) {
|
2009-11-28 18:17:17 +00:00
|
|
|
return (s == this ? 0 : AddressCopyCost);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual bool match(Context*, const SiteMask& mask) {
|
|
|
|
return mask.typeMask & (1 << AddressOperand);
|
2008-08-23 18:04:36 +00:00
|
|
|
}
|
|
|
|
|
2009-08-11 19:46:51 +00:00
|
|
|
virtual bool loneMatch(Context*, const SiteMask&) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual bool matchNextWord(Context* c, Site*, unsigned) {
|
2009-10-04 19:56:48 +00:00
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
virtual OperandType type(Context*) {
|
2008-04-17 22:07:32 +00:00
|
|
|
return AddressOperand;
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
virtual void asAssemblerOperand(Context* c UNUSED, Site* high UNUSED,
|
|
|
|
Assembler::Operand* result)
|
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
assert(c, high == this);
|
2009-02-01 23:10:56 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
new (result) Assembler::Address(address);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
virtual Site* copy(Context* c) {
|
2009-01-25 22:03:38 +00:00
|
|
|
return addressSite(c, address);
|
2008-10-12 00:23:08 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
virtual Site* copyLow(Context* c) {
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Site* copyHigh(Context* c) {
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual Site* makeNextWord(Context* c, unsigned) {
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
virtual SiteMask mask(Context*) {
|
|
|
|
return SiteMask(1 << AddressOperand, 0, NoFrameIndex);
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual SiteMask nextWordMask(Context* c, unsigned) {
|
2009-10-04 19:56:48 +00:00
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
Promise* address;
|
2008-04-16 20:58:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
AddressSite*
|
|
|
|
addressSite(Context* c, Promise* address)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) AddressSite(address);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
RegisterSite*
|
2009-10-04 19:56:48 +00:00
|
|
|
freeRegisterSite(Context* c, uint32_t mask);
|
2008-10-12 00:23:08 +00:00
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
class RegisterSite: public Site {
|
|
|
|
public:
|
2009-01-25 22:03:38 +00:00
|
|
|
RegisterSite(uint32_t mask, int number):
|
2009-11-28 04:15:12 +00:00
|
|
|
mask_(mask), number(number)
|
2008-05-12 13:54:47 +00:00
|
|
|
{ }
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) {
|
|
|
|
if (number != NoRegister) {
|
2009-08-27 00:26:44 +00:00
|
|
|
return vm::snprintf(buffer, bufferSize, "%p register %d", this, number);
|
2008-10-04 17:26:35 +00:00
|
|
|
} else {
|
2009-10-26 23:59:20 +00:00
|
|
|
return vm::snprintf(buffer, bufferSize,
|
2009-11-28 04:15:12 +00:00
|
|
|
"%p register unacquired (mask %d)", this, mask_);
|
2008-10-04 17:26:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
virtual unsigned copyCost(Context* c, Site* s) {
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(c, number != NoRegister);
|
2008-05-12 13:54:47 +00:00
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
if (s and
|
|
|
|
(this == s or
|
2008-04-17 22:07:32 +00:00
|
|
|
(s->type(c) == RegisterOperand
|
2009-11-28 04:15:12 +00:00
|
|
|
and (static_cast<RegisterSite*>(s)->mask_ & (1 << number)))))
|
2008-04-16 20:58:21 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
} else {
|
2009-11-28 18:17:17 +00:00
|
|
|
return RegisterCopyCost;
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-08 20:21:35 +00:00
|
|
|
virtual bool match(Context* c UNUSED, const SiteMask& mask) {
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(c, number != NoRegister);
|
|
|
|
|
|
|
|
if ((mask.typeMask & (1 << RegisterOperand))) {
|
|
|
|
return ((static_cast<uint64_t>(1) << number) & mask.registerMask);
|
2008-08-23 18:04:36 +00:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-11 19:46:51 +00:00
|
|
|
virtual bool loneMatch(Context* c UNUSED, const SiteMask& mask) {
|
|
|
|
assert(c, number != NoRegister);
|
|
|
|
|
|
|
|
if ((mask.typeMask & (1 << RegisterOperand))) {
|
|
|
|
return ((static_cast<uint64_t>(1) << number) == mask.registerMask);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual bool matchNextWord(Context* c, Site* s, unsigned) {
|
2009-11-30 22:08:59 +00:00
|
|
|
assert(c, number != NoRegister);
|
|
|
|
|
|
|
|
if (s->type(c) != RegisterOperand) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegisterSite* rs = static_cast<RegisterSite*>(s);
|
|
|
|
unsigned size = rs->registerSize(c);
|
2011-08-30 01:00:17 +00:00
|
|
|
if (size > TargetBytesPerWord) {
|
2009-11-30 22:08:59 +00:00
|
|
|
assert(c, number != NoRegister);
|
|
|
|
return number == rs->number;
|
|
|
|
} else {
|
|
|
|
uint32_t mask = c->arch->generalRegisterMask();
|
|
|
|
return ((1 << number) & mask) and ((1 << rs->number) & mask);
|
|
|
|
}
|
2009-10-04 19:56:48 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void acquire(Context* c, Value* v) {
|
2009-01-03 21:34:45 +00:00
|
|
|
Target target;
|
2009-01-25 22:03:38 +00:00
|
|
|
if (number != NoRegister) {
|
|
|
|
target = Target(number, RegisterOperand, 0);
|
2009-01-03 21:34:45 +00:00
|
|
|
} else {
|
2009-11-28 04:15:12 +00:00
|
|
|
target = pickRegisterTarget(c, v, mask_);
|
2009-01-03 21:34:45 +00:00
|
|
|
expect(c, target.cost < Target::Impossible);
|
|
|
|
}
|
2009-01-03 00:44:47 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
RegisterResource* resource = c->registerResources + target.index;
|
2009-08-27 00:26:44 +00:00
|
|
|
local::acquire(c, resource, v, this);
|
2009-01-03 00:44:47 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
number = target.index;
|
2008-04-19 00:19:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void release(Context* c, Value* v) {
|
|
|
|
assert(c, number != NoRegister);
|
2008-05-12 13:54:47 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
local::release(c, c->registerResources + number, v, this);
|
2008-05-12 13:54:47 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void freeze(Context* c, Value* v) {
|
|
|
|
assert(c, number != NoRegister);
|
2008-05-12 13:54:47 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
c->registerResources[number].freeze(c, v);
|
2008-05-12 13:54:47 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void thaw(Context* c, Value* v) {
|
|
|
|
assert(c, number != NoRegister);
|
2008-05-12 13:54:47 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
c->registerResources[number].thaw(c, v);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual bool frozen(Context* c UNUSED) {
|
|
|
|
assert(c, number != NoRegister);
|
|
|
|
|
|
|
|
return c->registerResources[number].freezeCount != 0;
|
2009-01-04 20:35:09 +00:00
|
|
|
}
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
virtual OperandType type(Context*) {
|
2008-04-17 22:07:32 +00:00
|
|
|
return RegisterOperand;
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
virtual void asAssemblerOperand(Context* c UNUSED, Site* high,
|
|
|
|
Assembler::Operand* result)
|
2009-01-25 22:03:38 +00:00
|
|
|
{
|
|
|
|
assert(c, number != NoRegister);
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
int highNumber;
|
2009-09-26 19:43:44 +00:00
|
|
|
if (high != this) {
|
2009-02-01 23:10:56 +00:00
|
|
|
highNumber = static_cast<RegisterSite*>(high)->number;
|
|
|
|
assert(c, highNumber != NoRegister);
|
|
|
|
} else {
|
|
|
|
highNumber = NoRegister;
|
|
|
|
}
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
new (result) Assembler::Register(number, highNumber);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
virtual Site* copy(Context* c) {
|
2009-01-25 22:03:38 +00:00
|
|
|
uint32_t mask;
|
2008-10-12 00:23:08 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
if (number != NoRegister) {
|
|
|
|
mask = 1 << number;
|
2008-10-12 00:23:08 +00:00
|
|
|
} else {
|
2009-11-28 04:15:12 +00:00
|
|
|
mask = mask_;
|
2008-10-04 17:26:35 +00:00
|
|
|
}
|
2008-10-12 00:23:08 +00:00
|
|
|
|
|
|
|
return freeRegisterSite(c, mask);
|
2008-10-04 17:26:35 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
virtual Site* copyLow(Context* c) {
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Site* copyHigh(Context* c) {
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual Site* makeNextWord(Context* c, unsigned) {
|
2009-11-30 22:08:59 +00:00
|
|
|
assert(c, number != NoRegister);
|
|
|
|
assert(c, ((1 << number) & c->arch->generalRegisterMask()));
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
return freeRegisterSite(c, c->arch->generalRegisterMask());
|
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
virtual SiteMask mask(Context* c UNUSED) {
|
|
|
|
return SiteMask(1 << RegisterOperand, mask_, NoFrameIndex);
|
|
|
|
}
|
|
|
|
|
2009-11-30 22:08:59 +00:00
|
|
|
virtual SiteMask nextWordMask(Context* c, unsigned) {
|
|
|
|
assert(c, number != NoRegister);
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (registerSize(c) > TargetBytesPerWord) {
|
2009-11-30 22:08:59 +00:00
|
|
|
return SiteMask
|
|
|
|
(1 << RegisterOperand, number, NoFrameIndex);
|
|
|
|
} else {
|
|
|
|
return SiteMask
|
|
|
|
(1 << RegisterOperand, c->arch->generalRegisterMask(), NoFrameIndex);
|
|
|
|
}
|
2009-10-24 23:18:56 +00:00
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
virtual unsigned registerSize(Context* c) {
|
|
|
|
assert(c, number != NoRegister);
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
if ((1 << number) & c->arch->floatRegisterMask()) {
|
|
|
|
return c->arch->floatRegisterSize();
|
|
|
|
} else {
|
2011-08-30 01:00:17 +00:00
|
|
|
return TargetBytesPerWord;
|
2009-09-26 19:43:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-10 23:46:43 +00:00
|
|
|
virtual unsigned registerMask(Context* c UNUSED) {
|
2009-10-04 19:56:48 +00:00
|
|
|
assert(c, number != NoRegister);
|
|
|
|
|
|
|
|
return 1 << number;
|
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
uint32_t mask_;
|
2009-01-25 22:03:38 +00:00
|
|
|
int number;
|
2008-04-16 20:58:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
RegisterSite*
|
2009-01-25 22:03:38 +00:00
|
|
|
registerSite(Context* c, int number)
|
|
|
|
{
|
|
|
|
assert(c, number >= 0);
|
2009-09-26 19:43:44 +00:00
|
|
|
assert(c, (1 << number) & (c->arch->generalRegisterMask()
|
|
|
|
| c->arch->floatRegisterMask()));
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) RegisterSite(1 << number, number);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
RegisterSite*
|
2009-01-25 22:03:38 +00:00
|
|
|
freeRegisterSite(Context* c, uint32_t mask)
|
2008-05-12 13:54:47 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) RegisterSite(mask, NoRegister);
|
2008-05-12 13:54:47 +00:00
|
|
|
}
|
2008-04-17 22:07:32 +00:00
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
MemorySite*
|
|
|
|
memorySite(Context* c, int base, int offset = 0, int index = NoRegister,
|
|
|
|
unsigned scale = 1);
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
class MemorySite: public Site {
|
|
|
|
public:
|
2008-04-17 02:55:38 +00:00
|
|
|
MemorySite(int base, int offset, int index, unsigned scale):
|
2009-01-25 22:03:38 +00:00
|
|
|
acquired(false), base(base), offset(offset), index(index), scale(scale)
|
2008-04-16 20:58:21 +00:00
|
|
|
{ }
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) {
|
|
|
|
if (acquired) {
|
2009-08-27 00:26:44 +00:00
|
|
|
return vm::snprintf(buffer, bufferSize, "memory %d 0x%x %d %d",
|
2009-01-25 22:03:38 +00:00
|
|
|
base, offset, index, scale);
|
2008-10-04 17:26:35 +00:00
|
|
|
} else {
|
2009-08-27 00:26:44 +00:00
|
|
|
return vm::snprintf(buffer, bufferSize, "memory unacquired");
|
2008-10-04 17:26:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
virtual unsigned copyCost(Context* c, Site* s) {
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(c, acquired);
|
2008-05-12 13:54:47 +00:00
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
if (s and
|
|
|
|
(this == s or
|
2008-04-17 22:07:32 +00:00
|
|
|
(s->type(c) == MemoryOperand
|
2009-01-25 22:03:38 +00:00
|
|
|
and static_cast<MemorySite*>(s)->base == base
|
|
|
|
and static_cast<MemorySite*>(s)->offset == offset
|
|
|
|
and static_cast<MemorySite*>(s)->index == index
|
|
|
|
and static_cast<MemorySite*>(s)->scale == scale)))
|
2008-04-16 20:58:21 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
} else {
|
2009-11-28 18:17:17 +00:00
|
|
|
return MemoryCopyCost;
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual bool match(Context* c, const SiteMask& mask) {
|
|
|
|
assert(c, acquired);
|
|
|
|
|
|
|
|
if (mask.typeMask & (1 << MemoryOperand)) {
|
2009-11-30 22:08:59 +00:00
|
|
|
if (mask.frameIndex >= 0) {
|
|
|
|
if (base == c->arch->stack()) {
|
|
|
|
assert(c, index == NoRegister);
|
|
|
|
return static_cast<int>(frameIndexToOffset(c, mask.frameIndex))
|
|
|
|
== offset;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2008-08-23 18:04:36 +00:00
|
|
|
} else {
|
2008-10-19 00:15:57 +00:00
|
|
|
return true;
|
2008-08-23 18:04:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-11 19:46:51 +00:00
|
|
|
virtual bool loneMatch(Context* c, const SiteMask& mask) {
|
|
|
|
assert(c, acquired);
|
|
|
|
|
|
|
|
if (mask.typeMask & (1 << MemoryOperand)) {
|
|
|
|
if (base == c->arch->stack()) {
|
|
|
|
assert(c, index == NoRegister);
|
|
|
|
|
|
|
|
if (mask.frameIndex == AnyFrameIndex) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual bool matchNextWord(Context* c, Site* s, unsigned index) {
|
2009-10-04 19:56:48 +00:00
|
|
|
if (s->type(c) == MemoryOperand) {
|
|
|
|
MemorySite* ms = static_cast<MemorySite*>(s);
|
|
|
|
return ms->base == this->base
|
|
|
|
and ((index == 1 and ms->offset == static_cast<int>
|
2011-08-30 01:00:17 +00:00
|
|
|
(this->offset + TargetBytesPerWord))
|
2009-10-04 19:56:48 +00:00
|
|
|
or (index == 0 and this->offset == static_cast<int>
|
2011-08-30 01:00:17 +00:00
|
|
|
(ms->offset + TargetBytesPerWord)))
|
2009-10-04 19:56:48 +00:00
|
|
|
and ms->index == this->index
|
|
|
|
and ms->scale == this->scale;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void acquire(Context* c, Value* v) {
|
|
|
|
increment(c, c->registerResources + base);
|
|
|
|
if (index != NoRegister) {
|
|
|
|
increment(c, c->registerResources + index);
|
2008-04-19 00:19:45 +00:00
|
|
|
}
|
2008-09-28 21:56:12 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
if (base == c->arch->stack()) {
|
|
|
|
assert(c, index == NoRegister);
|
2009-10-24 23:18:56 +00:00
|
|
|
assert
|
|
|
|
(c, not c->frameResources[offsetToFrameIndex(c, offset)].reserved);
|
2009-01-03 00:44:47 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
local::acquire
|
|
|
|
(c, c->frameResources + offsetToFrameIndex(c, offset), v, this);
|
2008-09-28 21:56:12 +00:00
|
|
|
}
|
2008-04-19 00:19:45 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
acquired = true;
|
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void release(Context* c, Value* v) {
|
|
|
|
if (base == c->arch->stack()) {
|
|
|
|
assert(c, index == NoRegister);
|
2009-10-24 23:18:56 +00:00
|
|
|
assert
|
|
|
|
(c, not c->frameResources[offsetToFrameIndex(c, offset)].reserved);
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
local::release
|
|
|
|
(c, c->frameResources + offsetToFrameIndex(c, offset), v, this);
|
2008-09-28 21:56:12 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
decrement(c, c->registerResources + base);
|
2009-01-30 01:36:19 +00:00
|
|
|
if (index != NoRegister) {
|
2009-01-25 22:03:38 +00:00
|
|
|
decrement(c, c->registerResources + index);
|
2008-04-19 00:19:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
acquired = false;
|
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void freeze(Context* c, Value* v) {
|
|
|
|
if (base == c->arch->stack()) {
|
|
|
|
c->frameResources[offsetToFrameIndex(c, offset)].freeze(c, v);
|
2009-10-24 23:18:56 +00:00
|
|
|
} else {
|
|
|
|
increment(c, c->registerResources + base);
|
|
|
|
if (index != NoRegister) {
|
|
|
|
increment(c, c->registerResources + index);
|
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void thaw(Context* c, Value* v) {
|
|
|
|
if (base == c->arch->stack()) {
|
|
|
|
c->frameResources[offsetToFrameIndex(c, offset)].thaw(c, v);
|
2009-10-24 23:18:56 +00:00
|
|
|
} else {
|
|
|
|
decrement(c, c->registerResources + base);
|
|
|
|
if (index != NoRegister) {
|
|
|
|
decrement(c, c->registerResources + index);
|
|
|
|
}
|
2008-11-17 15:20:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual bool frozen(Context* c) {
|
|
|
|
return base == c->arch->stack()
|
|
|
|
and c->frameResources[offsetToFrameIndex(c, offset)].freezeCount != 0;
|
2009-01-04 20:35:09 +00:00
|
|
|
}
|
|
|
|
|
2008-04-16 20:58:21 +00:00
|
|
|
virtual OperandType type(Context*) {
|
2008-04-17 22:07:32 +00:00
|
|
|
return MemoryOperand;
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
virtual void asAssemblerOperand(Context* c UNUSED, Site* high UNUSED,
|
|
|
|
Assembler::Operand* result)
|
2009-01-25 22:03:38 +00:00
|
|
|
{
|
2009-10-24 23:18:56 +00:00
|
|
|
// todo: endianness?
|
2009-09-26 19:43:44 +00:00
|
|
|
assert(c, high == this
|
2009-02-01 23:10:56 +00:00
|
|
|
or (static_cast<MemorySite*>(high)->base == base
|
|
|
|
and static_cast<MemorySite*>(high)->offset
|
2011-08-30 01:00:17 +00:00
|
|
|
== static_cast<int>(offset + TargetBytesPerWord)
|
2009-02-01 23:10:56 +00:00
|
|
|
and static_cast<MemorySite*>(high)->index == index
|
|
|
|
and static_cast<MemorySite*>(high)->scale == scale));
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(c, acquired);
|
|
|
|
|
|
|
|
new (result) Assembler::Memory(base, offset, index, scale);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
virtual Site* copy(Context* c) {
|
2009-01-25 22:03:38 +00:00
|
|
|
return memorySite(c, base, offset, index, scale);
|
2008-10-12 00:23:08 +00:00
|
|
|
}
|
|
|
|
|
2009-03-12 03:07:30 +00:00
|
|
|
Site* copyHalf(Context* c, bool add) {
|
|
|
|
if (add) {
|
2011-08-30 01:00:17 +00:00
|
|
|
return memorySite(c, base, offset + TargetBytesPerWord, index, scale);
|
2009-03-12 03:07:30 +00:00
|
|
|
} else {
|
|
|
|
return copy(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
virtual Site* copyLow(Context* c) {
|
2009-03-12 03:07:30 +00:00
|
|
|
return copyHalf(c, c->arch->bigEndian());
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual Site* copyHigh(Context* c) {
|
2009-03-12 03:07:30 +00:00
|
|
|
return copyHalf(c, not c->arch->bigEndian());
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual Site* makeNextWord(Context* c, unsigned index) {
|
2009-10-04 19:56:48 +00:00
|
|
|
return memorySite
|
2011-02-26 19:45:22 +00:00
|
|
|
(c, base, offset + ((index == 1) xor c->arch->bigEndian()
|
2011-08-30 01:00:17 +00:00
|
|
|
? TargetBytesPerWord : -TargetBytesPerWord),
|
2009-10-04 19:56:48 +00:00
|
|
|
this->index, scale);
|
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
virtual SiteMask mask(Context* c) {
|
|
|
|
return SiteMask(1 << MemoryOperand, 0, (base == c->arch->stack())
|
2009-12-02 00:33:30 +00:00
|
|
|
? static_cast<int>(offsetToFrameIndex(c, offset))
|
|
|
|
: NoFrameIndex);
|
2009-11-28 04:15:12 +00:00
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
virtual SiteMask nextWordMask(Context* c, unsigned index) {
|
|
|
|
int frameIndex;
|
|
|
|
if (base == c->arch->stack()) {
|
|
|
|
assert(c, this->index == NoRegister);
|
|
|
|
frameIndex = static_cast<int>(offsetToFrameIndex(c, offset))
|
2011-02-26 19:45:22 +00:00
|
|
|
+ ((index == 1) xor c->arch->bigEndian() ? 1 : -1);
|
2009-10-24 23:18:56 +00:00
|
|
|
} else {
|
|
|
|
frameIndex = NoFrameIndex;
|
|
|
|
}
|
|
|
|
return SiteMask(1 << MemoryOperand, 0, frameIndex);
|
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
virtual bool isVolatile(Context* c) {
|
|
|
|
return base != c->arch->stack();
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
bool acquired;
|
|
|
|
int base;
|
|
|
|
int offset;
|
|
|
|
int index;
|
|
|
|
unsigned scale;
|
2008-04-16 20:58:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
MemorySite*
|
2008-10-12 00:23:08 +00:00
|
|
|
memorySite(Context* c, int base, int offset, int index, unsigned scale)
|
2008-04-16 20:58:21 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) MemorySite(base, offset, index, scale);
|
2008-04-16 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2008-08-23 18:04:36 +00:00
|
|
|
MemorySite*
|
|
|
|
frameSite(Context* c, int frameIndex)
|
|
|
|
{
|
|
|
|
assert(c, frameIndex >= 0);
|
2008-10-19 00:15:57 +00:00
|
|
|
return memorySite
|
2009-01-25 22:03:38 +00:00
|
|
|
(c, c->arch->stack(), frameIndexToOffset(c, frameIndex), NoRegister, 0);
|
2008-08-23 18:04:36 +00:00
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
void
|
2009-10-04 19:56:48 +00:00
|
|
|
move(Context* c, Value* value, Site* src, Site* dst);
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
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) {
|
2009-08-27 00:26:44 +00:00
|
|
|
total += vm::snprintf(buffer + total, size - total, "%p has ", p);
|
2009-01-04 01:17:51 +00:00
|
|
|
total += sitesToString(c, p->sites, buffer + total, size - total);
|
|
|
|
} else {
|
2009-08-27 00:26:44 +00:00
|
|
|
total += vm::snprintf(buffer + total, size - total, "%p has nothing", p);
|
2009-01-04 01:17:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p = p->buddy;
|
2009-09-26 19:43:44 +00:00
|
|
|
} while (p != v);
|
2009-01-04 01:17:51 +00:00
|
|
|
|
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
Site*
|
2009-01-11 18:48:02 +00:00
|
|
|
pickTargetSite(Context* c, Read* read, bool intersectRead = false,
|
2009-11-28 18:17:17 +00:00
|
|
|
unsigned registerReserveCount = 0,
|
|
|
|
CostCalculator* costCalculator = 0)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-11-28 18:17:17 +00:00
|
|
|
Target target
|
|
|
|
(pickTarget
|
|
|
|
(c, read, intersectRead, registerReserveCount, costCalculator));
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
expect(c, target.cost < Target::Impossible);
|
2009-11-28 18:17:17 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
if (target.type == MemoryOperand) {
|
|
|
|
return frameSite(c, target.index);
|
2009-01-03 21:34:45 +00:00
|
|
|
} else {
|
2009-01-25 22:03:38 +00:00
|
|
|
return registerSite(c, target.index);
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
class SingleRead: public Read {
|
|
|
|
public:
|
|
|
|
SingleRead(const SiteMask& mask, Value* successor):
|
2009-11-30 15:10:34 +00:00
|
|
|
next_(0), mask(mask), high_(0), successor_(successor)
|
2009-11-28 04:15:12 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual bool intersect(SiteMask* mask, unsigned) {
|
|
|
|
*mask = local::intersect(*mask, this->mask);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-11-30 15:10:34 +00:00
|
|
|
virtual Value* high(Context*) {
|
|
|
|
return high_;
|
2009-11-28 04:15:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual Value* successor() {
|
|
|
|
return successor_;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2009-11-30 15:10:34 +00:00
|
|
|
Value* high_;
|
2009-11-28 04:15:12 +00:00
|
|
|
Value* successor_;
|
|
|
|
};
|
|
|
|
|
|
|
|
SingleRead*
|
|
|
|
read(Context* c, const SiteMask& mask, Value* successor = 0)
|
|
|
|
{
|
|
|
|
assert(c, (mask.typeMask != 1 << MemoryOperand) or mask.frameIndex >= 0);
|
|
|
|
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) SingleRead(mask, successor);
|
2009-11-28 04:15:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
acceptMatch(Context* c, Site* s, Read*, const SiteMask& mask)
|
|
|
|
{
|
|
|
|
return s->match(c, mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
Site*
|
|
|
|
pickSourceSite(Context* c, Read* read, Site* target = 0,
|
2009-12-01 02:06:01 +00:00
|
|
|
unsigned* cost = 0, SiteMask* extraMask = 0,
|
2009-11-28 04:15:12 +00:00
|
|
|
bool intersectRead = true, bool includeBuddies = true,
|
|
|
|
bool includeNextWord = true,
|
|
|
|
bool (*accept)(Context*, Site*, Read*, const SiteMask&)
|
|
|
|
= acceptMatch)
|
|
|
|
{
|
2009-12-01 02:06:01 +00:00
|
|
|
SiteMask mask;
|
|
|
|
|
|
|
|
if (extraMask) {
|
|
|
|
mask = intersect(mask, *extraMask);
|
|
|
|
}
|
2009-11-28 04:15:12 +00:00
|
|
|
|
|
|
|
if (intersectRead) {
|
|
|
|
read->intersect(&mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
Site* site = 0;
|
|
|
|
unsigned copyCost = 0xFFFFFFFF;
|
|
|
|
for (SiteIterator it(c, read->value, includeBuddies, includeNextWord);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 (cost) *cost = copyCost;
|
|
|
|
return site;
|
|
|
|
}
|
|
|
|
|
|
|
|
Site*
|
|
|
|
maybeMove(Context* c, Read* read, bool intersectRead, bool includeNextWord,
|
|
|
|
unsigned registerReserveCount = 0)
|
|
|
|
{
|
|
|
|
Value* value = read->value;
|
2011-08-30 01:00:17 +00:00
|
|
|
unsigned size = value == value->nextWord ? TargetBytesPerWord : 8;
|
2009-11-28 04:15:12 +00:00
|
|
|
|
2009-11-28 18:17:17 +00:00
|
|
|
class MyCostCalculator: public CostCalculator {
|
|
|
|
public:
|
|
|
|
MyCostCalculator(Value* value, unsigned size, bool includeNextWord):
|
|
|
|
value(value),
|
|
|
|
size(size),
|
|
|
|
includeNextWord(includeNextWord)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual unsigned cost(Context* c, uint8_t typeMask, uint32_t registerMask,
|
|
|
|
int frameIndex)
|
|
|
|
{
|
|
|
|
uint8_t srcTypeMask;
|
|
|
|
uint64_t srcRegisterMask;
|
|
|
|
uint8_t tmpTypeMask;
|
|
|
|
uint64_t tmpRegisterMask;
|
|
|
|
c->arch->planMove
|
|
|
|
(size, &srcTypeMask, &srcRegisterMask,
|
|
|
|
&tmpTypeMask, &tmpRegisterMask,
|
|
|
|
typeMask, registerMask);
|
|
|
|
|
|
|
|
SiteMask srcMask(srcTypeMask, srcRegisterMask, AnyFrameIndex);
|
|
|
|
SiteMask dstMask(typeMask, registerMask, frameIndex);
|
|
|
|
for (SiteIterator it(c, value, true, includeNextWord); it.hasMore();) {
|
|
|
|
Site* s = it.next();
|
|
|
|
if (s->match(c, srcMask) or s->match(c, dstMask)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Target::IndirectMovePenalty;
|
|
|
|
}
|
|
|
|
|
|
|
|
Value* value;
|
|
|
|
unsigned size;
|
|
|
|
bool includeNextWord;
|
|
|
|
} costCalculator(value, size, includeNextWord);
|
|
|
|
|
|
|
|
Site* dst = pickTargetSite
|
|
|
|
(c, read, intersectRead, registerReserveCount, &costCalculator);
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
uint8_t srcTypeMask;
|
|
|
|
uint64_t srcRegisterMask;
|
|
|
|
uint8_t tmpTypeMask;
|
|
|
|
uint64_t tmpRegisterMask;
|
|
|
|
c->arch->planMove
|
|
|
|
(size, &srcTypeMask, &srcRegisterMask,
|
|
|
|
&tmpTypeMask, &tmpRegisterMask,
|
|
|
|
1 << dst->type(c), dst->registerMask(c));
|
|
|
|
|
|
|
|
SiteMask srcMask(srcTypeMask, srcRegisterMask, AnyFrameIndex);
|
2009-11-28 18:17:17 +00:00
|
|
|
unsigned cost = 0xFFFFFFFF;
|
|
|
|
Site* src = 0;
|
|
|
|
for (SiteIterator it(c, value, true, includeNextWord); it.hasMore();) {
|
|
|
|
Site* s = it.next();
|
|
|
|
unsigned v = s->copyCost(c, dst);
|
|
|
|
if (v == 0) {
|
|
|
|
src = s;
|
|
|
|
cost = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (not s->match(c, srcMask)) {
|
|
|
|
v += CopyPenalty;
|
|
|
|
}
|
|
|
|
if (v < cost) {
|
|
|
|
src = s;
|
|
|
|
cost = v;
|
2009-11-28 04:15:12 +00:00
|
|
|
}
|
|
|
|
}
|
2009-11-28 18:17:17 +00:00
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
if (cost) {
|
2009-12-01 18:14:57 +00:00
|
|
|
if (DebugMoves) {
|
|
|
|
char srcb[256]; src->toString(c, srcb, 256);
|
|
|
|
char dstb[256]; dst->toString(c, dstb, 256);
|
|
|
|
fprintf(stderr, "maybe move %s to %s for %p to %p\n",
|
|
|
|
srcb, dstb, value, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
src->freeze(c, value);
|
|
|
|
|
|
|
|
addSite(c, value, dst);
|
|
|
|
|
|
|
|
src->thaw(c, value);
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
if (not src->match(c, srcMask)) {
|
|
|
|
src->freeze(c, value);
|
|
|
|
dst->freeze(c, value);
|
|
|
|
|
|
|
|
SiteMask tmpMask(tmpTypeMask, tmpRegisterMask, AnyFrameIndex);
|
|
|
|
SingleRead tmpRead(tmpMask, 0);
|
|
|
|
tmpRead.value = value;
|
2009-11-28 18:17:17 +00:00
|
|
|
tmpRead.successor_ = value;
|
2009-11-28 04:15:12 +00:00
|
|
|
|
|
|
|
Site* tmp = pickTargetSite(c, &tmpRead, true);
|
|
|
|
|
2009-12-01 18:14:57 +00:00
|
|
|
addSite(c, value, tmp);
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
move(c, value, src, tmp);
|
|
|
|
|
|
|
|
dst->thaw(c, value);
|
|
|
|
src->thaw(c, value);
|
|
|
|
|
|
|
|
src = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
move(c, value, src, dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2009-11-30 15:10:34 +00:00
|
|
|
Site*
|
|
|
|
maybeMove(Context* c, Value* v, const SiteMask& mask, bool intersectMask,
|
|
|
|
bool includeNextWord, unsigned registerReserveCount = 0)
|
|
|
|
{
|
|
|
|
SingleRead read(mask, 0);
|
|
|
|
read.value = v;
|
|
|
|
read.successor_ = v;
|
|
|
|
|
|
|
|
return maybeMove
|
|
|
|
(c, &read, intersectMask, includeNextWord, registerReserveCount);
|
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
Site*
|
|
|
|
pickSiteOrMove(Context* c, Read* read, bool intersectRead,
|
|
|
|
bool includeNextWord, unsigned registerReserveCount = 0)
|
|
|
|
{
|
|
|
|
Site* s = pickSourceSite
|
2009-12-01 02:06:01 +00:00
|
|
|
(c, read, 0, 0, 0, intersectRead, true, includeNextWord);
|
2009-11-28 04:15:12 +00:00
|
|
|
|
|
|
|
if (s) {
|
|
|
|
return s;
|
|
|
|
} else {
|
|
|
|
return maybeMove
|
|
|
|
(c, read, intersectRead, includeNextWord, registerReserveCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Site*
|
|
|
|
pickSiteOrMove(Context* c, Value* v, const SiteMask& mask, bool intersectMask,
|
|
|
|
bool includeNextWord, unsigned registerReserveCount = 0)
|
|
|
|
{
|
|
|
|
SingleRead read(mask, 0);
|
|
|
|
read.value = v;
|
2009-11-28 18:17:17 +00:00
|
|
|
read.successor_ = v;
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
return pickSiteOrMove
|
|
|
|
(c, &read, intersectMask, includeNextWord, registerReserveCount);
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
steal(Context* c, Resource* r, Value* thief)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
|
|
|
if (DebugResources) {
|
2009-01-04 01:17:51 +00:00
|
|
|
char resourceBuffer[256]; r->toString(c, resourceBuffer, 256);
|
2009-01-04 19:38:31 +00:00
|
|
|
char siteBuffer[1024]; sitesToString(c, r->value, siteBuffer, 1024);
|
2009-01-04 01:17:51 +00:00
|
|
|
fprintf(stderr, "%p steal %s from %p (%s)\n",
|
|
|
|
thief, resourceBuffer, r->value, siteBuffer);
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
if ((not (thief and buddies(thief, r->value))
|
|
|
|
and uniqueSite(c, r->value, r->site)))
|
2009-01-11 18:48:02 +00:00
|
|
|
{
|
2009-01-25 22:03:38 +00:00
|
|
|
r->site->freeze(c, r->value);
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2010-11-26 19:36:43 +00:00
|
|
|
maybeMove(c, live(c, r->value), false, true, StealRegisterReserveCount);
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
r->site->thaw(c, r->value);
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
removeSite(c, r->value, r->site);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
acquire(Context* c, Resource* resource, Value* value, Site* site)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(c, value);
|
|
|
|
assert(c, site);
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
if (not resource->reserved) {
|
2009-01-03 21:34:45 +00:00
|
|
|
if (DebugResources) {
|
2009-01-25 22:03:38 +00:00
|
|
|
char buffer[256]; resource->toString(c, buffer, 256);
|
|
|
|
fprintf(stderr, "%p acquire %s\n", value, buffer);
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
if (resource->value) {
|
|
|
|
assert(c, findSite(c, resource->value, resource->site));
|
2009-09-26 19:43:44 +00:00
|
|
|
assert(c, not findSite(c, value, resource->site));
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
steal(c, resource, value);
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
2011-03-27 20:15:05 +00:00
|
|
|
if (c->acquiredResources) {
|
|
|
|
c->acquiredResources->previousAcquired = resource;
|
|
|
|
resource->nextAcquired = c->acquiredResources;
|
|
|
|
}
|
|
|
|
c->acquiredResources = resource;
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
resource->value = value;
|
|
|
|
resource->site = site;
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-02-08 20:21:35 +00:00
|
|
|
release(Context* c, Resource* resource, Value* value UNUSED, Site* site UNUSED)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2009-01-25 22:03:38 +00:00
|
|
|
if (not resource->reserved) {
|
2009-01-03 21:34:45 +00:00
|
|
|
if (DebugResources) {
|
2009-01-25 22:03:38 +00:00
|
|
|
char buffer[256]; resource->toString(c, buffer, 256);
|
|
|
|
fprintf(stderr, "%p release %s\n", resource->value, buffer);
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(c, resource->value);
|
|
|
|
assert(c, resource->site);
|
|
|
|
|
|
|
|
assert(c, buddies(resource->value, value));
|
|
|
|
assert(c, site == resource->site);
|
2011-03-27 20:15:05 +00:00
|
|
|
|
|
|
|
Resource* next = resource->nextAcquired;
|
|
|
|
if (next) {
|
|
|
|
next->previousAcquired = resource->previousAcquired;
|
|
|
|
resource->nextAcquired = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Resource* previous = resource->previousAcquired;
|
|
|
|
if (previous) {
|
|
|
|
previous->nextAcquired = next;
|
|
|
|
resource->previousAcquired = 0;
|
|
|
|
} else {
|
|
|
|
assert(c, c->acquiredResources == resource);
|
|
|
|
c->acquiredResources = next;
|
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
resource->value = 0;
|
|
|
|
resource->site = 0;
|
2009-01-03 21:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
SiteMask
|
|
|
|
generalRegisterMask(Context* c)
|
2008-08-28 22:43:35 +00:00
|
|
|
{
|
2009-10-04 19:56:48 +00:00
|
|
|
return SiteMask
|
|
|
|
(1 << RegisterOperand, c->arch->generalRegisterMask(), NoFrameIndex);
|
2008-08-28 22:43:35 +00:00
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
SiteMask
|
|
|
|
generalRegisterOrConstantMask(Context* c)
|
2008-08-28 22:43:35 +00:00
|
|
|
{
|
2009-10-04 19:56:48 +00:00
|
|
|
return SiteMask
|
|
|
|
((1 << RegisterOperand) | (1 << ConstantOperand),
|
|
|
|
c->arch->generalRegisterMask(), NoFrameIndex);
|
2008-08-28 22:43:35 +00:00
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
SiteMask
|
|
|
|
fixedRegisterMask(int number)
|
2008-08-28 22:43:35 +00:00
|
|
|
{
|
2009-10-04 19:56:48 +00:00
|
|
|
return SiteMask(1 << RegisterOperand, 1 << number, NoFrameIndex);
|
2008-08-28 22:43:35 +00:00
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
class MultiRead: public Read {
|
|
|
|
public:
|
2009-01-25 22:03:38 +00:00
|
|
|
MultiRead():
|
|
|
|
reads(0), lastRead(0), firstTarget(0), lastTarget(0), visited(false)
|
2009-01-03 21:34:45 +00:00
|
|
|
{ }
|
2009-01-03 00:44:47 +00:00
|
|
|
|
2009-08-05 00:28:34 +00:00
|
|
|
virtual bool intersect(SiteMask* mask, unsigned depth) {
|
|
|
|
if (depth > 0) {
|
|
|
|
// short-circuit recursion to avoid poor performance in
|
|
|
|
// deeply-nested branches
|
|
|
|
return reads != 0;
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
bool result = false;
|
|
|
|
if (not visited) {
|
|
|
|
visited = true;
|
|
|
|
for (Cell** cell = &reads; *cell;) {
|
|
|
|
Read* r = static_cast<Read*>((*cell)->value);
|
2009-08-05 00:28:34 +00:00
|
|
|
bool valid = r->intersect(mask, depth + 1);
|
2009-01-03 21:34:45 +00:00
|
|
|
if (valid) {
|
|
|
|
result = true;
|
|
|
|
cell = &((*cell)->next);
|
|
|
|
} else {
|
|
|
|
*cell = (*cell)->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
visited = false;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2008-12-24 20:35:43 +00:00
|
|
|
|
2009-04-08 00:55:43 +00:00
|
|
|
virtual Value* successor() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
virtual bool valid() {
|
|
|
|
bool result = false;
|
|
|
|
if (not visited) {
|
|
|
|
visited = true;
|
|
|
|
for (Cell** cell = &reads; *cell;) {
|
|
|
|
Read* r = static_cast<Read*>((*cell)->value);
|
|
|
|
if (r->valid()) {
|
|
|
|
result = true;
|
|
|
|
cell = &((*cell)->next);
|
|
|
|
} else {
|
|
|
|
*cell = (*cell)->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
visited = false;
|
2008-12-24 20:35:43 +00:00
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
return result;
|
2008-12-24 20:35:43 +00:00
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
virtual void append(Context* c, Read* r) {
|
|
|
|
Cell* cell = cons(c, r, 0);
|
|
|
|
if (lastRead == 0) {
|
|
|
|
reads = cell;
|
|
|
|
} else {
|
|
|
|
lastRead->next = cell;
|
2008-12-24 20:35:43 +00:00
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
lastRead = cell;
|
|
|
|
|
2009-07-08 14:18:40 +00:00
|
|
|
// fprintf(stderr, "append %p to %p for %p\n", r, lastTarget, this);
|
2009-02-14 20:26:39 +00:00
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
lastTarget->value = r;
|
2008-12-24 20:35:43 +00:00
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
virtual Read* next(Context* c) {
|
|
|
|
abort(c);
|
2008-12-24 20:35:43 +00:00
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
void allocateTarget(Context* c) {
|
|
|
|
Cell* cell = cons(c, 0, 0);
|
2009-02-14 20:26:39 +00:00
|
|
|
|
2009-07-08 14:18:40 +00:00
|
|
|
// fprintf(stderr, "allocate target for %p: %p\n", this, cell);
|
2009-02-14 20:26:39 +00:00
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
if (lastTarget) {
|
|
|
|
lastTarget->next = cell;
|
|
|
|
} else {
|
|
|
|
firstTarget = cell;
|
2008-12-24 20:35:43 +00:00
|
|
|
}
|
2009-01-03 21:34:45 +00:00
|
|
|
lastTarget = cell;
|
2008-12-24 20:35:43 +00:00
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
Read* nextTarget() {
|
2009-04-08 00:55:43 +00:00
|
|
|
// fprintf(stderr, "next target for %p: %p\n", this, firstTarget);
|
2009-02-14 20:26:39 +00:00
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
Read* r = static_cast<Read*>(firstTarget->value);
|
|
|
|
firstTarget = firstTarget->next;
|
|
|
|
return r;
|
2008-12-24 20:35:43 +00:00
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
Cell* reads;
|
|
|
|
Cell* lastRead;
|
|
|
|
Cell* firstTarget;
|
|
|
|
Cell* lastTarget;
|
|
|
|
bool visited;
|
|
|
|
};
|
2008-12-24 20:35:43 +00:00
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
MultiRead*
|
2009-01-25 22:03:38 +00:00
|
|
|
multiRead(Context* c)
|
2009-01-03 00:44:47 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) MultiRead;
|
2009-01-03 00:44:47 +00:00
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
class StubRead: public Read {
|
|
|
|
public:
|
2009-01-25 22:03:38 +00:00
|
|
|
StubRead():
|
|
|
|
next_(0), read(0), visited(false), valid_(true)
|
2009-01-03 21:34:45 +00:00
|
|
|
{ }
|
2008-11-17 15:20:48 +00:00
|
|
|
|
2009-08-05 00:28:34 +00:00
|
|
|
virtual bool intersect(SiteMask* mask, unsigned depth) {
|
2009-01-03 21:34:45 +00:00
|
|
|
if (not visited) {
|
|
|
|
visited = true;
|
|
|
|
if (read) {
|
2009-08-05 00:28:34 +00:00
|
|
|
bool valid = read->intersect(mask, depth);
|
2009-01-03 21:34:45 +00:00
|
|
|
if (not valid) {
|
|
|
|
read = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
visited = false;
|
|
|
|
}
|
|
|
|
return valid_;
|
2009-01-03 00:44:47 +00:00
|
|
|
}
|
2008-12-23 00:55:29 +00:00
|
|
|
|
2009-04-08 00:55:43 +00:00
|
|
|
virtual Value* successor() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
virtual bool valid() {
|
|
|
|
return valid_;
|
2008-04-27 20:15:18 +00:00
|
|
|
}
|
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
virtual void append(Context* c UNUSED, Read* r) {
|
|
|
|
assert(c, next_ == 0);
|
|
|
|
next_ = r;
|
|
|
|
}
|
2009-01-03 00:44:47 +00:00
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
virtual Read* next(Context*) {
|
|
|
|
return next_;
|
2008-11-17 15:20:48 +00:00
|
|
|
}
|
2008-04-27 20:15:18 +00:00
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
Read* next_;
|
|
|
|
Read* read;
|
|
|
|
bool visited;
|
|
|
|
bool valid_;
|
|
|
|
};
|
2009-01-03 00:44:47 +00:00
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
StubRead*
|
2009-01-25 22:03:38 +00:00
|
|
|
stubRead(Context* c)
|
2009-01-03 21:34:45 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) StubRead;
|
2008-04-27 20:15:18 +00:00
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
Site*
|
2009-11-30 15:10:34 +00:00
|
|
|
pickSite(Context* c, Value* v, Site* s, unsigned index, bool includeNextWord)
|
2009-10-04 19:56:48 +00:00
|
|
|
{
|
2009-11-30 15:10:34 +00:00
|
|
|
for (SiteIterator it(c, v, true, includeNextWord); it.hasMore();) {
|
2009-10-04 19:56:48 +00:00
|
|
|
Site* candidate = it.next();
|
2009-10-24 23:18:56 +00:00
|
|
|
if (s->matchNextWord(c, candidate, index)) {
|
2009-10-04 19:56:48 +00:00
|
|
|
return candidate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-30 15:10:34 +00:00
|
|
|
Site*
|
|
|
|
pickSiteOrMove(Context* c, Value* v, Site* s, unsigned index)
|
|
|
|
{
|
|
|
|
Site* n = pickSite(c, v, s, index, false);
|
|
|
|
if (n) {
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return maybeMove(c, v, s->nextWordMask(c, index), true, false);
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
Site*
|
2009-11-28 04:15:12 +00:00
|
|
|
pickSiteOrMove(Context* c, Value* v, Site* s, Site** low, Site** high)
|
2009-10-04 19:56:48 +00:00
|
|
|
{
|
2009-10-10 22:07:30 +00:00
|
|
|
if (v->wordIndex == 0) {
|
2009-10-04 19:56:48 +00:00
|
|
|
*low = s;
|
2009-11-28 04:15:12 +00:00
|
|
|
*high = pickSiteOrMove(c, v->nextWord, s, 1);
|
2009-10-04 19:56:48 +00:00
|
|
|
return *high;
|
|
|
|
} else {
|
2009-11-28 04:15:12 +00:00
|
|
|
*low = pickSiteOrMove(c, v->nextWord, s, 0);
|
2009-10-04 19:56:48 +00:00
|
|
|
*high = s;
|
|
|
|
return *low;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Site*
|
2009-11-28 04:15:12 +00:00
|
|
|
pickSiteOrGrow(Context* c, Value* v, Site* s, unsigned index)
|
2009-10-04 19:56:48 +00:00
|
|
|
{
|
2009-11-30 15:10:34 +00:00
|
|
|
Site* n = pickSite(c, v, s, index, false);
|
2009-10-24 23:18:56 +00:00
|
|
|
if (n) {
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = s->makeNextWord(c, index);
|
2009-10-04 19:56:48 +00:00
|
|
|
addSite(c, v, n);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
Site*
|
2009-11-28 04:15:12 +00:00
|
|
|
pickSiteOrGrow(Context* c, Value* v, Site* s, Site** low, Site** high)
|
2009-10-04 19:56:48 +00:00
|
|
|
{
|
2009-10-10 22:07:30 +00:00
|
|
|
if (v->wordIndex == 0) {
|
2009-10-04 19:56:48 +00:00
|
|
|
*low = s;
|
2009-11-28 04:15:12 +00:00
|
|
|
*high = pickSiteOrGrow(c, v->nextWord, s, 1);
|
2009-10-04 19:56:48 +00:00
|
|
|
return *high;
|
|
|
|
} else {
|
2009-11-28 04:15:12 +00:00
|
|
|
*low = pickSiteOrGrow(c, v->nextWord, s, 0);
|
2009-10-04 19:56:48 +00:00
|
|
|
*high = s;
|
|
|
|
return *low;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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->availableGeneralRegisterCount > ResolveRegisterReserveCount;
|
|
|
|
} else {
|
|
|
|
assert(c, s->match(c, SiteMask(1 << MemoryOperand, 0, AnyFrameIndex)));
|
|
|
|
|
|
|
|
return isHome(read->value, offsetToFrameIndex
|
|
|
|
(c, static_cast<MemorySite*>(s)->offset));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
move(Context* c, Value* value, Site* src, Site* dst)
|
|
|
|
{
|
|
|
|
if (DebugMoves) {
|
|
|
|
char srcb[256]; src->toString(c, srcb, 256);
|
|
|
|
char dstb[256]; dst->toString(c, dstb, 256);
|
2009-11-28 04:15:12 +00:00
|
|
|
fprintf(stderr, "move %s to %s for %p to %p\n",
|
|
|
|
srcb, dstb, value, value);
|
2009-10-04 19:56:48 +00:00
|
|
|
}
|
|
|
|
|
2009-12-01 18:14:57 +00:00
|
|
|
assert(c, findSite(c, value, dst));
|
2009-11-28 04:15:12 +00:00
|
|
|
|
2009-12-01 18:14:57 +00:00
|
|
|
src->freeze(c, value);
|
2009-10-04 19:56:48 +00:00
|
|
|
dst->freeze(c, value);
|
|
|
|
|
|
|
|
unsigned srcSize;
|
|
|
|
unsigned dstSize;
|
2009-10-10 22:07:30 +00:00
|
|
|
if (value->nextWord == value) {
|
2011-08-30 01:00:17 +00:00
|
|
|
srcSize = TargetBytesPerWord;
|
|
|
|
dstSize = TargetBytesPerWord;
|
2009-10-04 19:56:48 +00:00
|
|
|
} else {
|
|
|
|
srcSize = src->registerSize(c);
|
|
|
|
dstSize = dst->registerSize(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (srcSize == dstSize) {
|
|
|
|
apply(c, Move, srcSize, src, src, dstSize, dst, dst);
|
2011-08-30 01:00:17 +00:00
|
|
|
} else if (srcSize > TargetBytesPerWord) {
|
2009-11-28 04:15:12 +00:00
|
|
|
Site* low, *high, *other = pickSiteOrGrow(c, value, dst, &low, &high);
|
2009-10-10 22:07:30 +00:00
|
|
|
other->freeze(c, value->nextWord);
|
2009-10-04 19:56:48 +00:00
|
|
|
|
|
|
|
apply(c, Move, srcSize, src, src, srcSize, low, high);
|
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
other->thaw(c, value->nextWord);
|
2009-10-04 19:56:48 +00:00
|
|
|
} else {
|
2009-11-28 04:15:12 +00:00
|
|
|
Site* low, *high, *other = pickSiteOrMove(c, value, src, &low, &high);
|
2009-10-10 22:07:30 +00:00
|
|
|
other->freeze(c, value->nextWord);
|
2009-10-04 19:56:48 +00:00
|
|
|
|
|
|
|
apply(c, Move, dstSize, low, high, dstSize, dst, dst);
|
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
other->thaw(c, value->nextWord);
|
2009-10-04 19:56:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dst->thaw(c, value);
|
|
|
|
src->thaw(c, value);
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
void
|
|
|
|
asAssemblerOperand(Context* c, Site* low, Site* high,
|
|
|
|
Assembler::Operand* result)
|
2009-01-03 00:44:47 +00:00
|
|
|
{
|
2009-02-01 23:10:56 +00:00
|
|
|
low->asAssemblerOperand(c, high, result);
|
2008-10-17 00:10:35 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
class OperandUnion: public Assembler::Operand {
|
2009-02-01 23:10:56 +00:00
|
|
|
// 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):
|
2009-01-25 22:03:38 +00:00
|
|
|
uintptr_t padding[4];
|
|
|
|
};
|
2008-11-11 04:25:36 +00:00
|
|
|
|
2008-04-17 02:55:38 +00:00
|
|
|
void
|
2008-08-16 17:45:36 +00:00
|
|
|
apply(Context* c, UnaryOperation op,
|
2009-01-25 22:03:38 +00:00
|
|
|
unsigned s1Size, Site* s1Low, Site* s1High)
|
2008-08-16 17:45:36 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
assert(c, s1Low->type(c) == s1High->type(c));
|
2008-08-16 17:45:36 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
OperandType s1Type = s1Low->type(c);
|
|
|
|
OperandUnion s1Union; asAssemblerOperand(c, s1Low, s1High, &s1Union);
|
|
|
|
|
|
|
|
c->assembler->apply(op, s1Size, s1Type, &s1Union);
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
apply(Context* c, BinaryOperation op,
|
2009-01-25 22:03:38 +00:00
|
|
|
unsigned s1Size, Site* s1Low, Site* s1High,
|
|
|
|
unsigned s2Size, Site* s2Low, Site* s2High)
|
2008-04-17 02:55:38 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
assert(c, s1Low->type(c) == s1High->type(c));
|
|
|
|
assert(c, s2Low->type(c) == s2High->type(c));
|
2009-01-25 22:03:38 +00:00
|
|
|
|
|
|
|
OperandType s1Type = s1Low->type(c);
|
|
|
|
OperandUnion s1Union; asAssemblerOperand(c, s1Low, s1High, &s1Union);
|
2008-08-16 17:45:36 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
OperandType s2Type = s2Low->type(c);
|
|
|
|
OperandUnion s2Union; asAssemblerOperand(c, s2Low, s2High, &s2Union);
|
2008-03-15 20:24:04 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
c->assembler->apply(op, s1Size, s1Type, &s1Union,
|
|
|
|
s2Size, s2Type, &s2Union);
|
2008-04-17 02:55:38 +00:00
|
|
|
}
|
2008-02-17 20:57:40 +00:00
|
|
|
|
2008-04-17 02:55:38 +00:00
|
|
|
void
|
2008-08-16 17:45:36 +00:00
|
|
|
apply(Context* c, TernaryOperation op,
|
2009-01-25 22:03:38 +00:00
|
|
|
unsigned s1Size, Site* s1Low, Site* s1High,
|
|
|
|
unsigned s2Size, Site* s2Low, Site* s2High,
|
|
|
|
unsigned s3Size, Site* s3Low, Site* s3High)
|
2008-04-17 02:55:38 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
assert(c, s1Low->type(c) == s1High->type(c));
|
|
|
|
assert(c, s2Low->type(c) == s2High->type(c));
|
|
|
|
assert(c, s3Low->type(c) == s3High->type(c));
|
2009-01-25 22:03:38 +00:00
|
|
|
|
|
|
|
OperandType s1Type = s1Low->type(c);
|
|
|
|
OperandUnion s1Union; asAssemblerOperand(c, s1Low, s1High, &s1Union);
|
2008-02-17 20:57:40 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
OperandType s2Type = s2Low->type(c);
|
|
|
|
OperandUnion s2Union; asAssemblerOperand(c, s2Low, s2High, &s2Union);
|
2008-02-17 22:29:04 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
OperandType s3Type = s3Low->type(c);
|
|
|
|
OperandUnion s3Union; asAssemblerOperand(c, s3Low, s3High, &s3Union);
|
2008-08-16 17:45:36 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
c->assembler->apply(op, s1Size, s1Type, &s1Union,
|
|
|
|
s2Size, s2Type, &s2Union,
|
|
|
|
s3Size, s3Type, &s3Union);
|
2008-04-17 02:55:38 +00:00
|
|
|
}
|
2008-02-17 20:57:40 +00:00
|
|
|
|
2008-03-11 16:40:28 +00:00
|
|
|
void
|
2008-09-15 02:28:42 +00:00
|
|
|
addRead(Context* c, Event* e, Value* v, Read* r)
|
2008-03-11 16:40:28 +00:00
|
|
|
{
|
2008-11-08 20:47:26 +00:00
|
|
|
if (DebugReads) {
|
2009-08-27 00:26:44 +00:00
|
|
|
fprintf(stderr, "add read %p to %p last %p event %p (%s)\n",
|
|
|
|
r, v, v->lastRead, e, (e ? e->name() : 0));
|
2008-11-08 20:47:26 +00:00
|
|
|
}
|
2009-09-26 19:43:44 +00:00
|
|
|
|
2008-08-28 22:43:35 +00:00
|
|
|
r->value = v;
|
2008-09-15 02:28:42 +00:00
|
|
|
if (e) {
|
|
|
|
r->event = e;
|
|
|
|
r->eventNext = e->reads;
|
|
|
|
e->reads = r;
|
|
|
|
++ e->readCount;
|
|
|
|
}
|
2008-04-17 02:55:38 +00:00
|
|
|
|
2008-09-13 21:09:26 +00:00
|
|
|
if (v->lastRead) {
|
2009-04-08 00:55:43 +00:00
|
|
|
// if (DebugReads) {
|
|
|
|
// fprintf(stderr, "append %p to %p for %p\n", r, v->lastRead, v);
|
|
|
|
// }
|
2008-11-08 20:47:26 +00:00
|
|
|
|
2008-09-13 21:09:26 +00:00
|
|
|
v->lastRead->append(c, r);
|
|
|
|
} else {
|
|
|
|
v->reads = r;
|
2008-04-17 02:55:38 +00:00
|
|
|
}
|
2008-09-13 21:09:26 +00:00
|
|
|
v->lastRead = r;
|
2008-03-11 16:40:28 +00:00
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
void
|
|
|
|
addRead(Context* c, Event* e, Value* v, const SiteMask& mask,
|
|
|
|
Value* successor = 0)
|
|
|
|
{
|
|
|
|
addRead(c, e, v, read(c, mask, successor));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
addReads(Context* c, Event* e, Value* v, unsigned size,
|
|
|
|
const SiteMask& lowMask, Value* lowSuccessor,
|
|
|
|
const SiteMask& highMask, Value* highSuccessor)
|
|
|
|
{
|
|
|
|
SingleRead* r = read(c, lowMask, lowSuccessor);
|
|
|
|
addRead(c, e, v, r);
|
2011-08-30 01:00:17 +00:00
|
|
|
if (size > TargetBytesPerWord) {
|
2009-11-30 15:10:34 +00:00
|
|
|
r->high_ = v->nextWord;
|
2009-10-10 22:07:30 +00:00
|
|
|
addRead(c, e, v->nextWord, highMask, highSuccessor);
|
2009-10-04 19:56:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
addReads(Context* c, Event* e, Value* v, unsigned size,
|
|
|
|
const SiteMask& lowMask, const SiteMask& highMask)
|
|
|
|
{
|
|
|
|
addReads(c, e, v, size, lowMask, 0, highMask, 0);
|
|
|
|
}
|
|
|
|
|
2008-07-05 20:21:13 +00:00
|
|
|
void
|
2008-10-06 00:50:59 +00:00
|
|
|
clean(Context* c, Value* v, unsigned popIndex)
|
2008-07-05 20:21:13 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
for (SiteIterator it(c, v); it.hasMore();) {
|
2008-11-01 22:16:18 +00:00
|
|
|
Site* s = it.next();
|
2009-01-25 22:03:38 +00:00
|
|
|
if (not (s->match(c, SiteMask(1 << MemoryOperand, 0, AnyFrameIndex))
|
2008-11-01 22:16:18 +00:00
|
|
|
and offsetToFrameIndex
|
2009-01-25 22:03:38 +00:00
|
|
|
(c, static_cast<MemorySite*>(s)->offset)
|
2008-11-01 22:16:18 +00:00
|
|
|
>= popIndex))
|
2008-10-06 00:50:59 +00:00
|
|
|
{
|
2009-04-27 03:59:22 +00:00
|
|
|
if (false and
|
|
|
|
s->match(c, SiteMask(1 << MemoryOperand, 0, AnyFrameIndex)))
|
|
|
|
{
|
2009-01-04 22:58:05 +00:00
|
|
|
char buffer[256]; s->toString(c, buffer, 256);
|
2009-04-27 03:59:22 +00:00
|
|
|
fprintf(stderr, "remove %s from %p at %d pop offset 0x%x\n",
|
2009-01-04 22:58:05 +00:00
|
|
|
buffer, v, offsetToFrameIndex
|
2009-04-27 03:59:22 +00:00
|
|
|
(c, static_cast<MemorySite*>(s)->offset),
|
|
|
|
frameIndexToOffset(c, popIndex));
|
2009-01-04 22:58:05 +00:00
|
|
|
}
|
2008-11-01 22:16:18 +00:00
|
|
|
it.remove(c);
|
2008-07-05 20:21:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
void
|
2008-10-06 00:50:59 +00:00
|
|
|
clean(Context* c, Event* e, Stack* stack, Local* locals, Read* reads,
|
|
|
|
unsigned popIndex)
|
2008-05-19 04:31:52 +00:00
|
|
|
{
|
2008-11-01 19:14:13 +00:00
|
|
|
for (FrameIterator it(c, stack, locals); it.hasMore();) {
|
|
|
|
FrameIterator::Element e = it.next(c);
|
|
|
|
clean(c, e.value, popIndex);
|
2008-05-19 04:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (Read* r = reads; r; r = r->eventNext) {
|
2009-01-25 22:03:38 +00:00
|
|
|
popRead(c, e, r->value);
|
2008-11-25 17:34:48 +00:00
|
|
|
}
|
2008-05-19 04:31:52 +00:00
|
|
|
}
|
|
|
|
|
2008-05-31 22:24:04 +00:00
|
|
|
CodePromise*
|
|
|
|
codePromise(Context* c, Event* e)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return e->promises = new(c->zone) CodePromise(c, e->promises);
|
2008-05-31 22:24:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CodePromise*
|
2008-09-09 00:31:19 +00:00
|
|
|
codePromise(Context* c, Promise* offset)
|
2008-05-31 22:24:04 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new (c->zone) CodePromise(c, offset);
|
2008-05-31 22:24:04 +00:00
|
|
|
}
|
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
void
|
|
|
|
append(Context* c, Event* e);
|
|
|
|
|
2008-11-25 17:34:48 +00:00
|
|
|
void
|
|
|
|
saveLocals(Context* c, Event* e)
|
|
|
|
{
|
|
|
|
for (unsigned li = 0; li < c->localFootprint; ++li) {
|
|
|
|
Local* local = e->localsBefore + li;
|
|
|
|
if (local->value) {
|
|
|
|
if (DebugReads) {
|
2009-01-25 22:03:38 +00:00
|
|
|
fprintf(stderr, "local save read %p at %d of %d\n",
|
2009-08-27 00:26:44 +00:00
|
|
|
local->value, local::frameIndex(c, li), totalFrameSize(c));
|
2008-11-25 17:34:48 +00:00
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
addRead(c, e, local->value, SiteMask
|
|
|
|
(1 << MemoryOperand, 0, local::frameIndex(c, li)));
|
2008-11-25 17:34:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-17 02:55:38 +00:00
|
|
|
class CallEvent: public Event {
|
2008-02-11 17:21:41 +00:00
|
|
|
public:
|
2008-05-06 21:13:02 +00:00
|
|
|
CallEvent(Context* c, Value* address, unsigned flags,
|
2008-04-18 04:16:20 +00:00
|
|
|
TraceHandler* traceHandler, Value* result, unsigned resultSize,
|
2008-08-23 18:04:36 +00:00
|
|
|
Stack* argumentStack, unsigned argumentCount,
|
|
|
|
unsigned stackArgumentFootprint):
|
2008-04-17 02:55:38 +00:00
|
|
|
Event(c),
|
|
|
|
address(address),
|
|
|
|
traceHandler(traceHandler),
|
2008-04-17 20:48:26 +00:00
|
|
|
result(result),
|
2009-04-19 22:36:11 +00:00
|
|
|
returnAddressSurrogate(0),
|
|
|
|
framePointerSurrogate(0),
|
2008-10-25 02:12:02 +00:00
|
|
|
popIndex(0),
|
2009-04-27 01:53:42 +00:00
|
|
|
stackArgumentIndex(0),
|
2008-04-17 20:48:26 +00:00
|
|
|
flags(flags),
|
2009-04-19 22:36:11 +00:00
|
|
|
resultSize(resultSize),
|
|
|
|
stackArgumentFootprint(stackArgumentFootprint)
|
2008-02-17 20:57:40 +00:00
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
uint32_t registerMask = c->arch->generalRegisterMask();
|
2009-04-19 22:36:11 +00:00
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
if (argumentCount) {
|
|
|
|
assert(c, (flags & Compiler::TailJump) == 0);
|
|
|
|
assert(c, stackArgumentFootprint == 0);
|
2009-04-19 22:36:11 +00:00
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
Stack* s = argumentStack;
|
|
|
|
unsigned index = 0;
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
unsigned argumentIndex = 0;
|
2008-11-08 22:36:38 +00:00
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
while (true) {
|
2011-08-11 03:33:56 +00:00
|
|
|
unsigned footprint
|
|
|
|
= (argumentIndex + 1 < argumentCount
|
|
|
|
and s->value->nextWord == s->next->value)
|
|
|
|
? 2 : 1;
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
|
2011-08-11 03:33:56 +00:00
|
|
|
if (index % (c->arch->argumentAlignment() ? footprint : 1)) {
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
++ index;
|
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
SiteMask targetMask;
|
2011-08-11 03:33:56 +00:00
|
|
|
if (index + (c->arch->argumentRegisterAlignment() ? footprint : 1)
|
|
|
|
<= c->arch->argumentRegisterCount())
|
|
|
|
{
|
2009-05-03 20:57:11 +00:00
|
|
|
int number = c->arch->argumentRegister(index);
|
2008-11-08 20:47:26 +00:00
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
if (DebugReads) {
|
|
|
|
fprintf(stderr, "reg %d arg read %p\n", number, s->value);
|
2009-04-19 22:36:11 +00:00
|
|
|
}
|
2008-11-08 20:47:26 +00:00
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
targetMask = fixedRegisterMask(number);
|
2009-05-03 20:57:11 +00:00
|
|
|
registerMask &= ~(1 << number);
|
|
|
|
} else {
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
if (index < c->arch->argumentRegisterCount()) {
|
|
|
|
index = c->arch->argumentRegisterCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned frameIndex = index - c->arch->argumentRegisterCount();
|
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
if (DebugReads) {
|
|
|
|
fprintf(stderr, "stack %d arg read %p\n", frameIndex, s->value);
|
2009-04-19 22:36:11 +00:00
|
|
|
}
|
2009-05-03 20:57:11 +00:00
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
targetMask = SiteMask(1 << MemoryOperand, 0, frameIndex);
|
2009-05-03 20:57:11 +00:00
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
addRead(c, this, s->value, targetMask);
|
2009-05-03 20:57:11 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
++ index;
|
|
|
|
|
|
|
|
if ((++ argumentIndex) < argumentCount) {
|
2009-05-03 20:57:11 +00:00
|
|
|
s = s->next;
|
|
|
|
} else {
|
|
|
|
break;
|
2008-11-08 22:36:38 +00:00
|
|
|
}
|
2008-04-19 00:19:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-08 20:47:26 +00:00
|
|
|
if (DebugReads) {
|
|
|
|
fprintf(stderr, "address read %p\n", address);
|
|
|
|
}
|
|
|
|
|
2009-02-26 01:11:41 +00:00
|
|
|
{ bool thunk;
|
|
|
|
uint8_t typeMask;
|
|
|
|
uint64_t planRegisterMask;
|
|
|
|
c->arch->plan
|
2011-08-30 01:00:17 +00:00
|
|
|
((flags & Compiler::Aligned) ? AlignedCall : Call, TargetBytesPerWord,
|
2009-02-26 01:11:41 +00:00
|
|
|
&typeMask, &planRegisterMask, &thunk);
|
|
|
|
|
2009-05-24 06:31:53 +00:00
|
|
|
assert(c, not thunk);
|
2009-02-26 01:11:41 +00:00
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
addRead(c, this, address, SiteMask
|
|
|
|
(typeMask, registerMask & planRegisterMask, AnyFrameIndex));
|
2009-02-26 01:11:41 +00:00
|
|
|
}
|
2008-05-15 20:00:57 +00:00
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
Stack* stack = stackBefore;
|
|
|
|
|
|
|
|
if (stackArgumentFootprint) {
|
2009-10-24 23:18:56 +00:00
|
|
|
RUNTIME_ARRAY(Value*, arguments, stackArgumentFootprint);
|
|
|
|
for (int i = stackArgumentFootprint - 1; i >= 0; --i) {
|
|
|
|
Value* v = stack->value;
|
|
|
|
stack = stack->next;
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if ((TargetBytesPerWord == 8
|
|
|
|
and (v == 0 or (i >= 1 and stack->value == 0)))
|
|
|
|
or (TargetBytesPerWord == 4 and v->nextWord != v))
|
2009-10-24 23:18:56 +00:00
|
|
|
{
|
2011-08-30 01:00:17 +00:00
|
|
|
assert(c, TargetBytesPerWord == 8 or v->nextWord == stack->value);
|
2009-10-24 23:18:56 +00:00
|
|
|
|
|
|
|
RUNTIME_ARRAY_BODY(arguments)[i--] = stack->value;
|
|
|
|
stack = stack->next;
|
|
|
|
}
|
|
|
|
RUNTIME_ARRAY_BODY(arguments)[i] = v;
|
|
|
|
}
|
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
int returnAddressIndex;
|
|
|
|
int framePointerIndex;
|
|
|
|
int frameOffset;
|
|
|
|
|
2009-05-26 05:27:10 +00:00
|
|
|
if (TailCalls and (flags & Compiler::TailJump)) {
|
2009-05-03 20:57:11 +00:00
|
|
|
assert(c, argumentCount == 0);
|
|
|
|
|
|
|
|
int base = frameBase(c);
|
|
|
|
returnAddressIndex = base + c->arch->returnAddressOffset();
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
if (UseFramePointer) {
|
|
|
|
framePointerIndex = base + c->arch->framePointerOffset();
|
|
|
|
} else {
|
|
|
|
framePointerIndex = -1;
|
|
|
|
}
|
2009-05-03 20:57:11 +00:00
|
|
|
|
|
|
|
frameOffset = totalFrameSize(c)
|
2009-10-24 23:18:56 +00:00
|
|
|
- c->arch->argumentFootprint(stackArgumentFootprint);
|
2009-05-03 20:57:11 +00:00
|
|
|
} else {
|
|
|
|
returnAddressIndex = -1;
|
|
|
|
framePointerIndex = -1;
|
2009-10-24 23:18:56 +00:00
|
|
|
frameOffset = 0;
|
2009-05-03 20:57:11 +00:00
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
for (unsigned i = 0; i < stackArgumentFootprint; ++i) {
|
2009-12-02 15:49:10 +00:00
|
|
|
Value* v = RUNTIME_ARRAY_BODY(arguments)[i];
|
2009-10-24 23:18:56 +00:00
|
|
|
if (v) {
|
|
|
|
int frameIndex = i + frameOffset;
|
2009-05-03 20:57:11 +00:00
|
|
|
|
2009-04-19 22:36:11 +00:00
|
|
|
if (DebugReads) {
|
|
|
|
fprintf(stderr, "stack arg read %p at %d of %d\n",
|
2009-10-24 23:18:56 +00:00
|
|
|
v, frameIndex, totalFrameSize(c));
|
2009-04-19 22:36:11 +00:00
|
|
|
}
|
2009-03-31 20:15:08 +00:00
|
|
|
|
2009-04-19 22:36:11 +00:00
|
|
|
if (static_cast<int>(frameIndex) == returnAddressIndex) {
|
2009-10-24 23:18:56 +00:00
|
|
|
returnAddressSurrogate = v;
|
|
|
|
addRead(c, this, v, generalRegisterMask(c));
|
2009-04-19 22:36:11 +00:00
|
|
|
} else if (static_cast<int>(frameIndex) == framePointerIndex) {
|
2009-10-24 23:18:56 +00:00
|
|
|
framePointerSurrogate = v;
|
|
|
|
addRead(c, this, v, generalRegisterMask(c));
|
2009-03-31 20:15:08 +00:00
|
|
|
} else {
|
2009-10-24 23:18:56 +00:00
|
|
|
addRead(c, this, v, SiteMask(1 << MemoryOperand, 0, frameIndex));
|
2009-01-30 01:36:19 +00:00
|
|
|
}
|
|
|
|
}
|
2009-05-03 20:57:11 +00:00
|
|
|
}
|
2009-04-19 22:36:11 +00:00
|
|
|
}
|
|
|
|
|
2009-05-26 05:27:10 +00:00
|
|
|
if ((not TailCalls) or (flags & Compiler::TailJump) == 0) {
|
2009-04-27 03:59:22 +00:00
|
|
|
stackArgumentIndex = c->localFootprint;
|
|
|
|
if (stackBefore) {
|
|
|
|
stackArgumentIndex += stackBefore->index + 1 - stackArgumentFootprint;
|
2009-04-27 01:53:42 +00:00
|
|
|
}
|
|
|
|
|
2009-03-31 20:15:08 +00:00
|
|
|
popIndex
|
2009-04-19 22:36:11 +00:00
|
|
|
= c->alignedFrameSize
|
2009-04-27 03:59:22 +00:00
|
|
|
+ c->parameterFootprint
|
2009-04-19 22:36:11 +00:00
|
|
|
- c->arch->frameFooterSize()
|
2009-04-27 03:59:22 +00:00
|
|
|
- stackArgumentIndex;
|
2009-01-30 01:36:19 +00:00
|
|
|
|
2009-03-31 20:15:08 +00:00
|
|
|
assert(c, static_cast<int>(popIndex) >= 0);
|
2008-11-25 23:00:40 +00:00
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
while (stack) {
|
|
|
|
if (stack->value) {
|
2009-08-27 00:26:44 +00:00
|
|
|
unsigned logicalIndex = local::frameIndex
|
2009-05-03 20:57:11 +00:00
|
|
|
(c, stack->index + c->localFootprint);
|
|
|
|
|
|
|
|
if (DebugReads) {
|
|
|
|
fprintf(stderr, "stack save read %p at %d of %d\n",
|
|
|
|
stack->value, logicalIndex, totalFrameSize(c));
|
|
|
|
}
|
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
addRead(c, this, stack->value, SiteMask
|
|
|
|
(1 << MemoryOperand, 0, logicalIndex));
|
2009-05-03 20:57:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
stack = stack->next;
|
|
|
|
}
|
|
|
|
|
2009-03-31 20:15:08 +00:00
|
|
|
saveLocals(c, this);
|
|
|
|
}
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
2007-12-12 22:19:13 +00:00
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual const char* name() {
|
|
|
|
return "CallEvent";
|
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual void compile(Context* c) {
|
2009-03-31 20:15:08 +00:00
|
|
|
UnaryOperation op;
|
|
|
|
|
2009-05-26 05:27:10 +00:00
|
|
|
if (TailCalls and (flags & Compiler::TailJump)) {
|
2009-10-18 00:18:03 +00:00
|
|
|
if (flags & Compiler::LongJumpOrCall) {
|
|
|
|
if (flags & Compiler::Aligned) {
|
|
|
|
op = AlignedLongJump;
|
|
|
|
} else {
|
|
|
|
op = LongJump;
|
|
|
|
}
|
|
|
|
} else if (flags & Compiler::Aligned) {
|
2009-04-22 01:39:25 +00:00
|
|
|
op = AlignedJump;
|
2009-03-31 20:15:08 +00:00
|
|
|
} else {
|
2009-04-22 01:39:25 +00:00
|
|
|
op = Jump;
|
2009-03-31 20:15:08 +00:00
|
|
|
}
|
|
|
|
|
2009-04-19 22:36:11 +00:00
|
|
|
assert(c, returnAddressSurrogate == 0
|
|
|
|
or returnAddressSurrogate->source->type(c) == RegisterOperand);
|
|
|
|
assert(c, framePointerSurrogate == 0
|
|
|
|
or framePointerSurrogate->source->type(c) == RegisterOperand);
|
|
|
|
|
2009-04-26 02:07:47 +00:00
|
|
|
int ras;
|
|
|
|
if (returnAddressSurrogate) {
|
|
|
|
returnAddressSurrogate->source->freeze(c, returnAddressSurrogate);
|
|
|
|
|
|
|
|
ras = static_cast<RegisterSite*>
|
|
|
|
(returnAddressSurrogate->source)->number;
|
|
|
|
} else {
|
|
|
|
ras = NoRegister;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fps;
|
|
|
|
if (framePointerSurrogate) {
|
|
|
|
framePointerSurrogate->source->freeze(c, framePointerSurrogate);
|
|
|
|
|
|
|
|
fps = static_cast<RegisterSite*>
|
|
|
|
(framePointerSurrogate->source)->number;
|
|
|
|
} else {
|
|
|
|
fps = NoRegister;
|
|
|
|
}
|
2009-04-19 22:36:11 +00:00
|
|
|
|
|
|
|
int offset
|
2009-04-22 01:39:25 +00:00
|
|
|
= static_cast<int>(c->arch->argumentFootprint(stackArgumentFootprint))
|
|
|
|
- static_cast<int>(c->arch->argumentFootprint(c->parameterFootprint));
|
2009-04-19 22:36:11 +00:00
|
|
|
|
|
|
|
c->assembler->popFrameForTailCall(c->alignedFrameSize, offset, ras, fps);
|
2009-10-18 00:18:03 +00:00
|
|
|
} else if (flags & Compiler::LongJumpOrCall) {
|
|
|
|
if (flags & Compiler::Aligned) {
|
|
|
|
op = AlignedLongCall;
|
|
|
|
} else {
|
|
|
|
op = LongCall;
|
|
|
|
}
|
2009-04-19 22:36:11 +00:00
|
|
|
} else if (flags & Compiler::Aligned) {
|
|
|
|
op = AlignedCall;
|
2009-03-31 20:15:08 +00:00
|
|
|
} else {
|
2009-04-19 22:36:11 +00:00
|
|
|
op = Call;
|
2009-03-31 20:15:08 +00:00
|
|
|
}
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
apply(c, op, TargetBytesPerWord, address->source, address->source);
|
2007-12-12 22:19:13 +00:00
|
|
|
|
2008-05-15 23:19:23 +00:00
|
|
|
if (traceHandler) {
|
2010-12-07 22:57:11 +00:00
|
|
|
traceHandler->handleTrace(codePromise(c, c->assembler->offset(true)),
|
2009-04-27 01:53:42 +00:00
|
|
|
stackArgumentIndex);
|
2008-05-15 23:19:23 +00:00
|
|
|
}
|
|
|
|
|
2009-05-26 05:27:10 +00:00
|
|
|
if (TailCalls) {
|
|
|
|
if (flags & Compiler::TailJump) {
|
|
|
|
if (returnAddressSurrogate) {
|
|
|
|
returnAddressSurrogate->source->thaw(c, returnAddressSurrogate);
|
|
|
|
}
|
2009-04-26 02:07:47 +00:00
|
|
|
|
2009-05-26 05:27:10 +00:00
|
|
|
if (framePointerSurrogate) {
|
|
|
|
framePointerSurrogate->source->thaw(c, framePointerSurrogate);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unsigned footprint = c->arch->argumentFootprint
|
|
|
|
(stackArgumentFootprint);
|
|
|
|
|
|
|
|
if (footprint > c->arch->stackAlignmentInWords()) {
|
2009-05-27 01:02:39 +00:00
|
|
|
c->assembler->adjustFrame
|
|
|
|
(footprint - c->arch->stackAlignmentInWords());
|
2009-05-26 05:27:10 +00:00
|
|
|
}
|
2009-04-25 17:47:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-06 00:50:59 +00:00
|
|
|
clean(c, this, stackBefore, localsBefore, reads, popIndex);
|
2008-04-19 00:19:45 +00:00
|
|
|
|
2010-11-26 19:36:43 +00:00
|
|
|
if (resultSize and live(c, result)) {
|
2009-02-28 21:20:43 +00:00
|
|
|
addSite(c, result, registerSite(c, c->arch->returnLow()));
|
2011-08-30 01:00:17 +00:00
|
|
|
if (resultSize > TargetBytesPerWord and live(c, result->nextWord)) {
|
2009-10-10 22:07:30 +00:00
|
|
|
addSite(c, result->nextWord, registerSite(c, c->arch->returnHigh()));
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
2008-04-19 00:19:45 +00:00
|
|
|
}
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
2007-12-23 18:48:22 +00:00
|
|
|
|
2009-04-26 02:54:36 +00:00
|
|
|
virtual bool allExits() {
|
2009-04-26 01:51:33 +00:00
|
|
|
return (flags & Compiler::TailJump) != 0;
|
|
|
|
}
|
|
|
|
|
2008-04-17 02:55:38 +00:00
|
|
|
Value* address;
|
|
|
|
TraceHandler* traceHandler;
|
|
|
|
Value* result;
|
2009-04-19 22:36:11 +00:00
|
|
|
Value* returnAddressSurrogate;
|
|
|
|
Value* framePointerSurrogate;
|
2008-10-06 00:50:59 +00:00
|
|
|
unsigned popIndex;
|
2009-04-27 01:53:42 +00:00
|
|
|
unsigned stackArgumentIndex;
|
2008-04-17 20:48:26 +00:00
|
|
|
unsigned flags;
|
2008-04-18 04:16:20 +00:00
|
|
|
unsigned resultSize;
|
2009-04-19 22:36:11 +00:00
|
|
|
unsigned stackArgumentFootprint;
|
2008-02-11 17:21:41 +00:00
|
|
|
};
|
2007-12-12 22:19:13 +00:00
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
void
|
2008-05-06 21:13:02 +00:00
|
|
|
appendCall(Context* c, Value* address, unsigned flags,
|
2008-04-18 04:16:20 +00:00
|
|
|
TraceHandler* traceHandler, Value* result, unsigned resultSize,
|
2008-08-23 18:04:36 +00:00
|
|
|
Stack* argumentStack, unsigned argumentCount,
|
|
|
|
unsigned stackArgumentFootprint)
|
2008-02-11 17:21:41 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone)
|
2008-10-14 00:18:18 +00:00
|
|
|
CallEvent(c, address, flags, traceHandler, result,
|
|
|
|
resultSize, argumentStack, argumentCount,
|
|
|
|
stackArgumentFootprint));
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
2007-12-23 18:48:22 +00:00
|
|
|
|
2009-04-26 01:51:33 +00:00
|
|
|
bool
|
2009-04-26 02:54:36 +00:00
|
|
|
unreachable(Event* event)
|
2009-04-26 01:51:33 +00:00
|
|
|
{
|
|
|
|
for (Link* p = event->predecessors; p; p = p->nextPredecessor) {
|
2009-04-26 02:54:36 +00:00
|
|
|
if (not p->predecessor->allExits()) return false;
|
2009-04-26 01:51:33 +00:00
|
|
|
}
|
2009-06-12 15:45:29 +00:00
|
|
|
return event->predecessors != 0;
|
2009-04-26 01:51:33 +00:00
|
|
|
}
|
|
|
|
|
2008-04-17 02:55:38 +00:00
|
|
|
class ReturnEvent: public Event {
|
2008-02-17 20:57:40 +00:00
|
|
|
public:
|
2008-04-17 02:55:38 +00:00
|
|
|
ReturnEvent(Context* c, unsigned size, Value* value):
|
|
|
|
Event(c), value(value)
|
|
|
|
{
|
|
|
|
if (value) {
|
2009-10-04 19:56:48 +00:00
|
|
|
addReads(c, this, value, size, fixedRegisterMask(c->arch->returnLow()),
|
|
|
|
fixedRegisterMask(c->arch->returnHigh()));
|
2008-04-17 02:55:38 +00:00
|
|
|
}
|
2008-03-15 20:24:04 +00:00
|
|
|
}
|
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual const char* name() {
|
|
|
|
return "ReturnEvent";
|
|
|
|
}
|
2008-02-17 20:57:40 +00:00
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual void compile(Context* c) {
|
2009-01-25 22:03:38 +00:00
|
|
|
for (Read* r = reads; r; r = r->eventNext) {
|
|
|
|
popRead(c, this, r->value);
|
2008-04-19 00:19:45 +00:00
|
|
|
}
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2009-04-26 02:54:36 +00:00
|
|
|
if (not unreachable(this)) {
|
2009-04-26 01:51:33 +00:00
|
|
|
c->assembler->popFrameAndPopArgumentsAndReturn
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
(c->alignedFrameSize,
|
|
|
|
c->arch->argumentFootprint(c->parameterFootprint));
|
2009-04-26 01:51:33 +00:00
|
|
|
}
|
2008-02-17 20:57:40 +00:00
|
|
|
}
|
|
|
|
|
2008-04-17 02:55:38 +00:00
|
|
|
Value* value;
|
2008-02-17 20:57:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2008-04-17 22:07:32 +00:00
|
|
|
appendReturn(Context* c, unsigned size, Value* value)
|
2008-02-17 20:57:40 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone) ReturnEvent(c, size, value));
|
2008-02-17 20:57:40 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
void
|
2009-03-06 17:56:11 +00:00
|
|
|
maybeMove(Context* c, BinaryOperation type, unsigned srcSize,
|
|
|
|
unsigned srcSelectSize, Value* src, unsigned dstSize, Value* dst,
|
|
|
|
const SiteMask& dstMask)
|
2009-01-25 22:03:38 +00:00
|
|
|
{
|
2010-11-26 19:36:43 +00:00
|
|
|
Read* read = live(c, dst);
|
2009-01-25 22:03:38 +00:00
|
|
|
bool isStore = read == 0;
|
2008-03-15 20:24:04 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
Site* target;
|
|
|
|
if (dst->target) {
|
|
|
|
target = dst->target;
|
|
|
|
} else if (isStore) {
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
target = pickTargetSite(c, read);
|
2008-09-15 02:28:42 +00:00
|
|
|
}
|
2008-03-15 20:24:04 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
unsigned cost = src->source->copyCost(c, target);
|
|
|
|
|
2009-03-14 22:47:26 +00:00
|
|
|
if (srcSelectSize < dstSize) cost = 1;
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2009-02-09 01:58:33 +00:00
|
|
|
if (cost) {
|
2009-10-24 23:18:56 +00:00
|
|
|
// todo: let c->arch->planMove decide this:
|
2009-01-25 22:03:38 +00:00
|
|
|
bool useTemporary = ((target->type(c) == MemoryOperand
|
|
|
|
and src->source->type(c) == MemoryOperand)
|
2009-03-14 22:47:26 +00:00
|
|
|
or (srcSelectSize < dstSize
|
2009-01-25 22:03:38 +00:00
|
|
|
and target->type(c) != RegisterOperand));
|
|
|
|
|
2009-03-14 22:47:26 +00:00
|
|
|
src->source->freeze(c, src);
|
|
|
|
|
2009-02-09 01:58:33 +00:00
|
|
|
addSite(c, dst, target);
|
|
|
|
|
2009-03-14 22:47:26 +00:00
|
|
|
src->source->thaw(c, src);
|
|
|
|
|
2009-03-06 19:14:37 +00:00
|
|
|
bool addOffset = srcSize != srcSelectSize
|
|
|
|
and c->arch->bigEndian()
|
|
|
|
and src->source->type(c) == MemoryOperand;
|
|
|
|
|
|
|
|
if (addOffset) {
|
2009-03-06 17:56:11 +00:00
|
|
|
static_cast<MemorySite*>(src->source)->offset
|
|
|
|
+= (srcSize - srcSelectSize);
|
|
|
|
}
|
|
|
|
|
2009-03-14 02:55:41 +00:00
|
|
|
target->freeze(c, dst);
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-03-07 23:32:05 +00:00
|
|
|
src->source->freeze(c, src);
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
apply(c, type, min(srcSelectSize, dstSize), src->source, src->source,
|
|
|
|
dstSize, target, target);
|
2009-03-07 23:32:05 +00:00
|
|
|
|
|
|
|
src->source->thaw(c, src);
|
2009-01-03 21:34:45 +00:00
|
|
|
} else {
|
2009-03-01 22:41:03 +00:00
|
|
|
// pick a temporary register which is valid as both a
|
|
|
|
// destination and a source for the moves we need to perform:
|
2009-10-24 23:18:56 +00:00
|
|
|
|
|
|
|
removeSite(c, dst, target);
|
2008-11-12 00:39:26 +00:00
|
|
|
|
2009-03-01 22:41:03 +00:00
|
|
|
bool thunk;
|
|
|
|
uint8_t srcTypeMask;
|
|
|
|
uint64_t srcRegisterMask;
|
|
|
|
|
2009-08-06 16:14:31 +00:00
|
|
|
c->arch->planSource(type, dstSize, &srcTypeMask, &srcRegisterMask,
|
2009-10-24 23:18:56 +00:00
|
|
|
dstSize, &thunk);
|
2009-03-01 22:41:03 +00:00
|
|
|
|
2009-11-30 02:17:08 +00:00
|
|
|
if (src->type == ValueGeneral) {
|
|
|
|
srcRegisterMask &= c->arch->generalRegisterMask();
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
assert(c, thunk == 0);
|
2009-03-01 22:41:03 +00:00
|
|
|
assert(c, dstMask.typeMask & srcTypeMask & (1 << RegisterOperand));
|
|
|
|
|
|
|
|
Site* tmpTarget = freeRegisterSite
|
|
|
|
(c, dstMask.registerMask & srcRegisterMask);
|
2008-11-12 00:39:26 +00:00
|
|
|
|
2009-03-07 23:32:05 +00:00
|
|
|
src->source->freeze(c, src);
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
addSite(c, dst, tmpTarget);
|
2008-08-28 22:43:35 +00:00
|
|
|
|
2009-03-14 02:55:41 +00:00
|
|
|
tmpTarget->freeze(c, dst);
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-10-04 17:26:35 +00:00
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
apply(c, type, srcSelectSize, src->source, src->source,
|
|
|
|
dstSize, tmpTarget, tmpTarget);
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2009-03-14 02:55:41 +00:00
|
|
|
tmpTarget->thaw(c, dst);
|
|
|
|
|
2009-03-07 23:32:05 +00:00
|
|
|
src->source->thaw(c, src);
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
if (useTemporary or isStore) {
|
2008-11-11 02:12:36 +00:00
|
|
|
if (DebugMoves) {
|
2009-01-25 22:03:38 +00:00
|
|
|
char srcb[256]; tmpTarget->toString(c, srcb, 256);
|
2008-11-11 02:12:36 +00:00
|
|
|
char dstb[256]; target->toString(c, dstb, 256);
|
|
|
|
fprintf(stderr, "move %s to %s for %p to %p\n",
|
|
|
|
srcb, dstb, src, dst);
|
|
|
|
}
|
2008-10-19 00:15:57 +00:00
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
addSite(c, dst, target);
|
|
|
|
|
2009-03-07 23:32:05 +00:00
|
|
|
tmpTarget->freeze(c, dst);
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
apply(c, Move, dstSize, tmpTarget, tmpTarget, dstSize, target, target);
|
2008-05-16 16:01:24 +00:00
|
|
|
|
2009-03-07 23:32:05 +00:00
|
|
|
tmpTarget->thaw(c, dst);
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
if (isStore) {
|
|
|
|
removeSite(c, dst, tmpTarget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-03-06 19:14:37 +00:00
|
|
|
|
2009-03-14 02:55:41 +00:00
|
|
|
target->thaw(c, dst);
|
|
|
|
|
2009-03-06 19:14:37 +00:00
|
|
|
if (addOffset) {
|
|
|
|
static_cast<MemorySite*>(src->source)->offset
|
|
|
|
-= (srcSize - srcSelectSize);
|
|
|
|
}
|
2009-01-25 22:03:38 +00:00
|
|
|
} else {
|
|
|
|
target = src->source;
|
2008-05-16 16:01:24 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
if (DebugMoves) {
|
|
|
|
char dstb[256]; target->toString(c, dstb, 256);
|
|
|
|
fprintf(stderr, "null move in %s for %p to %p\n", dstb, src, dst);
|
|
|
|
}
|
|
|
|
}
|
2008-10-19 00:15:57 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
if (isStore) {
|
|
|
|
removeSite(c, dst, target);
|
|
|
|
}
|
|
|
|
}
|
2008-05-16 16:01:24 +00:00
|
|
|
|
2009-11-30 22:08:59 +00:00
|
|
|
Site*
|
|
|
|
pickMatchOrMove(Context* c, Read* r, Site* nextWord, unsigned index,
|
|
|
|
bool intersectRead)
|
|
|
|
{
|
|
|
|
Site* s = pickSite(c, r->value, nextWord, index, true);
|
|
|
|
SiteMask mask;
|
|
|
|
if (intersectRead) {
|
|
|
|
r->intersect(&mask);
|
|
|
|
}
|
|
|
|
if (s and s->match(c, mask)) {
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pickSiteOrMove
|
|
|
|
(c, r->value, intersect(mask, nextWord->nextWordMask(c, index)),
|
|
|
|
true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Site*
|
|
|
|
pickSiteOrMove(Context* c, Value* src, Value* dst, Site* nextWord,
|
|
|
|
unsigned index)
|
2009-11-28 04:15:12 +00:00
|
|
|
{
|
2010-11-26 19:36:43 +00:00
|
|
|
if (live(c, dst)) {
|
|
|
|
Read* read = live(c, src);
|
2009-11-30 22:08:59 +00:00
|
|
|
Site* s;
|
|
|
|
if (nextWord) {
|
|
|
|
s = pickMatchOrMove(c, read, nextWord, index, false);
|
|
|
|
} else {
|
2009-12-01 02:06:01 +00:00
|
|
|
s = pickSourceSite(c, read, 0, 0, 0, false, true, true);
|
2009-11-30 15:10:34 +00:00
|
|
|
|
2009-11-30 22:08:59 +00:00
|
|
|
if (s == 0 or s->isVolatile(c)) {
|
|
|
|
s = maybeMove(c, read, false, true);
|
|
|
|
}
|
2009-11-30 15:10:34 +00:00
|
|
|
}
|
2009-11-30 22:08:59 +00:00
|
|
|
assert(c, s);
|
2009-11-30 15:10:34 +00:00
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
addBuddy(src, dst);
|
|
|
|
|
|
|
|
if (src->source->isVolatile(c)) {
|
|
|
|
removeSite(c, src, src->source);
|
|
|
|
}
|
2009-11-30 22:08:59 +00:00
|
|
|
|
|
|
|
return s;
|
|
|
|
} else {
|
|
|
|
return 0;
|
2009-11-28 04:15:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
Value*
|
2009-08-10 19:20:23 +00:00
|
|
|
value(Context* c, ValueType type, Site* site = 0, Site* target = 0)
|
2009-02-01 23:10:56 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) Value(site, target, type);
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-09-26 19:43:44 +00:00
|
|
|
grow(Context* c, Value* v)
|
2009-02-01 23:10:56 +00:00
|
|
|
{
|
2009-10-10 22:07:30 +00:00
|
|
|
assert(c, v->nextWord == v);
|
2009-02-01 23:10:56 +00:00
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
Value* next = value(c, v->type);
|
2009-10-10 22:07:30 +00:00
|
|
|
v->nextWord = next;
|
|
|
|
next->nextWord = v;
|
|
|
|
next->wordIndex = 1;
|
2009-09-26 19:43:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
split(Context* c, Value* v)
|
|
|
|
{
|
|
|
|
grow(c, v);
|
|
|
|
for (SiteIterator it(c, v); it.hasMore();) {
|
2009-02-01 23:10:56 +00:00
|
|
|
Site* s = it.next();
|
|
|
|
removeSite(c, v, s);
|
|
|
|
|
|
|
|
addSite(c, v, s->copyLow(c));
|
2009-10-10 22:07:30 +00:00
|
|
|
addSite(c, v->nextWord, s->copyHigh(c));
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
maybeSplit(Context* c, Value* v)
|
|
|
|
{
|
2009-10-10 22:07:30 +00:00
|
|
|
if (v->nextWord == v) {
|
2009-02-01 23:10:56 +00:00
|
|
|
split(c, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
class MoveEvent: public Event {
|
|
|
|
public:
|
2009-03-06 17:56:11 +00:00
|
|
|
MoveEvent(Context* c, BinaryOperation type, unsigned srcSize,
|
|
|
|
unsigned srcSelectSize, Value* src, unsigned dstSize, Value* dst,
|
2009-10-04 19:56:48 +00:00
|
|
|
const SiteMask& srcLowMask, const SiteMask& srcHighMask):
|
2009-03-06 17:56:11 +00:00
|
|
|
Event(c), type(type), srcSize(srcSize), srcSelectSize(srcSelectSize),
|
2009-10-04 19:56:48 +00:00
|
|
|
src(src), dstSize(dstSize), dst(dst)
|
2009-01-25 22:03:38 +00:00
|
|
|
{
|
2009-03-06 17:56:11 +00:00
|
|
|
assert(c, srcSelectSize <= srcSize);
|
|
|
|
|
2009-04-07 00:34:12 +00:00
|
|
|
bool noop = srcSelectSize >= dstSize;
|
2009-02-01 23:10:56 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (dstSize > TargetBytesPerWord) {
|
2009-02-01 23:10:56 +00:00
|
|
|
grow(c, dst);
|
|
|
|
}
|
2009-04-07 00:34:12 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (srcSelectSize > TargetBytesPerWord) {
|
2009-04-07 00:34:12 +00:00
|
|
|
maybeSplit(c, src);
|
|
|
|
}
|
2009-10-04 19:56:48 +00:00
|
|
|
|
|
|
|
addReads(c, this, src, srcSelectSize, srcLowMask, noop ? dst : 0,
|
2011-08-30 01:00:17 +00:00
|
|
|
srcHighMask,
|
|
|
|
noop and dstSize > TargetBytesPerWord ? dst->nextWord : 0);
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
2008-10-19 00:15:57 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual const char* name() {
|
|
|
|
return "MoveEvent";
|
|
|
|
}
|
2008-12-20 21:55:45 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
virtual void compile(Context* c) {
|
2009-10-04 19:56:48 +00:00
|
|
|
uint8_t dstTypeMask;
|
|
|
|
uint64_t dstRegisterMask;
|
|
|
|
|
|
|
|
c->arch->planDestination
|
|
|
|
(type,
|
|
|
|
srcSelectSize,
|
|
|
|
1 << src->source->type(c),
|
2009-10-10 22:07:30 +00:00
|
|
|
(static_cast<uint64_t>(src->nextWord->source->registerMask(c)) << 32)
|
2009-10-04 19:56:48 +00:00
|
|
|
| static_cast<uint64_t>(src->source->registerMask(c)),
|
|
|
|
dstSize,
|
|
|
|
&dstTypeMask,
|
|
|
|
&dstRegisterMask);
|
|
|
|
|
|
|
|
SiteMask dstLowMask(dstTypeMask, dstRegisterMask, AnyFrameIndex);
|
|
|
|
SiteMask dstHighMask(dstTypeMask, dstRegisterMask >> 32, AnyFrameIndex);
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (srcSelectSize >= TargetBytesPerWord
|
|
|
|
and dstSize >= TargetBytesPerWord
|
2009-11-28 04:15:12 +00:00
|
|
|
and srcSelectSize >= dstSize)
|
|
|
|
{
|
|
|
|
if (dst->target) {
|
2012-06-26 14:39:23 +00:00
|
|
|
if (dstSize > TargetBytesPerWord) {
|
|
|
|
if (src->source->registerSize(c) > TargetBytesPerWord) {
|
|
|
|
apply(c, Move, srcSelectSize, src->source, src->source,
|
|
|
|
dstSize, dst->target, dst->target);
|
|
|
|
|
|
|
|
if (live(c, dst) == 0) {
|
|
|
|
removeSite(c, dst, dst->target);
|
|
|
|
if (dstSize > TargetBytesPerWord) {
|
|
|
|
removeSite(c, dst->nextWord, dst->nextWord->target);
|
|
|
|
}
|
2009-11-30 22:08:59 +00:00
|
|
|
}
|
2012-06-26 14:39:23 +00:00
|
|
|
} else {
|
|
|
|
src->nextWord->source->freeze(c, src->nextWord);
|
|
|
|
|
|
|
|
maybeMove(c, Move, TargetBytesPerWord, TargetBytesPerWord, src,
|
|
|
|
TargetBytesPerWord, dst, dstLowMask);
|
|
|
|
|
|
|
|
src->nextWord->source->thaw(c, src->nextWord);
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
maybeMove
|
|
|
|
(c, Move, TargetBytesPerWord, TargetBytesPerWord, src->nextWord,
|
|
|
|
TargetBytesPerWord, dst->nextWord, dstHighMask);
|
2009-11-30 15:10:34 +00:00
|
|
|
}
|
2012-06-26 14:39:23 +00:00
|
|
|
} else {
|
|
|
|
maybeMove(c, Move, TargetBytesPerWord, TargetBytesPerWord, src,
|
|
|
|
TargetBytesPerWord, dst, dstLowMask);
|
2009-11-28 04:15:12 +00:00
|
|
|
}
|
|
|
|
} else {
|
2009-11-30 22:08:59 +00:00
|
|
|
Site* low = pickSiteOrMove(c, src, dst, 0, 0);
|
2011-08-30 01:00:17 +00:00
|
|
|
if (dstSize > TargetBytesPerWord) {
|
2009-11-30 22:08:59 +00:00
|
|
|
pickSiteOrMove(c, src->nextWord, dst->nextWord, low, 1);
|
2009-11-28 04:15:12 +00:00
|
|
|
}
|
|
|
|
}
|
2011-08-30 01:00:17 +00:00
|
|
|
} else if (srcSelectSize <= TargetBytesPerWord
|
|
|
|
and dstSize <= TargetBytesPerWord)
|
|
|
|
{
|
2009-03-06 17:56:11 +00:00
|
|
|
maybeMove(c, type, srcSize, srcSelectSize, src, dstSize, dst,
|
|
|
|
dstLowMask);
|
2008-12-21 21:41:56 +00:00
|
|
|
} else {
|
2011-08-30 01:00:17 +00:00
|
|
|
assert(c, srcSize == TargetBytesPerWord);
|
|
|
|
assert(c, srcSelectSize == TargetBytesPerWord);
|
2008-12-21 21:41:56 +00:00
|
|
|
|
2010-11-26 19:36:43 +00:00
|
|
|
if (dst->nextWord->target or live(c, dst->nextWord)) {
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(c, dstLowMask.typeMask & (1 << RegisterOperand));
|
2008-12-21 21:41:56 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
Site* low = freeRegisterSite(c, dstLowMask.registerMask);
|
|
|
|
|
2009-02-03 02:13:02 +00:00
|
|
|
src->source->freeze(c, src);
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
addSite(c, dst, low);
|
2009-03-14 02:55:41 +00:00
|
|
|
|
|
|
|
low->freeze(c, dst);
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2009-02-03 02:13:02 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
apply(c, Move, TargetBytesPerWord, src->source, src->source,
|
|
|
|
TargetBytesPerWord, low, low);
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2009-03-14 02:55:41 +00:00
|
|
|
low->thaw(c, dst);
|
|
|
|
|
2009-03-07 23:32:05 +00:00
|
|
|
src->source->thaw(c, src);
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(c, dstHighMask.typeMask & (1 << RegisterOperand));
|
|
|
|
|
|
|
|
Site* high = freeRegisterSite(c, dstHighMask.registerMask);
|
|
|
|
|
2009-02-03 02:13:02 +00:00
|
|
|
low->freeze(c, dst);
|
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
addSite(c, dst->nextWord, high);
|
2009-03-14 02:55:41 +00:00
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
high->freeze(c, dst->nextWord);
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2009-02-03 02:13:02 +00:00
|
|
|
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",
|
2009-10-10 22:07:30 +00:00
|
|
|
srcb, dstb, dst, dst->nextWord);
|
2009-02-03 02:13:02 +00:00
|
|
|
}
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
apply(c, Move, TargetBytesPerWord, low, low, dstSize, low, high);
|
2009-03-07 23:32:05 +00:00
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
high->thaw(c, dst->nextWord);
|
2009-03-14 02:55:41 +00:00
|
|
|
|
2009-03-07 23:32:05 +00:00
|
|
|
low->thaw(c, dst);
|
2009-01-25 22:03:38 +00:00
|
|
|
} else {
|
2009-11-30 22:08:59 +00:00
|
|
|
pickSiteOrMove(c, src, dst, 0, 0);
|
2008-12-21 21:41:56 +00:00
|
|
|
}
|
2008-04-27 20:15:18 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
for (Read* r = reads; r; r = r->eventNext) {
|
|
|
|
popRead(c, this, r->value);
|
2008-04-20 19:35:36 +00:00
|
|
|
}
|
2007-12-11 21:26:59 +00:00
|
|
|
}
|
|
|
|
|
2008-04-17 02:55:38 +00:00
|
|
|
BinaryOperation type;
|
2008-08-16 17:45:36 +00:00
|
|
|
unsigned srcSize;
|
2009-03-06 17:56:11 +00:00
|
|
|
unsigned srcSelectSize;
|
2008-04-17 02:55:38 +00:00
|
|
|
Value* src;
|
2008-08-16 17:45:36 +00:00
|
|
|
unsigned dstSize;
|
2008-04-17 02:55:38 +00:00
|
|
|
Value* dst;
|
2008-02-11 17:21:41 +00:00
|
|
|
};
|
2007-12-11 21:26:59 +00:00
|
|
|
|
|
|
|
void
|
2009-03-06 17:56:11 +00:00
|
|
|
appendMove(Context* c, BinaryOperation type, unsigned srcSize,
|
|
|
|
unsigned srcSelectSize, Value* src, unsigned dstSize, Value* dst)
|
2007-12-11 21:26:59 +00:00
|
|
|
{
|
2008-05-31 22:14:27 +00:00
|
|
|
bool thunk;
|
2008-08-28 22:43:35 +00:00
|
|
|
uint8_t srcTypeMask;
|
|
|
|
uint64_t srcRegisterMask;
|
2008-05-04 20:55:34 +00:00
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
c->arch->planSource
|
|
|
|
(type, srcSelectSize, &srcTypeMask, &srcRegisterMask, dstSize, &thunk);
|
2008-05-04 20:55:34 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(c, not thunk);
|
2008-05-04 20:55:34 +00:00
|
|
|
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone)
|
2008-10-14 00:18:18 +00:00
|
|
|
MoveEvent
|
2009-03-06 17:56:11 +00:00
|
|
|
(c, type, srcSize, srcSelectSize, src, dstSize, dst,
|
2009-01-25 22:03:38 +00:00
|
|
|
SiteMask(srcTypeMask, srcRegisterMask, AnyFrameIndex),
|
2009-10-04 19:56:48 +00:00
|
|
|
SiteMask(srcTypeMask, srcRegisterMask >> 32, AnyFrameIndex)));
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
2007-12-20 01:42:12 +00:00
|
|
|
|
2008-06-11 00:17:44 +00:00
|
|
|
ConstantSite*
|
|
|
|
findConstantSite(Context* c, Value* v)
|
|
|
|
{
|
2009-09-26 19:43:44 +00:00
|
|
|
for (SiteIterator it(c, v); it.hasMore();) {
|
2008-11-01 22:16:18 +00:00
|
|
|
Site* s = it.next();
|
2008-06-11 00:17:44 +00:00
|
|
|
if (s->type(c) == ConstantOperand) {
|
|
|
|
return static_cast<ConstantSite*>(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
void
|
2009-11-28 04:15:12 +00:00
|
|
|
preserve(Context* c, Value* v, Read* r, Site* s)
|
2009-01-25 22:03:38 +00:00
|
|
|
{
|
|
|
|
s->freeze(c, v);
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
maybeMove(c, r, false, true, 0);
|
2009-01-25 22:03:38 +00:00
|
|
|
|
|
|
|
s->thaw(c, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
Site*
|
|
|
|
getTarget(Context* c, Value* value, Value* result, const SiteMask& resultMask)
|
|
|
|
{
|
2009-03-01 02:08:14 +00:00
|
|
|
Site* s;
|
|
|
|
Value* v;
|
2009-03-14 20:17:32 +00:00
|
|
|
Read* r = liveNext(c, value);
|
2009-09-20 21:43:32 +00:00
|
|
|
if (value->source->match
|
|
|
|
(c, static_cast<const SiteMask&>(resultMask))
|
|
|
|
and (r == 0 or value->source->loneMatch
|
|
|
|
(c, static_cast<const SiteMask&>(resultMask))))
|
|
|
|
{
|
2009-03-01 02:08:14 +00:00
|
|
|
s = value->source;
|
|
|
|
v = value;
|
2009-10-10 22:07:30 +00:00
|
|
|
if (r and uniqueSite(c, v, s)) {
|
2009-11-28 04:15:12 +00:00
|
|
|
preserve(c, v, r, s);
|
2009-03-14 20:17:32 +00:00
|
|
|
}
|
2009-01-25 22:03:38 +00:00
|
|
|
} else {
|
2009-04-08 00:55:43 +00:00
|
|
|
SingleRead r(resultMask, 0);
|
2009-10-04 22:10:36 +00:00
|
|
|
r.value = result;
|
2009-11-28 18:17:17 +00:00
|
|
|
r.successor_ = result;
|
2009-03-07 00:37:54 +00:00
|
|
|
s = pickTargetSite(c, &r, true);
|
2009-03-01 02:08:14 +00:00
|
|
|
v = result;
|
2009-01-25 22:03:38 +00:00
|
|
|
addSite(c, result, s);
|
|
|
|
}
|
2009-03-01 02:08:14 +00:00
|
|
|
|
|
|
|
removeSite(c, v, s);
|
|
|
|
|
|
|
|
s->freeze(c, v);
|
|
|
|
|
|
|
|
return s;
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
freezeSource(Context* c, unsigned size, Value* v)
|
|
|
|
{
|
|
|
|
v->source->freeze(c, v);
|
2011-08-30 01:00:17 +00:00
|
|
|
if (size > TargetBytesPerWord) {
|
2009-10-10 22:07:30 +00:00
|
|
|
v->nextWord->source->freeze(c, v->nextWord);
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
thawSource(Context* c, unsigned size, Value* v)
|
|
|
|
{
|
|
|
|
v->source->thaw(c, v);
|
2011-08-30 01:00:17 +00:00
|
|
|
if (size > TargetBytesPerWord) {
|
2009-10-10 22:07:30 +00:00
|
|
|
v->nextWord->source->thaw(c, v->nextWord);
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class CombineEvent: public Event {
|
|
|
|
public:
|
2008-08-16 17:45:36 +00:00
|
|
|
CombineEvent(Context* c, TernaryOperation type,
|
|
|
|
unsigned firstSize, Value* first,
|
|
|
|
unsigned secondSize, Value* second,
|
|
|
|
unsigned resultSize, Value* result,
|
2009-01-25 22:03:38 +00:00
|
|
|
const SiteMask& firstLowMask,
|
|
|
|
const SiteMask& firstHighMask,
|
|
|
|
const SiteMask& secondLowMask,
|
2009-08-06 16:14:31 +00:00
|
|
|
const SiteMask& secondHighMask):
|
2008-08-16 17:45:36 +00:00
|
|
|
Event(c), type(type), firstSize(firstSize), first(first),
|
|
|
|
secondSize(secondSize), second(second), resultSize(resultSize),
|
2009-08-06 16:14:31 +00:00
|
|
|
result(result)
|
2008-02-17 20:57:40 +00:00
|
|
|
{
|
2009-10-04 19:56:48 +00:00
|
|
|
addReads(c, this, first, firstSize, firstLowMask, firstHighMask);
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (resultSize > TargetBytesPerWord) {
|
2009-02-01 23:10:56 +00:00
|
|
|
grow(c, result);
|
|
|
|
}
|
2009-04-07 00:34:12 +00:00
|
|
|
|
2009-08-10 19:20:23 +00:00
|
|
|
bool condensed = c->arch->alwaysCondensed(type);
|
2009-04-07 00:34:12 +00:00
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
addReads(c, this, second, secondSize,
|
|
|
|
secondLowMask, condensed ? result : 0,
|
2009-10-10 22:07:30 +00:00
|
|
|
secondHighMask, condensed ? result->nextWord : 0);
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
2007-12-16 23:52:38 +00:00
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual const char* name() {
|
|
|
|
return "CombineEvent";
|
|
|
|
}
|
2008-02-17 20:57:40 +00:00
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual void compile(Context* c) {
|
2009-10-10 22:07:30 +00:00
|
|
|
assert(c, first->source->type(c) == first->nextWord->source->type(c));
|
2009-10-04 22:10:36 +00:00
|
|
|
|
2010-11-26 19:36:43 +00:00
|
|
|
// if (second->source->type(c) != second->nextWord->source->type(c)) {
|
|
|
|
// fprintf(stderr, "%p %p %d : %p %p %d\n",
|
|
|
|
// second, second->source, second->source->type(c),
|
|
|
|
// second->nextWord, second->nextWord->source,
|
|
|
|
// second->nextWord->source->type(c));
|
|
|
|
// }
|
2009-10-04 22:10:36 +00:00
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
assert(c, second->source->type(c) == second->nextWord->source->type(c));
|
2009-10-04 19:56:48 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
freezeSource(c, firstSize, first);
|
2009-08-06 16:14:31 +00:00
|
|
|
|
|
|
|
uint8_t cTypeMask;
|
|
|
|
uint64_t cRegisterMask;
|
2009-10-04 19:56:48 +00:00
|
|
|
|
2009-09-20 21:43:32 +00:00
|
|
|
c->arch->planDestination
|
2009-10-04 19:56:48 +00:00
|
|
|
(type,
|
|
|
|
firstSize,
|
|
|
|
1 << first->source->type(c),
|
2009-10-10 22:07:30 +00:00
|
|
|
(static_cast<uint64_t>(first->nextWord->source->registerMask(c)) << 32)
|
2009-10-04 19:56:48 +00:00
|
|
|
| static_cast<uint64_t>(first->source->registerMask(c)),
|
|
|
|
secondSize,
|
|
|
|
1 << second->source->type(c),
|
2009-10-10 22:07:30 +00:00
|
|
|
(static_cast<uint64_t>(second->nextWord->source->registerMask(c)) << 32)
|
2009-10-04 19:56:48 +00:00
|
|
|
| static_cast<uint64_t>(second->source->registerMask(c)),
|
|
|
|
resultSize,
|
|
|
|
&cTypeMask,
|
|
|
|
&cRegisterMask);
|
|
|
|
|
2009-08-06 16:14:31 +00:00
|
|
|
SiteMask resultLowMask(cTypeMask, cRegisterMask, AnyFrameIndex);
|
|
|
|
SiteMask resultHighMask(cTypeMask, cRegisterMask >> 32, AnyFrameIndex);
|
2009-01-11 18:48:02 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
Site* low = getTarget(c, second, result, resultLowMask);
|
2009-10-04 19:56:48 +00:00
|
|
|
unsigned lowSize = low->registerSize(c);
|
2009-01-25 22:03:38 +00:00
|
|
|
Site* high
|
2009-10-04 19:56:48 +00:00
|
|
|
= (resultSize > lowSize
|
2009-10-10 22:07:30 +00:00
|
|
|
? getTarget(c, second->nextWord, result->nextWord, resultHighMask)
|
2009-09-26 19:43:44 +00:00
|
|
|
: low);
|
2008-04-29 16:25:20 +00:00
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
// fprintf(stderr, "combine %p:%p and %p:%p into %p:%p\n",
|
|
|
|
// first, first->nextWord,
|
|
|
|
// second, second->nextWord,
|
|
|
|
// result, result->nextWord);
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
apply(c, type,
|
2009-10-10 22:07:30 +00:00
|
|
|
firstSize, first->source, first->nextWord->source,
|
|
|
|
secondSize, second->source, second->nextWord->source,
|
2009-01-25 22:03:38 +00:00
|
|
|
resultSize, low, high);
|
2008-04-19 00:19:45 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
thawSource(c, firstSize, first);
|
2009-01-11 18:48:02 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
for (Read* r = reads; r; r = r->eventNext) {
|
|
|
|
popRead(c, this, r->value);
|
|
|
|
}
|
2008-09-23 21:18:41 +00:00
|
|
|
|
2009-03-01 02:08:14 +00:00
|
|
|
low->thaw(c, second);
|
2009-10-04 19:56:48 +00:00
|
|
|
if (resultSize > lowSize) {
|
2009-10-10 22:07:30 +00:00
|
|
|
high->thaw(c, second->nextWord);
|
2009-03-01 02:08:14 +00:00
|
|
|
}
|
2009-01-11 18:48:02 +00:00
|
|
|
|
2010-11-26 19:36:43 +00:00
|
|
|
if (live(c, result)) {
|
2009-03-01 02:08:14 +00:00
|
|
|
addSite(c, result, low);
|
2010-11-26 19:36:43 +00:00
|
|
|
if (resultSize > lowSize and live(c, result->nextWord)) {
|
2009-10-10 22:07:30 +00:00
|
|
|
addSite(c, result->nextWord, high);
|
2008-11-11 00:07:44 +00:00
|
|
|
}
|
2008-09-23 21:18:41 +00:00
|
|
|
}
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
2007-12-23 18:48:22 +00:00
|
|
|
|
2008-08-28 22:43:35 +00:00
|
|
|
TernaryOperation type;
|
2008-08-16 17:45:36 +00:00
|
|
|
unsigned firstSize;
|
2008-04-17 02:55:38 +00:00
|
|
|
Value* first;
|
2008-08-16 17:45:36 +00:00
|
|
|
unsigned secondSize;
|
2008-04-17 02:55:38 +00:00
|
|
|
Value* second;
|
2008-08-16 17:45:36 +00:00
|
|
|
unsigned resultSize;
|
2008-04-17 22:07:32 +00:00
|
|
|
Value* result;
|
2008-02-11 17:21:41 +00:00
|
|
|
};
|
2007-12-20 16:02:00 +00:00
|
|
|
|
2008-11-01 19:14:13 +00:00
|
|
|
void
|
2008-11-01 22:16:18 +00:00
|
|
|
removeBuddy(Context* c, Value* v)
|
2008-11-01 19:14:13 +00:00
|
|
|
{
|
|
|
|
if (v->buddy != v) {
|
2009-01-11 22:53:51 +00:00
|
|
|
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");
|
|
|
|
}
|
2008-11-01 19:14:13 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
assert(c, v->buddy);
|
|
|
|
|
2008-11-01 19:14:13 +00:00
|
|
|
Value* next = v->buddy;
|
|
|
|
v->buddy = v;
|
|
|
|
Value* p = next;
|
|
|
|
while (p->buddy != v) p = p->buddy;
|
|
|
|
p->buddy = next;
|
2008-11-01 22:16:18 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
assert(c, p->buddy);
|
|
|
|
|
2010-11-26 19:36:43 +00:00
|
|
|
if (not live(c, next)) {
|
2008-11-01 22:16:18 +00:00
|
|
|
clearSites(c, next);
|
|
|
|
}
|
2008-12-16 01:21:01 +00:00
|
|
|
|
2010-11-26 19:36:43 +00:00
|
|
|
if (not live(c, v)) {
|
2008-12-16 01:21:01 +00:00
|
|
|
clearSites(c, v);
|
|
|
|
}
|
2008-11-01 19:14:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-01 22:16:18 +00:00
|
|
|
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)
|
|
|
|
{
|
2008-11-02 22:25:51 +00:00
|
|
|
if (DebugControl) {
|
2009-01-04 01:17:51 +00:00
|
|
|
char buffer[256]; sitesToString(c, value->sites, buffer, 256);
|
2008-11-02 22:25:51 +00:00
|
|
|
fprintf(stderr, "snapshot %p buddy %p sites %s\n",
|
|
|
|
value, value->buddy, buffer);
|
|
|
|
}
|
2008-11-01 22:16:18 +00:00
|
|
|
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) Snapshot(c, value, next);
|
2008-11-01 22:16:18 +00:00
|
|
|
}
|
|
|
|
|
2008-11-07 00:39:38 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-08-28 22:43:35 +00:00
|
|
|
Stack*
|
2009-01-25 22:03:38 +00:00
|
|
|
stack(Context* c, Value* value, Stack* next)
|
2008-11-07 00:39:38 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) Stack(next ? next->index + 1 : 0, value, next);
|
2008-08-28 22:43:35 +00:00
|
|
|
}
|
|
|
|
|
2008-11-02 20:35:35 +00:00
|
|
|
Value*
|
2009-01-25 22:03:38 +00:00
|
|
|
maybeBuddy(Context* c, Value* v);
|
2008-11-02 20:35:35 +00:00
|
|
|
|
2009-03-01 19:28:17 +00:00
|
|
|
Value*
|
|
|
|
pushWord(Context* c, Value* v)
|
|
|
|
{
|
|
|
|
if (v) {
|
|
|
|
v = maybeBuddy(c, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
void
|
|
|
|
push(Context* c, unsigned footprint, Value* v)
|
2008-02-11 17:21:41 +00:00
|
|
|
{
|
2008-11-02 22:25:51 +00:00
|
|
|
assert(c, footprint);
|
2008-04-28 22:08:31 +00:00
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
bool bigEndian = c->arch->bigEndian();
|
2009-03-01 19:28:17 +00:00
|
|
|
|
|
|
|
Value* low = v;
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
if (bigEndian) {
|
2009-03-01 19:28:17 +00:00
|
|
|
v = pushWord(c, v);
|
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
Value* high;
|
2009-01-30 01:36:19 +00:00
|
|
|
if (footprint > 1) {
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(c, footprint == 2);
|
2009-02-01 23:10:56 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (TargetBytesPerWord == 4) {
|
2009-10-04 22:10:36 +00:00
|
|
|
maybeSplit(c, low);
|
2009-10-10 22:07:30 +00:00
|
|
|
high = pushWord(c, low->nextWord);
|
2009-10-04 22:10:36 +00:00
|
|
|
} else {
|
|
|
|
high = pushWord(c, 0);
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
2009-02-01 23:19:11 +00:00
|
|
|
} else {
|
|
|
|
high = 0;
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
2009-03-01 19:28:17 +00:00
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
if (not bigEndian) {
|
2009-03-01 19:28:17 +00:00
|
|
|
v = pushWord(c, v);
|
2009-01-30 01:36:19 +00:00
|
|
|
}
|
|
|
|
|
2009-10-04 22:10:36 +00:00
|
|
|
if (high) {
|
2009-10-10 22:07:30 +00:00
|
|
|
v->nextWord = high;
|
|
|
|
high->nextWord = v;
|
|
|
|
high->wordIndex = 1;
|
2008-11-02 22:25:51 +00:00
|
|
|
}
|
2008-08-28 22:43:35 +00:00
|
|
|
}
|
2008-04-28 22:08:31 +00:00
|
|
|
|
2009-03-01 19:28:17 +00:00
|
|
|
void
|
|
|
|
popWord(Context* c)
|
2008-08-28 22:43:35 +00:00
|
|
|
{
|
2008-09-13 21:09:26 +00:00
|
|
|
Stack* s = c->stack;
|
2009-01-30 01:36:19 +00:00
|
|
|
assert(c, s->value == 0 or s->value->home >= 0);
|
2008-11-02 20:35:35 +00:00
|
|
|
|
2008-11-02 22:25:51 +00:00
|
|
|
if (DebugFrame) {
|
2009-02-01 23:19:11 +00:00
|
|
|
fprintf(stderr, "pop %p\n", s->value);
|
2008-11-02 22:25:51 +00:00
|
|
|
}
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2009-03-01 19:28:17 +00:00
|
|
|
c->stack = s->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
Value*
|
|
|
|
pop(Context* c, unsigned footprint)
|
|
|
|
{
|
|
|
|
assert(c, footprint);
|
|
|
|
|
2009-03-08 00:52:18 +00:00
|
|
|
Stack* s = 0;
|
2009-03-01 19:28:17 +00:00
|
|
|
|
|
|
|
bool bigEndian = c->arch->bigEndian();
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
if (not bigEndian) {
|
2009-03-01 19:28:17 +00:00
|
|
|
s = c->stack;
|
|
|
|
}
|
2009-01-25 22:03:38 +00:00
|
|
|
|
|
|
|
if (footprint > 1) {
|
|
|
|
assert(c, footprint == 2);
|
2009-01-30 01:36:19 +00:00
|
|
|
|
2009-03-01 19:28:17 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
Stack* low;
|
|
|
|
Stack* high;
|
|
|
|
if (bigEndian) {
|
2009-05-03 20:57:11 +00:00
|
|
|
high = c->stack;
|
|
|
|
low = high->next;
|
2009-10-24 23:18:56 +00:00
|
|
|
} else {
|
|
|
|
low = c->stack;
|
|
|
|
high = low->next;
|
2009-03-01 19:28:17 +00:00
|
|
|
}
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
assert(c, (TargetBytesPerWord == 8
|
2009-10-10 22:07:30 +00:00
|
|
|
and low->value->nextWord == low->value and high->value == 0)
|
2011-08-30 01:00:17 +00:00
|
|
|
or (TargetBytesPerWord == 4 and low->value->nextWord == high->value));
|
2009-03-01 19:28:17 +00:00
|
|
|
#endif // not NDEBUG
|
|
|
|
|
|
|
|
popWord(c);
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
if (bigEndian) {
|
2009-03-01 19:28:17 +00:00
|
|
|
s = c->stack;
|
|
|
|
}
|
|
|
|
|
|
|
|
popWord(c);
|
|
|
|
|
2008-08-28 22:43:35 +00:00
|
|
|
return s->value;
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Value*
|
2009-02-14 20:26:39 +00:00
|
|
|
storeLocal(Context* c, unsigned footprint, Value* v, unsigned index, bool copy)
|
2009-02-01 23:10:56 +00:00
|
|
|
{
|
|
|
|
assert(c, index + footprint <= c->localFootprint);
|
|
|
|
|
2009-02-14 20:26:39 +00:00
|
|
|
if (copy) {
|
|
|
|
unsigned sizeInBytes = sizeof(Local) * c->localFootprint;
|
|
|
|
Local* newLocals = static_cast<Local*>(c->zone->allocate(sizeInBytes));
|
|
|
|
memcpy(newLocals, c->locals, sizeInBytes);
|
|
|
|
c->locals = newLocals;
|
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
Value* high;
|
|
|
|
if (footprint > 1) {
|
|
|
|
assert(c, footprint == 2);
|
|
|
|
|
2009-03-01 19:28:17 +00:00
|
|
|
unsigned highIndex;
|
|
|
|
unsigned lowIndex;
|
|
|
|
if (c->arch->bigEndian()) {
|
|
|
|
highIndex = index + 1;
|
|
|
|
lowIndex = index;
|
|
|
|
} else {
|
|
|
|
lowIndex = index + 1;
|
|
|
|
highIndex = index;
|
|
|
|
}
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (TargetBytesPerWord == 4) {
|
2009-10-10 22:07:30 +00:00
|
|
|
assert(c, v->nextWord != v);
|
2009-02-01 23:10:56 +00:00
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
high = storeLocal(c, 1, v->nextWord, highIndex, false);
|
2009-02-01 23:19:11 +00:00
|
|
|
} else {
|
|
|
|
high = 0;
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
|
|
|
|
2009-03-01 19:28:17 +00:00
|
|
|
index = lowIndex;
|
2009-02-01 23:10:56 +00:00
|
|
|
} else {
|
2009-10-04 22:10:36 +00:00
|
|
|
high = 0;
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
v = maybeBuddy(c, v);
|
2009-10-04 22:10:36 +00:00
|
|
|
|
|
|
|
if (high != 0) {
|
2009-10-10 22:07:30 +00:00
|
|
|
v->nextWord = high;
|
|
|
|
high->nextWord = v;
|
|
|
|
high->wordIndex = 1;
|
2009-10-04 22:10:36 +00:00
|
|
|
}
|
2009-02-01 23:10:56 +00:00
|
|
|
|
|
|
|
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*
|
2009-03-01 19:28:17 +00:00
|
|
|
loadLocal(Context* c, unsigned footprint, unsigned index)
|
2009-02-01 23:10:56 +00:00
|
|
|
{
|
|
|
|
assert(c, index + footprint <= c->localFootprint);
|
|
|
|
|
|
|
|
if (footprint > 1) {
|
|
|
|
assert(c, footprint == 2);
|
|
|
|
|
2009-03-01 19:28:17 +00:00
|
|
|
if (not c->arch->bigEndian()) {
|
|
|
|
++ index;
|
|
|
|
}
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
return c->locals[index].value;
|
2008-08-28 22:43:35 +00:00
|
|
|
}
|
|
|
|
|
2010-12-20 00:47:21 +00:00
|
|
|
Value*
|
|
|
|
register_(Context* c, int number)
|
|
|
|
{
|
|
|
|
assert(c, (1 << number) & (c->arch->generalRegisterMask()
|
|
|
|
| c->arch->floatRegisterMask()));
|
|
|
|
|
|
|
|
Site* s = registerSite(c, number);
|
|
|
|
ValueType type = ((1 << number) & c->arch->floatRegisterMask())
|
|
|
|
? ValueFloat: ValueGeneral;
|
|
|
|
|
|
|
|
return value(c, type, s, s);
|
|
|
|
}
|
|
|
|
|
2008-08-28 22:43:35 +00:00
|
|
|
void
|
|
|
|
appendCombine(Context* c, TernaryOperation type,
|
|
|
|
unsigned firstSize, Value* first,
|
|
|
|
unsigned secondSize, Value* second,
|
|
|
|
unsigned resultSize, Value* result)
|
|
|
|
{
|
|
|
|
bool thunk;
|
|
|
|
uint8_t firstTypeMask;
|
|
|
|
uint64_t firstRegisterMask;
|
|
|
|
uint8_t secondTypeMask;
|
|
|
|
uint64_t secondRegisterMask;
|
|
|
|
|
2009-08-06 16:14:31 +00:00
|
|
|
c->arch->planSource(type, firstSize, &firstTypeMask, &firstRegisterMask,
|
2010-12-20 00:47:21 +00:00
|
|
|
secondSize, &secondTypeMask, &secondRegisterMask,
|
|
|
|
resultSize, &thunk);
|
2008-05-16 00:35:17 +00:00
|
|
|
|
2008-08-28 22:43:35 +00:00
|
|
|
if (thunk) {
|
2008-09-13 21:09:26 +00:00
|
|
|
Stack* oldStack = c->stack;
|
2008-05-04 20:55:34 +00:00
|
|
|
|
2010-12-20 00:47:21 +00:00
|
|
|
bool threadParameter;
|
|
|
|
intptr_t handler = c->client->getThunk
|
|
|
|
(type, firstSize, resultSize, &threadParameter);
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
unsigned stackSize = ceiling(secondSize, TargetBytesPerWord)
|
|
|
|
+ ceiling(firstSize, TargetBytesPerWord);
|
2010-12-20 00:47:21 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
local::push(c, ceiling(secondSize, TargetBytesPerWord), second);
|
|
|
|
local::push(c, ceiling(firstSize, TargetBytesPerWord), first);
|
2008-04-18 03:47:42 +00:00
|
|
|
|
2010-12-20 00:47:21 +00:00
|
|
|
if (threadParameter) {
|
|
|
|
++ stackSize;
|
|
|
|
|
|
|
|
local::push(c, 1, register_(c, c->arch->thread()));
|
|
|
|
}
|
|
|
|
|
2008-09-13 21:09:26 +00:00
|
|
|
Stack* argumentStack = c->stack;
|
|
|
|
c->stack = oldStack;
|
2008-05-04 20:55:34 +00:00
|
|
|
|
2008-08-28 22:43:35 +00:00
|
|
|
appendCall
|
2010-12-20 00:47:21 +00:00
|
|
|
(c, value(c, ValueGeneral, constantSite(c, handler)), 0, 0, result,
|
|
|
|
resultSize, argumentStack, stackSize, 0);
|
2008-05-04 20:55:34 +00:00
|
|
|
} else {
|
2008-10-14 00:18:18 +00:00
|
|
|
append
|
2012-05-08 22:13:17 +00:00
|
|
|
(c, new(c->zone)
|
2008-10-14 00:18:18 +00:00
|
|
|
CombineEvent
|
|
|
|
(c, type,
|
|
|
|
firstSize, first,
|
|
|
|
secondSize, second,
|
|
|
|
resultSize, result,
|
2009-01-25 22:03:38 +00:00
|
|
|
SiteMask(firstTypeMask, firstRegisterMask, AnyFrameIndex),
|
|
|
|
SiteMask(firstTypeMask, firstRegisterMask >> 32, AnyFrameIndex),
|
|
|
|
SiteMask(secondTypeMask, secondRegisterMask, AnyFrameIndex),
|
2009-08-06 16:14:31 +00:00
|
|
|
SiteMask(secondTypeMask, secondRegisterMask >> 32, AnyFrameIndex)));
|
2008-05-04 20:55:34 +00:00
|
|
|
}
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
2007-12-20 16:02:00 +00:00
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
class TranslateEvent: public Event {
|
|
|
|
public:
|
2009-10-04 19:56:48 +00:00
|
|
|
TranslateEvent(Context* c, BinaryOperation type, unsigned valueSize,
|
|
|
|
Value* value, unsigned resultSize, Value* result,
|
2009-01-25 22:03:38 +00:00
|
|
|
const SiteMask& valueLowMask,
|
2009-08-06 16:14:31 +00:00
|
|
|
const SiteMask& valueHighMask):
|
2009-10-04 19:56:48 +00:00
|
|
|
Event(c), type(type), valueSize(valueSize), resultSize(resultSize),
|
|
|
|
value(value), result(result)
|
2008-02-17 20:57:40 +00:00
|
|
|
{
|
2009-08-10 19:20:23 +00:00
|
|
|
bool condensed = c->arch->alwaysCondensed(type);
|
2009-04-07 00:34:12 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (resultSize > TargetBytesPerWord) {
|
2009-02-01 23:10:56 +00:00
|
|
|
grow(c, result);
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
2009-10-04 19:56:48 +00:00
|
|
|
|
|
|
|
addReads(c, this, value, valueSize, valueLowMask, condensed ? result : 0,
|
2009-10-10 22:07:30 +00:00
|
|
|
valueHighMask, condensed ? result->nextWord : 0);
|
2008-03-15 20:24:04 +00:00
|
|
|
}
|
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual const char* name() {
|
|
|
|
return "TranslateEvent";
|
|
|
|
}
|
2008-02-17 20:57:40 +00:00
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual void compile(Context* c) {
|
2009-10-10 22:07:30 +00:00
|
|
|
assert(c, value->source->type(c) == value->nextWord->source->type(c));
|
2009-10-04 22:10:36 +00:00
|
|
|
|
2009-08-06 16:14:31 +00:00
|
|
|
uint8_t bTypeMask;
|
|
|
|
uint64_t bRegisterMask;
|
|
|
|
|
2009-09-20 21:43:32 +00:00
|
|
|
c->arch->planDestination
|
2009-10-04 19:56:48 +00:00
|
|
|
(type,
|
|
|
|
valueSize,
|
|
|
|
1 << value->source->type(c),
|
2009-10-10 22:07:30 +00:00
|
|
|
(static_cast<uint64_t>(value->nextWord->source->registerMask(c)) << 32)
|
2009-10-04 19:56:48 +00:00
|
|
|
| static_cast<uint64_t>(value->source->registerMask(c)),
|
|
|
|
resultSize,
|
|
|
|
&bTypeMask,
|
2009-09-20 21:43:32 +00:00
|
|
|
&bRegisterMask);
|
2009-10-04 19:56:48 +00:00
|
|
|
|
2009-08-06 16:14:31 +00:00
|
|
|
SiteMask resultLowMask(bTypeMask, bRegisterMask, AnyFrameIndex);
|
|
|
|
SiteMask resultHighMask(bTypeMask, bRegisterMask >> 32, AnyFrameIndex);
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
Site* low = getTarget(c, value, result, resultLowMask);
|
2009-10-04 19:56:48 +00:00
|
|
|
unsigned lowSize = low->registerSize(c);
|
2009-01-25 22:03:38 +00:00
|
|
|
Site* high
|
2009-10-04 19:56:48 +00:00
|
|
|
= (resultSize > lowSize
|
2009-10-10 22:07:30 +00:00
|
|
|
? getTarget(c, value->nextWord, result->nextWord, resultHighMask)
|
2009-09-26 19:43:44 +00:00
|
|
|
: low);
|
2008-04-29 16:25:20 +00:00
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
apply(c, type, valueSize, value->source, value->nextWord->source,
|
2009-10-04 19:56:48 +00:00
|
|
|
resultSize, low, high);
|
2009-01-11 18:48:02 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
for (Read* r = reads; r; r = r->eventNext) {
|
|
|
|
popRead(c, this, r->value);
|
2009-01-11 18:48:02 +00:00
|
|
|
}
|
2008-04-19 00:19:45 +00:00
|
|
|
|
2009-03-01 02:08:14 +00:00
|
|
|
low->thaw(c, value);
|
2009-10-04 19:56:48 +00:00
|
|
|
if (resultSize > lowSize) {
|
2009-10-10 22:07:30 +00:00
|
|
|
high->thaw(c, value->nextWord);
|
2009-03-01 02:08:14 +00:00
|
|
|
}
|
2009-01-11 18:48:02 +00:00
|
|
|
|
2010-11-26 19:36:43 +00:00
|
|
|
if (live(c, result)) {
|
2009-03-01 02:08:14 +00:00
|
|
|
addSite(c, result, low);
|
2010-11-26 19:36:43 +00:00
|
|
|
if (resultSize > lowSize and live(c, result->nextWord)) {
|
2009-10-10 22:07:30 +00:00
|
|
|
addSite(c, result->nextWord, high);
|
2008-11-11 00:07:44 +00:00
|
|
|
}
|
2008-04-21 00:21:48 +00:00
|
|
|
}
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
2007-12-20 16:02:00 +00:00
|
|
|
|
2008-08-28 22:43:35 +00:00
|
|
|
BinaryOperation type;
|
2009-10-04 19:56:48 +00:00
|
|
|
unsigned valueSize;
|
|
|
|
unsigned resultSize;
|
2008-04-17 02:55:38 +00:00
|
|
|
Value* value;
|
|
|
|
Value* result;
|
2008-10-15 00:45:31 +00:00
|
|
|
Read* resultRead;
|
2009-01-25 22:03:38 +00:00
|
|
|
SiteMask resultLowMask;
|
|
|
|
SiteMask resultHighMask;
|
2008-02-11 17:21:41 +00:00
|
|
|
};
|
2007-12-12 18:59:45 +00:00
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
void
|
2009-09-20 21:43:32 +00:00
|
|
|
appendTranslate(Context* c, BinaryOperation type, unsigned firstSize,
|
|
|
|
Value* first, unsigned resultSize, Value* result)
|
2008-02-11 17:21:41 +00:00
|
|
|
{
|
2008-05-31 22:14:27 +00:00
|
|
|
bool thunk;
|
2008-08-28 22:43:35 +00:00
|
|
|
uint8_t firstTypeMask;
|
|
|
|
uint64_t firstRegisterMask;
|
2008-05-04 20:55:34 +00:00
|
|
|
|
2009-08-06 16:14:31 +00:00
|
|
|
c->arch->planSource(type, firstSize, &firstTypeMask, &firstRegisterMask,
|
|
|
|
resultSize, &thunk);
|
2008-05-04 20:55:34 +00:00
|
|
|
|
2009-08-06 16:14:31 +00:00
|
|
|
if (thunk) {
|
|
|
|
Stack* oldStack = c->stack;
|
2008-05-04 20:55:34 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
local::push(c, ceiling(firstSize, TargetBytesPerWord), first);
|
2009-08-06 16:14:31 +00:00
|
|
|
|
|
|
|
Stack* argumentStack = c->stack;
|
|
|
|
c->stack = oldStack;
|
|
|
|
|
|
|
|
appendCall
|
2009-09-20 21:43:32 +00:00
|
|
|
(c, value
|
|
|
|
(c, ValueGeneral, constantSite
|
|
|
|
(c, c->client->getThunk(type, firstSize, resultSize))),
|
2009-08-06 16:14:31 +00:00
|
|
|
0, 0, result, resultSize, argumentStack,
|
2011-08-30 01:00:17 +00:00
|
|
|
ceiling(firstSize, TargetBytesPerWord), 0);
|
2009-08-06 16:14:31 +00:00
|
|
|
} else {
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone)
|
2009-08-06 16:14:31 +00:00
|
|
|
TranslateEvent
|
2009-10-04 19:56:48 +00:00
|
|
|
(c, type, firstSize, first, resultSize, result,
|
2009-08-06 16:14:31 +00:00
|
|
|
SiteMask(firstTypeMask, firstRegisterMask, AnyFrameIndex),
|
|
|
|
SiteMask(firstTypeMask, firstRegisterMask >> 32, AnyFrameIndex)));
|
|
|
|
}
|
2008-02-11 17:21:41 +00:00
|
|
|
}
|
2007-12-20 16:02:00 +00:00
|
|
|
|
fix a couple of subtle Thread.getStackTrace bugs
The first problem was that, on x86, we failed to properly keep track
of whether to expect the return address to be on the stack or not when
unwinding through a frame. We were relying on a "stackLimit" pointer
to tell us whether we were looking at the most recently-called frame
by comparing it with the stack pointer for that frame. That was
inaccurate in the case of a thread executing at the beginning of a
method before a new frame is allocated, in which case the most recent
two frames share a stack pointer, confusing the unwinder. The
solution involves keeping track of how many frames we've looked at
while walking the stack.
The other problem was that compareIpToMethodBounds assumed every
method was followed by at least one byte of padding before the next
method started. That assumption was usually valid because we were
storing the size following method code prior to the code itself.
However, the last method of an AOT-compiled code image is not followed
by any such method header and may instead be followed directly by
native code with no intervening padding. In that case, we risk
interpreting that native code as part of the preceding method, with
potentially bizarre results.
The reason for the compareIpToMethodBounds assumption was that methods
which throw exceptions as their last instruction generate a
non-returning call, which nonetheless push a return address on the
stack which points past the end of the method, and the unwinder needs
to know that return address belongs to that method. A better solution
is to add an extra trap instruction to the end of such methods, which
is what this patch does.
2012-05-05 00:35:13 +00:00
|
|
|
class OperationEvent: public Event {
|
2009-03-03 03:18:15 +00:00
|
|
|
public:
|
fix a couple of subtle Thread.getStackTrace bugs
The first problem was that, on x86, we failed to properly keep track
of whether to expect the return address to be on the stack or not when
unwinding through a frame. We were relying on a "stackLimit" pointer
to tell us whether we were looking at the most recently-called frame
by comparing it with the stack pointer for that frame. That was
inaccurate in the case of a thread executing at the beginning of a
method before a new frame is allocated, in which case the most recent
two frames share a stack pointer, confusing the unwinder. The
solution involves keeping track of how many frames we've looked at
while walking the stack.
The other problem was that compareIpToMethodBounds assumed every
method was followed by at least one byte of padding before the next
method started. That assumption was usually valid because we were
storing the size following method code prior to the code itself.
However, the last method of an AOT-compiled code image is not followed
by any such method header and may instead be followed directly by
native code with no intervening padding. In that case, we risk
interpreting that native code as part of the preceding method, with
potentially bizarre results.
The reason for the compareIpToMethodBounds assumption was that methods
which throw exceptions as their last instruction generate a
non-returning call, which nonetheless push a return address on the
stack which points past the end of the method, and the unwinder needs
to know that return address belongs to that method. A better solution
is to add an extra trap instruction to the end of such methods, which
is what this patch does.
2012-05-05 00:35:13 +00:00
|
|
|
OperationEvent(Context* c, Operation op):
|
2009-03-03 03:18:15 +00:00
|
|
|
Event(c), op(op)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual const char* name() {
|
fix a couple of subtle Thread.getStackTrace bugs
The first problem was that, on x86, we failed to properly keep track
of whether to expect the return address to be on the stack or not when
unwinding through a frame. We were relying on a "stackLimit" pointer
to tell us whether we were looking at the most recently-called frame
by comparing it with the stack pointer for that frame. That was
inaccurate in the case of a thread executing at the beginning of a
method before a new frame is allocated, in which case the most recent
two frames share a stack pointer, confusing the unwinder. The
solution involves keeping track of how many frames we've looked at
while walking the stack.
The other problem was that compareIpToMethodBounds assumed every
method was followed by at least one byte of padding before the next
method started. That assumption was usually valid because we were
storing the size following method code prior to the code itself.
However, the last method of an AOT-compiled code image is not followed
by any such method header and may instead be followed directly by
native code with no intervening padding. In that case, we risk
interpreting that native code as part of the preceding method, with
potentially bizarre results.
The reason for the compareIpToMethodBounds assumption was that methods
which throw exceptions as their last instruction generate a
non-returning call, which nonetheless push a return address on the
stack which points past the end of the method, and the unwinder needs
to know that return address belongs to that method. A better solution
is to add an extra trap instruction to the end of such methods, which
is what this patch does.
2012-05-05 00:35:13 +00:00
|
|
|
return "OperationEvent";
|
2009-03-03 03:18:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void compile(Context* c) {
|
|
|
|
c->assembler->apply(op);
|
|
|
|
}
|
|
|
|
|
|
|
|
Operation op;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
fix a couple of subtle Thread.getStackTrace bugs
The first problem was that, on x86, we failed to properly keep track
of whether to expect the return address to be on the stack or not when
unwinding through a frame. We were relying on a "stackLimit" pointer
to tell us whether we were looking at the most recently-called frame
by comparing it with the stack pointer for that frame. That was
inaccurate in the case of a thread executing at the beginning of a
method before a new frame is allocated, in which case the most recent
two frames share a stack pointer, confusing the unwinder. The
solution involves keeping track of how many frames we've looked at
while walking the stack.
The other problem was that compareIpToMethodBounds assumed every
method was followed by at least one byte of padding before the next
method started. That assumption was usually valid because we were
storing the size following method code prior to the code itself.
However, the last method of an AOT-compiled code image is not followed
by any such method header and may instead be followed directly by
native code with no intervening padding. In that case, we risk
interpreting that native code as part of the preceding method, with
potentially bizarre results.
The reason for the compareIpToMethodBounds assumption was that methods
which throw exceptions as their last instruction generate a
non-returning call, which nonetheless push a return address on the
stack which points past the end of the method, and the unwinder needs
to know that return address belongs to that method. A better solution
is to add an extra trap instruction to the end of such methods, which
is what this patch does.
2012-05-05 00:35:13 +00:00
|
|
|
appendOperation(Context* c, Operation op)
|
2009-03-03 03:18:15 +00:00
|
|
|
{
|
fix a couple of subtle Thread.getStackTrace bugs
The first problem was that, on x86, we failed to properly keep track
of whether to expect the return address to be on the stack or not when
unwinding through a frame. We were relying on a "stackLimit" pointer
to tell us whether we were looking at the most recently-called frame
by comparing it with the stack pointer for that frame. That was
inaccurate in the case of a thread executing at the beginning of a
method before a new frame is allocated, in which case the most recent
two frames share a stack pointer, confusing the unwinder. The
solution involves keeping track of how many frames we've looked at
while walking the stack.
The other problem was that compareIpToMethodBounds assumed every
method was followed by at least one byte of padding before the next
method started. That assumption was usually valid because we were
storing the size following method code prior to the code itself.
However, the last method of an AOT-compiled code image is not followed
by any such method header and may instead be followed directly by
native code with no intervening padding. In that case, we risk
interpreting that native code as part of the preceding method, with
potentially bizarre results.
The reason for the compareIpToMethodBounds assumption was that methods
which throw exceptions as their last instruction generate a
non-returning call, which nonetheless push a return address on the
stack which points past the end of the method, and the unwinder needs
to know that return address belongs to that method. A better solution
is to add an extra trap instruction to the end of such methods, which
is what this patch does.
2012-05-05 00:35:13 +00:00
|
|
|
append
|
2012-05-08 22:13:17 +00:00
|
|
|
(c, new(c->zone) OperationEvent(c, op));
|
2009-03-03 03:18:15 +00:00
|
|
|
}
|
|
|
|
|
2008-03-15 23:54:20 +00:00
|
|
|
class MemoryEvent: public Event {
|
|
|
|
public:
|
2008-04-17 20:48:26 +00:00
|
|
|
MemoryEvent(Context* c, Value* base, int displacement, Value* index,
|
|
|
|
unsigned scale, Value* result):
|
|
|
|
Event(c), base(base), displacement(displacement), index(index),
|
|
|
|
scale(scale), result(result)
|
2008-03-15 23:54:20 +00:00
|
|
|
{
|
2009-10-04 19:56:48 +00:00
|
|
|
addRead(c, this, base, generalRegisterMask(c));
|
2009-01-04 22:58:05 +00:00
|
|
|
if (index) {
|
2009-10-04 19:56:48 +00:00
|
|
|
addRead(c, this, index, generalRegisterOrConstantMask(c));
|
2009-01-04 22:58:05 +00:00
|
|
|
}
|
2008-09-15 02:28:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual const char* name() {
|
|
|
|
return "MemoryEvent";
|
2008-03-15 23:54:20 +00:00
|
|
|
}
|
|
|
|
|
2008-04-17 22:07:32 +00:00
|
|
|
virtual void compile(Context* c) {
|
2008-04-17 20:48:26 +00:00
|
|
|
int indexRegister;
|
2008-06-10 14:49:13 +00:00
|
|
|
int displacement = this->displacement;
|
|
|
|
unsigned scale = this->scale;
|
2008-04-17 20:48:26 +00:00
|
|
|
if (index) {
|
2008-06-11 00:17:44 +00:00
|
|
|
ConstantSite* constant = findConstantSite(c, index);
|
2008-06-10 14:49:13 +00:00
|
|
|
|
|
|
|
if (constant) {
|
|
|
|
indexRegister = NoRegister;
|
2009-01-25 22:03:38 +00:00
|
|
|
displacement += (constant->value->value() * scale);
|
2008-06-10 14:49:13 +00:00
|
|
|
scale = 1;
|
|
|
|
} else {
|
|
|
|
assert(c, index->source->type(c) == RegisterOperand);
|
2009-01-25 22:03:38 +00:00
|
|
|
indexRegister = static_cast<RegisterSite*>(index->source)->number;
|
2008-06-10 14:49:13 +00:00
|
|
|
}
|
2008-04-17 20:48:26 +00:00
|
|
|
} else {
|
|
|
|
indexRegister = NoRegister;
|
|
|
|
}
|
2008-04-18 00:39:41 +00:00
|
|
|
assert(c, base->source->type(c) == RegisterOperand);
|
2009-01-25 22:03:38 +00:00
|
|
|
int baseRegister = static_cast<RegisterSite*>(base->source)->number;
|
2008-04-17 20:48:26 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
popRead(c, this, base);
|
2008-04-19 00:19:45 +00:00
|
|
|
if (index) {
|
2011-08-30 01:00:17 +00:00
|
|
|
if (TargetBytesPerWord == 8 and indexRegister != NoRegister) {
|
2009-09-26 19:43:44 +00:00
|
|
|
apply(c, Move, 4, index->source, index->source,
|
|
|
|
8, index->source, index->source);
|
2008-05-04 20:55:34 +00:00
|
|
|
}
|
2008-05-13 17:27:57 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
popRead(c, this, index);
|
2008-04-19 00:19:45 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
Site* site = memorySite
|
2009-02-09 01:58:33 +00:00
|
|
|
(c, baseRegister, displacement, indexRegister, scale);
|
2009-02-01 23:10:56 +00:00
|
|
|
|
2009-03-12 03:07:30 +00:00
|
|
|
Site* low;
|
2009-10-10 22:07:30 +00:00
|
|
|
if (result->nextWord != result) {
|
2009-02-01 23:10:56 +00:00
|
|
|
Site* high = site->copyHigh(c);
|
2009-03-12 03:07:30 +00:00
|
|
|
low = site->copyLow(c);
|
2009-01-25 22:03:38 +00:00
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
result->nextWord->target = high;
|
|
|
|
addSite(c, result->nextWord, high);
|
2009-03-12 03:07:30 +00:00
|
|
|
} else {
|
|
|
|
low = site;
|
2009-02-01 23:10:56 +00:00
|
|
|
}
|
2009-03-12 03:07:30 +00:00
|
|
|
|
|
|
|
result->target = low;
|
|
|
|
addSite(c, result, low);
|
2008-03-15 23:54:20 +00:00
|
|
|
}
|
|
|
|
|
2008-04-17 02:55:38 +00:00
|
|
|
Value* base;
|
2008-04-17 20:48:26 +00:00
|
|
|
int displacement;
|
2008-04-17 02:55:38 +00:00
|
|
|
Value* index;
|
2008-04-17 20:48:26 +00:00
|
|
|
unsigned scale;
|
2008-04-17 02:55:38 +00:00
|
|
|
Value* result;
|
2008-03-15 23:54:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2008-04-17 20:48:26 +00:00
|
|
|
appendMemory(Context* c, Value* base, int displacement, Value* index,
|
|
|
|
unsigned scale, Value* result)
|
2008-04-17 02:55:38 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone)
|
2008-10-14 00:18:18 +00:00
|
|
|
MemoryEvent(c, base, displacement, index, scale, result));
|
2008-04-17 20:48:26 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
double
|
|
|
|
asFloat(unsigned size, int64_t v)
|
|
|
|
{
|
|
|
|
if (size == 4) {
|
|
|
|
return bitsToFloat(v);
|
|
|
|
} else {
|
|
|
|
return bitsToDouble(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
unordered(double a, double b)
|
|
|
|
{
|
|
|
|
return not (a >= b or a < b);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2009-10-10 21:03:23 +00:00
|
|
|
shouldJump(Context* c, TernaryOperation type, unsigned size, int64_t b,
|
|
|
|
int64_t a)
|
2009-10-07 00:50:32 +00:00
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case JumpIfEqual:
|
|
|
|
return a == b;
|
|
|
|
|
|
|
|
case JumpIfNotEqual:
|
|
|
|
return a != b;
|
|
|
|
|
|
|
|
case JumpIfLess:
|
|
|
|
return a < b;
|
|
|
|
|
|
|
|
case JumpIfGreater:
|
|
|
|
return a > b;
|
|
|
|
|
|
|
|
case JumpIfLessOrEqual:
|
|
|
|
return a <= b;
|
|
|
|
|
|
|
|
case JumpIfGreaterOrEqual:
|
|
|
|
return a >= b;
|
|
|
|
|
|
|
|
case JumpIfFloatEqual:
|
|
|
|
return asFloat(size, a) == asFloat(size, b);
|
|
|
|
|
|
|
|
case JumpIfFloatNotEqual:
|
|
|
|
return asFloat(size, a) != asFloat(size, b);
|
|
|
|
|
|
|
|
case JumpIfFloatLess:
|
|
|
|
return asFloat(size, a) < asFloat(size, b);
|
|
|
|
|
|
|
|
case JumpIfFloatGreater:
|
|
|
|
return asFloat(size, a) > asFloat(size, b);
|
|
|
|
|
|
|
|
case JumpIfFloatLessOrEqual:
|
|
|
|
return asFloat(size, a) <= asFloat(size, b);
|
|
|
|
|
|
|
|
case JumpIfFloatGreaterOrEqual:
|
|
|
|
return asFloat(size, a) >= asFloat(size, b);
|
|
|
|
|
|
|
|
case JumpIfFloatLessOrUnordered:
|
|
|
|
return asFloat(size, a) < asFloat(size, b)
|
|
|
|
or unordered(asFloat(size, a), asFloat(size, b));
|
|
|
|
|
|
|
|
case JumpIfFloatGreaterOrUnordered:
|
|
|
|
return asFloat(size, a) > asFloat(size, b)
|
|
|
|
or unordered(asFloat(size, a), asFloat(size, b));
|
|
|
|
|
|
|
|
case JumpIfFloatLessOrEqualOrUnordered:
|
|
|
|
return asFloat(size, a) <= asFloat(size, b)
|
|
|
|
or unordered(asFloat(size, a), asFloat(size, b));
|
|
|
|
|
|
|
|
case JumpIfFloatGreaterOrEqualOrUnordered:
|
|
|
|
return asFloat(size, a) >= asFloat(size, b)
|
|
|
|
or unordered(asFloat(size, a), asFloat(size, b));
|
|
|
|
|
|
|
|
default:
|
2009-10-10 21:03:23 +00:00
|
|
|
abort(c);
|
2009-10-07 00:50:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-10 23:46:43 +00:00
|
|
|
TernaryOperation
|
|
|
|
thunkBranch(Context* c, TernaryOperation type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case JumpIfFloatEqual:
|
|
|
|
return JumpIfEqual;
|
|
|
|
|
|
|
|
case JumpIfFloatNotEqual:
|
|
|
|
return JumpIfNotEqual;
|
|
|
|
|
|
|
|
case JumpIfFloatLess:
|
|
|
|
case JumpIfFloatLessOrUnordered:
|
|
|
|
return JumpIfLess;
|
|
|
|
|
|
|
|
case JumpIfFloatGreater:
|
|
|
|
case JumpIfFloatGreaterOrUnordered:
|
|
|
|
return JumpIfGreater;
|
|
|
|
|
|
|
|
case JumpIfFloatLessOrEqual:
|
|
|
|
case JumpIfFloatLessOrEqualOrUnordered:
|
|
|
|
return JumpIfLessOrEqual;
|
|
|
|
|
|
|
|
case JumpIfFloatGreaterOrEqual:
|
|
|
|
case JumpIfFloatGreaterOrEqualOrUnordered:
|
|
|
|
return JumpIfGreaterOrEqual;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-20 05:23:08 +00:00
|
|
|
class BranchEvent: public Event {
|
|
|
|
public:
|
2009-10-07 00:50:32 +00:00
|
|
|
BranchEvent(Context* c, TernaryOperation type, unsigned size,
|
2009-10-10 21:03:23 +00:00
|
|
|
Value* first, Value* second, Value* address,
|
2009-10-07 00:50:32 +00:00
|
|
|
const SiteMask& firstLowMask,
|
|
|
|
const SiteMask& firstHighMask,
|
|
|
|
const SiteMask& secondLowMask,
|
|
|
|
const SiteMask& secondHighMask):
|
|
|
|
Event(c), type(type), size(size), first(first), second(second),
|
2009-10-10 21:03:23 +00:00
|
|
|
address(address)
|
2008-04-20 05:23:08 +00:00
|
|
|
{
|
2009-10-10 21:03:23 +00:00
|
|
|
addReads(c, this, first, size, firstLowMask, firstHighMask);
|
|
|
|
addReads(c, this, second, size, secondLowMask, secondHighMask);
|
|
|
|
|
|
|
|
uint8_t typeMask;
|
|
|
|
uint64_t registerMask;
|
2011-08-30 01:00:17 +00:00
|
|
|
c->arch->planDestination(type, size, 0, 0, size, 0, 0, TargetBytesPerWord,
|
2009-10-10 21:03:23 +00:00
|
|
|
&typeMask, ®isterMask);
|
|
|
|
|
|
|
|
addRead(c, this, address, SiteMask(typeMask, registerMask, AnyFrameIndex));
|
2008-04-20 05:23:08 +00:00
|
|
|
}
|
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual const char* name() {
|
|
|
|
return "BranchEvent";
|
|
|
|
}
|
2008-04-20 05:23:08 +00:00
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual void compile(Context* c) {
|
2009-10-07 00:50:32 +00:00
|
|
|
ConstantSite* firstConstant = findConstantSite(c, first);
|
|
|
|
ConstantSite* secondConstant = findConstantSite(c, second);
|
2008-06-11 00:17:44 +00:00
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
if (not unreachable(this)) {
|
2011-07-17 01:10:05 +00:00
|
|
|
if (firstConstant
|
|
|
|
and secondConstant
|
|
|
|
and firstConstant->value->resolved()
|
|
|
|
and secondConstant->value->resolved())
|
|
|
|
{
|
2010-12-21 01:08:52 +00:00
|
|
|
int64_t firstValue = firstConstant->value->value();
|
|
|
|
int64_t secondValue = secondConstant->value->value();
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (size > TargetBytesPerWord) {
|
2010-12-21 01:08:52 +00:00
|
|
|
firstValue |= findConstantSite
|
|
|
|
(c, first->nextWord)->value->value() << 32;
|
|
|
|
secondValue |= findConstantSite
|
|
|
|
(c, second->nextWord)->value->value() << 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shouldJump(c, type, size, firstValue, secondValue)) {
|
2011-08-30 01:00:17 +00:00
|
|
|
apply(c, Jump, TargetBytesPerWord, address->source, address->source);
|
2009-10-07 00:50:32 +00:00
|
|
|
}
|
|
|
|
} else {
|
2010-12-08 01:16:19 +00:00
|
|
|
freezeSource(c, size, first);
|
|
|
|
freezeSource(c, size, second);
|
2011-08-30 01:00:17 +00:00
|
|
|
freezeSource(c, TargetBytesPerWord, address);
|
2010-12-08 01:16:19 +00:00
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
apply(c, type, size, first->source, first->nextWord->source,
|
|
|
|
size, second->source, second->nextWord->source,
|
2011-08-30 01:00:17 +00:00
|
|
|
TargetBytesPerWord, address->source, address->source);
|
2010-12-08 01:16:19 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
thawSource(c, TargetBytesPerWord, address);
|
2010-12-08 01:16:19 +00:00
|
|
|
thawSource(c, size, second);
|
|
|
|
thawSource(c, size, first);
|
2008-06-11 00:17:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
for (Read* r = reads; r; r = r->eventNext) {
|
|
|
|
popRead(c, this, r->value);
|
2008-06-11 00:17:44 +00:00
|
|
|
}
|
2008-04-20 05:23:08 +00:00
|
|
|
}
|
|
|
|
|
2008-10-08 00:08:13 +00:00
|
|
|
virtual bool isBranch() { return true; }
|
|
|
|
|
2009-10-10 21:03:23 +00:00
|
|
|
TernaryOperation type;
|
2009-10-07 00:50:32 +00:00
|
|
|
unsigned size;
|
|
|
|
Value* first;
|
|
|
|
Value* second;
|
2008-04-20 05:23:08 +00:00
|
|
|
Value* address;
|
|
|
|
};
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
void
|
|
|
|
appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first,
|
2009-10-10 21:03:23 +00:00
|
|
|
Value* second, Value* address)
|
2009-10-07 00:50:32 +00:00
|
|
|
{
|
|
|
|
bool thunk;
|
|
|
|
uint8_t firstTypeMask;
|
|
|
|
uint64_t firstRegisterMask;
|
|
|
|
uint8_t secondTypeMask;
|
|
|
|
uint64_t secondRegisterMask;
|
|
|
|
|
|
|
|
c->arch->planSource(type, size, &firstTypeMask, &firstRegisterMask,
|
|
|
|
size, &secondTypeMask, &secondRegisterMask,
|
2011-08-30 01:00:17 +00:00
|
|
|
TargetBytesPerWord, &thunk);
|
2009-10-07 00:50:32 +00:00
|
|
|
|
|
|
|
if (thunk) {
|
|
|
|
Stack* oldStack = c->stack;
|
|
|
|
|
2010-12-20 00:47:21 +00:00
|
|
|
bool threadParameter;
|
|
|
|
intptr_t handler = c->client->getThunk
|
|
|
|
(type, size, size, &threadParameter);
|
|
|
|
|
|
|
|
assert(c, not threadParameter);
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
local::push(c, ceiling(size, TargetBytesPerWord), second);
|
|
|
|
local::push(c, ceiling(size, TargetBytesPerWord), first);
|
2009-10-07 00:50:32 +00:00
|
|
|
|
|
|
|
Stack* argumentStack = c->stack;
|
|
|
|
c->stack = oldStack;
|
|
|
|
|
2009-10-10 21:03:23 +00:00
|
|
|
Value* result = value(c, ValueGeneral);
|
2009-10-07 00:50:32 +00:00
|
|
|
appendCall
|
|
|
|
(c, value
|
2010-12-20 00:47:21 +00:00
|
|
|
(c, ValueGeneral, constantSite(c, handler)), 0, 0, result, 4,
|
2011-08-30 01:00:17 +00:00
|
|
|
argumentStack, ceiling(size, TargetBytesPerWord) * 2, 0);
|
2009-10-07 00:50:32 +00:00
|
|
|
|
2009-10-10 23:46:43 +00:00
|
|
|
appendBranch(c, thunkBranch(c, type), 4, value
|
2009-10-10 21:03:23 +00:00
|
|
|
(c, ValueGeneral, constantSite(c, static_cast<int64_t>(0))),
|
2009-10-07 00:50:32 +00:00
|
|
|
result, address);
|
|
|
|
} else {
|
|
|
|
append
|
2012-05-08 22:13:17 +00:00
|
|
|
(c, new(c->zone)
|
2009-10-07 00:50:32 +00:00
|
|
|
BranchEvent
|
2009-10-10 21:03:23 +00:00
|
|
|
(c, type, size, first, second, address,
|
2009-10-07 00:50:32 +00:00
|
|
|
SiteMask(firstTypeMask, firstRegisterMask, AnyFrameIndex),
|
|
|
|
SiteMask(firstTypeMask, firstRegisterMask >> 32, AnyFrameIndex),
|
|
|
|
SiteMask(secondTypeMask, secondRegisterMask, AnyFrameIndex),
|
|
|
|
SiteMask(secondTypeMask, secondRegisterMask >> 32, AnyFrameIndex)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-10 21:03:23 +00:00
|
|
|
class JumpEvent: public Event {
|
|
|
|
public:
|
2010-01-05 00:17:16 +00:00
|
|
|
JumpEvent(Context* c, UnaryOperation type, Value* address, bool exit,
|
|
|
|
bool cleanLocals):
|
|
|
|
Event(c), type(type), address(address), exit(exit),
|
|
|
|
cleanLocals(cleanLocals)
|
2009-10-10 21:03:23 +00:00
|
|
|
{
|
|
|
|
bool thunk;
|
|
|
|
uint8_t typeMask;
|
|
|
|
uint64_t registerMask;
|
2011-08-30 01:00:17 +00:00
|
|
|
c->arch->plan(type, TargetBytesPerWord, &typeMask, ®isterMask, &thunk);
|
2009-10-10 21:03:23 +00:00
|
|
|
|
|
|
|
assert(c, not thunk);
|
|
|
|
|
|
|
|
addRead(c, this, address, SiteMask(typeMask, registerMask, AnyFrameIndex));
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual const char* name() {
|
|
|
|
return "JumpEvent";
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void compile(Context* c) {
|
|
|
|
if (not unreachable(this)) {
|
2011-08-30 01:00:17 +00:00
|
|
|
apply(c, type, TargetBytesPerWord, address->source, address->source);
|
2009-10-10 21:03:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (Read* r = reads; r; r = r->eventNext) {
|
|
|
|
popRead(c, this, r->value);
|
|
|
|
}
|
2010-01-05 00:17:16 +00:00
|
|
|
|
|
|
|
if (cleanLocals) {
|
|
|
|
for (FrameIterator it(c, 0, c->locals); it.hasMore();) {
|
|
|
|
FrameIterator::Element e = it.next(c);
|
|
|
|
clean(c, e.value, 0);
|
|
|
|
}
|
|
|
|
}
|
2009-10-10 21:03:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool isBranch() { return true; }
|
|
|
|
|
|
|
|
virtual bool allExits() {
|
|
|
|
return exit or unreachable(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
UnaryOperation type;
|
|
|
|
Value* address;
|
|
|
|
bool exit;
|
2010-01-05 00:17:16 +00:00
|
|
|
bool cleanLocals;
|
2009-10-10 21:03:23 +00:00
|
|
|
};
|
|
|
|
|
2008-04-20 05:23:08 +00:00
|
|
|
void
|
2010-01-05 00:17:16 +00:00
|
|
|
appendJump(Context* c, UnaryOperation type, Value* address, bool exit = false,
|
|
|
|
bool cleanLocals = false)
|
2008-04-20 05:23:08 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone) JumpEvent(c, type, address, exit, cleanLocals));
|
2008-04-18 03:47:42 +00:00
|
|
|
}
|
|
|
|
|
2008-05-31 22:14:27 +00:00
|
|
|
class BoundsCheckEvent: public Event {
|
|
|
|
public:
|
|
|
|
BoundsCheckEvent(Context* c, Value* object, unsigned lengthOffset,
|
|
|
|
Value* index, intptr_t handler):
|
|
|
|
Event(c), object(object), lengthOffset(lengthOffset), index(index),
|
|
|
|
handler(handler)
|
|
|
|
{
|
2009-10-04 19:56:48 +00:00
|
|
|
addRead(c, this, object, generalRegisterMask(c));
|
|
|
|
addRead(c, this, index, generalRegisterOrConstantMask(c));
|
2008-05-31 22:14:27 +00:00
|
|
|
}
|
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual const char* name() {
|
|
|
|
return "BoundsCheckEvent";
|
|
|
|
}
|
2008-05-31 22:14:27 +00:00
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual void compile(Context* c) {
|
2008-05-31 22:14:27 +00:00
|
|
|
Assembler* a = c->assembler;
|
|
|
|
|
2008-06-11 00:17:44 +00:00
|
|
|
ConstantSite* constant = findConstantSite(c, index);
|
2008-05-31 23:06:45 +00:00
|
|
|
CodePromise* outOfBoundsPromise = 0;
|
2008-05-31 22:14:27 +00:00
|
|
|
|
|
|
|
if (constant) {
|
2010-09-25 21:48:15 +00:00
|
|
|
if (constant->value->value() < 0) {
|
|
|
|
Assembler::Constant handlerConstant(resolved(c, handler));
|
2011-08-30 01:00:17 +00:00
|
|
|
a->apply(Call, TargetBytesPerWord, ConstantOperand, &handlerConstant);
|
2010-09-25 21:48:15 +00:00
|
|
|
}
|
2008-05-31 22:14:27 +00:00
|
|
|
} else {
|
2008-09-09 00:31:19 +00:00
|
|
|
outOfBoundsPromise = codePromise(c, static_cast<Promise*>(0));
|
2008-05-31 22:14:27 +00:00
|
|
|
|
2009-10-10 21:03:23 +00:00
|
|
|
ConstantSite zero(resolved(c, 0));
|
|
|
|
ConstantSite oob(outOfBoundsPromise);
|
|
|
|
apply(c, JumpIfLess, 4, &zero, &zero, 4, index->source, index->source,
|
2011-08-30 01:00:17 +00:00
|
|
|
TargetBytesPerWord, &oob, &oob);
|
2008-05-31 22:14:27 +00:00
|
|
|
}
|
|
|
|
|
2010-09-25 21:48:15 +00:00
|
|
|
if (constant == 0 or constant->value->value() >= 0) {
|
|
|
|
assert(c, object->source->type(c) == RegisterOperand);
|
|
|
|
MemorySite length(static_cast<RegisterSite*>(object->source)->number,
|
|
|
|
lengthOffset, NoRegister, 1);
|
|
|
|
length.acquired = true;
|
2008-05-31 22:14:27 +00:00
|
|
|
|
2010-12-19 22:23:19 +00:00
|
|
|
CodePromise* nextPromise = codePromise(c, static_cast<Promise*>(0));
|
2008-05-31 22:14:27 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
freezeSource(c, TargetBytesPerWord, index);
|
2008-05-31 22:14:27 +00:00
|
|
|
|
2010-09-25 21:48:15 +00:00
|
|
|
ConstantSite next(nextPromise);
|
|
|
|
apply(c, JumpIfGreater, 4, index->source, index->source, 4, &length,
|
2011-08-30 01:00:17 +00:00
|
|
|
&length, TargetBytesPerWord, &next, &next);
|
2008-05-31 22:14:27 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
thawSource(c, TargetBytesPerWord, index);
|
2008-05-31 22:14:27 +00:00
|
|
|
|
2010-09-25 21:48:15 +00:00
|
|
|
if (constant == 0) {
|
|
|
|
outOfBoundsPromise->offset = a->offset();
|
|
|
|
}
|
2008-05-31 22:14:27 +00:00
|
|
|
|
2010-09-25 21:48:15 +00:00
|
|
|
Assembler::Constant handlerConstant(resolved(c, handler));
|
2011-08-30 01:00:17 +00:00
|
|
|
a->apply(Call, TargetBytesPerWord, ConstantOperand, &handlerConstant);
|
2010-09-25 21:48:15 +00:00
|
|
|
|
|
|
|
nextPromise->offset = a->offset();
|
|
|
|
}
|
2008-05-31 22:14:27 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
popRead(c, this, object);
|
|
|
|
popRead(c, this, index);
|
2008-05-31 22:14:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Value* object;
|
|
|
|
unsigned lengthOffset;
|
|
|
|
Value* index;
|
|
|
|
intptr_t handler;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
appendBoundsCheck(Context* c, Value* object, unsigned lengthOffset,
|
|
|
|
Value* index, intptr_t handler)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone) BoundsCheckEvent(c, object, lengthOffset, index, handler));
|
2008-05-31 22:14:27 +00:00
|
|
|
}
|
|
|
|
|
2008-09-25 00:48:32 +00:00
|
|
|
class FrameSiteEvent: public Event {
|
2008-09-09 00:31:19 +00:00
|
|
|
public:
|
2009-01-25 22:03:38 +00:00
|
|
|
FrameSiteEvent(Context* c, Value* value, int index):
|
|
|
|
Event(c), value(value), index(index)
|
2008-09-09 00:31:19 +00:00
|
|
|
{ }
|
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual const char* name() {
|
2008-09-25 00:48:32 +00:00
|
|
|
return "FrameSiteEvent";
|
2008-09-15 02:28:42 +00:00
|
|
|
}
|
2008-09-09 00:31:19 +00:00
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
virtual void compile(Context* c) {
|
2010-11-26 19:36:43 +00:00
|
|
|
if (live(c, value)) {
|
2009-01-25 22:03:38 +00:00
|
|
|
addSite(c, value, frameSite(c, index));
|
2008-11-14 00:59:21 +00:00
|
|
|
}
|
2008-09-09 00:31:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Value* value;
|
|
|
|
int index;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
appendFrameSite(Context* c, Value* value, int index)
|
2008-09-09 00:31:19 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone) FrameSiteEvent(c, value, index));
|
2008-09-09 00:31:19 +00:00
|
|
|
}
|
|
|
|
|
2008-10-05 00:14:43 +00:00
|
|
|
unsigned
|
|
|
|
frameFootprint(Context* c, Stack* s)
|
|
|
|
{
|
2009-01-25 22:03:38 +00:00
|
|
|
return c->localFootprint + (s ? (s->index + 1) : 0);
|
2008-10-14 00:18:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-15 00:45:31 +00:00
|
|
|
visit(Context* c, Link* link)
|
2008-10-14 00:18:18 +00:00
|
|
|
{
|
2009-04-08 00:55:43 +00:00
|
|
|
// 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);
|
2008-10-14 00:18:18 +00:00
|
|
|
|
|
|
|
ForkState* forkState = link->forkState;
|
|
|
|
if (forkState) {
|
|
|
|
for (unsigned i = 0; i < forkState->readCount; ++i) {
|
2008-11-02 20:35:35 +00:00
|
|
|
ForkElement* p = forkState->elements + i;
|
2008-10-14 00:18:18 +00:00
|
|
|
Value* v = p->value;
|
|
|
|
v->reads = p->read->nextTarget();
|
2009-04-08 00:55:43 +00:00
|
|
|
// fprintf(stderr, "next read %p for %p from %p\n", v->reads, v, p->read);
|
2010-11-26 19:36:43 +00:00
|
|
|
if (not live(c, v)) {
|
2008-10-14 00:18:18 +00:00
|
|
|
clearSites(c, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JunctionState* junctionState = link->junctionState;
|
|
|
|
if (junctionState) {
|
2008-12-15 14:35:19 +00:00
|
|
|
for (unsigned i = 0; i < junctionState->frameFootprint; ++i) {
|
|
|
|
StubReadPair* p = junctionState->reads + i;
|
|
|
|
|
2008-12-23 01:25:00 +00:00
|
|
|
if (p->value and p->value->reads) {
|
2008-12-15 14:35:19 +00:00
|
|
|
assert(c, p->value->reads == p->read);
|
2009-01-25 22:03:38 +00:00
|
|
|
popRead(c, 0, p->value);
|
2008-12-15 14:35:19 +00:00
|
|
|
}
|
2008-10-14 00:18:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-01 19:14:13 +00:00
|
|
|
class BuddyEvent: public Event {
|
|
|
|
public:
|
2009-01-25 22:03:38 +00:00
|
|
|
BuddyEvent(Context* c, Value* original, Value* buddy):
|
2008-11-01 19:14:13 +00:00
|
|
|
Event(c), original(original), buddy(buddy)
|
|
|
|
{
|
2009-10-24 23:18:56 +00:00
|
|
|
addRead(c, this, original, SiteMask(~0, ~0, AnyFrameIndex), buddy);
|
2008-11-01 19:14:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual const char* name() {
|
|
|
|
return "BuddyEvent";
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void compile(Context* c) {
|
2009-11-28 04:15:12 +00:00
|
|
|
if (DebugBuddies) {
|
|
|
|
fprintf(stderr, "original %p buddy %p\n", original, buddy);
|
|
|
|
}
|
|
|
|
|
2009-09-26 19:43:44 +00:00
|
|
|
assert(c, hasSite(c, original));
|
2008-12-12 01:09:36 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
assert(c, original);
|
|
|
|
assert(c, buddy);
|
|
|
|
|
2008-11-12 00:39:26 +00:00
|
|
|
addBuddy(original, buddy);
|
2008-11-01 19:14:13 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
popRead(c, this, original);
|
2008-11-01 19:14:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Value* original;
|
|
|
|
Value* buddy;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
appendBuddy(Context* c, Value* original, Value* buddy)
|
2008-11-01 19:14:13 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone) BuddyEvent(c, original, buddy));
|
2008-11-01 19:14:13 +00:00
|
|
|
}
|
|
|
|
|
2008-11-25 17:34:48 +00:00
|
|
|
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) {
|
2009-01-25 22:03:38 +00:00
|
|
|
popRead(c, this, r->value);
|
2008-11-25 17:34:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
appendSaveLocals(Context* c)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone) SaveLocalsEvent(c));
|
2008-11-25 17:34:48 +00:00
|
|
|
}
|
|
|
|
|
2008-09-13 21:09:26 +00:00
|
|
|
class DummyEvent: public Event {
|
|
|
|
public:
|
|
|
|
DummyEvent(Context* c):
|
|
|
|
Event(c)
|
2008-10-05 00:14:43 +00:00
|
|
|
{ }
|
2008-09-15 02:28:42 +00:00
|
|
|
|
|
|
|
virtual const char* name() {
|
|
|
|
return "DummyEvent";
|
|
|
|
}
|
2008-09-13 21:09:26 +00:00
|
|
|
|
|
|
|
virtual void compile(Context*) { }
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
appendDummy(Context* c)
|
|
|
|
{
|
2008-10-05 00:14:43 +00:00
|
|
|
Stack* stack = c->stack;
|
|
|
|
Local* locals = c->locals;
|
|
|
|
LogicalInstruction* i = c->logicalCode[c->logicalIp];
|
|
|
|
|
|
|
|
c->stack = i->stack;
|
|
|
|
c->locals = i->locals;
|
|
|
|
|
2012-05-08 22:13:17 +00:00
|
|
|
append(c, new(c->zone) DummyEvent(c));
|
2008-10-05 00:14:43 +00:00
|
|
|
|
|
|
|
c->stack = stack;
|
|
|
|
c->locals = locals;
|
2008-09-13 21:09:26 +00:00
|
|
|
}
|
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
void
|
|
|
|
append(Context* c, Event* e)
|
|
|
|
{
|
2008-10-25 02:12:02 +00:00
|
|
|
LogicalInstruction* i = c->logicalCode[c->logicalIp];
|
|
|
|
if (c->stack != i->stack or c->locals != i->locals) {
|
|
|
|
appendDummy(c);
|
2008-10-14 00:18:18 +00:00
|
|
|
}
|
|
|
|
|
2008-10-25 02:12:02 +00:00
|
|
|
if (DebugAppend) {
|
|
|
|
fprintf(stderr, " -- append %s at %d with %d stack before\n",
|
|
|
|
e->name(), e->logicalInstruction->index, c->stack ?
|
2009-01-25 22:03:38 +00:00
|
|
|
c->stack->index + 1 : 0);
|
2008-10-25 02:12:02 +00:00
|
|
|
}
|
2008-10-14 00:18:18 +00:00
|
|
|
|
|
|
|
if (c->lastEvent) {
|
|
|
|
c->lastEvent->next = e;
|
|
|
|
} else {
|
|
|
|
c->firstEvent = e;
|
|
|
|
}
|
|
|
|
c->lastEvent = e;
|
|
|
|
|
|
|
|
Event* p = c->predecessor;
|
|
|
|
if (p) {
|
2009-02-14 20:26:39 +00:00
|
|
|
if (DebugAppend) {
|
|
|
|
fprintf(stderr, "%d precedes %d\n", p->logicalInstruction->index,
|
|
|
|
e->logicalInstruction->index);
|
|
|
|
}
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
Link* link = local::link
|
|
|
|
(c, p, e->predecessors, e, p->successors, c->forkState);
|
2008-10-14 00:18:18 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
Site*
|
2009-01-25 22:03:38 +00:00
|
|
|
readSource(Context* c, Read* r)
|
2009-01-04 01:17:51 +00:00
|
|
|
{
|
2009-10-04 19:56:48 +00:00
|
|
|
Value* v = r->value;
|
|
|
|
|
2008-12-20 21:55:45 +00:00
|
|
|
if (DebugReads) {
|
2009-10-04 19:56:48 +00:00
|
|
|
char buffer[1024]; sitesToString(c, v, buffer, 1024);
|
|
|
|
fprintf(stderr, "read source for %p from %s\n", v, buffer);
|
2008-12-20 21:55:45 +00:00
|
|
|
}
|
2008-05-15 20:00:57 +00:00
|
|
|
|
2009-10-04 19:56:48 +00:00
|
|
|
if (not hasSite(c, v)) {
|
2009-09-26 19:43:44 +00:00
|
|
|
if (DebugReads) {
|
2009-10-04 19:56:48 +00:00
|
|
|
fprintf(stderr, "no sites found for %p\n", v);
|
2009-09-26 19:43:44 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2009-01-04 01:17:51 +00:00
|
|
|
|
2009-11-30 15:10:34 +00:00
|
|
|
Value* high = r->high(c);
|
|
|
|
if (high) {
|
2009-11-30 22:08:59 +00:00
|
|
|
return pickMatchOrMove(c, r, high->source, 0, true);
|
2009-11-30 15:10:34 +00:00
|
|
|
} else {
|
|
|
|
return pickSiteOrMove(c, r, true, true);
|
|
|
|
}
|
2007-12-11 21:26:59 +00:00
|
|
|
}
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
void
|
|
|
|
propagateJunctionSites(Context* c, Event* e, Site** sites)
|
2008-07-23 23:58:29 +00:00
|
|
|
{
|
2009-01-04 01:17:51 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-09-15 02:28:42 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
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<Site**>
|
|
|
|
(c->zone->allocate(size));
|
|
|
|
memset(junctionSites, 0, size);
|
2008-07-23 23:58:29 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
propagateJunctionSites(c, s, junctionSites);
|
|
|
|
break;
|
2008-07-23 23:58:29 +00:00
|
|
|
}
|
2009-01-04 01:17:51 +00:00
|
|
|
}
|
|
|
|
}
|
2008-07-23 23:58:29 +00:00
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
class SiteRecord {
|
|
|
|
public:
|
|
|
|
Site* site;
|
|
|
|
Value* value;
|
|
|
|
};
|
|
|
|
|
2012-06-01 23:43:42 +00:00
|
|
|
void
|
|
|
|
init(SiteRecord* r, Site* s, Value* v)
|
|
|
|
{
|
|
|
|
r->site = s;
|
|
|
|
r->value = v;
|
|
|
|
}
|
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
class SiteRecordList {
|
|
|
|
public:
|
|
|
|
SiteRecordList(SiteRecord* records, unsigned capacity):
|
|
|
|
records(records), index(0), capacity(capacity)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
SiteRecord* records;
|
|
|
|
unsigned index;
|
|
|
|
unsigned capacity;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
freeze(Context* c, SiteRecordList* frozen, Site* s, Value* v)
|
2009-01-11 22:53:51 +00:00
|
|
|
{
|
|
|
|
assert(c, frozen->index < frozen->capacity);
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
s->freeze(c, v);
|
2012-06-01 23:43:42 +00:00
|
|
|
init(new (frozen->records + (frozen->index ++)) SiteRecord, s, v);
|
2009-01-11 22:53:51 +00:00
|
|
|
}
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
void
|
2009-01-11 22:53:51 +00:00
|
|
|
thaw(Context* c, SiteRecordList* frozen)
|
|
|
|
{
|
|
|
|
while (frozen->index) {
|
|
|
|
SiteRecord* sr = frozen->records + (-- frozen->index);
|
2009-01-25 22:03:38 +00:00
|
|
|
sr->site->thaw(c, sr->value);
|
2009-01-11 22:53:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
bool
|
2009-01-11 22:53:51 +00:00
|
|
|
resolveOriginalSites(Context* c, Event* e, SiteRecordList* frozen,
|
|
|
|
Site** sites)
|
2009-01-04 01:17:51 +00:00
|
|
|
{
|
|
|
|
bool complete = true;
|
2009-10-26 23:59:20 +00:00
|
|
|
for (FrameIterator it(c, e->stackAfter, e->localsAfter, true);
|
|
|
|
it.hasMore();)
|
|
|
|
{
|
2009-01-04 01:17:51 +00:00
|
|
|
FrameIterator::Element el = it.next(c);
|
2009-01-11 22:53:51 +00:00
|
|
|
Value* v = el.value;
|
2010-11-26 19:36:43 +00:00
|
|
|
Read* r = v ? live(c, v) : 0;
|
2009-08-10 13:51:19 +00:00
|
|
|
Site* s = sites[el.localIndex];
|
2009-01-11 22:53:51 +00:00
|
|
|
|
|
|
|
if (r) {
|
2009-08-10 13:51:19 +00:00
|
|
|
if (s) {
|
2009-01-04 01:17:51 +00:00
|
|
|
if (DebugControl) {
|
|
|
|
char buffer[256];
|
2009-08-10 13:51:19 +00:00
|
|
|
s->toString(c, buffer, 256);
|
2009-01-04 01:17:51 +00:00
|
|
|
fprintf(stderr, "resolve original %s for %p local %d frame %d\n",
|
2009-08-10 13:51:19 +00:00
|
|
|
buffer, v, el.localIndex, frameIndex(c, &el));
|
2009-01-04 01:17:51 +00:00
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
Site* target = pickSiteOrMove
|
|
|
|
(c, v, s->mask(c), true, true, ResolveRegisterReserveCount);
|
|
|
|
|
|
|
|
freeze(c, frozen, target, v);
|
2009-01-04 01:17:51 +00:00
|
|
|
} else {
|
|
|
|
complete = false;
|
2008-11-26 02:23:47 +00:00
|
|
|
}
|
2009-08-10 13:51:19 +00:00
|
|
|
} else if (s) {
|
|
|
|
if (DebugControl) {
|
|
|
|
char buffer[256];
|
|
|
|
s->toString(c, buffer, 256);
|
|
|
|
fprintf(stderr, "freeze original %s for %p local %d frame %d\n",
|
|
|
|
buffer, v, el.localIndex, frameIndex(c, &el));
|
|
|
|
}
|
|
|
|
|
2009-10-26 23:59:20 +00:00
|
|
|
Value dummy(0, 0, ValueGeneral);
|
|
|
|
addSite(c, &dummy, s);
|
|
|
|
removeSite(c, &dummy, s);
|
|
|
|
freeze(c, frozen, s, 0);
|
2008-07-23 23:58:29 +00:00
|
|
|
}
|
2009-01-04 01:17:51 +00:00
|
|
|
}
|
2008-07-23 23:58:29 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
return complete;
|
|
|
|
}
|
2008-10-12 00:23:08 +00:00
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
bool
|
2009-01-11 22:53:51 +00:00
|
|
|
resolveSourceSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites)
|
2009-01-04 01:17:51 +00:00
|
|
|
{
|
|
|
|
bool complete = true;
|
|
|
|
for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) {
|
|
|
|
FrameIterator::Element el = it.next(c);
|
|
|
|
Value* v = el.value;
|
2010-11-26 19:36:43 +00:00
|
|
|
Read* r = live(c, v);
|
2009-01-04 01:17:51 +00:00
|
|
|
|
2009-01-04 21:52:46 +00:00
|
|
|
if (r and sites[el.localIndex] == 0) {
|
2009-12-01 02:06:01 +00:00
|
|
|
SiteMask mask((1 << RegisterOperand) | (1 << MemoryOperand),
|
|
|
|
c->arch->generalRegisterMask(), AnyFrameIndex);
|
2009-01-04 01:17:51 +00:00
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
Site* s = pickSourceSite
|
2009-12-01 02:06:01 +00:00
|
|
|
(c, r, 0, 0, &mask, true, false, true, acceptForResolve);
|
2009-01-04 01:17:51 +00:00
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
freeze(c, frozen, s, v);
|
|
|
|
|
|
|
|
sites[el.localIndex] = s->copy(c);
|
2009-01-04 01:17:51 +00:00
|
|
|
} else {
|
|
|
|
complete = false;
|
|
|
|
}
|
2008-11-02 22:25:51 +00:00
|
|
|
}
|
2008-07-23 23:58:29 +00:00
|
|
|
}
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
return complete;
|
2008-07-23 23:58:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-01-11 22:53:51 +00:00
|
|
|
resolveTargetSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites)
|
2008-07-23 23:58:29 +00:00
|
|
|
{
|
2009-01-04 01:17:51 +00:00
|
|
|
for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) {
|
|
|
|
FrameIterator::Element el = it.next(c);
|
2009-01-11 22:53:51 +00:00
|
|
|
Value* v = el.value;
|
2010-11-26 19:36:43 +00:00
|
|
|
Read* r = live(c, v);
|
2009-01-04 01:17:51 +00:00
|
|
|
|
2009-01-04 21:52:46 +00:00
|
|
|
if (r and sites[el.localIndex] == 0) {
|
2009-12-01 02:06:01 +00:00
|
|
|
SiteMask mask((1 << RegisterOperand) | (1 << MemoryOperand),
|
|
|
|
c->arch->generalRegisterMask(), AnyFrameIndex);
|
2009-01-04 21:52:46 +00:00
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
Site* s = pickSourceSite
|
2009-12-25 00:47:58 +00:00
|
|
|
(c, r, 0, 0, &mask, false, true, true, acceptForResolve);
|
2009-12-05 22:49:53 +00:00
|
|
|
|
2009-01-04 21:52:46 +00:00
|
|
|
if (s == 0) {
|
2009-12-05 22:49:53 +00:00
|
|
|
s = maybeMove(c, v, mask, false, true, ResolveRegisterReserveCount);
|
2009-01-04 21:52:46 +00:00
|
|
|
}
|
2009-01-04 01:17:51 +00:00
|
|
|
|
2009-11-28 04:15:12 +00:00
|
|
|
freeze(c, frozen, s, v);
|
|
|
|
|
|
|
|
sites[el.localIndex] = s->copy(c);
|
|
|
|
|
2009-01-04 01:17:51 +00:00
|
|
|
if (DebugControl) {
|
2009-11-28 04:15:12 +00:00
|
|
|
char buffer[256]; sites[el.localIndex]->toString(c, buffer, 256);
|
2009-01-04 01:17:51 +00:00
|
|
|
fprintf(stderr, "resolve target %s for %p local %d frame %d\n",
|
|
|
|
buffer, el.value, el.localIndex, frameIndex(c, &el));
|
2008-07-23 23:58:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-16 17:45:36 +00:00
|
|
|
void
|
2009-01-11 22:53:51 +00:00
|
|
|
resolveJunctionSites(Context* c, Event* e, SiteRecordList* frozen)
|
2008-08-16 17:45:36 +00:00
|
|
|
{
|
2009-01-04 01:17:51 +00:00
|
|
|
bool complete;
|
2008-12-12 01:09:36 +00:00
|
|
|
if (e->junctionSites) {
|
2009-01-11 22:53:51 +00:00
|
|
|
complete = resolveOriginalSites(c, e, frozen, e->junctionSites);
|
2008-12-12 01:09:36 +00:00
|
|
|
} else {
|
2009-01-04 01:17:51 +00:00
|
|
|
propagateJunctionSites(c, e);
|
|
|
|
complete = false;
|
2008-12-12 01:09:36 +00:00
|
|
|
}
|
2008-07-23 23:58:29 +00:00
|
|
|
|
2008-12-12 01:09:36 +00:00
|
|
|
if (e->junctionSites) {
|
2009-01-04 21:52:46 +00:00
|
|
|
if (not complete) {
|
2009-01-11 22:53:51 +00:00
|
|
|
complete = resolveSourceSites(c, e, frozen, e->junctionSites);
|
2009-01-04 21:52:46 +00:00
|
|
|
if (not complete) {
|
2009-01-11 22:53:51 +00:00
|
|
|
resolveTargetSites(c, e, frozen, e->junctionSites);
|
2009-01-04 21:52:46 +00:00
|
|
|
}
|
2008-12-12 01:09:36 +00:00
|
|
|
}
|
2008-10-25 02:12:02 +00:00
|
|
|
|
2008-12-12 01:09:36 +00:00
|
|
|
if (DebugControl) {
|
|
|
|
fprintf(stderr, "resolved junction sites %p at %d\n",
|
|
|
|
e->junctionSites, e->logicalInstruction->index);
|
|
|
|
}
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
2008-12-12 01:09:36 +00:00
|
|
|
}
|
2008-07-23 23:58:29 +00:00
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
void
|
|
|
|
resolveBranchSites(Context* c, Event* e, SiteRecordList* frozen)
|
2008-12-12 01:09:36 +00:00
|
|
|
{
|
2009-01-11 18:48:02 +00:00
|
|
|
if (e->successors->nextSuccessor and e->junctionSites == 0) {
|
2009-01-11 22:53:51 +00:00
|
|
|
unsigned footprint = frameFootprint(c, e->stackAfter);
|
2009-08-27 00:26:44 +00:00
|
|
|
RUNTIME_ARRAY(Site*, branchSites, footprint);
|
|
|
|
memset(RUNTIME_ARRAY_BODY(branchSites), 0, sizeof(Site*) * footprint);
|
2009-01-04 21:52:46 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
if (not resolveSourceSites(c, e, frozen, RUNTIME_ARRAY_BODY(branchSites)))
|
|
|
|
{
|
|
|
|
resolveTargetSites(c, e, frozen, RUNTIME_ARRAY_BODY(branchSites));
|
2009-01-04 21:52:46 +00:00
|
|
|
}
|
2009-01-11 18:48:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
captureBranchSnapshots(Context* c, Event* e)
|
|
|
|
{
|
|
|
|
if (e->successors->nextSuccessor) {
|
2008-11-01 19:14:13 +00:00
|
|
|
for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) {
|
|
|
|
FrameIterator::Element el = it.next(c);
|
2008-11-07 00:39:38 +00:00
|
|
|
e->snapshots = makeSnapshots(c, el.value, e->snapshots);
|
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
for (Cell* sv = e->successors->forkState->saved; sv; sv = sv->next) {
|
|
|
|
e->snapshots = makeSnapshots
|
|
|
|
(c, static_cast<Value*>(sv->value), e->snapshots);
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
2008-09-15 02:28:42 +00:00
|
|
|
|
2008-11-02 22:25:51 +00:00
|
|
|
if (DebugControl) {
|
|
|
|
fprintf(stderr, "captured snapshots %p at %d\n",
|
|
|
|
e->snapshots, e->logicalInstruction->index);
|
|
|
|
}
|
2008-11-01 22:16:18 +00:00
|
|
|
}
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
2008-04-17 02:55:38 +00:00
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
void
|
|
|
|
populateSiteTables(Context* c, Event* e, SiteRecordList* frozen)
|
2008-12-12 01:09:36 +00:00
|
|
|
{
|
2009-01-11 22:53:51 +00:00
|
|
|
resolveJunctionSites(c, e, frozen);
|
2008-12-13 19:59:02 +00:00
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
resolveBranchSites(c, e, frozen);
|
2008-12-12 01:09:36 +00:00
|
|
|
}
|
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
setSites(Context* c, Value* v, Site* s)
|
2008-10-12 00:23:08 +00:00
|
|
|
{
|
2010-11-26 19:36:43 +00:00
|
|
|
assert(c, live(c, v));
|
2008-12-16 01:21:01 +00:00
|
|
|
|
2008-10-12 00:23:08 +00:00
|
|
|
for (; s; s = s->next) {
|
2009-01-25 22:03:38 +00:00
|
|
|
addSite(c, v, s->copy(c));
|
2008-10-12 00:23:08 +00:00
|
|
|
}
|
|
|
|
|
2008-11-02 22:25:51 +00:00
|
|
|
if (DebugControl) {
|
2009-01-04 01:17:51 +00:00
|
|
|
char buffer[256]; sitesToString(c, v->sites, buffer, 256);
|
2008-11-02 22:25:51 +00:00
|
|
|
fprintf(stderr, "set sites %s for %p\n", buffer, v);
|
|
|
|
}
|
2008-10-12 00:23:08 +00:00
|
|
|
}
|
|
|
|
|
2008-08-16 17:45:36 +00:00
|
|
|
void
|
2008-11-01 22:16:18 +00:00
|
|
|
resetFrame(Context* c, Event* e)
|
2008-08-16 17:45:36 +00:00
|
|
|
{
|
2008-11-01 19:14:13 +00:00
|
|
|
for (FrameIterator it(c, e->stackBefore, e->localsBefore); it.hasMore();) {
|
|
|
|
FrameIterator::Element el = it.next(c);
|
|
|
|
clearSites(c, el.value);
|
2008-10-12 00:23:08 +00:00
|
|
|
}
|
2011-03-27 20:15:05 +00:00
|
|
|
|
2011-03-28 14:54:37 +00:00
|
|
|
while (c->acquiredResources) {
|
|
|
|
clearSites(c, c->acquiredResources->value);
|
2011-03-27 20:15:05 +00:00
|
|
|
}
|
2008-11-01 22:16:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
setSites(Context* c, Event* e, Site** sites)
|
|
|
|
{
|
|
|
|
resetFrame(c, e);
|
2008-10-12 00:23:08 +00:00
|
|
|
|
2008-11-01 19:14:13 +00:00
|
|
|
for (FrameIterator it(c, e->stackBefore, e->localsBefore); it.hasMore();) {
|
|
|
|
FrameIterator::Element el = it.next(c);
|
2008-11-01 22:16:18 +00:00
|
|
|
if (sites[el.localIndex]) {
|
2010-11-26 19:36:43 +00:00
|
|
|
if (live(c, el.value)) {
|
2009-01-25 22:03:38 +00:00
|
|
|
setSites(c, el.value, sites[el.localIndex]);
|
2009-08-10 13:51:19 +00:00
|
|
|
} else if (DebugControl) {
|
|
|
|
char buffer[256]; sitesToString(c, sites[el.localIndex], buffer, 256);
|
|
|
|
fprintf(stderr, "skip sites %s for %p local %d frame %d\n",
|
|
|
|
buffer, el.value, el.localIndex, frameIndex(c, &el));
|
2008-11-01 22:16:18 +00:00
|
|
|
}
|
2009-08-10 13:51:19 +00:00
|
|
|
} else if (DebugControl) {
|
|
|
|
fprintf(stderr, "no sites for %p local %d frame %d\n",
|
|
|
|
el.value, el.localIndex, frameIndex(c, &el));
|
2008-11-01 22:16:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-13 19:59:02 +00:00
|
|
|
void
|
|
|
|
removeBuddies(Context* c)
|
|
|
|
{
|
|
|
|
for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) {
|
|
|
|
FrameIterator::Element el = it.next(c);
|
|
|
|
removeBuddy(c, el.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-01 22:16:18 +00:00
|
|
|
void
|
|
|
|
restore(Context* c, Event* e, Snapshot* snapshots)
|
|
|
|
{
|
|
|
|
for (Snapshot* s = snapshots; s; s = s->next) {
|
2010-11-26 19:36:43 +00:00
|
|
|
Value* v = s->value;
|
|
|
|
Value* next = v->buddy;
|
|
|
|
if (v != next) {
|
|
|
|
v->buddy = v;
|
|
|
|
Value* p = next;
|
|
|
|
while (p->buddy != v) p = p->buddy;
|
|
|
|
p->buddy = next;
|
|
|
|
}
|
|
|
|
}
|
2008-11-01 22:16:18 +00:00
|
|
|
|
2010-11-26 19:36:43 +00:00
|
|
|
for (Snapshot* s = snapshots; s; s = s->next) {
|
2009-08-27 00:26:44 +00:00
|
|
|
assert(c, s->buddy);
|
|
|
|
|
2008-11-01 22:16:18 +00:00
|
|
|
s->value->buddy = s->buddy;
|
|
|
|
}
|
|
|
|
|
|
|
|
resetFrame(c, e);
|
|
|
|
|
|
|
|
for (Snapshot* s = snapshots; s; s = s->next) {
|
2010-11-26 19:36:43 +00:00
|
|
|
if (live(c, s->value)) {
|
|
|
|
if (live(c, s->value) and s->sites and s->value->sites == 0) {
|
2009-01-25 22:03:38 +00:00
|
|
|
setSites(c, s->value, s->sites);
|
2008-11-01 22:16:18 +00:00
|
|
|
}
|
2008-10-12 00:23:08 +00:00
|
|
|
}
|
2010-11-26 19:36:43 +00:00
|
|
|
|
|
|
|
// 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(c, s->value));
|
2008-10-12 00:23:08 +00:00
|
|
|
}
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
2008-07-23 23:58:29 +00:00
|
|
|
|
2008-08-16 17:45:36 +00:00
|
|
|
void
|
|
|
|
populateSources(Context* c, Event* e)
|
|
|
|
{
|
2009-08-27 00:26:44 +00:00
|
|
|
RUNTIME_ARRAY(SiteRecord, frozenRecords, e->readCount);
|
|
|
|
SiteRecordList frozen(RUNTIME_ARRAY_BODY(frozenRecords), e->readCount);
|
2009-01-04 21:52:46 +00:00
|
|
|
|
2008-08-16 17:45:36 +00:00
|
|
|
for (Read* r = e->reads; r; r = r->eventNext) {
|
2009-01-25 22:03:38 +00:00
|
|
|
r->value->source = readSource(c, r);
|
2008-08-16 17:45:36 +00:00
|
|
|
if (r->value->source) {
|
2008-12-20 21:55:45 +00:00
|
|
|
if (DebugReads) {
|
|
|
|
char buffer[256]; r->value->source->toString(c, buffer, 256);
|
|
|
|
fprintf(stderr, "freeze source %s for %p\n",
|
|
|
|
buffer, r->value);
|
|
|
|
}
|
2008-12-12 01:09:36 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
freeze(c, &frozen, r->value->source, r->value);
|
2008-07-23 23:58:29 +00:00
|
|
|
}
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
thaw(c, &frozen);
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
2008-07-23 23:58:29 +00:00
|
|
|
|
2008-09-22 00:58:54 +00:00
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
setStubRead(Context* c, StubReadPair* p, Value* v)
|
2008-09-22 00:58:54 +00:00
|
|
|
{
|
2008-11-01 19:14:13 +00:00
|
|
|
if (v) {
|
2009-01-25 22:03:38 +00:00
|
|
|
StubRead* r = stubRead(c);
|
2008-12-15 14:35:19 +00:00
|
|
|
if (DebugReads) {
|
|
|
|
fprintf(stderr, "add stub read %p to %p\n", r, v);
|
|
|
|
}
|
2008-10-14 00:18:18 +00:00
|
|
|
addRead(c, 0, v, r);
|
2008-09-22 00:58:54 +00:00
|
|
|
|
|
|
|
p->value = v;
|
|
|
|
p->read = r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-14 00:18:18 +00:00
|
|
|
populateJunctionReads(Context* c, Link* link)
|
2008-09-22 00:58:54 +00:00
|
|
|
{
|
2008-10-14 00:18:18 +00:00
|
|
|
JunctionState* state = new
|
|
|
|
(c->zone->allocate
|
|
|
|
(sizeof(JunctionState)
|
|
|
|
+ (sizeof(StubReadPair) * frameFootprint(c, c->stack))))
|
2008-12-15 14:35:19 +00:00
|
|
|
JunctionState(frameFootprint(c, c->stack));
|
2008-09-22 14:28:18 +00:00
|
|
|
|
2008-12-15 14:35:19 +00:00
|
|
|
memset(state->reads, 0, sizeof(StubReadPair) * frameFootprint(c, c->stack));
|
2008-10-14 00:18:18 +00:00
|
|
|
|
2008-12-15 14:35:19 +00:00
|
|
|
link->junctionState = state;
|
2008-11-01 19:14:13 +00:00
|
|
|
|
|
|
|
for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) {
|
|
|
|
FrameIterator::Element e = it.next(c);
|
2009-01-25 22:03:38 +00:00
|
|
|
setStubRead(c, state->reads + e.localIndex, e.value);
|
2008-09-22 00:58:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-12-15 14:35:19 +00:00
|
|
|
updateJunctionReads(Context* c, JunctionState* state)
|
2008-09-22 00:58:54 +00:00
|
|
|
{
|
2008-12-15 14:35:19 +00:00
|
|
|
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) {
|
2010-11-26 19:36:43 +00:00
|
|
|
Read* r = live(c, e.value);
|
2008-12-12 01:09:36 +00:00
|
|
|
if (r) {
|
2008-12-15 14:35:19 +00:00
|
|
|
if (DebugReads) {
|
|
|
|
fprintf(stderr, "stub read %p for %p valid: %p\n",
|
|
|
|
p->read, p->value, r);
|
|
|
|
}
|
2008-12-12 01:09:36 +00:00
|
|
|
p->read->read = r;
|
|
|
|
}
|
|
|
|
}
|
2008-09-22 00:58:54 +00:00
|
|
|
}
|
2008-12-15 14:35:19 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2008-09-22 00:58:54 +00:00
|
|
|
}
|
|
|
|
|
2008-08-16 17:45:36 +00:00
|
|
|
LogicalInstruction*
|
|
|
|
next(Context* c, LogicalInstruction* i)
|
|
|
|
{
|
|
|
|
for (unsigned n = i->index + 1; n < c->logicalCodeLength; ++n) {
|
|
|
|
i = c->logicalCode[n];
|
2008-09-13 21:09:26 +00:00
|
|
|
if (i) return i;
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2008-07-23 23:58:29 +00:00
|
|
|
|
2008-08-16 17:45:36 +00:00
|
|
|
class Block {
|
|
|
|
public:
|
|
|
|
Block(Event* head):
|
2008-11-07 00:39:38 +00:00
|
|
|
head(head), nextBlock(0), nextInstruction(0), assemblerBlock(0), start(0)
|
2008-08-16 17:45:36 +00:00
|
|
|
{ }
|
2008-07-23 23:58:29 +00:00
|
|
|
|
2008-08-16 17:45:36 +00:00
|
|
|
Event* head;
|
2008-11-07 00:39:38 +00:00
|
|
|
Block* nextBlock;
|
2008-08-16 17:45:36 +00:00
|
|
|
LogicalInstruction* nextInstruction;
|
2008-09-07 20:12:11 +00:00
|
|
|
Assembler::Block* assemblerBlock;
|
2008-08-16 17:45:36 +00:00
|
|
|
unsigned start;
|
|
|
|
};
|
2008-07-23 23:58:29 +00:00
|
|
|
|
2008-08-16 17:45:36 +00:00
|
|
|
Block*
|
|
|
|
block(Context* c, Event* head)
|
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c->zone) Block(head);
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
|
|
|
|
2011-02-28 06:03:13 +00:00
|
|
|
void
|
2010-12-19 22:23:19 +00:00
|
|
|
compile(Context* c, uintptr_t stackOverflowHandler, unsigned stackLimitOffset)
|
2008-08-16 17:45:36 +00:00
|
|
|
{
|
2008-11-08 23:21:30 +00:00
|
|
|
if (c->logicalCode[c->logicalIp]->lastEvent == 0) {
|
2008-10-05 00:14:43 +00:00
|
|
|
appendDummy(c);
|
|
|
|
}
|
|
|
|
|
2008-08-16 17:45:36 +00:00
|
|
|
Assembler* a = c->assembler;
|
|
|
|
|
|
|
|
Block* firstBlock = block(c, c->firstEvent);
|
|
|
|
Block* block = firstBlock;
|
|
|
|
|
2010-12-19 22:23:19 +00:00
|
|
|
if (stackOverflowHandler) {
|
2011-01-30 21:14:57 +00:00
|
|
|
a->checkStackOverflow(stackOverflowHandler, stackLimitOffset);
|
2010-12-19 22:23:19 +00:00
|
|
|
}
|
|
|
|
|
2008-09-28 19:00:52 +00:00
|
|
|
a->allocateFrame(c->alignedFrameSize);
|
2008-08-16 17:45:36 +00:00
|
|
|
|
|
|
|
for (Event* e = c->firstEvent; e; e = e->next) {
|
2008-09-15 02:28:42 +00:00
|
|
|
if (DebugCompile) {
|
|
|
|
fprintf(stderr,
|
2008-11-09 23:56:37 +00:00
|
|
|
" -- compile %s at %d with %d preds %d succs %d stack\n",
|
2008-09-15 02:28:42 +00:00
|
|
|
e->name(), e->logicalInstruction->index,
|
2008-10-14 00:18:18 +00:00
|
|
|
countPredecessors(e->predecessors),
|
|
|
|
countSuccessors(e->successors),
|
2009-01-25 22:03:38 +00:00
|
|
|
e->stackBefore ? e->stackBefore->index + 1 : 0);
|
2008-09-15 02:28:42 +00:00
|
|
|
}
|
|
|
|
|
2008-10-15 00:45:31 +00:00
|
|
|
e->block = block;
|
|
|
|
|
|
|
|
c->stack = e->stackBefore;
|
|
|
|
c->locals = e->localsBefore;
|
|
|
|
|
2008-09-07 01:37:12 +00:00
|
|
|
if (e->logicalInstruction->machineOffset == 0) {
|
|
|
|
e->logicalInstruction->machineOffset = a->offset();
|
|
|
|
}
|
|
|
|
|
2008-09-07 20:12:11 +00:00
|
|
|
if (e->predecessors) {
|
2008-10-15 00:45:31 +00:00
|
|
|
visit(c, lastPredecessor(e->predecessors));
|
2008-10-14 00:18:18 +00:00
|
|
|
|
|
|
|
Event* first = e->predecessors->predecessor;
|
|
|
|
if (e->predecessors->nextPredecessor) {
|
|
|
|
for (Link* pl = e->predecessors;
|
|
|
|
pl->nextPredecessor;
|
|
|
|
pl = pl->nextPredecessor)
|
|
|
|
{
|
|
|
|
updateJunctionReads(c, pl->junctionState);
|
2008-09-22 00:58:54 +00:00
|
|
|
}
|
2008-11-02 22:25:51 +00:00
|
|
|
|
|
|
|
if (DebugControl) {
|
|
|
|
fprintf(stderr, "set sites to junction sites %p at %d\n",
|
|
|
|
first->junctionSites, first->logicalInstruction->index);
|
|
|
|
}
|
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
setSites(c, e, first->junctionSites);
|
2008-12-13 19:59:02 +00:00
|
|
|
removeBuddies(c);
|
2008-10-14 00:18:18 +00:00
|
|
|
} else if (first->successors->nextSuccessor) {
|
2008-11-02 22:25:51 +00:00
|
|
|
if (DebugControl) {
|
|
|
|
fprintf(stderr, "restore snapshots %p at %d\n",
|
|
|
|
first->snapshots, first->logicalInstruction->index);
|
|
|
|
}
|
|
|
|
|
2008-11-01 22:16:18 +00:00
|
|
|
restore(c, e, first->snapshots);
|
2008-09-07 20:12:11 +00:00
|
|
|
}
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
unsigned footprint = frameFootprint(c, e->stackAfter);
|
2009-08-27 00:26:44 +00:00
|
|
|
RUNTIME_ARRAY(SiteRecord, frozenRecords, footprint);
|
|
|
|
SiteRecordList frozen(RUNTIME_ARRAY_BODY(frozenRecords), footprint);
|
2008-08-16 17:45:36 +00:00
|
|
|
|
2008-10-08 00:08:13 +00:00
|
|
|
bool branch = e->isBranch();
|
|
|
|
if (branch and e->successors) {
|
2009-01-11 22:53:51 +00:00
|
|
|
populateSiteTables(c, e, &frozen);
|
2008-10-08 00:08:13 +00:00
|
|
|
}
|
|
|
|
|
2009-01-11 18:48:02 +00:00
|
|
|
populateSources(c, e);
|
|
|
|
|
2009-11-03 04:11:39 +00:00
|
|
|
if (branch and e->successors) {
|
|
|
|
captureBranchSnapshots(c, e);
|
|
|
|
}
|
|
|
|
|
2009-01-11 22:53:51 +00:00
|
|
|
thaw(c, &frozen);
|
2009-01-11 18:48:02 +00:00
|
|
|
|
2008-08-16 17:45:36 +00:00
|
|
|
e->compile(c);
|
|
|
|
|
2008-10-08 00:08:13 +00:00
|
|
|
if ((not branch) and e->successors) {
|
2009-01-11 22:53:51 +00:00
|
|
|
populateSiteTables(c, e, &frozen);
|
2009-11-03 04:11:39 +00:00
|
|
|
captureBranchSnapshots(c, e);
|
2009-01-11 22:53:51 +00:00
|
|
|
thaw(c, &frozen);
|
2008-07-23 23:58:29 +00:00
|
|
|
}
|
|
|
|
|
2008-10-15 00:45:31 +00:00
|
|
|
if (e->visitLinks) {
|
|
|
|
for (Cell* cell = reverseDestroy(e->visitLinks); cell; cell = cell->next)
|
|
|
|
{
|
|
|
|
visit(c, static_cast<Link*>(cell->value));
|
|
|
|
}
|
|
|
|
e->visitLinks = 0;
|
2008-10-14 00:18:18 +00:00
|
|
|
}
|
2008-08-16 17:45:36 +00:00
|
|
|
|
2008-07-23 23:58:29 +00:00
|
|
|
for (CodePromise* p = e->promises; p; p = p->next) {
|
|
|
|
p->offset = a->offset();
|
2008-04-17 02:55:38 +00:00
|
|
|
}
|
2008-09-20 23:42:46 +00:00
|
|
|
|
2010-11-14 02:28:05 +00:00
|
|
|
a->endEvent();
|
|
|
|
|
2008-09-22 00:58:54 +00:00
|
|
|
LogicalInstruction* nextInstruction = next(c, e->logicalInstruction);
|
|
|
|
if (e->next == 0
|
|
|
|
or (e->next->logicalInstruction != e->logicalInstruction
|
2009-02-15 18:11:00 +00:00
|
|
|
and (e->next->logicalInstruction != nextInstruction
|
|
|
|
or e != e->logicalInstruction->lastEvent)))
|
2008-09-22 00:58:54 +00:00
|
|
|
{
|
2008-11-07 00:39:38 +00:00
|
|
|
Block* b = e->logicalInstruction->firstEvent->block;
|
2009-02-15 18:11:00 +00:00
|
|
|
|
|
|
|
while (b->nextBlock) {
|
|
|
|
b = b->nextBlock;
|
|
|
|
}
|
|
|
|
|
2008-11-07 00:39:38 +00:00
|
|
|
if (b != block) {
|
|
|
|
b->nextBlock = block;
|
|
|
|
}
|
2009-02-15 18:11:00 +00:00
|
|
|
|
2008-09-20 23:42:46 +00:00
|
|
|
block->nextInstruction = nextInstruction;
|
|
|
|
block->assemblerBlock = a->endBlock(e->next != 0);
|
2008-11-07 00:39:38 +00:00
|
|
|
|
2008-09-20 23:42:46 +00:00
|
|
|
if (e->next) {
|
2009-08-27 00:26:44 +00:00
|
|
|
block = local::block(c, e->next);
|
2008-08-16 17:45:36 +00:00
|
|
|
}
|
|
|
|
}
|
2008-04-17 02:55:38 +00:00
|
|
|
}
|
2008-08-16 17:45:36 +00:00
|
|
|
|
2011-02-28 06:03:13 +00:00
|
|
|
c->firstBlock = firstBlock;
|
2007-12-12 00:27:04 +00:00
|
|
|
}
|
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
void
|
2008-11-02 20:35:35 +00:00
|
|
|
restore(Context* c, ForkState* state)
|
2008-09-15 02:28:42 +00:00
|
|
|
{
|
2008-09-20 23:42:46 +00:00
|
|
|
for (unsigned i = 0; i < state->readCount; ++i) {
|
2008-11-02 20:35:35 +00:00
|
|
|
ForkElement* p = state->elements + i;
|
2008-09-20 23:42:46 +00:00
|
|
|
p->value->lastRead = p->read;
|
|
|
|
p->read->allocateTarget(c);
|
2008-09-15 02:28:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-22 00:58:54 +00:00
|
|
|
void
|
2009-01-25 22:03:38 +00:00
|
|
|
addForkElement(Context* c, Value* v, ForkState* state, unsigned index)
|
2008-09-22 00:58:54 +00:00
|
|
|
{
|
2009-01-25 22:03:38 +00:00
|
|
|
MultiRead* r = multiRead(c);
|
2008-12-15 14:35:19 +00:00
|
|
|
if (DebugReads) {
|
|
|
|
fprintf(stderr, "add multi read %p to %p\n", r, v);
|
|
|
|
}
|
2008-11-02 20:35:35 +00:00
|
|
|
addRead(c, 0, v, r);
|
|
|
|
|
2008-11-07 00:39:38 +00:00
|
|
|
ForkElement* p = state->elements + index;
|
2008-11-02 20:35:35 +00:00
|
|
|
p->value = v;
|
|
|
|
p->read = r;
|
2008-09-22 00:58:54 +00:00
|
|
|
}
|
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
ForkState*
|
2008-09-13 21:09:26 +00:00
|
|
|
saveState(Context* c)
|
2007-12-14 18:27:56 +00:00
|
|
|
{
|
2010-11-26 19:36:43 +00:00
|
|
|
if (c->logicalCode[c->logicalIp]->lastEvent == 0) {
|
|
|
|
appendDummy(c);
|
|
|
|
}
|
|
|
|
|
2008-11-07 00:39:38 +00:00
|
|
|
unsigned elementCount = frameFootprint(c, c->stack) + count(c->saved);
|
|
|
|
|
2008-10-14 00:18:18 +00:00
|
|
|
ForkState* state = new
|
2008-09-22 14:28:18 +00:00
|
|
|
(c->zone->allocate
|
2008-11-07 00:39:38 +00:00
|
|
|
(sizeof(ForkState) + (sizeof(ForkElement) * elementCount)))
|
|
|
|
ForkState(c->stack, c->locals, c->saved, c->predecessor, c->logicalIp);
|
2007-12-14 18:27:56 +00:00
|
|
|
|
2008-09-20 23:42:46 +00:00
|
|
|
if (c->predecessor) {
|
2008-10-14 00:18:18 +00:00
|
|
|
c->forkState = state;
|
2008-09-15 02:28:42 +00:00
|
|
|
|
2008-09-20 23:42:46 +00:00
|
|
|
unsigned count = 0;
|
2008-09-15 02:28:42 +00:00
|
|
|
|
2008-11-01 19:14:13 +00:00
|
|
|
for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) {
|
|
|
|
FrameIterator::Element e = it.next(c);
|
2009-01-25 22:03:38 +00:00
|
|
|
addForkElement(c, e.value, state, count++);
|
2008-11-07 00:39:38 +00:00
|
|
|
}
|
2008-11-02 20:35:35 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
for (Cell* sv = c->saved; sv; sv = sv->next) {
|
|
|
|
addForkElement(c, static_cast<Value*>(sv->value), state, count++);
|
2008-09-13 21:09:26 +00:00
|
|
|
}
|
2008-09-15 02:28:42 +00:00
|
|
|
|
2008-09-20 23:42:46 +00:00
|
|
|
state->readCount = count;
|
2008-04-20 19:35:36 +00:00
|
|
|
}
|
2008-09-13 21:09:26 +00:00
|
|
|
|
2008-11-07 00:39:38 +00:00
|
|
|
c->saved = 0;
|
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
return state;
|
2008-04-20 19:35:36 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
void
|
2008-10-14 00:18:18 +00:00
|
|
|
restoreState(Context* c, ForkState* s)
|
2007-12-11 23:52:28 +00:00
|
|
|
{
|
2008-11-08 23:21:30 +00:00
|
|
|
if (c->logicalCode[c->logicalIp]->lastEvent == 0) {
|
2008-09-15 02:28:42 +00:00
|
|
|
appendDummy(c);
|
|
|
|
}
|
|
|
|
|
2008-09-13 21:09:26 +00:00
|
|
|
c->stack = s->stack;
|
|
|
|
c->locals = s->locals;
|
2008-09-20 23:42:46 +00:00
|
|
|
c->predecessor = s->predecessor;
|
2008-09-22 14:28:18 +00:00
|
|
|
c->logicalIp = s->logicalIp;
|
2008-09-13 21:09:26 +00:00
|
|
|
|
2008-09-20 23:42:46 +00:00
|
|
|
if (c->predecessor) {
|
2008-10-14 00:18:18 +00:00
|
|
|
c->forkState = s;
|
2008-11-02 20:35:35 +00:00
|
|
|
restore(c, s);
|
2008-09-07 20:12:11 +00:00
|
|
|
}
|
2008-05-04 20:55:34 +00:00
|
|
|
}
|
|
|
|
|
2008-11-01 19:14:13 +00:00
|
|
|
Value*
|
2009-01-25 22:03:38 +00:00
|
|
|
maybeBuddy(Context* c, Value* v)
|
2008-11-01 19:14:13 +00:00
|
|
|
{
|
2009-01-03 00:44:47 +00:00
|
|
|
if (v->home >= 0) {
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* n = value(c, v->type);
|
2009-01-25 22:03:38 +00:00
|
|
|
appendBuddy(c, v, n);
|
2008-11-01 19:14:13 +00:00
|
|
|
return n;
|
|
|
|
} else {
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-06 03:17:12 +00:00
|
|
|
void
|
|
|
|
linkLocals(Context* c, Local* oldLocals, Local* newLocals)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < static_cast<int>(c->localFootprint); ++i) {
|
|
|
|
Local* local = oldLocals + i;
|
|
|
|
if (local->value) {
|
|
|
|
int highOffset = c->arch->bigEndian() ? 1 : -1;
|
|
|
|
|
|
|
|
if (i + highOffset >= 0
|
|
|
|
and i + highOffset < static_cast<int>(c->localFootprint)
|
2009-10-10 22:07:30 +00:00
|
|
|
and local->value->nextWord == local[highOffset].value)
|
2009-10-06 03:17:12 +00:00
|
|
|
{
|
|
|
|
Value* v = newLocals[i].value;
|
|
|
|
Value* next = newLocals[i + highOffset].value;
|
2009-10-10 22:07:30 +00:00
|
|
|
v->nextWord = next;
|
|
|
|
next->nextWord = v;
|
|
|
|
next->wordIndex = 1;
|
2009-10-06 03:17:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
class Client: public Assembler::Client {
|
|
|
|
public:
|
|
|
|
Client(Context* c): c(c) { }
|
|
|
|
|
2008-05-06 21:13:02 +00:00
|
|
|
virtual int acquireTemporary(uint32_t mask) {
|
2009-01-03 21:34:45 +00:00
|
|
|
unsigned cost;
|
|
|
|
int r = pickRegisterTarget(c, 0, mask, &cost);
|
|
|
|
expect(c, cost < Target::Impossible);
|
2008-04-30 15:44:17 +00:00
|
|
|
save(r);
|
2009-01-03 00:44:47 +00:00
|
|
|
increment(c, c->registerResources + r);
|
2008-03-13 23:43:11 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void releaseTemporary(int r) {
|
2009-01-03 00:44:47 +00:00
|
|
|
decrement(c, c->registerResources + r);
|
2008-03-13 23:43:11 +00:00
|
|
|
}
|
|
|
|
|
2008-04-27 20:15:18 +00:00
|
|
|
virtual void save(int r) {
|
2009-01-03 00:44:47 +00:00
|
|
|
RegisterResource* reg = c->registerResources + r;
|
2009-01-11 18:48:02 +00:00
|
|
|
|
2008-12-24 20:35:43 +00:00
|
|
|
assert(c, reg->referenceCount == 0);
|
2009-01-11 18:48:02 +00:00
|
|
|
assert(c, reg->freezeCount == 0);
|
|
|
|
assert(c, not reg->reserved);
|
|
|
|
|
|
|
|
if (reg->value) {
|
2009-01-25 22:03:38 +00:00
|
|
|
steal(c, reg, 0);
|
2009-01-11 18:48:02 +00:00
|
|
|
}
|
2008-04-27 20:15:18 +00:00
|
|
|
}
|
|
|
|
|
2008-03-13 23:43:11 +00:00
|
|
|
Context* c;
|
|
|
|
};
|
|
|
|
|
2007-12-08 23:22:13 +00:00
|
|
|
class MyCompiler: public Compiler {
|
|
|
|
public:
|
2008-05-31 22:14:27 +00:00
|
|
|
MyCompiler(System* s, Assembler* assembler, Zone* zone,
|
|
|
|
Compiler::Client* compilerClient):
|
|
|
|
c(s, assembler, zone, compilerClient), client(&c)
|
2008-03-13 23:43:11 +00:00
|
|
|
{
|
|
|
|
assembler->setClient(&client);
|
|
|
|
}
|
2007-12-08 23:22:13 +00:00
|
|
|
|
2008-09-13 21:09:26 +00:00
|
|
|
virtual State* saveState() {
|
2009-08-27 00:26:44 +00:00
|
|
|
State* s = local::saveState(&c);
|
2009-02-14 20:26:39 +00:00
|
|
|
restoreState(s);
|
|
|
|
return s;
|
2008-04-28 15:53:48 +00:00
|
|
|
}
|
|
|
|
|
2008-09-13 21:09:26 +00:00
|
|
|
virtual void restoreState(State* state) {
|
2009-08-27 00:26:44 +00:00
|
|
|
local::restoreState(&c, static_cast<ForkState*>(state));
|
2008-04-28 15:53:48 +00:00
|
|
|
}
|
|
|
|
|
2008-11-14 00:59:21 +00:00
|
|
|
virtual Subroutine* startSubroutine() {
|
2012-05-08 22:13:17 +00:00
|
|
|
return c.subroutine = new(c.zone) MySubroutine;
|
2008-11-14 00:59:21 +00:00
|
|
|
}
|
|
|
|
|
2010-01-05 00:17:16 +00:00
|
|
|
virtual void returnFromSubroutine(Subroutine* subroutine, Operand* address) {
|
|
|
|
appendSaveLocals(&c);
|
|
|
|
appendJump(&c, Jump, static_cast<Value*>(address), false, true);
|
2009-08-27 00:26:44 +00:00
|
|
|
static_cast<MySubroutine*>(subroutine)->forkState = local::saveState(&c);
|
2009-02-14 20:26:39 +00:00
|
|
|
}
|
|
|
|
|
2009-07-20 14:26:01 +00:00
|
|
|
virtual void linkSubroutine(Subroutine* subroutine) {
|
2009-10-06 03:17:12 +00:00
|
|
|
Local* oldLocals = c.locals;
|
2009-07-20 14:26:01 +00:00
|
|
|
restoreState(static_cast<MySubroutine*>(subroutine)->forkState);
|
2009-10-06 03:17:12 +00:00
|
|
|
linkLocals(&c, oldLocals, c.locals);
|
2009-07-20 14:26:01 +00:00
|
|
|
}
|
|
|
|
|
2008-05-19 04:31:52 +00:00
|
|
|
virtual void init(unsigned logicalCodeLength, unsigned parameterFootprint,
|
2008-09-28 19:00:52 +00:00
|
|
|
unsigned localFootprint, unsigned alignedFrameSize)
|
2008-05-19 04:31:52 +00:00
|
|
|
{
|
2008-02-11 17:21:41 +00:00
|
|
|
c.logicalCodeLength = logicalCodeLength;
|
2008-05-19 04:31:52 +00:00
|
|
|
c.parameterFootprint = parameterFootprint;
|
|
|
|
c.localFootprint = localFootprint;
|
2008-09-28 19:00:52 +00:00
|
|
|
c.alignedFrameSize = alignedFrameSize;
|
2008-05-19 04:31:52 +00:00
|
|
|
|
2009-04-19 22:36:11 +00:00
|
|
|
unsigned frameResourceCount = totalFrameSize(&c);
|
2008-09-28 21:56:12 +00:00
|
|
|
|
|
|
|
c.frameResources = static_cast<FrameResource*>
|
2009-01-03 21:34:45 +00:00
|
|
|
(c.zone->allocate(sizeof(FrameResource) * frameResourceCount));
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < frameResourceCount; ++i) {
|
|
|
|
new (c.frameResources + i) FrameResource;
|
|
|
|
}
|
2008-09-28 21:56:12 +00:00
|
|
|
|
2009-04-22 01:39:25 +00:00
|
|
|
unsigned base = frameBase(&c);
|
2009-04-19 22:36:11 +00:00
|
|
|
c.frameResources[base + c.arch->returnAddressOffset()].reserved = true;
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
c.frameResources[base + c.arch->framePointerOffset()].reserved
|
|
|
|
= UseFramePointer;
|
2009-04-19 22:36:11 +00:00
|
|
|
|
2008-11-08 23:21:30 +00:00
|
|
|
// leave room for logical instruction -1
|
2009-04-19 22:36:11 +00:00
|
|
|
unsigned codeSize = sizeof(LogicalInstruction*) * (logicalCodeLength + 1);
|
2008-08-16 17:45:36 +00:00
|
|
|
c.logicalCode = static_cast<LogicalInstruction**>
|
2008-11-08 23:21:30 +00:00
|
|
|
(c.zone->allocate(codeSize));
|
|
|
|
memset(c.logicalCode, 0, codeSize);
|
|
|
|
c.logicalCode++;
|
2008-05-19 04:31:52 +00:00
|
|
|
|
2008-09-24 00:01:42 +00:00
|
|
|
c.locals = static_cast<Local*>
|
|
|
|
(c.zone->allocate(sizeof(Local) * localFootprint));
|
2008-09-09 00:31:19 +00:00
|
|
|
|
2008-09-24 00:01:42 +00:00
|
|
|
memset(c.locals, 0, sizeof(Local) * localFootprint);
|
2008-11-08 23:21:30 +00:00
|
|
|
|
|
|
|
c.logicalCode[-1] = new
|
|
|
|
(c.zone->allocate(sizeof(LogicalInstruction)))
|
|
|
|
LogicalInstruction(-1, c.stack, c.locals);
|
2007-12-17 20:55:31 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual void visitLogicalIp(unsigned logicalIp) {
|
2008-09-15 02:28:42 +00:00
|
|
|
assert(&c, logicalIp < c.logicalCodeLength);
|
|
|
|
|
2008-11-08 23:21:30 +00:00
|
|
|
if (c.logicalCode[c.logicalIp]->lastEvent == 0) {
|
2008-11-07 00:39:38 +00:00
|
|
|
appendDummy(&c);
|
|
|
|
}
|
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
Event* e = c.logicalCode[logicalIp]->firstEvent;
|
|
|
|
|
2008-10-04 17:26:35 +00:00
|
|
|
Event* p = c.predecessor;
|
|
|
|
if (p) {
|
2008-12-23 01:25:00 +00:00
|
|
|
if (DebugAppend) {
|
|
|
|
fprintf(stderr, "visit %d pred %d\n", logicalIp,
|
|
|
|
p->logicalInstruction->index);
|
|
|
|
}
|
2008-11-07 00:39:38 +00:00
|
|
|
|
2008-10-04 17:26:35 +00:00
|
|
|
p->stackAfter = c.stack;
|
|
|
|
p->localsAfter = c.locals;
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
Link* link = local::link
|
2008-10-14 00:18:18 +00:00
|
|
|
(&c, p, e->predecessors, e, p->successors, c.forkState);
|
|
|
|
e->predecessors = link;
|
|
|
|
p->successors = link;
|
2008-10-15 00:45:31 +00:00
|
|
|
c.lastEvent->visitLinks = cons(&c, link, c.lastEvent->visitLinks);
|
2008-10-14 00:18:18 +00:00
|
|
|
|
2008-12-23 01:25:00 +00:00
|
|
|
if (DebugAppend) {
|
|
|
|
fprintf(stderr, "populate junction reads for %d to %d\n",
|
|
|
|
p->logicalInstruction->index, logicalIp);
|
|
|
|
}
|
|
|
|
|
2008-12-12 01:09:36 +00:00
|
|
|
populateJunctionReads(&c, link);
|
2008-09-15 02:28:42 +00:00
|
|
|
}
|
2008-10-14 00:18:18 +00:00
|
|
|
|
2008-11-14 00:59:21 +00:00
|
|
|
if (c.subroutine) {
|
|
|
|
c.subroutine->forkState
|
|
|
|
= c.logicalCode[logicalIp]->subroutine->forkState;
|
|
|
|
c.subroutine = 0;
|
|
|
|
}
|
|
|
|
|
2008-12-12 01:09:36 +00:00
|
|
|
c.forkState = 0;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual void startLogicalIp(unsigned logicalIp) {
|
2008-09-15 02:28:42 +00:00
|
|
|
assert(&c, logicalIp < c.logicalCodeLength);
|
|
|
|
assert(&c, c.logicalCode[logicalIp] == 0);
|
|
|
|
|
2008-11-08 23:21:30 +00:00
|
|
|
if (c.logicalCode[c.logicalIp]->lastEvent == 0) {
|
2008-09-13 21:09:26 +00:00
|
|
|
appendDummy(&c);
|
|
|
|
}
|
2008-04-20 19:35:36 +00:00
|
|
|
|
2008-10-06 00:50:59 +00:00
|
|
|
Event* p = c.predecessor;
|
|
|
|
if (p) {
|
|
|
|
p->stackAfter = c.stack;
|
|
|
|
p->localsAfter = c.locals;
|
|
|
|
}
|
|
|
|
|
2008-09-15 02:28:42 +00:00
|
|
|
c.logicalCode[logicalIp] = new
|
|
|
|
(c.zone->allocate(sizeof(LogicalInstruction)))
|
|
|
|
LogicalInstruction(logicalIp, c.stack, c.locals);
|
2008-04-20 19:35:36 +00:00
|
|
|
|
2009-07-08 14:18:40 +00:00
|
|
|
bool startSubroutine = c.subroutine != 0;
|
|
|
|
if (startSubroutine) {
|
2008-11-14 00:59:21 +00:00
|
|
|
c.logicalCode[logicalIp]->subroutine = c.subroutine;
|
|
|
|
c.subroutine = 0;
|
2009-07-08 14:18:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
c.logicalIp = logicalIp;
|
|
|
|
|
|
|
|
if (startSubroutine) {
|
|
|
|
// assume all local variables are initialized on entry to a
|
|
|
|
// subroutine, since other calls to the subroutine may
|
|
|
|
// initialize them:
|
|
|
|
unsigned sizeInBytes = sizeof(Local) * c.localFootprint;
|
|
|
|
Local* newLocals = static_cast<Local*>(c.zone->allocate(sizeInBytes));
|
|
|
|
memcpy(newLocals, c.locals, sizeInBytes);
|
|
|
|
c.locals = newLocals;
|
|
|
|
|
2009-06-30 23:33:54 +00:00
|
|
|
for (unsigned li = 0; li < c.localFootprint; ++li) {
|
|
|
|
Local* local = c.locals + li;
|
|
|
|
if (local->value == 0) {
|
2009-09-20 21:43:32 +00:00
|
|
|
initLocal(1, li, IntegerType);
|
2009-06-30 23:33:54 +00:00
|
|
|
}
|
2009-06-26 21:36:04 +00:00
|
|
|
}
|
|
|
|
}
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual Promise* machineIp(unsigned logicalIp) {
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(c.zone) IpPromise(&c, logicalIp);
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual Promise* poolAppend(intptr_t value) {
|
2008-03-13 20:50:56 +00:00
|
|
|
return poolAppendPromise(resolved(&c, value));
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual Promise* poolAppendPromise(Promise* value) {
|
2012-05-08 22:13:17 +00:00
|
|
|
Promise* p = new(c.zone) PoolPromise(&c, c.constantCount);
|
2007-12-08 23:22:13 +00:00
|
|
|
|
2012-05-08 22:13:17 +00:00
|
|
|
ConstantPoolNode* constant = new (c.zone) ConstantPoolNode(value);
|
2007-12-16 00:24:15 +00:00
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
if (c.firstConstant) {
|
|
|
|
c.lastConstant->next = constant;
|
|
|
|
} else {
|
|
|
|
c.firstConstant = constant;
|
2007-12-16 00:24:15 +00:00
|
|
|
}
|
2008-02-11 17:21:41 +00:00
|
|
|
c.lastConstant = constant;
|
|
|
|
++ c.constantCount;
|
2007-12-12 22:19:13 +00:00
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
return p;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-09-20 21:43:32 +00:00
|
|
|
virtual Operand* constant(int64_t value, OperandType type) {
|
|
|
|
return promiseConstant(resolved(&c, value), type);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-09-20 21:43:32 +00:00
|
|
|
virtual Operand* promiseConstant(Promise* value, OperandType type) {
|
|
|
|
return local::value
|
|
|
|
(&c, valueType(&c, type), local::constantSite(&c, value));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual Operand* address(Promise* address) {
|
2009-09-20 21:43:32 +00:00
|
|
|
return value(&c, ValueGeneral, local::addressSite(&c, address));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual Operand* memory(Operand* base,
|
2009-09-20 21:43:32 +00:00
|
|
|
OperandType type,
|
2008-02-11 17:21:41 +00:00
|
|
|
int displacement = 0,
|
|
|
|
Operand* index = 0,
|
2008-04-13 19:48:20 +00:00
|
|
|
unsigned scale = 1)
|
2008-02-11 17:21:41 +00:00
|
|
|
{
|
2009-09-20 21:43:32 +00:00
|
|
|
Value* result = value(&c, valueType(&c, type));
|
2008-03-15 23:54:20 +00:00
|
|
|
|
2008-04-17 20:48:26 +00:00
|
|
|
appendMemory(&c, static_cast<Value*>(base), displacement,
|
|
|
|
static_cast<Value*>(index), scale, result);
|
2008-03-15 23:54:20 +00:00
|
|
|
|
|
|
|
return result;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-04-08 00:55:43 +00:00
|
|
|
virtual Operand* register_(int number) {
|
2010-12-20 00:47:21 +00:00
|
|
|
return local::register_(&c, number);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-31 22:40:56 +00:00
|
|
|
Promise* machineIp() {
|
2008-08-16 17:45:36 +00:00
|
|
|
return codePromise(&c, c.logicalCode[c.logicalIp]->lastEvent);
|
2007-12-31 22:40:56 +00:00
|
|
|
}
|
|
|
|
|
2009-02-08 20:21:35 +00:00
|
|
|
virtual void push(unsigned footprint UNUSED) {
|
|
|
|
assert(&c, footprint == 1);
|
2008-04-27 20:15:18 +00:00
|
|
|
|
2009-11-30 02:17:08 +00:00
|
|
|
Value* v = value(&c, ValueGeneral);
|
2009-08-27 00:26:44 +00:00
|
|
|
Stack* s = local::stack(&c, v, c.stack);
|
2009-09-20 21:43:32 +00:00
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
v->home = frameIndex(&c, s->index + c.localFootprint);
|
2009-01-03 00:44:47 +00:00
|
|
|
c.stack = s;
|
2008-04-26 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
2008-11-02 22:25:51 +00:00
|
|
|
virtual void push(unsigned footprint, Operand* value) {
|
2009-10-24 23:18:56 +00:00
|
|
|
local::push(&c, footprint, static_cast<Value*>(value));
|
2007-12-22 00:26:55 +00:00
|
|
|
}
|
2007-12-09 22:45:43 +00:00
|
|
|
|
2008-11-14 00:59:21 +00:00
|
|
|
virtual void save(unsigned footprint, Operand* value) {
|
2009-01-25 22:03:38 +00:00
|
|
|
c.saved = cons(&c, static_cast<Value*>(value), c.saved);
|
2011-08-30 01:00:17 +00:00
|
|
|
if (TargetBytesPerWord == 4 and footprint > 1) {
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(&c, footprint == 2);
|
2009-10-10 22:07:30 +00:00
|
|
|
assert(&c, static_cast<Value*>(value)->nextWord);
|
2009-01-30 01:36:19 +00:00
|
|
|
|
2009-10-10 22:07:30 +00:00
|
|
|
save(1, static_cast<Value*>(value)->nextWord);
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
2008-11-14 00:59:21 +00:00
|
|
|
}
|
|
|
|
|
2008-11-02 22:25:51 +00:00
|
|
|
virtual Operand* pop(unsigned footprint) {
|
2009-08-27 00:26:44 +00:00
|
|
|
return local::pop(&c, footprint);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2008-07-05 20:21:13 +00:00
|
|
|
virtual void pushed() {
|
2009-10-24 23:18:56 +00:00
|
|
|
Value* v = value(&c, ValueGeneral);
|
2008-09-25 00:48:32 +00:00
|
|
|
appendFrameSite
|
2009-01-25 22:03:38 +00:00
|
|
|
(&c, v, frameIndex
|
|
|
|
(&c, (c.stack ? c.stack->index : 0) + c.localFootprint));
|
2008-09-25 00:48:32 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
Stack* s = local::stack(&c, v, c.stack);
|
2009-01-25 22:03:38 +00:00
|
|
|
v->home = frameIndex(&c, s->index + c.localFootprint);
|
2009-01-03 00:44:47 +00:00
|
|
|
c.stack = s;
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2009-01-30 01:36:19 +00:00
|
|
|
virtual void popped(unsigned footprint) {
|
2009-05-15 02:08:01 +00:00
|
|
|
for (; footprint; -- footprint) {
|
|
|
|
assert(&c, c.stack->value == 0 or c.stack->value->home >= 0);
|
2009-01-30 01:36:19 +00:00
|
|
|
|
2009-05-15 02:08:01 +00:00
|
|
|
if (DebugFrame) {
|
|
|
|
fprintf(stderr, "popped %p\n", c.stack->value);
|
|
|
|
}
|
|
|
|
|
|
|
|
c.stack = c.stack->next;
|
2009-01-30 01:36:19 +00:00
|
|
|
}
|
2008-07-05 20:21:13 +00:00
|
|
|
}
|
|
|
|
|
2009-05-15 02:08:01 +00:00
|
|
|
virtual unsigned topOfStack() {
|
|
|
|
return c.stack->index;
|
2008-11-11 00:07:44 +00:00
|
|
|
}
|
|
|
|
|
2009-03-01 19:36:30 +00:00
|
|
|
virtual Operand* peek(unsigned footprint, unsigned index) {
|
2008-09-13 21:09:26 +00:00
|
|
|
Stack* s = c.stack;
|
2009-01-25 22:03:38 +00:00
|
|
|
for (unsigned i = index; i > 0; --i) {
|
2008-04-29 16:55:56 +00:00
|
|
|
s = s->next;
|
2008-02-17 20:57:40 +00:00
|
|
|
}
|
2009-03-01 19:36:30 +00:00
|
|
|
|
|
|
|
if (footprint > 1) {
|
|
|
|
assert(&c, footprint == 2);
|
|
|
|
|
|
|
|
bool bigEndian = c.arch->bigEndian();
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
Stack* low;
|
|
|
|
Stack* high;
|
|
|
|
if (bigEndian) {
|
2009-05-03 20:57:11 +00:00
|
|
|
high = s;
|
|
|
|
low = s->next;
|
2009-10-24 23:18:56 +00:00
|
|
|
} else {
|
|
|
|
low = s;
|
|
|
|
high = s->next;
|
2009-03-01 19:36:30 +00:00
|
|
|
}
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
assert(&c, (TargetBytesPerWord == 8
|
2009-10-10 22:07:30 +00:00
|
|
|
and low->value->nextWord == low->value and high->value == 0)
|
2011-08-30 01:00:17 +00:00
|
|
|
or (TargetBytesPerWord == 4
|
|
|
|
and low->value->nextWord == high->value));
|
2009-03-01 19:36:30 +00:00
|
|
|
#endif // not NDEBUG
|
|
|
|
|
2009-10-24 23:18:56 +00:00
|
|
|
if (bigEndian) {
|
2009-03-01 19:36:30 +00:00
|
|
|
s = s->next;
|
|
|
|
}
|
|
|
|
}
|
2009-01-30 01:43:46 +00:00
|
|
|
|
2008-04-17 20:48:26 +00:00
|
|
|
return s->value;
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual Operand* call(Operand* address,
|
|
|
|
unsigned flags,
|
|
|
|
TraceHandler* traceHandler,
|
2008-04-18 04:16:20 +00:00
|
|
|
unsigned resultSize,
|
2009-09-20 21:43:32 +00:00
|
|
|
OperandType resultType,
|
2008-02-11 17:21:41 +00:00
|
|
|
unsigned argumentCount,
|
|
|
|
...)
|
|
|
|
{
|
|
|
|
va_list a; va_start(a, argumentCount);
|
2007-12-11 00:48:09 +00:00
|
|
|
|
2009-03-01 19:28:17 +00:00
|
|
|
bool bigEndian = c.arch->bigEndian();
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
unsigned footprint = 0;
|
2011-08-30 01:00:17 +00:00
|
|
|
unsigned size = TargetBytesPerWord;
|
2009-08-27 00:26:44 +00:00
|
|
|
RUNTIME_ARRAY(Value*, arguments, argumentCount);
|
2008-09-05 15:00:38 +00:00
|
|
|
int index = 0;
|
2008-02-11 17:21:41 +00:00
|
|
|
for (unsigned i = 0; i < argumentCount; ++i) {
|
2008-04-17 20:48:26 +00:00
|
|
|
Value* o = va_arg(a, Value*);
|
2008-02-12 02:06:12 +00:00
|
|
|
if (o) {
|
2011-08-30 01:00:17 +00:00
|
|
|
if (bigEndian and size > TargetBytesPerWord) {
|
2009-10-10 22:07:30 +00:00
|
|
|
RUNTIME_ARRAY_BODY(arguments)[index++] = o->nextWord;
|
2009-03-01 19:28:17 +00:00
|
|
|
}
|
2009-08-27 00:26:44 +00:00
|
|
|
RUNTIME_ARRAY_BODY(arguments)[index] = o;
|
2011-08-30 01:00:17 +00:00
|
|
|
if ((not bigEndian) and size > TargetBytesPerWord) {
|
2009-10-10 22:07:30 +00:00
|
|
|
RUNTIME_ARRAY_BODY(arguments)[++index] = o->nextWord;
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
2011-08-30 01:00:17 +00:00
|
|
|
size = TargetBytesPerWord;
|
2008-04-17 20:48:26 +00:00
|
|
|
++ index;
|
2008-02-12 02:06:12 +00:00
|
|
|
} else {
|
|
|
|
size = 8;
|
|
|
|
}
|
|
|
|
++ footprint;
|
2007-12-31 22:40:56 +00:00
|
|
|
}
|
2007-12-08 23:22:13 +00:00
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
va_end(a);
|
2007-12-26 16:56:14 +00:00
|
|
|
|
2009-01-03 21:34:45 +00:00
|
|
|
Stack* argumentStack = c.stack;
|
2008-04-29 16:40:44 +00:00
|
|
|
for (int i = index - 1; i >= 0; --i) {
|
2009-08-27 00:26:44 +00:00
|
|
|
argumentStack = local::stack
|
|
|
|
(&c, RUNTIME_ARRAY_BODY(arguments)[i], argumentStack);
|
2008-04-18 03:47:42 +00:00
|
|
|
}
|
|
|
|
|
2009-09-20 21:43:32 +00:00
|
|
|
Value* result = value(&c, valueType(&c, resultType));
|
2008-07-05 20:21:13 +00:00
|
|
|
appendCall(&c, static_cast<Value*>(address), flags, traceHandler, result,
|
2008-08-23 18:04:36 +00:00
|
|
|
resultSize, argumentStack, index, 0);
|
2008-07-05 20:21:13 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* stackCall(Operand* address,
|
|
|
|
unsigned flags,
|
|
|
|
TraceHandler* traceHandler,
|
|
|
|
unsigned resultSize,
|
2009-09-20 21:43:32 +00:00
|
|
|
OperandType resultType,
|
2008-07-05 20:21:13 +00:00
|
|
|
unsigned argumentFootprint)
|
|
|
|
{
|
2009-09-20 21:43:32 +00:00
|
|
|
Value* result = value(&c, valueType(&c, resultType));
|
2008-07-05 20:21:13 +00:00
|
|
|
appendCall(&c, static_cast<Value*>(address), flags, traceHandler, result,
|
2008-09-13 21:09:26 +00:00
|
|
|
resultSize, c.stack, 0, argumentFootprint);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual void return_(unsigned size, Operand* value) {
|
2008-04-17 20:48:26 +00:00
|
|
|
appendReturn(&c, size, static_cast<Value*>(value));
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2009-09-20 21:43:32 +00:00
|
|
|
virtual void initLocal(unsigned footprint, unsigned index, OperandType type)
|
|
|
|
{
|
2009-01-31 19:05:06 +00:00
|
|
|
assert(&c, index + footprint <= c.localFootprint);
|
2008-09-24 00:01:42 +00:00
|
|
|
|
2009-09-20 21:43:32 +00:00
|
|
|
Value* v = value(&c, valueType(&c, type));
|
2008-11-02 22:25:51 +00:00
|
|
|
|
2009-01-31 19:05:06 +00:00
|
|
|
if (footprint > 1) {
|
2009-01-25 22:03:38 +00:00
|
|
|
assert(&c, footprint == 2);
|
2009-01-31 19:05:06 +00:00
|
|
|
|
2009-03-01 19:28:17 +00:00
|
|
|
unsigned highIndex;
|
|
|
|
unsigned lowIndex;
|
|
|
|
if (c.arch->bigEndian()) {
|
|
|
|
highIndex = index + 1;
|
|
|
|
lowIndex = index;
|
|
|
|
} else {
|
|
|
|
lowIndex = index + 1;
|
|
|
|
highIndex = index;
|
|
|
|
}
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (TargetBytesPerWord == 4) {
|
2009-09-20 21:43:32 +00:00
|
|
|
initLocal(1, highIndex, type);
|
2009-09-26 19:43:44 +00:00
|
|
|
Value* next = c.locals[highIndex].value;
|
2009-10-10 22:07:30 +00:00
|
|
|
v->nextWord = next;
|
|
|
|
next->nextWord = v;
|
|
|
|
next->wordIndex = 1;
|
2009-01-31 19:05:06 +00:00
|
|
|
}
|
|
|
|
|
2009-03-01 19:28:17 +00:00
|
|
|
index = lowIndex;
|
2009-01-25 22:03:38 +00:00
|
|
|
}
|
|
|
|
|
2008-11-02 22:25:51 +00:00
|
|
|
if (DebugFrame) {
|
2009-01-25 22:03:38 +00:00
|
|
|
fprintf(stderr, "init local %p at %d (%d)\n",
|
|
|
|
v, index, frameIndex(&c, index));
|
2008-11-02 22:25:51 +00:00
|
|
|
}
|
|
|
|
|
2009-01-25 22:03:38 +00:00
|
|
|
appendFrameSite(&c, v, frameIndex(&c, index));
|
2008-09-24 00:01:42 +00:00
|
|
|
|
|
|
|
Local* local = c.locals + index;
|
|
|
|
local->value = v;
|
2009-01-25 22:03:38 +00:00
|
|
|
v->home = frameIndex(&c, index);
|
2008-09-09 00:31:19 +00:00
|
|
|
}
|
|
|
|
|
2008-09-25 00:48:32 +00:00
|
|
|
virtual void initLocalsFromLogicalIp(unsigned logicalIp) {
|
|
|
|
assert(&c, logicalIp < c.logicalCodeLength);
|
|
|
|
|
|
|
|
unsigned footprint = sizeof(Local) * c.localFootprint;
|
|
|
|
Local* newLocals = static_cast<Local*>(c.zone->allocate(footprint));
|
|
|
|
memset(newLocals, 0, footprint);
|
|
|
|
c.locals = newLocals;
|
2008-09-24 00:01:42 +00:00
|
|
|
|
2008-09-25 00:48:32 +00:00
|
|
|
Event* e = c.logicalCode[logicalIp]->firstEvent;
|
2009-03-01 22:47:07 +00:00
|
|
|
for (int i = 0; i < static_cast<int>(c.localFootprint); ++i) {
|
2008-10-04 17:26:35 +00:00
|
|
|
Local* local = e->localsBefore + i;
|
2008-09-25 00:48:32 +00:00
|
|
|
if (local->value) {
|
2009-09-20 21:43:32 +00:00
|
|
|
initLocal
|
|
|
|
(1, i, local->value->type == ValueGeneral ? IntegerType : FloatType);
|
2009-03-08 00:39:55 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-08 22:13:49 +00:00
|
|
|
|
2009-10-06 03:17:12 +00:00
|
|
|
linkLocals(&c, e->localsBefore, newLocals);
|
2008-09-25 00:48:32 +00:00
|
|
|
}
|
|
|
|
|
2008-11-02 22:25:51 +00:00
|
|
|
virtual void storeLocal(unsigned footprint, Operand* src, unsigned index) {
|
2009-08-27 00:26:44 +00:00
|
|
|
local::storeLocal(&c, footprint, static_cast<Value*>(src), index, true);
|
2008-05-19 04:31:52 +00:00
|
|
|
}
|
|
|
|
|
2009-02-01 23:10:56 +00:00
|
|
|
virtual Operand* loadLocal(unsigned footprint, unsigned index) {
|
2009-08-27 00:26:44 +00:00
|
|
|
return local::loadLocal(&c, footprint, index);
|
2008-05-19 04:31:52 +00:00
|
|
|
}
|
|
|
|
|
2008-11-25 17:34:48 +00:00
|
|
|
virtual void saveLocals() {
|
|
|
|
appendSaveLocals(&c);
|
|
|
|
}
|
|
|
|
|
2008-05-31 22:14:27 +00:00
|
|
|
virtual void checkBounds(Operand* object, unsigned lengthOffset,
|
|
|
|
Operand* index, intptr_t handler)
|
|
|
|
{
|
2010-12-19 22:23:19 +00:00
|
|
|
appendBoundsCheck(&c, static_cast<Value*>(object), lengthOffset,
|
|
|
|
static_cast<Value*>(index), handler);
|
2008-05-31 22:14:27 +00:00
|
|
|
}
|
|
|
|
|
2009-02-28 23:17:24 +00:00
|
|
|
virtual void store(unsigned srcSize, Operand* src, unsigned dstSize,
|
|
|
|
Operand* dst)
|
|
|
|
{
|
2009-03-06 17:56:11 +00:00
|
|
|
appendMove(&c, Move, srcSize, srcSize, static_cast<Value*>(src),
|
2009-02-28 23:17:24 +00:00
|
|
|
dstSize, static_cast<Value*>(dst));
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2009-03-06 17:56:11 +00:00
|
|
|
virtual Operand* load(unsigned srcSize, unsigned srcSelectSize, Operand* src,
|
|
|
|
unsigned dstSize)
|
|
|
|
{
|
2011-08-30 01:00:17 +00:00
|
|
|
assert(&c, dstSize >= TargetBytesPerWord);
|
2007-12-08 23:22:13 +00:00
|
|
|
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* dst = value(&c, static_cast<Value*>(src)->type);
|
2009-03-06 17:56:11 +00:00
|
|
|
appendMove(&c, Move, srcSize, srcSelectSize, static_cast<Value*>(src),
|
|
|
|
dstSize, dst);
|
2008-02-11 17:21:41 +00:00
|
|
|
return dst;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-03-06 17:56:11 +00:00
|
|
|
virtual Operand* loadz(unsigned srcSize, unsigned srcSelectSize,
|
|
|
|
Operand* src, unsigned dstSize)
|
|
|
|
{
|
2011-08-30 01:00:17 +00:00
|
|
|
assert(&c, dstSize >= TargetBytesPerWord);
|
2008-12-21 21:41:56 +00:00
|
|
|
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* dst = value(&c, static_cast<Value*>(src)->type);
|
2009-03-06 17:56:11 +00:00
|
|
|
appendMove(&c, MoveZ, srcSize, srcSelectSize, static_cast<Value*>(src),
|
|
|
|
dstSize, dst);
|
2008-02-11 17:21:41 +00:00
|
|
|
return dst;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfEqual(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
2009-10-07 00:50:32 +00:00
|
|
|
|
|
|
|
appendBranch(&c, JumpIfEqual, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2008-06-12 16:56:48 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfNotEqual(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
2009-10-07 00:50:32 +00:00
|
|
|
|
|
|
|
appendBranch(&c, JumpIfNotEqual, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfLess(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfLess, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2009-08-06 16:14:31 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfGreater(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfGreater, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfLessOrEqual(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfLessOrEqual, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfGreaterOrEqual(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfGreaterOrEqual, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfFloatEqual(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfFloatEqual, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfFloatNotEqual(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfFloatNotEqual, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfFloatLess(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfFloatLess, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfFloatGreater(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfFloatGreater, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2009-08-10 19:20:23 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfFloatLessOrEqual(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfFloatLessOrEqual, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2009-08-10 19:20:23 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfFloatGreaterOrEqual(unsigned size, Operand* a, Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfFloatGreaterOrEqual, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2009-08-10 19:20:23 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfFloatLessOrUnordered(unsigned size, Operand* a,
|
|
|
|
Operand* b, Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfFloatLessOrUnordered, size, static_cast<Value*>(a),
|
|
|
|
static_cast<Value*>(b), static_cast<Value*>(address));
|
2009-08-10 19:20:23 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfFloatGreaterOrUnordered(unsigned size, Operand* a,
|
|
|
|
Operand* b, Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfFloatGreaterOrUnordered, size,
|
|
|
|
static_cast<Value*>(a), static_cast<Value*>(b),
|
|
|
|
static_cast<Value*>(address));
|
2009-08-10 19:20:23 +00:00
|
|
|
}
|
|
|
|
|
2009-10-07 00:50:32 +00:00
|
|
|
virtual void jumpIfFloatLessOrEqualOrUnordered(unsigned size, Operand* a,
|
|
|
|
Operand* b, Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfFloatLessOrEqualOrUnordered, size,
|
|
|
|
static_cast<Value*>(a), static_cast<Value*>(b),
|
|
|
|
static_cast<Value*>(address));
|
2009-08-10 19:20:23 +00:00
|
|
|
}
|
2009-10-07 00:50:32 +00:00
|
|
|
|
|
|
|
virtual void jumpIfFloatGreaterOrEqualOrUnordered(unsigned size, Operand* a,
|
|
|
|
Operand* b,
|
|
|
|
Operand* address)
|
|
|
|
{
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
|
|
|
|
|
|
|
appendBranch(&c, JumpIfFloatGreaterOrEqualOrUnordered, size,
|
|
|
|
static_cast<Value*>(a), static_cast<Value*>(b),
|
|
|
|
static_cast<Value*>(address));
|
2009-08-06 16:14:31 +00:00
|
|
|
}
|
2007-12-26 16:56:14 +00:00
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
virtual void jmp(Operand* address) {
|
2009-10-10 21:03:23 +00:00
|
|
|
appendJump(&c, Jump, static_cast<Value*>(address));
|
2007-12-09 22:45:43 +00:00
|
|
|
}
|
|
|
|
|
2009-04-26 02:54:36 +00:00
|
|
|
virtual void exit(Operand* address) {
|
2009-10-10 21:03:23 +00:00
|
|
|
appendJump(&c, Jump, static_cast<Value*>(address), true);
|
2009-04-26 02:54:36 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* add(unsigned size, Operand* a, Operand* b) {
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* result = value(&c, ValueGeneral);
|
2008-04-17 20:48:26 +00:00
|
|
|
appendCombine(&c, Add, size, static_cast<Value*>(a),
|
2008-09-05 15:00:38 +00:00
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-09 22:45:43 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* sub(unsigned size, Operand* a, Operand* b) {
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* result = value(&c, ValueGeneral);
|
2008-04-17 20:48:26 +00:00
|
|
|
appendCombine(&c, Subtract, size, static_cast<Value*>(a),
|
2008-09-05 15:00:38 +00:00
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-23 00:00:35 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* mul(unsigned size, Operand* a, Operand* b) {
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* result = value(&c, ValueGeneral);
|
2008-04-17 20:48:26 +00:00
|
|
|
appendCombine(&c, Multiply, size, static_cast<Value*>(a),
|
2008-09-05 15:00:38 +00:00
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* div(unsigned size, Operand* a, Operand* b) {
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* result = value(&c, ValueGeneral);
|
2008-04-17 20:48:26 +00:00
|
|
|
appendCombine(&c, Divide, size, static_cast<Value*>(a),
|
2008-09-05 15:00:38 +00:00
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-22 00:26:55 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* rem(unsigned size, Operand* a, Operand* b) {
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral
|
|
|
|
and static_cast<Value*>(b)->type == ValueGeneral);
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* result = value(&c, ValueGeneral);
|
2008-04-17 20:48:26 +00:00
|
|
|
appendCombine(&c, Remainder, size, static_cast<Value*>(a),
|
2008-09-05 15:00:38 +00:00
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2009-08-06 16:14:31 +00:00
|
|
|
virtual Operand* fadd(unsigned size, Operand* a, Operand* b) {
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* result = value(&c, ValueFloat);
|
2009-08-06 16:14:31 +00:00
|
|
|
static_cast<Value*>(a)->type = static_cast<Value*>(b)->type = ValueFloat;
|
|
|
|
appendCombine(&c, FloatAdd, size, static_cast<Value*>(a),
|
|
|
|
size, static_cast<Value*>(b), size, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* fsub(unsigned size, Operand* a, Operand* b) {
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* result = value(&c, ValueFloat);
|
2009-08-06 16:14:31 +00:00
|
|
|
static_cast<Value*>(a)->type = static_cast<Value*>(b)->type = ValueFloat;
|
|
|
|
appendCombine(&c, FloatSubtract, size, static_cast<Value*>(a),
|
|
|
|
size, static_cast<Value*>(b), size, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* fmul(unsigned size, Operand* a, Operand* b) {
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* result = value(&c, ValueFloat);
|
2009-08-06 16:14:31 +00:00
|
|
|
static_cast<Value*>(a)->type = static_cast<Value*>(b)->type = ValueFloat;
|
|
|
|
appendCombine(&c, FloatMultiply, size, static_cast<Value*>(a),
|
|
|
|
size, static_cast<Value*>(b), size, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* fdiv(unsigned size, Operand* a, Operand* b) {
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* result = value(&c, ValueFloat);
|
2009-08-06 16:14:31 +00:00
|
|
|
appendCombine(&c, FloatDivide, size, static_cast<Value*>(a),
|
|
|
|
size, static_cast<Value*>(b), size, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* frem(unsigned size, Operand* a, Operand* b) {
|
2009-09-20 21:43:32 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat
|
|
|
|
and static_cast<Value*>(b)->type == ValueFloat);
|
2009-08-10 19:20:23 +00:00
|
|
|
Value* result = value(&c, ValueFloat);
|
2009-08-06 16:14:31 +00:00
|
|
|
appendCombine(&c, FloatRemainder, size, static_cast<Value*>(a),
|
|
|
|
size, static_cast<Value*>(b), size, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* shl(unsigned size, Operand* a, Operand* b) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral);
|
|
|
|
Value* result = value(&c, ValueGeneral);
|
2011-08-30 01:00:17 +00:00
|
|
|
appendCombine(&c, ShiftLeft, TargetBytesPerWord, static_cast<Value*>(a),
|
2008-09-05 15:00:38 +00:00
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* shr(unsigned size, Operand* a, Operand* b) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral);
|
|
|
|
Value* result = value(&c, ValueGeneral);
|
2011-08-30 01:00:17 +00:00
|
|
|
appendCombine(&c, ShiftRight, TargetBytesPerWord, static_cast<Value*>(a),
|
2008-09-05 15:00:38 +00:00
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-26 16:56:14 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* ushr(unsigned size, Operand* a, Operand* b) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral);
|
|
|
|
Value* result = value(&c, ValueGeneral);
|
2009-09-20 21:43:32 +00:00
|
|
|
appendCombine
|
2011-08-30 01:00:17 +00:00
|
|
|
(&c, UnsignedShiftRight, TargetBytesPerWord, static_cast<Value*>(a),
|
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* and_(unsigned size, Operand* a, Operand* b) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral);
|
|
|
|
Value* result = value(&c, ValueGeneral);
|
2008-04-17 20:48:26 +00:00
|
|
|
appendCombine(&c, And, size, static_cast<Value*>(a),
|
2008-09-05 15:00:38 +00:00
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* or_(unsigned size, Operand* a, Operand* b) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral);
|
|
|
|
Value* result = value(&c, ValueGeneral);
|
2008-04-17 20:48:26 +00:00
|
|
|
appendCombine(&c, Or, size, static_cast<Value*>(a),
|
2008-09-05 15:00:38 +00:00
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-12 18:59:45 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* xor_(unsigned size, Operand* a, Operand* b) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral);
|
|
|
|
Value* result = value(&c, ValueGeneral);
|
2008-04-17 20:48:26 +00:00
|
|
|
appendCombine(&c, Xor, size, static_cast<Value*>(a),
|
2008-09-05 15:00:38 +00:00
|
|
|
size, static_cast<Value*>(b), size, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 02:06:12 +00:00
|
|
|
virtual Operand* neg(unsigned size, Operand* a) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral);
|
|
|
|
Value* result = value(&c, ValueGeneral);
|
2009-08-06 16:14:31 +00:00
|
|
|
appendTranslate(&c, Negate, size, static_cast<Value*>(a), size, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* fneg(unsigned size, Operand* a) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat);
|
|
|
|
Value* result = value(&c, ValueFloat);
|
2009-09-20 21:43:32 +00:00
|
|
|
appendTranslate
|
|
|
|
(&c, FloatNegate, size, static_cast<Value*>(a), size, result);
|
2009-08-06 16:14:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
2009-10-18 01:26:14 +00:00
|
|
|
|
|
|
|
virtual Operand* abs(unsigned size, Operand* a) {
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral);
|
|
|
|
Value* result = value(&c, ValueGeneral);
|
|
|
|
appendTranslate(&c, Absolute, size, static_cast<Value*>(a), size, result);
|
2009-09-20 21:43:32 +00:00
|
|
|
return result;
|
2009-08-06 16:14:31 +00:00
|
|
|
}
|
2009-10-18 01:26:14 +00:00
|
|
|
|
|
|
|
virtual Operand* fabs(unsigned size, Operand* a) {
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat);
|
|
|
|
Value* result = value(&c, ValueFloat);
|
|
|
|
appendTranslate
|
|
|
|
(&c, FloatAbsolute, size, static_cast<Value*>(a), size, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* fsqrt(unsigned size, Operand* a) {
|
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat);
|
|
|
|
Value* result = value(&c, ValueFloat);
|
|
|
|
appendTranslate
|
|
|
|
(&c, FloatSquareRoot, size, static_cast<Value*>(a), size, result);
|
2009-08-06 16:14:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* f2f(unsigned aSize, unsigned resSize, Operand* a) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat);
|
|
|
|
Value* result = value(&c, ValueFloat);
|
2009-09-20 21:43:32 +00:00
|
|
|
appendTranslate
|
|
|
|
(&c, Float2Float, aSize, static_cast<Value*>(a), resSize, result);
|
2009-08-06 16:14:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* f2i(unsigned aSize, unsigned resSize, Operand* a) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueFloat);
|
|
|
|
Value* result = value(&c, ValueGeneral);
|
2009-09-20 21:43:32 +00:00
|
|
|
appendTranslate
|
|
|
|
(&c, Float2Int, aSize, static_cast<Value*>(a), resSize, result);
|
2009-08-06 16:14:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Operand* i2f(unsigned aSize, unsigned resSize, Operand* a) {
|
2009-08-10 19:20:23 +00:00
|
|
|
assert(&c, static_cast<Value*>(a)->type == ValueGeneral);
|
|
|
|
Value* result = value(&c, ValueFloat);
|
2009-09-20 21:43:32 +00:00
|
|
|
appendTranslate
|
|
|
|
(&c, Int2Float, aSize, static_cast<Value*>(a), resSize, result);
|
2008-02-11 17:21:41 +00:00
|
|
|
return result;
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
fix a couple of subtle Thread.getStackTrace bugs
The first problem was that, on x86, we failed to properly keep track
of whether to expect the return address to be on the stack or not when
unwinding through a frame. We were relying on a "stackLimit" pointer
to tell us whether we were looking at the most recently-called frame
by comparing it with the stack pointer for that frame. That was
inaccurate in the case of a thread executing at the beginning of a
method before a new frame is allocated, in which case the most recent
two frames share a stack pointer, confusing the unwinder. The
solution involves keeping track of how many frames we've looked at
while walking the stack.
The other problem was that compareIpToMethodBounds assumed every
method was followed by at least one byte of padding before the next
method started. That assumption was usually valid because we were
storing the size following method code prior to the code itself.
However, the last method of an AOT-compiled code image is not followed
by any such method header and may instead be followed directly by
native code with no intervening padding. In that case, we risk
interpreting that native code as part of the preceding method, with
potentially bizarre results.
The reason for the compareIpToMethodBounds assumption was that methods
which throw exceptions as their last instruction generate a
non-returning call, which nonetheless push a return address on the
stack which points past the end of the method, and the unwinder needs
to know that return address belongs to that method. A better solution
is to add an extra trap instruction to the end of such methods, which
is what this patch does.
2012-05-05 00:35:13 +00:00
|
|
|
virtual void trap() {
|
|
|
|
appendOperation(&c, Trap);
|
|
|
|
}
|
|
|
|
|
2009-03-03 03:18:15 +00:00
|
|
|
virtual void loadBarrier() {
|
fix a couple of subtle Thread.getStackTrace bugs
The first problem was that, on x86, we failed to properly keep track
of whether to expect the return address to be on the stack or not when
unwinding through a frame. We were relying on a "stackLimit" pointer
to tell us whether we were looking at the most recently-called frame
by comparing it with the stack pointer for that frame. That was
inaccurate in the case of a thread executing at the beginning of a
method before a new frame is allocated, in which case the most recent
two frames share a stack pointer, confusing the unwinder. The
solution involves keeping track of how many frames we've looked at
while walking the stack.
The other problem was that compareIpToMethodBounds assumed every
method was followed by at least one byte of padding before the next
method started. That assumption was usually valid because we were
storing the size following method code prior to the code itself.
However, the last method of an AOT-compiled code image is not followed
by any such method header and may instead be followed directly by
native code with no intervening padding. In that case, we risk
interpreting that native code as part of the preceding method, with
potentially bizarre results.
The reason for the compareIpToMethodBounds assumption was that methods
which throw exceptions as their last instruction generate a
non-returning call, which nonetheless push a return address on the
stack which points past the end of the method, and the unwinder needs
to know that return address belongs to that method. A better solution
is to add an extra trap instruction to the end of such methods, which
is what this patch does.
2012-05-05 00:35:13 +00:00
|
|
|
appendOperation(&c, LoadBarrier);
|
2009-03-03 03:18:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void storeStoreBarrier() {
|
fix a couple of subtle Thread.getStackTrace bugs
The first problem was that, on x86, we failed to properly keep track
of whether to expect the return address to be on the stack or not when
unwinding through a frame. We were relying on a "stackLimit" pointer
to tell us whether we were looking at the most recently-called frame
by comparing it with the stack pointer for that frame. That was
inaccurate in the case of a thread executing at the beginning of a
method before a new frame is allocated, in which case the most recent
two frames share a stack pointer, confusing the unwinder. The
solution involves keeping track of how many frames we've looked at
while walking the stack.
The other problem was that compareIpToMethodBounds assumed every
method was followed by at least one byte of padding before the next
method started. That assumption was usually valid because we were
storing the size following method code prior to the code itself.
However, the last method of an AOT-compiled code image is not followed
by any such method header and may instead be followed directly by
native code with no intervening padding. In that case, we risk
interpreting that native code as part of the preceding method, with
potentially bizarre results.
The reason for the compareIpToMethodBounds assumption was that methods
which throw exceptions as their last instruction generate a
non-returning call, which nonetheless push a return address on the
stack which points past the end of the method, and the unwinder needs
to know that return address belongs to that method. A better solution
is to add an extra trap instruction to the end of such methods, which
is what this patch does.
2012-05-05 00:35:13 +00:00
|
|
|
appendOperation(&c, StoreStoreBarrier);
|
2009-03-03 03:18:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void storeLoadBarrier() {
|
fix a couple of subtle Thread.getStackTrace bugs
The first problem was that, on x86, we failed to properly keep track
of whether to expect the return address to be on the stack or not when
unwinding through a frame. We were relying on a "stackLimit" pointer
to tell us whether we were looking at the most recently-called frame
by comparing it with the stack pointer for that frame. That was
inaccurate in the case of a thread executing at the beginning of a
method before a new frame is allocated, in which case the most recent
two frames share a stack pointer, confusing the unwinder. The
solution involves keeping track of how many frames we've looked at
while walking the stack.
The other problem was that compareIpToMethodBounds assumed every
method was followed by at least one byte of padding before the next
method started. That assumption was usually valid because we were
storing the size following method code prior to the code itself.
However, the last method of an AOT-compiled code image is not followed
by any such method header and may instead be followed directly by
native code with no intervening padding. In that case, we risk
interpreting that native code as part of the preceding method, with
potentially bizarre results.
The reason for the compareIpToMethodBounds assumption was that methods
which throw exceptions as their last instruction generate a
non-returning call, which nonetheless push a return address on the
stack which points past the end of the method, and the unwinder needs
to know that return address belongs to that method. A better solution
is to add an extra trap instruction to the end of such methods, which
is what this patch does.
2012-05-05 00:35:13 +00:00
|
|
|
appendOperation(&c, StoreLoadBarrier);
|
2009-03-03 03:18:15 +00:00
|
|
|
}
|
|
|
|
|
2011-02-28 06:03:13 +00:00
|
|
|
virtual void compile(uintptr_t stackOverflowHandler,
|
|
|
|
unsigned stackLimitOffset)
|
2010-12-19 22:23:19 +00:00
|
|
|
{
|
2011-02-28 06:03:13 +00:00
|
|
|
local::compile(&c, stackOverflowHandler, stackLimitOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned resolve(uint8_t* dst) {
|
|
|
|
c.machineCode = dst;
|
|
|
|
c.assembler->setDestination(dst);
|
|
|
|
|
|
|
|
Block* block = c.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 c.machineCodeSize = block->assemblerBlock->resolve
|
|
|
|
(block->start, 0) + c.assembler->footerSize();
|
2007-12-11 23:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned poolSize() {
|
2011-08-30 01:00:17 +00:00
|
|
|
return c.constantCount * TargetBytesPerWord;
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
2011-02-28 06:03:13 +00:00
|
|
|
virtual void write() {
|
|
|
|
c.assembler->write();
|
2007-12-11 23:52:28 +00:00
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
int i = 0;
|
|
|
|
for (ConstantPoolNode* n = c.firstConstant; n; n = n->next) {
|
2011-09-01 03:18:00 +00:00
|
|
|
target_intptr_t* target = reinterpret_cast<target_intptr_t*>
|
|
|
|
(c.machineCode + pad(c.machineCodeSize, TargetBytesPerWord) + i);
|
2008-12-02 16:45:20 +00:00
|
|
|
|
|
|
|
if (n->promise->resolved()) {
|
2011-09-24 04:21:54 +00:00
|
|
|
*target = targetVW(n->promise->value());
|
2008-12-02 16:45:20 +00:00
|
|
|
} else {
|
|
|
|
class Listener: public Promise::Listener {
|
|
|
|
public:
|
2011-09-01 03:18:00 +00:00
|
|
|
Listener(target_intptr_t* target): target(target){ }
|
2008-12-02 16:45:20 +00:00
|
|
|
|
2009-03-11 01:08:16 +00:00
|
|
|
virtual bool resolve(int64_t value, void** location) {
|
2011-09-24 04:21:54 +00:00
|
|
|
*target = targetVW(value);
|
2009-03-11 01:08:16 +00:00
|
|
|
if (location) *location = target;
|
|
|
|
return true;
|
2008-12-02 16:45:20 +00:00
|
|
|
}
|
|
|
|
|
2011-09-01 03:18:00 +00:00
|
|
|
target_intptr_t* target;
|
2008-12-02 16:45:20 +00:00
|
|
|
};
|
|
|
|
new (n->promise->listen(sizeof(Listener))) Listener(target);
|
|
|
|
}
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
i += TargetBytesPerWord;
|
2007-12-16 00:24:15 +00:00
|
|
|
}
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2008-02-11 17:21:41 +00:00
|
|
|
// ignore
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-09 20:03:21 +00:00
|
|
|
Context c;
|
2009-08-27 00:26:44 +00:00
|
|
|
local::Client client;
|
2007-12-08 23:22:13 +00:00
|
|
|
};
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
} // namespace local
|
|
|
|
|
2007-12-08 23:22:13 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
|
|
|
Compiler*
|
2008-05-06 21:13:02 +00:00
|
|
|
makeCompiler(System* system, Assembler* assembler, Zone* zone,
|
2008-05-31 22:14:27 +00:00
|
|
|
Compiler::Client* client)
|
2007-12-08 23:22:13 +00:00
|
|
|
{
|
2012-05-08 22:13:17 +00:00
|
|
|
return new(zone) local::MyCompiler(system, assembler, zone, client);
|
2007-12-08 23:22:13 +00:00
|
|
|
}
|
|
|
|
|
2008-02-11 17:21:41 +00:00
|
|
|
} // namespace vm
|