1
0
forked from Mirror/wren

Merge branch 'unify_string' of https://github.com/mhermier/wren into mhermier-unify_string

This commit is contained in:
Bob Nystrom
2018-04-28 10:22:42 -07:00
9 changed files with 99 additions and 73 deletions

View File

@ -52,9 +52,7 @@ void metaGetModuleVariables(WrenVM* vm) {
for (int i = 0; i < names->elements.count; i++)
{
String* name = &module->variableNames.data[i];
names->elements.data[i] = wrenNewStringLength(vm,
name->buffer, name->length);
names->elements.data[i] = OBJ_VAL(module->variableNames.data[i]);
}
}

View File

@ -199,4 +199,17 @@
#endif
typedef struct sObjClass ObjClass;
typedef struct sObjClosure ObjClosure;
typedef struct sObjFiber ObjFiber;
typedef struct sObjForeign ObjForeign;
typedef struct sObjFn ObjFn;
typedef struct sObjInstance ObjInstance;
typedef struct sObjList ObjList;
typedef struct sObjMap ObjMap;
typedef struct sObjModule ObjModule;
typedef struct sObjRange ObjRange;
typedef struct sObjString ObjString;
typedef struct sObjUpvalue ObjUpvalue;
#endif

View File

@ -3487,8 +3487,8 @@ ObjFn* wrenCompile(WrenVM* vm, ObjModule* module, const char* source,
{
// Synthesize a token for the original use site.
parser.previous.type = TOKEN_NAME;
parser.previous.start = parser.module->variableNames.data[i].buffer;
parser.previous.length = parser.module->variableNames.data[i].length;
parser.previous.start = parser.module->variableNames.data[i]->value;
parser.previous.length = parser.module->variableNames.data[i]->length;
parser.previous.line = (int)AS_NUM(parser.module->variables.data[i]);
error(&compiler, "Variable is used but not defined.");
}

View File

@ -159,7 +159,7 @@ static int dumpInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine)
{
int slot = READ_SHORT();
printf("%-16s %5d '%s'\n", "LOAD_MODULE_VAR", slot,
fn->module->variableNames.data[slot].buffer);
fn->module->variableNames.data[slot]->value);
break;
}
@ -167,7 +167,7 @@ static int dumpInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine)
{
int slot = READ_SHORT();
printf("%-16s %5d '%s'\n", "STORE_MODULE_VAR", slot,
fn->module->variableNames.data[slot].buffer);
fn->module->variableNames.data[slot]->value);
break;
}
@ -199,7 +199,7 @@ static int dumpInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine)
int numArgs = bytecode[i - 1] - CODE_CALL_0;
int symbol = READ_SHORT();
printf("CALL_%-11d %5d '%s'\n", numArgs, symbol,
vm->methodNames.data[symbol].buffer);
vm->methodNames.data[symbol]->value);
break;
}
@ -225,7 +225,7 @@ static int dumpInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine)
int symbol = READ_SHORT();
int superclass = READ_SHORT();
printf("SUPER_%-10d %5d '%s' %5d\n", numArgs, symbol,
vm->methodNames.data[symbol].buffer, superclass);
vm->methodNames.data[symbol]->value, superclass);
break;
}
@ -301,7 +301,7 @@ static int dumpInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine)
{
int symbol = READ_SHORT();
printf("%-16s %5d '%s'\n", "METHOD_INSTANCE", symbol,
vm->methodNames.data[symbol].buffer);
vm->methodNames.data[symbol]->value);
break;
}
@ -309,7 +309,7 @@ static int dumpInstruction(WrenVM* vm, ObjFn* fn, int i, int* lastLine)
{
int symbol = READ_SHORT();
printf("%-16s %5d '%s'\n", "METHOD_STATIC", symbol,
vm->methodNames.data[symbol].buffer);
vm->methodNames.data[symbol]->value);
break;
}

View File

