Merge r13661-13672 into trunk.

git-svn-id: http://dart.googlecode.com/svn/trunk@13673 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/client/tools/buildbot_annotated_steps.py b/client/tools/buildbot_annotated_steps.py
index 7d4cdd6..91bf125 100644
--- a/client/tools/buildbot_annotated_steps.py
+++ b/client/tools/buildbot_annotated_steps.py
@@ -96,6 +96,10 @@
 
   toolsBuildScript = os.path.join('.', 'editor', 'build', 'build.py')
 
+  # TODO(devoncarew): should we move this into GetBuildInfo()?  
+  # get the latest changed revision from the current repository sub-tree
+  version = GetLatestChangedRevision()
+
   #TODO: debug statements to be removed in the future.
   print "mode = " + mode
   print "name = " + name
@@ -152,8 +156,36 @@
 def GetShouldClobber():
   return os.environ.get(BUILDER_CLOBBER) == "1"
 
+def RunDart(scriptPath):
+  if sys.platform == 'darwin':
+    pipe = subprocess.Popen(
+          ['./tools/testing/bin/macos/dart', scriptPath], 
+          stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+  elif os.name == 'posix':
+    pipe = subprocess.Popen(
+          ['./tools/testing/bin/linux/dart', scriptPath], 
+          stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+  else:
+    pipe = subprocess.Popen(
+          ['tools\\testing\\bin\\windows\\dart.exe', scriptPath], 
+          stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+
+  output = pipe.communicate()
+  return output[0]
+
+def GetLatestChangedRevision():
+  # 0.1.2.0_r13661
+  # 0.1.2.0_r13661_username
+  fullVersion = RunDart("tools/version.dart")
+
+  m = re.search('._r(\d+)', fullVersion)
+  svnRev = m.group(1)
+
+  return svnRev
+
 def main():
   print 'main'
+
   if len(sys.argv) == 0:
     print 'Script pathname not known, giving up.'
     return 1
diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
index bb381a1..5b398fd 100644
--- a/runtime/bin/dbg_connection.cc
+++ b/runtime/bin/dbg_connection.cc
@@ -227,12 +227,14 @@
         // Get debug message queue corresponding to isolate.
         // TODO(asiva): Once we have support for including the isolate id
         // in the debug wire protocol we need to read the isolate id and
-        // pass it down to GetIsolateMsgQueue to get the appropriate debug
-        // message queue.
-        DbgMsgQueue* queue =
-            DbgMsgQueueList::GetIsolateMsgQueue(ILLEGAL_ISOLATE_ID);
-        ASSERT(queue != NULL);
-        queue->AddMessage(cmd_idx, msgbuf_->buf(), r.EndOfObject(), debug_fd_);
+        // pass it down to AddIsolateMessage.
+        if (!DbgMsgQueueList::AddIsolateMessage(ILLEGAL_ISOLATE_ID,
+                                                cmd_idx,
+                                                msgbuf_->buf(),
+                                                r.EndOfObject(),
+                                                debug_fd_)) {
+          SendError(debug_fd_, MessageId(), "Invalid isolate specified");
+        }
         msgbuf_->PopMessage();
         continue;
       }
@@ -377,9 +379,10 @@
     in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
     return;
   }
-  DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueue(isolate_id);
-  ASSERT(queue != NULL);
-  queue->InterruptIsolate();
+  if (!DbgMsgQueueList::InterruptIsolate(isolate_id)) {
+    in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
+    return;
+  }
   dart::TextBuffer msg(64);
   msg.Printf("{ \"id\": %d }", msg_id);
   in_msg->SendReply(&msg);
diff --git a/runtime/bin/dbg_message.cc b/runtime/bin/dbg_message.cc
index 9b690e3..f0356cf 100644
--- a/runtime/bin/dbg_message.cc
+++ b/runtime/bin/dbg_message.cc
@@ -845,7 +845,6 @@
 
 void DbgMsgQueue::InterruptIsolate() {
   Dart_Isolate isolate = Dart_GetIsolate(isolate_id_);
-  ASSERT(DbgMsgQueueList::GetIsolateMsgQueue(isolate_id_) == this);
   MonitorLocker ml(&msg_queue_lock_);
   if (is_running_ && !is_interrupted_) {
     is_interrupted_ = true;
@@ -950,6 +949,32 @@
 }
 
 
+bool DbgMsgQueueList::AddIsolateMessage(Dart_IsolateId isolate_id,
+                                        int32_t cmd_idx,
+                                        const char* start,
+                                        const char* end,
+                                        int debug_fd) {
+  MutexLocker ml(&msg_queue_list_lock_);
+  DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
+  if (queue != NULL) {
+    queue->AddMessage(cmd_idx, start, end, debug_fd);
+    return true;
+  }
+  return false;
+}
+
+
+bool DbgMsgQueueList::InterruptIsolate(Dart_IsolateId isolate_id) {
+  MutexLocker ml(&msg_queue_list_lock_);
+  DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
+  if (queue != NULL) {
+    queue->InterruptIsolate();
+    return true;
+  }
+  return false;
+}
+
+
 DbgMsgQueue* DbgMsgQueueList::AddIsolateMsgQueue(Dart_IsolateId isolate_id) {
   MutexLocker ml(&msg_queue_list_lock_);
 
@@ -962,7 +987,12 @@
 
 DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueue(Dart_IsolateId isolate_id) {
   MutexLocker ml(&msg_queue_list_lock_);
+  ASSERT(Dart_GetIsolate(isolate_id) == Dart_CurrentIsolate());
+  return GetIsolateMsgQueueLocked(isolate_id);
+}
 
+
+DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueueLocked(Dart_IsolateId id) {
   if (list_ == NULL) {
     return NULL;  // No items in the list.
   }
@@ -970,13 +1000,13 @@
   // TODO(asiva): Remove once debug wire protocol has isolate id.
   // For now we return the first item in the list as we are only supporting
   // debugging of a single isolate.
-  if (isolate_id == ILLEGAL_ISOLATE_ID) {
+  if (id == ILLEGAL_ISOLATE_ID) {
     return list_;
   }
 
   // Find message queue corresponding to isolate id.
   DbgMsgQueue* iterator = list_;
-  while (iterator != NULL && iterator->isolate_id() != isolate_id) {
+  while (iterator != NULL && iterator->isolate_id() != id) {
     iterator = iterator->next();
   }
   return iterator;
@@ -992,19 +1022,21 @@
   if (queue->isolate_id() == isolate_id) {
     list_ = queue->next();  // Remove from list.
     delete queue;  // Delete the message queue.
+    return;
   } else {
     DbgMsgQueue* iterator = queue;
     queue = queue->next();
     while (queue != NULL) {
-      if (queue->isolate_id() != isolate_id) {
+      if (queue->isolate_id() == isolate_id) {
         iterator->set_next(queue->next());  // Remove from list.
         delete queue;  // Delete the message queue.
-        break;
+        return;
       }
       iterator = queue;
       queue = queue->next();
     }
   }
+  UNREACHABLE();
 }
 
 
@@ -1012,7 +1044,6 @@
                                          intptr_t bp_id,
                                          Dart_Handle url,
                                          intptr_t line_number) {
-  ASSERT(Dart_GetIsolate(isolate_id) == Dart_CurrentIsolate());
   Dart_EnterScope();
   dart::TextBuffer msg(128);
   msg.Printf("{ \"event\": \"breakpointResolved\", \"params\": {");
@@ -1029,7 +1060,6 @@
 void DbgMsgQueueList::BreakpointHandler(Dart_IsolateId isolate_id,
                                         Dart_Breakpoint bpt,
                                         Dart_StackTrace trace) {
-  ASSERT(Dart_GetIsolate(isolate_id) == Dart_CurrentIsolate());
   DebuggerConnectionHandler::WaitForConnection();
   Dart_EnterScope();
   DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
@@ -1044,7 +1074,6 @@
 void DbgMsgQueueList::ExceptionThrownHandler(Dart_IsolateId isolate_id,
                                              Dart_Handle exception,
                                              Dart_StackTrace stack_trace) {
-  ASSERT(Dart_GetIsolate(isolate_id) == Dart_CurrentIsolate());
   DebuggerConnectionHandler::WaitForConnection();
   Dart_EnterScope();
   DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
@@ -1064,7 +1093,6 @@
     DbgMsgQueue* msg_queue = AddIsolateMsgQueue(isolate_id);
     msg_queue->SendIsolateEvent(isolate_id, kind);
   } else {
-    ASSERT(Dart_GetIsolate(isolate_id) == Dart_CurrentIsolate());
     DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
     ASSERT(msg_queue != NULL);
     msg_queue->SendQueuedMsgs();
diff --git a/runtime/bin/dbg_message.h b/runtime/bin/dbg_message.h
index c45a81e..58d5df9 100644
--- a/runtime/bin/dbg_message.h
+++ b/runtime/bin/dbg_message.h
@@ -212,6 +212,16 @@
   // It returns kInvalidCommand otherwise.
   static int32_t LookupIsolateCommand(const char* buf, int32_t buflen);
 
+  // Queue debugger message targetted for the isolate.
+  static bool AddIsolateMessage(Dart_IsolateId isolate_id,
+                                int32_t cmd_idx,
+                                const char* start,
+                                const char* end,
+                                int debug_fd);
+
+  // Interrupt isolate.
+  static bool InterruptIsolate(Dart_IsolateId isolate_id);
+
   // Add Debugger Message Queue corresponding to the Isolate.
   static DbgMsgQueue* AddIsolateMsgQueue(Dart_IsolateId isolate_id);
 
@@ -237,6 +247,8 @@
                                   Dart_IsolateEvent kind);
 
  private:
+  static DbgMsgQueue* GetIsolateMsgQueueLocked(Dart_IsolateId isolate_id);
+
   static DbgMsgQueue* list_;
   static dart::Mutex msg_queue_list_lock_;
 
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 7760a93..76d7f5a 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -606,8 +606,10 @@
   Label fall_through;
   __ movl(EAX, Address(ESP, + 1 * kWordSize));  // Value.
   // If EAX is not an instance of double, jump to fall through.
+  __ testl(EAX, Immediate(kSmiTagMask));
+  __ j(ZERO, &fall_through);
   __ CompareClassId(EAX, kDoubleCid, EDI);
-  __ j(NOT_EQUAL, &fall_through);
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
   // Load double value into XMM7.
   __ movsd(XMM7, FieldAddress(EAX, Double::value_offset()));
   TestByteArraySetIndex(assembler, &fall_through);
@@ -657,8 +659,10 @@
   Label fall_through;
   __ movl(EAX, Address(ESP, + 1 * kWordSize));  // Value.
   // If EAX is not an instance of double, jump to fall through.
+  __ testl(EAX, Immediate(kSmiTagMask));
+  __ j(ZERO, &fall_through, Assembler::kNearJump);
   __ CompareClassId(EAX, kDoubleCid, EDI);
-  __ j(NOT_EQUAL, &fall_through);
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
   // Load double value into XMM7.
   __ movsd(XMM7, FieldAddress(EAX, Double::value_offset()));
   TestByteArraySetIndex(assembler, &fall_through);
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index b3f7be7..e101fae 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -570,8 +570,10 @@
   // This shift means we only multiply the index by 2 not 4 (sizeof float).
   __ movq(RDX, Address(RSP, + 1 * kWordSize));  // Value.
   // If RDX is not an instance of double, jump to fall through.
+  __ testq(RDX, Immediate(kSmiTagMask));
+  __ j(ZERO, &fall_through, Assembler::kNearJump);
   __ CompareClassId(RDX, kDoubleCid);
-  __ j(NOT_EQUAL, &fall_through);
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
   // Load double value into XMM7.
   __ movsd(XMM7, FieldAddress(RDX, Double::value_offset()));
   // Convert from double precision float to single precision float.
@@ -621,8 +623,10 @@
   // This shift means we only multiply the index by 4 not 8 (sizeof double).
   __ movq(RDX, Address(RSP, + 1 * kWordSize));  // Value.
   // If RDX is not an instance of double, jump to fall through.
+  __ testq(RDX, Immediate(kSmiTagMask));
+  __ j(ZERO, &fall_through, Assembler::kNearJump);
   __ CompareClassId(RDX, kDoubleCid);
-  __ j(NOT_EQUAL, &fall_through);
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
   // Load double value into XMM7.
   __ movsd(XMM7, FieldAddress(RDX, Double::value_offset()));
   // Store into array.
diff --git a/tests/standalone/float_array_test.dart b/tests/standalone/float_array_test.dart
index 41b4f7e..0b5db71 100644
--- a/tests/standalone/float_array_test.dart
+++ b/tests/standalone/float_array_test.dart
@@ -82,6 +82,17 @@
   Expect.equals(-1, list.indexOf(20.0));

 }

 

+void testBadValues32() {

+  var list = new Float32List(10);

+  list[0] = 2.0;

+  Expect.throws(() {

+    list[0] = 2;

+  });

+  Expect.throws(() {

+    list[0] = "hello";

+  });

+}

+

 void testCreateFloat64Array() {

   Float64List floatArray;

 

@@ -155,6 +166,17 @@
   Expect.equals(-1, list.indexOf(20.0));

 }

 

+void testBadValues64() {

+  var list = new Float64List(10);

+  list[0] = 2.0;

+  Expect.throws(() {

+    list[0] = 2;

+  });

+  Expect.throws(() {

+    list[0] = "hello";

+  });

+}

+

 main() {

   for (int i = 0; i < 2000; i++) {

     testCreateFloat32Array();

@@ -168,4 +190,7 @@
     testIndexOutOfRange64();

     testIndexOf64();

   }

+  // These two take a long time in checked mode.

+  testBadValues32();

+  testBadValues64();

 }

diff --git a/tools/VERSION b/tools/VERSION
index d7e61b7..c3d743e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 1
 BUILD 6
-PATCH 2
+PATCH 3
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 237c696..0543b64 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -323,10 +323,12 @@
   # Copy dart2js.
   CopyDart2Js(build_dir, SDK_tmp, version)
 
-  # Write the 'version' file
-  if version is not None:
-    with open(os.path.join(SDK_tmp, 'version'), 'w') as f:
-      f.write(version + '\n')
+  revision = utils.GetSVNRevision()
+
+  # Write the 'revision' file
+  if revision is not None:
+    with open(os.path.join(SDK_tmp, 'revision'), 'w') as f:
+      f.write(revision + '\n')
       f.close()
 
   Copy(join(HOME, 'README.dart-sdk'), join(SDK_tmp, 'README'))
diff --git a/utils/pub/hosted_source.dart b/utils/pub/hosted_source.dart
index 330ca5b..2d5c1f5 100644
--- a/utils/pub/hosted_source.dart
+++ b/utils/pub/hosted_source.dart
@@ -73,19 +73,30 @@
 
     var fullUrl = "$url/packages/$name/versions/${id.version}.tar.gz";
 
-    return Futures.wait([httpGet(fullUrl), ensureDir(destPath)]).chain((args) {
-      return timeout(extractTarGz(args[0], args[1]), HTTP_TIMEOUT,
-          'Timed out while fetching URL "$fullUrl".');
-    }).transformException((ex) {
-      // If the install failed, delete the directory. Prevents leaving a ghost
-      // directory in the system cache which would later make pub think the
-      // install succeeded.
-      // TODO(rnystrom): Use deleteDir() here when transformException() supports
-      // returning a future. Also remove dart:io import then.
-      new io.Directory(destPath).deleteRecursivelySync();
+    print('Downloading $id...');
 
-      throw ex;
-    });
+    // Download and extract the archive to a temp directory.
+    var tempDir;
+    return Futures.wait([httpGet(fullUrl), createTempDir()]).chain((args) {
+      tempDir = args[1];
+      return timeout(extractTarGz(args[0], tempDir), HTTP_TIMEOUT,
+          'Timed out while fetching URL "$fullUrl".');
+    }).chain((_) {
+      // Now that the install has succeeded, move it to the real location in
+      // the cache. This ensures that we don't leave half-busted ghost
+      // directories in the user's pub cache if an install fails.
+      var rename = renameDir(tempDir, destPath);
+
+      // TODO(rnystrom): Awful hack. On Windows, we see cases where the extract
+      // has not finished by the time we get here, so the rename fails with a
+      // "directory in use" error. So, we will just wait a couple of seconds
+      // before we start.
+      if (io.Platform.operatingSystem == "windows") {
+        rename = sleep(2000).chain((_) => rename);
+      }
+
+      return rename;
+    }).transform((_) => true);
   }
 
   /**
diff --git a/utils/pub/io.dart b/utils/pub/io.dart
index bef2b2a..c5f64c6 100644
--- a/utils/pub/io.dart
+++ b/utils/pub/io.dart
@@ -283,6 +283,10 @@
   });
 }
 
+/// Renames (i.e. moves) the directory [from] to [to]. Returns a [Future] with
+/// the destination directory.
+Future<Directory> renameDir(from, String to) =>_getDirectory(from).rename(to);
+
 /**
  * Creates a new symlink that creates an alias from [from] to [to], both of
  * which can be a [String], [File], or [Directory]. Returns a [Future] which
@@ -681,7 +685,13 @@
     // Write the archive to a temp file.
     tempDir = temp;
     return createFileFromStream(stream, join(tempDir, 'data.tar.gz'));
-  }).chain((tarGz) {
+  }).chain((_) {
+    // TODO(rnystrom): Hack. We get intermittent "file already in use" errors.
+    // It looks like the 7zip process is starting up before the file has
+    // finished being written. So we'll just sleep for a couple of seconds
+    // here. :(
+    return sleep(2000);
+  }).chain((_) {
     // 7zip can't unarchive from gzip -> tar -> destination all in one step
     // first we un-gzip it to a tar file.
     // Note: Setting the working directory instead of passing in a full file
@@ -690,9 +700,9 @@
   }).chain((result) {
     if (result.exitCode != 0) {
       throw 'Could not un-gzip (exit code ${result.exitCode}). Error:\n'
+          '${Strings.join(result.stdout, "\n")}\n'
           '${Strings.join(result.stderr, "\n")}';
     }
-
     // Find the tar file we just created since we don't know its name.
     return listDir(tempDir);
   }).chain((files) {
@@ -712,6 +722,7 @@
   }).chain((result) {
     if (result.exitCode != 0) {
       throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n'
+          '${Strings.join(result.stdout, "\n")}\n'
           '${Strings.join(result.stderr, "\n")}';
     }
 
diff --git a/utils/pub/version_solver.dart b/utils/pub/version_solver.dart
index 7efba41..80f3d48 100644
--- a/utils/pub/version_solver.dart
+++ b/utils/pub/version_solver.dart
@@ -59,6 +59,7 @@
  */
 Future<List<PackageId>> resolveVersions(SourceRegistry sources, Package root,
     LockFile lockFile) {
+  print('Resolving dependencies...');
   return new VersionSolver(sources, root, lockFile).solve();
 }
 
diff --git a/utils/tests/pub/update/pub_update_test.dart b/utils/tests/pub/update/pub_update_test.dart
index 99b5dff..29d8ca1 100644
--- a/utils/tests/pub/update/pub_update_test.dart
+++ b/utils/tests/pub/update/pub_update_test.dart
@@ -88,9 +88,7 @@
     ]).scheduleCreate();
 
     schedulePub(args: ['update'],
-        output: '''
-        Dependencies updated!
-        ''');
+        output: const RegExp(r"Dependencies updated!$"));
 
     packagesDir({"foo": null}).scheduleValidate();