{"action":"created","comment":{"url":"https://api.github.com/repos/JuliaLang/julia/pulls/comments/66514159","id":66514159,"diff_hunk":"@@ -0,0 +1,839 @@\n+// This file is a part of Julia. License is MIT: http://julialang.org/license\n+\n+#include \"llvm-version.h\"\n+#include \"platform.h\"\n+#include \"options.h\"\n+\n+#ifdef USE_MCJIT\n+#include <llvm/ExecutionEngine/SectionMemoryManager.h>\n+#include \"julia.h\"\n+#include \"julia_internal.h\"\n+\n+#ifdef LLVM37\n+#ifndef LLVM38\n+#  include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>\n+#endif\n+#ifdef _OS_LINUX_\n+#  include <sys/syscall.h>\n+#  ifdef __NR_memfd_create\n+#    include <linux/memfd.h>\n+#  endif\n+#endif\n+#ifndef _OS_WINDOWS_\n+#  include <sys/mman.h>\n+#  include <sys/stat.h>\n+#  include <fcntl.h>\n+#  include <unistd.h>\n+#  if defined(_OS_DARWIN_) && !defined(MAP_ANONYMOUS)\n+#    define MAP_ANONYMOUS MAP_ANON\n+#  endif\n+#endif\n+#ifdef _OS_FREEBSD_\n+#  include <sys/types.h>\n+#endif\n+\n+namespace {\n+\n+static size_t get_block_size(size_t size)\n+{\n+    return (size > jl_page_size * 256 ? LLT_ALIGN(size, jl_page_size) :\n+            jl_page_size * 256);\n+}\n+\n+// Wrapper function to mmap/munmap/mprotect pages...\n+static void *map_anon_page(size_t size)\n+{\n+#ifdef _OS_WINDOWS_\n+    char *mem = (char*)VirtualAlloc(NULL, size + jl_page_size,\n+                                    MEM_COMMIT, PAGE_READWRITE);\n+    assert(mem && \"Cannot allocate RW memory\");\n+    mem = (char*)LLT_ALIGN(uintptr_t(mem), jl_page_size);\n+#else // _OS_WINDOWS_\n+    void *mem = mmap(nullptr, size, PROT_READ | PROT_WRITE,\n+                     MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);\n+    assert(mem != MAP_FAILED && \"Cannot allocate RW memory\");\n+#endif // _OS_WINDOWS_\n+    return mem;\n+}\n+\n+static void unmap_page(void *ptr, size_t size)\n+{\n+#ifdef _OS_WINDOWS_\n+    VirtualFree(ptr, size, MEM_DECOMMIT);\n+#else // _OS_WINDOWS_\n+    munmap(ptr, size);\n+#endif // _OS_WINDOWS_\n+}\n+\n+#ifdef _OS_WINDOWS_\n+enum class Prot : int {\n+    RW = PAGE_READWRITE,\n+    RX = PAGE_EXECUTE,\n+    RO = PAGE_READONLY\n+};\n+\n+static void protect_page(void *ptr, size_t size, Prot flags)\n+{\n+    DWORD old_prot;\n+    if (!VirtualProtect(ptr, size, (DWORD)flags, &old_prot)) {\n+        jl_safe_printf(\"Cannot protect page @%p of size %u to 0x%x (err 0x%x)\\n\",\n+                       ptr, (unsigned)size, (unsigned)flags,\n+                       (unsigned)GetLastError());\n+        abort();\n+    }\n+}\n+#else // _OS_WINDOWS_\n+enum class Prot : int {\n+    RW = PROT_READ | PROT_WRITE,\n+    RX = PROT_READ | PROT_EXEC,\n+    RO = PROT_READ\n+};\n+\n+static void protect_page(void *ptr, size_t size, Prot flags)\n+{\n+    int ret = mprotect(ptr, size, (int)flags);\n+    if (ret != 0) {\n+        perror(__func__);\n+        abort();\n+    }\n+}\n+\n+static bool check_fd_or_close(int fd)\n+{\n+    if (fd == -1)\n+        return false;\n+    // This can fail due to `noexec` mount option ....\n+    fcntl(fd, F_SETFD, FD_CLOEXEC);\n+    fchmod(fd, S_IRWXU);\n+    ftruncate(fd, jl_page_size);\n+    void *ptr = mmap(nullptr, jl_page_size, PROT_READ | PROT_EXEC,\n+                     MAP_SHARED, fd, 0);\n+    if (ptr == MAP_FAILED) {\n+        close(fd);\n+        return false;\n+    }\n+    munmap(ptr, jl_page_size);\n+    return true;\n+}\n+#endif // _OS_WINDOWS_\n+\n+static intptr_t anon_hdl = -1;\n+\n+#ifdef _OS_WINDOWS_\n+// As far as I can tell `CreateFileMapping` cannot be resized on windows.\n+// Also, creating big file mapping and then map pieces of it seems to\n+// consume too much global resources. Therefore, we use each file mapping\n+// as a block on windows\n+static void *create_shared_map(size_t size, size_t offset)\n+{\n+    void *addr = MapViewOfFile((HANDLE)offset, FILE_MAP_ALL_ACCESS,\n+                               0, 0, size);\n+    assert(addr && \"Cannot map RW view\");\n+    return addr;\n+}\n+\n+static intptr_t init_shared_map()\n+{\n+    anon_hdl = 0;\n+}\n+\n+static void *alloc_shared_page(size_t size, size_t *offset, bool exec)\n+{\n+    assert(size % jl_page_size == 0);\n+    auto file_mode = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;\n+    HANDLE hdl = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,\n+                                   file_mode, 0, size, NULL);\n+    *offset = (size_t)hdl;\n+    auto map_mode = FILE_MAP_READ | (exec ? FILE_MAP_EXECUTE : 0);\n+    void *addr = MapViewOfFile(hdl, map_mode, 0, 0, size);\n+    assert(addr && \"Cannot map RO view\");\n+    return addr;\n+}\n+#else // _OS_WINDOWS_\n+// For shared mapped region\n+static intptr_t get_anon_hdl(void)\n+{\n+    int fd = -1;\n+\n+    // Linux and FreeBSD can create an anonymous fd without touching the\n+    // file system.\n+#  ifdef __NR_memfd_create\n+    fd = syscall(__NR_memfd_create, \"julia-codegen\", MFD_CLOEXEC);\n+    if (check_fd_or_close(fd))\n+        return fd;\n+#  endif\n+#  ifdef _OS_FREEBSD_\n+    fd = shm_open(SHM_ANON, O_RDWR, S_IRWXU);\n+    if (check_fd_or_close(fd))\n+        return fd;\n+#  endif\n+    char shm_name[] = \"julia-codegen-0123456789-0123456789/tmp///\";\n+    pid_t pid = getpid();\n+    // `shm_open` can't be mapped exec on mac\n+#  ifndef _OS_DARWIN_\n+    do {\n+        snprintf(shm_name, sizeof(shm_name),\n+                 \"julia-codegen-%d-%d\", (int)pid, rand());\n+        fd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, S_IRWXU);\n+        if (check_fd_or_close(fd)) {\n+            shm_unlink(shm_name);\n+            return fd;\n+        }\n+    } while (errno == EEXIST);\n+#  endif\n+    FILE *tmpf = tmpfile();\n+    if (tmpf) {\n+        fd = dup(fileno(tmpf));\n+        fclose(tmpf);\n+        if (check_fd_or_close(fd)) {\n+            return fd;\n+        }\n+    }\n+    snprintf(shm_name, sizeof(shm_name),\n+             \"/tmp/julia-codegen-%d-XXXXXX\", (int)pid);\n+    fd = mkstemp(shm_name);\n+    if (check_fd_or_close(fd)) {\n+        unlink(shm_name);\n+        return fd;\n+    }\n+    return -1;\n+}\n+\n+static size_t map_offset = 0;\n+// Multiple of 128MB.\n+// Hopefully no one will set a ulimit for this to be a problem...\n+static constexpr size_t map_size_inc = 128 * 1024 * 1024;\n+static size_t map_size = 0;\n+static jl_mutex_t shared_map_lock;\n+\n+static void *create_shared_map(size_t size, size_t offset)\n+{\n+    void *addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED,\n+                      anon_hdl, offset);\n+    assert(addr != MAP_FAILED && \"Cannot map RW view\");\n+    return addr;\n+}\n+\n+static intptr_t init_shared_map()\n+{\n+    anon_hdl = get_anon_hdl();\n+    if (anon_hdl == -1)\n+        return -1;\n+    map_offset = 0;\n+    map_size = map_size_inc;\n+    int ret = ftruncate(anon_hdl, map_size);\n+    if (ret != 0) {\n+        perror(__func__);\n+        abort();\n+    }\n+    return anon_hdl;\n+}\n+\n+static void *alloc_shared_page(size_t size, size_t *offset, bool exec)\n+{\n+    assert(size % jl_page_size == 0);\n+    size_t off = jl_atomic_fetch_add(&map_offset, size);\n+    *offset = off;\n+    if (__unlikely(off + size > map_size)) {\n+        JL_LOCK_NOGC(&shared_map_lock);\n+        size_t old_size = map_size;\n+        while (off + size > map_size)\n+            map_size += map_size_inc;\n+        if (old_size != map_size) {\n+            int ret = ftruncate(anon_hdl, map_size);\n+            if (ret != 0) {\n+                perror(__func__);\n+                abort();\n+            }\n+        }\n+        JL_UNLOCK_NOGC(&shared_map_lock);\n+    }\n+    return create_shared_map(size, off);\n+}\n+#endif // _OS_WINDOWS_\n+\n+#ifdef _OS_LINUX_\n+// Using `/proc/self/mem`, A.K.A. Keno's remote memory manager.\n+\n+static int self_mem_fd = -1;\n+\n+static int init_self_mem()\n+{\n+    int fd = open(\"/proc/self/mem\", O_RDWR | O_SYNC | O_CLOEXEC);\n+    if (fd == -1)\n+        return -1;\n+    // buffer to check if write works;\n+    volatile uint64_t buff = 0;\n+    uint64_t v = 0x12345678;\n+    int ret = pwrite(fd, (void*)&v, sizeof(uint64_t), (uintptr_t)&buff);\n+    if (ret != sizeof(uint64_t) || buff != 0x12345678) {\n+        close(fd);\n+        return -1;\n+    }\n+    self_mem_fd = fd;\n+    return fd;\n+}\n+\n+static void write_self_mem(void *dest, void *ptr, size_t size)\n+{\n+    while (size > 0) {\n+        ssize_t ret = pwrite(self_mem_fd, ptr, size, (uintptr_t)dest);\n+        if (ret == size)\n+            return;\n+        if (ret == -1 && (errno == EAGAIN || errno == EINTR))\n+            continue;\n+        assert(ret < size);\n+        size -= ret;\n+        ptr = (char*)ptr + ret;\n+        dest = (char*)dest + ret;\n+    }\n+}\n+#endif // _OS_LINUX_\n+\n+using namespace llvm;\n+\n+// Allocation strategies\n+// * For RW data, no memory protection needed, use plain memory pool.\n+// * For RO data or code,\n+//\n+//   The first allocation in the page always has write address equals to\n+//   runtime address.\n+//\n+//   1. shared dual map\n+//\n+//       Map an (unlinked) anonymous file as memory pool.\n+//       After first allocation, write address points to the second map.\n+//       The second map is set to unreadable and unwritable in finalization.\n+//\n+//   2. private dual map\n+//\n+//       Same as above but use anonymous memory map as memory pool,\n+//       and use low level OS api to set up the second map.\n+//\n+//   3. copying data into RO page bypassing page protection\n+//\n+//       After first allocation, write address points to a temporary buffer.\n+//       Requires copying data out of the temporary buffer in finalization.\n+\n+// Allocates at least 256 pages per block and keep up to 8 blocks in the free\n+// list. The block with the least free space is discarded when we need to\n+// allocate a new page.\n+// Unused full pages are free'd from the block before discarding so at most\n+// one page is wasted on each discarded blocks. There should be at most one\n+// block with more than 128 pages available so the discarded one must have\n+// less than 128 pages available and therefore at least 128 pages used.\n+// (Apart from fragmentation) this guarantees less than 1% of memory is wasted.\n+\n+// the `shared` type parameter is for Windows only....\n+struct Block {\n+    // runtime address\n+    char *ptr{nullptr};\n+    size_t total{0};\n+    size_t avail{0};\n+\n+    Block(const Block&) = delete;\n+    Block &operator=(const Block&) = delete;\n+\n+    Block() = default;\n+\n+    void *alloc(size_t size, size_t align)\n+    {\n+        size_t aligned_avail = avail & (-align);\n+        if (aligned_avail < size)\n+            return nullptr;\n+        char *p = ptr + total - aligned_avail;\n+        avail = aligned_avail - size;\n+        return p;\n+    }\n+    void reset(void *addr, size_t size)\n+    {\n+        if (avail >= jl_page_size) {\n+            uintptr_t end = uintptr_t(ptr) + total;\n+            uintptr_t first_free = end - avail;\n+            first_free = LLT_ALIGN(first_free, jl_page_size);\n+            assert(first_free < end);\n+            unmap_page((void*)first_free, end - first_free);\n+        }\n+        ptr = (char*)addr;\n+        total = avail = size;\n+    }\n+};\n+\n+class RWAllocator {\n+    static constexpr int nblocks = 8;\n+    Block blocks[nblocks]{};\n+public:\n+    void *alloc(size_t size, size_t align)\n+    {\n+        size_t min_size = (size_t)-1;\n+        int min_id = 0;\n+        for (int i = 0;i < nblocks && blocks[i].ptr;i++) {\n+            if (void *ptr = blocks[i].alloc(size, align))\n+                return ptr;\n+            if (blocks[i].avail < min_size) {\n+                min_size = blocks[i].avail;\n+                min_id = i;\n+            }\n+        }\n+        size_t block_size = get_block_size(size);\n+        blocks[min_id].reset(map_anon_page(block_size), block_size);\n+        return blocks[min_id].alloc(size, align);\n+    }\n+};\n+\n+struct ROBlock : public Block {\n+    // Possible states\n+    // Allocation:\n+    // * Initial allocation: `state & InitAlloc`\n+    // * Followup allocation: `(state & Alloc) && !(state & InitAlloc)`\n+    enum State {\n+        // This block has no page protection set yet.\n+        InitAlloc = (1 << 0),\n+        // There is at least one allocation in this page.\n+        Alloc = (1 << 1),\n+        // `wr_ptr` can be directly used as write address.\n+        WRInit = (1 << 2),\n+        // With `WRInit` set, whether `wr_ptr` has write permission enabled.\n+        WRReady = (1 << 3),\n+    };\n+\n+    uintptr_t wr_ptr{0};\n+    uint32_t state{0};\n+    ROBlock() = default;\n+\n+    void swap(ROBlock &other)\n+    {\n+        std::swap(ptr, other.ptr);\n+        std::swap(total, other.total);\n+        std::swap(avail, other.avail);\n+        std::swap(wr_ptr, other.wr_ptr);\n+        std::swap(state, other.state);\n+    }\n+\n+    ROBlock(ROBlock &&other)\n+        : ROBlock()\n+    {\n+        swap(other);\n+    }\n+};\n+\n+struct Allocation {\n+    void *wr_addr;\n+    void *rt_addr;\n+    size_t sz;\n+    bool relocated;\n+};\n+\n+template<bool exec>\n+class ROAllocator {\n+protected:\n+    static constexpr int nblocks = 8;\n+    ROBlock blocks[nblocks];\n+    // Blocks that are done allocating but might not have all the permissions\n+    // set or data copied yet.\n+    SmallVector<ROBlock, 16> pendings;","path":"src/cgmemmgr.cpp","position":434,"original_position":434,"commit_id":"64c7f59e446a57bf0726752c1cc5882b03b4e039","original_commit_id":"64c7f59e446a57bf0726752c1cc5882b03b4e039","user":{"login":"yuyichao","id":712232,"avatar_url":"https://avatars.githubusercontent.com/u/712232?v=3","gravatar_id":"","url":"https://api.github.com/users/yuyichao","html_url":"https://github.com/yuyichao","followers_url":"https://api.github.com/users/yuyichao/followers","following_url":"https://api.github.com/users/yuyichao/following{/other_user}","gists_url":"https://api.github.com/users/yuyichao/gists{/gist_id}","starred_url":"https://api.github.com/users/yuyichao/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yuyichao/subscriptions","organizations_url":"https://api.github.com/users/yuyichao/orgs","repos_url":"https://api.github.com/users/yuyichao/repos","events_url":"https://api.github.com/users/yuyichao/events{/privacy}","received_events_url":"https://api.github.com/users/yuyichao/received_events","type":"User","site_admin":false},"body":"`to_be_removed`?","created_at":"2016-06-09T20:19:48Z","updated_at":"2016-06-09T20:19:48Z","html_url":"https://github.com/JuliaLang/julia/pull/16777#discussion_r66514159","pull_request_url":"https://api.github.com/repos/JuliaLang/julia/pulls/16777","_links":{"self":{"href":"https://api.github.com/repos/JuliaLang/julia/pulls/comments/66514159"},"html":{"href":"https://github.com/JuliaLang/julia/pull/16777#discussion_r66514159"},"pull_request":{"href":"https://api.github.com/repos/JuliaLang/julia/pulls/16777"}}},"pull_request":{"url":"https://api.github.com/repos/JuliaLang/julia/pulls/16777","id":72646666,"html_url":"https://github.com/JuliaLang/julia/pull/16777","diff_url":"https://github.com/JuliaLang/julia/pull/16777.diff","patch_url":"https://github.com/JuliaLang/julia/pull/16777.patch","issue_url":"https://api.github.com/repos/JuliaLang/julia/issues/16777","number":16777,"state":"open","locked":false,"title":"Implement custom memory manager for LLVM","user":{"login":"yuyichao","id":712232,"avatar_url":"https://avatars.githubusercontent.com/u/712232?v=3","gravatar_id":"","url":"https://api.github.com/users/yuyichao","html_url":"https://github.com/yuyichao","followers_url":"https://api.github.com/users/yuyichao/followers","following_url":"https://api.github.com/users/yuyichao/following{/other_user}","gists_url":"https://api.github.com/users/yuyichao/gists{/gist_id}","starred_url":"https://api.github.com/users/yuyichao/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yuyichao/subscriptions","organizations_url":"https://api.github.com/users/yuyichao/orgs","repos_url":"https://api.github.com/users/yuyichao/repos","events_url":"https://api.github.com/users/yuyichao/events{/privacy}","received_events_url":"https://api.github.com/users/yuyichao/received_events","type":"User","site_admin":false},"body":"Use various ways to reuse the page that has the page protection set in order to avoid wasting a page of memory for each JIT event.\r\n\r\nFixes #14626\r\n\r\nTested on Linux with LLVM 3.7.1 and 3.8 with OrcJIT.\r\nThis reduces the memory used in the subarray test by `~100MB` (There are around `25k` JIT events each page protects at least one page of memory even though the total allocation is only around `10-20MB`.)\r\n\r\nShould in principle work on OSX, using the ~~`mkstemp`~~ `tmpfile` fallback code path.\r\n\r\n~~Does not work on windows yet due to how we handle windows unwinding (we patch the code section after the code is generated, causing a segfault since the load address is never writable). It might be enough to modify those code to write to local address instead of load address. @Keno also mentioned some way to fix this properly. (This is what the request for help is mainly for....)~~ Fixed","created_at":"2016-06-06T01:16:35Z","updated_at":"2016-06-09T20:19:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d03cb3897c578c07e0116e65253d0f9a581097b2","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/JuliaLang/julia/pulls/16777/commits","review_comments_url":"https://api.github.com/repos/JuliaLang/julia/pulls/16777/comments","review_comment_url":"https://api.github.com/repos/JuliaLang/julia/pulls/comments{/number}","comments_url":"https://api.github.com/repos/JuliaLang/julia/issues/16777/comments","statuses_url":"https://api.github.com/repos/JuliaLang/julia/statuses/64c7f59e446a57bf0726752c1cc5882b03b4e039","head":{"label":"JuliaLang:yyc/codegen/memmgr","ref":"yyc/codegen/memmgr","sha":"64c7f59e446a57bf0726752c1cc5882b03b4e039","user":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"repo":{"id":1644196,"name":"julia","full_name":"JuliaLang/julia","owner":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/JuliaLang/julia","description":"The Julia Language: A fresh approach to technical computing.","fork":false,"url":"https://api.github.com/repos/JuliaLang/julia","forks_url":"https://api.github.com/repos/JuliaLang/julia/forks","keys_url":"https://api.github.com/repos/JuliaLang/julia/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JuliaLang/julia/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JuliaLang/julia/teams","hooks_url":"https://api.github.com/repos/JuliaLang/julia/hooks","issue_events_url":"https://api.github.com/repos/JuliaLang/julia/issues/events{/number}","events_url":"https://api.github.com/repos/JuliaLang/julia/events","assignees_url":"https://api.github.com/repos/JuliaLang/julia/assignees{/user}","branches_url":"https://api.github.com/repos/JuliaLang/julia/branches{/branch}","tags_url":"https://api.github.com/repos/JuliaLang/julia/tags","blobs_url":"https://api.github.com/repos/JuliaLang/julia/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JuliaLang/julia/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JuliaLang/julia/git/refs{/sha}","trees_url":"https://api.github.com/repos/JuliaLang/julia/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JuliaLang/julia/statuses/{sha}","languages_url":"https://api.github.com/repos/JuliaLang/julia/languages","stargazers_url":"https://api.github.com/repos/JuliaLang/julia/stargazers","contributors_url":"https://api.github.com/repos/JuliaLang/julia/contributors","subscribers_url":"https://api.github.com/repos/JuliaLang/julia/subscribers","subscription_url":"https://api.github.com/repos/JuliaLang/julia/subscription","commits_url":"https://api.github.com/repos/JuliaLang/julia/commits{/sha}","git_commits_url":"https://api.github.com/repos/JuliaLang/julia/git/commits{/sha}","comments_url":"https://api.github.com/repos/JuliaLang/julia/comments{/number}","issue_comment_url":"https://api.github.com/repos/JuliaLang/julia/issues/comments{/number}","contents_url":"https://api.github.com/repos/JuliaLang/julia/contents/{+path}","compare_url":"https://api.github.com/repos/JuliaLang/julia/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JuliaLang/julia/merges","archive_url":"https://api.github.com/repos/JuliaLang/julia/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JuliaLang/julia/downloads","issues_url":"https://api.github.com/repos/JuliaLang/julia/issues{/number}","pulls_url":"https://api.github.com/repos/JuliaLang/julia/pulls{/number}","milestones_url":"https://api.github.com/repos/JuliaLang/julia/milestones{/number}","notifications_url":"https://api.github.com/repos/JuliaLang/julia/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JuliaLang/julia/labels{/name}","releases_url":"https://api.github.com/repos/JuliaLang/julia/releases{/id}","deployments_url":"https://api.github.com/repos/JuliaLang/julia/deployments","created_at":"2011-04-21T07:01:50Z","updated_at":"2016-06-09T19:50:14Z","pushed_at":"2016-06-09T20:17:16Z","git_url":"git://github.com/JuliaLang/julia.git","ssh_url":"git@github.com:JuliaLang/julia.git","clone_url":"https://github.com/JuliaLang/julia.git","svn_url":"https://github.com/JuliaLang/julia","homepage":"http://julialang.org/","size":393988,"stargazers_count":7122,"watchers_count":7122,"language":"Julia","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1647,"mirror_url":null,"open_issues_count":1806,"forks":1647,"open_issues":1806,"watchers":7122,"default_branch":"master"}},"base":{"label":"JuliaLang:master","ref":"master","sha":"9ab1519db4ab8c525f84fce542bfc463d9a2b071","user":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"repo":{"id":1644196,"name":"julia","full_name":"JuliaLang/julia","owner":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/JuliaLang/julia","description":"The Julia Language: A fresh approach to technical computing.","fork":false,"url":"https://api.github.com/repos/JuliaLang/julia","forks_url":"https://api.github.com/repos/JuliaLang/julia/forks","keys_url":"https://api.github.com/repos/JuliaLang/julia/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JuliaLang/julia/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JuliaLang/julia/teams","hooks_url":"https://api.github.com/repos/JuliaLang/julia/hooks","issue_events_url":"https://api.github.com/repos/JuliaLang/julia/issues/events{/number}","events_url":"https://api.github.com/repos/JuliaLang/julia/events","assignees_url":"https://api.github.com/repos/JuliaLang/julia/assignees{/user}","branches_url":"https://api.github.com/repos/JuliaLang/julia/branches{/branch}","tags_url":"https://api.github.com/repos/JuliaLang/julia/tags","blobs_url":"https://api.github.com/repos/JuliaLang/julia/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JuliaLang/julia/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JuliaLang/julia/git/refs{/sha}","trees_url":"https://api.github.com/repos/JuliaLang/julia/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JuliaLang/julia/statuses/{sha}","languages_url":"https://api.github.com/repos/JuliaLang/julia/languages","stargazers_url":"https://api.github.com/repos/JuliaLang/julia/stargazers","contributors_url":"https://api.github.com/repos/JuliaLang/julia/contributors","subscribers_url":"https://api.github.com/repos/JuliaLang/julia/subscribers","subscription_url":"https://api.github.com/repos/JuliaLang/julia/subscription","commits_url":"https://api.github.com/repos/JuliaLang/julia/commits{/sha}","git_commits_url":"https://api.github.com/repos/JuliaLang/julia/git/commits{/sha}","comments_url":"https://api.github.com/repos/JuliaLang/julia/comments{/number}","issue_comment_url":"https://api.github.com/repos/JuliaLang/julia/issues/comments{/number}","contents_url":"https://api.github.com/repos/JuliaLang/julia/contents/{+path}","compare_url":"https://api.github.com/repos/JuliaLang/julia/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JuliaLang/julia/merges","archive_url":"https://api.github.com/repos/JuliaLang/julia/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JuliaLang/julia/downloads","issues_url":"https://api.github.com/repos/JuliaLang/julia/issues{/number}","pulls_url":"https://api.github.com/repos/JuliaLang/julia/pulls{/number}","milestones_url":"https://api.github.com/repos/JuliaLang/julia/milestones{/number}","notifications_url":"https://api.github.com/repos/JuliaLang/julia/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JuliaLang/julia/labels{/name}","releases_url":"https://api.github.com/repos/JuliaLang/julia/releases{/id}","deployments_url":"https://api.github.com/repos/JuliaLang/julia/deployments","created_at":"2011-04-21T07:01:50Z","updated_at":"2016-06-09T19:50:14Z","pushed_at":"2016-06-09T20:17:16Z","git_url":"git://github.com/JuliaLang/julia.git","ssh_url":"git@github.com:JuliaLang/julia.git","clone_url":"https://github.com/JuliaLang/julia.git","svn_url":"https://github.com/JuliaLang/julia","homepage":"http://julialang.org/","size":393988,"stargazers_count":7122,"watchers_count":7122,"language":"Julia","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1647,"mirror_url":null,"open_issues_count":1806,"forks":1647,"open_issues":1806,"watchers":7122,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/JuliaLang/julia/pulls/16777"},"html":{"href":"https://github.com/JuliaLang/julia/pull/16777"},"issue":{"href":"https://api.github.com/repos/JuliaLang/julia/issues/16777"},"comments":{"href":"https://api.github.com/repos/JuliaLang/julia/issues/16777/comments"},"review_comments":{"href":"https://api.github.com/repos/JuliaLang/julia/pulls/16777/comments"},"review_comment":{"href":"https://api.github.com/repos/JuliaLang/julia/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/JuliaLang/julia/pulls/16777/commits"},"statuses":{"href":"https://api.github.com/repos/JuliaLang/julia/statuses/64c7f59e446a57bf0726752c1cc5882b03b4e039"}}}}
{"actor":{"display_login":"yuyichao"}}