Make the transition to ArrayBuffer backed Arrays (#70)

* Traverse base classes when resolving overloads
* Implement preliminary TypedArray accessors
* Extract decorator flags from common flags to make space
* Add '**' overload
* Implement basic explicit inlining
* Support inlining of instance methods
* Reduce number of required locals when inlining
* Implement inlining of operator overloads
* Fix issues when inlining generic functions
This commit is contained in:
Daniel Wirtz
2018-04-11 23:35:19 +02:00
committed by GitHub
parent 0f49e054d2
commit 623597c23a
44 changed files with 13242 additions and 4945 deletions

View File

@ -198,32 +198,9 @@ export abstract class Node {
stmt.range = range;
stmt.name = expression; expression.parent = stmt;
stmt.arguments = args; if (args) setParent(args, stmt);
if (expression.kind == NodeKind.IDENTIFIER) {
switch ((<IdentifierExpression>expression).text) {
case "global": {
stmt.decoratorKind = DecoratorKind.GLOBAL;
break;
}
case "operator": {
stmt.decoratorKind = DecoratorKind.OPERATOR;
break;
}
case "unmanaged": {
stmt.decoratorKind = DecoratorKind.UNMANAGED;
break;
}
case "offset": {
stmt.decoratorKind = DecoratorKind.OFFSET;
break;
}
default: {
stmt.decoratorKind = DecoratorKind.CUSTOM;
break;
}
}
} else {
stmt.decoratorKind = DecoratorKind.CUSTOM;
}
stmt.decoratorKind = expression.kind == NodeKind.IDENTIFIER
? stringToDecoratorKind((<IdentifierExpression>expression).text)
: DecoratorKind.CUSTOM;
return stmt;
}
@ -1075,7 +1052,22 @@ export enum DecoratorKind {
GLOBAL,
OPERATOR,
UNMANAGED,
OFFSET
SEALED,
INLINE,
PRECOMPUTE
}
/** Returns the decorator kind represented by the specified string. */
export function stringToDecoratorKind(str: string): DecoratorKind {
switch (str) {
case "global": return DecoratorKind.GLOBAL;
case "operator": return DecoratorKind.OPERATOR;
case "unmanaged": return DecoratorKind.UNMANAGED;
case "sealed": return DecoratorKind.SEALED;
case "inline": return DecoratorKind.INLINE;
case "precompute": return DecoratorKind.PRECOMPUTE;
default: return DecoratorKind.CUSTOM;
}
}
/** Represents a decorator. */

View File

@ -43,7 +43,8 @@ import {
Global,
FunctionPrototype,
Class,
Field
Field,
OperatorKind
} from "./program";
/** Compiles a get of a built-in global. */
@ -146,7 +147,7 @@ export function compileCall(
compiler.currentType = Type.bool;
if (!type) return module.createUnreachable();
let classType = type.classReference;
return classType != null && classType.prototype.fnIndexedGet != null
return classType != null && classType.lookupOverload(OperatorKind.INDEXED_GET) != null
? module.createI32(1)
: module.createI32(0);
}
@ -1738,6 +1739,7 @@ export function compileCall(
DiagnosticCode.Expected_0_type_arguments_but_got_1,
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
);
return module.createUnreachable();
}
let byteSize = (<Type[]>typeArguments)[0].byteSize;
let alignLog2: i32;

File diff suppressed because it is too large Load Diff

View File

