精华内容
下载资源
问答
  • **很多人安装Android Studio时,电脑用起手机虚拟器(HAXM(用于虚拟机)没安装成功)查看链接,因此就需要在真机实时运行开发的APP,但是苦于一直连接不上真机,很苦恼。因此,写这个教程博客,可以帮助大家...
  • “独立实现”表示它是使用Java虚拟机规范构建的,而使用任何其他Java虚拟机的任何代码。 OpenJ9 JVM与OpenJDK的Java类库相结合,创建一个针对占位面积,性能和可靠性进行调整的完整JDK,非常适合云部署。 ...
  • 一.2019Android~BAT等面试...一般人应该用到 很详实。适合提高看 ) 三.String 的几种创建方式(掌握该知识需要知道java的内存模型) 引号创建 -> String text = “bloom” new 创建 -> String t...

    一.2019Android~BAT等面试大全

    GitHub链接:关于我
    联系我

    二.深入理解Java虚拟机:JVM高级特性与最佳实践PDF

    (太详细了。一般人应该用不到 很详实了。适合提高看 )



    三.String 的几种创建方式(掌握该知识需要知道java的内存模型)

    • 引号创建 -> String text = “bloom”

    • new 创建 -> String text = new String()

    • new 和引号结合 -> String text = new String(“slaughter”)

    • 使用字符串连接符创建 -> String text = “flowers” + “dawn”

    String 常量池

    在 java 的内存结构的方法区中, 有一块被称作常量池(Constant Pool)的区域. 用来存储程序中的各种常量, 包括 Class、String、Integer 等各种 Java 基础数据类型.

    String Pool 是常量池中负责存储 String 常量的区域

    引号创建 String 的机制

    String s1 = "bloom";
    String s2 = "bloom";
    System.out.println(s1 == s2);   //true
    
    1. 编译期: 字符串 “bloom” 是编译期常量, 在编译的时候就能确认它的值

    2. 运行期: JVM 会维护并查询常量池, 如果池中已有改值, 会直接将内存地址的引用返回给对应的变量;如果不存在, 那么 JVM 将会现在字符串常量池中创建改值, 再将引用传递给声明. 由于 “bloom” 已经在程序启动后就存在与字符串常量池中, 所以 s1 赋值时会将常量池中的内存引用传递给 s1, s2 也是同理. 这一系列过程使用过 String 类中的 native 方法 intern() 实现的

    整个过程中, 所有 String 的值 都在方法区的常量池中, 声明的变量引用地址也指向该值在常量池中的内存地址

    使用 new 以及 new 和引号结合的方式创建

    在 Java 中, 使用 new 关键字创建新的对象, 都会在堆区(Heap)中申请一块空间用于存储 new 对应的对象. 这条规则对 String 也适用.

    所以通过 new 关键字创建的字符串对象, 其内存地址对应堆中的某一个内存空间, 而它的值也被存在改内存空间而不是常量区. 即使该值在常量区中存在.


    所以总的来说,如果不是有特定目的不建议使用 new 关键字创建字符串对象, 如果需要频繁的对字符串对象进行修改可以使用 StringBuffer(线程安全) 或者 StringBuilder(非线程安全但是更高效)

    上述PDF文档+github链接:
    关于我
    嘿嘿.gif

    展开全文
  • 我用的虚拟机与主机网络连接有点问题,虚拟机上不了Google,所以下载还是龟速20k 3.移动网络开热点 真正解决问题的方法!我用手机开热点,联通网络有200,300k的速度,换了移动网络开热点直接到了几M/s的速度,这个...

    最近在虚拟机上的Ubuntu16.04下载GitHub上的包,速度只有20k左右,并且时间长长了还会因为网络连接超时问题下载不成功,我总共试验了3种方法。
    1.配置域名ip地址(无效)
    2.连接外网vpn
    我用的虚拟机与主机网络连接有点问题,虚拟机上不了Google,所以下载还是龟速20k
    3.移动网络开热点
    真正解决问题的方法!我用手机开热点,联通网络有200,300k的速度,换了移动网络开热点直接到了几M/s的速度,这个哪个速度快应该因地区而异,总之终于快速下载完了GitHub上的一个包

    我看还有其他方法没有一个一个去试,我的方法没有效果的话大家可以去试一试其他方法。

    展开全文
  • 虚拟机的virtwl Wayland代理 状态:原型制作 wayland-proxy-virtwl在VM内运行,为应用程序提供Wayland套接字。 它使用virtwl Linux模块将对主机Wayland合成器的所有请求代理。 有关某些背景,请参见 。 由于无法与...
  • 本文是根据 https://justinmeiners.github.io/lc3-vm 和 ...代码已上传到 Github :https://github.com/chenx6/lc3-vmLC3 架构内存LC3 架构有 2^16 个地址...

    d39a0a48323e3af8fe55294650cb51ed.png

    本文是根据 https://justinmeiners.github.io/lc3-vmhttps://justinmeiners.github.io/lc3-vm/supplies/lc3-isa.pdf ISA 写出 LC3 VM 的实现过程。

    代码已上传到了 Github 上:https://github.com/chenx6/lc3-vm

    LC3 架构

    内存

    LC3 架构有 2^16 个地址,每个地址包含一个 word (2 byte, 16 bit)。是大端序存储。所以用 C 表示如下。

    uint16_t *memory = malloc(UINT16_MAX * sizeof(uint16_t));

    指令

    指令长度为固定 16 bit (不定长的 x86 出来挨打)。12-15 bit 用于表示 opcode,其他部分则是根据 opcode 来发挥其用途。下面是使用枚举类型表示出 LC3 指令的 opcode。

    enum Opcode
    {
        OP_BR = 0, /* branch */
        OP_ADD,    /* add  */
        OP_LD,     /* load */
        OP_ST,     /* store */
        OP_JSR,    /* jump register */
        OP_AND,    /* bitwise and */
        OP_LDR,    /* load register */
        OP_STR,    /* store register */
        OP_RTI,    /* unused */
        OP_NOT,    /* bitwise not */
        OP_LDI,    /* load indirect */
        OP_STI,    /* store indirect */
        OP_JMP,    /* jump/ret */
        OP_RES,    /* reserved (unused) */
        OP_LEA,    /* load effective address */
        OP_TRAP    /* execute trap */
    };

    寄存器

    LC3 有三种寄存器,通用寄存器 (R0-R7),指令计数器 (PC),条件寄存器 (COND)。

    条件寄存器则是存储着三种状态:负数 (N),零 (Z),正 (P)。

    下面是使用枚举类型表示出寄存器的下标,还有条件寄存器的条件。

    枚举类型的最后一个无实际价值,只是用来表示寄存器的数量
    enum Register
    {
        R_R0 = 0, /* General purpose registers */
        R_R1,
        R_R2,
        R_R3,
        R_R4,
        R_R5,
        R_R6, /* User Stack Pointer */
        R_R7,
        R_PC,   /* Program counter */
        R_COND, /* Condition codes */
        R_COUNT /* Counter */
    };
    
    enum Condition
    {
        FL_POS = 1 << 0, /* Positive */
        FL_ZRO = 1 << 1, /* Zero */
        FL_NEG = 1 << 2, /* Negative */
    };

    其他

    LC3 还有中断,内存映射的 IO,优先级等。

    在 LC3 中有个类似 x86 int 的 TRAP,实现输入输出等功能。

    enum Trap
    {
        TRAP_GETC = 0x20,  /* get character from keyboard */
        TRAP_OUT = 0x21,   /* output a character */
        TRAP_PUTS = 0x22,  /* output a word string */
        TRAP_IN = 0x23,    /* input a string */
        TRAP_PUTSP = 0x24, /* output a byte string */
        TRAP_HALT = 0x25   /* halt the program */
    };

    在内存中映射的寄存器,可以通过内存地址进行访问,这里可以访问内存知道当前键盘按下与否,按下的按键,还有输出状态的功能。

    enum Memory
    {
        MR_KBSR = 0xFE00,  /* keyboard status */
        MR_KBDR = 0xFE02,  /* keyboard data */
        MR_DSR = 0xFE04,   /* display status */
        MV_DDR = 0xFE06,   /* display data */
        MCR = 0xFFFE       /* machine control */
    };

    虚拟机实现

    虚拟机基本架构

    原文将读取文件和解析指令耦合在了一起,并且将内存和寄存器都变成了全局变量,那样就不能同时跑多个虚拟机了。所以在我的实现中,将读取文件,和解析指令并执行进行了拆分,将存储内存和寄存器的数组从全局变量变成了动态内存,还从别的项目里偷了测试样例 https://github.com/viking/lc3-vm/,最后写个 CMake 来负责处理编译依赖。

    通过一个结构体表示虚拟机的状态 (内存和寄存器) 会方便管理一些。

    typedef struct _vm_ctx
    {
        uint16_t *memory;
        uint16_t *regs;
    } vm_ctx;
    
    vm_ctx *init_vm(const char *path)
    {
        vm_ctx *curr_vm = malloc(sizeof(vm_ctx));
        curr_vm->memory = read_image(path);
        curr_vm->regs = malloc(sizeof(uint16_t) * R_COUNT);
    }
    
    void destory_vm(vm_ctx *curr_vm)
    {
        free(curr_vm->memory);
        free(curr_vm->regs);
        free(curr_vm);
    }

    整个虚拟机先从参数指向的程序读取程序镜像,然后开始不断运行程序,直到虚拟机解析到相关 Trap 时终止程序运行。

    int main(int argc, char **argv)
    {
        vm_ctx *curr_vm;
        if (argc == 2)
        {
            curr_vm = init_vm(argv[1]);
        }
        else
        {
            fprintf(stderr, "Usage: %s [program]n", argv[0]);
            exit(-1);
        }
    
        int running = 1;
        while (running)
        {
            running = execute_inst(curr_vm);
        }
        destory_vm(curr_vm);
        return 0;
    }

    读取程序

    就是上面代码中出现的 read_image 函数。

    由于程序为大端序,而平时使用的 x86 PC 是小端序,所以在读取时需要将程序转换成小端序以方便后面的解析。

    我们通过 read_image 函数来将程序加载到内存中,并且转换为小端序的操作。

    /* change endianness */
    uint16_t swap16(uint16_t x)
    {
        return (x << 8) | (x >> 8);
    }
    
    uint16_t *read_image(const char *path)
    {
        FILE *file = fopen(path, "rb");
        if (!file)
        {
            printf("[-] Read error!");
            return NULL;
        }
        uint16_t *memory = malloc(sizeof(INT16_MAX * sizeof(uint16_t)));
    
        /* the origin tells us where in memory to place the image */
        uint16_t origin;
        fread(&origin, sizeof(origin), 1, file);
        origin = swap16(origin);
    
        /* we know the maximum file size so we only need one fread */
        uint16_t max_read = UINT16_MAX - origin;
        uint16_t *p = memory + origin;
        size_t read = fread(p, sizeof(uint16_t), max_read, file);
    
        /* swap file content to little endian */
        while (read-- > 0)
        {
            *p = swap16(*p);
            ++p;
        }
        fclose(file);
        return memory;
    }

    执行指令

    执行指令前得解析指令格式,我们可以从前面的链接中拿到 ISA,根据上面的格式来进行解析。

    ADD

    例如 ADD 指令编码如下

    15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
    +--------------------+--------+--------+--------+
    | 0| 0| 0| 1|   DR   |  SR1   | 0| 00  |  SR2   |
    +--------------------------------------+--------+
    | 0| 0| 0| 1|   DR   |  SR1   | 1|    imm5      |
    +--------------------+--------+-----------------+

    汇编格式

    ADD DR, SR1, SR2
    ADD DR, SR1, imm5

    描述

    If bit [5] is 0, the second source operand is obtained from SR2. If bit [5] is 1, the second source operand is obtained by sign-extending the imm5 field to 16 bits. In both cases, the second source operand is added to the contents of SR1 and the result stored in DR. The condition codes are set, based on whether the result is negative, zero, or positive.

    通过上面的资料可以知道 ADD 指令的编码的 12-15 bit 为 ADD 的 opcode 0001,9-11 bit 为目标寄存器 8-6 bit 为源寄存器 1。由指令的 bit [5] 第 5 个 bit 指定操作对象,一种操作对象为立即数,另一种操作对象是寄存器。

    所以根据分析写出如下代码,通过位操作取出目标寄存器和源寄存器的下标,或者取出立即数,通过下标访问不同寄存器进行计算。最后根据运算结果更新条件寄存器。

    switch (op)
    {
    case OP_ADD:
        /* using {} to declare varible in labels */
        {
            uint16_t dr = (instr >> 9) & 0x7;
            uint16_t sr1 = (instr >> 6) & 0x7;
            uint16_t is_imm = (instr >> 5) & 0x1; /* check the op2 is sr2 or imm */
    
            if (is_imm)
            {
                uint16_t imm5 = sign_extend(instr & 0x1F, 5);
                curr_vm->regs[dr] = curr_vm->regs[sr1] + imm5;
            }
            else
            {
                uint16_t sr2 = instr & 0x7;
                curr_vm->regs[dr] = curr_vm->regs[sr1] + curr_vm->regs[sr2];
            }
            update_flags(dr, curr_vm->regs);
        }
        break;
        /* ... */
    }

    取出立即数时需要注意立即数的长度为 5 bit,但是寄存器的长度为 16 bit。例如在长度为 4 bit 内使用补码表示 -1,则 0-4 bit 存储着 1111,直接转换为长度到 16 bit 时则和 31 0000000000001111 相等,造成混乱。这就需要对立即数进行扩展。

    /* convert to 16 bit with sign */
    uint16_t sign_extend(uint16_t num, int bit_count)
    {
        if ((num >> (bit_count - 1)) & 1)
        {
            num |= (0XFFFF << bit_count);
        }
        return num;
    }

    在进行完运算后,要根据结果将条件寄存器进行更新,这就是 update_flags 函数。

    /* using regs[index] to update flags */
    void update_flags(uint16_t index, uint16_t regs[])
    {
        if (regs[index] == 0)
        {
            regs[R_COND] = FL_ZRO;
        }
        else if (regs[index] >> 15)
        {
            regs[R_COND] = FL_NEG;
        }
        else
        {
            regs[R_COND] = FL_POS;
        }
    }

    LD

    同样我们可以解析并执行 LD 语句的 C 语言代码。

    15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
    +--------------------+--------------------------+
    | 0| 0| 1| 0|   DR   |        PCoffset9         |
    +--------------------+--------------------------+

    LD 语句就是从 PC + 相对偏移得到地址后,从地址中取出值并赋予 DR。当然 pc_offset 又是需要进行扩展的。

    case OP_LD:
    {
        uint16_t dr = (instr >> 9) & 0x7;
        uint16_t pc_offset = sign_extend(instr & 0x1ff, 9);
    
        curr_vm->regs[dr] = mem_read(curr_vm->regs[R_PC] + pc_offset, curr_vm->memory);
        update_flags(dr, curr_vm->regs);
    }

    BR

    而 BR 语句则是负责条件跳转,条件则为指令中的 9-11 bit 进行决定。例如指令中 N 位为 1,而且寄存器中的条件寄存器 N 也为 1,则跳转。N, P, Z 这三种条件可以自由组合,只要满足某一个条件就跳转。跳转表示为 PC 指针加上偏移值。

    case OP_BR:
    {
        uint16_t n_flag = (instr >> 11) & 0x1;
        uint16_t z_flag = (instr >> 10) & 0x1;
        uint16_t p_flag = (instr >> 9) & 0x1;
        uint16_t pc_offset = sign_extend(instr & 0x1FF, 9);
    
        if ((n_flag && (curr_vm->regs[R_COND] & FL_NEG)) ||
            (z_flag && (curr_vm->regs[R_COND] & FL_ZRO)) ||
            (p_flag && (curr_vm->regs[R_COND] & FL_POS)))
        {
    
            curr_vm->regs[R_PC] += pc_offset;
        }
    }

    mem_read 函数

    由于有内存映射的寄存器的存在,所以要将访问某些特殊地址时实际上是想访问某些寄存器,所以在读写特殊内存地址时要进行魔改。例如在访问 MR_KBSR 地址时候就需要将按键状态返回。

    uint16_t mem_read(uint16_t address, uint16_t *memory)
    {
        /* reading the memory mapped keyboard register triggers a key check */
        if (address == MR_KBSR)
        {
            if (check_key())
            {
                memory[MR_KBSR] = (1 << 15);
                memory[MR_KBDR] = getchar();
            }
            else
            {
                memory[MR_KBSR] = 0;
            }
        }
        return memory[address];
    }

    check_key 函数用于将按键状态返回给程序。首先将 STDIN 绑定到集合中,然后通过 select 函数监视文件描述符的状态,如果有按键输入,则返回 1,否则返回 0;

    /* get keyboard status */
    uint16_t check_key()
    {
        fd_set readfds;
        FD_ZERO(&readfds);
        FD_SET(STDIN_FILENO, &readfds);
    
        struct timeval timeout;
        timeout.tv_sec = 0;
        timeout.tv_usec = 0;
        return select(1, &readfds, NULL, NULL, &timeout) != 0;
    }

    TRAP

    在处理中断时使用函数来进行处理,降低代码耦合度。

    case OP_TRAP:
    {
        running = execute_trap(curr_vm, instr, stdin, stdout);
    }
    break;

    Trap 翻译

    将不同中断用 C 语言表示就行。由 ISA 可以知道 Trap 向量由 0-7 bit 表示。上面已经提及过了 Trap 的路径和功能,所以相关功能使用 C 语言表示如下。

    switch (instr & 0xFF)
    {
    case TRAP_GETC:
    {
        uint16_t c = getc(in);
        curr_vm->regs[R_R0] = c;
    }
    break;
    /* ... */
    }
    break;

    虚拟机测试

    通过位运算构造相应的指令,然后运行此指令,看看预期和结果是否相符。如果不相符就是挂了,返回 0;如果通过了那就返回 1。

    int test_add_1(vm_ctx *curr_vm)
    {
        int pass = 1;
        uint16_t add_instr =
            ((OP_ADD & 0xf) << 12) |
            ((R_R0 & 0x7) << 9) |
            ((R_R1 & 0x7) << 6) |
            (R_R2 & 0x7);
    
        curr_vm->memory[0x3000] = add_instr;
        curr_vm->regs[R_R1] = 1;
        curr_vm->regs[R_R2] = 2;
    
        int result = execute_inst(curr_vm);
        if (result != 1)
        {
            printf("Expected return value to be 1, got %dn", result);
            pass = 0;
        }
    
        if (curr_vm->regs[R_R0] != 3)
        {
            printf("Expected register 0 to contain 3, got %dn", curr_vm->regs[R_R0]);
            pass = 0;
        }
    
        if (curr_vm->regs[R_COND] != FL_POS)
        {
            printf("Expected condition flags to be %d, got %dn", FL_POS, curr_vm->regs[R_COND]);
            pass = 0;
        }
    
        return pass;
    }

    通过将不同测试函数用指针数组装起来,不断调用,通过返回值判断测试样例是否通过。

    int test_env()
    {
        vm_ctx curr_vm;
        curr_vm.regs = malloc(sizeof(uint16_t) * R_COUNT);
        curr_vm.memory = malloc(UINT16_MAX * sizeof(uint16_t));
        int (*test_case[])(vm_ctx * curr_vm) = {test_add_1, test_add_2};
    
        int result = 1;
        int case_num = sizeof(test_case) / sizeof(uint16_t *);
        for (int i = 0; i < case_num; i++)
        {
            curr_vm.regs[R_PC] = 0x3000;
            memset(curr_vm.memory, 0, UINT16_MAX);
            memset(curr_vm.regs, 0, R_COUNT);
            result = test_case[i](&curr_vm);
            if (result == 0)
            {
                printf("Test %d fail!n", i);
                free(curr_vm.memory);
                free(curr_vm.regs);
                return result;
            }
    
            else if (result == 1)
            {
                printf("Test %d passed!n", i);
            }
        }
        free(curr_vm.memory);
        free(curr_vm.regs);
        return result;
    }

    原文中还有编译好的 2048 和 rouge,可以试着跑一下。

    编译

    使用 CMake 进行依赖处理,将测试程序和源程序分开,并且使用 make test 就可以跑测试了。

    if( POLICY CMP0048 )
      cmake_policy( SET CMP0048 NEW ) # CMake 3.0
    endif()
    
    project( lc3-vm VERSION 0.1 )
    cmake_minimum_required( VERSION 2.6 )
    set( CMAKE_C_STANDARD 99 )
    add_library( read_image OBJECT lc3.h read_image.c )
    add_library( exec_inst OBJECT lc3.h exec_inst.c )
    add_executable( ${PROJECT_NAME} $<TARGET_OBJECTS:read_image> $<TARGET_OBJECTS:exec_inst> main.c )
    
    add_executable( ${PROJECT_NAME}-test $<TARGET_OBJECTS:read_image> $<TARGET_OBJECTS:exec_inst> test.c )
    enable_testing()
    add_test(NAME ${PROJECT_NAME}-test COMMAND ./${PROJECT_NAME}-test )
    SET_TESTS_PROPERTIES( ${PROJECT_NAME}-test PROPERTIES
      PASS_REGULAR_EXPRESSION "All test passed!"
      FAIL_REGULAR_EXPRESSION "Test [d]+ fail!"
    )

    refs

    原文 https://justinmeiners.github.io/lc3-vm 这个 C 实现的虚拟机封装比较完整 https://github.com/rpendleton/lc3sim-c 这个实现里加了测试样例 https://github.com/viking/lc3-vm

    展开全文
  • 自制Java虚拟机-总结

    千次阅读 2017-06-24 12:05:13
    自制Java虚拟机-总结项目介绍该项目的目的是从零开始用C语言做一个实验性质的Java虚拟机,实现大部分JVM指令,实现基本的面向对象特性(封装、继承、多态),能够运行一个...经过整理之后,代码托管到了github上

    自制Java虚拟机-总结

    项目介绍

    该项目的目的是从零开始用C语言做一个实验性质的Java虚拟机,实现大部分JVM指令,实现基本的面向对象特性(封装、继承、多态),能够运行一个不涉及Java本地方法调用的类(不能包含未实现的指令,见下面的指令实现情况),因为涉及到Java的本地方法(native method)还是比较麻烦的,暂时没有那么多时间精力去研究。
    经过整理之后,代码托管到了github上。
    项目地址: https://github.com/springlchy/myjvm
    欢迎大家一起交流!!

    项目文件介绍

    • main.c 这是整个项目的入口文件。主要是加载需要运行的类,然后运行该类的main方法
    • jvm.c 实现虚拟机的基本框架(如指令执行循环、方法调用)。一些复杂的指令实现(invokespecial,invokevirtual,invokestatic)也在这里
    • parse_class.c 实现了把字节码文件解析成Class结构体,以及递归加载类
    • structs.h Class结构体中的各个数据类型的结构定义(如常量池中的各种结构、method_info、field_info)
    • constants.h 定义了一些常量,主要是访问控制标志、常量池种类
    • my_types.h 对C中的基本数据类型重新定义了个名字
    • utils.h 对读取文件做了个简单的封装(如读取一个字节(多个字节),读取一个short,读取一个int
    • op_core.h 该文件抽象地实现了JVM中的各种指令,简单的指令以宏的方式实现,复杂的以函数的方式。该文件很重要!
    • opcode.h 实现了指令中用到的一些方法,之所以不与op_core放在一起,是因为op_core过于庞大
    • opcode.c 主要是一个结构体数组,存放JVM指令的预处理函数及实现函数,数组的下标就是指令的opcode的十进制值
    • opcode_pre.c 方法区代码段的预处理函数集,主要是大小端转换
    • opcode_actions.c 该文件用include把opcode_actions目录中的文件包含进来,是指令实现的函数,每遇到一个指令,就调用相应的函数执行。
    • class_hash.h 简单地实现了一个HashTable结构类型和hash算法,用于保存已经加载并解析的字节码文件,rehash方法没有实现
    • test_jvm_types.c 一些测试用例,为了方便在不加载字节码文件的情况下测试代码而写

    • 其它:
      test目录下的.java文件是测试文件。

    指令实现情况

    • constant系列指令(加载常量到当前操作数栈上),除ldc, ldc_w,ldc2_w这三条指令只实现了部分之外(字符串和对象部分没实现),其余均以实现
    • load系列指令(从局部变量表中加载数据到当前操作数栈上),全部实现
    • store系列指令(把当前操作数栈栈顶的数据保存到局部变量表),全部实现
    • stack系列指令(操作操作数栈的),全部实现
    • math系列指令(数学运算),全部实现
    • conversion(cast)系列指令(类型转换),全部实现
    • compare系列指令(比较跳转),全部实现
    • reference系列指令(主要是关于面向对象相关的指令),除athrow,checkcast,instanceof,monitorenter,monitorexit,invokedynamic,invokeinterface没有实现外,其余均已实现
    • control系列指令(控制转移指令),全部实现
    • extend系列指令,实现了multianewarray,ifnull,ifnotnull,goto_w指令
    • 保留指令,未实现

    后话

    该项目是用业余时间做的,在QT5.0下开发,原先只是想做个解析Java字节码的程序,后来灵感一来就越写越多。

    由于时间精力有限,没有去好好组织项目结构,代码风格不是很好,请不要学习。

    该项目对于学习C语言和想了解Java虚拟节的人来说还是都有很大帮助的。指令的实现中大量用到了宏,把运算符、变量类型作为参数传给宏,通过宏来定义类似的函数,省了很多代码。还有各种指针转换、函数指针的运用等,创建带有指向数组指针的结构体时,特意分配比结构体大的内存,然后让结构体中的成员指向剩余的内存,避免再次调用malloc,也减少了内存碎片。

    对于想了解JVM的人而言,虽然商用JVM的类加载、指令的实现不一定是这样的,但至少可以从中大概知道JVM内部是什么个情况,加深对JVM的了解。

    展开全文
  • Android虚拟机多开检测

    千次阅读 2017-09-14 23:40:30
    0. 背景目前市面越来越多通过虚拟化多开的应用或者开源项目,包括 平行空间 VirtualApp 双开助手 DualSpace Go双开 双开精灵 其中VirtualApp是一个个人开源的,直接点击可以跳转到GitHub页面。这些虚拟化方案都...
  • 显示的提交者(commit的人)却是另外一个账户名,起因可能是直接使用别人的虚拟机,所以某些地方的账户暂时没有修改过来,(虽然已经建立ssh_key公钥,并且能从自己的github账户克隆项目到本地,但是提交的...
  • 一直以来用Git都是用的别人的服务器, 比如oschina 和github, 今天因为工作需要在自己的ubuntu搭建自己Git 服务器, 以为很简单, 但是过程却那么顺利.   1) 首先需要在ubuntu 安装openssh,  命令: sudo ...
  • 在发布4个月的时间里,下载量就超过50000次,github上收到超过4000个star,涌现超过100个贡献者,并且有超过150个项目和超过1000个产品开始使用docker。 最有意思的事情是,在docker本身还没有稳定之前,就...
  • 前言 小米pro的Hackintosh方案挺香的,用也有8个月,还是挺稳定的。... Wi-Fi解决方案也比较完美,使用Comfast的CF-811AC可支持5G网络,搭配GitHub上的驱动使用,效果极佳。 蓝牙,当时随便在淘宝买...
  • 这段时间做项目,涉及到虚拟机 Mac 地址生成,网上找一些 Java 随机生成 Mac 地址的代码,大多都是从 {‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘a’, ‘b’, ‘c’, ‘e’, ‘d...
  • emm之前百度也没找到合适的方法,找半天才找到一个github上的idea插件……然而万年没有更新,貌似能用,所以干脆节省时间也没有试过。。有兴趣的小伙伴可以去试一试吧 最后直接在idea中的插件marketplace搜索...
  • 之前的博客是用wordpress搭建在阿里云的一台虚拟机上,由于出个意外,造成我在上面写的文章全部丢失,虽然多,但是也都是心血。吸取教训我打算换种方式搭建博客,分析目前比较流行的博客框架ghost、Jekyll、...
  • 这个Hugo Setup Action可以将安装到GitHub Actions的虚拟机上。 支持Hugo扩展版本, Hugo Modules ,Linux(Ubuntu),macOS和Windows。 从v2 ,此Hugo设置操作已迁移到JavaScript(TypeScript)操作。 我们不再...
  • 如果您是Python / Django的新手,建议您使用Vagrant在虚拟机上运行此项目,这有助于解决常见的软件依赖关系问题。 但是,对于更有经验的开发人员,请按照以下说明在没有Vagrant的情况下启动该项目。 一旦您熟悉...
  • 虚拟机安装及使用Linux,看这一篇就够! 推荐一个项目管理工具,落地基于Scrum的敏捷开发! IDEA中创建和启动SpringBoot应用的正确姿势 盘点下我用的顺手的那些工具! 我用起来顺手的数据库设计工具,这次推荐给...
  • 无论是在学习,测试,迁移时候无疑是最快的方式,尤其是在多个环境下还想使用同一套环境时候,https://github.com/hulichao/docker-bigdata,搭建思路,可以参考本仓库,一般情况下只要注意比虚拟机要多做个端口映射等...
  • 笔记、源码同步在github上,欢迎Star,蟹蟹~ 前一天我们借助Java语言设计一种专用的虚拟机,用于执行中间代码。从内部来看,该虚拟机通过Java语言的Object类型来表示所有类型的值,整数也将由Integer对象表现。...
  • 170627 逆向-GeekerDoll

    2017-06-28 03:29:55
    之前试了很多方法,IDA中找不到源码,因为是64位的所以OD也跟不了,拖到linux虚拟机中用IDA单步跟,被计时器的消息给报异常中断了,无论怎么走都过不去…… 最后换了writeup看,发现了之前提到过但是没给连接的...
  • 这个问题是我按了com + shift + K 调出Simulatior 的时候出现的, 然后虚拟机就刷新不了了, 怎么按com+r都不好使. 在Simulatior的菜单栏选择Hardware --> Keyboard --> Connect Hardware Keyboard 选就好了 ...
  • 虽然GitHub已经很好,但是我们必须联公网才可以使用并且如果付费的话,你的代码在网上就是公开的!但是在企业环境中,我们公司的代码希望被公开并且也想付费给GitHub,这时怎么办呢?我们可以用GitLab搭建...
  • 这个问题是我按了com + shift + K 调出Simulatior 的时候出现的, 然后虚拟机就刷新不了了, 怎么按com+r都不好使. 在Simulatior的菜单栏选择Hardware --> Keyboard --> Connect Hardware Keyboard 选就好了 ...
  • 最近接触下GlusterFS,所以就想着在自己的笔记本虚拟机里安装个测试环境。起初想要从https://github.com/gluster/glusterfs/下载一个build然后编译安装, 但是试很多次,在make时总是失败,折腾两天后,...
  • 自从用WSL,对于在本机搭建各类服务进行开发调试的事情,就想再劳烦虚拟机或者容器。 Debian 9 WSL安装好ArangoDB 3 for Debian 9后,因WSL支持systemd,加之此版次的ArangoDB只提供systemd服务,故能以...
  • 还记得劳资刚刚开始学chisel的时候,跟着github上的Bootcamp学习一大堆chisel语法(然而知道这些语法怎么用2333) 彼时彼刻,困扰老子的问题莫过于怎么在自己电脑的ubuntu(其实是虚拟机辣)把那些chisel代码...

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 231
精华内容 92
关键字:

虚拟机上不了github