Chromium Code Reviews| Index: sdk/lib/_internal/lib/preambles/d8.js |
| diff --git a/sdk/lib/_internal/lib/preambles/d8.js b/sdk/lib/_internal/lib/preambles/d8.js |
| index 2b20e498350596c49ba89a8227e4eef465dfeb83..b26e6fddb9ecde7313019b9c00ad0bffcdf224e3 100644 |
| --- a/sdk/lib/_internal/lib/preambles/d8.js |
| +++ b/sdk/lib/_internal/lib/preambles/d8.js |
| @@ -3,3 +3,253 @@ |
| // BSD-style license that can be found in the LICENSE file. |
| // Javascript preamble, that lets the output of dart2js run on V8's d8 shell. |
| + |
| +var setTimeout; |
| +var clearTimeout; |
| +var setInterval; |
| +var clearInterval; |
| +var dartMainRunner; |
| +var scheduleImmediate; |
| + |
| +(function() { |
| + // Event loop. |
| + |
| + // Task queue as cyclic list queue. |
| + var taskQueue = new Array(8); // Length is power of 2. |
| + var head = 0; |
| + var tail = 0; |
| + var mask = taskQueue.length - 1; |
| + function addTask(elem) { |
| + taskQueue[head] = elem; |
| + head = (head + 1) & mask; |
| + if (head == tail) _growTaskQueue(); |
| + } |
| + function removeTask() { |
| + if (head == tail) return; |
| + var result = taskQueue[tail]; |
| + taskQueue[tail] = undefined; |
| + tail = (tail + 1) & mask; |
| + return result; |
| + } |
| + function _growTaskQueue() { |
| + // head == tail. |
| + var length = mask + 1; |
| + var split = head; |
| + taskQueue.length = length * 2; |
| + if (split * 2 < length) { // split < length / 2 |
| + for (var i = 0; i < split; i++) { |
| + taskQueue[length + i] = taskQueue[i]; |
| + taskQueue[i] = undefined; |
| + } |
| + tail += length; |
| + } else { |
| + for (var i = split; i < length; i++) { |
| + taskQueue[length + i] = taskQueue[i]; |
| + taskQueue[i] = undefined; |
| + } |
| + head += length; |
| + } |
| + mask = taskQueue.length - 1; |
| + } |
| + |
| + // Mapping from timer id to timer function. |
| + // The timer id is written on the function as .$timerId. |
| + // That field is cleared when the timer is cancelled, but it is not returned |
| + // from the queue until its time comes. |
| + var timerIds = {}; |
| + var timerIdCounter = 1; // Counter used to assing ids. |
| + |
| + // Zero-timer queue as simple array queue using push/shift. |
| + var zeroTimerQueue = []; |
| + |
| + function addTimer(f, ms) { |
| + var id = timerIdCounter++; |
| + f.$timerId = id; |
| + timerIds[id] = f; |
| + if (ms == 0) { |
| + zeroTimerQueue.push(f); |
| + } else { |
| + addDelayedTimer(f, ms); |
| + } |
| + return id; |
| + } |
| + |
| + function nextZeroTimer() { |
| + while (zeroTimerQueue.length > 0) { |
| + var action = zeroTimerQueue.shift(); |
| + if (action.$timerId !== undefined) return action; |
| + } |
| + } |
| + |
| + function nextEvent() { |
| + var action = removeTask(); |
| + if (action) { |
| + return action; |
| + } |
| + do { |
| + action = nextZeroTimer(); |
| + if (action) break; |
| + var nextList = nextDelayedTimerQueue(); |
| + if (!nextList) { |
| + return; |
| + } |
| + var newTime = nextList.shift(); |
| + advanceTimeTo(newTime); |
| + zeroTimerQueue = nextList; |
| + } while (true) |
| + var id = action.$timerId; |
| + clearTimerId(action, id); |
| + return action; |
| + } |
| + |
| + // Mocking time. |
| + var timeOffset = 0; |
| + var now = function() { |
| + installMockDate(); |
| + now = Date.now; |
|
floitsch
2014/03/19 14:08:31
I don't understand this.
Lasse Reichstein Nielsen
2014/04/11 10:28:43
Comment added.
|
| + return Date.now(); |
| + }; |
| + var originalDate = Date; |
| + var originalNow = originalDate.now; |
| + function advanceTimeTo(time) { |
| + timeOffset = time - originalNow(); |
| + } |
| + function installMockDate() { |
| + var NewDate = function Date(Y, M, D, h, m, s, ms) { |
| + if (this instanceof Date) { |
| + // Assume a construct call. |
| + switch (arguments.length) { |
| + case 0: return new originalDate(originalNow() + timeOffset); |
| + case 1: return new originalDate(Y); |
| + case 2: return new originalDate(Y, M); |
| + case 3: return new originalDate(Y, M, D); |
| + case 4: return new originalDate(Y, M, D, h); |
| + case 5: return new originalDate(Y, M, D, h, m); |
| + case 6: return new originalDate(Y, M, D, h, m, s); |
| + default: return new originalDate(Y, M, D, h, m, s, ms); |
| + } |
| + } |
| + return new originalDate(originalNow() + timeOffset).toString(); |
| + }; |
| + NewDate.now = function now() { return originalNow() + timeOffset; }; |
| + NewDate.prototype = originalDate.prototype; |
| + originalDate.prototype.constructor = NewDate; |
| + Date = NewDate; |
| + } |
| + |
| + // Heap priority queue with key index. |
| + // Each entry is list of [timeout, callback1 ... callbackn]. |
| + var timerHeap = []; |
| + var timerIndex = {}; |
| + function addDelayedTimer(f, ms) { |
| + var timeout = now() + ms; |
| + var timerList = timerIndex[timeout]; |
| + if (timerList == null) { |
| + timerList = [timeout, f]; |
| + timerIndex[timeout] = timerList; |
| + var index = timerHeap.length; |
| + timerHeap.length += 1; |
| + bubbleUp(index, timeout, timerList); |
| + } else { |
| + timerList.push(f); |
| + } |
| + } |
| + |
| + function nextDelayedTimerQueue() { |
| + if (timerHeap.length == 0) return null; |
| + var result = timerHeap[0]; |
| + var last = timerHeap.pop(); |
| + if (timerHeap.length > 0) { |
| + bubbleDown(0, last[0], last); |
| + } |
| + return result; |
| + } |
| + |
| + function bubbleUp(index, key, value) { |
| + while (index != 0) { |
| + var parentIndex = (index - 1) >> 1; |
| + var parent = timerHeap[parentIndex]; |
| + var parentKey = parent[0]; |
| + if (key > parentKey) break; |
| + timerHeap[index] = parent; |
| + index = parentIndex; |
| + } |
| + timerHeap[index] = value; |
| + } |
| + |
| + function bubbleDown(index, key, value) { |
| + while (true) { |
| + var rightChildIndex = index * 2 + 2; |
| + if (rightChildIndex > timerHeap.length) break; |
|
floitsch
2014/03/19 14:08:31
Nit.
It's hard to see that this test checks for th
|
| + var leftChildIndex = rightChildIndex - 1; |
| + var minChildIndex = leftChildIndex; |
| + var minChild = timerHeap[leftChildIndex]; |
| + var minChildKey = minChild[0]; |
| + if (rightChildIndex < timerHeap.length) { |
| + var rightChild = timerHeap[rightChildIndex]; |
| + var rightKey = rightChild[0]; |
| + if (rightKey < minChildKey) { |
| + minChildIndex = rightChildIndex; |
| + minChild = rightChild; |
| + minChildKey = rightKey; |
| + } |
| + } |
| + if (minChildKey > key) break; |
| + timerHeap[index] = minChild; |
| + index = minChildIndex; |
| + } |
| + timerHeap[index] = value; |
| + } |
| + |
| + function addInterval(f, ms) { |
| + var id = timerIdCounter++; |
| + function repeat() { |
| + // Reactivate with the same id. |
| + repeat.$timerId = id; |
| + timerIds[id] = repeat; |
| + addDelayedTimer(repeat, ms); |
| + f(); |
| + } |
| + repeat.$timerId = id; |
| + timerIds[id] = repeat; |
| + addDelayedTimer(repeat, ms); |
| + return id; |
| + } |
| + |
| + function cancelTimer(id) { |
| + var f = timerIds[id]; |
| + if (f == null) return; |
| + clearTimerId(f, id); |
| + } |
| + |
| + function clearTimerId(f, id) { |
| + f.$timerId = undefined; |
| + delete timerIds[id]; |
| + } |
| + |
| + function eventLoop(action) { |
| + while (action) { |
| + try { |
| + action(); |
| + } catch (e) { |
| + if (typeof onerror == "function") { |
| + onerror(e, null, -1); |
| + } else { |
| + throw e; |
| + } |
| + } |
| + action = nextEvent(); |
| + } |
| + } |
| + |
| + dartMainRunner = function(main, args) { |
| + // Initialize. |
| + var action = function() { main(args); } |
| + eventLoop(action); |
| + }; |
| + setTimeout = addTimer; |
| + clearTimeout = cancelTimer; |
| + setInterval = addInterval; |
| + clearInterval = cancelTimer; |
| + scheduleImmediate = addTask; |
| +})(); |