Fixes; Builtins; Testing in the interpreter

This commit is contained in:
dcodeIO
2017-12-03 23:04:33 +01:00
parent 032ae379cd
commit 017efc71b6
33 changed files with 791 additions and 68 deletions

View File

@ -1,6 +1,6 @@
import { PATH_DELIMITER } from "./constants";
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
import { Module, MemorySegment, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType, FunctionTypeRef } from "./module";
import { Module, MemorySegment, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType, FunctionTypeRef, getExpressionId, ExpressionId } from "./module";
import { Program, ClassPrototype, Class, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter } from "./program";
import { CharCode, I64, U64, normalizePath, sb } from "./util";
import { Token, Range } from "./tokenizer";
@ -286,11 +286,13 @@ export class Compiler extends DiagnosticEmitter {
// globals
compileGlobalDeclaration(declaration: VariableDeclaration, isConst: bool): bool {
compileGlobalDeclaration(declaration: VariableDeclaration, isConst: bool): Global | null {
const element: Element | null = <Element | null>this.program.elements.get(declaration.internalName);
if (!element || element.kind != ElementKind.GLOBAL)
throw new Error("unexpected missing global");
return this.compileGlobal(<Global>element);
return this.compileGlobal(<Global>element)
? <Global>element
: null;
}
compileGlobal(element: Global): bool {
@ -333,7 +335,7 @@ export class Compiler extends DiagnosticEmitter {
} else if (declaration) {
if (declaration.initializer) {
initializer = this.compileExpression(declaration.initializer, type);
initializeInStart = declaration.initializer.kind != NodeKind.LITERAL; // MVP doesn't support complex initializers
initializeInStart = getExpressionId(initializer) != ExpressionId.Const; // MVP doesn't support complex initializers
} else {
initializer = typeToNativeZero(this.module, type);
initializeInStart = false;
@ -342,12 +344,14 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("unexpected missing declaration or constant value");
const internalName: string = element.internalName;
if (initializeInStart) {
this.module.addGlobal(internalName, nativeType, true, this.module.createI32(-1));
this.module.addGlobal(internalName, nativeType, true, typeToNativeZero(this.module, type));
this.startFunctionBody.push(this.module.createSetGlobal(internalName, initializer));
} else
} else {
this.module.addGlobal(internalName, nativeType, element.isMutable, initializer);
// if (element.globalExportName != null && element.hasConstantValue && !initializeInStart)
// this.module.addGlobalExport(element.internalName, element.globalExportName);
if (!element.isMutable) {
// TODO: check export, requires updated binaryen.js with Module#addGlobalExport
}
}
return element.isCompiled = true;
}
@ -373,7 +377,7 @@ export class Compiler extends DiagnosticEmitter {
let initializeInStart: bool = false;
if (declaration.value) {
initializer = this.compileExpression(<Expression>declaration.value, Type.i32);
initializeInStart = declaration.value.kind != NodeKind.LITERAL; // MVP doesn't support complex initializers
initializeInStart = getExpressionId(initializer) != ExpressionId.Const; // MVP doesn't support complex initializers
} else if (previousInternalName == null) {
initializer = this.module.createI32(0);
initializeInStart = false;
@ -385,10 +389,12 @@ export class Compiler extends DiagnosticEmitter {
initializeInStart = true;
}
if (initializeInStart) {
this.module.addGlobal(val.internalName, NativeType.I32, true, this.module.createI32(-1));
this.module.addGlobal(val.internalName, NativeType.I32, true, this.module.createI32(0));
this.startFunctionBody.push(this.module.createSetGlobal(val.internalName, initializer));
} else
} else {
this.module.addGlobal(val.internalName, NativeType.I32, false, initializer);
// TODO: check export, requires updated binaryen.js with Module#addGlobalExport
}
} else
throw new Error("unexpected missing declaration or constant value");
previousInternalName = val.internalName;
@ -1183,6 +1189,20 @@ export class Compiler extends DiagnosticEmitter {
this.currentType = Type.bool;
break;
case Token.EXCLAMATION_EQUALS:
case Token.EXCLAMATION_EQUALS_EQUALS:
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.NeF32
: this.currentType == Type.f64
? BinaryOp.NeF64
: this.currentType.isLongInteger
? BinaryOp.NeI64
: BinaryOp.NeI32;
this.currentType = Type.bool;
break;
case Token.EQUALS:
return this.compileAssignment(expression.left, expression.right, contextualType);
@ -1544,7 +1564,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createHost(HostOp.CurrentMemory);
case "grow_memory":
this.warning(DiagnosticCode.Operation_is_unsafe, reportNode.range); // unsure
// this.warning(DiagnosticCode.Operation_is_unsafe, reportNode.range); // unsure
return this.module.createHost(HostOp.GrowMemory, null, operands);
case "unreachable":
@ -1566,7 +1586,7 @@ export class Compiler extends DiagnosticEmitter {
tempLocal = this.currentFunction.addLocal(Type.f32);
return this.module.createBinary(BinaryOp.NeF32,
this.module.createTeeLocal(tempLocal.index, operands[0]),
this.module.createGetLocal(tempLocal.index, NativeType.F64)
this.module.createGetLocal(tempLocal.index, NativeType.F32)
);
}
break;
@ -1604,6 +1624,12 @@ export class Compiler extends DiagnosticEmitter {
);
}
break;
case "assert":
return this.module.createIf(
this.module.createUnary(UnaryOp.EqzI32, operands[0]),
this.module.createUnreachable()
);
}
this.error(DiagnosticCode.Operation_not_supported, reportNode.range);
return this.module.createUnreachable();

View File

@ -1,5 +1,5 @@
import { Range } from "./ast";
import { isLineBreak, sb } from "./util";
import { CharCode, isLineBreak, sb } from "./util";
import { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated";
export { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated";
@ -100,9 +100,9 @@ export function formatDiagnosticMessage(message: DiagnosticMessage, useColors: b
sb.push("\n");
let pos: i32 = range.start;
let line: i32 = 1;
let column: i32 = 0;
let column: i32 = 1;
while (pos-- > 0)
if (isLineBreak(text.charCodeAt(pos)))
if (text.charCodeAt(pos) == CharCode.LINEFEED)
line++;
else if (line == 1)
column++;

View File

@ -613,6 +613,10 @@ export class Module {
return _BinaryenModuleValidate(this.ref) == 1;
}
interpret(): void {
return _BinaryenModuleInterpret(this.ref);
}
toBinary(): Uint8Array {
throw new Error("not implemented");
}
@ -726,6 +730,10 @@ export class Relooper {
}
}
// export function setAPITracing(on: bool): void {
// _BinaryenSetAPITracing(on ? 1 : 0);
// }
// helpers
// can't do stack allocation here: STACKTOP is a global in WASM but a hidden variable in asm.js

View File

@ -1131,6 +1131,7 @@ function initializeBuiltins(program: Program): void {
const genericInt: Type[] = [ Type.i32, Type.i64 ];
const genericFloat: Type[] = [ Type.f32, Type.f64 ];
const usize: Type = program.target == Target.WASM64 ? Type.usize64 : Type.usize32;
addGenericUnaryBuiltin(program, "clz", genericInt);
addGenericUnaryBuiltin(program, "ctz", genericInt);
@ -1140,7 +1141,7 @@ function initializeBuiltins(program: Program): void {
addGenericUnaryBuiltin(program, "abs", genericFloat);
addGenericUnaryBuiltin(program, "ceil", genericFloat);
addGenericUnaryBuiltin(program, "copysign", genericFloat);
addGenericBinaryBuiltin(program, "copysign", genericFloat);
addGenericUnaryBuiltin(program, "floor", genericFloat);
addGenericBinaryBuiltin(program, "max", genericFloat);
addGenericBinaryBuiltin(program, "min", genericFloat);
@ -1148,12 +1149,13 @@ function initializeBuiltins(program: Program): void {
addGenericUnaryBuiltin(program, "sqrt", genericFloat);
addGenericUnaryBuiltin(program, "trunc", genericFloat);
addBuiltin(program, "current_memory", [], Type.i32);
addBuiltin(program, "grow_memory", [ Type.i32 ], Type.i32);
addBuiltin(program, "current_memory", [], usize);
addBuiltin(program, "grow_memory", [ usize ], usize);
addBuiltin(program, "unreachable", [], Type.void);
addGenericUnaryTestBuiltin(program, "isNaN", genericFloat);
addGenericUnaryTestBuiltin(program, "isFinite", genericFloat);
addBuiltin(program, "assert", [ Type.bool ], Type.void);
// TODO: load, store, sizeof
// sizeof, for example, has varying Ts but really shouldn't provide an instance for each class
@ -1167,7 +1169,8 @@ function addBuiltin(program: Program, name: string, parameterTypes: Type[], retu
const parameters: Parameter[] = new Array(k);
for (let i: i32 = 0; i < k; ++i)
parameters[i] = new Parameter("arg" + i, parameterTypes[i], null);
prototype.instances.set("", new Function(prototype, name, [], parameters, Type.bool, null));
prototype.instances.set("", new Function(prototype, name, [], parameters, returnType, null));
program.elements.set(name, prototype);
}
function addGenericUnaryBuiltin(program: Program, name: string, types: Type[]): void {