Skip to content

Commit 907eafc

Browse files
committed
Extract JS snippets to embedded *.js files
1 parent f1c1c69 commit 907eafc

File tree

10 files changed

+2382
-2361
lines changed

10 files changed

+2382
-2361
lines changed

compiler/prelude/goroutines.go

Lines changed: 5 additions & 390 deletions
Original file line numberDiff line numberDiff line change
@@ -1,393 +1,8 @@
11
package prelude
22

3-
const goroutines = `
4-
var $stackDepthOffset = 0;
5-
var $getStackDepth = function() {
6-
var err = new Error();
7-
if (err.stack === undefined) {
8-
return undefined;
9-
}
10-
return $stackDepthOffset + err.stack.split("\n").length;
11-
};
3+
import (
4+
_ "embed"
5+
)
126

13-
var $panicStackDepth = null, $panicValue;
14-
var $callDeferred = function(deferred, jsErr, fromPanic) {
15-
if (!fromPanic && deferred !== null && $curGoroutine.deferStack.indexOf(deferred) == -1) {
16-
throw jsErr;
17-
}
18-
if (jsErr !== null) {
19-
var newErr = null;
20-
try {
21-
$panic(new $jsErrorPtr(jsErr));
22-
} catch (err) {
23-
newErr = err;
24-
}
25-
$callDeferred(deferred, newErr);
26-
return;
27-
}
28-
if ($curGoroutine.asleep) {
29-
return;
30-
}
31-
32-
$stackDepthOffset--;
33-
var outerPanicStackDepth = $panicStackDepth;
34-
var outerPanicValue = $panicValue;
35-
36-
var localPanicValue = $curGoroutine.panicStack.pop();
37-
if (localPanicValue !== undefined) {
38-
$panicStackDepth = $getStackDepth();
39-
$panicValue = localPanicValue;
40-
}
41-
42-
try {
43-
while (true) {
44-
if (deferred === null) {
45-
deferred = $curGoroutine.deferStack[$curGoroutine.deferStack.length - 1];
46-
if (deferred === undefined) {
47-
/* The panic reached the top of the stack. Clear it and throw it as a JavaScript error. */
48-
$panicStackDepth = null;
49-
if (localPanicValue.Object instanceof Error) {
50-
throw localPanicValue.Object;
51-
}
52-
var msg;
53-
if (localPanicValue.constructor === $String) {
54-
msg = localPanicValue.$val;
55-
} else if (localPanicValue.Error !== undefined) {
56-
msg = localPanicValue.Error();
57-
} else if (localPanicValue.String !== undefined) {
58-
msg = localPanicValue.String();
59-
} else {
60-
msg = localPanicValue;
61-
}
62-
throw new Error(msg);
63-
}
64-
}
65-
var call = deferred.pop();
66-
if (call === undefined) {
67-
$curGoroutine.deferStack.pop();
68-
if (localPanicValue !== undefined) {
69-
deferred = null;
70-
continue;
71-
}
72-
return;
73-
}
74-
var r = call[0].apply(call[2], call[1]);
75-
if (r && r.$blk !== undefined) {
76-
deferred.push([r.$blk, [], r]);
77-
if (fromPanic) {
78-
throw null;
79-
}
80-
return;
81-
}
82-
83-
if (localPanicValue !== undefined && $panicStackDepth === null) {
84-
/* error was recovered */
85-
if (fromPanic) {
86-
throw null;
87-
}
88-
return;
89-
}
90-
}
91-
} catch(e) {
92-
// Deferred function threw a JavaScript exception or tries to unwind stack
93-
// to the point where a panic was handled.
94-
if (fromPanic) {
95-
// Re-throw the exception to reach deferral execution call at the end
96-
// of the function.
97-
throw e;
98-
}
99-
// We are at the end of the function, handle the error or re-throw to
100-
// continue unwinding if necessary, or simply stop unwinding if we got far
101-
// enough.
102-
$callDeferred(deferred, e, fromPanic);
103-
} finally {
104-
if (localPanicValue !== undefined) {
105-
if ($panicStackDepth !== null) {
106-
$curGoroutine.panicStack.push(localPanicValue);
107-
}
108-
$panicStackDepth = outerPanicStackDepth;
109-
$panicValue = outerPanicValue;
110-
}
111-
$stackDepthOffset++;
112-
}
113-
};
114-
115-
var $panic = function(value) {
116-
$curGoroutine.panicStack.push(value);
117-
$callDeferred(null, null, true);
118-
};
119-
var $recover = function() {
120-
if ($panicStackDepth === null || ($panicStackDepth !== undefined && $panicStackDepth !== $getStackDepth() - 2)) {
121-
return $ifaceNil;
122-
}
123-
$panicStackDepth = null;
124-
return $panicValue;
125-
};
126-
var $throw = function(err) { throw err; };
127-
128-
var $noGoroutine = { asleep: false, exit: false, deferStack: [], panicStack: [] };
129-
var $curGoroutine = $noGoroutine, $totalGoroutines = 0, $awakeGoroutines = 0, $checkForDeadlock = true, $exportedFunctions = 0;
130-
var $mainFinished = false;
131-
var $go = function(fun, args) {
132-
$totalGoroutines++;
133-
$awakeGoroutines++;
134-
var $goroutine = function() {
135-
try {
136-
$curGoroutine = $goroutine;
137-
var r = fun.apply(undefined, args);
138-
if (r && r.$blk !== undefined) {
139-
fun = function() { return r.$blk(); };
140-
args = [];
141-
return;
142-
}
143-
$goroutine.exit = true;
144-
} catch (err) {
145-
if (!$goroutine.exit) {
146-
throw err;
147-
}
148-
} finally {
149-
$curGoroutine = $noGoroutine;
150-
if ($goroutine.exit) { /* also set by runtime.Goexit() */
151-
$totalGoroutines--;
152-
$goroutine.asleep = true;
153-
}
154-
if ($goroutine.asleep) {
155-
$awakeGoroutines--;
156-
if (!$mainFinished && $awakeGoroutines === 0 && $checkForDeadlock && $exportedFunctions === 0) {
157-
console.error("fatal error: all goroutines are asleep - deadlock!");
158-
if ($global.process !== undefined) {
159-
$global.process.exit(2);
160-
}
161-
}
162-
}
163-
}
164-
};
165-
$goroutine.asleep = false;
166-
$goroutine.exit = false;
167-
$goroutine.deferStack = [];
168-
$goroutine.panicStack = [];
169-
$schedule($goroutine);
170-
};
171-
172-
var $scheduled = [];
173-
var $runScheduled = function() {
174-
// For nested setTimeout calls browsers enforce 4ms minimum delay. We minimize
175-
// the effect of this penalty by queueing the timer preemptively before we run
176-
// the goroutines, and later cancelling it if it turns out unneeded. See:
177-
// https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#nested_timeouts
178-
var nextRun = setTimeout($runScheduled);
179-
try {
180-
var start = Date.now();
181-
var r;
182-
while ((r = $scheduled.shift()) !== undefined) {
183-
r();
184-
// We need to interrupt this loop in order to allow the event loop to
185-
// process timers, IO, etc. However, invoking scheduling through
186-
// setTimeout is ~1000 times more expensive, so we amortize this cost by
187-
// looping until the 4ms minimal delay has elapsed (assuming there are
188-
// scheduled goroutines to run), and then yield to the event loop.
189-
var elapsed = Date.now() - start;
190-
if (elapsed > 4 || elapsed < 0) { break; }
191-
}
192-
} finally {
193-
if ($scheduled.length == 0) {
194-
// Cancel scheduling pass if there's nothing to run.
195-
clearTimeout(nextRun);
196-
}
197-
}
198-
};
199-
200-
var $schedule = function(goroutine) {
201-
if (goroutine.asleep) {
202-
goroutine.asleep = false;
203-
$awakeGoroutines++;
204-
}
205-
$scheduled.push(goroutine);
206-
if ($curGoroutine === $noGoroutine) {
207-
$runScheduled();
208-
}
209-
};
210-
211-
var $setTimeout = function(f, t) {
212-
$awakeGoroutines++;
213-
return setTimeout(function() {
214-
$awakeGoroutines--;
215-
f();
216-
}, t);
217-
};
218-
219-
var $block = function() {
220-
if ($curGoroutine === $noGoroutine) {
221-
$throwRuntimeError("cannot block in JavaScript callback, fix by wrapping code in goroutine");
222-
}
223-
$curGoroutine.asleep = true;
224-
};
225-
226-
var $restore = function(context, params) {
227-
if (context !== undefined && context.$blk !== undefined) {
228-
return context;
229-
}
230-
return params;
231-
}
232-
233-
var $send = function(chan, value) {
234-
if (chan.$closed) {
235-
$throwRuntimeError("send on closed channel");
236-
}
237-
var queuedRecv = chan.$recvQueue.shift();
238-
if (queuedRecv !== undefined) {
239-
queuedRecv([value, true]);
240-
return;
241-
}
242-
if (chan.$buffer.length < chan.$capacity) {
243-
chan.$buffer.push(value);
244-
return;
245-
}
246-
247-
var thisGoroutine = $curGoroutine;
248-
var closedDuringSend;
249-
chan.$sendQueue.push(function(closed) {
250-
closedDuringSend = closed;
251-
$schedule(thisGoroutine);
252-
return value;
253-
});
254-
$block();
255-
return {
256-
$blk: function() {
257-
if (closedDuringSend) {
258-
$throwRuntimeError("send on closed channel");
259-
}
260-
}
261-
};
262-
};
263-
var $recv = function(chan) {
264-
var queuedSend = chan.$sendQueue.shift();
265-
if (queuedSend !== undefined) {
266-
chan.$buffer.push(queuedSend(false));
267-
}
268-
var bufferedValue = chan.$buffer.shift();
269-
if (bufferedValue !== undefined) {
270-
return [bufferedValue, true];
271-
}
272-
if (chan.$closed) {
273-
return [chan.$elem.zero(), false];
274-
}
275-
276-
var thisGoroutine = $curGoroutine;
277-
var f = { $blk: function() { return this.value; } };
278-
var queueEntry = function(v) {
279-
f.value = v;
280-
$schedule(thisGoroutine);
281-
};
282-
chan.$recvQueue.push(queueEntry);
283-
$block();
284-
return f;
285-
};
286-
var $close = function(chan) {
287-
if (chan.$closed) {
288-
$throwRuntimeError("close of closed channel");
289-
}
290-
chan.$closed = true;
291-
while (true) {
292-
var queuedSend = chan.$sendQueue.shift();
293-
if (queuedSend === undefined) {
294-
break;
295-
}
296-
queuedSend(true); /* will panic */
297-
}
298-
while (true) {
299-
var queuedRecv = chan.$recvQueue.shift();
300-
if (queuedRecv === undefined) {
301-
break;
302-
}
303-
queuedRecv([chan.$elem.zero(), false]);
304-
}
305-
};
306-
var $select = function(comms) {
307-
var ready = [];
308-
var selection = -1;
309-
for (var i = 0; i < comms.length; i++) {
310-
var comm = comms[i];
311-
var chan = comm[0];
312-
switch (comm.length) {
313-
case 0: /* default */
314-
selection = i;
315-
break;
316-
case 1: /* recv */
317-
if (chan.$sendQueue.length !== 0 || chan.$buffer.length !== 0 || chan.$closed) {
318-
ready.push(i);
319-
}
320-
break;
321-
case 2: /* send */
322-
if (chan.$closed) {
323-
$throwRuntimeError("send on closed channel");
324-
}
325-
if (chan.$recvQueue.length !== 0 || chan.$buffer.length < chan.$capacity) {
326-
ready.push(i);
327-
}
328-
break;
329-
}
330-
}
331-
332-
if (ready.length !== 0) {
333-
selection = ready[Math.floor(Math.random() * ready.length)];
334-
}
335-
if (selection !== -1) {
336-
var comm = comms[selection];
337-
switch (comm.length) {
338-
case 0: /* default */
339-
return [selection];
340-
case 1: /* recv */
341-
return [selection, $recv(comm[0])];
342-
case 2: /* send */
343-
$send(comm[0], comm[1]);
344-
return [selection];
345-
}
346-
}
347-
348-
var entries = [];
349-
var thisGoroutine = $curGoroutine;
350-
var f = { $blk: function() { return this.selection; } };
351-
var removeFromQueues = function() {
352-
for (var i = 0; i < entries.length; i++) {
353-
var entry = entries[i];
354-
var queue = entry[0];
355-
var index = queue.indexOf(entry[1]);
356-
if (index !== -1) {
357-
queue.splice(index, 1);
358-
}
359-
}
360-
};
361-
for (var i = 0; i < comms.length; i++) {
362-
(function(i) {
363-
var comm = comms[i];
364-
switch (comm.length) {
365-
case 1: /* recv */
366-
var queueEntry = function(value) {
367-
f.selection = [i, value];
368-
removeFromQueues();
369-
$schedule(thisGoroutine);
370-
};
371-
entries.push([comm[0].$recvQueue, queueEntry]);
372-
comm[0].$recvQueue.push(queueEntry);
373-
break;
374-
case 2: /* send */
375-
var queueEntry = function() {
376-
if (comm[0].$closed) {
377-
$throwRuntimeError("send on closed channel");
378-
}
379-
f.selection = [i];
380-
removeFromQueues();
381-
$schedule(thisGoroutine);
382-
return comm[1];
383-
};
384-
entries.push([comm[0].$sendQueue, queueEntry]);
385-
comm[0].$sendQueue.push(queueEntry);
386-
break;
387-
}
388-
})(i);
389-
}
390-
$block();
391-
return f;
392-
};
393-
`
7+
//go:embed goroutines.js
8+
var goroutines string

0 commit comments

Comments
 (0)