Skip to content

Commit ef29f49

Browse files
author
Deian Stefan
committed
lab
0 parents  commit ef29f49

19 files changed

+537
-0
lines changed

lib/low-level.js

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
var assert = require('assert');
2+
var util = require('util');
3+
4+
// The heap (not yet initialized properly)
5+
var heap = new Array(1000);
6+
7+
// Heap objects
8+
9+
function HeapObject(next) {
10+
if (!this instanceof HeapObject) {
11+
return new HeapObject(next);
12+
}
13+
14+
assert(isPointer(next));
15+
16+
// Pointers to other objects
17+
this.fst = null;
18+
this.snd = null;
19+
20+
this._free = true; // Is this object free?
21+
this._next = next; // Next object on free list
22+
23+
this._refcount = 0;
24+
this._traced = false;
25+
}
26+
exports.HeapObject = HeapObject;
27+
28+
function isHeapObject(obj) {
29+
return (obj instanceof HeapObject);
30+
}
31+
32+
// Low level pointers
33+
34+
function Ptr(idx) {
35+
if (!this instanceof Ptr) {
36+
return new Ptr(idx);
37+
}
38+
assert(idx < heap.length);
39+
this._idx = idx;
40+
}
41+
exports.Ptr = Ptr;
42+
43+
Ptr.prototype.equals = function(other) {
44+
if (other instanceof Ptr) {
45+
return (this._idx === other._idx);
46+
}
47+
return false;
48+
};
49+
50+
Ptr.prototype.deref = function() {
51+
// Task 1 {{
52+
// }}
53+
};
54+
55+
Ptr.prototype.write = function(v) {
56+
if (!isHeapObject(v)) {
57+
throw new Error('Can only write HeapObject to the heap');
58+
}
59+
// Task 1 {{
60+
// }}
61+
};
62+
63+
Ptr.prototype.toString = function() {
64+
return this._idx.toString();
65+
};
66+
67+
function isPointer(p) {
68+
return (p instanceof Ptr) || p === null;
69+
}
70+
exports.isPointer = isPointer;
71+
72+
73+
// Initialize the heap
74+
75+
76+
function initHeap() {
77+
// Task 2(a) {{
78+
// }}
79+
}
80+
81+
var free_list_head = new Ptr(0);
82+
var free_list_tail = new Ptr(heap.length - 1);
83+
84+
initHeap();
85+
86+
// Exposed function for iterating over whole heap:
87+
exports.heapIterate = function(f) {
88+
for (var i = 0; i < heap.length - 1; i++) {
89+
f(new Ptr(i));
90+
}
91+
};
92+
93+
// Memory allocation
94+
95+
function malloc() {
96+
// Task 2(b) {{
97+
// }}
98+
}
99+
exports.malloc = malloc;
100+
101+
function free(ptr) {
102+
assert(isPointer(ptr));
103+
if (ptr === null) {
104+
throw new Error('Cannot free a null pointer');
105+
}
106+
// Task 2(b) {{
107+
// }}
108+
}
109+
exports.free = free;
110+
111+
// An easier way of freeing the object pointed to by this pointer:
112+
Ptr.prototype.free = function() { free(this); };
113+
114+
// Diagnostics
115+
116+
function showUsage() {
117+
var total = heap.length;
118+
var free = 1;
119+
var ptr = free_list_head;
120+
while (!ptr.equals(free_list_tail)) {
121+
free++;
122+
ptr = ptr.deref()._next;
123+
}
124+
return '[ free: ' + free +
125+
', used: ' + (total - free) +
126+
', total: ' + total + ' ]';
127+
}
128+
exports.showUsage = showUsage;
129+
130+
exports.showHeap = function(type) {
131+
var res = [];
132+
for (var i = 0; i < heap.length; i++) {
133+
var obj = heap[i];
134+
var fst = obj.fst ? obj.fst._idx : null;
135+
var snd = obj.snd ? obj.snd._idx : null;
136+
if (!obj._free) {
137+
switch (type) {
138+
case 'ref':
139+
res.push(util.format('{%d @ [%d] : (%s, %s)}', i,
140+
obj._refcount, fst, snd));
141+
break;
142+
case 'trace':
143+
res.push(util.format('{%d @ [%s] : (%s, %s)}', i,
144+
obj._traced ? '*' : '-', fst, snd));
145+
break;
146+
default:
147+
res.push(util.format('{%d @ [%d|%s] : (%s, %s)}', i,
148+
obj._refcount,
149+
obj._traced ? '*' : '-', fst, snd));
150+
break;
151+
};
152+
}
153+
}
154+
return '[ ' + res.toString() + ' ]';
155+
};

