no bug: concurrency changes, fixes for win8 support (p=jasowill,p=brbaker,p=kakher)
authorDan Schaffer <Dan.Schaffer@adobe.com>
Tue, 29 Jan 2013 06:59:24 -0800
changeset 7586 2b38aa82c803a98982168597e79ee428e3862338
parent 7585 1366af27b87ec3b55c467b5d2d969f9db5434b73
child 7587 5571cf86fc681fddf092fc369ff693a32f261d6c
push id4262
push userdschaffe@adobe.com
push dateWed, 30 Jan 2013 19:01:31 +0000
bugs1144817, 1159503
no bug: concurrency changes, fixes for win8 support (p=jasowill,p=brbaker,p=kakher) integrate to CL 1144817 CL@1159503
AVMPI/MMgcPortWinRT.cpp
AVMPI/SpyUtilsWinRT.cpp
VMPI/ThreadsWinRT.cpp
VMPI/WinPortUtils.cpp
VMPI/WinRTDebugUtils.cpp
core/CodegenLIR.cpp
platform/system-selection.h
platform/win32/win32-platform.h
platform/winrt/OSDepWinRT.cpp
new file mode 100644
--- /dev/null
+++ b/AVMPI/MMgcPortWinRT.cpp
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
+/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+#include <windows.h>
+
+#include "MMgc.h"
+
+bool AVMPI_canMergeContiguousRegions()
+{
+    return false;
+}
+
+bool AVMPI_canCommitAlreadyCommittedMemory()
+{
+    return false;
+}
+
+bool AVMPI_useVirtualMemory()
+{
+    return false;
+}
+
+bool AVMPI_areNewPagesDirty()
+{
+    return false;
+}
+
+void* AVMPI_reserveMemoryRegion(void* /*address*/, size_t /*size*/)
+{
+	return NULL;
+}
+
+bool AVMPI_releaseMemoryRegion(void* /*address*/, size_t /*size*/)
+{
+    return false;
+}
+
+bool AVMPI_commitMemory(void* /*address*/, size_t /*size*/)
+{
+	return false;
+}
+
+bool AVMPI_decommitMemory(char* /*address*/, size_t /*size*/)
+{
+	return false;
+}
+
+void* AVMPI_allocateAlignedMemory(size_t size)
+{
+	void* mem = _aligned_malloc(size, VMPI_getVMPageSize());
+	memset(mem, 0, size);
+	return mem;
+}
+
+void AVMPI_releaseAlignedMemory(void* address)
+{
+	_aligned_free(address);
+}
+
+size_t AVMPI_getPrivateResidentPageCount()
+{
+    void* addr = 0;
+    size_t bytes = 0;
+    MEMORY_BASIC_INFORMATION info;
+    while(true)
+    {
+        size_t ret = VirtualQuery(addr, &info, sizeof(MEMORY_BASIC_INFORMATION));
+        if(ret == 0)
+            break;
+
+        if((info.State & MEM_COMMIT) && (info.Type & MEM_PRIVATE))
+            bytes += info.RegionSize;
+
+            addr = (void*) ((intptr_t)info.BaseAddress + info.RegionSize);
+    }
+
+    return bytes / VMPI_getVMPageSize();
+}
+
+void AVMPI_cleanStack(size_t amt)
+{
+    void *space = alloca(amt);
+    if(space)
+    {
+        VMPI_memset(space, 0, amt);
+    }
+}
+
+uintptr_t AVMPI_getThreadStackBase()
+{
+    MEMORY_BASIC_INFORMATION info;
+    VirtualQuery(&info, &info, sizeof(MEMORY_BASIC_INFORMATION));
+    return (uintptr_t)info.BaseAddress + info.RegionSize;
+}
+
+void *AVMPI_allocateCodeMemory(size_t /*nbytes*/)
+{
+	return NULL;
+}
+
+void AVMPI_freeCodeMemory(void* /*address*/, size_t /*nbytes*/)
+{
+}
+
+void AVMPI_makeCodeMemoryExecutable(void* /*address*/, size_t /*nbytes*/, bool /*makeItSo*/)
+{
+}
+
+#ifdef MMGC_MEMORY_PROFILER
+/*
+It may not be possible to implement this feature in Windows Store apps, at least by using the same APIs as before.
+
+You can see win32 implementation in MMgcPortWin.cpp.
+*/
+
+bool AVMPI_captureStackTrace(uintptr_t* /*buffer*/, size_t /*bufferSize*/, uint32_t /*framesToSkip*/)
+{
+	return false;
+}
+
+bool AVMPI_getFileAndLineInfoFromPC(uintptr_t /*pc*/, char* /*filenameBuffer*/, size_t /*bufferSize*/, uint32_t* /*lineNumber*/)
+{
+	return false;
+}
+
+bool AVMPI_getFunctionNameFromPC(uintptr_t /*pc*/, char* /*buffer*/, size_t /*bufferSize*/)
+{
+	return false;
+}
+
+void AVMPI_setupPCResolution()
+{
+}
+
+void AVMPI_desetupPCResolution()
+{
+}
+
+bool AVMPI_isMemoryProfilingEnabled()
+{
+	return false;
+}
+
+#endif // MMGC_MEMORY_PROFILER
new file mode 100644
--- /dev/null
+++ b/AVMPI/SpyUtilsWinRT.cpp
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
+/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MMgc.h"
+
+#ifdef MMGC_MEMORY_PROFILER
+/*
+It may not be possible to implement this feature in Windows Store apps, at least by using the same APIs as before.
+
+You can see win32 implementation in SpyUtilsWin.cpp.
+*/
+
+void AVMPI_spyCallback()
+{
+}
+
+bool AVMPI_spySetup()
+{
+    return false;
+}
+
+void AVMPI_spyTeardown()
+{
+}
+
+bool AVMPI_hasSymbols()
+{
+    return false;
+}
+
+#endif //MMGC_MEMORY_PROFILER
new file mode 100644
--- /dev/null
+++ b/VMPI/ThreadsWinRT.cpp
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
+/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VMPI.h"
+#include "VMAssert.h"
+
+// std
+#include <thread>
+#include <map>
+#include <mutex>
+
+// We make an assumption that using fiber local storage is equivalent of using thread local storage.
+#ifndef FLS_OUT_OF_INDEXES
+    #define FLS_OUT_OF_INDEXES (DWORD)0xFFFFFFFF
+#endif
+
+bool VMPI_tlsCreate(uintptr_t* tlsId)
+{
+    DWORD id = FlsAlloc(NULL);
+    *tlsId = (uintptr_t)id;
+    return (id != FLS_OUT_OF_INDEXES);
+}
+
+void VMPI_tlsDestroy(uintptr_t tlsId)
+{
+    FlsFree((DWORD)tlsId);
+}
+
+/*
+The std::thread API does not use thread ids in the API unlike when using pthreads or win32 threads for example.
+Std::threads are objects. It is not possible to get std::thread object for "current thread" for example.
+Once we create a new std::thread, we get its id (which is an object as well) and then use a special
+hash map (which is defined by std API) to get an unique identifier for the thread, type if size_t.
+This is used as the thread type in the vmpi API. A look up is done whenever we need to access a thread that
+the vm has created earlier.
+
+It is not possible to call join, detach for threads that the vm did not create (for example the main thread)
+- we don't know their ids. Luckily by reading the code, the vm does not try to do such a thing.
+
+To return something from VMPI_currentThread we return hash of std::this_thread::get_id().
+To return something from VMPI_nullThread we return hash of an uninitialized std::thread::id object. Returning 0 might work too.
+
+TODO: test a bit so that the Ids we get are unique.
+*/
+std::map<size_t, std::thread*> g_vmpiThreadMap;
+std::mutex g_vmpiThreadMapMutex;
+#define THREAD_PAIR size_t, std::thread*
+
+std::thread* getThread(vmpi_thread_t thread)
+{
+	// NOTE: g_vmpiThreadMapMutex has to be locked at this point!
+	std::map<THREAD_PAIR>::iterator it;
+
+	it = g_vmpiThreadMap.find(thread);
+	if(it == g_vmpiThreadMap.end())
+	{
+		// This should never happen
+		assert(false); 
+		return NULL;
+	}
+
+	std::thread* th = it->second;
+	return th;
+}
+
+size_t getThreadId(std::thread* thread)
+{
+	std::hash<std::thread::id> hash;
+	return hash( thread->get_id() );
+}
+
+bool VMPI_threadCreate(vmpi_thread_t* thread, vmpi_thread_attr_t* attr, vmpi_thread_start_t start_fn, vmpi_thread_arg_t arg)
+{
+	// To do: support attributes such as priority if possible
+
+	std::lock_guard<std::mutex> lock(g_vmpiThreadMapMutex);
+
+	std::thread* newThread = new std::thread(start_fn, arg);
+	size_t threadId = getThreadId(newThread);
+
+	std::pair<std::map<THREAD_PAIR>::iterator, bool> ret;
+	ret = g_vmpiThreadMap.insert( std::pair<THREAD_PAIR>(threadId, newThread) );
+
+	// For some reason we could not insert. Maybe the id existed already?
+	if(ret.second == false)
+	{
+		// This should never happen.
+		assert(false);
+		return false;
+	}
+
+	*thread = threadId;
+	return true;
+}
+
+// Used by vmbase::VMThread::startInternal - in other words by threads created with VMPI_createThread.
+bool VMPI_threadDetach(vmpi_thread_t thread)
+{
+	// Note! For some reason they have not implemented detach on win32. However it is implemented in ThreadsPosix.cpp.
+
+	std::lock_guard<std::mutex> lock(g_vmpiThreadMapMutex);
+
+	std::thread* th = getThread(thread);
+	if(th)
+	{
+		g_vmpiThreadMap.erase(thread);
+		th->detach();
+		delete th;
+		return true;
+	} else
+	{
+		return false;
+	}
+}
+
+// Used by avmplus::MostlyonBlockingChannel in Channels.cpp.
+void VMPI_threadSleep(int32_t timeout_millis)
+{
+	std::this_thread::sleep_for( std::chrono::milliseconds(timeout_millis) );
+}
+
+// Actually VMPI_threadJoin is not called by the vm at the moment, so comment out:
+/*
+void VMPI_threadJoin(vmpi_thread_t thread)
+{
+	std::lock_guard<std::mutex> lock(g_vmpiThreadMapMutex);
+
+	std::thread* th = getThread(thread);
+	if(th)
+	{
+		th->join();
+	}
+}
+*/
+
+// VMPI_condVarInit happens to be in win32-platform.h.
+
+void VMPI_condVarWait(vmpi_condvar_t* condvar, vmpi_mutex_t* mutex)
+{
+	SleepConditionVariableCS(condvar, mutex, INFINITE);
+}
+
+bool VMPI_condVarTimedWait(vmpi_condvar_t* condvar, vmpi_mutex_t* mutex, int32_t timeout_millis)
+{
+	return SleepConditionVariableCS(condvar, mutex, timeout_millis) == 0;
+}
+
+void VMPI_condVarBroadcast(vmpi_condvar_t* condvar)
+{
+	WakeAllConditionVariable(condvar);
+}
+
+void VMPI_condVarSignal(vmpi_condvar_t* condvar)
+{
+	WakeConditionVariable(condvar);
+}
+
+bool VMPI_threadAttrInit(vmpi_thread_attr_t* attr)
+{
+    attr->stackSize = VMPI_threadAttrDefaultStackSize();
+    attr->guardSize = VMPI_threadAttrDefaultGuardSize();
+    attr->priority = THREAD_PRIORITY_NORMAL;
+    return true;
+}
+
+bool VMPI_threadAttrDestroy(vmpi_thread_attr_t* attr)
+{
+    (void)attr;
+    return true;
+}
+
+bool VMPI_threadAttrSetGuardSize(vmpi_thread_attr_t* attr, size_t size)
+{
+    attr->guardSize = size;
+    return true;
+}
+
+bool VMPI_threadAttrSetStackSize(vmpi_thread_attr_t* attr, size_t size)
+{
+    attr->stackSize = size;
+    return true;
+}
+
+void VMPI_threadAttrSetPriorityLow(vmpi_thread_attr_t* attr)
+{
+    attr->priority = THREAD_PRIORITY_BELOW_NORMAL;
+}
+
+void VMPI_threadAttrSetPriorityNormal(vmpi_thread_attr_t* attr)
+{
+    attr->priority = THREAD_PRIORITY_NORMAL;
+}
+
+void VMPI_threadAttrSetPriorityHigh(vmpi_thread_attr_t* attr)
+{
+    attr->priority = THREAD_PRIORITY_ABOVE_NORMAL;
+}
+
+size_t VMPI_threadAttrDefaultGuardSize()
+{
+    // It will be a single page.
+    // The SetThreadStackGuarantee API isn't available so we can't change it
+    // from the default.
+    // http://msdn.microsoft.com/en-us/library/8cxs58a6%28vs.71%29.aspx
+    return VMPI_getVMPageSize();
+}
+
+size_t VMPI_threadAttrDefaultStackSize()
+{
+    // FIXME: bug 609822 Is it possible to implement VMPI_threadAttrDefaultStackSize on win32?
+    //
+    // Stack size is set in the linker. The default is 1MB:
+    // http://msdn.microsoft.com/en-us/library/8cxs58a6%28vs.71%29.aspx
+    // But can we find this out programmatically? There doesn't appear to be an API:
+    // http://msdn.microsoft.com/en-us/library/ms686774%28v=VS.85%29.aspx
+    return 1024 * 1024;
+}
--- a/VMPI/WinPortUtils.cpp
+++ b/VMPI/WinPortUtils.cpp
@@ -187,17 +187,25 @@ double VMPI_getDate()
 {
     SYSTEMTIME stime;
     GetSystemTime(&stime);
     return NormalizeSystemTime(&stime);
 }
 
 uint64_t VMPI_getTime()
 {
+#if AVMSYSTEM_WINDOWSSTOREAPP
+	LARGE_INTEGER counter;
+	LARGE_INTEGER frequency;
+	QueryPerformanceCounter(&counter);
+	QueryPerformanceFrequency(&frequency);
+	return (counter.QuadPart * 1000) / frequency.QuadPart;
+#else
     return timeGetTime();
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
 }
 
 // On Windows, _vsnprintf isn't reliable (no NUL termination) and _vsnprintf_s
 // is not compatible (throws an exception if the format is wrong).  Easy
 // enough to create our own on top of _vsnprintf by adding the terminator
 // and adjusting the return value.
 //
 // ANSI C requires vsnprintf to return the number of characters that would have
