Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement stringref operations #2687

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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 .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ jobs:
run: npm run build
- name: Test experimental features
env:
ASC_FEATURES: threads,reference-types,gc,exception-handling
ASC_FEATURES: threads,reference-types,gc,exception-handling,stringref
run: |
npm run test:compiler features/threads features/reference-types features/gc features/exception-handling
npm run test:compiler features/threads features/reference-types features/gc features/exception-handling features/stringref
runtimes:
name: "Runtimes"
runs-on: ubuntu-latest
Expand Down
655 changes: 655 additions & 0 deletions src/builtins.ts

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7923,6 +7923,11 @@ export class Compiler extends DiagnosticEmitter {
}
case LiteralKind.String: {
assert(!implicitlyNegate);
// Emit a stringref if context indicates
if (contextualType.kind == TypeKind.String) {
this.currentType = Type.string;
return module.string_const((<StringLiteralExpression>expression).value);
}
return this.compileStringLiteral(<StringLiteralExpression>expression, constraints);
}
case LiteralKind.Template: {
Expand Down
9 changes: 9 additions & 0 deletions src/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import {
getUnaryValue,
getCallOperandAt,
getCallOperandCount,
getRefIsNullValue,
isConstZero,
isConstNonZero
} from "./module";
Expand Down Expand Up @@ -1049,6 +1050,10 @@ export class Flow {
}
break;
}
case ExpressionId.RefIsNull: {
this.inheritNonnullIfFalse(getRefIsNullValue(expr), iff); // value == null -> value must have been null
break;
}
}
}

Expand Down Expand Up @@ -1140,6 +1145,10 @@ export class Flow {
}
break;
}
case ExpressionId.RefIsNull: {
this.inheritNonnullIfTrue(getRefIsNullValue(expr), iff); // value == null -> value must have been non-null
break;
}
}
}

Expand Down
287 changes: 277 additions & 10 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,9 @@ export const enum StringMeasureOp {
/** string.is_usv_sequence */
IsUSV = 3 /* _BinaryenStringMeasureIsUSV */,
/** stringview_wtf16.length */
WTF16View = 4 /* _BinaryenStringMeasureWTF16View */
WTF16View = 4 /* _BinaryenStringMeasureWTF16View */,
/** string.hash */
Hash = 5 /* TODO_BinaryenStringMeasureHash */
}

/** Binaryen StringEncode operation constants. */
Expand Down Expand Up @@ -1472,14 +1474,6 @@ export class Module {
return binaryen._BinaryenRefEq(this.ref, left, right);
}

string_eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef {
return binaryen._BinaryenStringEq(this.ref, StringEqOp.Equal, left, right);
}

string_compare(left: ExpressionRef, right: ExpressionRef): ExpressionRef {
return binaryen._BinaryenStringEq(this.ref, StringEqOp.Compare, left, right);
}

// expressions

unary(
Expand Down Expand Up @@ -2136,6 +2130,274 @@ export class Module {
return binaryen._BinaryenI31Get(this.ref, expr, signed);
}

// stringref

string_const(
str: string
): ExpressionRef {
return binaryen._BinaryenStringConst(this.ref, this.allocStringCached(str));
}

string_new_utf8(
ptr: ExpressionRef,
length: ExpressionRef,
memory: string = CommonNames.DefaultMemory // TODO
): ExpressionRef {
return binaryen._BinaryenStringNew(this.ref, StringNewOp.UTF8, ptr, length, 0, 0, false);
}

string_new_utf8_array(
arr: ExpressionRef,
start: ExpressionRef,
end: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringNew(this.ref, StringNewOp.UTF8Array, arr, 0, start, end, false);
}

string_new_lossy_utf8(
ptr: ExpressionRef,
length: ExpressionRef,
memory: string = CommonNames.DefaultMemory // TODO
): ExpressionRef {
return binaryen._BinaryenStringNew(this.ref, StringNewOp.Replace, ptr, length, 0, 0, false);
}

string_new_lossy_utf8_array(
arr: ExpressionRef,
start: ExpressionRef,
end: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringNew(this.ref, StringNewOp.ReplaceArray, arr, 0, start, end, false);
}

string_new_wtf8(
ptr: ExpressionRef,
length: ExpressionRef,
memory: string = CommonNames.DefaultMemory // TODO
): ExpressionRef {
return binaryen._BinaryenStringNew(this.ref, StringNewOp.WTF8, ptr, length, 0, 0, false);
}

string_new_wtf8_array(
arr: ExpressionRef,
start: ExpressionRef,
end: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringNew(this.ref, StringNewOp.WTF8Array, arr, 0, start, end, false);
}

string_new_wtf16(
ptr: ExpressionRef,
length: ExpressionRef,
memory: string = CommonNames.DefaultMemory // TODO
): ExpressionRef {
return binaryen._BinaryenStringNew(this.ref, StringNewOp.WTF16, ptr, length, 0, 0, false);
}

string_new_wtf16_array(
arr: ExpressionRef,
start: ExpressionRef,
end: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringNew(this.ref, StringNewOp.WTF16Array, arr, 0, start, end, false);
}

string_from_code_point(
codepoint: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringNew(this.ref, StringNewOp.FromCodePoint, codepoint, 0, 0, 0, false);
}

string_hash(
str: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.Hash, str);
}

