Control flow evaluator; Support for block-level let/const variables

This commit is contained in:
dcodeIO 2018-01-18 23:34:12 +01:00
parent 1c4b0ddc57
commit 7be4f9fabb
54 changed files with 3285 additions and 13138 deletions

View File

@ -541,7 +541,7 @@ function fls<T>(word: T): i32 {
return (<i32>sizeof<T>() << 3) - 1 - <i32>clz(word); return (<i32>sizeof<T>() << 3) - 1 - <i32>clz(word);
} }
var fl_out: i32, sl_out: i32; let fl_out: i32, sl_out: i32;
function mapping_insert(size: usize): void { function mapping_insert(size: usize): void {
var fl: i32, sl: i32; var fl: i32, sl: i32;
@ -585,7 +585,7 @@ function find_suitable_block(control: Control, fl: i32, sl: i32): BlockHeader {
// Exported interface // Exported interface
var TLSF: Control; let TLSF: Control;
/** Requests more memory from the host environment. */ /** Requests more memory from the host environment. */
function request_memory(size: usize): void { function request_memory(size: usize): void {
@ -711,8 +711,8 @@ function check(): i32 {
return status; return status;
} }
var integrity_prev_status: i32; let integrity_prev_status: i32,
var integrity_status: i32; integrity_status: i32;
function integrity_walker(ptr: usize, size: usize, used: bool): void { function integrity_walker(ptr: usize, size: usize, used: bool): void {
var block = BlockHeader.fromDataPtr(ptr); var block = BlockHeader.fromDataPtr(ptr);

View File

@ -980,6 +980,7 @@ export class UnaryPrefixExpression extends UnaryExpression {
export enum ModifierKind { export enum ModifierKind {
ASYNC, ASYNC,
CONST, CONST,
LET,
DECLARE, DECLARE,
EXPORT, EXPORT,
IMPORT, IMPORT,

View File

@ -36,7 +36,8 @@ import {
Program, Program,
Global, Global,
FunctionPrototype, FunctionPrototype,
Local Local,
ElementFlags
} from "./program"; } from "./program";
/** Initializes the specified program with built-in constants and functions. */ /** Initializes the specified program with built-in constants and functions. */
@ -152,8 +153,8 @@ export function initialize(program: Program): void {
/** Adds a built-in constant to the specified program. */ /** Adds a built-in constant to the specified program. */
function addConstant(program: Program, name: string, type: Type): Global { function addConstant(program: Program, name: string, type: Type): Global {
var global = new Global(program, name, name, null, type); var global = new Global(program, name, name, null, type);
global.isBuiltIn = true; global.set(ElementFlags.BUILTIN);
global.isConstant = true; global.set(ElementFlags.CONSTANT);
program.elements.set(name, global); program.elements.set(name, global);
return global; return global;
} }
@ -161,9 +162,9 @@ function addConstant(program: Program, name: string, type: Type): Global {
/** Adds a built-in function to the specified program. */ /** Adds a built-in function to the specified program. */
function addFunction(program: Program, name: string, isGeneric: bool = false): FunctionPrototype { function addFunction(program: Program, name: string, isGeneric: bool = false): FunctionPrototype {
var prototype = new FunctionPrototype(program, name, name, null, null); var prototype = new FunctionPrototype(program, name, name, null, null);
prototype.isBuiltIn = true; prototype.set(ElementFlags.BUILTIN);
if (isGeneric) if (isGeneric)
prototype.isGeneric = true; prototype.set(ElementFlags.GENERIC);
program.elements.set(name, prototype); program.elements.set(name, prototype);
return prototype; return prototype;
} }

View File

@ -42,7 +42,10 @@ import {
Parameter, Parameter,
EnumValue, EnumValue,
Property, Property,
VariableLikeElement VariableLikeElement,
Flow,
FlowFlags,
ElementFlags
} from "./program"; } from "./program";
import { import {
@ -112,6 +115,7 @@ import {
Type, Type,
TypeKind, TypeKind,
TypeFlags, TypeFlags,
typesToNativeTypes typesToNativeTypes
} from "./types"; } from "./types";
@ -166,17 +170,13 @@ export class Compiler extends DiagnosticEmitter {
/** Start function being compiled. */ /** Start function being compiled. */
startFunction: Function; startFunction: Function;
/** Start function expressions. */ /** Start function statements. */
startFunctionBody: ExpressionRef[] = new Array(); startFunctionBody: ExpressionRef[] = new Array();
/** Current type in compilation. */
currentType: Type = Type.void;
/** Current function in compilation. */ /** Current function in compilation. */
currentFunction: Function; currentFunction: Function;
/** Marker indicating whether continue statements are allowed in the current break context. */ /** Current type in compilation. */
disallowContinue: bool = true; currentType: Type = Type.void;
/** Marker indicating that a new variable, if present, is always a local. Used to distinguish locals from globals in the start function. */
variableIsLocal: bool = false;
/** Counting memory offset. */ /** Counting memory offset. */
memoryOffset: U64 = new U64(8, 0); // leave space for (any size of) NULL memoryOffset: U64 = new U64(8, 0); // leave space for (any size of) NULL
@ -203,7 +203,7 @@ export class Compiler extends DiagnosticEmitter {
var startFunctionTemplate = new FunctionPrototype(program, "start", "start", null); var startFunctionTemplate = new FunctionPrototype(program, "start", "start", null);
var startFunctionInstance = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null); var startFunctionInstance = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null);
this.currentFunction = this.startFunction = startFunctionInstance; this.currentFunction = this.startFunction = startFunctionInstance;
} }
/** Performs compilation of the underlying {@link Program} to a {@link Module}. */ /** Performs compilation of the underlying {@link Program} to a {@link Module}. */
compile(): Module { compile(): Module {
@ -297,8 +297,10 @@ export class Compiler extends DiagnosticEmitter {
this.compileNamespaceDeclaration(<NamespaceDeclaration>statement); this.compileNamespaceDeclaration(<NamespaceDeclaration>statement);
break; break;
case NodeKind.VARIABLE: // global case NodeKind.VARIABLE: // global, always compiled because initializers might have side effects
this.compileVariableStatement(<VariableStatement>statement); // always because initializers might have side effects var variableInit = this.compileVariableStatement(<VariableStatement>statement);
if (variableInit)
this.startFunctionBody.push(variableInit);
break; break;
case NodeKind.EXPORT: case NodeKind.EXPORT:
@ -322,7 +324,7 @@ export class Compiler extends DiagnosticEmitter {
// globals // globals
compileGlobalDeclaration(declaration: VariableDeclaration, isConst: bool): Global | null { compileGlobalDeclaration(declaration: VariableDeclaration): Global | null {
var element = this.program.elements.get(declaration.fileLevelInternalName); var element = this.program.elements.get(declaration.fileLevelInternalName);
if (!element || element.kind != ElementKind.GLOBAL) if (!element || element.kind != ElementKind.GLOBAL)
throw new Error("global expected"); throw new Error("global expected");
@ -332,7 +334,7 @@ export class Compiler extends DiagnosticEmitter {
} }
compileGlobal(global: Global): bool { compileGlobal(global: Global): bool {
if (global.isCompiled || global.isBuiltIn) if (global.is(ElementFlags.COMPILED) || global.is(ElementFlags.BUILTIN))
return true; return true;
var declaration = global.declaration; var declaration = global.declaration;
@ -366,10 +368,10 @@ export class Compiler extends DiagnosticEmitter {
var nativeType = global.type.toNativeType(); var nativeType = global.type.toNativeType();
if (global.isDeclared) { if (global.is(ElementFlags.DECLARED)) {
if (global.isConstant) { if (global.is(ElementFlags.CONSTANT)) {
this.module.addGlobalImport(global.internalName, global.namespace ? global.namespace.simpleName : "env", global.simpleName, nativeType); this.module.addGlobalImport(global.internalName, global.namespace ? global.namespace.simpleName : "env", global.simpleName, nativeType);
global.isCompiled = true; global.set(ElementFlags.COMPILED);
return true; return true;
} else if (declaration) { } else if (declaration) {
this.error(DiagnosticCode.Operation_not_supported, declaration.range); this.error(DiagnosticCode.Operation_not_supported, declaration.range);
@ -379,14 +381,14 @@ export class Compiler extends DiagnosticEmitter {
var initializeInStart = false; var initializeInStart = false;
if (global.hasConstantValue) { if (global.is(ElementFlags.INLINED)) {
initExpr = makeInlineConstant(global, this.module); initExpr = makeInlineConstant(global, this.module);
} else if (declaration) { } else if (declaration) {
if (declaration.initializer) { if (declaration.initializer) {
if (!initExpr) if (!initExpr)
initExpr = this.compileExpression(declaration.initializer, global.type); initExpr = this.compileExpression(declaration.initializer, global.type);
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
if (!global.isMutable) { if (global.is(ElementFlags.CONSTANT)) {
initExpr = this.precomputeExpressionRef(initExpr); initExpr = this.precomputeExpressionRef(initExpr);
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, declaration.range); this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, declaration.range);
@ -406,7 +408,7 @@ export class Compiler extends DiagnosticEmitter {
var setExpr = this.module.createSetGlobal(internalName, initExpr); var setExpr = this.module.createSetGlobal(internalName, initExpr);
this.startFunctionBody.push(setExpr); this.startFunctionBody.push(setExpr);
} else { } else {
if (!global.isMutable) { if (global.is(ElementFlags.CONSTANT)) {
var exprType = _BinaryenExpressionGetType(initExpr); var exprType = _BinaryenExpressionGetType(initExpr);
switch (exprType) { switch (exprType) {
@ -429,16 +431,16 @@ export class Compiler extends DiagnosticEmitter {
default: default:
throw new Error("concrete type expected"); throw new Error("concrete type expected");
} }
global.hasConstantValue = true; global.set(ElementFlags.INLINED);
if (!declaration || declaration.isTopLevel) { // might be re-exported if (!declaration || declaration.isTopLevel) { // might be re-exported
this.module.addGlobal(internalName, nativeType, global.isMutable, initExpr); this.module.addGlobal(internalName, nativeType, !global.is(ElementFlags.CONSTANT), initExpr);
} }
if (declaration && declaration.range.source.isEntry && declaration.isTopLevelExport) if (declaration && declaration.range.source.isEntry && declaration.isTopLevelExport)
this.module.addGlobalExport(global.internalName, declaration.programLevelInternalName); this.module.addGlobalExport(global.internalName, declaration.programLevelInternalName);
} else } else
this.module.addGlobal(internalName, nativeType, global.isMutable, initExpr); this.module.addGlobal(internalName, nativeType, !global.is(ElementFlags.CONSTANT), initExpr);
} }
global.isCompiled = true; global.set(ElementFlags.COMPILED);
return true; return true;
} }
@ -452,10 +454,12 @@ export class Compiler extends DiagnosticEmitter {
} }
compileEnum(element: Enum): bool { compileEnum(element: Enum): bool {
if (element.isCompiled) if (element.is(ElementFlags.COMPILED))
return true; return true;
element.isCompiled = true; // members might reference each other, triggering another compile // members might reference each other, triggering another compile
element.set(ElementFlags.COMPILED);
var previousValue: EnumValue | null = null; var previousValue: EnumValue | null = null;
if (element.members) if (element.members)
for (var member of element.members.values()) { for (var member of element.members.values()) {
@ -464,7 +468,7 @@ export class Compiler extends DiagnosticEmitter {
var initInStart = false; var initInStart = false;
var val = <EnumValue>member; var val = <EnumValue>member;
var valueDeclaration = val.declaration; var valueDeclaration = val.declaration;
if (val.hasConstantValue) { if (val.is(ElementFlags.INLINED)) {
if (!element.declaration || element.declaration.isTopLevelExport) if (!element.declaration || element.declaration.isTopLevelExport)
this.module.addGlobal(val.internalName, NativeType.I32, false, this.module.createI32(val.constantValue)); this.module.addGlobal(val.internalName, NativeType.I32, false, this.module.createI32(val.constantValue));
} else if (valueDeclaration) { } else if (valueDeclaration) {
@ -474,14 +478,14 @@ export class Compiler extends DiagnosticEmitter {
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
initExpr = this.precomputeExpressionRef(initExpr); initExpr = this.precomputeExpressionRef(initExpr);
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
if (element.isConstant) if (element.is(ElementFlags.CONSTANT))
this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, valueDeclaration.range); this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, valueDeclaration.range);
initInStart = true; initInStart = true;
} }
} }
} else if (previousValue == null) { } else if (previousValue == null) {
initExpr = this.module.createI32(0); initExpr = this.module.createI32(0);
} else if (previousValue.hasConstantValue) { } else if (previousValue.is(ElementFlags.INLINED)) {
initExpr = this.module.createI32(previousValue.constantValue + 1); initExpr = this.module.createI32(previousValue.constantValue + 1);
} else { } else {
// in TypeScript this errors with TS1061, but actually we can do: // in TypeScript this errors with TS1061, but actually we can do:
@ -489,7 +493,7 @@ export class Compiler extends DiagnosticEmitter {
this.module.createGetGlobal(previousValue.internalName, NativeType.I32), this.module.createGetGlobal(previousValue.internalName, NativeType.I32),
this.module.createI32(1) this.module.createI32(1)
); );
if (element.isConstant) if (element.is(ElementFlags.CONSTANT))
this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, valueDeclaration.range); this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, valueDeclaration.range);
initInStart = true; initInStart = true;
} }
@ -501,7 +505,7 @@ export class Compiler extends DiagnosticEmitter {
this.module.addGlobal(val.internalName, NativeType.I32, false, initExpr); this.module.addGlobal(val.internalName, NativeType.I32, false, initExpr);
if (_BinaryenExpressionGetType(initExpr) == NativeType.I32) { if (_BinaryenExpressionGetType(initExpr) == NativeType.I32) {
val.constantValue = _BinaryenConstGetValueI32(initExpr); val.constantValue = _BinaryenConstGetValueI32(initExpr);
val.hasConstantValue = true; val.set(ElementFlags.INLINED);
} else } else
throw new Error("i32 expected"); throw new Error("i32 expected");
} }
@ -511,7 +515,7 @@ export class Compiler extends DiagnosticEmitter {
// export values if the enum is exported // export values if the enum is exported
if (element.declaration && element.declaration.range.source.isEntry && element.declaration.isTopLevelExport) { if (element.declaration && element.declaration.range.source.isEntry && element.declaration.isTopLevelExport) {
if (member.hasConstantValue) if (member.is(ElementFlags.INLINED))
this.module.addGlobalExport(member.internalName, member.internalName); this.module.addGlobalExport(member.internalName, member.internalName);
else if (valueDeclaration) else if (valueDeclaration)
this.warning(DiagnosticCode.Cannot_export_a_mutable_global, valueDeclaration.range); this.warning(DiagnosticCode.Cannot_export_a_mutable_global, valueDeclaration.range);
@ -537,14 +541,14 @@ export class Compiler extends DiagnosticEmitter {
} }
compileFunction(instance: Function): bool { compileFunction(instance: Function): bool {
if (instance.isCompiled) if (instance.is(ElementFlags.COMPILED))
return true; return true;
var declaration = instance.prototype.declaration; var declaration = instance.prototype.declaration;
if (!declaration) if (!declaration)
throw new Error("declaration expected"); // built-ins are not compiled here throw new Error("declaration expected"); // built-ins are not compiled here
if (instance.isDeclared) { if (instance.is(ElementFlags.DECLARED)) {
if (declaration.statements) { if (declaration.statements) {
this.error(DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts, declaration.name.range); this.error(DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts, declaration.name.range);
return false; return false;
@ -555,11 +559,13 @@ export class Compiler extends DiagnosticEmitter {
return false; return false;
} }
} }
instance.isCompiled = true;
// might trigger compilation of other functions referring to this one
instance.set(ElementFlags.COMPILED);
// compile statements // compile statements
var stmts: ExpressionRef[] | null = null; var stmts: ExpressionRef[] | null = null;
if (!instance.isDeclared) { if (!instance.is(ElementFlags.DECLARED)) {
var previousFunction = this.currentFunction; var previousFunction = this.currentFunction;
this.currentFunction = instance; this.currentFunction = instance;
stmts = this.compileStatements(<Statement[]>declaration.statements); stmts = this.compileStatements(<Statement[]>declaration.statements);
@ -589,7 +595,7 @@ export class Compiler extends DiagnosticEmitter {
typeRef = this.module.addFunctionType(signatureNameParts.join(""), nativeResultType, nativeParamTypes); typeRef = this.module.addFunctionType(signatureNameParts.join(""), nativeResultType, nativeParamTypes);
// create the function // create the function
if (instance.isDeclared) { if (instance.is(ElementFlags.DECLARED)) {
this.module.addFunctionImport(instance.internalName, instance.prototype.namespace ? instance.prototype.namespace.simpleName : "env", declaration.name.name, typeRef); this.module.addFunctionImport(instance.internalName, instance.prototype.namespace ? instance.prototype.namespace.simpleName : "env", declaration.name.name, typeRef);
} else { } else {
this.module.addFunction(instance.internalName, typeRef, typesToNativeTypes(instance.additionalLocals), this.module.createBlock(null, <ExpressionRef[]>stmts, NativeType.None)); this.module.addFunction(instance.internalName, typeRef, typesToNativeTypes(instance.additionalLocals), this.module.createBlock(null, <ExpressionRef[]>stmts, NativeType.None));
@ -636,8 +642,11 @@ export class Compiler extends DiagnosticEmitter {
break; break;
case NodeKind.VARIABLE: case NodeKind.VARIABLE:
if (noTreeShaking || hasModifier(ModifierKind.EXPORT, (<VariableStatement>member).modifiers)) if (noTreeShaking || hasModifier(ModifierKind.EXPORT, (<VariableStatement>member).modifiers)) {
this.compileVariableStatement(<VariableStatement>member); var variableInit = this.compileVariableStatement(<VariableStatement>member, true);
if (variableInit)
this.startFunctionBody.push(variableInit);
}
break; break;
default: default:
@ -655,7 +664,7 @@ export class Compiler extends DiagnosticEmitter {
switch (element.kind) { switch (element.kind) {
case ElementKind.CLASS_PROTOTYPE: case ElementKind.CLASS_PROTOTYPE:
if ((noTreeShaking || (<ClassPrototype>element).isExported) && !(<ClassPrototype>element).isGeneric) if ((noTreeShaking || (<ClassPrototype>element).is(ElementFlags.EXPORTED)) && !(<ClassPrototype>element).is(ElementFlags.GENERIC))
this.compileClassUsingTypeArguments(<ClassPrototype>element, []); this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
break; break;
@ -664,7 +673,7 @@ export class Compiler extends DiagnosticEmitter {
break; break;
case ElementKind.FUNCTION_PROTOTYPE: case ElementKind.FUNCTION_PROTOTYPE:
if ((noTreeShaking || (<FunctionPrototype>element).isExported) && !(<FunctionPrototype>element).isGeneric) if ((noTreeShaking || (<FunctionPrototype>element).is(ElementFlags.EXPORTED)) && !(<FunctionPrototype>element).is(ElementFlags.GENERIC))
this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []); this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []);
break; break;
@ -692,7 +701,7 @@ export class Compiler extends DiagnosticEmitter {
switch (element.kind) { switch (element.kind) {
case ElementKind.CLASS_PROTOTYPE: case ElementKind.CLASS_PROTOTYPE:
if (!(<ClassPrototype>element).isGeneric) if (!(<ClassPrototype>element).is(ElementFlags.GENERIC))
this.compileClassUsingTypeArguments(<ClassPrototype>element, []); this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
break; break;
@ -701,7 +710,7 @@ export class Compiler extends DiagnosticEmitter {
break; break;
case ElementKind.FUNCTION_PROTOTYPE: case ElementKind.FUNCTION_PROTOTYPE:
if (!(<FunctionPrototype>element).isGeneric && statement.range.source.isEntry) { if (!(<FunctionPrototype>element).is(ElementFlags.GENERIC) && statement.range.source.isEntry) {
var functionInstance = this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []); var functionInstance = this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []);
if (functionInstance) { if (functionInstance) {
var functionDeclaration = functionInstance.prototype.declaration; var functionDeclaration = functionInstance.prototype.declaration;
@ -715,7 +724,7 @@ export class Compiler extends DiagnosticEmitter {
if (this.compileGlobal(<Global>element) && statement.range.source.isEntry) { if (this.compileGlobal(<Global>element) && statement.range.source.isEntry) {
var globalDeclaration = (<Global>element).declaration; var globalDeclaration = (<Global>element).declaration;
if (globalDeclaration && globalDeclaration.needsExplicitExport(member)) { if (globalDeclaration && globalDeclaration.needsExplicitExport(member)) {
if ((<Global>element).hasConstantValue) if ((<Global>element).is(ElementFlags.INLINED))
this.module.addGlobalExport(element.internalName, member.externalIdentifier.name); this.module.addGlobalExport(element.internalName, member.externalIdentifier.name);
else else
this.warning(DiagnosticCode.Cannot_export_a_mutable_global, member.range); this.warning(DiagnosticCode.Cannot_export_a_mutable_global, member.range);
@ -747,10 +756,10 @@ export class Compiler extends DiagnosticEmitter {
} }
compileClass(instance: Class): bool { compileClass(instance: Class): bool {
if (instance.isCompiled) if (instance.is(ElementFlags.COMPILED))
return true; return true;
instance.set(ElementFlags.COMPILED);
return instance.isCompiled = true; return true;
} }
compileInterfaceDeclaration(declaration: InterfaceDeclaration, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void { compileInterfaceDeclaration(declaration: InterfaceDeclaration, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void {
@ -813,7 +822,8 @@ export class Compiler extends DiagnosticEmitter {
return this.compileTryStatement(<TryStatement>statement); return this.compileTryStatement(<TryStatement>statement);
case NodeKind.VARIABLE: case NodeKind.VARIABLE:
return this.compileVariableStatement(<VariableStatement>statement); var variableInit = this.compileVariableStatement(<VariableStatement>statement);
return variableInit ? variableInit : this.module.createNop();
case NodeKind.WHILE: case NodeKind.WHILE:
return this.compileWhileStatement(<WhileStatement>statement); return this.compileWhileStatement(<WhileStatement>statement);
@ -838,11 +848,20 @@ export class Compiler extends DiagnosticEmitter {
compileBlockStatement(statement: BlockStatement): ExpressionRef { compileBlockStatement(statement: BlockStatement): ExpressionRef {
var statements = statement.statements; var statements = statement.statements;
if (statements.length == 0)
return this.module.createNop(); // NOTE that we could optimize this to a NOP if empty or unwrap a single
if (statements.length == 1) // statement, but that's not what the source told us to do and left to the
return this.compileStatement(statements[0]); // optimizer.
return this.module.createBlock(null, this.compileStatements(statements), NativeType.None);
// Not actually a branch, but can contain its own scoped variables.
this.currentFunction.flow = this.currentFunction.flow.enterBranch();
var stmt = this.module.createBlock(null, this.compileStatements(statements), NativeType.None);
// Switch back to the parent flow
this.currentFunction.flow = this.currentFunction.flow.leaveBranch();
return stmt;
} }
compileBreakStatement(statement: BreakStatement): ExpressionRef { compileBreakStatement(statement: BreakStatement): ExpressionRef {
@ -850,12 +869,12 @@ export class Compiler extends DiagnosticEmitter {
this.error(DiagnosticCode.Operation_not_supported, statement.label.range); this.error(DiagnosticCode.Operation_not_supported, statement.label.range);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
var context = this.currentFunction.breakContext; var breakLabel = this.currentFunction.flow.breakLabel;
if (context != null) if (breakLabel == null) {
return this.module.createBreak("break|" + context); this.error(DiagnosticCode.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement, statement.range);
return this.module.createUnreachable();
this.error(DiagnosticCode.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement, statement.range); }
return this.module.createUnreachable(); return this.module.createBreak(breakLabel);
} }
compileContinueStatement(statement: ContinueStatement): ExpressionRef { compileContinueStatement(statement: ContinueStatement): ExpressionRef {
@ -863,21 +882,35 @@ export class Compiler extends DiagnosticEmitter {
this.error(DiagnosticCode.Operation_not_supported, statement.label.range); this.error(DiagnosticCode.Operation_not_supported, statement.label.range);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
var context = this.currentFunction.breakContext; // Check if 'continue' is allowed here
if (context && !this.disallowContinue) var continueLabel = this.currentFunction.flow.continueLabel;
return this.module.createBreak("continue|" + context); if (continueLabel == null) {
this.error(DiagnosticCode.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement, statement.range);
this.error(DiagnosticCode.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement, statement.range); return this.module.createUnreachable();
return this.module.createUnreachable(); }
return this.module.createBreak(continueLabel);
} }
compileDoStatement(statement: DoStatement): ExpressionRef { compileDoStatement(statement: DoStatement): ExpressionRef {
// A do statement does not initiate a new branch because it is executed at
// least once, but has its own break and continue labels.
var label = this.currentFunction.enterBreakContext(); var label = this.currentFunction.enterBreakContext();
var previousBreakLabel = this.currentFunction.flow.breakLabel;
var previousContinueLabel = this.currentFunction.flow.continueLabel;
var breakLabel = this.currentFunction.flow.breakLabel = "break|" + label;
var continueLabel = this.currentFunction.flow.continueLabel = "continue|" + label;
var body = this.compileStatement(statement.statement); var body = this.compileStatement(statement.statement);
// Reset to the previous break and continue labels, if any.
this.currentFunction.flow.breakLabel = previousBreakLabel;
this.currentFunction.flow.continueLabel = previousContinueLabel;
var condition = this.compileExpression(statement.condition, Type.i32); var condition = this.compileExpression(statement.condition, Type.i32);
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
var breakLabel = "break|" + label;
var continueLabel = "continue|" + label;
return this.module.createBlock(breakLabel, [ return this.module.createBlock(breakLabel, [
this.module.createLoop(continueLabel, this.module.createLoop(continueLabel,
this.module.createBlock(null, [ this.module.createBlock(null, [
@ -901,18 +934,24 @@ export class Compiler extends DiagnosticEmitter {
} }
compileForStatement(statement: ForStatement): ExpressionRef { compileForStatement(statement: ForStatement): ExpressionRef {
// A for statement initiates a new branch with its own scoped variables
// possibly declared in its initializer, and break context.
var context = this.currentFunction.enterBreakContext(); var context = this.currentFunction.enterBreakContext();
var variableWasLocal = this.variableIsLocal; this.currentFunction.flow = this.currentFunction.flow.enterBranch();
if (this.currentFunction == this.startFunction) var breakLabel = this.currentFunction.flow.breakLabel = "break|" + context;
this.variableIsLocal = true; var continueLabel = this.currentFunction.flow.continueLabel = "continue|" + context;
// Compile in correct order
var initializer = statement.initializer ? this.compileStatement(<Statement>statement.initializer) : this.module.createNop(); var initializer = statement.initializer ? this.compileStatement(<Statement>statement.initializer) : this.module.createNop();
this.variableIsLocal = variableWasLocal;
var condition = statement.condition ? this.compileExpression(<Expression>statement.condition, Type.i32) : this.module.createI32(1); var condition = statement.condition ? this.compileExpression(<Expression>statement.condition, Type.i32) : this.module.createI32(1);
var incrementor = statement.incrementor ? this.compileExpression(<Expression>statement.incrementor, Type.void) : this.module.createNop(); var incrementor = statement.incrementor ? this.compileExpression(<Expression>statement.incrementor, Type.void) : this.module.createNop();
var body = this.compileStatement(statement.statement); var body = this.compileStatement(statement.statement);
// Switch back to the parent flow
this.currentFunction.flow = this.currentFunction.flow.leaveBranch();
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
var continueLabel = "continue|" + context;
var breakLabel = "break|" + context;
return this.module.createBlock(breakLabel, [ return this.module.createBlock(breakLabel, [
initializer, initializer,
this.module.createLoop(continueLabel, this.module.createBlock(null, [ this.module.createLoop(continueLabel, this.module.createBlock(null, [
@ -926,30 +965,47 @@ export class Compiler extends DiagnosticEmitter {
} }
compileIfStatement(statement: IfStatement): ExpressionRef { compileIfStatement(statement: IfStatement): ExpressionRef {
// The condition doesn't initiate a branch yet
var condition = this.compileExpression(statement.condition, Type.i32); var condition = this.compileExpression(statement.condition, Type.i32);
// Each arm initiates a branch
this.currentFunction.flow = this.currentFunction.flow.enterBranch();
var ifTrue = this.compileStatement(statement.ifTrue); var ifTrue = this.compileStatement(statement.ifTrue);
var ifFalse = statement.ifFalse ? this.compileStatement(<Statement>statement.ifFalse) : <ExpressionRef>0; this.currentFunction.flow = this.currentFunction.flow.leaveBranch();
var ifFalse: ExpressionRef = 0;
if (statement.ifFalse) {
this.currentFunction.flow = this.currentFunction.flow.enterBranch();
ifFalse = this.compileStatement(statement.ifFalse);
this.currentFunction.flow = this.currentFunction.flow.leaveBranch();
}
return this.module.createIf(condition, ifTrue, ifFalse); return this.module.createIf(condition, ifTrue, ifFalse);
} }
compileReturnStatement(statement: ReturnStatement): ExpressionRef { compileReturnStatement(statement: ReturnStatement): ExpressionRef {
if (this.currentFunction) { assert(this.currentFunction);
var expression = statement.value ? this.compileExpression(<Expression>statement.value, this.currentFunction.returnType) : <ExpressionRef>0;
return this.module.createReturn(expression); var expression: ExpressionRef = 0;
} if (statement.value)
return this.module.createUnreachable(); expression = this.compileExpression(<Expression>statement.value, this.currentFunction.returnType);
// Remember that this flow returns
this.currentFunction.flow.set(FlowFlags.RETURNS);
return this.module.createReturn(expression);
} }
compileSwitchStatement(statement: SwitchStatement): ExpressionRef { compileSwitchStatement(statement: SwitchStatement): ExpressionRef {
// Everything within a switch uses the same break context
var context = this.currentFunction.enterBreakContext(); var context = this.currentFunction.enterBreakContext();
var previousDisallowContinue = this.disallowContinue;
this.disallowContinue = true;
// introduce a local for evaluating the condition (exactly once) // introduce a local for evaluating the condition (exactly once)
var tempLocal = this.currentFunction.getTempLocal(Type.i32); var tempLocal = this.currentFunction.getTempLocal(Type.i32);
var k = statement.cases.length; var k = statement.cases.length;
// prepend initializer to inner block // Prepend initializer to inner block. Does not initiate a new branch, yet.
var breaks = new Array<ExpressionRef>(1 + k); var breaks = new Array<ExpressionRef>(1 + k);
breaks[0] = this.module.createSetLocal(tempLocal.index, this.compileExpression(statement.condition, Type.i32)); // initializer breaks[0] = this.module.createSetLocal(tempLocal.index, this.compileExpression(statement.condition, Type.i32)); // initializer
@ -981,22 +1037,34 @@ export class Compiler extends DiagnosticEmitter {
var currentBlock = this.module.createBlock("case0|" + context, breaks, NativeType.None); var currentBlock = this.module.createBlock("case0|" + context, breaks, NativeType.None);
for (i = 0; i < k; ++i) { for (i = 0; i < k; ++i) {
case_ = statement.cases[i]; case_ = statement.cases[i];
var nextLabel = i == k - 1 ? "break|" + context : "case" + (i + 1).toString(10) + "|" + context;
var l = case_.statements.length; var l = case_.statements.length;
var body = new Array<ExpressionRef>(1 + l); var body = new Array<ExpressionRef>(1 + l);
body[0] = currentBlock; body[0] = currentBlock;
// Each switch case initiates a new branch
this.currentFunction.flow = this.currentFunction.flow.enterBranch();
var breakLabel = this.currentFunction.flow.breakLabel = "break|" + context;
var nextLabel = i == k - 1 ? breakLabel : "case" + (i + 1).toString(10) + "|" + context;
for (var j = 0; j < l; ++j) for (var j = 0; j < l; ++j)
body[j + 1] = this.compileStatement(case_.statements[j]); body[j + 1] = this.compileStatement(case_.statements[j]);
// Switch back to the parent flow
this.currentFunction.flow = this.currentFunction.flow.leaveBranch();
currentBlock = this.module.createBlock(nextLabel, body, NativeType.None); currentBlock = this.module.createBlock(nextLabel, body, NativeType.None);
} }
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
this.disallowContinue = previousDisallowContinue;
return currentBlock; return currentBlock;
} }
compileThrowStatement(statement: ThrowStatement): ExpressionRef { compileThrowStatement(statement: ThrowStatement): ExpressionRef {
return this.module.createUnreachable(); // TODO: waiting for exception-handling spec
// Remember that this branch possibly throws
this.currentFunction.flow.set(FlowFlags.THROWS);
// TODO: requires exception-handling spec.
return this.module.createUnreachable();
} }
compileTryStatement(statement: TryStatement): ExpressionRef { compileTryStatement(statement: TryStatement): ExpressionRef {
@ -1005,16 +1073,28 @@ export class Compiler extends DiagnosticEmitter {
// worthwhile to investigate lowering returns to block results (here)? // worthwhile to investigate lowering returns to block results (here)?
} }
compileVariableStatement(statement: VariableStatement): ExpressionRef { /**
* Compiles a variable statement. Returns `0` if an initializer is not
* necessary.
*/
compileVariableStatement(statement: VariableStatement, isKnownGlobal: bool = false): ExpressionRef {
var declarations = statement.declarations; var declarations = statement.declarations;
// top-level variables become globals // top-level variables and constants become globals
if (this.currentFunction == this.startFunction && !this.variableIsLocal) { if (isKnownGlobal || (
var isConst = hasModifier(ModifierKind.CONST, statement.modifiers); this.currentFunction == this.startFunction &&
statement.parent && statement.parent.kind == NodeKind.SOURCE
)) {
// NOTE that the above condition also covers top-level variables declared with 'let', even
// though such variables could also become start function locals if, and only if, not used
// within any function declared in the same source, which is unknown at this point. the only
// efficient way to deal with this would be to keep track of all occasions it is used and
// replace these instructions afterwards, dynamically. (TOOD: what about a Binaryen pass?)
for (var i = 0, k = declarations.length; i < k; ++i) for (var i = 0, k = declarations.length; i < k; ++i)
this.compileGlobalDeclaration(declarations[i], isConst); this.compileGlobalDeclaration(declarations[i]);
return this.module.createNop(); return 0;
} }
// other variables become locals // other variables become locals
var initializers = new Array<ExpressionRef>(); var initializers = new Array<ExpressionRef>();
for (i = 0, k = declarations.length; i < k; ++i) { for (i = 0, k = declarations.length; i < k; ++i) {
@ -1039,53 +1119,73 @@ export class Compiler extends DiagnosticEmitter {
this.error(DiagnosticCode.Type_expected, declaration.name.range.atEnd); this.error(DiagnosticCode.Type_expected, declaration.name.range.atEnd);
continue; continue;
} }
if (this.currentFunction.locals.has(name)) if (hasModifier(ModifierKind.CONST, declaration.modifiers)) {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name); // recoverable if (init) {
else { init = this.precomputeExpressionRef(init);
if (hasModifier(ModifierKind.CONST, declaration.modifiers)) { if (_BinaryenExpressionGetId(init) == ExpressionId.Const) {
if (init) { var local = new Local(this.program, name, -1, type);
init = this.precomputeExpressionRef(init); switch (_BinaryenExpressionGetType(init)) {
if (_BinaryenExpressionGetId(init) == ExpressionId.Const) { case NativeType.I32:
var local = new Local(this.program, name, -1, type); local = local.withConstantIntegerValue(_BinaryenConstGetValueI32(init), 0);
switch (_BinaryenExpressionGetType(init)) { break;
case NativeType.I32: case NativeType.I64:
local = local.withConstantIntegerValue(_BinaryenConstGetValueI32(init), 0); local = local.withConstantIntegerValue(_BinaryenConstGetValueI64Low(init), _BinaryenConstGetValueI64High(init));
break; break;
case NativeType.I64: case NativeType.F32:
local = local.withConstantIntegerValue(_BinaryenConstGetValueI64Low(init), _BinaryenConstGetValueI64High(init)); local = local.withConstantFloatValue(<f64>_BinaryenConstGetValueF32(init));
break; break;
case NativeType.F32: case NativeType.F64:
local = local.withConstantFloatValue(<f64>_BinaryenConstGetValueF32(init)); local = local.withConstantFloatValue(_BinaryenConstGetValueF64(init));
break; break;
case NativeType.F64: default:
local = local.withConstantFloatValue(_BinaryenConstGetValueF64(init)); throw new Error("concrete type expected");
break; }
default: // Create a virtual local that doesn't actually exist in WebAssembly
throw new Error("concrete type expected"); var scopedLocals = this.currentFunction.flow.scopedLocals;
} if (!scopedLocals)
this.currentFunction.locals.set(name, local); scopedLocals = this.currentFunction.flow.scopedLocals = new Map();
continue; else if (scopedLocals.has(name)) {
} else this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name);
this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, declaration.range); return 0;
} else { }
this.error(DiagnosticCode._const_declarations_must_be_initialized, declaration.range); scopedLocals.set(name, local);
} return 0;
} } else
this.currentFunction.addLocal(type, name); this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, declaration.range);
if (init) } else
initializers.push(this.compileAssignmentWithValue(declaration.name, init)); this.error(DiagnosticCode._const_declarations_must_be_initialized, declaration.range);
} }
if (hasModifier(ModifierKind.LET, declaration.modifiers)) // here: not top-level
this.currentFunction.flow.addScopedLocal(name, type, declaration.name); // reports
else
this.currentFunction.addLocal(type, name); // reports
if (init)
initializers.push(this.compileAssignmentWithValue(declaration.name, init));
} }
return initializers.length ? this.module.createBlock(null, initializers, NativeType.None) : this.module.createNop(); return initializers.length // we can unwrap these here because the
? initializers.length == 1 // source didn't tell us exactly what to do
? initializers[0]
: this.module.createBlock(null, initializers, NativeType.None)
: 0;
} }
compileWhileStatement(statement: WhileStatement): ExpressionRef { compileWhileStatement(statement: WhileStatement): ExpressionRef {
var label = this.currentFunction.enterBreakContext();
// The condition does not yet initialize a branch
var condition = this.compileExpression(statement.condition, Type.i32); var condition = this.compileExpression(statement.condition, Type.i32);
var breakLabel = "break|" + label;
var continueLabel = "continue|" + label; // Statements initiate a new branch with its own break context
var label = this.currentFunction.enterBreakContext();
this.currentFunction.flow = this.currentFunction.flow.enterBranch();
var breakLabel = this.currentFunction.flow.breakLabel = "break|" + label;
var continueLabel = this.currentFunction.flow.continueLabel = "continue|" + label;
var body = this.compileStatement(statement.statement); var body = this.compileStatement(statement.statement);
// Switch back to the parent flow
this.currentFunction.flow = this.currentFunction.flow.leaveBranch();
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
return this.module.createBlock(breakLabel, [ return this.module.createBlock(breakLabel, [
this.module.createLoop(continueLabel, this.module.createLoop(continueLabel,
this.module.createIf(condition, this.module.createBlock(null, [ this.module.createIf(condition, this.module.createBlock(null, [
@ -2256,7 +2356,7 @@ export class Compiler extends DiagnosticEmitter {
case ElementKind.LOCAL: case ElementKind.LOCAL:
this.currentType = tee ? (<Local>element).type : Type.void; this.currentType = tee ? (<Local>element).type : Type.void;
if ((<Local>element).isConstant) { if ((<Local>element).is(ElementFlags.CONSTANT)) {
this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, (<Local>element).internalName); this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, (<Local>element).internalName);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
@ -2269,7 +2369,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
assert((<Global>element).type != Type.void); assert((<Global>element).type != Type.void);
this.currentType = tee ? (<Global>element).type : Type.void; this.currentType = tee ? (<Global>element).type : Type.void;
if ((<Local>element).isConstant) { if ((<Local>element).is(ElementFlags.CONSTANT)) {
this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, (<Local>element).internalName); this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, (<Local>element).internalName);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
@ -2307,7 +2407,7 @@ export class Compiler extends DiagnosticEmitter {
if (setterInstance) { if (setterInstance) {
assert(setterInstance.parameters.length == 1); assert(setterInstance.parameters.length == 1);
if (!tee) { if (!tee) {
if (setterInstance.isInstance) { if (setterInstance.is(ElementFlags.INSTANCE)) {
assert(resolved.targetExpression != null); assert(resolved.targetExpression != null);
targetExpr = this.compileExpression(<Expression>resolved.targetExpression, this.options.target == Target.WASM64 ? Type.usize64 : Type.usize32, ConversionKind.NONE); targetExpr = this.compileExpression(<Expression>resolved.targetExpression, this.options.target == Target.WASM64 ? Type.usize64 : Type.usize32, ConversionKind.NONE);
assert(this.currentType.classType); assert(this.currentType.classType);
@ -2323,7 +2423,7 @@ export class Compiler extends DiagnosticEmitter {
var getterInstance = (<FunctionPrototype>getterPrototype).resolve(); // reports var getterInstance = (<FunctionPrototype>getterPrototype).resolve(); // reports
if (getterInstance) { if (getterInstance) {
assert(getterInstance.parameters.length == 0); assert(getterInstance.parameters.length == 0);
if (setterInstance.isInstance) { if (setterInstance.is(ElementFlags.INSTANCE)) {
assert(resolved.targetExpression != null); assert(resolved.targetExpression != null);
targetExpr = this.compileExpression(<Expression>resolved.targetExpression, this.options.target == Target.WASM64 ? Type.usize64 : Type.usize32, ConversionKind.NONE); targetExpr = this.compileExpression(<Expression>resolved.targetExpression, this.options.target == Target.WASM64 ? Type.usize64 : Type.usize32, ConversionKind.NONE);
assert(this.currentType.classType); assert(this.currentType.classType);
@ -2388,7 +2488,7 @@ export class Compiler extends DiagnosticEmitter {
if (element.kind == ElementKind.FUNCTION_PROTOTYPE) { if (element.kind == ElementKind.FUNCTION_PROTOTYPE) {
var functionPrototype = <FunctionPrototype>element; var functionPrototype = <FunctionPrototype>element;
var functionInstance: Function | null = null; var functionInstance: Function | null = null;
if (functionPrototype.isBuiltIn) { if (functionPrototype.is(ElementFlags.BUILTIN)) {
var resolvedTypeArguments: Type[] | null = null; var resolvedTypeArguments: Type[] | null = null;
if (expression.typeArguments) { if (expression.typeArguments) {
var k = expression.typeArguments.length; var k = expression.typeArguments.length;
@ -2489,11 +2589,11 @@ export class Compiler extends DiagnosticEmitter {
} }
private makeCall(functionInstance: Function, operands: ExpressionRef[] | null = null): ExpressionRef { private makeCall(functionInstance: Function, operands: ExpressionRef[] | null = null): ExpressionRef {
if (!(functionInstance.isCompiled || this.compileFunction(functionInstance))) if (!(functionInstance.is(ElementFlags.COMPILED) || this.compileFunction(functionInstance)))
return this.module.createUnreachable(); return this.module.createUnreachable();
// imported function // imported function
if (functionInstance.isDeclared) if (functionInstance.is(ElementFlags.DECLARED))
return this.module.createCallImport(functionInstance.internalName, operands, functionInstance.returnType.toNativeType()); return this.module.createCallImport(functionInstance.internalName, operands, functionInstance.returnType.toNativeType());
// internal function // internal function
@ -2576,19 +2676,19 @@ export class Compiler extends DiagnosticEmitter {
case ElementKind.LOCAL: case ElementKind.LOCAL:
this.currentType = (<Local>element).type; this.currentType = (<Local>element).type;
if ((<Local>element).hasConstantValue) if ((<Local>element).is(ElementFlags.INLINED))
return makeInlineConstant(<Local>element, this.module); return makeInlineConstant(<Local>element, this.module);
assert((<Local>element).index >= 0); assert((<Local>element).index >= 0);
return this.module.createGetLocal((<Local>element).index, this.currentType.toNativeType()); return this.module.createGetLocal((<Local>element).index, this.currentType.toNativeType());
case ElementKind.GLOBAL: case ElementKind.GLOBAL:
if (element.isBuiltIn) if (element.is(ElementFlags.BUILTIN))
return compileBuiltinGetConstant(this, <Global>element, expression); return compileBuiltinGetConstant(this, <Global>element, expression);
if (!this.compileGlobal(<Global>element)) // reports; not yet compiled if a static field compiled as a global if (!this.compileGlobal(<Global>element)) // reports; not yet compiled if a static field compiled as a global
return this.module.createUnreachable(); return this.module.createUnreachable();
assert((<Global>element).type != Type.void); assert((<Global>element).type != Type.void);
this.currentType = (<Global>element).type; this.currentType = (<Global>element).type;
if ((<Global>element).hasConstantValue) if ((<Global>element).is(ElementFlags.INLINED))
return makeInlineConstant(<Global>element, this.module); return makeInlineConstant(<Global>element, this.module);
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType()); return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
} }
@ -2660,13 +2760,13 @@ export class Compiler extends DiagnosticEmitter {
switch (element.kind) { switch (element.kind) {
case ElementKind.GLOBAL: // static property case ElementKind.GLOBAL: // static property
if (element.isBuiltIn) if (element.is(ElementFlags.BUILTIN))
return compileBuiltinGetConstant(this, <Global>element, propertyAccess); return compileBuiltinGetConstant(this, <Global>element, propertyAccess);
if (!this.compileGlobal(<Global>element)) // reports; not yet compiled if a static field compiled as a global if (!this.compileGlobal(<Global>element)) // reports; not yet compiled if a static field compiled as a global
return this.module.createUnreachable(); return this.module.createUnreachable();
assert((<Global>element).type != Type.void); assert((<Global>element).type != Type.void);
this.currentType = (<Global>element).type; this.currentType = (<Global>element).type;
if ((<Global>element).hasConstantValue) if ((<Global>element).is(ElementFlags.INLINED))
return makeInlineConstant(<Global>element, this.module); return makeInlineConstant(<Global>element, this.module);
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType()); return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
@ -2674,7 +2774,7 @@ export class Compiler extends DiagnosticEmitter {
if (!this.compileEnum((<EnumValue>element).enum)) if (!this.compileEnum((<EnumValue>element).enum))
return this.module.createUnreachable(); return this.module.createUnreachable();
this.currentType = Type.i32; this.currentType = Type.i32;
if ((<EnumValue>element).hasConstantValue) if ((<EnumValue>element).is(ElementFlags.INLINED))
return this.module.createI32((<EnumValue>element).constantValue); return this.module.createI32((<EnumValue>element).constantValue);
return this.module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32); return this.module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32);
@ -2698,7 +2798,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
assert(getterInstance.parameters.length == 0); assert(getterInstance.parameters.length == 0);
this.currentType = getterInstance.returnType; this.currentType = getterInstance.returnType;
if (getterInstance.isInstance) { if (getterInstance.is(ElementFlags.INSTANCE)) {
var targetExpr = this.compileExpression(<Expression>resolved.targetExpression, this.options.target == Target.WASM64 ? Type.usize64 : Type.usize32) var targetExpr = this.compileExpression(<Expression>resolved.targetExpression, this.options.target == Target.WASM64 ? Type.usize64 : Type.usize32)
this.currentType = getterInstance.returnType; this.currentType = getterInstance.returnType;
return this.makeCall(getterInstance, [ targetExpr ]); return this.makeCall(getterInstance, [ targetExpr ]);
@ -3062,7 +3162,7 @@ export class Compiler extends DiagnosticEmitter {
/** Creates an inlined expression of a constant variable-like element. */ /** Creates an inlined expression of a constant variable-like element. */
function makeInlineConstant(element: VariableLikeElement, module: Module): ExpressionRef { function makeInlineConstant(element: VariableLikeElement, module: Module): ExpressionRef {
assert(element.hasConstantValue); assert(element.is(ElementFlags.INLINED));
assert(element.type != null); assert(element.type != null);
switch ((<Type>element.type).kind) { switch ((<Type>element.type).kind) {

View File

@ -153,15 +153,17 @@ export class Parser extends DiagnosticEmitter {
case Token.CONST: case Token.CONST:
modifiers = addModifier(Node.createModifier(ModifierKind.CONST, tn.range()), modifiers); modifiers = addModifier(Node.createModifier(ModifierKind.CONST, tn.range()), modifiers);
if (tn.skip(Token.ENUM)) { if (tn.skip(Token.ENUM)) {
statement = this.parseEnum(tn, modifiers, decorators); statement = this.parseEnum(tn, modifiers, decorators);
break; break;
} }
// fall through statement = this.parseVariable(tn, modifiers, decorators);
decorators = null;
break;
case Token.VAR:
case Token.LET: case Token.LET:
modifiers = addModifier(Node.createModifier(ModifierKind.LET, tn.range()), modifiers);
case Token.VAR:
statement = this.parseVariable(tn, modifiers, decorators); statement = this.parseVariable(tn, modifiers, decorators);
decorators = null; decorators = null;
break; break;
@ -1032,6 +1034,8 @@ export class Parser extends DiagnosticEmitter {
return this.parseIfStatement(tn); return this.parseIfStatement(tn);
case Token.LET: case Token.LET:
return this.parseVariable(tn, [ Node.createModifier(ModifierKind.LET, tn.range()) ], null);
case Token.VAR: case Token.VAR:
return this.parseVariable(tn, null, null); return this.parseVariable(tn, null, null);

View File

@ -272,7 +272,7 @@ export class Program extends DiagnosticEmitter {
} }
private checkGlobalAlias(element: Element, declaration: DeclarationStatement) { private checkGlobalAlias(element: Element, declaration: DeclarationStatement) {
if (hasDecorator("global", declaration.decorators) || (declaration.range.source.isStdlib && assert(declaration.parent).kind == NodeKind.SOURCE && element.isExported)) { if (hasDecorator("global", declaration.decorators) || (declaration.range.source.isStdlib && assert(declaration.parent).kind == NodeKind.SOURCE && element.is(ElementFlags.EXPORTED))) {
if (this.elements.has(declaration.name.name)) if (this.elements.has(declaration.name.name))
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, element.internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, element.internalName);
else { else {
@ -317,7 +317,7 @@ export class Program extends DiagnosticEmitter {
namespace.members.set(declaration.name.name, prototype); namespace.members.set(declaration.name.name, prototype);
// otherwise add to file-level exports if exported // otherwise add to file-level exports if exported
} else if (prototype.isExported) { } else if (prototype.is(ElementFlags.EXPORTED)) {
if (this.exports.has(internalName)) { if (this.exports.has(internalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName);
return; return;
@ -541,7 +541,7 @@ export class Program extends DiagnosticEmitter {
} else } else
namespace.members = new Map(); namespace.members = new Map();
namespace.members.set(declaration.name.name, enm); namespace.members.set(declaration.name.name, enm);
} else if (enm.isExported) { } else if (enm.is(ElementFlags.EXPORTED)) {
if (this.exports.has(internalName)) { if (this.exports.has(internalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName);
return; return;
@ -669,7 +669,7 @@ export class Program extends DiagnosticEmitter {
} else } else
namespace.members = new Map(); namespace.members = new Map();
namespace.members.set(declaration.name.name, prototype); namespace.members.set(declaration.name.name, prototype);
} else if (prototype.isExported) { } else if (prototype.is(ElementFlags.EXPORTED)) {
if (this.exports.has(internalName)) { if (this.exports.has(internalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName);
return; return;
@ -759,7 +759,7 @@ export class Program extends DiagnosticEmitter {
} else } else
namespace.members = new Map(); namespace.members = new Map();
namespace.members.set(prototype.internalName, prototype); namespace.members.set(prototype.internalName, prototype);
} else if (prototype.isExported) { } else if (prototype.is(ElementFlags.EXPORTED)) {
if (this.exports.has(internalName)) { if (this.exports.has(internalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName);
return; return;
@ -810,7 +810,7 @@ export class Program extends DiagnosticEmitter {
} else } else
parentNamespace.members = new Map(); parentNamespace.members = new Map();
parentNamespace.members.set(declaration.name.name, namespace); parentNamespace.members.set(declaration.name.name, namespace);
} else if (namespace.isExported) { } else if (namespace.is(ElementFlags.EXPORTED)) {
if (this.exports.has(internalName)) { if (this.exports.has(internalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName);
return; return;
@ -884,7 +884,7 @@ export class Program extends DiagnosticEmitter {
this.elements.set(internalName, global); this.elements.set(internalName, global);
// differs a bit from this.checkGlobalAlias in that it checks the statement's parent // differs a bit from this.checkGlobalAlias in that it checks the statement's parent
if (hasDecorator("global", declaration.decorators) || (declaration.range.source.isStdlib && assert(statement.parent).kind == NodeKind.SOURCE && global.isExported)) { if (hasDecorator("global", declaration.decorators) || (declaration.range.source.isStdlib && assert(statement.parent).kind == NodeKind.SOURCE && global.is(ElementFlags.EXPORTED))) {
if (this.elements.has(declaration.name.name)) if (this.elements.has(declaration.name.name))
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
else else
@ -900,7 +900,7 @@ export class Program extends DiagnosticEmitter {
} else } else
namespace.members = new Map(); namespace.members = new Map();
namespace.members.set(declaration.name.name, global); namespace.members.set(declaration.name.name, global);
} else if (global.isExported) { } else if (global.is(ElementFlags.EXPORTED)) {
if (this.exports.has(internalName)) if (this.exports.has(internalName))
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
else else
@ -994,8 +994,9 @@ export class Program extends DiagnosticEmitter {
var namespace: Element | null; var namespace: Element | null;
if (contextualFunction) { if (contextualFunction) {
// check locals // check locals
var local = contextualFunction.locals.get(name); var local = contextualFunction.flow.getScopedLocal(name);
if (local) if (local)
return (resolvedElement || (resolvedElement = new ResolvedElement())).set(local); return (resolvedElement || (resolvedElement = new ResolvedElement())).set(local);
@ -1228,8 +1229,8 @@ export enum ElementFlags {
GENERIC = 1 << 5, GENERIC = 1 << 5,
/** Is constant. */ /** Is constant. */
CONSTANT = 1 << 6, CONSTANT = 1 << 6,
/** Has constant value. */ /** Has a constant value and is therefore inlined. */
CONSTANT_VALUE = 1 << 7, INLINED = 1 << 7,
/** Is instance member. */ /** Is instance member. */
INSTANCE = 1 << 8, INSTANCE = 1 << 8,
/** Is getter. */ /** Is getter. */
@ -1251,7 +1252,9 @@ export enum ElementFlags {
/** Is an explicitly layed out and allocated class with limited capabilites. */ /** Is an explicitly layed out and allocated class with limited capabilites. */
EXPLICIT = 1 << 17, EXPLICIT = 1 << 17,
/** Has already inherited base class static members. */ /** Has already inherited base class static members. */
HAS_STATIC_BASE_MEMBERS = 1 << 18 HAS_STATIC_BASE_MEMBERS = 1 << 18,
/** Is scoped. */
SCOPED = 1 << 19
} }
/** Base class of all program elements. */ /** Base class of all program elements. */
@ -1279,49 +1282,11 @@ export abstract class Element {
this.internalName = internalName; this.internalName = internalName;
} }
/** Whether compiled or not. */ /** Tests if this element has a specific flag or flags. */
get isCompiled(): bool { return (this.flags & ElementFlags.COMPILED) != 0; } is(flag: ElementFlags): bool { return (this.flags & flag) == flag; }
set isCompiled(is: bool) { if (is) this.flags |= ElementFlags.COMPILED; else this.flags &= ~ElementFlags.COMPILED; }
/** Whether imported or not. */ /** Sets a specific flag or flags. */
get isImported(): bool { return (this.flags & ElementFlags.IMPORTED) != 0; } set(flag: ElementFlags): void { this.flags |= flag; }
set isImported(is: bool) { if (is) this.flags |= ElementFlags.IMPORTED; else this.flags &= ~ElementFlags.IMPORTED; }
/** Whether exported or not. */
get isExported(): bool { return (this.flags & ElementFlags.EXPORTED) != 0; }
set isExported(is: bool) { if (is) this.flags |= ElementFlags.EXPORTED; else this.flags &= ~ElementFlags.EXPORTED; }
/** Whether built-in or not. */
get isBuiltIn(): bool { return (this.flags & ElementFlags.BUILTIN) != 0; }
set isBuiltIn(is: bool) { if (is) this.flags |= ElementFlags.BUILTIN; else this.flags &= ~ElementFlags.BUILTIN; }
/** Whether declared or not. */
get isDeclared(): bool { return (this.flags & ElementFlags.DECLARED) != 0; }
set isDeclared(is: bool) { if (is) this.flags |= ElementFlags.DECLARED; else this.flags &= ~ElementFlags.DECLARED; }
/** Whether generic or not. */
get isGeneric(): bool { return (this.flags & ElementFlags.GENERIC) != 0; }
set isGeneric(is: bool) { if (is) this.flags |= ElementFlags.GENERIC; else this.flags &= ~ElementFlags.GENERIC; }
/** Whether constant or not. */
get isConstant(): bool { return (this.flags & ElementFlags.CONSTANT) != 0; }
set isConstant(is: bool) { if (is) this.flags |= ElementFlags.CONSTANT; else this.flags &= ~ElementFlags.CONSTANT; }
/** Whether mutable or not. */
get isMutable(): bool { return !(this.flags & ElementFlags.CONSTANT); } // reuses constant flag
set isMutable(is: bool) { if (is) this.flags &= ~ElementFlags.CONSTANT; else this.flags |= ElementFlags.CONSTANT; }
/** Whether this element has a constant value or not. */
get hasConstantValue(): bool { return (this.flags & ElementFlags.CONSTANT_VALUE) != 0; }
set hasConstantValue(is: bool) { if (is) this.flags |= ElementFlags.CONSTANT_VALUE; else this.flags &= ~ElementFlags.CONSTANT_VALUE; }
/** Whether an instance member or not. */
get isInstance(): bool { return (this.flags & ElementFlags.INSTANCE) != 0; }
set isInstance(is: bool) { if (is) this.flags |= ElementFlags.INSTANCE; else this.flags &= ~ElementFlags.INSTANCE; }
/** Whether a member of the global namespace or not. */
get isGlobal(): bool { return (this.flags & ElementFlags.GLOBAL) != 0; }
set isGlobal(is: bool) { if (is) this.flags |= ElementFlags.GLOBAL; else this.flags &= ~ElementFlags.GLOBAL; }
} }
/** A namespace. */ /** A namespace. */
@ -1339,9 +1304,9 @@ export class Namespace extends Element {
if ((this.declaration = declaration) && this.declaration.modifiers) { if ((this.declaration = declaration) && this.declaration.modifiers) {
for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) { for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) {
switch (this.declaration.modifiers[i].modifierKind) { switch (this.declaration.modifiers[i].modifierKind) {
case ModifierKind.IMPORT: this.isImported = true; break; case ModifierKind.IMPORT: this.set(ElementFlags.IMPORTED); break;
case ModifierKind.EXPORT: this.isExported = true; break; case ModifierKind.EXPORT: this.set(ElementFlags.EXPORTED); break;
case ModifierKind.DECLARE: this.isDeclared = true; break; case ModifierKind.DECLARE: this.set(ElementFlags.DECLARED); break;
default: throw new Error("unexpected modifier"); default: throw new Error("unexpected modifier");
} }
} }
@ -1363,10 +1328,10 @@ export class Enum extends Element {
if ((this.declaration = declaration) && this.declaration.modifiers) { if ((this.declaration = declaration) && this.declaration.modifiers) {
for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) { for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) {
switch (this.declaration.modifiers[i].modifierKind) { switch (this.declaration.modifiers[i].modifierKind) {
case ModifierKind.EXPORT: this.isExported = true; break; case ModifierKind.EXPORT: this.set(ElementFlags.EXPORTED); break;
case ModifierKind.IMPORT: this.isImported = true; break; case ModifierKind.IMPORT: this.set(ElementFlags.IMPORTED); break;
case ModifierKind.DECLARE: this.isDeclared = true; break; case ModifierKind.DECLARE: this.set(ElementFlags.DECLARED); break;
case ModifierKind.CONST: this.isConstant = true; break; case ModifierKind.CONST: this.set(ElementFlags.CONSTANT); break;
default: throw new Error("unexpected modifier"); default: throw new Error("unexpected modifier");
} }
} }
@ -1408,15 +1373,13 @@ export class VariableLikeElement extends Element {
withConstantIntegerValue(lo: i32, hi: i32): this { withConstantIntegerValue(lo: i32, hi: i32): this {
this.constantIntegerValue = new I64(lo, hi); this.constantIntegerValue = new I64(lo, hi);
this.hasConstantValue = true; this.set(ElementFlags.CONSTANT | ElementFlags.INLINED);
this.isMutable = false;
return this; return this;
} }
withConstantFloatValue(value: f64): this { withConstantFloatValue(value: f64): this {
this.constantFloatValue = value; this.constantFloatValue = value;
this.hasConstantValue = true; this.set(ElementFlags.CONSTANT | ElementFlags.INLINED);
this.isMutable = false;
return this; return this;
} }
} }
@ -1432,18 +1395,19 @@ export class Global extends VariableLikeElement {
if (this.declaration.modifiers) { if (this.declaration.modifiers) {
for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) { for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) {
switch (this.declaration.modifiers[i].modifierKind) { switch (this.declaration.modifiers[i].modifierKind) {
case ModifierKind.IMPORT: this.isImported = true; break; case ModifierKind.IMPORT: this.set(ElementFlags.IMPORTED); break;
case ModifierKind.EXPORT: this.isExported = true; break; case ModifierKind.EXPORT: this.set(ElementFlags.EXPORTED); break;
case ModifierKind.CONST: this.isConstant = true; break; case ModifierKind.CONST: this.set(ElementFlags.CONSTANT); break;
case ModifierKind.DECLARE: this.isDeclared = true; break; case ModifierKind.LET: this.set(ElementFlags.SCOPED); break;
case ModifierKind.READONLY: this.isConstant = true; break; case ModifierKind.DECLARE: this.set(ElementFlags.DECLARED); break;
case ModifierKind.READONLY: this.set(this.declaration.initializer ? ElementFlags.CONSTANT | ElementFlags.READONLY : ElementFlags.READONLY); break;
case ModifierKind.STATIC: break; // static fields become globals case ModifierKind.STATIC: break; // static fields become globals
default: throw new Error("unexpected modifier"); default: throw new Error("unexpected modifier");
} }
} }
} }
} else { } else {
this.hasConstantValue = true; // built-ins have constant values this.set(ElementFlags.CONSTANT | ElementFlags.INLINED); // built-ins have constant values
} }
this.type = type; // resolved later if `void` this.type = type; // resolved later if `void`
} }
@ -1505,11 +1469,11 @@ export class FunctionPrototype extends Element {
if (this.declaration.modifiers) if (this.declaration.modifiers)
for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) { for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) {
switch (this.declaration.modifiers[i].modifierKind) { switch (this.declaration.modifiers[i].modifierKind) {
case ModifierKind.IMPORT: this.isImported = true; break; case ModifierKind.IMPORT: this.set(ElementFlags.IMPORTED); break;
case ModifierKind.EXPORT: this.isExported = true; break; case ModifierKind.EXPORT: this.set(ElementFlags.EXPORTED); break;
case ModifierKind.DECLARE: this.isDeclared = true; break; case ModifierKind.DECLARE: this.set(ElementFlags.DECLARED); break;
case ModifierKind.GET: this.isGetter = true; break; case ModifierKind.GET: this.set(ElementFlags.GETTER); break;
case ModifierKind.SET: this.isSetter = true; break; case ModifierKind.SET: this.set(ElementFlags.SETTER); break;
case ModifierKind.STATIC: case ModifierKind.STATIC:
case ModifierKind.ABSTRACT: case ModifierKind.ABSTRACT:
case ModifierKind.PRIVATE: case ModifierKind.PRIVATE:
@ -1519,10 +1483,10 @@ export class FunctionPrototype extends Element {
} }
} }
if (this.declaration.typeParameters.length) if (this.declaration.typeParameters.length)
this.isGeneric = true; this.set(ElementFlags.GENERIC);
} }
if (this.classPrototype = classPrototype) if (this.classPrototype = classPrototype)
this.isInstance = true; this.set(ElementFlags.INSTANCE);
} }
/** Whether a getter function or not. */ /** Whether a getter function or not. */
@ -1629,7 +1593,7 @@ export class FunctionPrototype extends Element {
resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Function | null { resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Function | null {
var resolvedTypeArguments: Type[] | null = null; var resolvedTypeArguments: Type[] | null = null;
if (this.isGeneric) { if (this.is(ElementFlags.GENERIC)) {
assert(typeArgumentNodes != null && typeArgumentNodes.length != 0); assert(typeArgumentNodes != null && typeArgumentNodes.length != 0);
if (!this.declaration) if (!this.declaration)
throw new Error("cannot resolve built-ins"); throw new Error("cannot resolve built-ins");
@ -1678,6 +1642,8 @@ export class Function extends Element {
breakContext: string | null = null; breakContext: string | null = null;
/** Contextual type arguments. */ /** Contextual type arguments. */
contextualTypeArguments: Map<string,Type> | null; contextualTypeArguments: Map<string,Type> | null;
/** Current control flow. */
flow: Flow;
private nextBreakId: i32 = 0; private nextBreakId: i32 = 0;
private breakStack: i32[] | null = null; private breakStack: i32[] | null = null;
@ -1693,7 +1659,7 @@ export class Function extends Element {
this.flags = prototype.flags; this.flags = prototype.flags;
var localIndex = 0; var localIndex = 0;
if (instanceMethodOf) { if (instanceMethodOf) {
assert(this.isInstance); // internal error assert(this.is(ElementFlags.INSTANCE)); // internal error
this.locals.set("this", new Local(prototype.program, "this", localIndex++, instanceMethodOf.type)); this.locals.set("this", new Local(prototype.program, "this", localIndex++, instanceMethodOf.type));
if (instanceMethodOf.contextualTypeArguments) { if (instanceMethodOf.contextualTypeArguments) {
if (!this.contextualTypeArguments) if (!this.contextualTypeArguments)
@ -1702,18 +1668,19 @@ export class Function extends Element {
this.contextualTypeArguments.set(inheritedName, inheritedType); this.contextualTypeArguments.set(inheritedName, inheritedType);
} }
} else } else
assert(!this.isInstance); // internal error assert(!this.is(ElementFlags.INSTANCE)); // internal error
for (var i = 0, k = parameters.length; i < k; ++i) { for (var i = 0, k = parameters.length; i < k; ++i) {
var parameter = parameters[i]; var parameter = parameters[i];
this.locals.set(parameter.name, new Local(prototype.program, parameter.name, localIndex++, parameter.type)); this.locals.set(parameter.name, new Local(prototype.program, parameter.name, localIndex++, parameter.type));
} }
this.flow = Flow.create(this);
} }
/** Adds a local of the specified type, with an optional name. */ /** Adds a local of the specified type, with an optional name. */
addLocal(type: Type, name: string | null = null): Local { addLocal(type: Type, name: string | null = null): Local {
// if it has a name, check previously as this method will throw otherwise // if it has a name, check previously as this method will throw otherwise
var localIndex = this.parameters.length + this.additionalLocals.length; var localIndex = this.parameters.length + this.additionalLocals.length;
if (this.isInstance) localIndex++; // plus 'this' if (this.is(ElementFlags.INSTANCE)) localIndex++; // plus 'this'
var local = new Local(this.prototype.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type); var local = new Local(this.prototype.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type);
if (name) { if (name) {
if (this.locals.has(name)) if (this.locals.has(name))
@ -1831,8 +1798,8 @@ export class FieldPrototype extends Element {
if ((this.declaration = declaration) && this.declaration.modifiers) { if ((this.declaration = declaration) && this.declaration.modifiers) {
for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) { for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) {
switch (this.declaration.modifiers[i].modifierKind) { switch (this.declaration.modifiers[i].modifierKind) {
case ModifierKind.EXPORT: this.isExported = true; break; case ModifierKind.EXPORT: this.set(ElementFlags.EXPORTED); break;
case ModifierKind.READONLY: this.isReadonly = true; break; case ModifierKind.READONLY: this.set(ElementFlags.READONLY); break;
case ModifierKind.PRIVATE: case ModifierKind.PRIVATE:
case ModifierKind.PROTECTED: case ModifierKind.PROTECTED:
case ModifierKind.PUBLIC: case ModifierKind.PUBLIC:
@ -1915,15 +1882,15 @@ export class ClassPrototype extends Element {
if (this.declaration.modifiers) { if (this.declaration.modifiers) {
for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) { for (var i = 0, k = this.declaration.modifiers.length; i < k; ++i) {
switch (this.declaration.modifiers[i].modifierKind) { switch (this.declaration.modifiers[i].modifierKind) {
case ModifierKind.IMPORT: this.isImported = true; break; case ModifierKind.IMPORT: this.set(ElementFlags.IMPORTED); break;
case ModifierKind.EXPORT: this.isExported = true; break; case ModifierKind.EXPORT: this.set(ElementFlags.EXPORTED); break;
case ModifierKind.DECLARE: this.isDeclared = true; break; case ModifierKind.DECLARE: this.set(ElementFlags.DECLARED); break;
default: throw new Error("unexpected modifier"); default: throw new Error("unexpected modifier");
} }
} }
} }
if (this.declaration.typeParameters.length) if (this.declaration.typeParameters.length)
this.isGeneric = true; this.set(ElementFlags.GENERIC);
} }
} }
@ -2050,7 +2017,7 @@ export class ClassPrototype extends Element {
resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Class | null { resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Class | null {
var resolvedTypeArguments: Type[] | null = null; var resolvedTypeArguments: Type[] | null = null;
if (this.isGeneric) { if (this.is(ElementFlags.GENERIC)) {
assert(typeArgumentNodes != null && typeArgumentNodes.length != 0); assert(typeArgumentNodes != null && typeArgumentNodes.length != 0);
if (!this.declaration) if (!this.declaration)
throw new Error("cannot resolve built-ins"); throw new Error("cannot resolve built-ins");
@ -2153,3 +2120,90 @@ export class Interface extends Class {
super(prototype, internalName, typeArguments, base); super(prototype, internalName, typeArguments, base);
} }
} }
/** Control flow flags indicating specific conditions. */
export const enum FlowFlags {
NONE = 0,
RETURNS = 1 << 0,
THROWS = 1 << 1
}
/** A control flow evaluator. */
export class Flow {
/** Parent flow. */
parent: Flow | null;
/** Flow flags indicating specific conditions. */
flags: FlowFlags;
/** Function this flow belongs to. */
currentFunction: Function;
/** The label we break to when encountering a continue statement. */
continueLabel: string | null;
/** The label we break to when encountering a break statement. */
breakLabel: string | null;
/** Scoped local variables. */
scopedLocals: Map<string,Local> | null = null;
/** Creates the parent flow of the specified function. */
static create(currentFunction: Function): Flow {
var parentFlow = new Flow();
parentFlow.flags = FlowFlags.NONE;
parentFlow.currentFunction = currentFunction;
parentFlow.continueLabel = null;
parentFlow.breakLabel = null;
return parentFlow;
}
private constructor() { }
/** Tests if this flow has the specified flag or flags. */
is(flag: FlowFlags): bool { return (this.flags & flag) == flag; }
/** Sets the specified flag or flags. */
set(flag: FlowFlags): void { this.flags |= flag; }
/** Enters a new branch and returns the new flow. */
enterBranch(): Flow {
var branchFlow = new Flow();
branchFlow.parent = this;
branchFlow.flags = this.flags;
branchFlow.currentFunction = this.currentFunction;
branchFlow.continueLabel = this.continueLabel;
branchFlow.breakLabel = this.breakLabel;
return branchFlow;
}
/** Leaves the current branch and returns the parent flow. */
leaveBranch(): Flow {
if (this.scopedLocals) {
for (var scopedLocal of this.scopedLocals.values())
this.currentFunction.freeTempLocal(scopedLocal);
this.scopedLocals = null;
}
return assert(this.parent);
}
/** Adds a new scoped local of the specified name. */
addScopedLocal(name: string, type: Type, reportNode: Node): void {
var scopedLocal = this.currentFunction.getTempLocal(type);
if (!this.scopedLocals)
this.scopedLocals = new Map();
else if (this.scopedLocals.has(name)) {
this.currentFunction.program.error(DiagnosticCode.Duplicate_identifier_0, reportNode.range);
return;
}
this.scopedLocals.set(name, scopedLocal);
}
/** Gets the local of the specified name in the current scope. */
getScopedLocal(name: string): Local | null {
// console.log("checking: " + name);
var local: Local | null;
var current: Flow | null = this;
do {
if (current.scopedLocals && (local = current.scopedLocals.get(name)))
return local;
} while (current = current.parent);
return this.currentFunction.locals.get(name);
}
}

View File

@ -51,13 +51,20 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
var program = parser.finish(); var program = parser.finish();
var parseTime = process.hrtime(startTime); var parseTime = process.hrtime(startTime);
startTime = process.hrtime(); startTime = process.hrtime();
var module = Compiler.compile(program); var module;
try {
module = Compiler.compile(program);
} catch (e) {
failed = true;
module = Module.create();
console.log(chalk.red("compile ERROR: ") + e.stack);
}
var compileTime = process.hrtime(startTime); var compileTime = process.hrtime(startTime);
var actual = module.toText() + "(;\n[program.elements]\n " + elements(program.elements) var actual = module.toText() + "(;\n[program.elements]\n " + elements(program.elements)
+ "\n[program.exports]\n " + elements(program.exports) + "\n[program.exports]\n " + elements(program.exports)
+ "\n;)\n"; + "\n;)\n";
var actualOptimized = null; var actualOptimized = null;
var actualInlined = null; // var actualInlined = null;
console.log("parse incl. I/O: " + ((parseTime[0] * 1e9 + parseTime[1]) / 1e6).toFixed(3) + "ms / compile: " + ((compileTime[0] * 1e9 + compileTime[1]) / 1e6).toFixed(3) + "ms"); console.log("parse incl. I/O: " + ((parseTime[0] * 1e9 + parseTime[1]) / 1e6).toFixed(3) + "ms / compile: " + ((compileTime[0] * 1e9 + compileTime[1]) / 1e6).toFixed(3) + "ms");
@ -87,16 +94,14 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
console.log(chalk.green("instantiate OK")); console.log(chalk.green("instantiate OK"));
} catch (e) { } catch (e) {
failed = true; failed = true;
console.log(chalk.red("instantiate ERROR: ") + e); console.log(chalk.red("instantiate ERROR: ") + e.stack);
} }
} catch (e) { } catch (e) {
failed = true; failed = true;
console.log(chalk.red("interpret ERROR:") + e); console.log(chalk.red("interpret ERROR:") + e.stack);
} }
module.optimize(); module.optimize();
actualOptimized = module.toText(); actualOptimized = module.toText();
module.runPasses([ "inlining" ]);
actualInlined = module.toText();
if (isCreate) if (isCreate)
fs.writeFileSync(__dirname + "/compiler/" + fixture + ".optimized.wasm", module.toBinary()); fs.writeFileSync(__dirname + "/compiler/" + fixture + ".optimized.wasm", module.toBinary());
} else { } else {
@ -111,17 +116,6 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
fs.writeFileSync(__dirname + "/compiler/" + fixture + ".optimized.wast", actualOptimized, { encoding: "utf8" }); fs.writeFileSync(__dirname + "/compiler/" + fixture + ".optimized.wast", actualOptimized, { encoding: "utf8" });
console.log("Created optimized"); console.log("Created optimized");
} }
if (actualInlined != null) {
if (actualInlined != actualOptimized) {
fs.writeFileSync(__dirname + "/compiler/" + fixture + ".optimized-inlined.wast", actualInlined, { encoding: "utf8" });
console.log("Created optimized & inlined");
} else {
try {
fs.unlinkSync(__dirname + "/compiler/" + fixture + ".optimized-inlined.wast");
console.log("Deleted optimized & inlined");
} catch (e) {}
}
}
} else { } else {
var expected; var expected;
try { try {

View File

@ -34,20 +34,6 @@
) )
) )
) )
(drop
(select
(tee_local $2
(i32.const 1)
)
(tee_local $3
(i32.const 2)
)
(i32.lt_s
(get_local $2)
(get_local $3)
)
)
)
(set_global $builtins/i (set_global $builtins/i
(i32.const 31) (i32.const 31)
) )
@ -90,9 +76,7 @@
(tee_local $2 (tee_local $2
(i32.const 1) (i32.const 1)
) )
(tee_local $3 (i32.const 2)
(i32.const 2)
)
(i32.gt_s (i32.gt_s
(get_local $2) (get_local $2)
(get_local $3) (get_local $3)
@ -108,12 +92,8 @@
) )
(set_global $builtins/i (set_global $builtins/i
(select (select
(tee_local $2 (i32.const 1)
(i32.const 1) (i32.const 2)
)
(tee_local $3
(i32.const 2)
)
(i32.lt_s (i32.lt_s
(get_local $2) (get_local $2)
(get_local $3) (get_local $3)
@ -187,12 +167,8 @@
) )
(set_global $builtins/I (set_global $builtins/I
(select (select
(tee_local $4 (i64.const 1)
(i64.const 1) (i64.const 2)
)
(tee_local $5
(i64.const 2)
)
(i64.lt_s (i64.lt_s
(get_local $4) (get_local $4)
(get_local $5) (get_local $5)
@ -251,9 +227,7 @@
(select (select
(f32.ne (f32.ne
(f32.abs (f32.abs
(tee_local $0 (f32.const 1.25)
(f32.const 1.25)
)
) )
(f32.const inf) (f32.const inf)
) )
@ -309,9 +283,7 @@
(select (select
(f64.ne (f64.ne
(f64.abs (f64.abs
(tee_local $1 (f64.const 1.25)
(f64.const 1.25)
)
) )
(f64.const inf) (f64.const inf)
) )

View File

@ -1,141 +0,0 @@
(module
(type $iii (func (param i32 i32) (result i32)))
(type $fff (func (param f32 f32) (result f32)))
(type $iiii (func (param i32 i32 i32) (result i32)))
(type $ifff (func (param i32 f32 f32) (result f32)))
(type $ii (func (param i32) (result i32)))
(type $v (func))
(global $class/Animal.ONE (mut i32) (i32.const 1))
(memory $0 1)
(export "test" (func $class/test))
(export "memory" (memory $0))
(start $start)
(func $class/test (; 0 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
(local $5 f32)
(local $6 f32)
(drop
(block (result i32)
(block $__inlined_func$class/Animal#instanceAdd (result i32)
(set_local $1
(get_local $0)
)
(set_local $2
(i32.const 1)
)
(set_local $3
(i32.const 2)
)
(i32.add
(i32.add
(get_local $2)
(get_local $3)
)
(get_global $class/Animal.ONE)
)
)
)
)
(drop
(block (result f32)
(block $__inlined_func$class/Animal#instanceSub<f32> (result f32)
(set_local $4
(get_local $0)
)
(set_local $5
(f32.const 1)
)
(set_local $6
(f32.const 2)
)
(f32.add
(f32.sub
(get_local $5)
(get_local $6)
)
(f32.convert_s/i32
(get_global $class/Animal.ONE)
)
)
)
)
)
(drop
(i32.load
(get_local $0)
)
)
(drop
(i32.load16_s offset=4
(get_local $0)
)
)
(drop
(i32.load8_s offset=6
(get_local $0)
)
)
(i32.store
(get_local $0)
(i32.const 1)
)
(i32.store16 offset=4
(get_local $0)
(i32.const 2)
)
(i32.store8 offset=6
(get_local $0)
(i32.const 3)
)
(get_local $0)
)
(func $start (; 1 ;) (type $v)
(local $0 i32)
(local $1 i32)
(local $2 f32)
(local $3 f32)
(drop
(block (result i32)
(block $__inlined_func$class/Animal.add (result i32)
(set_local $0
(i32.const 1)
)
(set_local $1
(i32.const 2)
)
(i32.add
(i32.add
(get_local $0)
(get_local $1)
)
(get_global $class/Animal.ONE)
)
)
)
)
(drop
(block (result f32)
(block $__inlined_func$class/Animal.sub<f32> (result f32)
(set_local $2
(f32.const 1)
)
(set_local $3
(f32.const 2)
)
(f32.add
(f32.sub
(get_local $2)
(get_local $3)
)
(f32.convert_s/i32
(get_global $class/Animal.ONE)
)
)
)
)
)
)
)

View File

@ -1,70 +1,11 @@
(module (module
(type $iii (func (param i32 i32) (result i32)))
(type $fff (func (param f32 f32) (result f32)))
(type $iiii (func (param i32 i32 i32) (result i32)))
(type $ifff (func (param i32 f32 f32) (result f32)))
(type $ii (func (param i32) (result i32))) (type $ii (func (param i32) (result i32)))
(type $v (func)) (type $v (func))
(global $class/Animal.ONE (mut i32) (i32.const 1))
(memory $0 1) (memory $0 1)
(export "test" (func $class/test)) (export "test" (func $class/test))
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $class/Animal.add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $class/test (; 0 ;) (type $ii) (param $0 i32) (result i32)
(i32.add
(i32.add
(get_local $0)
(get_local $1)
)
(get_global $class/Animal.ONE)
)
)
(func $class/Animal.sub<f32> (; 1 ;) (type $fff) (param $0 f32) (param $1 f32) (result f32)
(f32.add
(f32.sub
(get_local $0)
(get_local $1)
)
(f32.convert_s/i32
(get_global $class/Animal.ONE)
)
)
)
(func $class/Animal#instanceAdd (; 2 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(i32.add
(i32.add
(get_local $1)
(get_local $2)
)
(get_global $class/Animal.ONE)
)
)
(func $class/Animal#instanceSub<f32> (; 3 ;) (type $ifff) (param $0 i32) (param $1 f32) (param $2 f32) (result f32)
(f32.add
(f32.sub
(get_local $1)
(get_local $2)
)
(f32.convert_s/i32
(get_global $class/Animal.ONE)
)
)
)
(func $class/test (; 4 ;) (type $ii) (param $0 i32) (result i32)
(drop
(call $class/Animal#instanceAdd
(get_local $0)
(i32.const 1)
(i32.const 2)
)
)
(drop
(call $class/Animal#instanceSub<f32>
(get_local $0)
(f32.const 1)
(f32.const 2)
)
)
(drop (drop
(i32.load (i32.load
(get_local $0) (get_local $0)
@ -94,18 +35,7 @@
) )
(get_local $0) (get_local $0)
) )
(func $start (; 5 ;) (type $v) (func $start (; 1 ;) (type $v)
(drop (nop)
(call $class/Animal.add
(i32.const 1)
(i32.const 2)
)
)
(drop
(call $class/Animal.sub<f32>
(f32.const 1)
(f32.const 2)
)
)
) )
) )

View File

@ -127,15 +127,11 @@
(i32.const 24) (i32.const 24)
) )
) )
(block (set_local $1
(set_local $1 (get_local $0)
(get_local $0)
)
) )
(block (set_local $2
(set_local $2 (get_local $1)
(get_local $1)
)
) )
(return (return
(get_local $2) (get_local $2)

View File

@ -147,10 +147,8 @@
(unreachable) (unreachable)
) )
(block $break|0 (block $break|0
(block (set_local $1
(set_local $1 (i32.const 0)
(i32.const 0)
)
) )
(loop $continue|0 (loop $continue|0
(if (if

View File

@ -1,48 +0,0 @@
(module
(type $i (func (result i32)))
(type $v (func))
(global $enum/Implicit.ZERO i32 (i32.const 0))
(global $enum/Implicit.ONE i32 (i32.const 1))
(global $enum/Implicit.TWO i32 (i32.const 2))
(global $enum/Implicit.THREE i32 (i32.const 3))
(global $enum/Explicit.ZERO i32 (i32.const 0))
(global $enum/Explicit.ONE i32 (i32.const 1))
(global $enum/Explicit.TWO i32 (i32.const 2))
(global $enum/Explicit.THREE i32 (i32.const 3))
(global $enum/Mixed.ZERO i32 (i32.const 0))
(global $enum/Mixed.ONE i32 (i32.const 1))
(global $enum/Mixed.THREE i32 (i32.const 3))
(global $enum/Mixed.FOUR i32 (i32.const 4))
(global $enum/NonConstant.ZERO (mut i32) (i32.const 0))
(global $enum/NonConstant.ONE (mut i32) (i32.const 0))
(memory $0 1)
(export "enum/Implicit.ZERO" (global $enum/Implicit.ZERO))
(export "enum/Implicit.ONE" (global $enum/Implicit.ONE))
(export "enum/Implicit.TWO" (global $enum/Implicit.TWO))
(export "enum/Implicit.THREE" (global $enum/Implicit.THREE))
(export "enum/Explicit.ZERO" (global $enum/Explicit.ZERO))
(export "enum/Explicit.ONE" (global $enum/Explicit.ONE))
(export "enum/Explicit.TWO" (global $enum/Explicit.TWO))
(export "enum/Explicit.THREE" (global $enum/Explicit.THREE))
(export "enum/Mixed.ZERO" (global $enum/Mixed.ZERO))
(export "enum/Mixed.ONE" (global $enum/Mixed.ONE))
(export "enum/Mixed.THREE" (global $enum/Mixed.THREE))
(export "enum/Mixed.FOUR" (global $enum/Mixed.FOUR))
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(set_global $enum/NonConstant.ZERO
(block (result i32)
(block $__inlined_func$enum/getZero (result i32)
(i32.const 0)
)
)
)
(set_global $enum/NonConstant.ONE
(i32.add
(get_global $enum/NonConstant.ZERO)
(i32.const 1)
)
)
)
)

View File

@ -1,5 +1,4 @@
(module (module
(type $i (func (result i32)))
(type $v (func)) (type $v (func))
(global $enum/Implicit.ZERO i32 (i32.const 0)) (global $enum/Implicit.ZERO i32 (i32.const 0))
(global $enum/Implicit.ONE i32 (i32.const 1)) (global $enum/Implicit.ONE i32 (i32.const 1))
@ -30,12 +29,9 @@
(export "enum/Mixed.FOUR" (global $enum/Mixed.FOUR)) (export "enum/Mixed.FOUR" (global $enum/Mixed.FOUR))
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $enum/getZero (; 0 ;) (type $i) (result i32) (func $start (; 0 ;) (type $v)
(i32.const 0)
)
(func $start (; 1 ;) (type $v)
(set_global $enum/NonConstant.ZERO (set_global $enum/NonConstant.ZERO
(call $enum/getZero) (i32.const 0)
) )
(set_global $enum/NonConstant.ONE (set_global $enum/NonConstant.ONE
(i32.add (i32.add

File diff suppressed because it is too large Load Diff

View File

@ -19,53 +19,43 @@
(local $7 f64) (local $7 f64)
(local $8 i32) (local $8 i32)
(local $9 i64) (local $9 i64)
(block (set_local $2
(set_local $2 (i64.reinterpret/f64
(i64.reinterpret/f64 (get_local $0)
(get_local $0)
)
) )
) )
(block (set_local $3
(set_local $3 (i64.reinterpret/f64
(i64.reinterpret/f64 (get_local $1)
(get_local $1)
)
) )
) )
(block (set_local $4
(set_local $4 (i32.wrap/i64
(i32.wrap/i64 (i64.and
(i64.and
(i64.shr_u
(get_local $2)
(i64.const 52)
)
(i64.const 2047)
)
)
)
)
(block
(set_local $5
(i32.wrap/i64
(i64.and
(i64.shr_u
(get_local $3)
(i64.const 52)
)
(i64.const 2047)
)
)
)
)
(block
(set_local $6
(i32.wrap/i64
(i64.shr_u (i64.shr_u
(get_local $2) (get_local $2)
(i64.const 63) (i64.const 52)
) )
(i64.const 2047)
)
)
)
(set_local $5
(i32.wrap/i64
(i64.and
(i64.shr_u
(get_local $3)
(i64.const 52)
)
(i64.const 2047)
)
)
)
(set_local $6
(i32.wrap/i64
(i64.shr_u
(get_local $2)
(i64.const 63)
) )
) )
) )
@ -163,12 +153,10 @@
) )
(block (block
(block $break|0 (block $break|0
(block (set_local $9
(set_local $9 (i64.shl
(i64.shl (get_local $2)
(get_local $2) (i64.const 12)
(i64.const 12)
)
) )
) )
(loop $continue|0 (loop $continue|0
@ -497,48 +485,38 @@
(local $7 f32) (local $7 f32)
(local $8 i32) (local $8 i32)
(local $9 i32) (local $9 i32)
(block (set_local $2
(set_local $2 (i32.reinterpret/f32
(i32.reinterpret/f32 (get_local $0)
(get_local $0)
)
) )
) )
(block (set_local $3
(set_local $3 (i32.reinterpret/f32
(i32.reinterpret/f32 (get_local $1)
(get_local $1)
)
) )
) )
(block (set_local $4
(set_local $4 (i32.and
(i32.and (i32.shr_u
(i32.shr_u
(get_local $2)
(i32.const 23)
)
(i32.const 255)
)
)
)
(block
(set_local $5
(i32.and
(i32.shr_u
(get_local $3)
(i32.const 23)
)
(i32.const 255)
)
)
)
(block
(set_local $6
(i32.and
(get_local $2) (get_local $2)
(i32.const -2147483648) (i32.const 23)
) )
(i32.const 255)
)
)
(set_local $5
(i32.and
(i32.shr_u
(get_local $3)
(i32.const 23)
)
(i32.const 255)
)
)
(set_local $6
(i32.and
(get_local $2)
(i32.const -2147483648)
) )
) )
(if (if
@ -635,12 +613,10 @@
) )
(block (block
(block $break|0 (block $break|0
(block (set_local $9
(set_local $9 (i32.shl
(i32.shl (get_local $2)
(get_local $2) (i32.const 9)
(i32.const 9)
)
) )
) )
(loop $continue|0 (loop $continue|0

View File

@ -33,9 +33,6 @@
) )
(unreachable) (unreachable)
) )
(set_local $0
(i32.const 0)
)
(loop $continue|1 (loop $continue|1
(if (if
(i32.lt_s (i32.lt_s

View File

@ -18,7 +18,9 @@
(i32.const 10) (i32.const 10)
) )
(block (block
(nop) (block
(nop)
)
(set_global $for/i (set_global $for/i
(i32.add (i32.add
(get_global $for/i) (get_global $for/i)
@ -40,10 +42,8 @@
(unreachable) (unreachable)
) )
(block $break|1 (block $break|1
(block (set_local $0
(set_local $0 (i32.const 0)
(i32.const 0)
)
) )
(loop $continue|1 (loop $continue|1
(if (if
@ -52,7 +52,9 @@
(i32.const 10) (i32.const 10)
) )
(block (block
(nop) (block
(nop)
)
(set_local $0 (set_local $0
(i32.add (i32.add
(get_local $0) (get_local $0)

View File

@ -1,195 +0,0 @@
(module
(type $v (func))
(type $i (func (result i32)))
(type $I (func (result i64)))
(type $f (func (result f32)))
(type $F (func (result f64)))
(type $iv (func (param i32)))
(type $ii (func (param i32) (result i32)))
(type $II (func (param i64) (result i64)))
(type $ff (func (param f32) (result f32)))
(type $FF (func (param f64) (result f64)))
(type $iiv (func (param i32 i32)))
(type $iii (func (param i32 i32) (result i32)))
(type $IiI (func (param i64 i32) (result i64)))
(type $fff (func (param f32 f32) (result f32)))
(type $FFF (func (param f64 f64) (result f64)))
(memory $0 1)
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(local $0 i32)
(local $1 i32)
(local $2 i64)
(local $3 f32)
(local $4 f64)
(local $5 i32)
(local $6 i32)
(local $7 i32)
(local $8 i32)
(local $9 i64)
(local $10 i32)
(local $11 f32)
(local $12 f32)
(local $13 f64)
(local $14 f64)
(block
(block $__inlined_func$function/v
(nop)
)
)
(drop
(block (result i32)
(block $__inlined_func$function/i (result i32)
(i32.const 0)
)
)
)
(drop
(block (result i64)
(block $__inlined_func$function/I (result i64)
(i64.const 0)
)
)
)
(drop
(block (result f32)
(block $__inlined_func$function/f (result f32)
(f32.const 0)
)
)
)
(drop
(block (result f64)
(block $__inlined_func$function/F (result f64)
(f64.const 0)
)
)
)
(block
(block $__inlined_func$function/iv
(set_local $0
(i32.const 0)
)
(nop)
)
)
(drop
(block (result i32)
(block $__inlined_func$function/ii (result i32)
(set_local $1
(i32.const 0)
)
(get_local $1)
)
)
)
(drop
(block (result i64)
(block $__inlined_func$function/II (result i64)
(set_local $2
(i64.const 0)
)
(get_local $2)
)
)
)
(drop
(block (result f32)
(block $__inlined_func$function/ff (result f32)
(set_local $3
(f32.const 0)
)
(get_local $3)
)
)
)
(drop
(block (result f64)
(block $__inlined_func$function/FF (result f64)
(set_local $4
(f64.const 0)
)
(get_local $4)
)
)
)
(block
(block $__inlined_func$function/iiv
(set_local $5
(i32.const 1)
)
(set_local $6
(i32.const 2)
)
(nop)
)
)
(drop
(block (result i32)
(block $__inlined_func$function/iii (result i32)
(set_local $7
(i32.const 1)
)
(set_local $8
(i32.const 2)
)
(i32.add
(get_local $7)
(get_local $8)
)
)
)
)
(drop
(block (result i64)
(block $__inlined_func$function/III (result i64)
(set_local $9
(i64.const 1)
)
(set_local $10
(i32.const 2)
)
(i64.add
(get_local $9)
(i64.extend_s/i32
(get_local $10)
)
)
)
)
)
(drop
(block (result f32)
(block $__inlined_func$function/fff (result f32)
(set_local $11
(f32.const 1)
)
(set_local $12
(f32.const 2)
)
(f32.add
(get_local $11)
(get_local $12)
)
)
)
)
(drop
(block (result f64)
(block $__inlined_func$function/FFF (result f64)
(set_local $13
(f64.const 1)
)
(set_local $14
(f64.const 2)
)
(f64.add
(get_local $13)
(get_local $14)
)
)
)
)
)
)

View File

@ -1,145 +1,9 @@
(module (module
(type $v (func)) (type $v (func))
(type $i (func (result i32)))
(type $I (func (result i64)))
(type $f (func (result f32)))
(type $F (func (result f64)))
(type $iv (func (param i32)))
(type $ii (func (param i32) (result i32)))
(type $II (func (param i64) (result i64)))
(type $ff (func (param f32) (result f32)))
(type $FF (func (param f64) (result f64)))
(type $iiv (func (param i32 i32)))
(type $iii (func (param i32 i32) (result i32)))
(type $IiI (func (param i64 i32) (result i64)))
(type $fff (func (param f32 f32) (result f32)))
(type $FFF (func (param f64 f64) (result f64)))
(memory $0 1) (memory $0 1)
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $function/v (; 0 ;) (type $v) (func $start (; 0 ;) (type $v)
(nop) (nop)
) )
(func $function/i (; 1 ;) (type $i) (result i32)
(i32.const 0)
)
(func $function/I (; 2 ;) (type $I) (result i64)
(i64.const 0)
)
(func $function/f (; 3 ;) (type $f) (result f32)
(f32.const 0)
)
(func $function/F (; 4 ;) (type $F) (result f64)
(f64.const 0)
)
(func $function/iv (; 5 ;) (type $iv) (param $0 i32)
(nop)
)
(func $function/ii (; 6 ;) (type $ii) (param $0 i32) (result i32)
(get_local $0)
)
(func $function/II (; 7 ;) (type $II) (param $0 i64) (result i64)
(get_local $0)
)
(func $function/ff (; 8 ;) (type $ff) (param $0 f32) (result f32)
(get_local $0)
)
(func $function/FF (; 9 ;) (type $FF) (param $0 f64) (result f64)
(get_local $0)
)
(func $function/iiv (; 10 ;) (type $iiv) (param $0 i32) (param $1 i32)
(nop)
)
(func $function/iii (; 11 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(i32.add
(get_local $0)
(get_local $1)
)
)
(func $function/III (; 12 ;) (type $IiI) (param $0 i64) (param $1 i32) (result i64)
(i64.add
(get_local $0)
(i64.extend_s/i32
(get_local $1)
)
)
)
(func $function/fff (; 13 ;) (type $fff) (param $0 f32) (param $1 f32) (result f32)
(f32.add
(get_local $0)
(get_local $1)
)
)
(func $function/FFF (; 14 ;) (type $FFF) (param $0 f64) (param $1 f64) (result f64)
(f64.add
(get_local $0)
(get_local $1)
)
)
(func $start (; 15 ;) (type $v)
(call $function/v)
(drop
(call $function/i)
)
(drop
(call $function/I)
)
(drop
(call $function/f)
)
(drop
(call $function/F)
)
(call $function/iv
(i32.const 0)
)
(drop
(call $function/ii
(i32.const 0)
)
)
(drop
(call $function/II
(i64.const 0)
)
)
(drop
(call $function/ff
(f32.const 0)
)
)
(drop
(call $function/FF
(f64.const 0)
)
)
(call $function/iiv
(i32.const 1)
(i32.const 2)
)
(drop
(call $function/iii
(i32.const 1)
(i32.const 2)
)
)
(drop
(call $function/III
(i64.const 1)
(i32.const 2)
)
)
(drop
(call $function/fff
(f32.const 1)
(f32.const 2)
)
)
(drop
(call $function/FFF
(f64.const 1)
(f64.const 2)
)
)
)
) )

View File

@ -43,9 +43,6 @@
(i32.const 1) (i32.const 1)
) )
) )
(set_local $0
(i32.const 0)
)
(loop $continue|0 (loop $continue|0
(if (if
(i32.lt_u (i32.lt_u
@ -210,11 +207,7 @@
) )
(if (if
(i32.and (i32.and
(if (result i32) (select
(i32.lt_u
(get_local $2)
(i32.const 2)
)
(i32.lt_u (i32.lt_u
(get_local $2) (get_local $2)
(i32.const 2) (i32.const 2)
@ -223,6 +216,10 @@
(get_local $2) (get_local $2)
(i32.const 3) (i32.const 3)
) )
(i32.lt_u
(get_local $2)
(i32.const 2)
)
) )
(i32.const 1) (i32.const 1)
) )

View File

@ -48,10 +48,8 @@
) )
) )
(block $break|0 (block $break|0
(block (set_local $2
(set_local $2 (i32.const 0)
(i32.const 0)
)
) )
(loop $continue|0 (loop $continue|0
(if (if
@ -90,10 +88,8 @@
) )
) )
(block $break|1 (block $break|1
(block (set_local $5
(set_local $5 (i32.const 0)
(i32.const 0)
)
) )
(loop $continue|1 (loop $continue|1
(if (if
@ -131,33 +127,22 @@
) )
) )
) )
(block (set_local $8
(set_local $8 (i32.and
(i32.and (i32.add
(i32.add (i32.add
(i32.add (i32.add
(i32.add (i32.add
(i32.add (i32.add
(i32.add (i32.add
(i32.add (i32.add
(i32.add (i32.load8_u
(i32.load8_u (i32.add
(i32.add (i32.mul
(i32.mul (get_local $3)
(get_local $3) (get_global $../../examples/game-of-life/assembly/game-of-life/w)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $6)
)
)
(i32.load8_u
(i32.add
(i32.mul
(get_local $3)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $5)
) )
(get_local $6)
) )
) )
(i32.load8_u (i32.load8_u
@ -166,17 +151,17 @@
(get_local $3) (get_local $3)
(get_global $../../examples/game-of-life/assembly/game-of-life/w) (get_global $../../examples/game-of-life/assembly/game-of-life/w)
) )
(get_local $7) (get_local $5)
) )
) )
) )
(i32.load8_u (i32.load8_u
(i32.add (i32.add
(i32.mul (i32.mul
(get_local $2) (get_local $3)
(get_global $../../examples/game-of-life/assembly/game-of-life/w) (get_global $../../examples/game-of-life/assembly/game-of-life/w)
) )
(get_local $6) (get_local $7)
) )
) )
) )
@ -186,17 +171,17 @@
(get_local $2) (get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/w) (get_global $../../examples/game-of-life/assembly/game-of-life/w)
) )
(get_local $7) (get_local $6)
) )
) )
) )
(i32.load8_u (i32.load8_u
(i32.add (i32.add
(i32.mul (i32.mul
(get_local $4) (get_local $2)
(get_global $../../examples/game-of-life/assembly/game-of-life/w) (get_global $../../examples/game-of-life/assembly/game-of-life/w)
) )
(get_local $6) (get_local $7)
) )
) )
) )
@ -206,7 +191,7 @@
(get_local $4) (get_local $4)
(get_global $../../examples/game-of-life/assembly/game-of-life/w) (get_global $../../examples/game-of-life/assembly/game-of-life/w)
) )
(get_local $5) (get_local $6)
) )
) )
) )
@ -216,12 +201,21 @@
(get_local $4) (get_local $4)
(get_global $../../examples/game-of-life/assembly/game-of-life/w) (get_global $../../examples/game-of-life/assembly/game-of-life/w)
) )
(get_local $7) (get_local $5)
) )
) )
) )
(i32.const 255) (i32.load8_u
(i32.add
(i32.mul
(get_local $4)
(get_global $../../examples/game-of-life/assembly/game-of-life/w)
)
(get_local $7)
)
)
) )
(i32.const 255)
) )
) )
(if (if

File diff suppressed because it is too large Load Diff

View File

@ -8,10 +8,10 @@
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $if/ifThenElse (; 0 ;) (type $ii) (param $0 i32) (result i32) (func $if/ifThenElse (; 0 ;) (type $ii) (param $0 i32) (result i32)
(if (result i32) (select
(get_local $0)
(i32.const 1) (i32.const 1)
(i32.const 0) (i32.const 0)
(get_local $0)
) )
) )
(func $if/ifThen (; 1 ;) (type $ii) (param $0 i32) (result i32) (func $if/ifThen (; 1 ;) (type $ii) (param $0 i32) (result i32)

View File

@ -1,68 +0,0 @@
(module
(type $iii (func (param i32 i32) (result i32)))
(type $v (func))
(memory $0 1)
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(local $0 i32)
(local $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
(local $5 i32)
(drop
(i32.add
(i32.add
(block (result i32)
(block $__inlined_func$export/add (result i32)
(set_local $0
(i32.const 1)
)
(set_local $1
(i32.const 2)
)
(i32.add
(get_local $0)
(get_local $1)
)
)
)
(block (result i32)
(block $__inlined_func$export/sub (result i32)
(set_local $2
(i32.const 2)
)
(set_local $3
(i32.const 3)
)
(i32.sub
(get_local $2)
(get_local $3)
)
)
)
)
(block (result i32)
(block $__inlined_func$export/mul (result i32)
(set_local $4
(i32.const 3)
)
(set_local $5
(i32.const 1)
)
(i32.mul
(get_local $4)
(get_local $5)
)
)
)
)
)
(block
(block $__inlined_func$export/ns.two
(nop)
)
)
)
)

View File

@ -1,49 +1,9 @@
(module (module
(type $iii (func (param i32 i32) (result i32)))
(type $v (func)) (type $v (func))
(memory $0 1) (memory $0 1)
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $start (; 0 ;) (type $v)
(i32.add
(get_local $0)
(get_local $1)
)
)
(func $export/sub (; 1 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(i32.sub
(get_local $0)
(get_local $1)
)
)
(func $export/mul (; 2 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(i32.mul
(get_local $0)
(get_local $1)
)
)
(func $export/ns.two (; 3 ;) (type $v)
(nop) (nop)
) )
(func $start (; 4 ;) (type $v)
(drop
(i32.add
(i32.add
(call $export/add
(i32.const 1)
(i32.const 2)
)
(call $export/sub
(i32.const 2)
(i32.const 3)
)
)
(call $export/mul
(i32.const 3)
(i32.const 1)
)
)
)
(call $export/ns.two)
)
) )

View File

@ -1,74 +0,0 @@
(module
(type $v (func))
(type $i (func (result i32)))
(type $I (func (result i64)))
(type $f (func (result f32)))
(type $F (func (result f64)))
(global $infer-type/ri (mut i32) (i32.const 0))
(global $infer-type/rI (mut i64) (i64.const 0))
(global $infer-type/rf (mut f32) (f32.const 0))
(global $infer-type/rF (mut f64) (f64.const 0))
(memory $0 1)
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(local $0 i32)
(local $1 i32)
(block
(block $__inlined_func$infer-type/locals
(nop)
)
)
(set_global $infer-type/ri
(block (result i32)
(block $__inlined_func$infer-type/reti (result i32)
(i32.const 0)
)
)
)
(set_global $infer-type/rI
(block (result i64)
(block $__inlined_func$infer-type/retI (result i64)
(i64.const 0)
)
)
)
(set_global $infer-type/rf
(block (result f32)
(block $__inlined_func$infer-type/retf (result f32)
(f32.const 0)
)
)
)
(set_global $infer-type/rF
(block (result f64)
(block $__inlined_func$infer-type/refF (result f64)
(f64.const 0)
)
)
)
(set_local $0
(i32.const 0)
)
(set_local $1
(i32.const 10)
)
(loop $continue|0
(if
(i32.lt_u
(get_local $0)
(get_local $1)
)
(block
(set_local $0
(i32.add
(get_local $0)
(i32.const 1)
)
)
(br $continue|0)
)
)
)
)
)

View File

@ -1,9 +1,5 @@
(module (module
(type $v (func)) (type $v (func))
(type $i (func (result i32)))
(type $I (func (result i64)))
(type $f (func (result f32)))
(type $F (func (result f64)))
(global $infer-type/ri (mut i32) (i32.const 0)) (global $infer-type/ri (mut i32) (i32.const 0))
(global $infer-type/rI (mut i64) (i64.const 0)) (global $infer-type/rI (mut i64) (i64.const 0))
(global $infer-type/rf (mut f32) (f32.const 0)) (global $infer-type/rf (mut f32) (f32.const 0))
@ -11,48 +7,25 @@
(memory $0 1) (memory $0 1)
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $infer-type/locals (; 0 ;) (type $v) (func $start (; 0 ;) (type $v)
(nop)
)
(func $infer-type/reti (; 1 ;) (type $i) (result i32)
(i32.const 0)
)
(func $infer-type/retI (; 2 ;) (type $I) (result i64)
(i64.const 0)
)
(func $infer-type/retf (; 3 ;) (type $f) (result f32)
(f32.const 0)
)
(func $infer-type/refF (; 4 ;) (type $F) (result f64)
(f64.const 0)
)
(func $start (; 5 ;) (type $v)
(local $0 i32) (local $0 i32)
(local $1 i32)
(call $infer-type/locals)
(set_global $infer-type/ri (set_global $infer-type/ri
(call $infer-type/reti)
)
(set_global $infer-type/rI
(call $infer-type/retI)
)
(set_global $infer-type/rf
(call $infer-type/retf)
)
(set_global $infer-type/rF
(call $infer-type/refF)
)
(set_local $0
(i32.const 0) (i32.const 0)
) )
(set_local $1 (set_global $infer-type/rI
(i32.const 10) (i64.const 0)
)
(set_global $infer-type/rf
(f32.const 0)
)
(set_global $infer-type/rF
(f64.const 0)
) )
(loop $continue|0 (loop $continue|0
(if (if
(i32.lt_u (i32.lt_u
(get_local $0) (get_local $0)
(get_local $1) (i32.const 10)
) )
(block (block
(set_local $0 (set_local $0

View File

@ -22,35 +22,23 @@
(local $3 i32) (local $3 i32)
(local $4 i64) (local $4 i64)
(local $5 f64) (local $5 f64)
(block (set_local $0
(set_local $0 (i32.const 10)
(i32.const 10)
)
) )
(block (set_local $1
(set_local $1 (i64.const 4294967296)
(i64.const 4294967296)
)
) )
(block (set_local $2
(set_local $2 (f64.const 1.5)
(f64.const 1.5)
)
) )
(block (set_local $3
(set_local $3 (i32.const 10)
(i32.const 10)
)
) )
(block (set_local $4
(set_local $4 (i64.const 4294967296)
(i64.const 4294967296)
)
) )
(block (set_local $5
(set_local $5 (f64.const 1.5)
(f64.const 1.5)
)
) )
) )
(func $infer-type/reti (; 1 ;) (type $i) (result i32) (func $infer-type/reti (; 1 ;) (type $i) (result i32)
@ -126,7 +114,9 @@
(get_local $1) (get_local $1)
) )
(block (block
(nop) (block
(nop)
)
(set_local $0 (set_local $0
(i32.add (i32.add
(get_local $0) (get_local $0)

File diff suppressed because it is too large Load Diff

View File

@ -13,10 +13,8 @@
(local $4 i32) (local $4 i32)
(local $5 i32) (local $5 i32)
(local $6 i32) (local $6 i32)
(block (set_local $3
(set_local $3 (get_local $0)
(get_local $0)
)
) )
(nop) (nop)
(block $break|0 (block $break|0

View File

@ -10,10 +10,8 @@
(func $memmove/memmove (; 0 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (func $memmove/memmove (; 0 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32) (local $3 i32)
(local $4 i32) (local $4 i32)
(block (set_local $3
(set_local $3 (get_local $0)
(get_local $0)
)
) )
(if (if
(i32.eq (i32.eq
@ -283,20 +281,22 @@
(if (if
(get_local $2) (get_local $2)
(block (block
(i32.store8 (block
(i32.add (i32.store8
(get_local $0) (i32.add
(tee_local $2 (get_local $0)
(i32.sub (tee_local $2
(get_local $2) (i32.sub
(i32.const 1) (get_local $2)
(i32.const 1)
)
) )
) )
) (i32.load8_u
(i32.load8_u (i32.add
(i32.add (get_local $1)
(get_local $1) (get_local $2)
(get_local $2) )
) )
) )
) )

View File

@ -10,349 +10,336 @@
(local $3 i32) (local $3 i32)
(local $4 i64) (local $4 i64)
(local $5 i32) (local $5 i32)
(set_local $3 (block $folding-inner0
(get_local $0) (set_local $3
)
(if
(i32.eqz
(get_local $2)
)
(return
(get_local $3)
)
)
(i32.store8
(get_local $0)
(get_local $1)
)
(i32.store8
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 1)
)
(get_local $1)
)
(if
(i32.le_u
(get_local $2)
(i32.const 2)
)
(return
(get_local $3)
)
)
(i32.store8
(i32.add
(get_local $0) (get_local $0)
(i32.const 1)
) )
(get_local $1) (br_if $folding-inner0
) (i32.eqz
(i32.store8 (get_local $2)
(i32.add )
)
(i32.store8
(get_local $0) (get_local $0)
(i32.const 2) (get_local $1)
) )
(get_local $1) (i32.store8
) (i32.sub
(i32.store8 (i32.add
(i32.sub (get_local $0)
(get_local $2)
)
(i32.const 1)
)
(get_local $1)
)
(br_if $folding-inner0
(i32.le_u
(get_local $2)
(i32.const 2)
)
)
(i32.store8
(i32.add (i32.add
(get_local $0) (get_local $0)
(get_local $2) (i32.const 1)
) )
(i32.const 2) (get_local $1)
) )
(get_local $1) (i32.store8
)
(i32.store8
(i32.sub
(i32.add (i32.add
(get_local $0) (get_local $0)
(get_local $2) (i32.const 2)
) )
(i32.const 3) (get_local $1)
) )
(get_local $1) (i32.store8
) (i32.sub
(if (i32.add
(i32.le_u (get_local $0)
(get_local $2) (get_local $2)
(i32.const 6) )
(i32.const 2)
)
(get_local $1)
) )
(return (i32.store8
(get_local $3) (i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 3)
)
(get_local $1)
) )
) (br_if $folding-inner0
(i32.store8 (i32.le_u
(i32.add (get_local $2)
(get_local $0) (i32.const 6)
(i32.const 3) )
) )
(get_local $1) (i32.store8
)
(i32.store8
(i32.sub
(i32.add (i32.add
(get_local $0) (get_local $0)
(get_local $2) (i32.const 3)
) )
(i32.const 4) (get_local $1)
) )
(get_local $1) (i32.store8
) (i32.sub
(if (i32.add
(i32.le_u (get_local $0)
(get_local $2) (get_local $2)
(i32.const 8) )
(i32.const 4)
)
(get_local $1)
) )
(return (br_if $folding-inner0
(get_local $3) (i32.le_u
(get_local $2)
(i32.const 8)
)
) )
) (i32.store
(i32.store (tee_local $0
(tee_local $0 (i32.add
(get_local $0)
(tee_local $5
(i32.and
(i32.sub
(i32.const 0)
(get_local $0)
)
(i32.const 3)
)
)
)
)
(tee_local $1
(i32.mul
(get_local $1)
(i32.const 16843009)
)
)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(tee_local $2
(i32.and
(i32.sub
(get_local $2)
(get_local $5)
)
(i32.const -4)
)
)
)
(i32.const 4)
)
(get_local $1)
)
(br_if $folding-inner0
(i32.le_u
(get_local $2)
(i32.const 8)
)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 4)
)
(get_local $1)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 8)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 12)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 8)
)
(get_local $1)
)
(br_if $folding-inner0
(i32.le_u
(get_local $2)
(i32.const 24)
)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 12)
)
(get_local $1)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 16)
)
(get_local $1)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 20)
)
(get_local $1)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 24)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 28)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 24)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 20)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 16)
)
(get_local $1)
)
(set_local $0
(i32.add (i32.add
(get_local $0) (get_local $0)
(tee_local $5 (tee_local $5
(i32.and (i32.add
(i32.sub (i32.and
(i32.const 0)
(get_local $0) (get_local $0)
(i32.const 4)
) )
(i32.const 3) (i32.const 24)
) )
) )
) )
) )
(tee_local $1 (set_local $2
(i32.mul (i32.sub
(get_local $1)
(i32.const 16843009)
)
)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(tee_local $2
(i32.and
(i32.sub
(get_local $2)
(get_local $5)
)
(i32.const -4)
)
)
)
(i32.const 4)
)
(get_local $1)
)
(if
(i32.le_u
(get_local $2)
(i32.const 8)
)
(return
(get_local $3)
)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 4)
)
(get_local $1)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 8)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2) (get_local $2)
) (get_local $5)
(i32.const 12)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 8)
)
(get_local $1)
)
(if
(i32.le_u
(get_local $2)
(i32.const 24)
)
(return
(get_local $3)
)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 12)
)
(get_local $1)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 16)
)
(get_local $1)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 20)
)
(get_local $1)
)
(i32.store
(i32.add
(get_local $0)
(i32.const 24)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 28)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 24)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 20)
)
(get_local $1)
)
(i32.store
(i32.sub
(i32.add
(get_local $0)
(get_local $2)
)
(i32.const 16)
)
(get_local $1)
)
(set_local $0
(i32.add
(get_local $0)
(tee_local $5
(i32.add
(i32.and
(get_local $0)
(i32.const 4)
)
(i32.const 24)
)
) )
) )
) (set_local $4
(set_local $2 (i64.or
(i32.sub
(get_local $2)
(get_local $5)
)
)
(set_local $4
(i64.or
(i64.extend_u/i32
(get_local $1)
)
(i64.shl
(i64.extend_u/i32 (i64.extend_u/i32
(get_local $1) (get_local $1)
) )
(i64.const 32) (i64.shl
(i64.extend_u/i32
(get_local $1)
)
(i64.const 32)
)
) )
) )
) (loop $continue|0
(loop $continue|0 (if
(if (i32.ge_u
(i32.ge_u (get_local $2)
(get_local $2) (i32.const 32)
(i32.const 32) )
) (block
(block (i64.store
(i64.store (get_local $0)
(get_local $0) (get_local $4)
(get_local $4) )
) (i64.store
(i64.store (i32.add
(i32.add (get_local $0)
(get_local $0) (i32.const 8)
(i32.const 8) )
) (get_local $4)
(get_local $4) )
) (i64.store
(i64.store (i32.add
(i32.add (get_local $0)
(get_local $0) (i32.const 16)
(i32.const 16) )
) (get_local $4)
(get_local $4) )
) (i64.store
(i64.store (i32.add
(i32.add (get_local $0)
(get_local $0) (i32.const 24)
(i32.const 24) )
) (get_local $4)
(get_local $4) )
) (set_local $2
(set_local $2 (i32.sub
(i32.sub (get_local $2)
(get_local $2) (i32.const 32)
(i32.const 32) )
) )
) (set_local $0
(set_local $0 (i32.add
(i32.add (get_local $0)
(get_local $0) (i32.const 32)
(i32.const 32) )
) )
) (br $continue|0)
(br $continue|0) )
) )
) )
(return
(get_local $3)
)
) )
(get_local $3) (get_local $3)
) )

View File

@ -11,10 +11,8 @@
(local $4 i32) (local $4 i32)
(local $5 i32) (local $5 i32)
(local $6 i64) (local $6 i64)
(block (set_local $3
(set_local $3 (get_local $0)
(get_local $0)
)
) )
(if (if
(i32.eqz (i32.eqz
@ -116,15 +114,13 @@
(get_local $3) (get_local $3)
) )
) )
(block (set_local $4
(set_local $4 (i32.and
(i32.and (i32.sub
(i32.sub (i32.const 0)
(i32.const 0) (get_local $0)
(get_local $0)
)
(i32.const 3)
) )
(i32.const 3)
) )
) )
(set_local $0 (set_local $0
@ -148,18 +144,16 @@
) )
) )
) )
(block (set_local $5
(set_local $5 (i32.mul
(i32.mul (i32.div_u
(i32.div_u (i32.sub
(i32.sub (i32.const 0)
(i32.const 0) (i32.const 1)
(i32.const 1)
)
(i32.const 255)
) )
(get_local $1) (i32.const 255)
) )
(get_local $1)
) )
) )
(i32.store (i32.store
@ -317,18 +311,16 @@
(get_local $4) (get_local $4)
) )
) )
(block (set_local $6
(set_local $6 (i64.or
(i64.or (i64.extend_u/i32
(get_local $5)
)
(i64.shl
(i64.extend_u/i32 (i64.extend_u/i32
(get_local $5) (get_local $5)
) )
(i64.shl (i64.const 32)
(i64.extend_u/i32
(get_local $5)
)
(i64.const 32)
)
) )
) )
) )

View File

@ -1,24 +0,0 @@
(module
(type $i (func (result i32)))
(type $v (func))
(global $namespace/Outer.Inner.aVar (mut i32) (i32.const 0))
(memory $0 1)
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(drop
(block (result i32)
(block $__inlined_func$namespace/Outer.Inner.aFunc (result i32)
(get_global $namespace/Outer.Inner.aVar)
)
)
)
(drop
(block (result i32)
(block $__inlined_func$namespace/Joined.anotherFunc (result i32)
(i32.const 3)
)
)
)
)
)

View File

@ -1,22 +1,9 @@
(module (module
(type $i (func (result i32)))
(type $v (func)) (type $v (func))
(global $namespace/Outer.Inner.aVar (mut i32) (i32.const 0))
(memory $0 1) (memory $0 1)
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $namespace/Outer.Inner.aFunc (; 0 ;) (type $i) (result i32) (func $start (; 0 ;) (type $v)
(get_global $namespace/Outer.Inner.aVar) (nop)
)
(func $namespace/Joined.anotherFunc (; 1 ;) (type $i) (result i32)
(i32.const 3)
)
(func $start (; 2 ;) (type $v)
(drop
(call $namespace/Outer.Inner.aFunc)
)
(drop
(call $namespace/Joined.anotherFunc)
)
) )
) )

View File

@ -593,10 +593,8 @@
(i32.const 255) (i32.const 255)
) )
(block $break|0 (block $break|0
(block (set_local $0
(set_local $0 (i32.const -128)
(i32.const -128)
)
) )
(loop $continue|0 (loop $continue|0
(if (if

View File

@ -0,0 +1,46 @@
(module
(type $v (func))
(memory $0 1)
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(local $0 i32)
(loop $continue|0
(if
(i32.lt_s
(get_local $0)
(i32.const 1)
)
(block
(set_local $0
(i32.add
(get_local $0)
(i32.const 1)
)
)
(br $continue|0)
)
)
)
(set_local $0
(i32.const 0)
)
(loop $continue|1
(if
(i32.lt_s
(get_local $0)
(i32.const 1)
)
(block
(set_local $0
(i32.add
(get_local $0)
(i32.const 1)
)
)
(br $continue|1)
)
)
)
)
)

14
tests/compiler/scoped.ts Normal file
View File

@ -0,0 +1,14 @@
var aGlobal: i32 = 1;
const aConstant: i32 = 3;
let aStartFunctionLocal: i32 = 2;
for (var anotherStartFunctionLocal: i32 = 0; anotherStartFunctionLocal < 1; ++anotherStartFunctionLocal);
for (let aGlobal /* that shadows */: i32 = 0; aGlobal < 1; ++aGlobal)
aGlobal;
{
let /* actually not */ aConstant: i64 = 5;
{
let /* still not */ aConstant: f32 = 10;
}
}

124
tests/compiler/scoped.wast Normal file
View File

@ -0,0 +1,124 @@
(module
(type $v (func))
(global $scoped/aGlobal (mut i32) (i32.const 1))
(global $scoped/aConstant i32 (i32.const 3))
(global $scoped/aStartFunctionLocal (mut i32) (i32.const 2))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(local $0 i32)
(local $1 i32)
(local $2 i64)
(local $3 f32)
(block $break|0
(set_local $0
(i32.const 0)
)
(loop $continue|0
(if
(i32.lt_s
(get_local $0)
(i32.const 1)
)
(block
(nop)
(set_local $0
(i32.add
(get_local $0)
(i32.const 1)
)
)
(br $continue|0)
)
)
)
)
(block $break|1
(set_local $1
(i32.const 0)
)
(loop $continue|1
(if
(i32.lt_s
(get_local $1)
(i32.const 1)
)
(block
(drop
(get_local $1)
)
(set_local $1
(i32.add
(get_local $1)
(i32.const 1)
)
)
(br $continue|1)
)
)
)
)
(block
(set_local $2
(i64.const 5)
)
(block
(set_local $3
(f32.const 10)
)
)
)
)
)
(;
[program.elements]
GLOBAL: NaN
GLOBAL: Infinity
FUNCTION_PROTOTYPE: isNaN
FUNCTION_PROTOTYPE: isFinite
FUNCTION_PROTOTYPE: clz
FUNCTION_PROTOTYPE: ctz
FUNCTION_PROTOTYPE: popcnt
FUNCTION_PROTOTYPE: rotl
FUNCTION_PROTOTYPE: rotr
FUNCTION_PROTOTYPE: abs
FUNCTION_PROTOTYPE: max
FUNCTION_PROTOTYPE: min
FUNCTION_PROTOTYPE: ceil
FUNCTION_PROTOTYPE: floor
FUNCTION_PROTOTYPE: copysign
FUNCTION_PROTOTYPE: nearest
FUNCTION_PROTOTYPE: reinterpret
FUNCTION_PROTOTYPE: sqrt
FUNCTION_PROTOTYPE: trunc
FUNCTION_PROTOTYPE: load
FUNCTION_PROTOTYPE: store
FUNCTION_PROTOTYPE: sizeof
FUNCTION_PROTOTYPE: select
FUNCTION_PROTOTYPE: unreachable
FUNCTION_PROTOTYPE: current_memory
FUNCTION_PROTOTYPE: grow_memory
FUNCTION_PROTOTYPE: changetype
FUNCTION_PROTOTYPE: assert
FUNCTION_PROTOTYPE: i8
FUNCTION_PROTOTYPE: i16
FUNCTION_PROTOTYPE: i32
FUNCTION_PROTOTYPE: i64
FUNCTION_PROTOTYPE: u8
FUNCTION_PROTOTYPE: u16
FUNCTION_PROTOTYPE: u32
FUNCTION_PROTOTYPE: u64
FUNCTION_PROTOTYPE: bool
FUNCTION_PROTOTYPE: f32
FUNCTION_PROTOTYPE: f64
FUNCTION_PROTOTYPE: isize
FUNCTION_PROTOTYPE: usize
GLOBAL: HEAP_BASE
GLOBAL: scoped/aGlobal
GLOBAL: scoped/aConstant
GLOBAL: scoped/aStartFunctionLocal
[program.exports]
;)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -121,10 +121,8 @@
(local $4 i32) (local $4 i32)
(local $5 i32) (local $5 i32)
(local $6 i32) (local $6 i32)
(block (set_local $3
(set_local $3 (get_local $0)
(get_local $0)
)
) )
(nop) (nop)
(block $break|0 (block $break|0
@ -1936,53 +1934,43 @@
(local $7 f64) (local $7 f64)
(local $8 i32) (local $8 i32)
(local $9 i64) (local $9 i64)
(block (set_local $2
(set_local $2 (i64.reinterpret/f64
(i64.reinterpret/f64 (get_local $0)
(get_local $0)
)
) )
) )
(block (set_local $3
(set_local $3 (i64.reinterpret/f64
(i64.reinterpret/f64 (get_local $1)
(get_local $1)
)
) )
) )
(block (set_local $4
(set_local $4 (i32.wrap/i64
(i32.wrap/i64 (i64.and
(i64.and
(i64.shr_u
(get_local $2)
(i64.const 52)
)
(i64.const 2047)
)
)
)
)
(block
(set_local $5
(i32.wrap/i64
(i64.and
(i64.shr_u
(get_local $3)
(i64.const 52)
)
(i64.const 2047)
)
)
)
)
(block
(set_local $6
(i32.wrap/i64
(i64.shr_u (i64.shr_u
(get_local $2) (get_local $2)
(i64.const 63) (i64.const 52)
) )
(i64.const 2047)
)
)
)
(set_local $5
(i32.wrap/i64
(i64.and
(i64.shr_u
(get_local $3)
(i64.const 52)
)
(i64.const 2047)
)
)
)
(set_local $6
(i32.wrap/i64
(i64.shr_u
(get_local $2)
(i64.const 63)
) )
) )
) )
@ -2080,12 +2068,10 @@
) )
(block (block
(block $break|0 (block $break|0
(block (set_local $9
(set_local $9 (i64.shl
(i64.shl (get_local $2)
(get_local $2) (i64.const 12)
(i64.const 12)
)
) )
) )
(loop $continue|0 (loop $continue|0
@ -2414,48 +2400,38 @@
(local $7 f32) (local $7 f32)
(local $8 i32) (local $8 i32)
(local $9 i32) (local $9 i32)
(block (set_local $2
(set_local $2 (i32.reinterpret/f32
(i32.reinterpret/f32 (get_local $0)
(get_local $0)
)
) )
) )
(block (set_local $3
(set_local $3 (i32.reinterpret/f32
(i32.reinterpret/f32 (get_local $1)
(get_local $1)
)
) )
) )
(block (set_local $4
(set_local $4 (i32.and
(i32.and (i32.shr_u
(i32.shr_u
(get_local $2)
(i32.const 23)
)
(i32.const 255)
)
)
)
(block
(set_local $5
(i32.and
(i32.shr_u
(get_local $3)
(i32.const 23)
)
(i32.const 255)
)
)
)
(block
(set_local $6
(i32.and
(get_local $2) (get_local $2)
(i32.const -2147483648) (i32.const 23)
) )
(i32.const 255)
)
)
(set_local $5
(i32.and
(i32.shr_u
(get_local $3)
(i32.const 23)
)
(i32.const 255)
)
)
(set_local $6
(i32.and
(get_local $2)
(i32.const -2147483648)
) )
) )
(if (if
@ -2552,12 +2528,10 @@
) )
(block (block
(block $break|0 (block $break|0
(block (set_local $9
(set_local $9 (i32.shl
(i32.shl (get_local $2)
(get_local $2) (i32.const 9)
(i32.const 9)
)
) )
) )
(loop $continue|0 (loop $continue|0

View File

@ -2159,13 +2159,13 @@
(if (if
(i32.le_s (i32.le_s
(tee_local $3 (tee_local $3
(if (result i32) (select
(get_local $2)
(i32.shl (i32.shl
(get_local $2) (get_local $2)
(i32.const 1) (i32.const 1)
) )
(i32.const 1) (i32.const 1)
(get_local $2)
) )
) )
(i32.load offset=4 (i32.load offset=4
@ -2655,9 +2655,6 @@
(local $1 i32) (local $1 i32)
(local $2 i32) (local $2 i32)
(local $3 i32) (local $3 i32)
(set_local $1
(i32.const 0)
)
(set_local $2 (set_local $2
(i32.sub (i32.sub
(i32.load offset=8 (i32.load offset=8

View File

@ -30,10 +30,8 @@
(i32.const 0) (i32.const 0)
) )
) )
(block (set_local $1
(set_local $1 (current_memory)
(current_memory)
)
) )
(if (if
(i32.gt_u (i32.gt_u
@ -82,10 +80,8 @@
(unreachable) (unreachable)
) )
) )
(block (set_local $4
(set_local $4 (get_global $std:heap/HEAP_OFFSET)
(get_global $std:heap/HEAP_OFFSET)
)
) )
(if (if
(i32.and (i32.and
@ -2220,20 +2216,22 @@
(if (if
(get_local $2) (get_local $2)
(block (block
(i32.store8 (block
(i32.add (i32.store8
(get_local $0) (i32.add
(tee_local $2 (get_local $0)
(i32.sub (tee_local $2
(get_local $2) (i32.sub
(i32.const 1) (get_local $2)
(i32.const 1)
)
) )
) )
) (i32.load8_u
(i32.load8_u (i32.add
(i32.add (get_local $1)
(get_local $1) (get_local $2)
(get_local $2) )
) )
) )
) )
@ -2260,13 +2258,11 @@
) )
(unreachable) (unreachable)
) )
(block (set_local $2
(set_local $2 (call $std:heap/allocate_memory
(call $std:heap/allocate_memory (i32.mul
(i32.mul (get_local $1)
(get_local $1) (i32.const 4)
(i32.const 4)
)
) )
) )
) )
@ -2430,11 +2426,9 @@
(local $3 i32) (local $3 i32)
(local $4 i32) (local $4 i32)
(local $5 i32) (local $5 i32)
(block (set_local $2
(set_local $2 (i32.load offset=4
(i32.load offset=4 (get_local $0)
(get_local $0)
)
) )
) )
(if (if
@ -2445,16 +2439,14 @@
(get_local $2) (get_local $2)
) )
(block (block
(block (set_local $3
(set_local $3 (if (result i32)
(if (result i32) (get_local $2)
(i32.shl
(get_local $2) (get_local $2)
(i32.shl
(get_local $2)
(i32.const 1)
)
(i32.const 1) (i32.const 1)
) )
(i32.const 1)
) )
) )
(if (if
@ -2468,13 +2460,11 @@
) )
(unreachable) (unreachable)
) )
(block (set_local $4
(set_local $4 (call $std:heap/allocate_memory
(call $std:heap/allocate_memory (i32.mul
(i32.mul (get_local $3)
(get_local $3) (i32.const 4)
(i32.const 4)
)
) )
) )
) )
@ -2648,15 +2638,13 @@
) )
(return) (return)
) )
(block (set_local $3
(set_local $3 (i32.and
(i32.and (i32.sub
(i32.sub (i32.const 0)
(i32.const 0) (get_local $0)
(get_local $0)
)
(i32.const 3)
) )
(i32.const 3)
) )
) )
(set_local $0 (set_local $0
@ -2680,18 +2668,16 @@
) )
) )
) )
(block (set_local $4
(set_local $4 (i32.mul
(i32.mul (i32.div_u
(i32.div_u (i32.sub
(i32.sub (i32.const 0)
(i32.const 0) (i32.const 1)
(i32.const 1)
)
(i32.const 255)
) )
(get_local $1) (i32.const 255)
) )
(get_local $1)
) )
) )
(i32.store (i32.store
@ -2845,18 +2831,16 @@
(get_local $3) (get_local $3)
) )
) )
(block (set_local $5
(set_local $5 (i64.or
(i64.or (i64.extend_u/i32
(get_local $4)
)
(i64.shl
(i64.extend_u/i32 (i64.extend_u/i32
(get_local $4) (get_local $4)
) )
(i64.shl (i64.const 32)
(i64.extend_u/i32
(get_local $4)
)
(i64.const 32)
)
) )
) )
) )
@ -2924,12 +2908,10 @@
) )
(unreachable) (unreachable)
) )
(block (set_local $1
(set_local $1 (i32.load
(i32.load (i32.load
(i32.load (get_local $0)
(get_local $0)
)
) )
) )
) )
@ -3010,17 +2992,15 @@
) )
(block (block
(block (block
(block (set_local $3
(set_local $3 (i32.load
(i32.load (i32.add
(i32.add (i32.load
(i32.load (get_local $0)
(get_local $0) )
) (i32.mul
(i32.mul (get_local $1)
(get_local $1) (i32.const 4)
(i32.const 4)
)
) )
) )
) )

View File

@ -30,10 +30,8 @@
(i32.const 0) (i32.const 0)
) )
) )
(block (set_local $1
(set_local $1 (current_memory)
(current_memory)
)
) )
(if (if
(i32.gt_u (i32.gt_u
@ -82,10 +80,8 @@
(unreachable) (unreachable)
) )
) )
(block (set_local $4
(set_local $4 (get_global $std:heap/HEAP_OFFSET)
(get_global $std:heap/HEAP_OFFSET)
)
) )
(if (if
(i32.and (i32.and
@ -210,15 +206,13 @@
) )
(return) (return)
) )
(block (set_local $3
(set_local $3 (i32.and
(i32.and (i32.sub
(i32.sub (i32.const 0)
(i32.const 0) (get_local $0)
(get_local $0)
)
(i32.const 3)
) )
(i32.const 3)
) )
) )
(set_local $0 (set_local $0
@ -242,18 +236,16 @@
) )
) )
) )
(block (set_local $4
(set_local $4 (i32.mul
(i32.mul (i32.div_u
(i32.div_u (i32.sub
(i32.sub (i32.const 0)
(i32.const 0) (i32.const 1)
(i32.const 1)
)
(i32.const 255)
) )
(get_local $1) (i32.const 255)
) )
(get_local $1)
) )
) )
(i32.store (i32.store
@ -407,18 +399,16 @@
(get_local $3) (get_local $3)
) )
) )
(block (set_local $5
(set_local $5 (i64.or
(i64.or (i64.extend_u/i32
(get_local $4)
)
(i64.shl
(i64.extend_u/i32 (i64.extend_u/i32
(get_local $4) (get_local $4)
) )
(i64.shl (i64.const 32)
(i64.extend_u/i32
(get_local $4)
)
(i64.const 32)
)
) )
) )
) )
@ -2574,20 +2564,22 @@
(if (if
(get_local $2) (get_local $2)
(block (block
(i32.store8 (block
(i32.add (i32.store8
(get_local $0) (i32.add
(tee_local $2 (get_local $0)
(i32.sub (tee_local $2
(get_local $2) (i32.sub
(i32.const 1) (get_local $2)
(i32.const 1)
)
) )
) )
) (i32.load8_u
(i32.load8_u (i32.add
(i32.add (get_local $1)
(get_local $1) (get_local $2)
(get_local $2) )
) )
) )
) )

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
(module (module
(type $ii (func (param i32) (result i32))) (type $ii (func (param i32) (result i32)))
(type $iiiv (func (param i32 i32 i32))) (type $iiiv (func (param i32 i32 i32)))
(type $iv (func (param i32)))
(type $iii (func (param i32 i32) (result i32))) (type $iii (func (param i32 i32) (result i32)))
(type $v (func)) (type $v (func))
(global $std:heap/HEAP_OFFSET (mut i32) (i32.const 0)) (global $std:heap/HEAP_OFFSET (mut i32) (i32.const 0))
@ -1970,10 +1969,7 @@
) )
) )
) )
(func $std:heap/free_memory (; 4 ;) (type $iv) (param $0 i32) (func $std:set/Set#add (; 4 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(nop)
)
(func $std:set/Set#add (; 5 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32) (local $2 i32)
(local $3 i32) (local $3 i32)
(if (if
@ -1999,12 +1995,10 @@
(i32.const 1) (i32.const 1)
) )
) )
(tee_local $3 (i32.const 8)
(i32.const 8)
)
(i32.gt_u (i32.gt_u
(get_local $2) (get_local $2)
(get_local $3) (i32.const 8)
) )
) )
) )
@ -2029,7 +2023,7 @@
(i32.const 4) (i32.const 4)
) )
) )
(call $std:heap/free_memory (drop
(i32.load (i32.load
(get_local $0) (get_local $0)
) )
@ -2071,12 +2065,9 @@
) )
(get_local $0) (get_local $0)
) )
(func $std:set/Set#has (; 6 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $std:set/Set#has (; 5 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32) (local $2 i32)
(local $3 i32) (local $3 i32)
(set_local $2
(i32.const 0)
)
(set_local $3 (set_local $3
(i32.load offset=8 (i32.load offset=8
(get_local $0) (get_local $0)
@ -2120,12 +2111,9 @@
) )
(i32.const 0) (i32.const 0)
) )
(func $std:set/Set#delete (; 7 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $std:set/Set#delete (; 6 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32) (local $2 i32)
(local $3 i32) (local $3 i32)
(set_local $2
(i32.const 0)
)
(set_local $3 (set_local $3
(i32.load offset=8 (i32.load offset=8
(get_local $0) (get_local $0)
@ -2223,13 +2211,7 @@
) )
(i32.const 0) (i32.const 0)
) )
(func $std:set/Set#clear (; 8 ;) (type $iv) (param $0 i32) (func $start (; 7 ;) (type $v)
(i32.store offset=8
(get_local $0)
(i32.const 0)
)
)
(func $start (; 9 ;) (type $v)
(set_global $std:heap/HEAP_OFFSET (set_global $std:heap/HEAP_OFFSET
(get_global $HEAP_BASE) (get_global $HEAP_BASE)
) )
@ -2345,8 +2327,9 @@
) )
(unreachable) (unreachable)
) )
(call $std:set/Set#clear (i32.store offset=8
(get_global $std/set/set) (get_global $std/set/set)
(i32.const 0)
) )
(if (if
(call $std:set/Set#get:size (call $std:set/Set#get:size

View File

@ -27,10 +27,8 @@
(i32.const 0) (i32.const 0)
) )
) )
(block (set_local $1
(set_local $1 (current_memory)
(current_memory)
)
) )
(if (if
(i32.gt_u (i32.gt_u
@ -79,10 +77,8 @@
(unreachable) (unreachable)
) )
) )
(block (set_local $4
(set_local $4 (get_global $std:heap/HEAP_OFFSET)
(get_global $std:heap/HEAP_OFFSET)
)
) )
(if (if
(i32.and (i32.and
@ -2217,20 +2213,22 @@
(if (if
(get_local $2) (get_local $2)
(block (block
(i32.store8 (block
(i32.add (i32.store8
(get_local $0) (i32.add
(tee_local $2 (get_local $0)
(i32.sub (tee_local $2
(get_local $2) (i32.sub
(i32.const 1) (get_local $2)
(i32.const 1)
)
) )
) )
) (i32.load8_u
(i32.load8_u (i32.add
(i32.add (get_local $1)
(get_local $1) (get_local $2)
(get_local $2) )
) )
) )
) )
@ -2259,34 +2257,30 @@
) )
) )
(block (block
(block (set_local $4
(set_local $4 (select
(select (tee_local $2
(tee_local $2 (i32.shl
(i32.shl (i32.load offset=4
(i32.load offset=4 (get_local $0)
(get_local $0)
)
(i32.const 1)
) )
(i32.const 1)
) )
(tee_local $3 )
(i32.const 8) (tee_local $3
) (i32.const 8)
(i32.gt_u )
(get_local $2) (i32.gt_u
(get_local $3) (get_local $2)
) (get_local $3)
) )
) )
) )
(block (set_local $5
(set_local $5 (call $std:heap/allocate_memory
(call $std:heap/allocate_memory (i32.mul
(i32.mul (get_local $4)
(get_local $4) (i32.const 4)
(i32.const 4)
)
) )
) )
) )

View File

@ -6,15 +6,36 @@
(export "doSwitchDefaultOmitted" (func $switch/doSwitchDefaultOmitted)) (export "doSwitchDefaultOmitted" (func $switch/doSwitchDefaultOmitted))
(export "memory" (memory $0)) (export "memory" (memory $0))
(func $switch/doSwitch (; 0 ;) (type $ii) (param $0 i32) (result i32) (func $switch/doSwitch (; 0 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $case4|0 (block $case4|0
(block $case2|0 (block $case2|0
(block $case0|0 (if
(block $tablify|0 (i32.ne
(br_table $case2|0 $case0|0 $case4|0 $case4|0 $tablify|0 (tee_local $1
(get_local $0) (get_local $0)
) )
(i32.const 1)
)
(block
(br_if $case2|0
(i32.eqz
(get_local $1)
)
)
(br_if $case4|0
(i32.or
(i32.eq
(get_local $1)
(i32.const 2)
)
(i32.eq
(get_local $1)
(i32.const 3)
)
)
)
(br $case2|0)
) )
(br $case2|0)
) )
(return (return
(i32.const 1) (i32.const 1)
@ -27,18 +48,31 @@
(i32.const 23) (i32.const 23)
) )
(func $switch/doSwitchDefaultFirst (; 1 ;) (type $ii) (param $0 i32) (result i32) (func $switch/doSwitchDefaultFirst (; 1 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $case3|0 (block $case3|0
(block $case1|0 (if
(block $tablify|0 (i32.ne
(br_table $case1|0 $case3|0 $case3|0 $tablify|0 (tee_local $1
(i32.sub (get_local $0)
(get_local $0) )
(i32.const 1) (i32.const 1)
)
(block
(br_if $case3|0
(i32.or
(i32.eq
(get_local $1)
(i32.const 2)
)
(i32.eq
(get_local $1)
(i32.const 3)
)
) )
) )
) (return
(return (i32.const 0)
(i32.const 0) )
) )
) )
(return (return
@ -48,18 +82,31 @@
(i32.const 23) (i32.const 23)
) )
(func $switch/doSwitchDefaultOmitted (; 2 ;) (type $ii) (param $0 i32) (result i32) (func $switch/doSwitchDefaultOmitted (; 2 ;) (type $ii) (param $0 i32) (result i32)
(local $1 i32)
(block $break|0 (block $break|0
(block $case2|0 (block $case2|0
(block $case0|0 (if
(block $tablify|0 (i32.ne
(br_table $case0|0 $case2|0 $case2|0 $tablify|0 (tee_local $1
(i32.sub (get_local $0)
(get_local $0) )
(i32.const 1) (i32.const 1)
)
(block
(br_if $case2|0
(i32.or
(i32.eq
(get_local $1)
(i32.const 2)
)
(i32.eq
(get_local $1)
(i32.const 3)
)
) )
) )
(br $break|0)
) )
(br $break|0)
) )
(return (return
(i32.const 1) (i32.const 1)

View File

@ -1,277 +0,0 @@
(module
(type $ii (func (param i32) (result i32)))
(type $iiv (func (param i32 i32)))
(type $iiiv (func (param i32 i32 i32)))
(type $iiiiv (func (param i32 i32 i32 i32)))
(type $iv (func (param i32)))
(type $v (func))
(memory $0 1)
(export "control$construct" (func $tlsf/control$construct))
(export "memory" (memory $0))
(start $start)
(func $tlsf/fls (; 0 ;) (type $ii) (param $0 i32) (result i32)
(if (result i32)
(get_local $0)
(i32.sub
(i32.const 31)
(i32.clz
(get_local $0)
)
)
(i32.const -1)
)
)
(func $tlsf/ffs (; 1 ;) (type $ii) (param $0 i32) (result i32)
(if (result i32)
(get_local $0)
(i32.ctz
(get_local $0)
)
(i32.const -1)
)
)
(func $tlsf/control$set_block (; 2 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
(if
(i32.ge_u
(get_local $1)
(i32.const 23)
)
(unreachable)
)
(if
(i32.ge_u
(get_local $2)
(i32.const 32)
)
(unreachable)
)
(i32.store
(i32.add
(i32.add
(get_local $0)
(i32.const 112)
)
(i32.mul
(i32.add
(i32.mul
(get_local $1)
(i32.const 32)
)
(get_local $2)
)
(i32.const 4)
)
)
(get_local $3)
)
)
(func $tlsf/control$construct (; 3 ;) (type $iv) (param $0 i32)
(local $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
(local $5 i32)
(local $6 i32)
(local $7 i32)
(local $8 i32)
(local $9 i32)
(local $10 i32)
(local $11 i32)
(block
(block $__inlined_func$tlsf/block$set_next_free
(set_local $3
(get_local $0)
)
(set_local $4
(get_local $0)
)
(i32.store
(i32.add
(get_local $3)
(i32.const 8)
)
(get_local $4)
)
)
)
(block
(block $__inlined_func$tlsf/block$set_prev_free
(set_local $5
(get_local $0)
)
(set_local $6
(get_local $0)
)
(i32.store
(i32.add
(get_local $5)
(i32.const 12)
)
(get_local $6)
)
)
)
(block
(block $__inlined_func$tlsf/control$set_fl_bitmap
(set_local $7
(get_local $0)
)
(set_local $8
(i32.const 0)
)
(i32.store
(i32.add
(get_local $7)
(i32.const 16)
)
(get_local $8)
)
)
)
(set_local $1
(i32.const 0)
)
(loop $continue|0
(if
(i32.lt_u
(get_local $1)
(i32.const 23)
)
(block
(block
(block $__inlined_func$tlsf/control$set_sl_bitmap
(set_local $9
(get_local $0)
)
(set_local $10
(get_local $1)
)
(set_local $11
(i32.const 0)
)
(block
(if
(i32.ge_u
(get_local $10)
(i32.const 23)
)
(unreachable)
)
(i32.store
(i32.add
(i32.add
(get_local $9)
(i32.const 20)
)
(i32.mul
(get_local $10)
(i32.const 4)
)
)
(get_local $11)
)
)
)
)
(set_local $2
(i32.const 0)
)
(loop $continue|1
(if
(i32.lt_u
(get_local $2)
(i32.const 32)
)
(block
(call $tlsf/control$set_block
(get_local $0)
(get_local $1)
(get_local $2)
(get_local $0)
)
(set_local $2
(i32.add
(get_local $2)
(i32.const 1)
)
)
(br $continue|1)
)
)
)
(set_local $1
(i32.add
(get_local $1)
(i32.const 1)
)
)
(br $continue|0)
)
)
)
)
(func $start (; 4 ;) (type $v)
(if
(i32.ne
(call $tlsf/fls
(i32.const 0)
)
(i32.const -1)
)
(unreachable)
)
(if
(call $tlsf/fls
(i32.const 1)
)
(unreachable)
)
(if
(i32.ne
(call $tlsf/fls
(i32.const -2147483640)
)
(i32.const 31)
)
(unreachable)
)
(if
(i32.ne
(call $tlsf/fls
(i32.const 2147483647)
)
(i32.const 30)
)
(unreachable)
)
(if
(i32.ne
(call $tlsf/ffs
(i32.const 0)
)
(i32.const -1)
)
(unreachable)
)
(if
(call $tlsf/ffs
(i32.const 1)
)
(unreachable)
)
(if
(i32.ne
(call $tlsf/ffs
(i32.const -2147483648)
)
(i32.const 31)
)
(unreachable)
)
(call $tlsf/control$construct
(i32.load
(i32.const 4)
)
)
)
)

View File

@ -1,7 +1,5 @@
(module (module
(type $ii (func (param i32) (result i32))) (type $ii (func (param i32) (result i32)))
(type $iiv (func (param i32 i32)))
(type $iiiv (func (param i32 i32 i32)))
(type $iiiiv (func (param i32 i32 i32 i32))) (type $iiiiv (func (param i32 i32 i32 i32)))
(type $iv (func (param i32))) (type $iv (func (param i32)))
(type $v (func)) (type $v (func))
@ -10,8 +8,7 @@
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $tlsf/fls (; 0 ;) (type $ii) (param $0 i32) (result i32) (func $tlsf/fls (; 0 ;) (type $ii) (param $0 i32) (result i32)
(if (result i32) (select
(get_local $0)
(i32.sub (i32.sub
(i32.const 31) (i32.const 31)
(i32.clz (i32.clz
@ -19,67 +16,19 @@
) )
) )
(i32.const -1) (i32.const -1)
(get_local $0)
) )
) )
(func $tlsf/ffs (; 1 ;) (type $ii) (param $0 i32) (result i32) (func $tlsf/ffs (; 1 ;) (type $ii) (param $0 i32) (result i32)
(if (result i32) (select
(get_local $0)
(i32.ctz (i32.ctz
(get_local $0) (get_local $0)
) )
(i32.const -1) (i32.const -1)
(get_local $0)
) )
) )
(func $tlsf/block$set_next_free (; 2 ;) (type $iiv) (param $0 i32) (param $1 i32) (func $tlsf/control$set_block (; 2 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
(i32.store
(i32.add
(get_local $0)
(i32.const 8)
)
(get_local $1)
)
)
(func $tlsf/block$set_prev_free (; 3 ;) (type $iiv) (param $0 i32) (param $1 i32)
(i32.store
(i32.add
(get_local $0)
(i32.const 12)
)
(get_local $1)
)
)
(func $tlsf/control$set_fl_bitmap (; 4 ;) (type $iiv) (param $0 i32) (param $1 i32)
(i32.store
(i32.add
(get_local $0)
(i32.const 16)
)
(get_local $1)
)
)
(func $tlsf/control$set_sl_bitmap (; 5 ;) (type $iiiv) (param $0 i32) (param $1 i32) (param $2 i32)
(if
(i32.ge_u
(get_local $1)
(i32.const 23)
)
(unreachable)
)
(i32.store
(i32.add
(i32.add
(get_local $0)
(i32.const 20)
)
(i32.mul
(get_local $1)
(i32.const 4)
)
)
(get_local $2)
)
)
(func $tlsf/control$set_block (; 6 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
(if (if
(i32.ge_u (i32.ge_u
(get_local $1) (get_local $1)
@ -114,55 +63,92 @@
(get_local $3) (get_local $3)
) )
) )
(func $tlsf/control$construct (; 7 ;) (type $iv) (param $0 i32) (func $tlsf/control$construct (; 3 ;) (type $iv) (param $0 i32)
(local $1 i32) (local $1 i32)
(local $2 i32) (local $2 i32)
(call $tlsf/block$set_next_free (local $3 i32)
(get_local $0) (i32.store
(get_local $0) (i32.add
(tee_local $3
(get_local $0)
)
(i32.const 8)
)
(tee_local $1
(get_local $0)
)
) )
(call $tlsf/block$set_prev_free (i32.store
(get_local $0) (i32.add
(get_local $0) (tee_local $3
(get_local $0)
)
(i32.const 12)
)
(tee_local $1
(get_local $0)
)
) )
(call $tlsf/control$set_fl_bitmap (i32.store
(get_local $0) (i32.add
(i32.const 0) (tee_local $1
) (get_local $0)
(set_local $1 )
(i32.const 16)
)
(i32.const 0) (i32.const 0)
) )
(loop $continue|0 (loop $continue|0
(if (if
(i32.lt_u (i32.lt_u
(get_local $1) (get_local $2)
(i32.const 23) (i32.const 23)
) )
(block (block
(call $tlsf/control$set_sl_bitmap (set_local $3
(get_local $0) (get_local $0)
(get_local $1) )
(if
(i32.ge_u
(tee_local $1
(get_local $2)
)
(i32.const 23)
)
(unreachable)
)
(i32.store
(i32.add
(i32.add
(get_local $3)
(i32.const 20)
)
(i32.mul
(get_local $1)
(i32.const 4)
)
)
(i32.const 0) (i32.const 0)
) )
(set_local $2 (set_local $1
(i32.const 0) (i32.const 0)
) )
(loop $continue|1 (loop $continue|1
(if (if
(i32.lt_u (i32.lt_u
(get_local $2) (get_local $1)
(i32.const 32) (i32.const 32)
) )
(block (block
(call $tlsf/control$set_block (call $tlsf/control$set_block
(get_local $0) (get_local $0)
(get_local $1)
(get_local $2) (get_local $2)
(get_local $1)
(get_local $0) (get_local $0)
) )
(set_local $2 (set_local $1
(i32.add (i32.add
(get_local $2) (get_local $1)
(i32.const 1) (i32.const 1)
) )
) )
@ -170,9 +156,9 @@
) )
) )
) )
(set_local $1 (set_local $2
(i32.add (i32.add
(get_local $1) (get_local $2)
(i32.const 1) (i32.const 1)
) )
) )
@ -181,7 +167,7 @@
) )
) )
) )
(func $start (; 8 ;) (type $v) (func $start (; 4 ;) (type $v)
(if (if
(i32.ne (i32.ne
(call $tlsf/fls (call $tlsf/fls

View File

@ -175,10 +175,8 @@
(i32.const 0) (i32.const 0)
) )
(block $break|0 (block $break|0
(block (set_local $1
(set_local $1 (i32.const 0)
(i32.const 0)
)
) )
(loop $continue|0 (loop $continue|0
(if (if
@ -194,10 +192,8 @@
(i32.const 0) (i32.const 0)
) )
(block $break|1 (block $break|1
(block (set_local $2
(set_local $2 (i32.const 0)
(i32.const 0)
)
) )
(loop $continue|1 (loop $continue|1
(if (if

View File

@ -132,9 +132,7 @@
(i32.const 1) (i32.const 1)
) )
) )
(tee_local $0 (get_local $0)
(get_local $0)
)
) )
(block (result i32) (block (result i32)
(set_global $while/m (set_global $while/m