@@ -263,19 +271,22 @@ void VMPI_log(const char* message)
         fflush(stdout);
     }
 }
 
 const char *VMPI_getenv(const char *env)
 {
     const char *val = NULL;
     (void)env;
+	// Environment variables are not available for Windows Store applications.
+#ifndef AVMSYSTEM_WINDOWSSTOREAPP
 #ifndef UNDER_CE
     val = getenv(env);
 #endif
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
     return val;
 }
 
 // Call VMPI_getPerformanceFrequency() once to initialize its cache; avoids thread safety issues.
 static uint64_t unused_value = VMPI_getPerformanceFrequency();
 
 uint64_t VMPI_getPerformanceFrequency()
 {
@@ -310,31 +321,72 @@ void VMPI_callWithRegistersSaved(void (*
     VMPI_setjmpNoUnwind(buf);                   // Save registers
     CallWithRegistersSaved2(fn, arg, &buf);     // Computes the stack pointer, calls fn
     CallWithRegistersSaved3(fn, &arg, &buf);    // Probably prevents the previous call from being a tail call
 }
 
 static size_t computePagesize()
 {
     SYSTEM_INFO sysinfo;
+
+#if AVMSYSTEM_WINDOWSSTOREAPP
+	GetNativeSystemInfo(&sysinfo);
+#else
     GetSystemInfo(&sysinfo);
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
 
     return sysinfo.dwPageSize;
 }
 
 // Private to AAVMPI_getVMPageSize (but initialized here to avoid threading concerns).
 // DO NOT REFERENCE THIS VARIABLE ELSEWHERE.  Always call AAVMPI_getVMPageSize.
 
 static size_t pagesize = computePagesize();
 
 size_t VMPI_getVMPageSize()
 {
     return pagesize;
 }
 
+#if AVMSYSTEM_WINDOWSSTOREAPP
+
+using namespace Windows::System::Threading;
+using namespace Windows::Foundation;
+
+struct VMPI_WinTimerData : VMPI_TimerData
+{
+	ThreadPoolTimer^ timer;
+};
+
+uintptr_t VMPI_startTimer(uint32_t micros, VMPI_TimerClient *client)
+{
+    VMPI_WinTimerData *data = (VMPI_WinTimerData *) VMPI_alloc(sizeof(VMPI_WinTimerData));
+    data->init(micros, client);
+	data->timer = nullptr;
+
+    TimeSpan timeSpan;
+    timeSpan.Duration = micros / 1000;
+
+    data->timer = ThreadPoolTimer::CreatePeriodicTimer(ref new TimerElapsedHandler([&] (ThreadPoolTimer^ timer) {
+		data->client->tick();
+    }
+    ), timeSpan);
+    return (uintptr_t)data;
+}
+
+void VMPI_stopTimer(uintptr_t ptr)
+{
+	VMPI_WinTimerData *data = (VMPI_WinTimerData *)ptr;
+	data->timer->Cancel();
+	data->timer = nullptr;
+    VMPI_free(data);
+}
+
+#else
+
 // Timer data, Windows specific data
 struct VMPI_WinTimerData : VMPI_TimerData
 {
     // Platform-specific data
     unsigned int timerId;
 };
 
 // The timer callback proc, called when the timer fires
@@ -366,8 +418,10 @@ uintptr_t VMPI_startTimer(uint32_t micro
 // Stops a timer
 void VMPI_stopTimer(uintptr_t data)
 {
     UINT timerId = ((VMPI_WinTimerData *)data)->timerId;
     if (timerId)
         timeKillEvent((UINT)timerId);
     VMPI_free((VMPI_WinTimerData *)data);
 }
+
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
new file mode 100644
--- /dev/null
+++ b/VMPI/WinRTDebugUtils.cpp
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
+/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VMPI.h"
+
+#include <windows.h>
+
+void VMPI_debugLog(const char* message)
+{
+	OutputDebugStringA(message);
+	VMPI_log( message ); // also log to standard output
+}
+
+void VMPI_debugBreak()
+{
+	// As DebugBreak is not supported, trying to catch debugger's attention otherwise:
+	RaiseException(EXCEPTION_BREAKPOINT , 0,0, NULL);
+}
--- a/core/CodegenLIR.cpp
+++ b/core/CodegenLIR.cpp
@@ -6012,17 +6012,19 @@ FLOAT_ONLY(           !(v.sst_mask == (1
             case OP_lix16:
             case OP_li8:
             case OP_li16:
             case OP_li32:
             {
                 int32_t index = (int32_t) op1;
                 LIns* mopAddr = localGet(index);
                 const MopsInfo& mi = kMopsLoadInfo[opcode-OP_lix8];
+#if defined (VMCFG_INTERRUPT_SAFEPOINT_POLL) && defined (NJ_SAFEPOINT_POLLING_SUPPORTED)
 				Ins(LIR_memfence);
+#endif
             #ifdef VMCFG_MOPS_USE_EXPANDED_LOADSTORE_INT
                 int32_t disp = 0;
                 LIns* realAddr = mopAddrToRangeCheckedRealAddrAndDisp(mopAddr, mi.size, &disp);
                 LIns* i2 = loadIns(mi.op, disp, realAddr, ACCSET_OTHER);
             #else
                 LIns* realAddr = mopAddrToRangeCheckedRealAddrAndDisp(mopAddr, mi.size, NULL);
                 LIns* i2 = callIns(mi.call, 1, realAddr);
             #endif
@@ -6031,32 +6033,36 @@ FLOAT_ONLY(           !(v.sst_mask == (1
             }
 
             case OP_lf32:
             case OP_lf64:
             {
                 int32_t index = (int32_t) op1;
                 LIns* mopAddr = localGet(index);
                 const MopsInfo& mi = kMopsLoadInfo[opcode-OP_lix8];
+#if defined (VMCFG_INTERRUPT_SAFEPOINT_POLL) && defined (NJ_SAFEPOINT_POLLING_SUPPORTED)
 				Ins(LIR_memfence);
+#endif
             #ifdef VMCFG_MOPS_USE_EXPANDED_LOADSTORE_FP
                 int32_t disp = 0;
                 LIns* realAddr = mopAddrToRangeCheckedRealAddrAndDisp(mopAddr, mi.size, &disp);
                 LIns* i2 = loadIns(mi.op, disp, realAddr, ACCSET_OTHER);
             #else
                 LIns* realAddr = mopAddrToRangeCheckedRealAddrAndDisp(mopAddr, mi.size, NULL);
                 LIns* i2 = callIns(mi.call, 1, realAddr);
             #endif
                 localSet(index, i2, result);
                 break;
             }
 #ifdef VMCFG_FLOAT
             case OP_lf32x4:
             {
+#if defined (VMCFG_INTERRUPT_SAFEPOINT_POLL) && defined (NJ_SAFEPOINT_POLLING_SUPPORTED)
 				Ins(LIR_memfence);
+#endif
                 // TODO: inlining.  The appropriate condition is probably *not* VMCFG_MOPS_USE_EXPANDED_LOADSTORE_FP.
                 int32_t index = (int32_t) op1;
                 LIns* mopAddr = binaryIns(LIR_andi, localGet(index), InsConst(~15U));
                 LIns* realAddr = mopAddrToRangeCheckedRealAddrAndDisp(mopAddr, sizeof(float4_t), NULL);
                 LIns* retval = insAlloc(sizeof(float4_t));
                 callIns(FUNCTIONID(mop_lf32x4), 2, retval, realAddr);
                 localSet(index, ldf4(retval,0,ACCSET_OTHER), result);
                 break;
@@ -6066,17 +6072,19 @@ FLOAT_ONLY(           !(v.sst_mask == (1
             // stores
             case OP_si8:
             case OP_si16:
             case OP_si32:
             {
                 LIns* svalue = localGet(sp-1);
                 LIns* mopAddr = localGet(sp);
                 const MopsInfo& mi = kMopsStoreInfo[opcode-OP_si8];
+#if defined (VMCFG_INTERRUPT_SAFEPOINT_POLL) && defined (NJ_SAFEPOINT_POLLING_SUPPORTED)
  				Ins(LIR_memfence);
+#endif
            #ifdef VMCFG_MOPS_USE_EXPANDED_LOADSTORE_INT
                 int32_t disp = 0;
                 LIns* realAddr = mopAddrToRangeCheckedRealAddrAndDisp(mopAddr, mi.size, &disp);
                 lirout->insStore(mi.op, svalue, realAddr, disp, ACCSET_OTHER);
             #else
                 LIns* realAddr = mopAddrToRangeCheckedRealAddrAndDisp(mopAddr, mi.size, NULL);
                 callIns(mi.call, 2, realAddr, svalue);
             #endif
@@ -6085,31 +6093,35 @@ FLOAT_ONLY(           !(v.sst_mask == (1
 
             case OP_sf32:
             case OP_sf64:
             {
                 bool singlePrecision = IFFLOAT(state->value(sp-1).traits == FLOAT_TYPE, false);
                 LIns* svalue = singlePrecision ? localGetf(sp-1) : localGetd(sp-1);
                 LIns* mopAddr = localGet(sp);
                 const MopsInfo& mi = kMopsStoreInfo[opcode-OP_si8];
+#if defined (VMCFG_INTERRUPT_SAFEPOINT_POLL) && defined (NJ_SAFEPOINT_POLLING_SUPPORTED)
  				Ins(LIR_memfence);
+#endif
            #ifdef VMCFG_MOPS_USE_EXPANDED_LOADSTORE_FP
                 int32_t disp = 0;
                 LIns* realAddr = mopAddrToRangeCheckedRealAddrAndDisp(mopAddr, mi.size, &disp);
                 lirout->insStore(mi.op, svalue, realAddr, disp, ACCSET_OTHER);
             #else
                 LIns* realAddr = mopAddrToRangeCheckedRealAddrAndDisp(mopAddr, mi.size, NULL);
                 callIns(mi.call, 2, realAddr, svalue);
             #endif
                 break;
             }
 #ifdef VMCFG_FLOAT
             case OP_sf32x4:
             {
+#if defined (VMCFG_INTERRUPT_SAFEPOINT_POLL) && defined (NJ_SAFEPOINT_POLLING_SUPPORTED)
  				Ins(LIR_memfence);
+#endif
                // TODO: inlining.  The appropriate condition is probably *not* VMCFG_MOPS_USE_EXPANDED_LOADSTORE_FP.
                 LIns* svalue = localGetf4Addr(sp-1);
                 LIns* mopAddr = binaryIns(LIR_andi, localGet(sp), InsConst(~15U));
                 LIns* realAddr = mopAddrToRangeCheckedRealAddrAndDisp(mopAddr, sizeof(float4_t), NULL);
                 callIns(FUNCTIONID(mop_sf32x4), 2, realAddr, svalue);
                 break;
             }
 #endif
--- a/platform/system-selection.h
+++ b/platform/system-selection.h
@@ -23,16 +23,21 @@
 #else
   #define AVMSYSTEM_MAC  0
 #endif
 #ifdef WIN32
   #define AVMSYSTEM_WIN32 1
 #else
   #define AVMSYSTEM_WIN32 0
 #endif
+#ifdef WINDOWS_STORE_APP // For Windows Store Apps both AVMSYSTEM_WIN32 and AVMSYSTEM_WINDOWSSTOREAPP are defined.
+	#define AVMSYSTEM_WINDOWSSTOREAPP 1
+#else
+	#define AVMSYSTEM_WINDOWSSTOREAPP 0
+#endif
 #ifdef __SYMBIAN32__ // defined by Symbian S60 tool chain
   #define AVMSYSTEM_SYMBIAN 1
 #else
   #define AVMSYSTEM_SYMBIAN 0
 #endif
 
 #ifdef WEBOS
   #define AVMSYSTEM_WEBOS 1
--- a/platform/win32/win32-platform.h
+++ b/platform/win32/win32-platform.h
@@ -5,16 +5,25 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __avmplus_win32_platform__
 #define __avmplus_win32_platform__
 
 #include <stdarg.h>
 
+#if AVMSYSTEM_WINDOWSSTOREAPP
+// Including thread will cause warning 4265
+#pragma warning(disable:4265)
+#include <thread>
+#pragma warning(4:4265)
+#include <condition_variable>
+#include <functional>
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
+
 /**
  * We have avmplus.vcproj compiled with the /W4 warning level
  * which is quite picky.  Disable warnings we don't care about.
  */
 #ifdef _MSC_VER
     #pragma warning(disable:4946) // reinterpret_cast used between related classes (bugzilla 615964)
     #pragma warning(disable:4127) // conditional expression is constant - appears to be compiler noise primarily
     #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union
@@ -253,17 +262,24 @@ REALLY_INLINE bool VMPI_lockAcquire(vmpi
 {
     int tries = 0;
     while (::InterlockedCompareExchange((LPLONG)&lock->lock, 1, 0) != 0)
     {
         ++tries;
         // We used to reset to zero if we got to 100. This resets to 0 at 64 instead, with no branch.
         tries &= 63;
         // if tries == 0, we just rolled over 64, so we Sleep(1) to give other threads a chance to run... otherwise we Sleep(0)
+#if AVMSYSTEM_WINDOWSSTOREAPP
+		if(tries == 0)
+		{
+			std::this_thread::yield();
+		}
+#else
         ::Sleep(tries == 0);
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
     }
     return true;
 }
 
 REALLY_INLINE bool VMPI_lockRelease(vmpi_spin_lock_t *lock)
 {
     ::InterlockedExchange((LPLONG)&lock->lock, 0);
     return true;
@@ -323,16 +339,23 @@ REALLY_INLINE void VMPI_memoryBarrier()
     // FIXME: bug 609820 Memory barrier (fence) for win32
     //
     // void MemoryBarrier(void) is only available >= Vista
     // This is a temp solution until we have a x86 asm version.
     volatile int32_t dummy;
     VMPI_atomicIncAndGet32WithBarrier(&dummy);
 }
 
+#if AVMSYSTEM_WINDOWSSTOREAPP
+
+typedef size_t             vmpi_thread_t;
+typedef CONDITION_VARIABLE vmpi_condvar_t;
+
+#else
+
 /**
  * Threads waiting on a conditional variable are recorded in a list
  * of WaitingThread structs.
  */
 struct WaitingThread {
     WaitingThread* next;
     DWORD threadID;
     bool notified;
@@ -343,32 +366,39 @@ struct WaitingThread {
  * The variable itself needs to record only the head and the tail of the list.
  */
 struct vmpi_condvar_t {
     WaitingThread* head;
     WaitingThread* tail;
 };
 
 typedef DWORD                  vmpi_thread_t;
+
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
+
 typedef CRITICAL_SECTION       vmpi_mutex_t;
 typedef LPVOID                 vmpi_thread_arg_t; // Argument type for thread start function
 typedef DWORD                  vmpi_thread_rtn_t; // Return type for thread start function
 typedef LPTHREAD_START_ROUTINE vmpi_thread_start_t;
 
 struct vmpi_thread_attr_t {
     size_t stackSize;
     size_t guardSize;
     int priority;
 };
 
 #define VMPI_THREAD_START_CC   WINAPI
 
 REALLY_INLINE bool VMPI_recursiveMutexInit(vmpi_mutex_t* mutex)
 {
+#if AVMSYSTEM_WINDOWSSTOREAPP
+    InitializeCriticalSectionEx(mutex, 1000, 0);
+#else
     InitializeCriticalSection(mutex);
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
     return true;
 }
 
 REALLY_INLINE bool VMPI_recursiveMutexDestroy(vmpi_mutex_t* mutex)
 {
     DeleteCriticalSection(mutex);
     return true;
 }
@@ -385,60 +415,89 @@ REALLY_INLINE void VMPI_recursiveMutexLo
 
 REALLY_INLINE void VMPI_recursiveMutexUnlock(vmpi_mutex_t* mutex)
 {
     LeaveCriticalSection(mutex);
 }
 
 REALLY_INLINE bool VMPI_condVarInit(vmpi_condvar_t* condvar)
 {
+#if AVMSYSTEM_WINDOWSSTOREAPP
+	InitializeConditionVariable(condvar);
+#else
     condvar->head = NULL;
     condvar->tail = NULL;
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
     return true;
 }
 
 REALLY_INLINE bool VMPI_condVarDestroy(vmpi_condvar_t* condvar)
 {
     (void)condvar;
     return true;
 }
 
 REALLY_INLINE vmpi_thread_t VMPI_currentThread()
 {
+#if AVMSYSTEM_WINDOWSSTOREAPP
+	std::hash<std::thread::id> hash;
+	return hash( std::this_thread::get_id() );
+#else
     return (vmpi_thread_t) (uintptr_t)GetCurrentThreadId();
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
 }
 
 REALLY_INLINE vmpi_thread_t VMPI_nullThread()
 {
+#if AVMSYSTEM_WINDOWSSTOREAPP
+	std::thread::id nullThreadId;
+	std::hash<std::thread::id> hash;
+	return hash( nullThreadId );
+#else
     return NULL;
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
 }
 
 REALLY_INLINE bool VMPI_tlsSetValue(uintptr_t tlsId, void* value)
 {
+#if AVMSYSTEM_WINDOWSSTOREAPP
+	return FlsSetValue((DWORD)tlsId, value) == TRUE;
+#else
     return TlsSetValue((DWORD)tlsId, value) == TRUE;
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
 }
 
 REALLY_INLINE void* VMPI_tlsGetValue(uintptr_t tlsId)
 {
+#if AVMSYSTEM_WINDOWSSTOREAPP
+    return FlsGetValue((DWORD)tlsId);
+#else
     return TlsGetValue((DWORD)tlsId);
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
 }
 
 REALLY_INLINE void VMPI_threadYield()
 {
-#ifdef UNDER_CE
+#if AVMSYSTEM_WINDOWSSTOREAPP
+	std::this_thread::yield();
+#elif defined(UNDER_CE)
     Sleep(1);
 #else
     SwitchToThread();
 #endif
 }
 
 REALLY_INLINE int VMPI_processorQtyAtBoot()
 {
     SYSTEM_INFO systemInfo;
+#if AVMSYSTEM_WINDOWSSTOREAPP
+	GetNativeSystemInfo(&systemInfo);
+#else
     GetSystemInfo(&systemInfo);
+#endif // AVMSYSTEM_WINDOWSSTOREAPP
     // dwNumberOfProcessors can be unreliable, but we know we have at least one processor
     return systemInfo.dwNumberOfProcessors < 1 ? 1 : systemInfo.dwNumberOfProcessors;
 }
 
 REALLY_INLINE void VMPI_spinloopPause()
 {
 #ifdef AVMPLUS_IA32
     __asm pause;
new file mode 100644
--- /dev/null
+++ b/platform/winrt/OSDepWinRT.cpp
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
+/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "avmplus.h"
+
+using namespace Windows::System::Threading;
+using namespace Windows::Foundation;
+
+namespace avmplus
+{
+	struct IntWriterData
+	{
+		ThreadPoolTimer^ timer;
+	};
+	
+	uintptr_t OSDep::startIntWriteTimer(uint32_t millis, volatile int *addr)
+    {
+		IntWriterData *data = (IntWriterData *) VMPI_alloc(sizeof(IntWriterData));
+		data->timer = nullptr;
+		
+		TimeSpan timeSpan;
+		timeSpan.Duration = millis;
+
+		data->timer = ThreadPoolTimer::CreatePeriodicTimer(ref new TimerElapsedHandler([&] (ThreadPoolTimer^ timer) {
+			*addr = 1;
+		}
+		), timeSpan);
+		return (uintptr_t)data;
+    }
+
+    void OSDep::stopTimer(uintptr_t handle)
+    {
+		IntWriterData *data = (IntWriterData *) handle;
+		data->timer->Cancel();
+		data->timer = nullptr;
+		VMPI_free(data);
+    }
+}