Optimization 30
This commit is contained in:
parent
51bc1395f8
commit
f1e6ed4ef8
7 changed files with 101 additions and 29 deletions
3
dub.sdl
3
dub.sdl
|
|
@ -9,6 +9,7 @@ sourcePaths
|
|||
configuration "clox" {
|
||||
buildOptions "betterC"
|
||||
sourcePaths "src/clox"
|
||||
versions "nanBoxing"
|
||||
}
|
||||
|
||||
configuration "clox-dbg" {
|
||||
|
|
@ -18,6 +19,8 @@ configuration "clox-dbg" {
|
|||
sourcePaths "src/clox"
|
||||
buildRequirements "requireBoundsCheck" "requireContracts"
|
||||
|
||||
versions "nanBoxing"
|
||||
|
||||
debugVersions "printCode" "traceExec"
|
||||
|
||||
/* debugVersions "stressGC" */
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ debug import std.stdio : writeln;
|
|||
import clox.memory;
|
||||
import clox.memorydbg;
|
||||
import clox.obj;
|
||||
import clox.util;
|
||||
import clox.value;
|
||||
import clox.container.dynarray;
|
||||
import conf = clox.conf;
|
||||
|
|
@ -29,6 +30,7 @@ struct Table(K, V){
|
|||
Entry[] pool;
|
||||
size_t alive;
|
||||
this(size_t size){
|
||||
size = npow2(size);
|
||||
pool = allocatePool(size);
|
||||
}
|
||||
void free(){
|
||||
|
|
@ -69,21 +71,21 @@ struct Table(K, V){
|
|||
if(alive == 0)
|
||||
return null;
|
||||
Hash hash = getHash(key);
|
||||
size_t index = hash % pool.length;
|
||||
size_t index = hash & ((pool.length) - 1);
|
||||
while(true){
|
||||
const entry = pool[index];
|
||||
if(entry.isAlive && entry.key == key)
|
||||
return &pool[index];
|
||||
if(entry.isFree)
|
||||
break;
|
||||
index = (index+1) % pool.length;
|
||||
index = (index+1) & ((pool.length) - 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
void opIndexAssign(V val, in K key){
|
||||
checkResize();
|
||||
Hash hash = getHash(key);
|
||||
size_t index = hash % pool.length;
|
||||
size_t index = hash & ((pool.length) - 1);
|
||||
while(true){
|
||||
const Entry* entry = &pool[index];
|
||||
if(entry.isAlive && entry.key == key)
|
||||
|
|
@ -92,7 +94,7 @@ struct Table(K, V){
|
|||
alive++;
|
||||
break;
|
||||
}
|
||||
index = (index+1) % pool.length;
|
||||
index = (index+1) & ((pool.length) - 1);
|
||||
}
|
||||
pool[index] = Entry(cast(K)key, val);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,3 +70,18 @@ version(D_BetterC) {} else string prettyPtr(void* ptr){
|
|||
return "\033[38;2;" ~ colours[0].to!string ~ ";" ~ colours[1].to!string ~ ";" ~ colours[2].to!string ~ "m" ~ ptr.to!string ~ "\033[0m";
|
||||
}
|
||||
|
||||
size_t npow2(size_t n){
|
||||
n--;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
// https://github.com/dlang/phobos/blob/832cc465998b1ea77051cd3fd014b544442a4f8c/std/conv.d#L6396
|
||||
pragma(inline, true) ref T bitCast(T, S)(ref S value) if (T.sizeof <= S.sizeof){
|
||||
return *cast(T*) &value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,41 +4,88 @@ import core.stdc.stdio;
|
|||
|
||||
import clox.memory;
|
||||
import clox.obj;
|
||||
import clox.util;
|
||||
|
||||
struct Value{
|
||||
enum Type{
|
||||
None, Bool, Nil, Number, Obj
|
||||
}
|
||||
Type type;
|
||||
private union Un{
|
||||
bool boolean;
|
||||
double number;
|
||||
Obj* obj;
|
||||
}
|
||||
private Un un;
|
||||
version(nanBoxing){
|
||||
private enum QNAN = ulong(0x7ffc000000000000);
|
||||
private enum SIGN_BIT = ulong(0x8000000000000000);
|
||||
enum Tag{
|
||||
Nil = 1, False = 2, True = 3
|
||||
}
|
||||
ulong data;
|
||||
static Value from(double val) => Value(val.bitCast!ulong);
|
||||
static Value from(bool val) => Value(val ? QNAN | Tag.True : QNAN | Tag.False);
|
||||
static Value from(T)(T* val) if(__traits(compiles, val.obj)) => Value(SIGN_BIT | QNAN | val.bitCast!ulong);
|
||||
static Value nil() pure => Value(QNAN | Tag.Nil);
|
||||
|
||||
Type type() const pure{
|
||||
if(isType(Type.Number))
|
||||
return Type.Number;
|
||||
if(isType(Type.Bool))
|
||||
return Type.Bool;
|
||||
if(isType(Type.Nil))
|
||||
return Type.Nil;
|
||||
if(isType(Type.Obj))
|
||||
return Type.Obj;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
bool isType(Type type) const pure{
|
||||
final switch(type){
|
||||
case Type.Number: return (data & QNAN) != QNAN;
|
||||
case Type.Nil: return data == nil.data;
|
||||
case Type.Bool: return data == (QNAN | Tag.True) || data == (QNAN | Tag.False);
|
||||
case Type.Obj: return (data & (QNAN | SIGN_BIT)) == (QNAN | SIGN_BIT);
|
||||
case Type.None: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
auto as(Type type)() const pure{
|
||||
static if(type != Type.None)
|
||||
assert(isType(type));
|
||||
static if(type == Type.Number) return data.bitCast!double;
|
||||
static if(type == Type.Bool) return data == (QNAN | Tag.True);
|
||||
static if(type == Type.Obj) return cast(Obj*)(data & ~(SIGN_BIT | QNAN));
|
||||
static if(type == Type.None) return this;
|
||||
}
|
||||
|
||||
} else {
|
||||
private union Un{
|
||||
bool boolean;
|
||||
double number;
|
||||
Obj* obj;
|
||||
}
|
||||
private Type type;
|
||||
private Un un;
|
||||
static Value from(double val) => Value(Type.Number, Un(number: val));
|
||||
static Value from(bool val) => Value(Type.Bool, Un(boolean: val));
|
||||
static Value from(T)(T* val) if(__traits(compiles, val.obj)) => Value(Type.Obj, Un(obj: cast(Obj*)val));
|
||||
static Value from(Value val) => val;
|
||||
static Value nil() pure => Value(Type.Nil);
|
||||
|
||||
bool isType(Type type) const pure => this.type == type;
|
||||
auto as(Type type)() const pure{
|
||||
static if(type != Type.None)
|
||||
assert(isType(type));
|
||||
static if(type == Type.Number) return un.number;
|
||||
static if(type == Type.Bool) return un.boolean;
|
||||
static if(type == Type.Obj) return un.obj;
|
||||
static if(type == Type.None) return this;
|
||||
}
|
||||
|
||||
bool isType(Type type) const pure => this.type == type;
|
||||
bool isType(Obj.Type type) const pure => this.type == Type.Obj && asObj.isType(type);
|
||||
auto as(Type type)() const pure{
|
||||
static if(type != Type.None)
|
||||
assert(this.type == type);
|
||||
static if(type == Type.Number) return un.number;
|
||||
static if(type == Type.Bool) return un.boolean;
|
||||
static if(type == Type.Obj) return un.obj;
|
||||
static if(type == Type.None) return this;
|
||||
}
|
||||
|
||||
bool isType(Obj.Type type) const pure => isType(Type.Obj) && asObj.isType(type);
|
||||
|
||||
bool asBoolean() const pure => as!(Type.Bool);
|
||||
double asNumber() const pure => as!(Type.Number);
|
||||
Obj* asObj() const pure => cast(Obj*)as!(Type.Obj);
|
||||
|
||||
static Value from(T: double)(T val) => Value(Type.Number, Un(number: val));
|
||||
static Value from(T: bool)(T val) => Value(Type.Bool, Un(boolean: val));
|
||||
static Value from(T)(T* val) if(__traits(compiles, val.obj)) => Value(Type.Obj, Un(obj: cast(Obj*)val));
|
||||
static Value from(T: Value)(T val) => val;
|
||||
static Value nil() pure => Value(Type.Nil);
|
||||
|
||||
bool isFalsey() const pure => (type == Type.Bool && asBoolean == false) || type == Type.Nil;
|
||||
bool isFalsey() const pure => (isType(Type.Bool) && asBoolean == false) || isType(Type.Nil);
|
||||
bool isTruthy() const pure => !isFalsey;
|
||||
bool opEquals(Value rhs) const pure{
|
||||
if(rhs.type != type)
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@ struct VM{
|
|||
Value readConstant() => chunk.constants[readVarUint()];
|
||||
Obj.String* readString() => readConstant().asObj.asString;
|
||||
bool checkBinaryType(alias type)() => peek(0).isType(type) && peek(1).isType(type);
|
||||
bool checkSameType()() => peek(0).type == peek(1).type;
|
||||
int binaryOp(string op, alias check, string checkMsg, alias pre)(){
|
||||
if(!check){
|
||||
runtimeError(checkMsg.ptr);
|
||||
|
|
@ -234,7 +233,7 @@ struct VM{
|
|||
}
|
||||
static foreach(k, op; [ OpCode.Greater: ">", OpCode.Less: "<", OpCode.GreaterEqual: ">=", OpCode.LessEqual: "<=" ]){
|
||||
case k:
|
||||
if(binaryOp!(op, checkSameType, "Operands must be of the same type.", Value.Type.None))
|
||||
if(binaryOp!(op, checkBinaryType!(Value.Type.Number), "Operands must be of the same type.", Value.Type.None))
|
||||
return InterpretResult.RuntimeError;
|
||||
break opSwitch;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ int main(){
|
|||
"./test/while.lox".match("1 2 3 2 1 0 1 1 2 3 2 1 0 1 ".replace(' ', '\n'));
|
||||
"./test/fields.lox".match("0 10 ".replace(' ', '\n'));
|
||||
|
||||
"./test/nan!=nan.lox".match("false ".replace(' ', '\n'));
|
||||
|
||||
"./test/ops.lox".match("1\n2\n3\n4\n5\n6\n7\ntrue\nfalse\ntrue\ntrue\nhello, world\n");
|
||||
"./test/shortcircuit.lox".match("true\nAAAA!\nAAAA!\nAAAA?\n");
|
||||
"./test/closure.lox".match("1\n2\n");
|
||||
|
|
|
|||
4
test/nan!=nan.lox
Normal file
4
test/nan!=nan.lox
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
var nan = 0 / 0;
|
||||
print nan == nan;
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue