Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@
"prepublishOnly": "node scripts/prepublish",
"postpublish": "node scripts/postpublish",
"asbuild": "npm run asbuild:untouched && npm run asbuild:optimized",
"asbuild:untouched": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.untouched.wat -b out/assemblyscript.untouched.wasm -d out/assemblyscript.d.ts --validate --debug --measure",
"asbuild:optimized": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.optimized.wat -b out/assemblyscript.optimized.wasm -O3 --validate --measure",
"asbuild:untouched": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.untouched.wat -b out/assemblyscript.untouched.wasm -d out/assemblyscript.d.ts --validate --debug --measure --runtime stub",
"asbuild:optimized": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.optimized.wat -b out/assemblyscript.optimized.wasm -O3 --validate --measure --runtime stub",
"astest": "ts-node tests/bootstrap"
},
"releaseFiles": [
Expand Down
10 changes: 10 additions & 0 deletions src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,16 @@ export abstract class Node {
}
return false;
}

/** Checks if this is a call calling a method on super. */
get isCallOnSuper(): bool {
if (this.kind != NodeKind.CALL) return false;
var expression = changetype<CallExpression>(this).expression;
if (expression.kind != NodeKind.PROPERTYACCESS) return false;
var target = (<PropertyAccessExpression>expression).expression;
if (target.kind == NodeKind.SUPER) return true;
return false;
}
}