@ -5,7 +5,7 @@
DEFINE_BUFFER(Byte, uint8_t);
DEFINE_BUFFER(Int, int);
DEFINE_BUFFER(String, String);
DEFINE_BUFFER(String, ObjString*);
void wrenSymbolTableInit(SymbolTable* symbols)
{
@ -14,24 +14,18 @@ void wrenSymbolTableInit(SymbolTable* symbols)
void wrenSymbolTableClear(WrenVM* vm, SymbolTable* symbols)
{
for (int i = 0; i < symbols->count; i++)
{
DEALLOCATE(vm, symbols->data[i].buffer);
}
wrenStringBufferClear(vm, symbols);
}
int wrenSymbolTableAdd(WrenVM* vm, SymbolTable* symbols,
const char* name, size_t length)
{
String symbol;
symbol.buffer = ALLOCATE_ARRAY(vm, char, length + 1);
memcpy(symbol.buffer, name, length);
symbol.buffer[length] = '\0';
symbol.length = (int)length;
ObjString* symbol = AS_STRING(wrenNewStringLength(vm, name, length));
wrenPushRoot(vm, &symbol->obj);
wrenStringBufferWrite(vm, symbols, symbol);
wrenPopRoot(vm); // symbol
return symbols->count - 1;
}
@ -46,20 +40,30 @@ int wrenSymbolTableEnsure(WrenVM* vm, SymbolTable* symbols,
return wrenSymbolTableAdd(vm, symbols, name, length);
}
int wrenSymbolTableFind(const SymbolTable* symbols,
const char* name, size_t length)
int wrenSymbolTableFind(const SymbolTable* symbols,
const char* name, size_t length)
{
// See if the symbol is already defined.
// TODO: O(n). Do something better.
for (int i = 0; i < symbols->count; i++)
{
if (symbols->data[i].length == length &&
memcmp(symbols->data[i].buffer, name, length) == 0) return i;
if(wrenStringEqualStrLength(symbols->data[i], name, length)) return i;
}
return -1;
}
void wrenBlackenSymbolTable(WrenVM* vm, SymbolTable* symbolTable)
{
for (int i = 0; i < symbolTable->count; i++)
{
wrenGrayObj(vm, &symbolTable->data[i]->obj);
}
// Keep track of how much memory is still in use.
vm->bytesAllocated += symbolTable->capacity * sizeof(*symbolTable->data);
}
int wrenUtf8EncodeNumBytes(int value)
{
ASSERT(value >= 0, "Cannot encode a negative value.");

View File

@ -6,13 +6,6 @@
// Reusable data structures and other utility functions.
// A simple structure to keep track of a string and its length (including the
// null-terminator).
typedef struct {
char* buffer;
uint32_t length;
} String;
// We need buffers of a few different types. To avoid lots of casting between
// void* and back, we'll use the preprocessor as a poor man's generics and let
// it generate a few type-specific ones.
@ -68,7 +61,7 @@ typedef struct {
DECLARE_BUFFER(Byte, uint8_t);
DECLARE_BUFFER(Int, int);
DECLARE_BUFFER(String, String);
DECLARE_BUFFER(String, ObjString*);
// TODO: Change this to use a map.
typedef StringBuffer SymbolTable;
@ -90,8 +83,10 @@ int wrenSymbolTableEnsure(WrenVM* vm, SymbolTable* symbols,
const char* name, size_t length);
// Looks up name in the symbol table. Returns its index if found or -1 if not.
int wrenSymbolTableFind(const SymbolTable* symbols,
const char* name, size_t length);
int wrenSymbolTableFind(const SymbolTable* symbols,
const char* name, size_t length);
void wrenBlackenSymbolTable(WrenVM* vm, SymbolTable* symbolTable);
// Returns the number of bytes needed to encode [value] in UTF-8.
//

View File

@ -1141,11 +1141,12 @@ static void blackenModule(WrenVM* vm, ObjModule* module)
wrenGrayValue(vm, module->variables.data[i]);
}
wrenBlackenSymbolTable(vm, &module->variableNames);
wrenGrayObj(vm, (Obj*)module->name);
// Keep track of how much memory is still in use.
vm->bytesAllocated += sizeof(ObjModule);
// TODO: Track memory for symbol table and buffer.
}
static void blackenRange(WrenVM* vm, ObjRange* range)
@ -1298,11 +1299,7 @@ bool wrenValuesEqual(Value a, Value b)
case OBJ_STRING:
{
ObjString* aString = (ObjString*)aObj;
ObjString* bString = (ObjString*)bObj;
return aString->length == bString->length &&
aString->hash == bString->hash &&
memcmp(aString->value, bString->value, aString->length) == 0;
return wrenStringsEqual((ObjString*)aObj, (ObjString*)bObj);
}
default:

View File

@ -2,6 +2,7 @@
#define wren_value_h
#include <stdbool.h>
#include <string.h>
#include "wren_common.h"
#include "wren_utils.h"
@ -99,10 +100,9 @@ typedef enum {
OBJ_UPVALUE
} ObjType;
typedef struct sObjClass ObjClass;
// Base struct for all heap-allocated objects.
typedef struct sObj
typedef struct sObj Obj;
struct sObj
{
ObjType type;
bool isDark;
@ -112,7 +112,7 @@ typedef struct sObj
// The next object in the linked list of all currently allocated objects.
struct sObj* next;
} Obj;
};
#if WREN_NAN_TAGGING
@ -145,7 +145,7 @@ typedef struct
DECLARE_BUFFER(Value, Value);
// A heap-allocated string object.
typedef struct
struct sObjString
{
Obj obj;
@ -157,7 +157,7 @@ typedef struct
// Inline array of the string's bytes followed by a null terminator.
char value[FLEXIBLE_ARRAY];
} ObjString;
};
// The dynamically allocated data structure for a variable that has been used
// by a closure. Whenever a function accesses a variable declared in an
@ -171,7 +171,7 @@ typedef struct
// be closed. When that happens, the value gets copied off the stack into the
// upvalue itself. That way, it can have a longer lifetime than the stack
// variable.
typedef struct sUpvalue
struct sObjUpvalue
{
// The object header. Note that upvalues have this because they are garbage
// collected, but they are not first class Wren objects.
@ -187,8 +187,8 @@ typedef struct sUpvalue
// Open upvalues are stored in a linked list by the fiber. This points to the
// next upvalue in that list.
struct sUpvalue* next;
} ObjUpvalue;
struct sObjUpvalue* next;
};
// The type of a primitive function.
//
@ -217,7 +217,7 @@ typedef struct
//
// While this is an Obj and is managed by the GC, it never appears as a
// first-class object in Wren.
typedef struct
struct sObjModule
{
Obj obj;
@ -230,7 +230,7 @@ typedef struct
// The name of the module.
ObjString* name;
} ObjModule;
};
// A function object. It wraps and owns the bytecode and other debug information
// for a callable chunk of code.
@ -240,7 +240,7 @@ typedef struct
// representation of a function. This isn't strictly necessary if they function
// has no upvalues, but lets the rest of the VM assume all called objects will
// be closures.
typedef struct
struct sObjFn
{
Obj obj;
@ -261,11 +261,11 @@ typedef struct
// only be set for fns, and not ObjFns that represent methods or scripts.
int arity;
FnDebug* debug;
} ObjFn;
};
// An instance of a first-class function and the environment it has closed over.
// Unlike [ObjFn], this has captured the upvalues that the function accesses.
typedef struct
struct sObjClosure
{
Obj obj;
@ -274,7 +274,7 @@ typedef struct
// The upvalues this function has closed over.
ObjUpvalue* upvalues[FLEXIBLE_ARRAY];
} ObjClosure;
};
typedef struct
{
@ -291,7 +291,7 @@ typedef struct
Value* stackStart;
} CallFrame;
typedef struct sObjFiber
struct sObjFiber
{
Obj obj;
@ -333,7 +333,7 @@ typedef struct sObjFiber
// In that case, if this fiber fails with an error, the error will be given
// to the caller.
bool callerIsTrying;
} ObjFiber;
};
typedef enum
{
@ -395,25 +395,25 @@ struct sObjClass
ObjString* name;
};
typedef struct
struct sObjForeign
{
Obj obj;
uint8_t data[FLEXIBLE_ARRAY];
} ObjForeign;
};
typedef struct
struct sObjInstance
{
Obj obj;
Value fields[FLEXIBLE_ARRAY];
} ObjInstance;
};
typedef struct
struct sObjList
{
Obj obj;
// The elements in the list.
ValueBuffer elements;
} ObjList;
};
typedef struct
{
@ -443,7 +443,7 @@ typedef struct
// for a key, we will continue past tombstones, because the desired key may be
// found after them if the key that was removed was part of a prior collision.
// When the array gets resized, all tombstones are discarded.
typedef struct
struct sObjMap
{
Obj obj;
@ -455,9 +455,9 @@ typedef struct
// Pointer to a contiguous array of [capacity] entries.
MapEntry* entries;
} ObjMap;
};
typedef struct
struct sObjRange
{
Obj obj;
@ -469,7 +469,7 @@ typedef struct
// True if [to] is included in the range.
bool isInclusive;
} ObjRange;
};
// An IEEE 754 double-precision float is a 64-bit value with bits laid out like:
//
@ -782,6 +782,22 @@ static inline bool wrenValuesSame(Value a, Value b)
// other values are equal if they are identical objects.
bool wrenValuesEqual(Value a, Value b);
// Returns true is [a] and [str] represent the same string.
static inline bool wrenStringEqualStrLength(const ObjString* a,
const char* str, size_t length)
{
return a->length == length &&
memcmp(a->value, str, length) == 0;
}
// Returns true is [a] and [b] represent the same string.
static inline bool wrenStringsEqual(const ObjString* a, const ObjString* b)
{
return a == b ||
(a->hash == b->hash &&
wrenStringEqualStrLength(a, b->value, b->length));
}
// Returns true if [value] is a bool. Do not call this directly, instead use
// [IS_BOOL].
static inline bool wrenIsBool(Value value)

