Ver código fonte

add support for starting jit server in ch

Michael Holman 9 anos atrás
pai
commit
10cfef1f13

+ 1 - 0
bin/ChakraCore/ChakraCore.def

@@ -48,3 +48,4 @@ JsParseModuleSource
 JsModuleEvaluation
 JsSetModuleHostInfo
 JsGetModuleHostInfo
+JsInitializeJITServer

+ 18 - 0
bin/ch/HostConfigFlags.cpp

@@ -83,6 +83,24 @@ void HostConfigFlags::PrintUsage()
     ChakraRTInterface::PrintConfigFlagsUsageString();
 }
 
+int HostConfigFlags::FindArg(int argc, _In_reads_(argc) PWSTR argv[], PCWSTR targetArg, size_t targetArgLen)
+{
+    return FindArg(argc, argv, [=](PCWSTR arg) -> bool
+    {
+        return _wcsnicmp(arg, targetArg, targetArgLen) == 0;
+    });
+}
+
+void HostConfigFlags::RemoveArg(int& argc, _Inout_updates_to_(argc, argc) LPWSTR argv[], int index)
+{
+    Assert(index >= 0 && index < argc);
+    for (int i = index + 1; i < argc; ++i)
+    {
+        argv[i - 1] = argv[i];
+    }
+    --argc;
+}
+
 void HostConfigFlags::HandleArgsFlag(int& argc, _Inout_updates_to_(argc, argc) LPWSTR argv[])
 {
     const LPCWSTR argsFlag = _u("-args");

+ 26 - 0
bin/ch/HostConfigFlags.h

@@ -20,6 +20,11 @@ public:
     static void(__stdcall *pfnPrintUsage)();
 
     static void HandleArgsFlag(int& argc, _Inout_updates_to_(argc, argc) LPWSTR argv[]);
+    static void RemoveArg(int& argc, _Inout_updates_to_(argc, argc) PWSTR argv[], int index);
+    static int FindArg(int argc, _In_reads_(argc) PWSTR argv[], PCWSTR targetArg, size_t targetArgLen);
+
+    template <class Func> static int FindArg(int argc, _In_reads_(argc) PWSTR argv[], Func func);
+    template <int LEN> static int FindArg(int argc, _In_reads_(argc) PWSTR argv[], const char16(&targetArg)[LEN]);
 
     virtual bool ParseFlag(LPCWSTR flagsString, ICmdLineArgsParser * parser) override;
     virtual void PrintUsage() override;
@@ -32,3 +37,24 @@ private:
     template <typename T>
     void Parse(ICmdLineArgsParser * parser, T * value);
 };
