| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 // Javascript preamble, that lets the output of dart2js run on V8's d8 shell. | |
| 6 | |
| 7 // Node wraps files and provides them with a different `this`. The global | |
| 8 // `this` can be accessed through `global`. | |
| 9 | |
| 10 var self = this; | |
| 11 if (typeof global != "undefined") self = global; // Node.js. | |
| 12 | |
| 13 (function(self) { | |
| 14 // Using strict mode to avoid accidentally defining global variables. | |
| 15 "use strict"; // Should be first statement of this function. | |
| 16 | |
| 17 // Location (Uri.base) | |
| 18 | |
| 19 var workingDirectory; | |
| 20 // TODO(sgjesse): This does not work on Windows. | |
| 21 if (typeof os == "object" && "system" in os) { | |
| 22 // V8. | |
| 23 workingDirectory = os.system("pwd"); | |
| 24 var length = workingDirectory.length; | |
| 25 if (workingDirectory[length - 1] == '\n') { | |
| 26 workingDirectory = workingDirectory.substring(0, length - 1); | |
| 27 } | |
| 28 } else if (typeof process != "undefined" && | |
| 29 typeof process.cwd == "function") { | |
| 30 // Node.js. | |
| 31 workingDirectory = process.cwd(); | |
| 32 } | |
| 33 self.location = { href: "file://" + workingDirectory + "/" }; | |
| 34 | |
| 35 // Event loop. | |
| 36 | |
| 37 // Task queue as cyclic list queue. | |
| 38 var taskQueue = new Array(8); // Length is power of 2. | |
| 39 var head = 0; | |
| 40 var tail = 0; | |
| 41 var mask = taskQueue.length - 1; | |
| 42 function addTask(elem) { | |
| 43 taskQueue[head] = elem; | |
| 44 head = (head + 1) & mask; | |
| 45 if (head == tail) _growTaskQueue(); | |
| 46 } | |
| 47 function removeTask() { | |
| 48 if (head == tail) return; | |
| 49 var result = taskQueue[tail]; | |
| 50 taskQueue[tail] = undefined; | |
| 51 tail = (tail + 1) & mask; | |
| 52 return result; | |
| 53 } | |
| 54 function _growTaskQueue() { | |
| 55 // head == tail. | |
| 56 var length = taskQueue.length; | |
| 57 var split = head; | |
| 58 taskQueue.length = length * 2; | |
| 59 if (split * 2 < length) { // split < length / 2 | |
| 60 for (var i = 0; i < split; i++) { | |
| 61 taskQueue[length + i] = taskQueue[i]; | |
| 62 taskQueue[i] = undefined; | |
| 63 } | |
| 64 head += length; | |
| 65 } else { | |
| 66 for (var i = split; i < length; i++) { | |
| 67 taskQueue[length + i] = taskQueue[i]; | |
| 68 taskQueue[i] = undefined; | |
| 69 } | |
| 70 tail += length; | |
| 71 } | |
| 72 mask = taskQueue.length - 1; | |
| 73 } | |
| 74 | |
| 75 // Mapping from timer id to timer function. | |
| 76 // The timer id is written on the function as .$timerId. | |
| 77 // That field is cleared when the timer is cancelled, but it is not returned | |
| 78 // from the queue until its time comes. | |
| 79 var timerIds = {}; | |
| 80 var timerIdCounter = 1; // Counter used to assing ids. | |
| 81 | |
| 82 // Zero-timer queue as simple array queue using push/shift. | |
| 83 var zeroTimerQueue = []; | |
| 84 | |
| 85 function addTimer(f, ms) { | |
| 86 var id = timerIdCounter++; | |
| 87 f.$timerId = id; | |
| 88 timerIds[id] = f; | |
| 89 if (ms == 0) { | |
| 90 zeroTimerQueue.push(f); | |
| 91 } else { | |
| 92 addDelayedTimer(f, ms); | |
| 93 } | |
| 94 return id; | |
| 95 } | |
| 96 | |
| 97 function nextZeroTimer() { | |
| 98 while (zeroTimerQueue.length > 0) { | |
| 99 var action = zeroTimerQueue.shift(); | |
| 100 if (action.$timerId !== undefined) return action; | |
| 101 } | |
| 102 } | |
| 103 | |
| 104 function nextEvent() { | |
| 105 var action = removeTask(); | |
| 106 if (action) { | |
| 107 return action; | |
| 108 } | |
| 109 do { | |
| 110 action = nextZeroTimer(); | |
| 111 if (action) break; | |
| 112 var nextList = nextDelayedTimerQueue(); | |
| 113 if (!nextList) { | |
| 114 return; | |
| 115 } | |
| 116 var newTime = nextList.shift(); | |
| 117 advanceTimeTo(newTime); | |
| 118 zeroTimerQueue = nextList; | |
| 119 } while (true) | |
| 120 var id = action.$timerId; | |
| 121 clearTimerId(action, id); | |
| 122 return action; | |
| 123 } | |
| 124 | |
| 125 // Mocking time. | |
| 126 var timeOffset = 0; | |
| 127 var now = function() { | |
| 128 // Install the mock Date object only once. | |
| 129 // Following calls to "now" will just use the new (mocked) Date.now | |
| 130 // method directly. | |
| 131 installMockDate(); | |
| 132 now = Date.now; | |
| 133 return Date.now(); | |
| 134 }; | |
| 135 var originalDate = Date; | |
| 136 var originalNow = originalDate.now; | |
| 137 function advanceTimeTo(time) { | |
| 138 timeOffset = time - originalNow(); | |
| 139 } | |
| 140 function installMockDate() { | |
| 141 var NewDate = function Date(Y, M, D, h, m, s, ms) { | |
| 142 if (this instanceof Date) { | |
| 143 // Assume a construct call. | |
| 144 switch (arguments.length) { | |
| 145 case 0: return new originalDate(originalNow() + timeOffset); | |
| 146 case 1: return new originalDate(Y); | |
| 147 case 2: return new originalDate(Y, M); | |
| 148 case 3: return new originalDate(Y, M, D); | |
| 149 case 4: return new originalDate(Y, M, D, h); | |
| 150 case 5: return new originalDate(Y, M, D, h, m); | |
| 151 case 6: return new originalDate(Y, M, D, h, m, s); | |
| 152 default: return new originalDate(Y, M, D, h, m, s, ms); | |
| 153 } | |
| 154 } | |
| 155 return new originalDate(originalNow() + timeOffset).toString(); | |
| 156 }; | |
| 157 NewDate.UTC = originalDate.UTC; | |
| 158 NewDate.parse = originalDate.parse; | |
| 159 NewDate.now = function now() { return originalNow() + timeOffset; }; | |
| 160 NewDate.prototype = originalDate.prototype; | |
| 161 originalDate.prototype.constructor = NewDate; | |
| 162 Date = NewDate; | |
| 163 } | |
| 164 | |
| 165 // Heap priority queue with key index. | |
| 166 // Each entry is list of [timeout, callback1 ... callbackn]. | |
| 167 var timerHeap = []; | |
| 168 var timerIndex = {}; | |
| 169 function addDelayedTimer(f, ms) { | |
| 170 var timeout = now() + ms; | |
| 171 var timerList = timerIndex[timeout]; | |
| 172 if (timerList == null) { | |
| 173 timerList = [timeout, f]; | |
| 174 timerIndex[timeout] = timerList; | |
| 175 var index = timerHeap.length; | |
| 176 timerHeap.length += 1; | |
| 177 bubbleUp(index, timeout, timerList); | |
| 178 } else { | |
| 179 timerList.push(f); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 function nextDelayedTimerQueue() { | |
| 184 if (timerHeap.length == 0) return null; | |
| 185 var result = timerHeap[0]; | |
| 186 var last = timerHeap.pop(); | |
| 187 if (timerHeap.length > 0) { | |
| 188 bubbleDown(0, last[0], last); | |
| 189 } | |
| 190 return result; | |
| 191 } | |
| 192 | |
| 193 function bubbleUp(index, key, value) { | |
| 194 while (index != 0) { | |
| 195 var parentIndex = (index - 1) >> 1; | |
| 196 var parent = timerHeap[parentIndex]; | |
| 197 var parentKey = parent[0]; | |
| 198 if (key > parentKey) break; | |
| 199 timerHeap[index] = parent; | |
| 200 index = parentIndex; | |
| 201 } | |
| 202 timerHeap[index] = value; | |
| 203 } | |
| 204 | |
| 205 function bubbleDown(index, key, value) { | |
| 206 while (true) { | |
| 207 var leftChildIndex = index * 2 + 1; | |
| 208 if (leftChildIndex >= timerHeap.length) break; | |
| 209 var minChildIndex = leftChildIndex; | |
| 210 var minChild = timerHeap[leftChildIndex]; | |
| 211 var minChildKey = minChild[0]; | |
| 212 var rightChildIndex = leftChildIndex + 1; | |
| 213 if (rightChildIndex < timerHeap.length) { | |
| 214 var rightChild = timerHeap[rightChildIndex]; | |
| 215 var rightKey = rightChild[0]; | |
| 216 if (rightKey < minChildKey) { | |
| 217 minChildIndex = rightChildIndex; | |
| 218 minChild = rightChild; | |
| 219 minChildKey = rightKey; | |
| 220 } | |
| 221 } | |
| 222 if (minChildKey > key) break; | |
| 223 timerHeap[index] = minChild; | |
| 224 index = minChildIndex; | |
| 225 } | |
| 226 timerHeap[index] = value; | |
| 227 } | |
| 228 | |
| 229 function addInterval(f, ms) { | |
| 230 var id = timerIdCounter++; | |
| 231 function repeat() { | |
| 232 // Reactivate with the same id. | |
| 233 repeat.$timerId = id; | |
| 234 timerIds[id] = repeat; | |
| 235 addDelayedTimer(repeat, ms); | |
| 236 f(); | |
| 237 } | |
| 238 repeat.$timerId = id; | |
| 239 timerIds[id] = repeat; | |
| 240 addDelayedTimer(repeat, ms); | |
| 241 return id; | |
| 242 } | |
| 243 | |
| 244 function cancelTimer(id) { | |
| 245 var f = timerIds[id]; | |
| 246 if (f == null) return; | |
| 247 clearTimerId(f, id); | |
| 248 } | |
| 249 | |
| 250 function clearTimerId(f, id) { | |
| 251 f.$timerId = undefined; | |
| 252 delete timerIds[id]; | |
| 253 } | |
| 254 | |
| 255 function eventLoop(action) { | |
| 256 while (action) { | |
| 257 try { | |
| 258 action(); | |
| 259 } catch (e) { | |
| 260 if (typeof onerror == "function") { | |
| 261 onerror(e, null, -1); | |
| 262 } else { | |
| 263 throw e; | |
| 264 } | |
| 265 } | |
| 266 action = nextEvent(); | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 // Global properties. "self" refers to the global object, so adding a | |
| 271 // property to "self" defines a global variable. | |
| 272 self.self = self | |
| 273 self.dartMainRunner = function(main, args) { | |
| 274 // Initialize. | |
| 275 var action = function() { main(args); } | |
| 276 eventLoop(action); | |
| 277 }; | |
| 278 self.setTimeout = addTimer; | |
| 279 self.clearTimeout = cancelTimer; | |
| 280 self.setInterval = addInterval; | |
| 281 self.clearInterval = cancelTimer; | |
| 282 self.scheduleImmediate = addTask; | |
| 283 | |
| 284 function computeCurrentScript() { | |
| 285 try { | |
| 286 throw new Error(); | |
| 287 } catch(e) { | |
| 288 var stack = e.stack; | |
| 289 // The V8 stack looks like: | |
| 290 // at computeCurrentScript (preambles/d8.js:286:13) | |
| 291 // at Object.currentScript (preambles/d8.js:308:31) | |
| 292 // at init.currentScript (/tmp/foo.js:308:19) | |
| 293 // at /tmp/foo.js:320:7 | |
| 294 // at /tmp/foo.js:331:4 | |
| 295 var re = new RegExp("^ *at [^(]*\\((.*):[0-9]*:[0-9]*\\)$", "mg"); | |
| 296 var lastMatch = null; | |
| 297 do { | |
| 298 var match = re.exec(stack); | |
| 299 if (match != null) lastMatch = match; | |
| 300 } while (match != null); | |
| 301 return lastMatch[1]; | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 // Adding a 'document' is dangerous since it invalidates the 'typeof document' | |
| 306 // test to see if we are running in the browser. It means that the runtime | |
| 307 // needs to do more precise checks. | |
| 308 // Note that we can't run "currentScript" right away, since that would give | |
| 309 // us the location of the preamble file. Instead we wait for the first access | |
| 310 // which should happen just before invoking main. At this point we are in | |
| 311 // the main file and setting the currentScript property is correct. | |
| 312 var cachedCurrentScript = null; | |
| 313 self.document = { get currentScript() { | |
| 314 if (cachedCurrentScript == null) { | |
| 315 cachedCurrentScript = {src: computeCurrentScript()}; | |
| 316 } | |
| 317 return cachedCurrentScript; | |
| 318 } | |
| 319 }; | |
| 320 | |
| 321 // Support for deferred loading. | |
| 322 self.dartDeferredLibraryLoader = function(uri, successCallback, errorCallback)
{ | |
| 323 try { | |
| 324 load(uri); | |
| 325 successCallback(); | |
| 326 } catch (error) { | |
| 327 errorCallback(error); | |
| 328 } | |
| 329 }; | |
| 330 })(self); | |
| OLD | NEW |