View File

@ -150,6 +150,9 @@ void wrenCollectGarbage(WrenVM* vm)
// Any object the compiler is using (if there is one).
if (vm->compiler != NULL) wrenMarkCompiler(vm, vm->compiler);
// Method names.
wrenBlackenSymbolTable(vm, &vm->methodNames);
// Now that we have grayed the roots, do a depth-first search over all of the
// reachable objects.
wrenBlackenObjects(vm);
@ -420,7 +423,7 @@ static void runtimeError(WrenVM* vm)
static void methodNotFound(WrenVM* vm, ObjClass* classObj, int symbol)
{
vm->fiber->error = wrenStringFormat(vm, "@ does not implement '$'.",
OBJ_VAL(classObj->name), vm->methodNames.data[symbol].buffer);
OBJ_VAL(classObj->name), vm->methodNames.data[symbol]->value);
}
// Checks that [value], which must be a closure, does not require more
@ -492,8 +495,8 @@ static ObjClosure* compileInModule(WrenVM* vm, Value name, const char* source,
for (int i = 0; i < coreModule->variables.count; i++)
{
wrenDefineVariable(vm, module,
coreModule->variableNames.data[i].buffer,
coreModule->variableNames.data[i].length,
coreModule->variableNames.data[i]->value,
coreModule->variableNames.data[i]->length,
coreModule->variables.data[i]);
}
}