From 65c799c925f1032c1ece0f8ff51906dbe615dcf6 Mon Sep 17 00:00:00 2001 From: Max Graey Date: Fri, 22 Feb 2019 15:03:33 +0200 Subject: [PATCH] Speedup some compiler routines (#441) --- src/builtins.ts | 40 ++++------- src/compiler.ts | 18 ++--- src/program.ts | 17 ++--- src/tokenizer.ts | 160 ++++++++++++++++++++++--------------------- src/util/charcode.ts | 22 +++--- src/util/path.ts | 12 +++- 6 files changed, 139 insertions(+), 130 deletions(-) diff --git a/src/builtins.ts b/src/builtins.ts index e65d37af..cf785bb6 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -451,14 +451,11 @@ export function compileCall( arg0 = compiler.compileExpression(operands[0], Type.i32, ConversionKind.NONE, WrapMode.WRAP); } switch (compiler.currentType.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.U8: - case TypeKind.U16: { - ret = module.createUnary(UnaryOp.ClzI32, arg0); - break; - } case TypeKind.BOOL: // usually overflows + case TypeKind.I8: + case TypeKind.U8: + case TypeKind.I16: + case TypeKind.U16: case TypeKind.I32: case TypeKind.U32: { ret = module.createUnary(UnaryOp.ClzI32, arg0); @@ -531,14 +528,11 @@ export function compileCall( arg0 = compiler.compileExpression(operands[0], Type.i32, ConversionKind.NONE, WrapMode.WRAP); } switch (compiler.currentType.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.U8: - case TypeKind.U16: { - ret = module.createUnary(UnaryOp.CtzI32, arg0); - break; - } case TypeKind.BOOL: // usually overflows + case TypeKind.I8: + case TypeKind.U8: + case TypeKind.I16: + case TypeKind.U16: case TypeKind.I32: case TypeKind.U32: { ret = module.createUnary(UnaryOp.CtzI32, arg0); @@ -611,14 +605,11 @@ export function compileCall( arg0 = compiler.compileExpression(operands[0], Type.i32, ConversionKind.NONE, WrapMode.WRAP); } switch (compiler.currentType.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.U8: - case TypeKind.U16: { - ret = module.createUnary(UnaryOp.PopcntI32, arg0); - break; - } case TypeKind.BOOL: // usually overflows + case TypeKind.I8: + case TypeKind.U8: + case TypeKind.I16: + case TypeKind.U16: case TypeKind.I32: case TypeKind.U32: { ret = module.createUnary(UnaryOp.PopcntI32, arg0); @@ -2525,11 +2516,8 @@ export function compileCall( case TypeKind.I16: case TypeKind.U8: case TypeKind.U16: - case TypeKind.BOOL: { - ret = module.createSelect(arg0, arg1, arg2); - break; - } - default: { // any other value type + case TypeKind.BOOL: + default: { ret = module.createSelect(arg0, arg1, arg2); break; } diff --git a/src/compiler.ts b/src/compiler.ts index dc42f2f3..f5f849f3 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -4499,7 +4499,6 @@ export class Compiler extends DiagnosticEmitter { // simplify if cloning left without side effects is possible if (expr = module.cloneExpression(leftExpr, true, 0)) { - this.makeIsTrueish(leftExpr, this.currentType); expr = module.createIf( this.makeIsTrueish(leftExpr, this.currentType), rightExpr, @@ -6420,14 +6419,16 @@ export class Compiler extends DiagnosticEmitter { var arrayOffset = arraySegment.offset; if (hasGC) arrayOffset = i64_add(arrayOffset, i64_new(gcHeaderSize)); this.currentType = arrayInstance.type; + var buffer_offset = pos + arrayInstance.offsetof("buffer_"); + var length_offset = pos + arrayInstance.offsetof("length_"); if (usizeTypeSize == 8) { - writeI64(bufferOffset, buf, pos + arrayInstance.offsetof("buffer_")); - writeI32(length, buf, pos + arrayInstance.offsetof("length_")); + writeI64(bufferOffset, buf, buffer_offset); + writeI32(length, buf, length_offset); return this.module.createI64(i64_low(arrayOffset), i64_high(arrayOffset)); } else { assert(i64_is_u32(bufferOffset)); - writeI32(i64_low(bufferOffset), buf, pos + arrayInstance.offsetof("buffer_")); - writeI32(length, buf, pos + arrayInstance.offsetof("length_")); + writeI32(i64_low(bufferOffset), buf, buffer_offset); + writeI32(length, buf, length_offset); assert(i64_is_u32(arrayOffset)); return this.module.createI32(i64_low(arrayOffset)); } @@ -6448,12 +6449,13 @@ export class Compiler extends DiagnosticEmitter { var nativeElementType = elementType.toNativeType(); var isStatic = true; for (let i = 0; i < length; ++i) { - let expr = expressions[i] - ? this.compileExpression(expressions[i], elementType, ConversionKind.IMPLICIT, WrapMode.NONE) + let expression = expressions[i]; + let expr = expression + ? this.compileExpression(expression, elementType, ConversionKind.IMPLICIT, WrapMode.NONE) : elementType.toNativeZero(module); compiledValues[i] = expr; if (isStatic) { - expr = module.precomputeExpression(compiledValues[i]); + expr = module.precomputeExpression(expr); if (getExpressionId(expr) == ExpressionId.Const) { assert(getExpressionType(expr) == nativeElementType); constantValues[i] = expr; diff --git a/src/program.ts b/src/program.ts index 3ab27cde..2f4197a1 100644 --- a/src/program.ts +++ b/src/program.ts @@ -1614,33 +1614,34 @@ export class Program extends DiagnosticEmitter { element = assert(parent.lookupInSelf(name)); // possibly merged var members = declaration.members; for (let i = 0, k = members.length; i < k; ++i) { - switch (members[i].kind) { + let member = members[i]; + switch (member.kind) { case NodeKind.CLASSDECLARATION: { - this.initializeClass(members[i], element, queuedExtends, queuedImplements); + this.initializeClass(member, element, queuedExtends, queuedImplements); break; } case NodeKind.ENUMDECLARATION: { - this.initializeEnum(members[i], element); + this.initializeEnum(member, element); break; } case NodeKind.FUNCTIONDECLARATION: { - this.initializeFunction(members[i], element); + this.initializeFunction(member, element); break; } case NodeKind.INTERFACEDECLARATION: { - this.initializeInterface(members[i], element); + this.initializeInterface(member, element); break; } case NodeKind.NAMESPACEDECLARATION: { - this.initializeNamespace(members[i], element, queuedExtends, queuedImplements); + this.initializeNamespace(member, element, queuedExtends, queuedImplements); break; } case NodeKind.TYPEDECLARATION: { - this.initializeTypeDefinition(members[i], element); + this.initializeTypeDefinition(member, element); break; } case NodeKind.VARIABLE: { - this.initializeVariables(members[i], element); + this.initializeVariables(member, element); break; } default: assert(false); // namespace member expected diff --git a/src/tokenizer.ts b/src/tokenizer.ts index 31956f73..75088508 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -500,6 +500,7 @@ export class Tokenizer extends DiagnosticEmitter { /** Constructs a new tokenizer. */ constructor(source: Source, diagnostics: DiagnosticMessage[] | null = null) { super(diagnostics); + this.source = source; this.pos = 0; this.end = source.text.length; @@ -598,11 +599,12 @@ export class Tokenizer extends DiagnosticEmitter { case CharCode.AMPERSAND: { ++this.pos; if (maxTokenLength > 1 && this.pos < this.end) { - if (text.charCodeAt(this.pos) == CharCode.AMPERSAND) { + let chr = text.charCodeAt(this.pos); + if (chr == CharCode.AMPERSAND) { ++this.pos; return Token.AMPERSAND_AMPERSAND; } - if (text.charCodeAt(this.pos) == CharCode.EQUALS) { + if (chr == CharCode.EQUALS) { ++this.pos; return Token.AMPERSAND_EQUALS; } @@ -620,11 +622,12 @@ export class Tokenizer extends DiagnosticEmitter { case CharCode.ASTERISK: { ++this.pos; if (maxTokenLength > 1 && this.pos < this.end) { - if (text.charCodeAt(this.pos) == CharCode.EQUALS) { + let chr = text.charCodeAt(this.pos); + if (chr == CharCode.EQUALS) { ++this.pos; return Token.ASTERISK_EQUALS; } - if (text.charCodeAt(this.pos) == CharCode.ASTERISK) { + if (chr == CharCode.ASTERISK) { ++this.pos; if ( maxTokenLength > 2 && this.pos < this.end && @@ -641,11 +644,12 @@ export class Tokenizer extends DiagnosticEmitter { case CharCode.PLUS: { ++this.pos; if (maxTokenLength > 1 && this.pos < this.end) { - if (text.charCodeAt(this.pos) == CharCode.PLUS) { + let chr = text.charCodeAt(this.pos); + if (chr == CharCode.PLUS) { ++this.pos; return Token.PLUS_PLUS; } - if (text.charCodeAt(this.pos) == CharCode.EQUALS) { + if (chr == CharCode.EQUALS) { ++this.pos; return Token.PLUS_EQUALS; } @@ -659,11 +663,12 @@ export class Tokenizer extends DiagnosticEmitter { case CharCode.MINUS: { ++this.pos; if (maxTokenLength > 1 && this.pos < this.end) { - if (text.charCodeAt(this.pos) == CharCode.MINUS) { + let chr = text.charCodeAt(this.pos); + if (chr == CharCode.MINUS) { ++this.pos; return Token.MINUS_MINUS; } - if (text.charCodeAt(this.pos) == CharCode.EQUALS) { + if (chr == CharCode.EQUALS) { ++this.pos; return Token.MINUS_EQUALS; } @@ -673,13 +678,14 @@ export class Tokenizer extends DiagnosticEmitter { case CharCode.DOT: { ++this.pos; if (maxTokenLength > 1 && this.pos < this.end) { - if (isDecimalDigit(text.charCodeAt(this.pos))) { + let chr = text.charCodeAt(this.pos); + if (isDecimalDigit(chr)) { --this.pos; return Token.FLOATLITERAL; // expects a call to readFloat } if ( maxTokenLength > 2 && this.pos + 1 < this.end && - text.charCodeAt(this.pos) == CharCode.DOT && + chr == CharCode.DOT && text.charCodeAt(this.pos + 1) == CharCode.DOT ) { this.pos += 2; @@ -692,7 +698,8 @@ export class Tokenizer extends DiagnosticEmitter { let commentStartPos = this.pos; ++this.pos; if (maxTokenLength > 1 && this.pos < this.end) { - if (text.charCodeAt(this.pos) == CharCode.SLASH) { // single-line + let chr = text.charCodeAt(this.pos); + if (chr == CharCode.SLASH) { // single-line let commentKind = CommentKind.LINE; if ( this.pos + 1 < this.end && @@ -716,7 +723,7 @@ export class Tokenizer extends DiagnosticEmitter { } break; } - if (text.charCodeAt(this.pos) == CharCode.ASTERISK) { // multi-line + if (chr == CharCode.ASTERISK) { // multi-line let closed = false; while (++this.pos < this.end) { c = text.charCodeAt(this.pos); @@ -744,7 +751,7 @@ export class Tokenizer extends DiagnosticEmitter { } break; } - if (text.charCodeAt(this.pos) == CharCode.EQUALS) { + if (chr == CharCode.EQUALS) { ++this.pos; return Token.SLASH_EQUALS; } @@ -776,7 +783,8 @@ export class Tokenizer extends DiagnosticEmitter { case CharCode.LESSTHAN: { ++this.pos; if (maxTokenLength > 1 && this.pos < this.end) { - if (text.charCodeAt(this.pos) == CharCode.LESSTHAN) { + let chr = text.charCodeAt(this.pos); + if (chr == CharCode.LESSTHAN) { ++this.pos; if ( maxTokenLength > 2 && @@ -788,7 +796,7 @@ export class Tokenizer extends DiagnosticEmitter { } return Token.LESSTHAN_LESSTHAN; } - if (text.charCodeAt(this.pos) == CharCode.EQUALS) { + if (chr == CharCode.EQUALS) { ++this.pos; return Token.LESSTHAN_EQUALS; } @@ -798,7 +806,8 @@ export class Tokenizer extends DiagnosticEmitter { case CharCode.EQUALS: { ++this.pos; if (maxTokenLength > 1 && this.pos < this.end) { - if (text.charCodeAt(this.pos) == CharCode.EQUALS) { + let chr = text.charCodeAt(this.pos); + if (chr == CharCode.EQUALS) { ++this.pos; if ( maxTokenLength > 2 && @@ -810,7 +819,7 @@ export class Tokenizer extends DiagnosticEmitter { } return Token.EQUALS_EQUALS; } - if (text.charCodeAt(this.pos) == CharCode.GREATERTHAN) { + if (chr == CharCode.GREATERTHAN) { ++this.pos; return Token.EQUALS_GREATERTHAN; } @@ -820,10 +829,12 @@ export class Tokenizer extends DiagnosticEmitter { case CharCode.GREATERTHAN: { ++this.pos; if (maxTokenLength > 1 && this.pos < this.end) { - if (text.charCodeAt(this.pos) == CharCode.GREATERTHAN) { + let chr = text.charCodeAt(this.pos); + if (chr == CharCode.GREATERTHAN) { ++this.pos; if (maxTokenLength > 2 && this.pos < this.end) { - if (text.charCodeAt(this.pos) == CharCode.GREATERTHAN) { + chr = text.charCodeAt(this.pos); + if (chr == CharCode.GREATERTHAN) { ++this.pos; if ( maxTokenLength > 3 && this.pos < this.end && @@ -834,14 +845,14 @@ export class Tokenizer extends DiagnosticEmitter { } return Token.GREATERTHAN_GREATERTHAN_GREATERTHAN; } - if (text.charCodeAt(this.pos) == CharCode.EQUALS) { + if (chr == CharCode.EQUALS) { ++this.pos; return Token.GREATERTHAN_GREATERTHAN_EQUALS; } } return Token.GREATERTHAN_GREATERTHAN; } - if (text.charCodeAt(this.pos) == CharCode.EQUALS) { + if (chr == CharCode.EQUALS) { ++this.pos; return Token.GREATERTHAN_EQUALS; } @@ -878,11 +889,12 @@ export class Tokenizer extends DiagnosticEmitter { case CharCode.BAR: { ++this.pos; if (maxTokenLength > 1 && this.pos < this.end) { - if (text.charCodeAt(this.pos) == CharCode.BAR) { + let chr = text.charCodeAt(this.pos); + if (chr == CharCode.BAR) { ++this.pos; return Token.BAR_BAR; } - if (text.charCodeAt(this.pos) == CharCode.EQUALS) { + if (chr == CharCode.EQUALS) { ++this.pos; return Token.BAR_EQUALS; } @@ -917,7 +929,7 @@ export class Tokenizer extends DiagnosticEmitter { let keywordText = text.substring(posBefore, this.pos); let keywordToken = tokenFromKeyword(keywordText); if ( - keywordToken != Token.INVALID && + keywordToken !== Token.INVALID && identifierHandling !== IdentifierHandling.ALWAYS && !( identifierHandling === IdentifierHandling.PREFER && @@ -1148,7 +1160,7 @@ export class Tokenizer extends DiagnosticEmitter { continue; } let c = text.charCodeAt(this.pos); - if (c == CharCode.SLASH && !escaped) break; + if (!escaped && c == CharCode.SLASH) break; if (isLineBreak(c)) { this.error( DiagnosticCode.Unterminated_regular_expression_literal, @@ -1202,20 +1214,20 @@ export class Tokenizer extends DiagnosticEmitter { testInteger(): bool { var text = this.source.text; - if (text.charCodeAt(this.pos) == CharCode._0 && this.pos + 1 < this.end) { + if (this.pos + 1 < this.end && text.charCodeAt(this.pos) == CharCode._0) { switch (text.charCodeAt(this.pos + 2)) { - case CharCode.X: case CharCode.x: - case CharCode.B: + case CharCode.X: case CharCode.b: - case CharCode.O: - case CharCode.o: return true; + case CharCode.B: + case CharCode.o: + case CharCode.O: return true; } } var pos = this.pos; while (pos < this.end) { let c = text.charCodeAt(pos); - if (c == CharCode.DOT || c == CharCode.E || c == CharCode.e) { + if (c == CharCode.DOT || c == CharCode.e || c == CharCode.E) { return false; } if ((c < CharCode._0 || c > CharCode._9) && c != CharCode._) break; @@ -1227,20 +1239,20 @@ export class Tokenizer extends DiagnosticEmitter { readInteger(): I64 { var text = this.source.text; - if (text.charCodeAt(this.pos) == CharCode._0 && this.pos + 2 < this.end) { + if (this.pos + 2 < this.end && text.charCodeAt(this.pos) == CharCode._0) { switch (text.charCodeAt(this.pos + 1)) { - case CharCode.X: - case CharCode.x: { + case CharCode.x: + case CharCode.X: { this.pos += 2; return this.readHexInteger(); } - case CharCode.B: - case CharCode.b: { + case CharCode.b: + case CharCode.B: { this.pos += 2; return this.readBinaryInteger(); } - case CharCode.O: - case CharCode.o: { + case CharCode.o: + case CharCode.O: { this.pos += 2; return this.readOctalInteger(); } @@ -1262,29 +1274,29 @@ export class Tokenizer extends DiagnosticEmitter { readHexInteger(): I64 { var text = this.source.text; var start = this.pos; - var value = i64_new(0, 0); - var i64_16 = i64_new(16, 0); + var value = i64_new(0); + var i64_4 = i64_new(4); var sepEnd = start; while (this.pos < this.end) { let pos = this.pos; let c = text.charCodeAt(pos); if (c >= CharCode._0 && c <= CharCode._9) { - // value = value * 16 + c - CharCode._0; + // value = (value << 4) + c - CharCode._0; value = i64_add( - i64_mul(value, i64_16), - i64_new(c - CharCode._0, 0) + i64_shl(value, i64_4), + i64_new(c - CharCode._0) ); } else if (c >= CharCode.A && c <= CharCode.F) { - // value = value * 16 + 10 + c - CharCode.A; + // value = (value << 4) + 10 + c - CharCode.A; value = i64_add( - i64_mul(value, i64_16), - i64_new(10 + c - CharCode.A, 0) + i64_shl(value, i64_4), + i64_new(10 + c - CharCode.A) ); } else if (c >= CharCode.a && c <= CharCode.f) { - // value = value * 16 + 10 + c - CharCode.a; + // value = (value << 4) + 10 + c - CharCode.a; value = i64_add( - i64_mul(value, i64_16), - i64_new(10 + c - CharCode.a, 0) + i64_shl(value, i64_4), + i64_new(10 + c - CharCode.a) ); } else if (c == CharCode._) { if (sepEnd == pos) { @@ -1318,8 +1330,8 @@ export class Tokenizer extends DiagnosticEmitter { readDecimalInteger(): I64 { var text = this.source.text; var start = this.pos; - var value = i64_new(0, 0); - var i64_10 = i64_new(10, 0); + var value = i64_new(0); + var i64_10 = i64_new(10); var sepEnd = start; while (this.pos < this.end) { let pos = this.pos; @@ -1328,7 +1340,7 @@ export class Tokenizer extends DiagnosticEmitter { // value = value * 10 + c - CharCode._0; value = i64_add( i64_mul(value, i64_10), - i64_new(c - CharCode._0, 0) + i64_new(c - CharCode._0) ); } else if (c == CharCode._) { if (sepEnd == pos) { @@ -1362,17 +1374,17 @@ export class Tokenizer extends DiagnosticEmitter { readOctalInteger(): I64 { var text = this.source.text; var start = this.pos; - var value = i64_new(0, 0); - var i64_8 = i64_new(8, 0); + var value = i64_new(0); + var i64_3 = i64_new(3); var sepEnd = start; while (this.pos < this.end) { let pos = this.pos; let c = text.charCodeAt(pos); if (c >= CharCode._0 && c <= CharCode._7) { - // value = value * 8 + c - CharCode._0; + // value = (value << 3) + c - CharCode._0; value = i64_add( - i64_mul(value, i64_8), - i64_new(c - CharCode._0, 0) + i64_shl(value, i64_3), + i64_new(c - CharCode._0) ); } else if (c == CharCode._) { if (sepEnd == pos) { @@ -1406,23 +1418,19 @@ export class Tokenizer extends DiagnosticEmitter { readBinaryInteger(): I64 { var text = this.source.text; var start = this.pos; - var value = i64_new(0, 0); - var i64_2 = i64_new(2, 0); - var i64_1 = i64_new(1, 0); + var value = i64_new(0); + var i64_1 = i64_new(1); var sepEnd = start; while (this.pos < this.end) { let pos = this.pos; let c = text.charCodeAt(pos); if (c == CharCode._0) { - // value = value * 2; - value = i64_mul( - value, - i64_2 - ); + // value = (value << 1); + value = i64_shl(value, i64_1); } else if (c == CharCode._1) { - // value = value * 2 + 1; + // value = (value << 1) + 1; value = i64_add( - i64_mul(value, i64_2), + i64_shl(value, i64_1), i64_1 ); } else if (c == CharCode._) { @@ -1483,12 +1491,10 @@ export class Tokenizer extends DiagnosticEmitter { } if (this.pos < this.end) { let c = text.charCodeAt(this.pos); - if (c == CharCode.E || c == CharCode.e) { + if (c == CharCode.e || c == CharCode.E) { if ( - ++this.pos < this.end && ( - text.charCodeAt(this.pos) == CharCode.MINUS || - text.charCodeAt(this.pos) == CharCode.PLUS - ) && + ++this.pos < this.end && + (c = text.charCodeAt(this.pos)) == CharCode.MINUS || c == CharCode.PLUS && isDecimalDigit(text.charCodeAt(this.pos + 1)) ) { ++this.pos; @@ -1512,11 +1518,11 @@ export class Tokenizer extends DiagnosticEmitter { while (this.pos < this.end) { let c = text.charCodeAt(this.pos++); if (c >= CharCode._0 && c <= CharCode._9) { - value = value * 16 + c - CharCode._0; + value = (value << 4) + c - CharCode._0; } else if (c >= CharCode.A && c <= CharCode.F) { - value = value * 16 + 10 + c - CharCode.A; + value = (value << 4) + c + (10 - CharCode.A); } else if (c >= CharCode.a && c <= CharCode.f) { - value = value * 16 + 10 + c - CharCode.a; + value = (value << 4) + c + (10 - CharCode.a); } else { this.error( DiagnosticCode.Hexadecimal_digit_expected, @@ -1572,8 +1578,8 @@ export class Tokenizer extends DiagnosticEmitter { return value32 < 65536 ? String.fromCharCode(value32) : String.fromCharCode( - (((value32 - 65536) / 1024 | 0) + 0xD800) as i32, - ( (value32 - 65536) % 1024 + 0xDC00) as i32 + ((value32 - 65536) >>> 10) + 0xD800, + ((value32 - 65536) & 1023) + 0xDC00 ); } diff --git a/src/util/charcode.ts b/src/util/charcode.ts index 416f246f..a9eda98f 100644 --- a/src/util/charcode.ts +++ b/src/util/charcode.ts @@ -184,10 +184,10 @@ export function isOctalDigit(c: i32): bool { /** Tests if the specified character code is a valid start of an identifier. */ export function isIdentifierStart(c: i32): bool { - return c >= CharCode.A && c <= CharCode.Z - || c >= CharCode.a && c <= CharCode.z - || c == CharCode.DOLLAR + return c >= CharCode.a && c <= CharCode.z + || c >= CharCode.A && c <= CharCode.Z || c == CharCode._ + || c == CharCode.DOLLAR || c > 0x7f && isUnicodeIdentifierStart(c); } @@ -198,11 +198,11 @@ export function isKeywordCharacter(c: i32): bool { /** Tests if the specified character code is a valid part of an identifier. */ export function isIdentifierPart(c: i32): bool { - return c >= CharCode.A && c <= CharCode.Z - || c >= CharCode.a && c <= CharCode.z + return c >= CharCode.a && c <= CharCode.z + || c >= CharCode.A && c <= CharCode.Z || c >= CharCode._0 && c <= CharCode._9 - || c == CharCode.DOLLAR || c == CharCode._ + || c == CharCode.DOLLAR || c > 0x7f && isUnicodeIdentifierPart(c); } @@ -349,14 +349,16 @@ function lookupInUnicodeMap(code: u16, map: u16[]): bool { var lo = 0; var hi = map.length; var mid: i32; + var midVal: u16; while (lo + 1 < hi) { - mid = lo + (hi - lo) / 2; - mid -= mid % 2; - if (map[mid] <= code && code <= map[mid + 1]) { + mid = lo + ((hi - lo) >> 1); + mid -= (mid & 1); + midVal = map[mid]; + if (midVal <= code && code <= map[mid + 1]) { return true; } - if (code < map[mid]) { + if (code < midVal) { hi = mid; } else { lo = mid + 2; diff --git a/src/util/path.ts b/src/util/path.ts index 27985b6f..9fa61100 100644 --- a/src/util/path.ts +++ b/src/util/path.ts @@ -4,6 +4,10 @@ import { CharCode } from "./charcode"; +import { + PATH_DELIMITER +} from "../common"; + const separator = CharCode.SLASH; /** @@ -99,13 +103,19 @@ export function resolvePath(normalizedPath: string, origin: string): string { return normalizedPath; } return normalizePath( - dirname(origin) + String.fromCharCode(separator) + normalizedPath + dirname(origin) + PATH_DELIMITER + normalizedPath ); } /** Obtains the directory portion of a normalized path. */ export function dirname(normalizedPath: string): string { var pos = normalizedPath.length; + if (pos <= 1) { + if (pos == 0) return "."; + if (normalizedPath.charCodeAt(0) == separator) { + return normalizedPath; + } + } while (--pos > 0) { if (normalizedPath.charCodeAt(pos) == separator) { return normalizedPath.substring(0, pos);