Skip to content

Commit 666ba54

Browse files
committed
Heap fill/compare; Std string experiments
1 parent dd5c3e7 commit 666ba54

17 files changed

+5103
-217
lines changed

bin/asc.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,8 @@ function checkDiagnostics(parser) {
9393
if (!args.noLib) {
9494
var stdlibDir = path.join(__dirname + "..", "std", "assembly");
9595
glob.sync("*.ts", { cwd: stdlibDir }).forEach(file => {
96-
var nextPath = "std/" + file;
9796
var nextText = fs.readFileSync(path.join(stdlibDir, file), { encoding: "utf8" });
98-
parser = assemblyscript.parseFile(nextText, nextPath, parser, false);
97+
parser = assemblyscript.parseFile(nextText, "std:" + file, parser, false);
9998
});
10099
}
101100

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
"url": "https://github.com/AssemblyScript/next/issues"
1212
},
1313
"dependencies": {
14-
"@types/node": "^8.5.1",
1514
"binaryen": "40.0.0-nightly.20171209",
1615
"glob": "^7.1.2",
1716
"minimist": "^1.2.0",
@@ -23,6 +22,7 @@
2322
"@types/glob": "^5.0.34",
2423
"@types/long": "^3.0.32",
2524
"@types/minimist": "^1.2.0",
25+
"@types/node": "^8.5.1",
2626
"chalk": "^2.3.0",
2727
"diff": "^3.4.0",
2828
"long": "^3.2.0",

src/program.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,13 @@ export enum ElementFlags {
914914
/** Is global. */
915915
GLOBAL = 1 << 11,
916916
/** Is read-only. */
917-
READONLY = 1 << 12
917+
READONLY = 1 << 12,
918+
/** Is a public member. */
919+
PUBLIC = 1 << 13,
920+
/** Is a protected member. */
921+
PROTECTED = 1 << 14,
922+
/** Is a private member. */
923+
PRIVATE = 1 << 15
918924
}
919925

920926
/** Base class of all program elements. */
@@ -1441,8 +1447,11 @@ export class FieldPrototype extends Element {
14411447
switch (this.declaration.modifiers[i].modifierKind) {
14421448
case ModifierKind.EXPORT: this.isExported = true; break;
14431449
case ModifierKind.READONLY: this.isReadonly = true; break;
1450+
case ModifierKind.PRIVATE:
1451+
case ModifierKind.PROTECTED:
1452+
case ModifierKind.PUBLIC:
14441453
case ModifierKind.STATIC: break; // already handled
1445-
default: throw new Error("unexpected modifier");
1454+
default: throw new Error("unexpected modifier: " + this.declaration.modifiers[i]);
14461455
}
14471456
}
14481457
}

