mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 06:08:41 +01:00
Use a map to check for constant collisions.
Doing an O(n) lookup was too slow.
This commit is contained in:
@ -352,6 +352,8 @@ struct sCompiler
|
||||
|
||||
// The function being compiled.
|
||||
ObjFn* fn;
|
||||
|
||||
ObjMap* constants;
|
||||
};
|
||||
|
||||
// Describes where a variable is declared.
|
||||
@ -466,13 +468,10 @@ static int addConstant(Compiler* compiler, Value constant)
|
||||
if (compiler->parser->hasError) return -1;
|
||||
|
||||
// See if we already have a constant for the value. If so, reuse it.
|
||||
// TODO: This is O(n). Do something better?
|
||||
for (int i = 0; i < compiler->fn->constants.count; i++)
|
||||
if (compiler->constants != NULL)
|
||||
{
|
||||
if (wrenValuesEqual(constant, compiler->fn->constants.data[i]))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
Value existing = wrenMapGet(compiler->constants, constant);
|
||||
if (IS_NUM(existing)) return (int)AS_NUM(existing);
|
||||
}
|
||||
|
||||
// It's a new constant.
|
||||
@ -482,6 +481,13 @@ static int addConstant(Compiler* compiler, Value constant)
|
||||
wrenValueBufferWrite(compiler->parser->vm, &compiler->fn->constants,
|
||||
constant);
|
||||
if (IS_OBJ(constant)) wrenPopRoot(compiler->parser->vm);
|
||||
|
||||
if (compiler->constants == NULL)
|
||||
{
|
||||
compiler->constants = wrenNewMap(compiler->parser->vm);
|
||||
}
|
||||
wrenMapSet(compiler->parser->vm, compiler->constants, constant,
|
||||
NUM_VAL(compiler->fn->constants.count - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -501,9 +507,10 @@ static void initCompiler(Compiler* compiler, Parser* parser, Compiler* parent,
|
||||
compiler->loop = NULL;
|
||||
compiler->enclosingClass = NULL;
|
||||
|
||||
// Initialize this to NULL before allocating in case a GC gets triggered in
|
||||
// Initialize these to NULL before allocating in case a GC gets triggered in
|
||||
// the middle of initializing the compiler.
|
||||
compiler->fn = NULL;
|
||||
compiler->constants = NULL;
|
||||
|
||||
parser->vm->compiler = compiler;
|
||||
|
||||
@ -3551,6 +3558,7 @@ void wrenMarkCompiler(WrenVM* vm, Compiler* compiler)
|
||||
do
|
||||
{
|
||||
wrenGrayObj(vm, (Obj*)compiler->fn);
|
||||
wrenGrayObj(vm, (Obj*)compiler->constants);
|
||||
compiler = compiler->parent;
|
||||
}
|
||||
while (compiler != NULL);
|
||||
|
||||
@ -387,6 +387,16 @@ static uint32_t hashObject(Obj* object)
|
||||
case OBJ_CLASS:
|
||||
// Classes just use their name.
|
||||
return hashObject((Obj*)((ObjClass*)object)->name);
|
||||
|
||||
// Allow bare (non-closure) functions so that we can use a map to find
|
||||
// existing constants in a function's constant table. This is only used
|
||||
// internally. Since user code never sees a non-closure function, they
|
||||
// cannot use them as map keys.
|
||||
case OBJ_FN:
|
||||
{
|
||||
ObjFn* fn = (ObjFn*)object;
|
||||
return hashNumber(fn->arity) ^ hashNumber(fn->code.count);
|
||||
}
|
||||
|
||||
case OBJ_RANGE:
|
||||
{
|
||||
|
||||
65550
test/limit/reuse_constants.wren
Normal file
65550
test/limit/reuse_constants.wren
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user