blob: 01f890b1eedf4652673b9142ee606bb0d7a1515b [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library _isolate_helper;
import 'dart:async';
import 'dart:isolate';
import 'dart:_js_embedded_names' show CURRENT_SCRIPT;
import 'dart:_js_helper'
show convertDartClosureToJS, random64, requiresPreamble;
import 'dart:_foreign_helper' show JS, JS_EMBEDDED_GLOBAL;
import 'dart:_interceptors' show JSExtendableArray;
/// Returns true if we are currently in a worker context.
bool isWorker() {
requiresPreamble();
return JS('', '!self.window && !!self.postMessage');
}
/// The src url for the script tag that loaded this code.
String thisScript = computeThisScript();
/// The src url for the script tag that loaded this function.
///
/// Used to create JavaScript workers and load deferred libraries.
String computeThisScript() {
var currentScript = JS_EMBEDDED_GLOBAL('', CURRENT_SCRIPT);
if (currentScript != null) {
return JS('String', 'String(#.src)', currentScript);
}
// A worker has no script tag - so get an url from a stack-trace.
if (isWorker()) return _computeThisScriptFromTrace();
// An isolate that doesn't support workers, but doesn't have a
// currentScript either. This is most likely a Chrome extension.
return null;
}
String _computeThisScriptFromTrace() {
var stack = JS('String|Null', 'new Error().stack');
if (stack == null) {
// According to Internet Explorer documentation, the stack
// property is not set until the exception is thrown. The stack
// property was not provided until IE10.
stack = JS(
'String|Null',
'(function() {'
'try { throw new Error() } catch(e) { return e.stack }'
'})()');
if (stack == null) throw new UnsupportedError('No stack trace');
}
var pattern, matches;
// This pattern matches V8, Chrome, and Internet Explorer stack
// traces that look like this:
// Error
// at methodName (URI:LINE:COLUMN)
pattern = JS('', r'new RegExp("^ *at [^(]*\\((.*):[0-9]*:[0-9]*\\)$", "m")');
matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern);
if (matches != null) return JS('String', '#[1]', matches);
// This pattern matches Firefox stack traces that look like this:
// methodName@URI:LINE
pattern = JS('', r'new RegExp("^[^@]*@(.*):[0-9]*$", "m")');
matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern);
if (matches != null) return JS('String', '#[1]', matches);
throw new UnsupportedError('Cannot extract URI from "$stack"');
}
class ReceivePortImpl extends Stream implements ReceivePort {
ReceivePortImpl();
StreamSubscription listen(void onData(var event),
{Function onError, void onDone(), bool cancelOnError}) {
throw new UnsupportedError("ReceivePort.listen");
}
void close() {}
SendPort get sendPort => throw new UnsupportedError("ReceivePort.sendPort");
}
class TimerImpl implements Timer {
final bool _once;
int _handle;
int _tick = 0;
TimerImpl(int milliseconds, void callback()) : _once = true {
if (_hasTimer()) {
void internalCallback() {
_handle = null;
this._tick = 1;
callback();
}
_handle = JS('int', 'self.setTimeout(#, #)',
convertDartClosureToJS(internalCallback, 0), milliseconds);
} else {
throw new UnsupportedError('`setTimeout()` not found.');
}
}
TimerImpl.periodic(int milliseconds, void callback(Timer timer))
: _once = false {
if (_hasTimer()) {
int start = JS('int', 'Date.now()');
_handle = JS(
'int',
'self.setInterval(#, #)',
convertDartClosureToJS(() {
int tick = this._tick + 1;
if (milliseconds > 0) {
int duration = JS('int', 'Date.now()') - start;
if (duration > (tick + 1) * milliseconds) {
tick = duration ~/ milliseconds;
}
}
this._tick = tick;
callback(this);
}, 0),
milliseconds);
} else {
throw new UnsupportedError('Periodic timer.');
}
}
@override
bool get isActive => _handle != null;
@override
int get tick => _tick;
@override
void cancel() {
if (_hasTimer()) {
if (_handle == null) return;
if (_once) {
JS('void', 'self.clearTimeout(#)', _handle);
} else {
JS('void', 'self.clearInterval(#)', _handle);
}
_handle = null;
} else {
throw new UnsupportedError('Canceling a timer.');
}
}
}
bool _hasTimer() {
requiresPreamble();
return JS('', 'self.setTimeout') != null;
}