// types
Expand Down
400 changes: 297 additions & 103 deletions src/compiler.ts

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions src/diagnosticMessages.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ export enum DiagnosticCode {
_0_is_not_a_valid_operator = 224,
Expression_cannot_be_represented_by_a_type = 225,
Expression_resolves_to_unusual_type_0 = 226,
Function_0_is_virtual_and_will_not_be_inlined = 227,
Property_0_only_has_a_setter_and_is_missing_a_getter = 228,
_0_keyword_cannot_be_used_here = 229,
Type_0_is_cyclic_Module_will_include_deferred_garbage_collection = 900,
Importing_the_table_disables_some_indirect_call_optimizations = 901,
Exporting_the_table_disables_some_indirect_call_optimizations = 902,
Expand Down Expand Up @@ -107,6 +110,7 @@ export enum DiagnosticCode {
Duplicate_identifier_0 = 2300,
Cannot_find_name_0 = 2304,
Module_0_has_no_exported_member_1 = 2305,
An_interface_can_only_extend_an_interface = 2312,
Generic_type_0_requires_1_type_argument_s = 2314,
Type_0_is_not_generic = 2315,
Type_0_is_not_assignable_to_type_1 = 2322,
Expand All @@ -123,19 +127,25 @@ export enum DiagnosticCode {
Operator_0_cannot_be_applied_to_types_1_and_2 = 2365,
A_super_call_must_be_the_first_statement_in_the_constructor = 2376,
Constructors_for_derived_classes_must_contain_a_super_call = 2377,
Getter_and_setter_accessors_do_not_agree_in_visibility = 2379,
_get_and_set_accessor_must_have_the_same_type = 2380,
Overload_signatures_must_all_be_public_private_or_protected = 2385,
Constructor_implementation_is_missing = 2390,
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
Multiple_constructor_implementations_are_not_allowed = 2392,
Duplicate_function_implementation = 2393,
This_overload_signature_is_not_compatible_with_its_implementation_signature = 2394,
Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local = 2395,
A_class_can_only_implement_an_interface = 2422,
A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged = 2434,
The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly = 2453,
Type_0_has_no_property_1 = 2460,
The_0_operator_cannot_be_applied_to_type_1 = 2469,
In_const_enum_declarations_member_initializer_must_be_constant_expression = 2474,
Export_declaration_conflicts_with_exported_declaration_of_0 = 2484,
_0_is_referenced_directly_or_indirectly_in_its_own_base_expression = 2506,
Cannot_create_an_instance_of_an_abstract_class = 2511,
Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_2 = 2515,
Object_is_possibly_null = 2531,
Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property = 2540,
The_target_of_an_assignment_must_be_a_variable_or_a_property_access = 2541,
Expand Down Expand Up @@ -194,6 +204,9 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 224: return "'{0}' is not a valid operator.";
case 225: return "Expression cannot be represented by a type.";
case 226: return "Expression resolves to unusual type '{0}'.";
case 227: return "Function '{0}' is virtual and will not be inlined.";
case 228: return "Property '{0}' only has a setter and is missing a getter.";
case 229: return "'{0}' keyword cannot be used here.";
case 900: return "Type '{0}' is cyclic. Module will include deferred garbage collection.";
case 901: return "Importing the table disables some indirect call optimizations.";
case 902: return "Exporting the table disables some indirect call optimizations.";
Expand Down Expand Up @@ -261,6 +274,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 2300: return "Duplicate identifier '{0}'.";
case 2304: return "Cannot find name '{0}'.";
case 2305: return "Module '{0}' has no exported member '{1}'.";
case 2312: return "An interface can only extend an interface.";
case 2314: return "Generic type '{0}' requires {1} type argument(s).";
case 2315: return "Type '{0}' is not generic.";
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
Expand All @@ -277,19 +291,25 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 2365: return "Operator '{0}' cannot be applied to types '{1}' and '{2}'.";
case 2376: return "A 'super' call must be the first statement in the constructor.";
case 2377: return "Constructors for derived classes must contain a 'super' call.";
case 2379: return "Getter and setter accessors do not agree in visibility.";
case 2380: return "'get' and 'set' accessor must have the same type.";
case 2385: return "Overload signatures must all be public, private or protected.";
case 2390: return "Constructor implementation is missing.";
case 2391: return "Function implementation is missing or not immediately following the declaration.";
case 2392: return "Multiple constructor implementations are not allowed.";
case 2393: return "Duplicate function implementation.";
case 2394: return "This overload signature is not compatible with its implementation signature.";
case 2395: return "Individual declarations in merged declaration '{0}' must be all exported or all local.";
case 2422: return "A class can only implement an interface.";
case 2434: return "A namespace declaration cannot be located prior to a class or function with which it is merged.";
case 2453: return "The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly.";
case 2460: return "Type '{0}' has no property '{1}'.";
case 2469: return "The '{0}' operator cannot be applied to type '{1}'.";
case 2474: return "In 'const' enum declarations member initializer must be constant expression.";
case 2484: return "Export declaration conflicts with exported declaration of '{0}'.";
case 2506: return "'{0}' is referenced directly or indirectly in its own base expression.";
case 2511: return "Cannot create an instance of an abstract class.";
case 2515: return "Non-abstract class '{0}' does not implement inherited abstract member '{1}' from '{2}'.";
case 2531: return "Object is possibly 'null'.";
case 2540: return "Cannot assign to '{0}' because it is a constant or a read-only property.";
case 2541: return "The target of an assignment must be a variable or a property access.";
Expand Down
10 changes: 10 additions & 0 deletions src/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
"'{0}' is not a valid operator.": 224,
"Expression cannot be represented by a type.": 225,
"Expression resolves to unusual type '{0}'.": 226,
"Function '{0}' is virtual and will not be inlined.": 227,
"Property '{0}' only has a setter and is missing a getter.": 228,
"'{0}' keyword cannot be used here.": 229,

"Type '{0}' is cyclic. Module will include deferred garbage collection.": 900,
"Importing the table disables some indirect call optimizations.": 901,
Expand Down Expand Up @@ -103,6 +106,7 @@
"Duplicate identifier '{0}'.": 2300,
"Cannot find name '{0}'.": 2304,
"Module '{0}' has no exported member '{1}'.": 2305,
"An interface can only extend an interface.": 2312,
"Generic type '{0}' requires {1} type argument(s).": 2314,
"Type '{0}' is not generic.": 2315,
"Type '{0}' is not assignable to type '{1}'.": 2322,
Expand All @@ -119,19 +123,25 @@
"Operator '{0}' cannot be applied to types '{1}' and '{2}'.": 2365,
"A 'super' call must be the first statement in the constructor.": 2376,
"Constructors for derived classes must contain a 'super' call.": 2377,
"Getter and setter accessors do not agree in visibility.": 2379,
"'get' and 'set' accessor must have the same type.": 2380,
"Overload signatures must all be public, private or protected.": 2385,
"Constructor implementation is missing.": 2390,
"Function implementation is missing or not immediately following the declaration.": 2391,
"Multiple constructor implementations are not allowed.": 2392,
"Duplicate function implementation.": 2393,
"This overload signature is not compatible with its implementation signature.": 2394,
"Individual declarations in merged declaration '{0}' must be all exported or all local.": 2395,
"A class can only implement an interface.": 2422,
"A namespace declaration cannot be located prior to a class or function with which it is merged.": 2434,
"The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly.": 2453,
"Type '{0}' has no property '{1}'.": 2460,
"The '{0}' operator cannot be applied to type '{1}'.": 2469,
"In 'const' enum declarations member initializer must be constant expression.": 2474,
"Export declaration conflicts with exported declaration of '{0}'.": 2484,
"'{0}' is referenced directly or indirectly in its own base expression.": 2506,
"Cannot create an instance of an abstract class.": 2511,
"Non-abstract class '{0}' does not implement inherited abstract member '{1}' from '{2}'.": 2515,
"Object is possibly 'null'.": 2531,
"Cannot assign to '{0}' because it is a constant or a read-only property.": 2540,
"The target of an assignment must be a variable or a property access.": 2541,
Expand Down
53 changes: 39 additions & 14 deletions src/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class DiagnosticMessage {
/** Respective source range, if any. */
range: Range | null = null;
/** Related range, if any. */
relatedRange: Range | null = null;
relatedRange: Range | null = null; // TODO: Make this a related message for chains?

/** Constructs a new diagnostic message. */
private constructor(code: i32, category: DiagnosticCategory, message: string) {
Expand All @@ -112,6 +112,26 @@ export class DiagnosticMessage {
return new DiagnosticMessage(code, category, message);
}

/** Tests if this message equals the specified. */
equals(other: DiagnosticMessage): bool {
if (this.code != other.code) return false;
var thisRange = this.range;
var otherRange = other.range;
if (thisRange) {
if (!otherRange || !thisRange.equals(otherRange)) return false;
} else if (otherRange) {
return false;
}
var thisRelatedRange = this.relatedRange;
var otherRelatedRange = other.relatedRange;
if (thisRelatedRange) {
if (!otherRelatedRange || !thisRelatedRange.equals(otherRelatedRange)) return false;
} else if (otherRange) {
return false;
}
return this.message == other.message;
}

/** Adds a source range to this message. */
withRange(range: Range): this {
this.range = range;
Expand All @@ -137,10 +157,13 @@ export class DiagnosticMessage {
this.message +
"\" in " +
source.normalizedPath +
":" +
"(" +
source.lineAt(range.start).toString() +
":" +
source.columnAt().toString()
"," +
source.columnAt().toString() +
"+" +
(range.end - range.start).toString() +
")"
);
}
return (
Expand Down Expand Up @@ -248,7 +271,7 @@ export abstract class DiagnosticEmitter {
/** Diagnostic messages emitted so far. */
diagnostics: DiagnosticMessage[];
/** Diagnostic messages already seen, by range. */
private seen: Map<Source,Map<i32,i32[]>> = new Map();
private seen: Map<Source,Map<i32,DiagnosticMessage[]>> = new Map();

/** Initializes this diagnostic emitter. */
protected constructor(diagnostics: DiagnosticMessage[] | null = null) {
Expand All @@ -265,6 +288,9 @@ export abstract class DiagnosticEmitter {
arg1: string | null = null,
arg2: string | null = null
): void {
var message = DiagnosticMessage.create(code, category, arg0, arg1, arg2);
if (range) message = message.withRange(range);
if (relatedRange) message.relatedRange = relatedRange;
// It is possible that the same diagnostic is emitted twice, for example
// when compiling generics with different types or when recompiling a loop
// because our initial assumptions didn't hold. It is even possible to get
Expand All @@ -274,21 +300,20 @@ export abstract class DiagnosticEmitter {
if (seen.has(range.source)) {
let seenInSource = assert(seen.get(range.source));
if (seenInSource.has(range.start)) {
let seenCodesAtPos = assert(seenInSource.get(range.start));
if (seenCodesAtPos.includes(code)) return;
seenCodesAtPos.push(code);
let seenMessagesAtPos = assert(seenInSource.get(range.start));
for (let i = 0, k = seenMessagesAtPos.length; i < k; ++i) {
if (seenMessagesAtPos[i].equals(message)) return;
}
seenMessagesAtPos.push(message);
} else {
seenInSource.set(range.start, [ code ]);
seenInSource.set(range.start, [ message ]);
}
} else {
let seenInSource = new Map<i32,i32[]>();
seenInSource.set(range.start, [ code ]);
let seenInSource = new Map<i32,DiagnosticMessage[]>();
seenInSource.set(range.start, [ message ]);
seen.set(range.source, seenInSource);
}
}
var message = DiagnosticMessage.create(code, category, arg0, arg1, arg2);
if (range) message = message.withRange(range);
if (relatedRange) message.relatedRange = relatedRange;
this.diagnostics.push(message);
// console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary
// console.log(<string>new Error("stack").stack);
Expand Down
95 changes: 92 additions & 3 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1870,14 +1870,13 @@ export function getFunctionResults(func: FunctionRef): NativeType {
return binaryen._BinaryenFunctionGetResults(func);
}

export function getFunctionVars(func: FunctionRef): NativeType {
// TODO: unify this on Binaryen's side?
export function getFunctionVars(func: FunctionRef): NativeType[] {
var count = binaryen._BinaryenFunctionGetNumVars(func);
var types = new Array<NativeType>(count);
for (let i: Index = 0; i < count; ++i) {
types[i] = binaryen._BinaryenFunctionGetVar(func, i);
}
return createType(types);
return types;
}

// globals
Expand Down Expand Up @@ -1963,6 +1962,96 @@ export class Relooper {
}
}

/** Builds a switch using a sequence of `br_if`s. */
export class SwitchBuilder {
// This is useful because Binaryen understands sequences of `br_if`s and
// knows how to make a `br_table` from such a sequence if switched over
// values are considered dense enough, respectively a size-efficient sequence
// of `if`s if not, depending on optimization levels.

private module: Module;
private condition: ExpressionRef;
private values: i32[] = new Array();
private indexes: i32[] = new Array();
private cases: ExpressionRef[][] = new Array();
private defaultIndex: i32 = -1;

/** Creates a new builder using the specified i32 condition. */
constructor(module: Module, condition: ExpressionRef) {
this.module = module;
this.condition = condition;
}

/** Links a case to the specified branch. */
addCase(value: i32, code: ExpressionRef[]): void {
var cases = this.cases;
var index = cases.indexOf(code);
if (index < 0) {
index = cases.length;
cases.push(code);
}
this.values.push(value);
this.indexes.push(index);
}

/** Links the default branch. */
addDefault(code: ExpressionRef[]): void {
assert(this.defaultIndex == -1);
var cases = this.cases;
this.defaultIndex = cases.length;
cases.push(code);
}

/** Renders the switch to a block. */
render(localIndex: i32, labelPostfix: string = ""): ExpressionRef {
var module = this.module;
var cases = this.cases;
var numCases = cases.length;
if (!numCases) {
return module.drop(this.condition);
}
var values = this.values;
var numValues = values.length;
var indexes = this.indexes;
var entry = new Array<ExpressionRef>(1 + numValues + 1);
var labels = new Array<string>(numCases);
for (let i = 0; i < numCases; ++i) {
labels[i] = "case" + i.toString() + labelPostfix;
}
entry[0] = module.local_set(localIndex, this.condition);
for (let i = 0; i < numValues; ++i) {
let index = indexes[i];
entry[1 + i] = module.br(labels[index],
module.binary(BinaryOp.EqI32,
module.local_get(localIndex, NativeType.I32),
module.i32(values[i])
)
);
}
var defaultIndex = this.defaultIndex;
var defaultLabel = "default" + labelPostfix;
entry[1 + numValues] = module.br(
~defaultIndex
? labels[defaultIndex]
: defaultLabel
);
var current = module.block(labels[0], entry);
for (let i = 1; i < numCases; ++i) {
let block = cases[i - 1];
block.unshift(current);
current = module.block(labels[i], block);
}
var lastCase = cases[numCases - 1];
lastCase.unshift(current);
return module.block(
~defaultIndex
? null
: defaultLabel,
lastCase
);
}
}

export enum SideEffects {
None = 0 /* _BinaryenSideEffectNone */,
Branches = 1 /* _BinaryenSideEffectBranches */,
Expand Down
Loading