lib/marksweep.js

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
var assert = require('assert');
2+
var util = require('util');
3+
var ll = require('./low-level');
4+
5+
var HeapObject = ll.HeapObject;
6+
var Ptr = ll.Ptr;
7+
8+
Ptr.prototype.setfst = function(x) {
9+
assert(ll.isPointer(x));
10+
this.deref().fst = x;
11+
};
12+
13+
Ptr.prototype.setsnd = function(x) {
14+
assert(ll.isPointer(x));
15+
this.deref().snd = x;
16+
};
17+
18+
Ptr.prototype.withfst = function(f) {
19+
// Task 4(a) {{
20+
// }}
21+
};
22+
23+
Ptr.prototype.withsnd = function(f) {
24+
// Task 4(a) {{
25+
// }}
26+
};
27+
28+
function create(fst, snd, f) {
29+
// Task 4(a) {{
30+
// }}
31+
}
32+
exports.create = create;
33+
34+
// Roots
35+
36+
var root = { root: null, stack: [] };
37+
38+
function setroot(ptr) {
39+
assert(ll.isPointer(ptr));
40+
root.root = ptr;
41+
}
42+
exports.setroot = setroot;
43+
44+
function withroot(f) {
45+
// Task 4(a) {{
46+
// }}
47+
};
48+
exports.withroot = withroot;
49+
50+
exports.showRoots = function () {
51+
var a = root.stack.map(function(e) { return e.toString() });
52+
return util.format('[%s%s%s]', root.root ? root.root : ''
53+
, (root.root && a.length > 0) ? ',' : ''
54+
, a);
55+
}
56+
57+
// GC
58+
59+
function mark() {
60+
// Task 4(b) {{
61+
// }}
62+
}
63+
exports.mark = mark;
64+
65+
function sweep() {
66+
ll.heapIterate(function (ptr) {
67+
// Task 4(b) {{
68+
// }}
69+
});
70+
}
71+
exports.sweep = sweep;
72+
73+
function gc() {
74+
mark();
75+
sweep();
76+
}
77+
exports.gc = gc;
78+
79+
/* Task 4(c):
80+
81+
82+
83+
84+
85+
86+
*/

lib/refcount.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
var assert = require('assert');
2+
var ll = require('./low-level');
3+
4+
var HeapObject = ll.HeapObject;
5+
var Ptr = ll.Ptr;
6+
7+
Ptr.prototype.addref = function() {
8+
// Task 3(a){{
9+
// }}
10+
};
11+
12+
Ptr.prototype.release = function() {
13+
// Task 3(a){{
14+
// }}
15+
};
16+
17+
Ptr.prototype.setfst = function(x) {
18+
assert(ll.isPointer(x));
19+
// Task 3(b){{
20+
// }}
21+
};
22+
23+
Ptr.prototype.setsnd = function(x) {
24+
assert(ll.isPointer(x));
25+
// Task 3(b){{
26+
// }}
27+
};
28+
29+
Ptr.prototype.withfst = function(f) {
30+
// Task 3(b){{
31+
// }}
32+
};
33+
34+
Ptr.prototype.withsnd = function(f) {
35+
// Task 3(b){{
36+
// }}
37+
};
38+
39+
function create(fst, snd, f) {
40+
// Task 3(b){{
41+
// }}
42+
}
43+
exports.create = create;
44+
45+
// Roots
46+
47+
var root = null;
48+
49+
function setroot(ptr) {
50+
// Task 3(b){{
51+
// }}
52+
}
53+
exports.setroot = setroot;
54+
55+
function withroot(f) {
56+
// Task 3(b){{
57+
// }}
58+
}
59+
exports.withroot = withroot;

