Add a mechanism to enable additional (experimental) features and start with sign extension operations; Hashing experimentation

This commit is contained in:
dcodeIO
2018-05-08 00:36:19 +02:00
parent 00fee73022
commit 1bf0ca6525
17 changed files with 2337 additions and 1935 deletions

View File

@ -173,6 +173,8 @@ export class Options {
sourceMap: bool = false;
/** Global aliases. */
globalAliases: Map<string,string> | null = null;
/** Additional features to activate. */
features: Feature = Feature.NONE;
/** Tests if the target is WASM64 or, otherwise, WASM32. */
get isWasm64(): bool {
@ -193,6 +195,19 @@ export class Options {
get nativeSizeType(): NativeType {
return this.target == Target.WASM64 ? NativeType.I64 : NativeType.I32;
}
/** Tests if a specific feature is activated. */
hasFeature(feature: Feature): bool {
return (this.features & feature) != 0;
}
}
/** Indicates specific features to activate. */
export const enum Feature {
/** No additional features. */
NONE = 0,
/** Sign extension operations. */
SIGNEXT = 1 << 0 // see: https://github.com/WebAssembly/sign-extension-ops
}
/** Indicates the desired kind of a conversion. */
@ -237,11 +252,11 @@ export class Compiler extends DiagnosticEmitter {
/** Counting memory offset. */
memoryOffset: I64;
/** Memory segments being compiled. */
memorySegments: MemorySegment[] = new Array();
memorySegments: MemorySegment[] = [];
/** Map of already compiled static string segments. */
stringSegments: Map<string,MemorySegment> = new Map();
/** Function table being compiled. */
functionTable: Function[] = new Array();
functionTable: Function[] = [];
/** Argument count helper global. */
argcVar: GlobalRef = 0;
/** Argument count helper setter. */
@ -802,7 +817,7 @@ export class Compiler extends DiagnosticEmitter {
);
if (!instance) return null;
instance.outerScope = outerScope;
if (!this.compileFunction(instance)) return null;
if (!this.compileFunction(instance)) return null; // reports
return instance;
}
@ -868,7 +883,7 @@ export class Compiler extends DiagnosticEmitter {
var module = this.module;
if (body) {
let isConstructor = instance.is(CommonFlags.CONSTRUCTOR);
let returnType: Type = instance.signature.returnType;
let returnType = instance.signature.returnType;
// compile body
let previousFunction = this.currentFunction;
@ -886,6 +901,7 @@ export class Compiler extends DiagnosticEmitter {
);
flow.set(FlowFlags.RETURNS);
if (!flow.canOverflow(stmt, returnType)) flow.set(FlowFlags.RETURNS_WRAPPED);
flow.finalize();
} else {
assert(body.kind == NodeKind.BLOCK);
stmt = this.compileStatement(body);
@ -1179,6 +1195,7 @@ export class Compiler extends DiagnosticEmitter {
compileClass(instance: Class): bool {
if (instance.is(CommonFlags.COMPILED)) return true;
instance.set(CommonFlags.COMPILED);
var staticMembers = instance.prototype.members;
if (staticMembers) {
for (let element of staticMembers.values()) {
@ -6792,27 +6809,31 @@ export class Compiler extends DiagnosticEmitter {
var module = this.module;
var flow = this.currentFunction.flow;
switch (type.kind) {
case TypeKind.I8: { // TODO: Use 'i32.extend8_s' once sign-extension-ops lands
case TypeKind.I8: {
if (flow.canOverflow(expr, type)) {
expr = module.createBinary(BinaryOp.ShrI32,
module.createBinary(BinaryOp.ShlI32,
expr,
module.createI32(24)
),
module.createI32(24)
);
expr = this.options.hasFeature(Feature.SIGNEXT)
? module.createUnary(UnaryOp.ExtendI8ToI32, expr)
: module.createBinary(BinaryOp.ShrI32,
module.createBinary(BinaryOp.ShlI32,
expr,
module.createI32(24)
),
module.createI32(24)
);
}
break;
}
case TypeKind.I16: { // TODO: Use 'i32.extend16_s' once sign-extension-ops lands
case TypeKind.I16: {
if (flow.canOverflow(expr, type)) {
expr = module.createBinary(BinaryOp.ShrI32,
module.createBinary(BinaryOp.ShlI32,
expr,
module.createI32(16)
),
module.createI32(16)
);
expr = this.options.hasFeature(Feature.SIGNEXT)
? module.createUnary(UnaryOp.ExtendI16ToI32, expr)
: module.createBinary(BinaryOp.ShrI32,
module.createBinary(BinaryOp.ShlI32,
expr,
module.createI32(16)
),
module.createI32(16)
);
}
break;
}

View File

@ -115,6 +115,11 @@ declare function _BinaryenPromoteFloat32(): BinaryenOp;
declare function _BinaryenDemoteFloat64(): BinaryenOp;
declare function _BinaryenReinterpretInt32(): BinaryenOp;
declare function _BinaryenReinterpretInt64(): BinaryenOp;
declare function _BinaryenExtendS8Int32(): BinaryenOp;
declare function _BinaryenExtendS16Int32(): BinaryenOp;
declare function _BinaryenExtendS8Int64(): BinaryenOp;
declare function _BinaryenExtendS16Int64(): BinaryenOp;
declare function _BinaryenExtendS32Int64(): BinaryenOp;
declare function _BinaryenAddInt32(): BinaryenOp;
declare function _BinaryenSubInt32(): BinaryenOp;
declare function _BinaryenMulInt32(): BinaryenOp;

View File

@ -6,7 +6,8 @@
import {
Compiler,
Options,
Target
Target,
Feature
} from "./compiler";
import {
@ -129,6 +130,14 @@ export function setGlobalAlias(options: Options, name: string, alias: string): v
globalAliases.set(name, alias);
}
/** Sign extension operations. */
export const FEATURE_SIGNEXT = Feature.SIGNEXT;
/** Enables a specific feature. */
export function enableFeature(options: Options, feature: Feature): void {
options.features |= feature;
}
/** Finishes parsing. */
export function finishParsing(parser: Parser): Program {
return parser.finish();

View File

@ -104,14 +104,14 @@ export enum UnaryOp {
PromoteF32 = _BinaryenPromoteFloat32(),
DemoteF64 = _BinaryenDemoteFloat64(),
ReinterpretI32 = _BinaryenReinterpretInt32(),
ReinterpretI64 = _BinaryenReinterpretInt64()
ReinterpretI64 = _BinaryenReinterpretInt64(),
// see: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#new-sign-extending-operators
// ExtendI8ToI32 =_BinaryenExtendS8Int32()
// ExtendI16ToI32 = _BinaryenExtendS16Int32()
// ExtendI8ToI64 = _BinaryenExtendS8Int64() // operand is I64
// ExtendI16ToI64 = _BinaryenExtendS16Int64()
// ExtendI32ToI64 = _BinaryenExtendS32Int64()
// see: https://github.com/WebAssembly/sign-extension-ops
ExtendI8ToI32 = _BinaryenExtendS8Int32(),
ExtendI16ToI32 = _BinaryenExtendS16Int32(),
ExtendI8ToI64 = _BinaryenExtendS8Int64(),
ExtendI16ToI64 = _BinaryenExtendS16Int64(),
ExtendI32ToI64 = _BinaryenExtendS32Int64()
// see: https://github.com/WebAssembly/nontrapping-float-to-int-conversions
// TruncF32ToI32Sat

View File

@ -505,7 +505,7 @@ export class Signature {
var parameterNames = this.parameterNames;
return parameterNames && parameterNames.length > index
? parameterNames[index]
: getGenericParameterName(index);
: getDefaultParameterName(index);
}
/** Tests if a value of this function type is assignable to a target of the specified function type. */
@ -581,7 +581,7 @@ export class Signature {
if (index) sb.push(", ");
if (i == restIndex) sb.push("...");
if (i < numNames) sb.push((<string[]>names)[i]);
else sb.push(getGenericParameterName(i));
else sb.push(getDefaultParameterName(i));
if (i >= optionalStart && i != restIndex) sb.push("?: ");
else sb.push(": ");
sb.push(parameters[i].toString());
@ -595,14 +595,14 @@ export class Signature {
// helpers
// Cached generic parameter names used where names are unknown.
var cachedGenericParameterNames: string[] | null = null;
// Cached default parameter names used where names are unknown.
var cachedDefaultParameterNames: string[] | null = null;
/** Gets the cached generic parameter name for the specified index. */
export function getGenericParameterName(index: i32): string {
if (!cachedGenericParameterNames) cachedGenericParameterNames = [];
for (let i = cachedGenericParameterNames.length; i <= index; ++i) {
cachedGenericParameterNames.push("arg$" + i.toString(10));
/** Gets the cached default parameter name for the specified index. */
export function getDefaultParameterName(index: i32): string {
if (!cachedDefaultParameterNames) cachedDefaultParameterNames = [];
for (let i = cachedDefaultParameterNames.length; i <= index; ++i) {
cachedDefaultParameterNames.push("arg$" + i.toString(10));
}
return cachedGenericParameterNames[index - 1];
return cachedDefaultParameterNames[index - 1];
}