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