task2a.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
var ll = require('./lib/low-level');
2+
3+
console.log(ll.showUsage());

task2b.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
var ll = require('./lib/low-level');
2+
3+
console.log('init: %s', ll.showUsage());
4+
5+
var ptr = ll.malloc();
6+
console.log('after 1 malloc: %s', ll.showUsage());
7+
8+
ll.free(ptr);
9+
console.log('after free: %s', ll.showUsage());
10+
11+
try {
12+
ll.free(ptr);
13+
} catch (e) {
14+
console.log('Failed to free again: %s', e);
15+
}
16+
17+
try {
18+
while (true) {
19+
ll.malloc();
20+
}
21+
} catch (e) {
22+
console.log('Infinite alloc stopped: %s', e);
23+
}
24+
25+
console.log('end: %s', ll.showUsage());

task3a.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
var ll = require('./lib/low-level');
2+
var rc = require('./lib/refcount');
3+
4+
// create a new object
5+
var ptr1 = ll.malloc();
6+
ptr1.addref();
7+
8+
// set the object's fst field to a newly allocated pointer
9+
ptr1.deref().fst = ll.malloc();
10+
ptr1.deref().fst.addref();
11+
12+
console.log(ll.showUsage());
13+
console.log('1 addref: %s', ll.showHeap('ref'));
14+
15+
var ptr2 = ptr1;
16+
17+
ptr2.addref();
18+
console.log('2 addref: %s', ll.showHeap('ref'));
19+
20+
ptr1.release();
21+
console.log(ll.showHeap('ref'));
22+
console.log('1 release: %s', ll.showHeap('ref'));
23+
24+
ptr2.release();
25+
console.log('2 release: %s', ll.showHeap('ref'));
26+
console.log(ll.showUsage());

task3b-create-1.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
var ll = require('./lib/low-level');
2+
var rc = require('./lib/refcount');
3+
4+
rc.create(null, null, function (ptr1) {
5+
console.log('a: create ptr1: %s', ll.showHeap('ref'));
6+
rc.create(null, null, function (ptr1_fst) {
7+
console.log('b: create fst: %s', ll.showHeap('ref'));
8+
ptr1.setfst(ptr1_fst);
9+
console.log('b: ptr1.setfst(fst): %s', ll.showHeap('ref'));
10+
});
11+
console.log('a: %s', ll.showHeap('ref'));
12+
});
13+
console.log('end: %s', ll.showHeap('ref'));

task3b-create-2.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
var ll = require('./lib/low-level');
2+
var rc = require('./lib/refcount');
3+
4+
rc.create(null, null, function (ptr1_fst) {
5+
console.log('a: create fst : %s', ll.showHeap('ref'));
6+
rc.create(ptr1_fst, null, function (ptr1) {
7+
console.log('b: create ptr: %s', ll.showHeap('ref'));
8+
});
9+
console.log('a: %s', ll.showHeap('ref'));
10+
});
11+
console.log('end: %s', ll.showHeap('ref'));

task3b-cycle.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
var ll = require('./lib/low-level');
2+
var rc = require('./lib/refcount');
3+
4+
rc.create(null, null, function (ptr1_fst) {
5+
console.log('a: create fst : %s', ll.showHeap('ref'));
6+
rc.create(ptr1_fst, null, function (ptr1) {
7+
console.log('b: create ptr: %s', ll.showHeap('ref'));
8+
ptr1_fst.setfst(ptr1);
9+
console.log('b: fst.setfst(ptr): %s', ll.showHeap('ref'));
10+
});
11+
console.log('a: %s', ll.showHeap('ref'));
12+
});
13+
console.log('end: %s', ll.showHeap('ref'));

0 commit comments

Comments
 (0)