Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: lib/isolate/dart2js/isolateimpl.dart

Issue 10837070: Remove old isolate API and update all code in the repository to use (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address review comments. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | lib/isolate/isolate_api.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * Concepts used here: 6 * Concepts used here:
7 * 7 *
8 * "manager" - A manager contains one or more isolates, schedules their 8 * "manager" - A manager contains one or more isolates, schedules their
9 * execution, and performs other plumbing on their behalf. The isolate 9 * execution, and performs other plumbing on their behalf. The isolate
10 * present at the creation of the manager is designated as its "root isolate". 10 * present at the creation of the manager is designated as its "root isolate".
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 } 45 }
46 return _lazyPort; 46 return _lazyPort;
47 } 47 }
48 48
49 SendPort _spawnFunction(void topLevelFunction()) { 49 SendPort _spawnFunction(void topLevelFunction()) {
50 final name = _IsolateNatives._getJSFunctionName(topLevelFunction); 50 final name = _IsolateNatives._getJSFunctionName(topLevelFunction);
51 if (name == null) { 51 if (name == null) {
52 throw new UnsupportedOperationException( 52 throw new UnsupportedOperationException(
53 "only top-level functions can be spawned."); 53 "only top-level functions can be spawned.");
54 } 54 }
55 return _IsolateNatives._spawn2(name, null, false); 55 return _IsolateNatives._spawn(name, null, false);
56 } 56 }
57 57
58 SendPort _spawnUri(String uri) { 58 SendPort _spawnUri(String uri) {
59 return _IsolateNatives._spawn2(null, uri, false); 59 return _IsolateNatives._spawn(null, uri, false);
60 } 60 }
61 61
62 /** State associated with the current manager. See [globalState]. */ 62 /** State associated with the current manager. See [globalState]. */
63 // TODO(sigmund): split in multiple classes: global, thread, main-worker states? 63 // TODO(sigmund): split in multiple classes: global, thread, main-worker states?
64 class _Manager { 64 class _Manager {
65 65
66 /** Next available isolate id within this [_Manager]. */ 66 /** Next available isolate id within this [_Manager]. */
67 int nextIsolateId = 0; 67 int nextIsolateId = 0;
68 68
69 /** id assigned to this [_Manager]. */ 69 /** id assigned to this [_Manager]. */
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 void set onmessage(f) native "this.onmessage = f;"; 352 void set onmessage(f) native "this.onmessage = f;";
353 void postMessage(msg) native "return this.postMessage(msg);"; 353 void postMessage(msg) native "return this.postMessage(msg);";
354 // terminate() is implemented by Worker. 354 // terminate() is implemented by Worker.
355 abstract void terminate(); 355 abstract void terminate();
356 } 356 }
357 357
358 final String _SPAWNED_SIGNAL = "spawned"; 358 final String _SPAWNED_SIGNAL = "spawned";
359 359
360 class _IsolateNatives { 360 class _IsolateNatives {
361 361
362 /** JavaScript-specific implementation to spawn an isolate. */
363 static Future<SendPort> spawn(Isolate isolate, bool isLight) {
364 Completer<SendPort> completer = new Completer<SendPort>();
365 ReceivePort port = new ReceivePort();
366 port.receive((msg, SendPort replyPort) {
367 port.close();
368 assert(msg == _SPAWNED_SIGNAL);
369 completer.complete(replyPort);
370 });
371
372 // TODO(floitsch): throw exception if isolate's class doesn't have a
373 // default constructor.
374 if (_globalState.useWorkers && !isLight) {
375 _startWorker(isolate, port.toSendPort());
376 } else {
377 _startNonWorker(isolate, port.toSendPort());
378 }
379
380 return completer.future;
381 }
382
383 static SendPort _startWorker(Isolate runnable, SendPort replyPort) {
384 var factoryName = _getJSConstructorName(runnable);
385 if (_globalState.isWorker) {
386 _globalState.mainManager.postMessage(_serializeMessage({
387 'command': 'spawn-worker',
388 'factoryName': factoryName,
389 'replyPort': _serializeMessage(replyPort)}));
390 } else {
391 _spawnWorker(factoryName, _serializeMessage(replyPort));
392 }
393 }
394
395 /** 362 /**
396 * The src url for the script tag that loaded this code. Used to create 363 * The src url for the script tag that loaded this code. Used to create
397 * JavaScript workers. 364 * JavaScript workers.
398 */ 365 */
399 static String get _thisScript() native @"return $thisScriptUrl"; 366 static String get _thisScript() native @"return $thisScriptUrl";
400 367
401 /** Starts a new worker with the given URL. */ 368 /** Starts a new worker with the given URL. */
402 static _WorkerStub _newWorker(url) native "return new Worker(url);"; 369 static _WorkerStub _newWorker(url) native "return new Worker(url);";
403 370
404 /** 371 /**
405 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor
406 * name for the isolate entry point class.
407 */
408 static void _spawnWorker(factoryName, serializedReplyPort) {
409 final worker = _newWorker(_thisScript);
410 worker.onmessage = (e) { _processWorkerMessage(worker, e); };
411 var workerId = _globalState.nextManagerId++;
412 // We also store the id on the worker itself so that we can unregister it.
413 worker.id = workerId;
414 _globalState.managers[workerId] = worker;
415 worker.postMessage(_serializeMessage({
416 'command': 'start',
417 'id': workerId,
418 'replyTo': serializedReplyPort,
419 'factoryName': factoryName }));
420 }
421
422 /**
423 * Assume that [e] is a browser message event and extract its message data. 372 * Assume that [e] is a browser message event and extract its message data.
424 * We don't import the dom explicitly so, when workers are disabled, this 373 * We don't import the dom explicitly so, when workers are disabled, this
425 * library can also run on top of nodejs. 374 * library can also run on top of nodejs.
426 */ 375 */
427 static _getEventData(e) native "return e.data"; 376 static _getEventData(e) native "return e.data";
428 377
429 /** 378 /**
430 * Process messages on a worker, either to control the worker instance or to 379 * Process messages on a worker, either to control the worker instance or to
431 * pass messages along to the isolate running in the worker. 380 * pass messages along to the isolate running in the worker.
432 */ 381 */
433 static void _processWorkerMessage(sender, e) { 382 static void _processWorkerMessage(sender, e) {
434 var msg = _deserializeMessage(_getEventData(e)); 383 var msg = _deserializeMessage(_getEventData(e));
435 switch (msg['command']) { 384 switch (msg['command']) {
436 // TODO(sigmund): delete after we migrate to the new API
437 case 'start': 385 case 'start':
438 _globalState.currentManagerId = msg['id']; 386 _globalState.currentManagerId = msg['id'];
439 var runnerObject =
440 _allocate(_getJSConstructorFromName(msg['factoryName']));
441 var serializedReplyTo = msg['replyTo'];
442 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
443 var replyTo = _deserializeMessage(serializedReplyTo);
444 _startIsolate(runnerObject, replyTo);
445 }, 'worker-start');
446 _globalState.topEventLoop.run();
447 break;
448 case 'start2':
449 _globalState.currentManagerId = msg['id'];
450 Function entryPoint = _getJSFunctionFromName(msg['functionName']); 387 Function entryPoint = _getJSFunctionFromName(msg['functionName']);
451 var replyTo = _deserializeMessage(msg['replyTo']); 388 var replyTo = _deserializeMessage(msg['replyTo']);
452 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { 389 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
453 _startIsolate2(entryPoint, replyTo); 390 _startIsolate(entryPoint, replyTo);
454 }, 'worker-start'); 391 }, 'worker-start');
455 _globalState.topEventLoop.run(); 392 _globalState.topEventLoop.run();
456 break; 393 break;
457 // TODO(sigmund): delete after we migrate to the new API
458 case 'spawn-worker': 394 case 'spawn-worker':
459 _spawnWorker(msg['factoryName'], msg['replyPort']); 395 _spawnWorker(msg['functionName'], msg['uri'], msg['replyPort']);
460 break;
461 case 'spawn-worker2':
462 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']);
463 break; 396 break;
464 case 'message': 397 case 'message':
465 msg['port'].send(msg['msg'], msg['replyTo']); 398 msg['port'].send(msg['msg'], msg['replyTo']);
466 _globalState.topEventLoop.run(); 399 _globalState.topEventLoop.run();
467 break; 400 break;
468 case 'close': 401 case 'close':
469 _log("Closing Worker"); 402 _log("Closing Worker");
470 _globalState.managers.remove(sender.id); 403 _globalState.managers.remove(sender.id);
471 sender.terminate(); 404 sender.terminate();
472 _globalState.topEventLoop.run(); 405 _globalState.topEventLoop.run();
(...skipping 23 matching lines...) Expand all
496 try { 429 try {
497 _consoleLog(msg); 430 _consoleLog(msg);
498 } catch(var e, var trace) { 431 } catch(var e, var trace) {
499 throw new Exception(trace); 432 throw new Exception(trace);
500 } 433 }
501 } 434 }
502 } 435 }
503 436
504 static void _consoleLog(msg) native "\$globalThis.console.log(msg);"; 437 static void _consoleLog(msg) native "\$globalThis.console.log(msg);";
505 438
506
507 /** 439 /**
508 * Extract the constructor of runnable, so it can be allocated in another 440 * Extract the constructor of runnable, so it can be allocated in another
509 * isolate. 441 * isolate.
510 */ 442 */
511 static Dynamic _getJSConstructor(Isolate runnable) native """ 443 static Dynamic _getJSConstructor(Isolate runnable) native """
512 return runnable.constructor; 444 return runnable.constructor;
513 """; 445 """;
514 446
515 /** Extract the constructor name of a runnable */ 447 /** Extract the constructor name of a runnable */
516 // TODO(sigmund): find a browser-generic way to support this. 448 // TODO(sigmund): find a browser-generic way to support this.
(...skipping 14 matching lines...) Expand all
531 * Get a string name for the function, if possible. The result for 463 * Get a string name for the function, if possible. The result for
532 * anonymous functions is browser-dependent -- it may be "" or "anonymous" 464 * anonymous functions is browser-dependent -- it may be "" or "anonymous"
533 * but you should probably not count on this. 465 * but you should probably not count on this.
534 */ 466 */
535 static String _getJSFunctionName(Function f) 467 static String _getJSFunctionName(Function f)
536 native @"return f.$name || (void 0);"; 468 native @"return f.$name || (void 0);";
537 469
538 /** Create a new JavaScript object instance given its constructor. */ 470 /** Create a new JavaScript object instance given its constructor. */
539 static Dynamic _allocate(var ctor) native "return new ctor();"; 471 static Dynamic _allocate(var ctor) native "return new ctor();";
540 472
541 /** Starts a non-worker isolate. */
542 static SendPort _startNonWorker(Isolate runnable, SendPort replyTo) {
543 // Spawn a new isolate and create the receive port in it.
544 final spawned = new _IsolateContext();
545
546 // Instead of just running the provided runnable, we create a
547 // new cloned instance of it with a fresh state in the spawned
548 // isolate. This way, we do not get cross-isolate references
549 // through the runnable.
550 final ctor = _getJSConstructor(runnable);
551 _globalState.topEventLoop.enqueue(spawned, function() {
552 _startIsolate(_allocate(ctor), replyTo);
553 }, 'nonworker start');
554 }
555
556 /** Given a ready-to-start runnable, start running it. */
557 static void _startIsolate(Isolate isolate, SendPort replyTo) {
558 _fillStatics(_globalState.currentContext);
559 ReceivePort port = new ReceivePort();
560 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
561 isolate._run(port);
562 }
563
564 // TODO(sigmund): clean up above, after we make the new API the default: 473 // TODO(sigmund): clean up above, after we make the new API the default:
565 474
566 static _spawn2(String functionName, String uri, bool isLight) { 475 static _spawn(String functionName, String uri, bool isLight) {
567 Completer<SendPort> completer = new Completer<SendPort>(); 476 Completer<SendPort> completer = new Completer<SendPort>();
568 ReceivePort port = new ReceivePort(); 477 ReceivePort port = new ReceivePort();
569 port.receive((msg, SendPort replyPort) { 478 port.receive((msg, SendPort replyPort) {
570 port.close(); 479 port.close();
571 assert(msg == _SPAWNED_SIGNAL); 480 assert(msg == _SPAWNED_SIGNAL);
572 completer.complete(replyPort); 481 completer.complete(replyPort);
573 }); 482 });
574 483
575 SendPort signalReply = port.toSendPort(); 484 SendPort signalReply = port.toSendPort();
576 485
577 if (_globalState.useWorkers && !isLight) { 486 if (_globalState.useWorkers && !isLight) {
578 _startWorker2(functionName, uri, signalReply); 487 _startWorker(functionName, uri, signalReply);
579 } else { 488 } else {
580 _startNonWorker2(functionName, uri, signalReply); 489 _startNonWorker(functionName, uri, signalReply);
581 } 490 }
582 return new _BufferingSendPort( 491 return new _BufferingSendPort(
583 _globalState.currentContext.id, completer.future); 492 _globalState.currentContext.id, completer.future);
584 } 493 }
585 494
586 static SendPort _startWorker2( 495 static SendPort _startWorker(
587 String functionName, String uri, SendPort replyPort) { 496 String functionName, String uri, SendPort replyPort) {
588 if (_globalState.isWorker) { 497 if (_globalState.isWorker) {
589 _globalState.mainManager.postMessage(_serializeMessage({ 498 _globalState.mainManager.postMessage(_serializeMessage({
590 'command': 'spawn-worker2', 499 'command': 'spawn-worker',
591 'functionName': functionName, 500 'functionName': functionName,
592 'uri': uri, 501 'uri': uri,
593 'replyPort': replyPort})); 502 'replyPort': replyPort}));
594 } else { 503 } else {
595 _spawnWorker2(functionName, uri, replyPort); 504 _spawnWorker(functionName, uri, replyPort);
596 } 505 }
597 } 506 }
598 507
599 static SendPort _startNonWorker2( 508 static SendPort _startNonWorker(
600 String functionName, String uri, SendPort replyPort) { 509 String functionName, String uri, SendPort replyPort) {
601 // TODO(eub): support IE9 using an iframe -- Dart issue 1702. 510 // TODO(eub): support IE9 using an iframe -- Dart issue 1702.
602 if (uri != null) throw new UnsupportedOperationException( 511 if (uri != null) throw new UnsupportedOperationException(
603 "Currently spawnUri is not supported without web workers."); 512 "Currently spawnUri is not supported without web workers.");
604 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { 513 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
605 final func = _getJSFunctionFromName(functionName); 514 final func = _getJSFunctionFromName(functionName);
606 _startIsolate2(func, replyPort); 515 _startIsolate(func, replyPort);
607 }, 'nonworker start'); 516 }, 'nonworker start');
608 } 517 }
609 518
610 static void _startIsolate2(Function topLevel, SendPort replyTo) { 519 static void _startIsolate(Function topLevel, SendPort replyTo) {
611 _fillStatics(_globalState.currentContext); 520 _fillStatics(_globalState.currentContext);
612 _lazyPort = new ReceivePort(); 521 _lazyPort = new ReceivePort();
613 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); 522 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
614 topLevel(); 523 topLevel();
615 } 524 }
616 525
617 /** 526 /**
618 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor 527 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor
619 * name for the isolate entry point class. 528 * name for the isolate entry point class.
620 */ 529 */
621 static void _spawnWorker2(functionName, uri, replyPort) { 530 static void _spawnWorker(functionName, uri, replyPort) {
622 if (functionName == null) functionName = 'main'; 531 if (functionName == null) functionName = 'main';
623 if (uri == null) uri = _thisScript; 532 if (uri == null) uri = _thisScript;
624 if (!(new Uri.fromString(uri).isAbsolute())) { 533 if (!(new Uri.fromString(uri).isAbsolute())) {
625 // The constructor of dom workers requires an absolute URL. If we use a 534 // The constructor of dom workers requires an absolute URL. If we use a
626 // relative path we will get a DOM exception. 535 // relative path we will get a DOM exception.
627 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/')); 536 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/'));
628 uri = "$prefix/$uri"; 537 uri = "$prefix/$uri";
629 } 538 }
630 final worker = _newWorker(uri); 539 final worker = _newWorker(uri);
631 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; 540 worker.onmessage = (e) { _processWorkerMessage(worker, e); };
632 var workerId = _globalState.nextManagerId++; 541 var workerId = _globalState.nextManagerId++;
633 // We also store the id on the worker itself so that we can unregister it. 542 // We also store the id on the worker itself so that we can unregister it.
634 worker.id = workerId; 543 worker.id = workerId;
635 _globalState.managers[workerId] = worker; 544 _globalState.managers[workerId] = worker;
636 worker.postMessage(_serializeMessage({ 545 worker.postMessage(_serializeMessage({
637 'command': 'start2', 546 'command': 'start',
638 'id': workerId, 547 'id': workerId,
639 // Note: we serialize replyPort twice because the child worker needs to 548 // Note: we serialize replyPort twice because the child worker needs to
640 // first deserialize the worker id, before it can correctly deserialize 549 // first deserialize the worker id, before it can correctly deserialize
641 // the port (port deserialization is sensitive to what is the current 550 // the port (port deserialization is sensitive to what is the current
642 // workerId). 551 // workerId).
643 'replyTo': _serializeMessage(replyPort), 552 'replyTo': _serializeMessage(replyPort),
644 'functionName': functionName })); 553 'functionName': functionName }));
645 } 554 }
646 } 555 }
OLDNEW
« no previous file with comments | « no previous file | lib/isolate/isolate_api.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698