string_measure_utf8(
str: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.UTF8, str);
}

string_measure_wtf8(
str: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.WTF8, str);
}

string_measure_wtf16(
str: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.WTF16, str);
}

string_is_usv_sequence(
str: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.IsUSV, str);
}

string_encode_utf8(
str: ExpressionRef,
ptr: ExpressionRef,
memory: string = CommonNames.DefaultMemory // TODO
): ExpressionRef {
return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.UTF8, str, ptr, 0);
}

string_encode_utf8_array(
str: ExpressionRef,
arr: ExpressionRef,
start: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.UTF8Array, str, arr, start);
}

// TOOD: string_encode_lossy_utf8
// TODO: string_encode_lossy_utf8_array

string_encode_wtf8(
str: ExpressionRef,
ptr: ExpressionRef,
memory: string = CommonNames.DefaultMemory // TODO
): ExpressionRef {
return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.WTF8, str, ptr, 0);
}

string_encode_wtf8_array(
str: ExpressionRef,
arr: ExpressionRef,
start: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.WTF8Array, str, arr, start);
}

string_encode_wtf16(
str: ExpressionRef,
ptr: ExpressionRef,
memory: string = CommonNames.DefaultMemory // TODO
): ExpressionRef {
return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.WTF16, str, ptr, 0);
}

string_encode_wtf16_array(
str: ExpressionRef,
arr: ExpressionRef,
start: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringEncode(this.ref, StringEncodeOp.WTF16Array, str, arr, start);
}

string_concat(
left: ExpressionRef,
right: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringConcat(this.ref, left, right);
}

string_eq(
left: ExpressionRef,
right: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringEq(this.ref, StringEqOp.Equal, left, right);
}

string_compare(
left: ExpressionRef,
right: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringEq(this.ref, StringEqOp.Compare, left, right);
}

string_as_wtf8(
str: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringAs(this.ref, StringAsOp.WTF8, str);
}

string_as_wtf16(
str: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringAs(this.ref, StringAsOp.WTF16, str);
}

string_as_iter(
str: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringAs(this.ref, StringAsOp.Iter, str);
}

stringview_wtf8_advance(
view: ExpressionRef,
pos: ExpressionRef,
bytes: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringWTF8Advance(this.ref, view, pos, bytes);
}

// TODO: stringview_wtf8_encode_utf8
// TODO: stringview_wtf8_encode_lossy_utf8
// TODO: stringview_wtf8_encode_wtf8

stringview_wtf8_slice(
view: ExpressionRef,
start: ExpressionRef,
end: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringSliceWTF(this.ref, StringSliceWTFOp.WTF8, view, start, end);
}

stringview_wtf16_length(
view: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringMeasure(this.ref, StringMeasureOp.WTF16View, view);
}

stringview_wtf16_slice(
view: ExpressionRef,
start: ExpressionRef,
end: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringSliceWTF(this.ref, StringSliceWTFOp.WTF16, view, start, end);
}

stringview_wtf16_get_codeunit(
view: ExpressionRef,
pos: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringWTF16Get(this.ref, view, pos);
}

// TODO: stringview_wtf16_encode

stringview_iter_next(
view: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringIterNext(this.ref, view);
}

stringview_iter_advance(
view: ExpressionRef,
count: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringIterMove(this.ref, StringIterMoveOp.Advance, view, count);
}

stringview_iter_rewind(
view: ExpressionRef,
count: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringIterMove(this.ref, StringIterMoveOp.Rewind, view, count);
}

stringview_iter_slice(
view: ExpressionRef,
count: ExpressionRef
): ExpressionRef {
return binaryen._BinaryenStringSliceIter(this.ref, view, count);
}

// globals

addGlobal(
Expand Down Expand Up @@ -2959,7 +3221,8 @@ export class Module {
case ExpressionId.Const:
case ExpressionId.RefNull:
case ExpressionId.RefFunc:
case ExpressionId.I31New: return true;
case ExpressionId.I31New:
case ExpressionId.StringConst: return true;
case ExpressionId.Binary: {
if (this.getFeatures() & FeatureFlags.ExtendedConst) {
switch (getBinaryOp(expr)) {
Expand Down Expand Up @@ -3290,6 +3553,10 @@ export function getMemoryGrowDelta(expr: ExpressionRef): ExpressionRef {
return binaryen._BinaryenMemoryGrowGetDelta(expr);
}

export function getRefIsNullValue(expr: ExpressionRef): ExpressionRef {
return binaryen._BinaryenRefIsNullGetValue(expr);
}

// functions

export function getFunctionBody(func: FunctionRef): ExpressionRef {
Expand Down
8 changes: 8 additions & 0 deletions src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,14 @@ export class Program extends DiagnosticEmitter {
}
private _stringInstance: Class | null = null;

/** Gets the standard `RefString` instance. */
get refStringInstance(): Class {
let cached = this._refStringInstance;
if (!cached) this._refStringInstance = cached = this.requireClass(CommonNames.RefString);
return cached;
}
private _refStringInstance: Class | null = null;

/** Gets the standard `RegExp` instance. */
get regexpInstance(): Class {
let cached = this._regexpInstance;
Expand Down
Loading