std/assembly.d.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,25 @@ declare class Array<T> {
191191

192192
/** Class representing a sequence of characters. */
193193
declare class String {
194+
194195
static fromCharCode(ls: i32, hs?: i32): string;
195196
static fromCharCodes(arr: u16[]): string;
196197
static fromCodePoint(cp: i32): string;
197198
static fromCodePoints(arr: i32[]): string;
199+
200+
readonly length: u32;
201+
202+
charAt(index: u32): string;
203+
charCodeAt(index: u32): u16;
204+
concat(other: string): string;
205+
endsWith(other: string): bool;
206+
indexOf(other: string): u32;
207+
startsWith(other: string): bool;
208+
substr(start: u32, length?: u32): string;
209+
substring(start: u32, end?: u32): string;
210+
trim(): string;
211+
trimLeft(): string;
212+
trimRight(): string;
198213
}
199214

200215
/** Class for representing a runtime error. Base class of all errors. */
@@ -237,6 +252,12 @@ declare class Heap {
237252
/** Copies a chunk of memory from one location to another. */
238253
static copy(dest: usize, src: usize, n: usize): usize;
239254

255+
/** Fills a chunk of memory with the specified byte value. */
256+
static fill(dest: usize, c: u8, n: usize): usize;
257+
258+
/** Compares two chunks of memory. Returns `0` if equal, otherwise the difference of the first differing bytes. */
259+
static compare(vl: usize, vr: usize, n: usize): i32;
260+
240261
private constructor();
241262
}
242263

@@ -251,3 +272,6 @@ interface RegExp {}
251272

252273
/** Annotates an element being part of the global namespace. */
253274
declare function global(): any;
275+
276+
/** Annotates a method being an operator overload. */
277+
declare function operator(token: string): any;

std/assembly/heap.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class Heap {
2929
// just a big chunk of non-disposable memory for now
3030
}
3131

32-
static copy(dest: usize, src: usize, n: usize): usize {
32+
static copy(dest: usize, src: usize, n: usize): usize { // TODO: use move_memory op once available
3333
assert(dest >= HEAP_BASE);
3434

3535
// the following is based on musl's implementation of memcpy
@@ -174,5 +174,76 @@ export class Heap {
174174
return dest;
175175
}
176176

177+
static fill(dest: usize, c: u8, n: usize): usize { // TODO: use set_memory op once available
178+
assert(dest >= HEAP_BASE);
179+
180+
// the following is based on musl's implementation of memset
181+
if (!n) return dest;
182+
183+
let s: usize = dest;
184+
185+
// Fill head and tail with minimal branching
186+
store<u8>(s, c); store<u8>(s + n - 1, c);
187+
if (n <= 2) return dest;
188+
store<u8>(s + 1, c); store<u8>(s + n - 2, c);
189+
store<u8>(s + 2, c); store<u8>(s + n - 3, c);
190+
if (n <= 6) return dest;
191+
store<u8>(s + 3, c); store<u8>(s + n - 4, c);
192+
if (n <= 8) return dest;
193+
194+
// Align to 4 bytes
195+
let k: usize = -s & 3;
196+
s += k;
197+
n -= k;
198+
n &= -4;
199+
200+
let c32: u32 = -1 / 255 * c;
201+
202+
// Fill head and tail in preparation of setting 32 bytes at a time
203+
store<u32>(s, c32);
204+
store<u32>(s + n - 4, c32);
205+
if (n <= 8) return dest;
206+
store<u32>(s + 4, c32);
207+
store<u32>(s + 8, c32);
208+
store<u32>(s + n - 12, c32);
209+
store<u32>(s + n - 8, c32);
210+
if (n <= 24) return dest;
211+
store<u32>(s + 12, c32);
212+
store<u32>(s + 16, c32);
213+
store<u32>(s + 20, c32);
214+
store<u32>(s + 24, c32);
215+
store<u32>(s + n - 28, c32);
216+
store<u32>(s + n - 24, c32);
217+
store<u32>(s + n - 20, c32);
218+
store<u32>(s + n - 16, c32);
219+
220+
// Align to 8 bytes
221+
k = 24 + (s & 4);
222+
s += k;
223+
n -= k;
224+
225+
// Set 32 bytes at a time
226+
let c64: u64 = <u64>c32 | (<u64>c32 << 32);
227+
while (n >= 32) {
228+
store<u64>(s, c64);
229+
store<u64>(s + 8, c64);
230+
store<u64>(s + 16, c64);
231+
store<u64>(s + 24, c64);
232+
n -= 32; s += 32;
233+
}
234+
235+
return dest;
236+
}
237+
238+
static compare(vl: usize, vr: usize, n: usize): i32 {
239+
if (vl == vr) return 0;
240+
241+
// the following is based on musl's implementation of memcmp
242+
while (n && load<u8>(vl) == load<u8>(vr)) {
243+
n--; vl++; vr++;
244+
}
245+
return n ? <i32>load<u8>(vl) - <i32>load<u8>(vr) : 0;
246+
}
247+
177248
private constructor() {}
178249
}

std/assembly/string.ts

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,98 @@
11
@global()
22
export class String {
3-
// TODO
3+
4+
private ptr: usize;
5+
readonly length: u32;
6+
7+
constructor(ptr: usize, len: u32) {
8+
this.ptr = ptr;
9+
this.length = len;
10+
}
11+
12+
charAt(index: u32): String {
13+
assert(this != null && index < this.length);
14+
return new String(this.ptr + (index << 1), 1);
15+
}
16+
17+
charCodeAt(index: u32): u16 {
18+
assert(this != null && index < this.length);
19+
return load<u16>(this.ptr + (index << 1));
20+
}
21+
22+
@operator("+")
23+
concat(other: String): String {
24+
assert(this != null && other != null);
25+
const len: u32 = this.length + other.length;
26+
const ptr: usize = Heap.allocate(len << 1);
27+
Heap.copy(ptr, this.ptr, this.length << 1);
28+
Heap.copy(ptr, this.ptr + (len << 1), other.length << 1);
29+
return new String(ptr, len);
30+
}
31+
32+
endsWith(other: String): bool {
33+
assert(this != null && other != null);
34+
if (other.length > this.length)
35+
return false;
36+
for (let i: u32 = this.length - other.length, j: u32 = 0, k: u32 = this.length; i < k;)
37+
if (this.charCodeAt(i++) != other.charCodeAt(j++))
38+
return false;
39+
return true;
40+
}
41+
42+
@operator("==")
43+
equals(other: String): bool {
44+
assert(this != null && other != null);
45+
if (this.length != other.length)
46+
return false;
47+
for (let i: u32 = 0, k: u32 = this.length; i < k; ++i)
48+
if (this.charCodeAt(i) != other.charCodeAt(i))
49+
return false;
50+
return true;
51+
}
52+
53+
indexOf(other: String): u32 {
54+
assert(this != null && other != null);
55+
throw new Error("not implemented");
56+
}
57+
58+
startsWith(other: String): bool {
59+
assert(this != null && other != null);
60+
if (other.length > this.length)
61+
return false;
62+
for (let i: u32 = 0, k: u32 = other.length; i < k; ++i)
63+
if (this.charCodeAt(i) != other.charCodeAt(i))
64+
return false;
65+
return true;
66+
}
67+
68+
substr(start: u32, length: u32 = <u32>-1): String {
69+
assert(this != null);
70+
if (start >= this.length)
71+
return changetype<string,String>("");
72+
const len: u32 = min<u32>(length, this.length - start);
73+
return new String(this.ptr + (start << 1), len);
74+
}
75+
76+
substring(start: u32, end: u32 = <u32>-1): String {
77+
assert(this != null);
78+
if (start >= this.length || end <= start)
79+
return changetype<string,String>("");
80+
const len: u32 = min<u32>(end - start, this.length - start);
81+
return new String(this.ptr + (start << 1), len);
82+
}
83+
84+
trim(): string {
85+
assert(this != null);
86+
throw new Error("not implemented");
87+
}
88+
89+
trimLeft(): string {
90+
assert(this != null);
91+
throw new Error("not implemented");
92+
}
93+
94+
trimRight(): string {
95+
assert(this != null);
96+
throw new Error("not implemented");
97+
}
498
}

tests/compiler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
2626
var parser = new Parser();
2727
if (filename.startsWith("std/")) {
2828
stdFiles.forEach(file => {
29-
parser.parseFile(fs.readFileSync(__dirname + "/../std/assembly/" + file, { encoding: "utf8" }), file, false);
29+
parser.parseFile(fs.readFileSync(__dirname + "/../std/assembly/" + file, { encoding: "utf8" }), "std:" + path.basename(file), false);
3030
});
3131
fixture = "std/" + fixture;
3232
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
(module
2+
(type $ii (func (param i32) (result i32)))
3+
(memory $0 1)
4+
(export "fib" (func $recursive/fib))
5+
(export "memory" (memory $0))
6+
(func $recursive/fib (; 0 ;) (type $ii) (param $0 i32) (result i32)
7+
(if
8+
(i32.le_s
9+
(get_local $0)
10+
(i32.const 1)
11+
)
12+
(return
13+
(i32.const 1)
14+
)
15+
)
16+
(i32.add
17+
(call $recursive/fib
18+
(i32.sub
19+
(get_local $0)
20+
(i32.const 1)
21+
)
22+
)
23+
(call $recursive/fib
24+
(i32.sub
25+
(get_local $0)
26+
(i32.const 2)
27+
)
28+
)
29+
)
30+
)
31+
)

tests/compiler/recursive.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export function fib(n: i32): i32 {
2+
if (n <= 1) return 1;
3+
return fib(n - 1) + fib(n - 2);
4+
}

0 commit comments

Comments
 (0)