Version 1.4.1

svn merge -c 36348 https://dart.googlecode.com/svn/branches/bleeding_edge 1.4
svn merge -c 36502 https://dart.googlecode.com/svn/branches/bleeding_edge 1.4
svn merge -c 36504 https://dart.googlecode.com/svn/branches/bleeding_edge 1.4
svn merge -c 36522 https://dart.googlecode.com/svn/branches/bleeding_edge 1.4
svn merge -c 36623 https://dart.googlecode.com/svn/branches/bleeding_edge 1.4

Review URL: https://codereview.chromium.org//298153002

git-svn-id: http://dart.googlecode.com/svn/branches/1.4@36641 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/platform/thread.h b/runtime/platform/thread.h
index fb56a50..0554d5c 100644
--- a/runtime/platform/thread.h
+++ b/runtime/platform/thread.h
@@ -42,6 +42,7 @@
   static void SetThreadLocal(ThreadLocalKey key, uword value);
   static intptr_t GetMaxStackSize();
   static ThreadId GetCurrentThreadId();
+  static bool Join(ThreadId id);
   static intptr_t ThreadIdToIntPtr(ThreadId id);
   static bool Compare(ThreadId a, ThreadId b);
   static void GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage);
diff --git a/runtime/platform/thread_android.cc b/runtime/platform/thread_android.cc
index 4f3e446..246cd34 100644
--- a/runtime/platform/thread_android.cc
+++ b/runtime/platform/thread_android.cc
@@ -149,6 +149,11 @@
 }
 
 
+bool Thread::Join(ThreadId id) {
+  return false;
+}
+
+
 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
   ASSERT(sizeof(id) == sizeof(intptr_t));
   return static_cast<intptr_t>(id);
diff --git a/runtime/platform/thread_linux.cc b/runtime/platform/thread_linux.cc
index 12ea1f9..aedd8d9 100644
--- a/runtime/platform/thread_linux.cc
+++ b/runtime/platform/thread_linux.cc
@@ -150,6 +150,11 @@
 }
 
 
+bool Thread::Join(ThreadId id) {
+  return false;
+}
+
+
 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
   ASSERT(sizeof(id) == sizeof(intptr_t));
   return static_cast<intptr_t>(id);
diff --git a/runtime/platform/thread_macos.cc b/runtime/platform/thread_macos.cc
index 01c5c8c..a113abc 100644
--- a/runtime/platform/thread_macos.cc
+++ b/runtime/platform/thread_macos.cc
@@ -142,6 +142,11 @@
 }
 
 
+bool Thread::Join(ThreadId id) {
+  return false;
+}
+
+
 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
   ASSERT(sizeof(id) == sizeof(intptr_t));
   return reinterpret_cast<intptr_t>(id);
diff --git a/runtime/platform/thread_win.cc b/runtime/platform/thread_win.cc
index afbae8b..beca34a 100644
--- a/runtime/platform/thread_win.cc
+++ b/runtime/platform/thread_win.cc
@@ -33,18 +33,12 @@
 // is used to ensure that the thread is properly destroyed if the thread just
 // exits.
 static unsigned int __stdcall ThreadEntry(void* data_ptr) {
-  ThreadStartData* data =  reinterpret_cast<ThreadStartData*>(data_ptr);
+  ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
 
   Thread::ThreadStartFunction function = data->function();
   uword parameter = data->parameter();
   delete data;
 
-  ASSERT(ThreadInlineImpl::thread_id_key != Thread::kUnsetThreadLocalKey);
-
-  ThreadId thread_id = ThreadInlineImpl::CreateThreadId();
-  // Set thread ID in TLS.
-  Thread::SetThreadLocal(ThreadInlineImpl::thread_id_key,
-                         reinterpret_cast<DWORD>(thread_id));
   MonitorData::GetMonitorWaitDataForThread();
 
   // Call the supplied thread start function handing it its parameters.
@@ -53,10 +47,6 @@
   // Clean up the monitor wait data for this thread.
   MonitorWaitData::ThreadExit();
 
-  // Clear thread ID in TLS.
-  Thread::SetThreadLocal(ThreadInlineImpl::thread_id_key, NULL);
-  ThreadInlineImpl::DestroyThreadId(thread_id);
-
   return 0;
 }
 