@ -16,11 +16,13 @@ export enum DiagnosticCode {
Basic_type_0_cannot_be_nullable = 204,
Cannot_export_a_mutable_global = 205,
Compiling_constant_with_non_constant_initializer_as_mutable = 206,
Structs_cannot_extend_classes_and_vice_versa = 207,
Structs_cannot_implement_interfaces = 208,
Unmanaged_classes_cannot_extend_managed_classes_and_vice_versa = 207,
Unmanaged_classes_cannot_implement_interfaces = 208,
Invalid_regular_expression_flags = 209,
Implementation_0_must_match_the_signature_1 = 210,
Class_0_is_sealed_and_cannot_be_extended = 211,
Decorator_0_is_not_valid_here = 212,
Duplicate_decorator = 213,
Unterminated_string_literal = 1002,
Identifier_expected = 1003,
_0_expected = 1005,
@ -122,11 +124,13 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 204: return "Basic type '{0}' cannot be nullable.";
case 205: return "Cannot export a mutable global.";
case 206: return "Compiling constant with non-constant initializer as mutable.";
case 207: return "Structs cannot extend classes and vice-versa.";
case 208: return "Structs cannot implement interfaces.";
case 207: return "Unmanaged classes cannot extend managed classes and vice-versa.";
case 208: return "Unmanaged classes cannot implement interfaces.";
case 209: return "Invalid regular expression flags.";
case 210: return "Implementation '{0}' must match the signature '{1}'.";
case 211: return "Class '{0}' is sealed and cannot be extended.";
case 212: return "Decorator '{0}' is not valid here.";
case 213: return "Duplicate decorator.";
case 1002: return "Unterminated string literal.";
case 1003: return "Identifier expected.";
case 1005: return "'{0}' expected.";

View File

@ -8,11 +8,13 @@
"Basic type '{0}' cannot be nullable.": 204,
"Cannot export a mutable global.": 205,
"Compiling constant with non-constant initializer as mutable.": 206,
"Structs cannot extend classes and vice-versa.": 207,
"Structs cannot implement interfaces.": 208,
"Unmanaged classes cannot extend managed classes and vice-versa.": 207,
"Unmanaged classes cannot implement interfaces.": 208,
"Invalid regular expression flags.": 209,
"Implementation '{0}' must match the signature '{1}'.": 210,
"Class '{0}' is sealed and cannot be extended.": 211,
"Decorator '{0}' is not valid here.": 212,
"Duplicate decorator.": 213,
"Unterminated string literal.": 1002,
"Identifier expected.": 1003,

View File

@ -206,12 +206,8 @@ export function formatDiagnosticContext(range: Range, useColors: bool = false):
var len = text.length;
var start = range.start;
var end = range.end;
while (start > 0 && !isLineBreak(text.charCodeAt(start - 1))) {
start--;
}
while (end < len && !isLineBreak(text.charCodeAt(end))) {
end++;
}
while (start > 0 && !isLineBreak(text.charCodeAt(start - 1))) start--;
while (end < len && !isLineBreak(text.charCodeAt(end))) end++;
var sb: string[] = [
"\n ",
text.substring(start, end),
@ -225,9 +221,7 @@ export function formatDiagnosticContext(range: Range, useColors: bool = false):
if (range.start == range.end) {
sb.push("^");
} else {
while (start++ < range.end) {
sb.push("~");
}
while (start++ < range.end) sb.push("~");
}
if (useColors) sb.push(COLOR_RESET);
return sb.join("");

View File

@ -75,7 +75,8 @@ import {
ParameterNode,
ParameterKind,
ExportMember,
SwitchCase
SwitchCase,
DeclarationStatement
} from "../ast";
import {
@ -912,7 +913,6 @@ export class ASTBuilder {
}
visitFieldDeclaration(node: FieldDeclaration): void {
this.serializeBuiltinDecorators(node);
var decorators = node.decorators;
if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) {
@ -961,7 +961,6 @@ export class ASTBuilder {
visitFunctionDeclaration(node: FunctionDeclaration): void {
var sb = this.sb;
this.serializeBuiltinDecorators(node);
var decorators = node.decorators;
if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) {
@ -1098,7 +1097,6 @@ export class ASTBuilder {
}
visitInterfaceDeclaration(node: InterfaceDeclaration): void {
this.serializeBuiltinDecorators(node);
var decorators = node.decorators;
if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) {
@ -1138,7 +1136,6 @@ export class ASTBuilder {
}
visitMethodDeclaration(node: MethodDeclaration): void {
this.serializeBuiltinDecorators(node);
var decorators = node.decorators;
if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) {
@ -1155,7 +1152,6 @@ export class ASTBuilder {
}
visitNamespaceDeclaration(node: NamespaceDeclaration): void {
this.serializeBuiltinDecorators(node);
var decorators = node.decorators;
if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) {
@ -1315,7 +1311,6 @@ export class ASTBuilder {
}
visitVariableStatement(node: VariableStatement): void {
this.serializeBuiltinDecorators(node);
var decorators = node.decorators;
if (decorators) {
for (let i = 0, k = decorators.length; i < k; ++i) {
@ -1398,19 +1393,6 @@ export class ASTBuilder {
}
}
serializeBuiltinDecorators(node: Node): void {
var sb = this.sb;
var indentLevel = this.indentLevel;
if (node.is(CommonFlags.GLOBAL)) {
sb.push("@global\n");
indent(sb, indentLevel);
}
if (node.is(CommonFlags.UNMANAGED)) {
sb.push("@unmanaged\n");
indent(sb, indentLevel);
}
}
serializeExternalModifiers(node: Node): void {
var sb = this.sb;
if (node.is(CommonFlags.EXPORT)) {

View File

@ -1099,6 +1099,45 @@ export class Relooper {
}
}
// export function hasSideEffects(expr: ExpressionRef): bool {
// switch (_BinaryenExpressionGetId(expr)) {
// case ExpressionId.GetLocal:
// case ExpressionId.GetGlobal:
// case ExpressionId.Const:
// case ExpressionId.Nop:
// case ExpressionId.Unreachable: {
// return false;
// }
// case ExpressionId.Block: {
// for (let i = 0, k = _BinaryenBlockGetNumChildren(expr); i < k; ++i) {
// if (hasSideEffects(_BinaryenBlockGetChild(expr, i))) return true;
// }
// return false;
// }
// case ExpressionId.If: {
// return hasSideEffects(_BinaryenIfGetCondition(expr))
// || hasSideEffects(_BinaryenIfGetIfTrue(expr))
// || hasSideEffects(_BinaryenIfGetIfFalse(expr));
// }
// case ExpressionId.Unary: {
// return hasSideEffects(_BinaryenUnaryGetValue(expr));
// }
// case ExpressionId.Binary: {
// return hasSideEffects(_BinaryenBinaryGetLeft(expr))
// || hasSideEffects(_BinaryenBinaryGetRight(expr));
// }
// case ExpressionId.Drop: {
// return hasSideEffects(_BinaryenDropGetValue(expr));
// }
// case ExpressionId.Select: {
// return hasSideEffects(_BinaryenSelectGetIfTrue(expr))
// || hasSideEffects(_BinaryenSelectGetIfFalse(expr))
// || hasSideEffects(_BinaryenSelectGetCondition(expr));
// }
// }
// return true;
// }
// helpers
// can't do stack allocation here: STACKTOP is a global in WASM but a hidden variable in asm.js

View File

@ -27,7 +27,6 @@ import {
} from "./util";
import {
Node,
NodeKind,
Source,
@ -162,22 +161,9 @@ export class Parser extends DiagnosticEmitter {
while (tn.skip(Token.AT)) {
if (startPos < 0) startPos = tn.tokenPos;
let decorator = this.parseDecorator(tn);
if (!decorator) break;
let name = decorator.name;
if (name.kind == NodeKind.IDENTIFIER) {
let text = (<IdentifierExpression>name).text;
if (text == "global") {
flags |= CommonFlags.GLOBAL;
continue;
}
if (text == "unmananged") {
flags |= CommonFlags.UNMANAGED;
continue;
}
if (text == "sealed") {
flags |= CommonFlags.SEALED;
continue;
}
if (!decorator) {
this.skipStatement(tn);
continue;
}
if (!decorators) decorators = [];
decorators.push(decorator);

File diff suppressed because it is too large Load Diff

View File

@ -166,7 +166,7 @@ export enum Token {
ENDOFFILE
}
export function tokenFomKeyword(text: string): Token {
export function tokenFromKeyword(text: string): Token {
switch (text) {
case "abstract": return Token.ABSTRACT;
case "as": return Token.AS;
@ -805,7 +805,7 @@ export class Tokenizer extends DiagnosticEmitter {
}
}
let keywordText = text.substring(posBefore, this.pos);
let keywordToken = tokenFomKeyword(keywordText);
let keywordToken = tokenFromKeyword(keywordText);
if (
keywordToken != Token.INVALID &&
!(preferIdentifier && tokenIsAlsoIdentifier(keywordToken))

View File

@ -80,7 +80,9 @@ export const enum TypeFlags {
/** Is a reference type. */
REFERENCE = 1 << 8,
/** Is a nullable type. */
NULLABLE = 1 << 9
NULLABLE = 1 << 9,
/** Is the special 'this' type. */
THIS = 1 << 10
}
/** Represents a resolved type. */
@ -102,6 +104,8 @@ export class Type {
nullableType: Type | null = null;
/** Respective non-nullable type, if nullable. */
nonNullableType: Type;
/** Respective special 'this' type. */
thisType: Type | null = null;
/** Constructs a new resolved type. */
constructor(kind: TypeKind, flags: TypeFlags, size: i32) {
@ -157,6 +161,18 @@ export class Type {
return this.nullableType;
}
/** Composes the respective 'this' type of this type. */
asThis(): Type {
var thisType = this.thisType;
if (thisType) return thisType;
thisType = new Type(this.kind, this.flags | TypeFlags.THIS, this.size);
thisType.classReference = this.classReference;
thisType.nullableType = this.nullableType;
thisType.nonNullableType = this.nonNullableType;
this.thisType = thisType;
return thisType;
}
/** Tests if a value of this type is assignable to a target of the specified type. */
isAssignableTo(target: Type, signednessIsImportant: bool = false): bool {
var currentClass: Class | null;