+
+// Find an arg in the arg list that satisfies func. Return the arg index if found.
+template <class Func>
+int HostConfigFlags::FindArg(int argc, _In_reads_(argc) PWSTR argv[], Func func)
+{
+    for (int i = 1; i < argc; ++i)
+    {
+        if (func(argv[i]))
+        {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+template <int LEN>
+int HostConfigFlags::FindArg(int argc, _In_reads_(argc) PWSTR argv[], const char16(&targetArg)[LEN])
+{
+    return FindArg(argc, argv, targetArg, LEN - 1); // -1 to exclude null terminator
+}

+ 1 - 1
bin/ch/HostConfigFlagsList.h

@@ -9,6 +9,6 @@ FLAG(bool, DebugLaunch,                     "Create the test debugger and execut
 FLAG(BSTR, GenerateLibraryByteCodeHeader,   "Generate bytecode header file from library code", NULL)
 FLAG(int,  InspectMaxStringLength,          "Max string length to dump in locals inspection", 16)
 FLAG(BSTR, Serialized,                      "If source is UTF8, deserializes from bytecode file", NULL)
-FLAG(bool, EnableOutOfProcJIT,              "JIT in a separate process", false)
+FLAG(bool, EnableOutOfProcJIT,              "Run JIT in a separate process", true)
 #undef FLAG
 #endif

+ 165 - 0
bin/ch/JITProcessManager.cpp

@@ -0,0 +1,165 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+#include "stdafx.h"
+
+#ifdef _WIN32
+HANDLE JITProcessManager::s_rpcServerProcessHandle = 0; // 0 is the "invalid handle" value for process handles
+UUID JITProcessManager::s_connectionId = GUID_NULL;
+
+HRESULT JITProcessManager::StartRpcServer(int argc, __in_ecount(argc) LPWSTR argv[])
+{
+    HRESULT hr = S_OK;
+
+    if (IsEqualGUID(s_connectionId, GUID_NULL))
+    {
+        RPC_STATUS status = UuidCreate(&s_connectionId);
+        if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
+        {
+            hr = CreateServerProcess(argc, argv);
+        }
+        else
+        {
+            hr = HRESULT_FROM_WIN32(status);
+        }
+    }
+
+    return hr;
+}
+
+/* static */
+void
+JITProcessManager::RemoveArg(LPCWSTR flag, int * argc, __in_ecount(*argc) LPWSTR * argv[])
+{
+    size_t flagLen = wcslen(flag);
+    int flagIndex;
+    while ((flagIndex = HostConfigFlags::FindArg(*argc, *argv, flag, flagLen)) >= 0)
+    {
+        HostConfigFlags::RemoveArg(*argc, *argv, flagIndex);
+    }
+}
+
+HRESULT JITProcessManager::CreateServerProcess(int argc, __in_ecount(argc) LPWSTR argv[])
+{
+    HRESULT hr;
+    PROCESS_INFORMATION processInfo = { 0 };
+    STARTUPINFOW si = { 0 };
+
+    // overallocate constant cmd line (jshost -jitserver:<guid>)
+    size_t cmdLineSize = (MAX_PATH + argc) * sizeof(WCHAR);
+    for (int i = 0; i < argc; ++i)
+    {
+        // calculate space requirement for each arg
+        cmdLineSize += wcslen(argv[i]) * sizeof(WCHAR);
+    }
+
+    WCHAR* cmdLine = (WCHAR*)malloc(cmdLineSize);
+    if (cmdLine == nullptr)
+    {
+        return E_OUTOFMEMORY;
+    }
+    RPC_WSTR connectionUuidString = NULL;
+
+    hr = StringCchCopyW(cmdLine, cmdLineSize, L"ch.exe -jitserver:");
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    RPC_STATUS status = UuidToStringW(&s_connectionId, &connectionUuidString);
+    if (status != S_OK)
+    {
+        return HRESULT_FROM_WIN32(status);
+    }
+
+    hr = StringCchCatW(cmdLine, cmdLineSize, (WCHAR*)connectionUuidString);
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    for (int i = 1; i < argc; ++i)
+    {
+        hr = StringCchCatW(cmdLine, cmdLineSize, L" ");
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+        hr = StringCchCatW(cmdLine, cmdLineSize, argv[i]);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+    }
+
+    if (!CreateProcessW(
+        NULL,
+        cmdLine,
+        NULL,
+        NULL,
+        FALSE,
+        CREATE_SUSPENDED,
+        NULL,
+        NULL,
+        &si,
+        &processInfo))
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    free(cmdLine);
+
+    if (ResumeThread(processInfo.hThread) == (DWORD)-1)
+    {
+        TerminateProcess(processInfo.hProcess, GetLastError());
+        CloseHandle(processInfo.hProcess);
+        CloseHandle(processInfo.hThread);
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    CloseHandle(processInfo.hThread);
+    s_rpcServerProcessHandle = processInfo.hProcess;
+
+    // create job object so if parent jshost gets killed, server is killed as well
+    HANDLE jobObject = CreateJobObject(nullptr, nullptr);
+    if (jobObject == nullptr)
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+    if (!AssignProcessToJobObject(jobObject, s_rpcServerProcessHandle))
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo = { 0 };
+    jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+
+    if (!SetInformationJobObject(jobObject, JobObjectExtendedLimitInformation, &jobInfo, sizeof(jobInfo)))
+    {
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    return NOERROR;
+}
+
+void JITProcessManager::StopRpcServer()
+{
+    // For now we just kill the process
+    TerminateProcess(s_rpcServerProcessHandle, 1);
+
+    CloseHandle(s_rpcServerProcessHandle);
+    s_rpcServerProcessHandle = NULL;
+}
+
+HANDLE JITProcessManager::GetRpcProccessHandle()
+{
+    return s_rpcServerProcessHandle;
+}
+
+UUID JITProcessManager::GetRpcConnectionId()
+{
+    return s_connectionId;
+}
+#endif

+ 23 - 0
bin/ch/JITProcessManager.h

@@ -0,0 +1,23 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+#pragma once
+
+class JITProcessManager
+{
+public:
+    static HRESULT StartRpcServer(int argc, __in_ecount(argc) LPWSTR argv[]);
+    static void StopRpcServer();
+
+    static HANDLE GetRpcProccessHandle();
+    static UUID GetRpcConnectionId();
+    static void RemoveArg(LPCWSTR flag, int * argc, __in_ecount(*argc) LPWSTR * argv[]);
+
+private:
+    static HRESULT CreateServerProcess(int argc, __in_ecount(argc) LPWSTR argv[]);
+
+    static HANDLE s_rpcServerProcessHandle;
+    static UUID s_connectionId;
+};

+ 103 - 0
bin/ch/ch.cpp

@@ -22,6 +22,7 @@ byte ttUri[MAX_PATH * sizeof(wchar_t)];
 size_t ttUriByteLength = 0;
 UINT32 snapInterval = MAXUINT32;
 UINT32 snapHistoryLength = MAXUINT32;
+LPWSTR connectionUuidString = NULL;
 UINT32 startEventCount = 1;
 
 extern "C"
@@ -36,6 +37,7 @@ int HostExceptionFilter(int exceptionCode, _EXCEPTION_POINTERS *ep)
 {
     ChakraRTInterface::NotifyUnhandledException(ep);
 
+    JITProcessManager::StopRpcServer();
     bool crashOnException = false;
     ChakraRTInterface::GetCrashOnExceptionFlag(&crashOnException);
 
@@ -633,6 +635,81 @@ HRESULT ExecuteTestWithMemoryCheck(char* fileName)
     return hr;
 }
 
+#ifdef _WIN32
+bool HandleJITServerFlag(int& argc, _Inout_updates_to_(argc, argc) LPWSTR argv[])
+{
+    LPCWSTR flag = L"-jitserver:";
+    LPCWSTR flagWithoutColon = L"-jitserver";
+    size_t flagLen = wcslen(flag);
+
+    int i = 0;
+    for (i = 1; i < argc; ++i)
+    {
+        if (!_wcsicmp(argv[i], flagWithoutColon))
+        {
+            connectionUuidString = L"";
+            break;
+        }
+        else if (!_wcsnicmp(argv[i], flag, flagLen))
+        {
+            connectionUuidString = argv[i] + flagLen;
+            if (wcslen(connectionUuidString) == 0)
+            {
+                fwprintf(stdout, L"[FAILED]: must pass a UUID to -jitserver:\n");
+                return false;
+            }
+            else
+            {
+                break;
+            }
+        }
+    }
+
+    if (i == argc)
+        return false;
+
+    // remove this flag now
+    HostConfigFlags::RemoveArg(argc, argv, i);
+
+    return true;
+}
+
+typedef HRESULT(WINAPI *JsInitializeJITServerPtr)(UUID* connectionUuid, void* securityDescriptor, void* alpcSecurityDescriptor);
+
+int _cdecl RunJITServer(int argc, __in_ecount(argc) LPWSTR argv[])
+{
+    ChakraRTInterface::ArgInfo argInfo = { argc, argv, PrintUsage, nullptr };
+    HINSTANCE chakraLibrary = nullptr;
+    bool success = ChakraRTInterface::LoadChakraDll(&argInfo, &chakraLibrary);
+
+    if (!success)
+    {
+        wprintf(L"\nDll load failed\n");
+        return ERROR_DLL_INIT_FAILED;
+    }
+
+    UUID connectionUuid;
+    DWORD status = UuidFromStringW((RPC_WSTR)connectionUuidString, &connectionUuid);
+    if (status != RPC_S_OK)
+    {
+        return status;
+    }
+
+    JsInitializeJITServerPtr initRpcServer = (JsInitializeJITServerPtr)GetProcAddress(chakraLibrary, "JsInitializeJITServer");
+    HRESULT hr = initRpcServer(&connectionUuid, nullptr, nullptr);
+    if (FAILED(hr))
+    {
+        wprintf(L"InitializeJITServer failed by 0x%x\n", hr);
+        return hr;
+    }
+
+    if (chakraLibrary)
+    {
+        ChakraRTInterface::UnloadChakraDll(chakraLibrary);
+    }
+    return 0;
+}
+#endif
 
 unsigned int WINAPI StaticThreadProc(void *lpParam)
 {
@@ -656,6 +733,10 @@ int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[])
 {
 #endif
 
+#ifdef _WIN32
+    bool runJITServer = HandleJITServerFlag(argc, argv);
+#endif
+
     if (argc < 2)
     {
         PrintUsage();
@@ -663,6 +744,13 @@ int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[])
         return EXIT_FAILURE;
     }
 
+#ifdef _WIN32
+    if (runJITServer)
+    {
+        return RunJITServer(argc, argv);
+    }
+#endif
+
     int cpos = 0;
     for(int i = 0; i < argc; ++i)
     {
@@ -719,6 +807,14 @@ int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[])
 
     HostConfigFlags::HandleArgsFlag(argc, argv);
 
+#ifdef _WIN32
+    if (HostConfigFlags::flags.EnableOutOfProcJIT)
+    {
+        JITProcessManager::RemoveArg(_u("-dynamicprofilecache:"), &argc, &argv);
+        JITProcessManager::RemoveArg(_u("-dynamicprofileinput:"), &argc, &argv);
+    }
+#endif
+
     ChakraRTInterface::ArgInfo argInfo = { argc, argv, PrintUsage, nullptr };
     HINSTANCE chakraLibrary = nullptr;
     bool success = ChakraRTInterface::LoadChakraDll(&argInfo, &chakraLibrary);
@@ -736,6 +832,13 @@ int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[])
     if (success)
     {
 #ifdef _WIN32
+
+        if (HostConfigFlags::flags.EnableOutOfProcJIT)
+        {
+            // TODO: Error checking
+            JITProcessManager::StartRpcServer(argc, argv);
+        }
+
         HANDLE threadHandle;
         threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, &StaticThreadProc, &argInfo, STACK_SIZE_PARAM_IS_A_RESERVATION, 0));
 

+ 7 - 2
bin/ch/ch.vcxproj

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <Import Condition="'$(ChakraBuildPathImported)'!='true'" Project="$(SolutionDir)Chakra.Build.Paths.props" />
   <Import Project="$(BuildConfigPropsPath)Chakra.Build.ProjectConfiguration.props" />
@@ -36,7 +36,10 @@
         oleaut32.lib;
         ole32.lib;
         kernel32.lib;
+        Rpcrt4.lib;
       </AdditionalDependencies>
+      <IgnoreAllDefaultLibraries Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+      </IgnoreAllDefaultLibraries>
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
@@ -53,6 +56,7 @@
     <ClInclude Include="Helpers.h" />
     <ClInclude Include="HostConfigFlags.h" />
     <ClInclude Include="HostConfigFlagsList.h" />
+    <ClInclude Include="JITProcessManager.h" />
     <ClInclude Include="MessageQueue.h" />
     <ClInclude Include="stdafx.h" />
     <ClInclude Include="WScriptJsrt.h" />
@@ -64,6 +68,7 @@
     <ClCompile Include="Debugger.cpp" />
     <ClCompile Include="Helpers.cpp" />
     <ClCompile Include="HostConfigFlags.cpp" />
+    <ClCompile Include="JITProcessManager.cpp" />
     <ClCompile Include="WScriptJsrt.cpp" />
   </ItemGroup>
   <ItemGroup>
@@ -99,4 +104,4 @@
   </ItemGroup>
   <Import Project="$(BuildConfigPropsPath)Chakra.Build.targets" Condition="exists('$(BuildConfigPropsPath)Chakra.Build.targets')" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-</Project>
+</Project>

+ 5 - 0
bin/ch/stdafx.h

@@ -147,6 +147,11 @@ do { \
 #include "WScriptJsrt.h"
 #include "Debugger.h"
 
+#ifdef _WIN32
+#include <strsafe.h>
+#include "JITProcessManager.h"
+#endif
+
 template<class T, bool JSRTHeap>
 class AutoStringPtr
 {

+ 1 - 1
lib/JITServer/JITServer.cpp

@@ -6,7 +6,7 @@
 #include "JITServerPch.h"
 
 __declspec(dllexport)
-HRESULT JsInitializeRpcServer(
+HRESULT JsInitializeJITServer(
     __in UUID* connectionUuid,
     __in_opt void* securityDescriptor,
     __in_opt void* alpcSecurityDescriptor)

+ 1 - 1
lib/Parser/Chakra.Parser.vcxproj

@@ -145,4 +145,4 @@
   </ItemGroup>
   <Import Project="$(BuildConfigPropsPath)Chakra.Build.targets" Condition="exists('$(BuildConfigPropsPath)Chakra.Build.targets')" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-</Project>
+</Project>