@@ -73,34 +63,14 @@
     return errno;
   }
 
+  // Close the handle, so we don't leak the thread object.
+  CloseHandle(reinterpret_cast<HANDLE>(thread));
+
   return 0;
 }
 
-
-ThreadId ThreadInlineImpl::CreateThreadId() {
-  // Create an ID for this thread that can be shared with other threads.
-  HANDLE thread_id = OpenThread(THREAD_GET_CONTEXT |
-                                THREAD_SUSPEND_RESUME |
-                                THREAD_QUERY_INFORMATION,
-                                false,
-                                GetCurrentThreadId());
-  ASSERT(thread_id != NULL);
-  return thread_id;
-}
-
-
-void ThreadInlineImpl::DestroyThreadId(ThreadId thread_id) {
-  ASSERT(thread_id != NULL);
-  // Destroy thread ID.
-  CloseHandle(thread_id);
-}
-
-
-ThreadLocalKey ThreadInlineImpl::thread_id_key = Thread::kUnsetThreadLocalKey;
-
 ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
-ThreadId Thread::kInvalidThreadId =
-    reinterpret_cast<ThreadId>(INVALID_HANDLE_VALUE);
+ThreadId Thread::kInvalidThreadId = 0;
 
 ThreadLocalKey Thread::CreateThreadLocal() {
   ThreadLocalKey key = TlsAlloc();
@@ -127,16 +97,24 @@
 
 
 ThreadId Thread::GetCurrentThreadId() {
-  ThreadId id = reinterpret_cast<ThreadId>(
-      Thread::GetThreadLocal(ThreadInlineImpl::thread_id_key));
-  ASSERT(id != NULL);
-  return id;
+  return ::GetCurrentThreadId();
+}
+
+
+bool Thread::Join(ThreadId id) {
+  HANDLE handle = OpenThread(SYNCHRONIZE, false, id);
+  if (handle == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+  DWORD res = WaitForSingleObject(handle, INFINITE);
+  CloseHandle(handle);
+  return res == WAIT_OBJECT_0;
 }
 
 
 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
-  ASSERT(sizeof(id) == sizeof(intptr_t));
-  return reinterpret_cast<intptr_t>(id);
+  ASSERT(sizeof(id) <= sizeof(intptr_t));
+  return static_cast<intptr_t>(id);
 }
 
 
@@ -163,11 +141,13 @@
   TimeStamp exited;
   TimeStamp kernel;
   TimeStamp user;
-  BOOL result = GetThreadTimes(thread_id,
+  HANDLE handle = OpenThread(THREAD_QUERY_INFORMATION, false, thread_id);
+  BOOL result = GetThreadTimes(handle,
                                &created.ft_,
                                &exited.ft_,
                                &kernel.ft_,
                                &user.ft_);
+  CloseHandle(handle);
   if (!result) {
     FATAL1("GetThreadCpuUsage failed %d\n", GetLastError());
   }
diff --git a/runtime/platform/thread_win.h b/runtime/platform/thread_win.h
index 40e5a11..1fffde0 100644
--- a/runtime/platform/thread_win.h
+++ b/runtime/platform/thread_win.h
@@ -15,7 +15,7 @@
 namespace dart {
 
 typedef DWORD ThreadLocalKey;
-typedef HANDLE ThreadId;
+typedef DWORD ThreadId;
 
 
 class ThreadInlineImpl {
@@ -23,9 +23,6 @@
   ThreadInlineImpl() {}
   ~ThreadInlineImpl() {}
 
-  static ThreadLocalKey thread_id_key;
-  static ThreadId CreateThreadId();
-  static void DestroyThreadId(ThreadId);
   static uword GetThreadLocal(ThreadLocalKey key) {
     static ThreadLocalKey kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
     ASSERT(key != kUnsetThreadLocalKey);
@@ -33,7 +30,6 @@
   }
 
   friend class Thread;
-  friend class OS;
   friend unsigned int __stdcall ThreadEntry(void* data_ptr);
 
   DISALLOW_ALLOCATION();
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 3584bec..acdca49 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -103,7 +103,7 @@
     ASSERT(space == kOld);
     old_space_->AllocateExternal(size);
     if (old_space_->NeedsGarbageCollection()) {
-      CollectGarbage(kOld);
+      CollectAllGarbage();
     }
   }
 }
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index 98e864e..800e759 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -316,12 +316,8 @@
   init_once_called = true;
   // Do not pop up a message box when abort is called.
   _set_abort_behavior(0, _WRITE_ABORT_MSG);
-  ThreadInlineImpl::thread_id_key = Thread::CreateThreadLocal();
   MonitorWaitData::monitor_wait_data_key_ = Thread::CreateThreadLocal();
   MonitorData::GetMonitorWaitDataForThread();
-  ThreadId thread_id = ThreadInlineImpl::CreateThreadId();
-  Thread::SetThreadLocal(ThreadInlineImpl::thread_id_key,
-                         reinterpret_cast<DWORD>(thread_id));
 }
 
 
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index b019d06..ba17f70 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -9178,6 +9178,11 @@
         // be found.
         AstNode* receiver = NULL;
         const bool kTestOnly = true;
+        if (parsing_metadata_) {
+          ErrorMsg(ident_pos,
+                   "'%s' is not a compile-time constant",
+                   ident.ToCString());
+        }
         if (!current_function().is_static() &&
             (LookupReceiver(current_block_->scope, kTestOnly) != NULL)) {
           receiver = LoadReceiver(ident_pos);
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 49df08a..1c6e2cc 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -21,8 +21,7 @@
 namespace dart {
 
 
-#if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \
-    defined(TARGET_OS_ANDROID)
+#if defined(USING_SIMULATOR) || defined(TARGET_OS_ANDROID)
   DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
 #else
   DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
@@ -1688,7 +1687,7 @@
       // Stack pointer should not be above frame pointer.
       return 1;
     }
-    intptr_t gap = original_fp_ - original_sp_;
+    const intptr_t gap = original_fp_ - original_sp_;
     if (gap >= kMaxStep) {
       // Gap between frame pointer and stack pointer is
       // too large.
@@ -1699,8 +1698,19 @@
       // the isolates stack limit.
       lower_bound_ = original_sp_;
     }
-    // Store the PC marker for the top frame.
-    sample_->set_pc_marker(GetCurrentFramePcMarker(fp));
+#if defined(TARGET_OS_WINDOWS)
+    // If the original_fp_ is at the beginning of a page, it may be unsafe
+    // to access the pc marker, because we are reading it from a different
+    // thread on Windows. The next page may be a guard page.
+    const intptr_t kPageMask = kMaxStep - 1;
+    bool safe_to_read_pc_marker = (original_fp_ & kPageMask) != 0;
+#else
+    bool safe_to_read_pc_marker = true;
+#endif
+    if (safe_to_read_pc_marker && (gap > 0)) {
+      // Store the PC marker for the top frame.
+      sample_->set_pc_marker(GetCurrentFramePcMarker(fp));
+    }
     int i = 0;
     for (; i < FLAG_profile_depth; i++) {
       if (FLAG_profile_verify_stack_walk) {
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index c15e052..632688a 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -86,25 +86,28 @@
 
 
 void ThreadInterrupter::Shutdown() {
-  if (shutdown_) {
-    // Already shutdown.
-    return;
-  }
-  ASSERT(initialized_);
-  if (FLAG_trace_thread_interrupter) {
-    OS::Print("ThreadInterrupter shutting down.\n");
-  }
-  {
-    MonitorLocker ml(monitor_);
-    shutdown_ = true;
-  }
   {
     MonitorLocker shutdown_ml(monitor_);
+    if (shutdown_) {
+      // Already shutdown.
+      return;
+    }
+    shutdown_ = true;
+    ASSERT(initialized_);
+    if (FLAG_trace_thread_interrupter) {
+      OS::Print("ThreadInterrupter shutting down.\n");
+    }
     while (thread_running_) {
       shutdown_ml.Wait();
     }
+    // Join in the interrupter thread. On Windows, a thread's exit-code can
+    // leak into the process's exit-code, if exiting 'at same time' as the
+    // process ends.
+    if (interrupter_thread_id_ != Thread::kInvalidThreadId) {
+      Thread::Join(interrupter_thread_id_);
+      interrupter_thread_id_ = Thread::kInvalidThreadId;
+    }
   }
-  interrupter_thread_id_ = Thread::kInvalidThreadId;
   if (FLAG_trace_thread_interrupter) {
     OS::Print("ThreadInterrupter shut down.\n");
   }
@@ -234,8 +237,8 @@
   {
     // Signal to main thread we are ready.
     MonitorLocker startup_ml(monitor_);
-    thread_running_ = true;
     interrupter_thread_id_ = Thread::GetCurrentThreadId();
+    thread_running_ = true;
     startup_ml.Notify();
   }
   {
diff --git a/runtime/vm/thread_interrupter_win.cc b/runtime/vm/thread_interrupter_win.cc
index 4058da3..b39c188 100644
--- a/runtime/vm/thread_interrupter_win.cc
+++ b/runtime/vm/thread_interrupter_win.cc
@@ -16,11 +16,11 @@
 
 class ThreadInterrupterWin : public AllStatic {
  public:
-  static bool GrabRegisters(ThreadId thread, InterruptedThreadState* state) {
+  static bool GrabRegisters(HANDLE handle, InterruptedThreadState* state) {
     CONTEXT context;
     memset(&context, 0, sizeof(context));
-    context.ContextFlags = CONTEXT_FULL;
-    if (GetThreadContext(thread, &context) != 0) {
+    context.ContextFlags = CONTEXT_CONTROL;
+    if (GetThreadContext(handle, &context) != 0) {
 #if defined(TARGET_ARCH_IA32)
       state->pc = static_cast<uintptr_t>(context.Eip);
       state->fp = static_cast<uintptr_t>(context.Ebp);
@@ -39,33 +39,43 @@
 
 
   static void Interrupt(InterruptableThreadState* state) {
-    ASSERT(GetCurrentThread() != state->id);
-    DWORD result = SuspendThread(state->id);
+    ASSERT(!Thread::Compare(GetCurrentThreadId(), state->id));
+    HANDLE handle = OpenThread(THREAD_GET_CONTEXT |
+                               THREAD_QUERY_INFORMATION |
+                               THREAD_SUSPEND_RESUME,
+                               false,
+                               state->id);
+    ASSERT(handle != NULL);
+    DWORD result = SuspendThread(handle);
     if (result == kThreadError) {
       if (FLAG_trace_thread_interrupter) {
         OS::Print("ThreadInterrupted failed to suspend thread %p\n",
                   reinterpret_cast<void*>(state->id));
       }
+      CloseHandle(handle);
       return;
     }
     InterruptedThreadState its;
     its.tid = state->id;
-    if (!GrabRegisters(state->id, &its)) {
+    if (!GrabRegisters(handle, &its)) {
       // Failed to get thread registers.
-      ResumeThread(state->id);
+      ResumeThread(handle);
       if (FLAG_trace_thread_interrupter) {
         OS::Print("ThreadInterrupted failed to get registers for %p\n",
                   reinterpret_cast<void*>(state->id));
       }
+      CloseHandle(handle);
       return;
     }
     if (state->callback == NULL) {
       // No callback registered.
-      ResumeThread(state->id);
+      ResumeThread(handle);
+      CloseHandle(handle);
       return;
     }
     state->callback(its, state->data);
-    ResumeThread(state->id);
+    ResumeThread(handle);
+    CloseHandle(handle);
   }
 };
 
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
index d8e9245..7ff08a9 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
@@ -212,7 +212,7 @@
     jsAst.Expression value = new jsAst.Call(
         new jsAst.PropertyAccess.field(
             new jsAst.VariableUse(namer.isolateName),
-            'makeConstantList'),
+            namer.getMappedInstanceName('makeConstantList')),
         [new jsAst.ArrayInitializer.from(_array(constant.entries))]);
     return maybeAddTypeArguments(constant.type, value);
   }
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
index 5d29b6b..2f7dc05 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
@@ -135,6 +135,8 @@
   String get lazyInitializerName
       => '${namer.isolateName}.\$lazy';
   String get initName => 'init';
+  String get makeConstListProperty
+      => namer.getMappedInstanceName('makeConstantList');
 
   jsAst.FunctionDeclaration get generateAccessorFunction {
     const RANGE1_SIZE = RANGE1_LAST - RANGE1_FIRST + 1;
@@ -538,7 +540,7 @@
         if (#)
           Isolate.$finishClassesProperty = oldIsolate.$finishClassesProperty;
         if (#)
-          Isolate.makeConstantList = oldIsolate.makeConstantList;
+          Isolate.$makeConstListProperty = oldIsolate.$makeConstListProperty;
         return Isolate;
       }''',
         [ needsDefineClass, hasMakeConstantList ]);
@@ -956,14 +958,16 @@
   void emitMakeConstantListIfNotEmitted(CodeBuffer buffer) {
     if (hasMakeConstantList) return;
     hasMakeConstantList = true;
-    buffer
-        ..write(namer.isolateName)
-        ..write('''.makeConstantList = function(list) {
-  list.immutable\$list = $initName;
-  list.fixed\$length = $initName;
-  return list;
-};
-''');
+    jsAst.Statement value = new jsAst.ExpressionStatement(new jsAst.Assignment(
+            new jsAst.PropertyAccess.field(
+                new jsAst.VariableUse(namer.isolateName),
+                makeConstListProperty),
+            js('''function(list) {
+                    list.immutable\$list = $initName;
+                    list.fixed\$length = $initName;
+                    return list;
+                  }''')));
+    buffer.write(jsAst.prettyPrint(value, compiler));
   }
 
   /// Returns the code equivalent to:
diff --git a/tests/lib/mirrors/metadata_allowed_values_test.dart b/tests/lib/mirrors/metadata_allowed_values_test.dart
index d410a63..ce1011b 100644
--- a/tests/lib/mirrors/metadata_allowed_values_test.dart
+++ b/tests/lib/mirrors/metadata_allowed_values_test.dart
@@ -143,6 +143,12 @@
 @a[0]  /// 26: compile-time error
 class JJ {}
 
+@kk  /// 27: compile-time error
+class KK {
+  const KK();
+}
+get kk => const KK();
+
 checkMetadata(DeclarationMirror mirror, List expectedMetadata) {
   Expect.listEquals(expectedMetadata.map(reflect).toList(), mirror.metadata);
 }
@@ -184,4 +190,5 @@
   reflectClass(HH).metadata;
   reflectClass(II).metadata;
   reflectClass(JJ).metadata;
+  reflectClass(KK).metadata;
 }
diff --git a/tools/VERSION b/tools/VERSION
index 0b169d4..0a41326 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -26,6 +26,6 @@
 CHANNEL stable
 MAJOR 1
 MINOR 4
-PATCH 0
+PATCH 1
 PRERELEASE 0
 PRERELEASE_PATCH 0