├── logo └── jetbrains.png ├── .editorconfig ├── include ├── shared │ ├── arch │ │ ├── x86_64 │ │ │ └── atomic.h │ │ ├── arm │ │ │ └── atomic.h │ │ └── x86 │ │ │ └── atomic.h │ ├── zip.h │ ├── os │ │ ├── common │ │ │ └── dl.h │ │ ├── windows │ │ │ ├── osInfo.h │ │ │ └── dl.h │ │ ├── unix │ │ │ ├── osInfo.h │ │ │ └── dl.h │ │ └── macos │ │ │ └── osInfo.h │ ├── lock.h │ ├── atomic.h │ ├── dl.h │ ├── hashMap.h │ ├── osInfo.h │ ├── filesystem.h │ ├── string.h │ ├── mmap.h │ ├── monitor.h │ └── types.h ├── kivm │ ├── asm │ │ ├── address.h │ │ └── register.h │ ├── runtime │ │ ├── threadState.h │ │ ├── vmThread.h │ │ ├── slot.h │ │ ├── runtimeConfig.h │ │ ├── abstractThread.h │ │ ├── frameWalker.h │ │ └── frame.h │ ├── bytecode2 │ │ ├── interpreterMacroAssembler.h │ │ └── template.h │ ├── jni │ │ ├── jni_md.h │ │ ├── jniJavaVM.h │ │ ├── nativeLibrariy.h │ │ └── nativeMethod.h │ ├── oop │ │ ├── mirrorKlass.h │ │ ├── mirrorOop.h │ │ ├── oopfwd.h │ │ ├── arrayOop.h │ │ ├── oop.h │ │ ├── primitiveOop.h │ │ ├── arrayKlass.h │ │ ├── field.h │ │ └── klass.h │ ├── bytecode │ │ ├── interpreter.h │ │ ├── bytecodeInterpreter.h │ │ ├── codeBlob.h │ │ ├── threadedInterpreter.h │ │ └── javaCall.h │ ├── native │ │ ├── java_lang_reflect_Method.h │ │ ├── java_lang_reflect_Constructor.h │ │ ├── java_lang_Thread.h │ │ ├── classNames.h │ │ ├── java_lang_Class.h │ │ └── java_lang_String.h │ ├── memory │ │ ├── collectedHeap.h │ │ ├── universe.h │ │ ├── heapRegion.h │ │ ├── gcThread.h │ │ └── copyingHeap.h │ ├── classpath │ │ ├── system.h │ │ ├── classPathManager.h │ │ └── classLoader.h │ ├── classfile │ │ ├── classFileParser.h │ │ └── annotation.h │ └── cfg │ │ └── edge.h └── sparsepp │ ├── spp_stdint.h │ ├── spp_timer.h │ └── spp_smartptr.h ├── java-src ├── com │ └── imkiva │ │ └── kivm │ │ ├── AssertTest.java │ │ ├── ArithmeticTest.java │ │ ├── HelloWorld.java │ │ ├── ChineseTest.java │ │ ├── ExceptionTest1.java │ │ ├── GCTest.java │ │ ├── ArgumentTest.java │ │ ├── Main.java │ │ ├── LambdaTest.java │ │ ├── ArrayTest.java │ │ ├── ClassCastTest.java │ │ ├── FileTest.java │ │ ├── StringBuilderTest1.java │ │ ├── ListTest.java │ │ ├── ArrayTest1.java │ │ ├── PackagePrivateTest.java │ │ ├── CovScriptJNITest.java │ │ ├── ArrayTest2.java │ │ ├── ClassNameTest.java │ │ ├── ThreadExceptionTest.java │ │ ├── StaticFieldTest.java │ │ ├── HashTest.java │ │ ├── LookupSwitchTest.java │ │ ├── StaticResolution.java │ │ ├── Polymorphism.java │ │ ├── ExceptionTest.java │ │ ├── ExceptionTest2.java │ │ ├── ExceptionTest3.java │ │ ├── TableSwitchTest.java │ │ └── ThreadTest.java └── Makefile ├── src ├── kivm │ ├── oop │ │ ├── klass.cpp │ │ ├── mirrorOop.cpp │ │ ├── oop.cpp │ │ ├── primitiveOop.cpp │ │ ├── instanceOop.cpp │ │ ├── mirrorKlass.cpp │ │ ├── oopBase.cpp │ │ └── arrayOop.cpp │ ├── bytecode2 │ │ ├── interpreterMacroAssembler.cpp │ │ ├── templateTable.cpp │ │ └── template.cpp │ ├── native │ │ ├── sun_misc_VM.cpp │ │ ├── java_io_UnixFileSystem.cpp │ │ ├── java_io_FileInputStream.cpp │ │ ├── sun_misc_URLClassPath.cpp │ │ ├── java_lang_Runtime.cpp │ │ ├── java_util_concurrent_atomic_AtomicLong.cpp │ │ ├── java_lang_Float.cpp │ │ ├── java_io_FileDescriptor.cpp │ │ ├── java_lang_Double.cpp │ │ ├── java_lang_ClassLoader.cpp │ │ ├── java_lang_reflect_Method.cpp │ │ ├── java_lang_reflect_Constructor.cpp │ │ ├── sun_nio_cs_StreamEncoder.cpp │ │ ├── sun_reflect_NativeConstructorAccessorImpl.cpp │ │ ├── java_security_AccessController.cpp │ │ ├── java_lang_reflect_Array.cpp │ │ ├── sun_reflect_Reflection.cpp │ │ ├── java_lang_Thread.cpp │ │ ├── java_lang_Object.cpp │ │ ├── java_io_FileOutputStream.cpp │ │ └── sun_reflect_NativeMethodAccessorImpl.cpp │ ├── runtime │ │ ├── frame.cpp │ │ ├── runtimeConfig.cpp │ │ ├── stack.cpp │ │ └── abstractThread.cpp │ ├── classpath │ │ ├── system.cpp │ │ ├── classLoader.cpp │ │ └── baseClassLoader.cpp │ ├── jni │ │ ├── jniJavaVM.cpp │ │ ├── jniGlobal.cpp │ │ ├── nativeLibrary.cpp │ │ └── nativeMethod.cpp │ ├── bytecode │ │ ├── virtualMethodResolver.cpp │ │ ├── dynamicCall.cpp │ │ ├── bytecodeInterpreter.cpp │ │ ├── resolver.cpp │ │ └── javaMethodCall.cpp │ ├── classfile │ │ ├── annotation.cpp │ │ ├── classFile.cpp │ │ └── constantPool.cpp │ └── memory │ │ ├── universe.cpp │ │ └── copyingHeap.cpp ├── shared │ ├── os │ │ ├── windows │ │ │ ├── osInfo.cpp │ │ │ ├── mmap.cpp │ │ │ └── dl.cpp │ │ ├── unix │ │ │ ├── osInfo.cpp │ │ │ └── dl.cpp │ │ └── macos │ │ │ └── osInfo.cpp │ └── filesystem.cpp └── bin │ └── java.cpp ├── cmake ├── check-threaded.cpp ├── cmake-config.h.in ├── FindFFI.cmake └── FindZIP.cmake ├── tests ├── test-args-parser.cpp ├── test-stack-and-locals.cpp ├── test-oop-size.cpp ├── main.csc ├── bench-allocation.cpp ├── test-encode-decode-offset.cpp ├── bench-map.cpp └── test-native-image.cpp ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md └── ext └── extension-helper.h /logo/jetbrains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imkiva/KiVM/HEAD/logo/jetbrains.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset=utf-8 3 | end_of_line=lf 4 | insert_final_newline=true 5 | indent_style=space 6 | tab_width=4 7 | -------------------------------------------------------------------------------- /include/shared/arch/x86_64/atomic.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/13. 3 | // 4 | #pragma once 5 | 6 | #include 7 | -------------------------------------------------------------------------------- /include/kivm/asm/address.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-06-28. 3 | // 4 | #pragma once 5 | 6 | namespace kivm { 7 | using Address = void *; 8 | } 9 | -------------------------------------------------------------------------------- /include/kivm/asm/register.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-06-28. 3 | // 4 | #pragma once 5 | 6 | namespace kivm { 7 | using Register = unsigned long; 8 | } 9 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/AssertTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class AssertTest { 4 | public static void main(String[] args) { 5 | assert 1 + 1 == 2; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /include/kivm/runtime/threadState.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/4. 3 | // 4 | #pragma once 5 | 6 | namespace kivm { 7 | enum ThreadState { 8 | RUNNING, BLOCKED, DIED 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ArithmeticTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ArithmeticTest { 4 | public static void main(String[] args) { 5 | System.out.println(1 / 0); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/HelloWorld.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class HelloWorld { 4 | public static void main(String[] args) { 5 | System.out.println("hello world"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ChineseTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ChineseTest { 4 | public static void main(String[] args) { 5 | System.out.println("你好世界!我爱 KiVM"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/kivm/oop/klass.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/27. 3 | // 4 | 5 | #include 6 | 7 | namespace kivm { 8 | Klass::Klass() { 9 | setClassState(ClassState::ALLOCATED); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /include/kivm/bytecode2/interpreterMacroAssembler.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-06-28. 3 | // 4 | #pragma once 5 | 6 | namespace kivm { 7 | class InterpreterMacroAssembler { 8 | public: 9 | void flush(); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ExceptionTest1.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ExceptionTest1 { 4 | public static void main(String[] args) throws ClassNotFoundException { 5 | Class.forName("a.non.existing.Class"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /include/shared/zip.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/21. 3 | // 4 | #pragma once 5 | 6 | #ifdef KIVM_JAR_CLASS_LOADING 7 | 8 | #include 9 | 10 | namespace kivm { 11 | using namespace libzippp; 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/kivm/runtime/vmThread.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/4. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace kivm { 10 | class VMThread : public AbstractThread { 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /include/shared/os/common/dl.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/15. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | namespace dl { 10 | using DLHandler = void *; 11 | using DLSymbol = void *; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/GCTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class GCTest { 4 | public static void main(String[] args) { 5 | for (int i = 0; i < 2; ++i) { 6 | byte[] b = new byte[1024 * 1024]; 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/kivm/bytecode2/interpreterMacroAssembler.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-06-28. 3 | // 4 | 5 | #include 6 | 7 | namespace kivm { 8 | void InterpreterMacroAssembler::flush() { 9 | // TODO 10 | } 11 | } -------------------------------------------------------------------------------- /java-src/Makefile: -------------------------------------------------------------------------------- 1 | JAVAC := javac 2 | 3 | DIR := $(shell pwd) 4 | SRC := $(wildcard com/imkiva/kivm/*.java) 5 | OBJ := $(SRC:.java=.class) 6 | 7 | all: $(OBJ) 8 | @echo " Done" 9 | 10 | %.class: %.java 11 | @echo "[Compiling] $<" 12 | @$(JAVAC) -d ../java-out -encoding utf-8 $< 13 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ArgumentTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ArgumentTest { 4 | public static void main(String[] args) { 5 | for (int i = 0; i < args.length; ++i) { 6 | System.out.println(args[i]); 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/Main.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | System.out.println("hello world, hello KiVM."); 6 | System.out.println("kivm.info: " + System.getProperty("kivm.info")); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/LambdaTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class LambdaTest { 4 | public static void f(Runnable r) { 5 | r.run(); 6 | } 7 | 8 | public static void main(String... args) { 9 | f(() -> System.out.println("Hello Lambda")); 10 | } 11 | } -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ArrayTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ArrayTest { 4 | public static void main(String[] args) { 5 | int[] a = new int[10]; 6 | for (int i = 0; i < a.length; ++i) { 7 | System.out.println(a[i]); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/kivm/native/sun_misc_VM.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/24. 3 | // 4 | 5 | #include 6 | 7 | using namespace kivm; 8 | 9 | JAVA_NATIVE void Java_sun_misc_VM_initialize(JNIEnv *env, jclass sun_misc_VM) { 10 | D("native: sun/misc/VM.initialize(): JVM initialized"); 11 | } 12 | -------------------------------------------------------------------------------- /cmake/check-threaded.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/3. 3 | // 4 | 5 | /** 6 | * Check whether compiler supports label address 7 | * @return 1 when supports, 0 when not 8 | */ 9 | int main() { 10 | void *p = &&label; 11 | goto *p; 12 | 13 | return 0; 14 | 15 | label: 16 | return 1; 17 | } 18 | -------------------------------------------------------------------------------- /include/kivm/runtime/slot.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/21. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | struct Slot final { 10 | bool isObject; 11 | union { 12 | jint i32; 13 | jobject ref; 14 | }; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ClassCastTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ClassCastTest { 4 | public static void main(String[] args) { 5 | Object x = null; 6 | String s = (String) x; 7 | 8 | Object z = new ClassCastTest(); 9 | String y = (String) z; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/FileTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | import java.io.*; 4 | 5 | public class FileTest { 6 | public static void main(String[] args) { 7 | File f = new File("."); 8 | for (String x : f.list()) { 9 | System.out.println(x); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/kivm/native/java_io_UnixFileSystem.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/26. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace kivm; 9 | 10 | JAVA_NATIVE void Java_java_io_UnixFileSystem_initIDs(JNIEnv *env, jclass java_io_FileInputStream) { 11 | D("java/io/UnixFileSystem.initIDs()V"); 12 | } 13 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/StringBuilderTest1.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class StringBuilderTest1 { 4 | public static void main(String[] args) { 5 | StringBuilder sb = new StringBuilder(); 6 | String s = new String("world"); 7 | sb.append("hello, " + s); 8 | System.out.println(sb.toString()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/kivm/native/java_io_FileInputStream.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/28. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace kivm; 9 | 10 | JAVA_NATIVE void Java_java_io_FileInputStream_initIDs(JNIEnv *env, jclass java_io_FileInputStream) { 11 | D("java/io/FileInputStream.initIDs()V"); 12 | } 13 | -------------------------------------------------------------------------------- /src/kivm/native/sun_misc_URLClassPath.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-02-09. 3 | // 4 | 5 | #include 6 | 7 | using namespace kivm; 8 | 9 | JAVA_NATIVE jarray Java_sun_misc_URLClassPath_getLookupCacheURLs(JNIEnv *env, jclass unused, jobject cl) { 10 | D("native: sun/misc/URLClassPath.getLookupCacheURLs()"); 11 | return nullptr; 12 | } 13 | -------------------------------------------------------------------------------- /src/kivm/native/java_lang_Runtime.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/10. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace kivm; 10 | 11 | JAVA_NATIVE jint Java_java_lang_Runtime_availableProcessors(JNIEnv *env, jclass unused) { 12 | return OSInformation::getCpuNumbers(); 13 | } 14 | -------------------------------------------------------------------------------- /include/kivm/jni/jni_md.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/15. 3 | // 4 | #pragma once 5 | 6 | #define JNIEXPORT __attribute__((visibility("default"))) 7 | #define JNIIMPORT 8 | #define JNICALL 9 | 10 | #if defined(__LP64__) && __LP64__ /* for -Wundef */ 11 | typedef int jint; 12 | #else 13 | typedef long jint; 14 | #endif 15 | typedef long long jlong; 16 | typedef signed char jbyte; 17 | 18 | -------------------------------------------------------------------------------- /src/kivm/runtime/frame.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/23. 3 | // 4 | #include 5 | 6 | namespace kivm { 7 | Frame::Frame(int maxLocals, int maxStacks) 8 | : _locals(maxLocals), _stack(maxStacks) { 9 | } 10 | 11 | FrameList::FrameList(int maxFrames) 12 | : _max_frames(maxFrames), _size(0), _current(nullptr) { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/kivm/native/java_util_concurrent_atomic_AtomicLong.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/26. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | JAVA_NATIVE jboolean Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8(JNIEnv *env, jclass unused) { 9 | #ifdef KIVM_SUPPORT_CS8 10 | return JNI_TRUE; 11 | #else 12 | return JNI_FALSE; 13 | #endif 14 | } 15 | -------------------------------------------------------------------------------- /include/shared/lock.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // Modified by mikecovlee on 2018/2/25. 4 | // 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | namespace kivm { 11 | using Lock = std::mutex; 12 | using RecursiveLock = std::recursive_mutex; 13 | 14 | using LockGuard = std::lock_guard; 15 | using RecursiveLockGuard = std::lock_guard; 16 | } 17 | -------------------------------------------------------------------------------- /include/shared/atomic.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/13. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | #if KIVM_ARCH_arm 9 | #include 10 | #elif KIVM_ARCH_aarch64 11 | #include 12 | #elif KIVM_ARCH_x86 13 | #include 14 | #elif KIVM_ARCH_x86_64 15 | #include 16 | #endif 17 | -------------------------------------------------------------------------------- /src/kivm/native/java_lang_Float.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/24. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace kivm; 9 | 10 | JAVA_NATIVE jint Java_java_lang_Float_floatToRawIntBits(JNIEnv *env, jclass java_lang_Float, jfloat f) { 11 | union { 12 | jint i; 13 | jfloat f; 14 | } u{}; 15 | u.f = f; 16 | return u.i; 17 | } 18 | -------------------------------------------------------------------------------- /include/shared/os/windows/osInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/10. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #ifdef KIVM_PLATFORM_WINDOWS 10 | namespace kivm { 11 | class WindowsInformation final { 12 | public: 13 | static String getOSName(); 14 | 15 | static String getOSVersion(); 16 | 17 | static int getCpuNumbers(); 18 | }; 19 | } 20 | #endif 21 | -------------------------------------------------------------------------------- /include/kivm/runtime/runtimeConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/25. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | struct RuntimeConfig final { 10 | int threadMaxStackFrames; 11 | size_t initialHeapSizeInBytes; 12 | size_t maxHeapSizeInBytes; 13 | 14 | static RuntimeConfig &get(); 15 | 16 | RuntimeConfig(); 17 | }; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/kivm/oop/mirrorOop.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | 5 | #include 6 | 7 | namespace kivm { 8 | 9 | mirrorOopDesc::mirrorOopDesc(Klass *mirror) 10 | : instanceOopDesc((InstanceKlass *) BootstrapClassLoader::get()->loadClass(L"java/lang/Class")), 11 | _mirrorTarget(mirror), 12 | _mirroringPrimitiveType(ValueType::OBJECT) { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ListTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | import java.util.*; 4 | 5 | public class ListTest { 6 | public static void main(String[] args) { 7 | List l = new ArrayList<>(); 8 | l.add("hhaa"); 9 | String[] aa = new String[5]; 10 | l.toArray(aa); 11 | for (int i = 0; i < aa.length; i ++) { 12 | System.out.println(aa[i]); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /include/shared/dl.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/15. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | namespace dl { 12 | #if defined(KIVM_PLATFORM_UNIX) || defined(KIVM_PLATFORM_APPLE) 13 | using DLInterface = UnixDLInterface; 14 | #elif KIVM_PLATFORM_WINDOWS 15 | using DLInterface = WindowsDLInterface; 16 | #endif 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /include/sparsepp/spp_stdint.h: -------------------------------------------------------------------------------- 1 | #if !defined(spp_stdint_h_guard) 2 | #define spp_stdint_h_guard 3 | 4 | #include "spp_config.h" 5 | 6 | #if defined(SPP_HAS_CSTDINT) && (__cplusplus >= 201103) 7 | #include 8 | #else 9 | #if defined(__FreeBSD__) || defined(__IBMCPP__) || defined(_AIX) 10 | #include 11 | #else 12 | #include 13 | #endif 14 | #endif 15 | 16 | #endif // spp_stdint_h_guard 17 | -------------------------------------------------------------------------------- /include/shared/os/unix/osInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/10. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #if defined(KIVM_PLATFORM_UNIX) 11 | namespace kivm { 12 | class UnixInformation final { 13 | public: 14 | static String getOSName(); 15 | 16 | static String getOSVersion(); 17 | 18 | static int getCpuNumbers(); 19 | }; 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /include/shared/os/macos/osInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/10. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #if defined(KIVM_PLATFORM_APPLE) 11 | namespace kivm { 12 | class MacOSInformation final { 13 | public: 14 | static String getOSName(); 15 | 16 | static String getOSVersion(); 17 | 18 | static int getCpuNumbers(); 19 | }; 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ArrayTest1.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ArrayTest1 { 4 | public static void main(String[] args) { 5 | try { int[] a = new int[-1]; } catch (Throwable ignore) { ignore.printStackTrace(); } 6 | try { int[][] a = new int[3][-10]; } catch (Throwable ignore) { ignore.printStackTrace(); } 7 | try { String[] a = new String[-5]; } catch (Throwable ignore) { ignore.printStackTrace(); } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/PackagePrivateTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class PackagePrivateTest { 4 | static void packagePrivateMethod() { 5 | System.out.println("package private"); 6 | } 7 | 8 | static class Sub extends PackagePrivateTest { 9 | static void f() { 10 | packagePrivateMethod(); 11 | } 12 | } 13 | 14 | public static void main(String[] args) { 15 | Sub.f(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/kivm/oop/oop.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // 4 | 5 | #include 6 | 7 | namespace kivm { 8 | markOopDesc::markOopDesc(oopType type) 9 | : _type(type), _hash(0) { 10 | } 11 | 12 | oopDesc::oopDesc(Klass *klass, oopType type) { 13 | this->_klass = klass; 14 | this->_mark = new markOopDesc(type); 15 | } 16 | 17 | oopDesc::~oopDesc() { 18 | delete this->_mark; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/test-args-parser.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-02-02. 3 | // 4 | 5 | #include 6 | 7 | int main() { 8 | using namespace kivm; 9 | parseArguments(L"([Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodType;)Ljava/lang/Object;"); 10 | parseArguments(L"(BZSCIJFLjava/lang/Object;D)Ljava/lang/Object;"); 11 | parseArguments(L"(BZSCIJFLjava/lang/Object;D)V"); 12 | parseArguments(L"([[[[B[[[Z[[[Ljava/lang/String;)V"); 13 | } 14 | -------------------------------------------------------------------------------- /src/shared/os/windows/osInfo.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/10. 3 | // 4 | #include 5 | 6 | #if defined(KIVM_PLATFORM_WINDOWS) 7 | 8 | namespace kivm { 9 | String WindowsInformation::getOSName() { 10 | return L"Windows"; 11 | } 12 | 13 | String WindowsInformation::getOSVersion() { 14 | return L"unknown"; 15 | } 16 | 17 | int WindowsInformation::getCpuNumbers() { 18 | return 1; 19 | } 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/CovScriptJNITest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class CovScriptJNITest { 4 | public static native void csSayHello(); 5 | 6 | public static native void csSayHello(int magicNumber); 7 | 8 | public static void oldMethod() { 9 | System.out.println("I am too old!"); 10 | } 11 | 12 | public static void main(String[] args) { 13 | csSayHello(); 14 | csSayHello(10086); 15 | oldMethod(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /include/kivm/oop/mirrorKlass.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | class mirrorKlass : public InstanceKlass { 10 | public: 11 | mirrorKlass() = delete; 12 | 13 | mirrorKlass(const mirrorKlass &) = delete; 14 | 15 | mirrorKlass(mirrorKlass &&) noexcept = delete; 16 | 17 | static mirrorOop newMirror(Klass *target, mirrorOop loader); 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ArrayTest2.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ArrayTest2 { 4 | public static void main(String[] args) { 5 | int[] i = new int[100]; 6 | try { 7 | i[100] = 10; 8 | } catch (Throwable e) { 9 | e.printStackTrace(); 10 | } 11 | 12 | try { 13 | System.out.println(i[1000]); 14 | } catch (Throwable e) { 15 | e.printStackTrace(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /include/kivm/jni/jniJavaVM.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/16. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | JNI_ENTRY(jint, DestroyJavaVM(JavaVM * vm)); 9 | 10 | JNI_ENTRY(jint, AttachCurrentThread(JavaVM * vm, void * *penv, void * args)); 11 | 12 | JNI_ENTRY(jint, DetachCurrentThread(JavaVM * vm)); 13 | 14 | JNI_ENTRY(jint, GetEnv(JavaVM * vm, void * *penv, jint version)); 15 | 16 | JNI_ENTRY(jint, AttachCurrentThreadAsDaemon(JavaVM * vm, void * *penv, void * args)); 17 | -------------------------------------------------------------------------------- /include/shared/hashMap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/12. 3 | // 4 | 5 | #pragma once 6 | 7 | #if defined(KIVM_PLATFORM_APPLE) 8 | 9 | #include 10 | 11 | namespace kivm { 12 | template 13 | using HashMap = std::unordered_map; 14 | } 15 | 16 | #else 17 | 18 | #include 19 | 20 | namespace kivm { 21 | template 22 | using HashMap = spp::sparse_hash_map; 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/kivm/runtime/runtimeConfig.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/25. 3 | // 4 | #include 5 | 6 | namespace kivm { 7 | RuntimeConfig &RuntimeConfig::get() { 8 | static RuntimeConfig RUNTIME_CONFIG; 9 | return RUNTIME_CONFIG; 10 | } 11 | 12 | RuntimeConfig::RuntimeConfig() { 13 | threadMaxStackFrames = 1024; 14 | initialHeapSizeInBytes = SIZE_MB(512L); 15 | maxHeapSizeInBytes = SIZE_MB(2048L); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | 31 | # Logs 32 | *.log 33 | 34 | .idea/ 35 | cmake-build-*/ 36 | 37 | .DS_Store 38 | java-out 39 | 40 | CMakeFiles/ 41 | -------------------------------------------------------------------------------- /src/kivm/oop/primitiveOop.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | 5 | #include 6 | 7 | namespace kivm { 8 | intOopDesc::intOopDesc(jint value) : primitiveOopDesc(value) { 9 | } 10 | 11 | longOopDesc::longOopDesc(jlong value) : primitiveOopDesc(value) { 12 | } 13 | 14 | floatOopDesc::floatOopDesc(jfloat value) : primitiveOopDesc(value) { 15 | } 16 | 17 | doubleOopDesc::doubleOopDesc(jdouble value) : primitiveOopDesc(value) { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ClassNameTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ClassNameTest { 4 | public static void main(String[] args) { 5 | System.out.println(String.class.getName()); 6 | System.out.println(byte.class.getName()); 7 | System.out.println((new Object[3]).getClass().getName()); 8 | System.out.println((new int[3][4][5][6][7][8][9]).getClass().getName()); 9 | System.out.println((new String[3][4][5][6][7][8][9]).getClass().getName()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /include/kivm/bytecode/interpreter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/3. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | #if defined(KIVM_THREADED) && !defined(KIVM_DEBUG) 9 | 10 | #include 11 | 12 | namespace kivm { 13 | using DefaultInterpreter = ThreadedInterpreter; 14 | } 15 | 16 | #else 17 | 18 | #include 19 | 20 | namespace kivm { 21 | using DefaultInterpreter = ByteCodeInterpreter; 22 | } 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/kivm/native/java_io_FileDescriptor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/28. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace kivm; 9 | 10 | JAVA_NATIVE void Java_java_io_FileDescriptor_initIDs(JNIEnv *env, jclass java_io_FileDescriptor) { 11 | D("java/io/FileDescriptor.initIDs()V"); 12 | } 13 | 14 | JAVA_NATIVE jlong Java_java_io_FileDescriptor_set(JNIEnv *env, jclass java_io_FileDescriptor, jint fd) { 15 | // TODO: convert fd to file handle for windows 16 | return fd; 17 | } 18 | -------------------------------------------------------------------------------- /include/shared/osInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/10. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | #if defined(KIVM_PLATFORM_APPLE) 12 | using OSInformation = MacOSInformation; 13 | #elif defined(KIVM_PLATFORM_UNIX) 14 | using OSInformation = UnixInformation; 15 | #elif defined(KIVM_PLATFORM_WINDOWS) 16 | using OSInformation = WindowsInformation; 17 | #else 18 | #error Unknow platform 19 | #endif 20 | } 21 | -------------------------------------------------------------------------------- /src/kivm/bytecode2/templateTable.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-06-28. 3 | // 4 | #include 5 | 6 | namespace kivm { 7 | bool TemplateTable::_is_initialized = false; 8 | Template TemplateTable::_templateTable[Bytecodes::number_of_codes]; 9 | Template TemplateTable::_templateTableWide[Bytecodes::number_of_codes]; 10 | Template *TemplateTable::_desc = nullptr; 11 | InterpreterMacroAssembler *TemplateTable::_masm = nullptr; 12 | 13 | 14 | void TemplateTable::initialize() { 15 | // TODO 16 | } 17 | } -------------------------------------------------------------------------------- /include/kivm/native/java_lang_reflect_Method.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/24. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | namespace java { 10 | namespace lang { 11 | namespace reflect { 12 | struct Method { 13 | static void initialize(); 14 | 15 | static InstanceKlass *CLASS; 16 | static FieldID *FIELD_CLAZZ; 17 | static FieldID *FIELD_SLOT; 18 | }; 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/kivm/oop/instanceOop.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace kivm { 10 | 11 | instanceOopDesc::instanceOopDesc(InstanceKlass *klass) 12 | : oopDesc(klass, oopType::INSTANCE_OOP) { 13 | this->_instanceFieldValues.resize(klass->_instanceFields.size()); 14 | for (auto &e : klass->_instanceFields) { 15 | helperInitField(this->_instanceFieldValues, e.second->_offset, e.second->_field); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /include/shared/filesystem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/21. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | namespace kivm { 9 | class FileSystem final { 10 | public: 11 | static bool isDirectory(const String &path); 12 | 13 | static bool canRead(const String &path); 14 | 15 | static size_t getFileSize(const String &path); 16 | 17 | static void *createFileMapping(const String &path, int *pFd, size_t *pSize); 18 | 19 | static void destroyFileMapping(void *memory, int fd, size_t size); 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /tests/test-stack-and-locals.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/23. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace kivm; 9 | 10 | int main() { 11 | Stack s(6); 12 | s.pushInt(1); 13 | s.pushFloat(3.14f); 14 | s.pushDouble(6.28); 15 | s.pushLong(10086); 16 | 17 | jlong j = s.popLong(); 18 | assert(j == 10086L); 19 | jdouble d = s.popDouble(); 20 | assert(d == 6.28); 21 | jfloat f = s.popFloat(); 22 | assert(f == 3.14f); 23 | assert(s.popInt() == 1); 24 | 25 | 26 | return 0; 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /include/kivm/native/java_lang_reflect_Constructor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/24. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | namespace java { 10 | namespace lang { 11 | namespace reflect { 12 | struct Constructor { 13 | static void initialize(); 14 | 15 | static InstanceKlass *CLASS; 16 | static FieldID *FIELD_CLAZZ; 17 | static FieldID *FIELD_SLOT; 18 | }; 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ThreadExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ThreadExceptionTest { 4 | static class MyThread extends Thread { 5 | public void run() { 6 | for (int i = 0; i < 10; ++i) { 7 | System.out.println(getName() + ": " + i); 8 | } 9 | throw new RuntimeException("exception thrown from my thread: " + getName()); 10 | } 11 | } 12 | 13 | public static void main(String[] args) throws Exception { 14 | MyThread t = new MyThread(); 15 | t.start(); 16 | t.join(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/StaticFieldTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | class Person { 4 | static int i; 5 | } 6 | 7 | interface PersonContainer { 8 | Person p = new Person(); 9 | } 10 | 11 | class StaticFieldTest extends Person implements PersonContainer { 12 | 13 | public void print() { 14 | i = 4; 15 | super.i = 2; 16 | System.out.println(Person.i); 17 | } 18 | 19 | public static void main(String[] args) { 20 | StaticFieldTest u = new StaticFieldTest(); 21 | u.i = 3; 22 | u.print(); 23 | Person.i = 10; 24 | System.out.println(u.i); 25 | System.out.println(Person.i); 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /include/kivm/jni/nativeLibrariy.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/11/11. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace kivm { 10 | class JavaNativeLibrary final { 11 | private: 12 | dl::DLInterface _sharedLibrary; 13 | String _libraryName; 14 | bool _linked; 15 | 16 | String findLibrary(const String &libraryName); 17 | 18 | public: 19 | explicit JavaNativeLibrary(const String &libraryName); 20 | 21 | ~JavaNativeLibrary(); 22 | 23 | bool prepare(); 24 | 25 | void dispose(); 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /include/kivm/memory/collectedHeap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/19. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | class CollectedHeap { 10 | public: 11 | virtual ~CollectedHeap() = default; 12 | 13 | virtual void *allocate(size_t size) = 0; 14 | 15 | virtual void initializeAll() = 0; 16 | 17 | virtual void* getHeapStart() = 0; 18 | 19 | virtual void *getHeapEnd() = 0; 20 | 21 | virtual size_t getHeapSize() = 0; 22 | 23 | virtual bool isHeapObject(void *addr) = 0; 24 | 25 | virtual void doGarbageCollection() = 0; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/HashTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | /** 4 | * @author kiva 5 | * @date 2018/6/10 6 | */ 7 | public class HashTest { 8 | public static void main(String[] args) { 9 | String x = "so, nvdia, fuck you"; 10 | int hash = x.hashCode(); 11 | System.out.println(hash); 12 | int length = 1 << 10; 13 | int step1 = hash ^ ((hash >>> 20) ^ (hash >>> 12)); 14 | System.out.println(step1); 15 | int step2 = step1 ^ (step1 >>> 7) ^ (step1 >>> 4); 16 | System.out.println(step2); 17 | int index = step2 & (length - 1); 18 | System.out.println(index); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/kivm/native/java_lang_Double.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/24. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace kivm; 9 | 10 | JAVA_NATIVE jlong Java_java_lang_Double_doubleToRawLongBits(JNIEnv *env, jclass java_lang_Double, jdouble d) { 11 | union { 12 | jlong j; 13 | jdouble d; 14 | } u{}; 15 | u.d = d; 16 | return u.j; 17 | } 18 | 19 | JAVA_NATIVE jdouble Java_java_lang_Double_longBitsToDouble(JNIEnv *env, jclass java_lang_Double, jlong j) { 20 | union { 21 | jlong j; 22 | jdouble d; 23 | } u{}; 24 | u.j = j; 25 | return u.d; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | dist: trusty 3 | sudo: false 4 | 5 | compiler: g++ 6 | 7 | install: cmake . && make -j4 8 | 9 | script: echo hello KiVM. 10 | 11 | addons: 12 | apt: 13 | sources: 14 | - george-edison55-precise-backports 15 | packages: 16 | - cmake-data 17 | - cmake 18 | 19 | matrix: 20 | include: 21 | - os: linux 22 | addons: 23 | apt: 24 | sources: 25 | - ubuntu-toolchain-r-test 26 | packages: 27 | - g++-7 28 | - libffi-dev 29 | - libzip-dev 30 | env: 31 | - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" 32 | 33 | before_install: 34 | - eval "${MATRIX_EVAL}" 35 | -------------------------------------------------------------------------------- /include/kivm/classpath/system.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/28. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | class Klass; 12 | 13 | class SystemDictionary final { 14 | private: 15 | HashMap _classes; 16 | Lock _lock; 17 | 18 | public: 19 | static SystemDictionary *get(); 20 | 21 | Klass *find(const String &name); 22 | 23 | void put(const String &name, Klass *klass); 24 | 25 | inline const HashMap &getLoadedClasses() const { 26 | return _classes; 27 | }; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /include/kivm/bytecode/bytecodeInterpreter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace kivm { 12 | class ByteCodeInterpreter final { 13 | public: 14 | /** 15 | * Run a thread method 16 | * 17 | * @param thread Java Thread that contains method 18 | * @return method return value(nullptr if void) o 19 | * exception object(if thrown and not handled) 20 | */ 21 | static oop interp(JavaThread *thread); 22 | 23 | static void initialize(); 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /include/shared/string.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | 12 | namespace strings { 13 | using String = std::wstring; 14 | 15 | String fromBytes(u1 *bytes, size_t length); 16 | 17 | String fromStdString(const std::string &str); 18 | 19 | String replaceAll(const String &string, const String &oldValue, const String &newValue); 20 | 21 | std::string toStdString(const String &str); 22 | 23 | std::vector split(const String &string, const String &delimiter); 24 | } 25 | 26 | using String = strings::String; 27 | } 28 | -------------------------------------------------------------------------------- /src/kivm/classpath/system.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/28. 3 | // 4 | #include 5 | 6 | namespace kivm { 7 | SystemDictionary *SystemDictionary::get() { 8 | static SystemDictionary dictionary; 9 | return &dictionary; 10 | } 11 | 12 | Klass *SystemDictionary::find(const String &name) { 13 | LockGuard lockGuard(this->_lock); 14 | const auto &iter = this->_classes.find(name); 15 | return iter != this->_classes.end() ? iter->second : nullptr; 16 | } 17 | 18 | void SystemDictionary::put(const String &name, Klass *klass) { 19 | LockGuard lockGuard(this->_lock); 20 | this->_classes.insert(std::make_pair(name, klass)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/LookupSwitchTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | import sun.misc.Unsafe; 4 | 5 | public class LookupSwitchTest { 6 | public static void main(String[] args) { 7 | Unsafe unsafe = Unsafe.getUnsafe(); 8 | long a = unsafe.allocateMemory(8); 9 | try { 10 | unsafe.putLong(a, 0x0102030405060708L); 11 | byte b = unsafe.getByte(a); 12 | switch (b) { 13 | case 0x01: System.out.println("BE"); break; 14 | case 0x08: System.out.println("LE"); break; 15 | default: 16 | assert false; 17 | } 18 | } finally { 19 | unsafe.freeMemory(a); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/test-oop-size.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/20. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace kivm; 12 | 13 | int main() { 14 | printf("intOopDesc: %zd\n", sizeof(intOopDesc)); 15 | printf("floatOopDesc: %zd\n", sizeof(floatOopDesc)); 16 | printf("doubleOopDesc: %zd\n", sizeof(doubleOopDesc)); 17 | printf("longOopDesc: %zd\n", sizeof(longOopDesc)); 18 | printf("instanceOopDesc: %zd\n", sizeof(instanceOopDesc)); 19 | printf("arrayOopDesc: %zd\n", sizeof(arrayOopDesc)); 20 | printf("mirrorOopDesc: %zd\n", sizeof(mirrorOopDesc)); 21 | } 22 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/StaticResolution.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class StaticResolution { 4 | static class People { 5 | } 6 | 7 | static class Boy extends People { 8 | } 9 | 10 | static class Girl extends People { 11 | } 12 | 13 | public static void call(People p) { 14 | System.out.println("People"); 15 | } 16 | 17 | public static void call(Boy p) { 18 | System.out.println("Boy"); 19 | } 20 | 21 | public static void call(Girl p) { 22 | System.out.println("Girl"); 23 | } 24 | 25 | public static void main(String[] args) { 26 | People boy = new Boy(); 27 | People girl = new Girl(); 28 | call(boy); 29 | call(girl); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/shared/os/unix/osInfo.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/10. 3 | // 4 | #include 5 | 6 | #if defined(KIVM_PLATFORM_UNIX) 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | String UnixInformation::getOSName() { 12 | struct utsname name{}; 13 | uname(&name); 14 | return strings::fromStdString(name.sysname); 15 | } 16 | 17 | String UnixInformation::getOSVersion() { 18 | struct utsname name{}; 19 | uname(&name); 20 | return strings::fromStdString(name.release); 21 | } 22 | 23 | int UnixInformation::getCpuNumbers() { 24 | static long ncpu = sysconf(_SC_NPROCESSORS_CONF); 25 | return (int) ncpu; 26 | } 27 | } 28 | #endif 29 | -------------------------------------------------------------------------------- /tests/main.csc: -------------------------------------------------------------------------------- 1 | import kivm 2 | 3 | function csSayHello() 4 | system.out.println("hello world") 5 | end 6 | 7 | function csSayHelloInt(magicNumber) 8 | system.out.println("hello world, I got a magic number " + magicNumber + " from Java") 9 | end 10 | 11 | function newMethod() 12 | system.out.println("Yes! I've got updated!") 13 | end 14 | 15 | kivm.javaInit() 16 | 17 | kivm.registerNative("com.imkiva.kivm.CovScriptJNITest", "csSayHello", "()V", csSayHello) 18 | kivm.registerNative("com.imkiva.kivm.CovScriptJNITest", "csSayHello", "(I)V", csSayHelloInt) 19 | kivm.registerNative("com.imkiva.kivm.CovScriptJNITest", "oldMethod", "()V", newMethod) 20 | 21 | kivm.javaMain("com.imkiva.kivm.CovScriptJNITest", {}) 22 | 23 | kivm.javaDestroy() 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/kivm/runtime/stack.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/22. 3 | // 4 | #include 5 | #include 6 | 7 | namespace kivm { 8 | 9 | SlotArray::SlotArray(int size) 10 | : _size(size), _elements(nullptr) { 11 | if (size > 0) { 12 | this->_elements = new Slot[size]; 13 | memset(this->_elements, '\0', sizeof(Slot) * size); 14 | } 15 | } 16 | 17 | SlotArray::~SlotArray() { 18 | if (this->_elements != nullptr) { 19 | delete[] this->_elements; 20 | this->_elements = nullptr; 21 | } 22 | } 23 | 24 | Stack::Stack(int size) 25 | : _array(size), _sp(0) { 26 | } 27 | 28 | Locals::Locals(int size) 29 | : _array(size) { 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /include/kivm/memory/universe.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/20. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace kivm { 10 | class Universe final { 11 | friend class GCThread; 12 | 13 | private: 14 | static CollectedHeap *sCollectedHeapInstance; 15 | 16 | public: 17 | static void initialize(); 18 | 19 | static void destroy(); 20 | 21 | static void *allocVirtual(size_t size); 22 | 23 | static void deallocVirtual(void *memory); 24 | 25 | static void *allocHeap(size_t size); 26 | 27 | static void *allocCObject(size_t size); 28 | 29 | static void deallocCObject(void *memory); 30 | 31 | static bool isHeapObject(void *addr); 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /src/kivm/oop/mirrorKlass.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | namespace kivm { 9 | mirrorOop mirrorKlass::newMirror(Klass *target, mirrorOop loader) { 10 | if (target != nullptr && target->getName() == L"java/lang/Exception") { 11 | BootstrapClassLoader::get()->loadClass(L"java/lang/Class"); 12 | } 13 | auto mirror = new mirrorOopDesc(target); 14 | if (loader != nullptr) { 15 | mirror->setFieldValue(L"java/lang/Class", 16 | L"classLoader", 17 | L"Ljava/lang/ClassLoader;", 18 | loader); 19 | } 20 | 21 | return mirror; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /include/shared/os/windows/dl.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/15. 3 | // 4 | #pragma once 5 | 6 | #ifdef KIVM_PLATFORM_WINDOWS 7 | 8 | #include 9 | 10 | namespace kivm { 11 | namespace dl { 12 | class WindowsDLInterface final { 13 | private: 14 | DLHandler handler; 15 | 16 | public: 17 | WindowsDLInterface(); 18 | 19 | WindowsDLInterface(const WindowsDLInterface &) = delete; 20 | 21 | explicit WindowsDLInterface(const std::string &file); 22 | 23 | ~WindowsDLInterface(); 24 | 25 | bool open(const std::string &file); 26 | 27 | DLSymbol findSymbol(const std::string &symbolName) const; 28 | 29 | void close(); 30 | }; 31 | } 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/Polymorphism.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class Polymorphism { 4 | static class People { 5 | public void call() { 6 | System.out.println("People"); 7 | } 8 | } 9 | 10 | static class Boy extends People { 11 | public void call() { 12 | System.out.println("Boy"); 13 | } 14 | } 15 | 16 | static class Girl extends People { 17 | public void call() { 18 | System.out.println("Girl"); 19 | } 20 | } 21 | 22 | public static void call(People p) { 23 | p.call(); 24 | } 25 | 26 | public static void main(String[] args) { 27 | People boy = new Boy(); 28 | People girl = new Girl(); 29 | call(boy); 30 | call(girl); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /include/shared/os/unix/dl.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/15. 3 | // 4 | #pragma once 5 | 6 | #if defined(KIVM_PLATFORM_UNIX) || defined(KIVM_PLATFORM_APPLE) 7 | 8 | #include 9 | 10 | namespace kivm { 11 | namespace dl { 12 | class UnixDLInterface final { 13 | private: 14 | DLHandler handler; 15 | 16 | public: 17 | UnixDLInterface(); 18 | 19 | UnixDLInterface(const UnixDLInterface &) = delete; 20 | 21 | explicit UnixDLInterface(const std::string &file); 22 | 23 | ~UnixDLInterface(); 24 | 25 | bool open(const std::string &file); 26 | 27 | DLSymbol findSymbol(const std::string &symbolName) const; 28 | 29 | void close(); 30 | }; 31 | } 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/kivm/jni/jniJavaVM.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/16. 3 | // 4 | 5 | #include 6 | 7 | JNI_ENTRY(jint, DestroyJavaVM(JavaVM * vm)) { 8 | return kivm::KiVM::destroyJavaVM(vm); 9 | } 10 | 11 | JNI_ENTRY(jint, AttachCurrentThread(JavaVM * vm, void * *penv, void * args)) { 12 | kivm::KiVM::getEnv(vm, (JNIEnv **) penv, JNI_VERSION_1_8); 13 | return JNI_OK; 14 | } 15 | 16 | JNI_ENTRY(jint, DetachCurrentThread(JavaVM * vm)) { 17 | return JNI_OK; 18 | } 19 | 20 | JNI_ENTRY(jint, GetEnv(JavaVM * vm, void * *penv, jint 21 | version)) { 22 | return kivm::KiVM::getEnv(vm, (JNIEnv **) penv, version); 23 | } 24 | 25 | JNI_ENTRY(jint, AttachCurrentThreadAsDaemon(JavaVM * vm, void * *penv, void * args)) { 26 | return kivm::KiVM::getEnv(vm, (JNIEnv **) penv, JNI_VERSION_1_8); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /cmake/cmake-config.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef HAVE_CONFIG_H 4 | 5 | #cmakedefine01 HAVE_ZIP_FLAGS_T 6 | #cmakedefine01 HAVE_ZIP_SOURCE_T 7 | #cmakedefine01 HAVE_ZIP_FL_ENC_GUESS 8 | #cmakedefine01 HAVE_ZIP_H 9 | #cmakedefine01 KIVM_THREADED 10 | #cmakedefine01 KIVM_ARCH_x86 11 | #cmakedefine01 KIVM_ARCH_x86_64 12 | #cmakedefine01 KIVM_ARCH_arm 13 | #cmakedefine01 KIVM_ARCH_aarch64 14 | 15 | #define KIVM_ARCH_NAME L"@ARCH_NAME@" 16 | 17 | #if KIVM_ARCH_x86_64 || KIVM_ARCH_aarch64 18 | #define KIVM_ARCH_DATA_MODEL L"64" 19 | #else 20 | #define KIVM_ARCH_DATA_MODEL L"32" 21 | #endif 22 | 23 | #if HAVE_ZIP_H 24 | #define KIVM_JAR_CLASS_LOADING 25 | #if HAVE_ZIP_SOURCE_T 26 | #define KIVM_ZIP_OPEN_SOURCE 27 | #endif 28 | #endif 29 | 30 | #if KIVM_ARCH_x86_64 || KIVM_ARCH_x86 31 | #define KIVM_SUPPORT_CS8 32 | #endif 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/kivm/jni/nativeMethod.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/11/12. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | using JNIMethodPointer = void *; 10 | 11 | class NativeMethodPool; 12 | 13 | class JavaNativeMethod final { 14 | friend class NativeMethodPool; 15 | 16 | public: 17 | static JavaNativeMethod *resolve(Method *method); 18 | 19 | private: 20 | Method *_javaMethod = nullptr; 21 | JNIMethodPointer _invocationTarget = nullptr; 22 | 23 | private: 24 | JavaNativeMethod(Method *method, JNIMethodPointer target); 25 | 26 | ~JavaNativeMethod(); 27 | 28 | public: 29 | inline JNIMethodPointer getInvocationTarget() const { 30 | return _invocationTarget; 31 | } 32 | }; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ExceptionTest { 4 | public ExceptionTest() { 5 | fun1(); 6 | } 7 | 8 | public void fun1() { 9 | fun2(); 10 | } 11 | 12 | public void fun2() { 13 | fun3(); 14 | } 15 | 16 | public void fun3() { 17 | fun4(); 18 | } 19 | 20 | public void fun4() { 21 | fun5(); 22 | } 23 | 24 | public void fun5() { 25 | fun6(); 26 | } 27 | 28 | public void fun6() { 29 | fun7(); 30 | } 31 | 32 | public void fun7() { 33 | fun8(); 34 | } 35 | 36 | public void fun8() { 37 | throw new RuntimeException("So, NVDIA, fuck you!"); 38 | } 39 | 40 | public static void main(String[] args) { 41 | new ExceptionTest(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /include/kivm/bytecode/codeBlob.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/30. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | class CodeBlob final { 10 | friend class Method; 11 | 12 | private: 13 | u1 *_base; 14 | u4 _size; 15 | 16 | void init(u1 *base, u4 size) { 17 | this->_base = base; 18 | this->_size = size; 19 | } 20 | 21 | public: 22 | CodeBlob() : _base(nullptr), _size(0) {} 23 | 24 | inline bool validate() { 25 | return _base != nullptr && _size > 0; 26 | } 27 | 28 | inline bool validateOffset(int offset) const { 29 | return offset >= 0 && offset < _size; 30 | } 31 | 32 | inline u1 operator[](int offset) const { 33 | return *(_base + offset); 34 | } 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /include/shared/mmap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-01-19. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | #if defined(KIVM_PLATFORM_WINDOWS) 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | /* copied from sys/mman.h */ 17 | #define PROT_READ 1 18 | #define PROT_WRITE 2 19 | #define MAP_FAILED ((void*) -1) 20 | 21 | #define MAP_SHARED 0x01 /* Share changes. */ 22 | #define MAP_PRIVATE 0x02 /* Changes are private. */ 23 | #define MAP_ANON 0x1000 /* allocated from memory, swap space */ 24 | #define MAP_ANONYMOUS MAP_ANON 25 | 26 | void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); 27 | 28 | int munmap(void *start, size_t length); 29 | 30 | #else 31 | 32 | #include 33 | #include 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ExceptionTest2.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ExceptionTest2 { 4 | private int X; 5 | 6 | public static void main(String[] args) throws ClassNotFoundException { 7 | try { 8 | test1(); 9 | } catch (NullPointerException npe) { 10 | npe.printStackTrace(); 11 | } 12 | try { 13 | test2(); 14 | } catch (NullPointerException npe) { 15 | npe.printStackTrace(); 16 | } 17 | } 18 | 19 | 20 | public static void test1() { 21 | // test GETFIELD 22 | ExceptionTest2 s = null; 23 | System.out.println(s.X); 24 | } 25 | 26 | public static void test2() { 27 | // test MONITORENTER 28 | String s = null; 29 | synchronized (s) { 30 | System.out.println("should never reach here"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/kivm/bytecode/virtualMethodResolver.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/26. 3 | // 4 | 5 | #include 6 | 7 | namespace kivm { 8 | Method *JavaCall::resolveVirtualMethod(oop thisObject, Method *tagMethod) { 9 | auto thisClass = thisObject->getClass(); 10 | Method *resolved = nullptr; 11 | 12 | if (thisClass->getClassType() == ClassType::INSTANCE_CLASS) { 13 | auto instanceClass = (InstanceKlass *) thisClass; 14 | resolved = instanceClass->getVirtualMethod(tagMethod->getName(), tagMethod->getDescriptor()); 15 | } else if (thisClass->getClassType() == ClassType::OBJECT_ARRAY_CLASS 16 | || thisClass->getClassType() == ClassType::TYPE_ARRAY_CLASS) { 17 | resolved = tagMethod; 18 | } else { 19 | SHOULD_NOT_REACH_HERE(); 20 | } 21 | return resolved; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /include/kivm/native/java_lang_Thread.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/29. 3 | // 4 | #pragma once 5 | 6 | namespace kivm { 7 | namespace java { 8 | namespace lang { 9 | // JLS 20.20.1-3 10 | enum ThreadPriority { 11 | // Initial non-priority value 12 | NO_PRIORITY = -1, 13 | 14 | // Minimum priority 15 | MIN_PRIORITY = 1, 16 | 17 | // Normal (non-daemon) priority 18 | NORMAL_PRIORITY = 5, 19 | 20 | // High priority, used for VMThread 21 | NEAR_MAX_PRIORITY = 9, 22 | 23 | // Highest priority, used for WatcherThread, ensures that VMThread doesn't starve profiler 24 | MAX_PRIORITY = 10, 25 | 26 | // Critical thread priority 27 | CRITICAL_PRIORITY = 11 28 | }; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/bench-allocation.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/20. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | #define TIMES 1000000 9 | 10 | using namespace kivm; 11 | 12 | void bench(const char *tag, void(*func)()) { 13 | auto start = std::chrono::system_clock::now(); 14 | func(); 15 | auto end = std::chrono::system_clock::now(); 16 | auto cost = end - start; 17 | printf("benchmark %s: %lld\n", tag, cost.count()); 18 | } 19 | 20 | void benchMalloc() { 21 | for (int i = 0; i < TIMES; ++i) { 22 | auto m = (int *) malloc(sizeof(int)); 23 | *m = i; 24 | } 25 | } 26 | 27 | void benchUniverse() { 28 | for (int i = 0; i < TIMES; ++i) { 29 | auto m = (int *) Universe::allocHeap(sizeof(int)); 30 | *m = i; 31 | } 32 | } 33 | 34 | int main() { 35 | Universe::initialize(); 36 | bench("malloc", benchMalloc); 37 | bench("universe", benchUniverse); 38 | } 39 | -------------------------------------------------------------------------------- /src/kivm/jni/jniGlobal.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/16. 3 | // 4 | #include 5 | 6 | _JNI_IMPORT_OR_EXPORT_ 7 | jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args) { 8 | auto initArgs = (JavaVMInitArgs *) args; 9 | if (initArgs == nullptr) { 10 | return JNI_ERR; 11 | } 12 | initArgs->version = JNI_VERSION_1_8; 13 | initArgs->nOptions = 0; 14 | initArgs->ignoreUnrecognized = JNI_TRUE; 15 | initArgs->options = nullptr; 16 | return JNI_OK; 17 | } 18 | 19 | _JNI_IMPORT_OR_EXPORT_ 20 | jint JNICALL JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) { 21 | auto initArgs = (JavaVMInitArgs *) args; 22 | return kivm::KiVM::createVirtualMachine(pvm, (JNIEnv **) penv, initArgs); 23 | } 24 | 25 | _JNI_IMPORT_OR_EXPORT_ 26 | jint JNICALL JNI_GetCreatedJavaVMs(JavaVM **pJavaVM, jsize bufLen, jsize *nVMs) { 27 | *pJavaVM = kivm::KiVM::getJavaVMQuick(); 28 | *nVMs = 1; 29 | return JNI_OK; 30 | } 31 | -------------------------------------------------------------------------------- /src/kivm/native/java_lang_ClassLoader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/16. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace kivm; 10 | 11 | JAVA_NATIVE void Java_java_lang_ClassLoader_registerNatives(JNIEnv *env, jclass java_lang_ClassLoader) { 12 | D("java/lang/ClassLoader.registerNatives()V"); 13 | } 14 | 15 | JAVA_NATIVE jclass Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jclass unused, jstring jname) { 16 | auto nameObj = Resolver::instance(jname); 17 | if (nameObj == nullptr) { SHOULD_NOT_REACH_HERE(); } 18 | 19 | const auto &classBinaryName = java::lang::String::toNativeString(nameObj); 20 | const auto &fixedName = strings::replaceAll(classBinaryName, Global::DOT, Global::SLASH); 21 | 22 | auto dict = SystemDictionary::get(); 23 | auto klass = dict->find(fixedName); 24 | return klass == nullptr ? nullptr : klass->getJavaMirror(); 25 | } 26 | -------------------------------------------------------------------------------- /src/kivm/native/java_lang_reflect_Method.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/24. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | namespace kivm { 9 | namespace java { 10 | namespace lang { 11 | namespace reflect { 12 | InstanceKlass *Method::CLASS = nullptr; 13 | FieldID *Method::FIELD_CLAZZ = nullptr; 14 | FieldID *Method::FIELD_SLOT = nullptr; 15 | 16 | void Method::initialize() { 17 | CLASS = (InstanceKlass *) BootstrapClassLoader::get() 18 | ->loadClass(L"java/lang/reflect/Method"); 19 | FIELD_CLAZZ = CLASS->getInstanceFieldInfo(J_METHOD, 20 | L"clazz", L"Ljava/lang/Class;"); 21 | FIELD_SLOT = CLASS->getInstanceFieldInfo(J_METHOD, 22 | L"slot", L"I"); 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/kivm/bytecode2/template.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-06-28. 3 | // 4 | #include 5 | #include 6 | 7 | namespace kivm { 8 | void Template::initialize(int flags, TosState tosIn, TosState tosOut, Template::generator gen, int arg) { 9 | _flags = flags; 10 | _tosIn = tosIn; 11 | _tosOut = tosOut; 12 | _gen = gen; 13 | _arg = arg; 14 | } 15 | 16 | Bytecodes::Code Template::getBytecode() const { 17 | int i = this - TemplateTable::_templateTable; 18 | if (i < 0 || i >= Bytecodes::number_of_codes) i = this - TemplateTable::_templateTableWide; 19 | return static_cast(i); 20 | } 21 | 22 | void Template::generate(InterpreterMacroAssembler *masm) { 23 | // parameter passing 24 | TemplateTable::_desc = this; 25 | TemplateTable::_masm = masm; 26 | // code generation 27 | _gen(_arg); 28 | masm->flush(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/kivm/native/java_lang_reflect_Constructor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/24. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | namespace kivm { 9 | namespace java { 10 | namespace lang { 11 | namespace reflect { 12 | InstanceKlass *Constructor::CLASS = nullptr; 13 | FieldID *Constructor::FIELD_CLAZZ = nullptr; 14 | FieldID *Constructor::FIELD_SLOT = nullptr; 15 | 16 | void Constructor::initialize() { 17 | CLASS = (InstanceKlass *) BootstrapClassLoader::get() 18 | ->loadClass(L"java/lang/reflect/Constructor"); 19 | FIELD_CLAZZ = CLASS->getInstanceFieldInfo(J_CTOR, 20 | L"clazz", L"Ljava/lang/Class;"); 21 | FIELD_SLOT = CLASS->getInstanceFieldInfo(J_CTOR, 22 | L"slot", L"I"); 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /include/kivm/memory/heapRegion.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/21. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | struct HeapRegion final { 10 | size_t _regionSize{}; 11 | jbyte *_regionStart = nullptr; 12 | jbyte *_current = nullptr; 13 | 14 | inline size_t getUsed() const { 15 | return _current - _regionStart; 16 | } 17 | 18 | inline size_t getSize() const { 19 | return _regionSize; 20 | } 21 | 22 | inline jbyte *getRegionEnd() const { 23 | return _regionStart + getSize(); 24 | } 25 | 26 | inline bool shouldAllocate(size_t size) const { 27 | return (_current + size) < getRegionEnd(); 28 | } 29 | 30 | inline void *allocate(size_t size) { 31 | // bump the pointer 32 | jbyte *m = _current; 33 | _current += size; 34 | return m; 35 | } 36 | 37 | inline void reset() { 38 | this->_current = this->_regionStart; 39 | } 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /include/kivm/classfile/classFileParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | class ClassFileParser final { 12 | public: 13 | static ClassFile *alloc(); 14 | 15 | static void dealloc(ClassFile *class_file); 16 | 17 | private: 18 | ClassFile *_classFile = nullptr; 19 | ClassFileStream _classFileStream; 20 | u1 *_content = nullptr; 21 | size_t _size; 22 | 23 | ClassFile *parse(); 24 | 25 | void parseConstantPool(ClassFile *classFile); 26 | 27 | void parseInterfaces(ClassFile *classFile); 28 | 29 | void parseFields(ClassFile *classFile); 30 | 31 | void parseMethods(ClassFile *classFile); 32 | 33 | void parseAttributes(ClassFile *classFile); 34 | 35 | public: 36 | ClassFileParser(const String &filePath, u1 *buffer, size_t size); 37 | 38 | ~ClassFileParser(); 39 | 40 | ClassFile *getParsedClassFile(); 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /include/kivm/runtime/abstractThread.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/23. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | class AbstractThread { 12 | friend class Threads; 13 | 14 | protected: 15 | std::thread *_nativeThread = nullptr; 16 | 17 | ThreadState _state; 18 | 19 | protected: 20 | virtual void run() = 0; 21 | 22 | virtual void onDestroy(); 23 | 24 | virtual void onThreadLaunched(); 25 | 26 | public: 27 | AbstractThread(); 28 | 29 | virtual ~AbstractThread(); 30 | 31 | virtual void start(); 32 | 33 | long getNativeHandler() const; 34 | 35 | void setThreadName(const String &name); 36 | 37 | void setPriority(jint priority); 38 | 39 | inline ThreadState getThreadState() const { 40 | return _state; 41 | } 42 | 43 | inline void setThreadState(ThreadState threadState) { 44 | this->_state = threadState; 45 | } 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kiva 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /include/kivm/oop/mirrorOop.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace kivm { 10 | class mirrorOopDesc : public instanceOopDesc { 11 | friend class CopyingHeap; 12 | 13 | private: 14 | Klass *_mirrorTarget = nullptr; 15 | ValueType _mirroringPrimitiveType; 16 | 17 | public: 18 | explicit mirrorOopDesc(Klass *mirror); 19 | 20 | Klass *getTarget() const { 21 | return _mirrorTarget; 22 | } 23 | 24 | void setTarget(Klass *_mirrorTarget) { 25 | mirrorOopDesc::_mirrorTarget = _mirrorTarget; 26 | } 27 | 28 | ValueType getPrimitiveType() const { 29 | return _mirroringPrimitiveType; 30 | } 31 | 32 | void setPrimitiveType(ValueType mirroringPrimitiveType) { 33 | setTarget(nullptr); 34 | mirrorOopDesc::_mirroringPrimitiveType = mirroringPrimitiveType; 35 | } 36 | 37 | bool isPrimitiveMirror() const { 38 | return getTarget() == nullptr; 39 | } 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/kivm/oop/oopBase.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | void *GCJavaObject::allocate(size_t size) { 12 | if (size == 0) { 13 | return nullptr; 14 | } 15 | 16 | #ifdef KIVM_DEBUG_MALLOC_ONLY 17 | void *ptr = malloc(size); 18 | #else 19 | void *ptr = Universe::allocHeap(size); 20 | #endif 21 | memset(ptr, '\0', size); 22 | return ptr; 23 | } 24 | 25 | void GCJavaObject::deallocate(void *ptr) { 26 | #ifdef KIVM_DEBUG_MALLOC_ONLY 27 | free(ptr); 28 | #endif 29 | } 30 | 31 | void *GCJavaObject::operator new(size_t size, bool addToPool) noexcept { 32 | return allocate(size); 33 | } 34 | 35 | void *GCJavaObject::operator new[](size_t size, bool addToPool) noexcept { 36 | return allocate(size); 37 | } 38 | 39 | void GCJavaObject::operator delete(void *ptr) { 40 | return deallocate(ptr); 41 | } 42 | 43 | void GCJavaObject::operator delete[](void *ptr) { 44 | return deallocate(ptr); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /include/kivm/classpath/classPathManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/21. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace kivm { 10 | enum ClassSource { 11 | NOT_FOUND, 12 | DIR, 13 | JAR 14 | }; 15 | 16 | struct ClassSearchResult final { 17 | String _file; 18 | int _fd{}; 19 | ClassSource _source; 20 | u1 *_buffer = nullptr; 21 | size_t _bufferSize{}; 22 | 23 | ClassSearchResult(const String &file, int fd, ClassSource source, u1 *buffer, size_t bufferSize); 24 | 25 | void closeResource() const; 26 | }; 27 | 28 | struct ClassPathEntry final { 29 | ClassSource _source; 30 | String _path; 31 | void *_cookie; 32 | }; 33 | 34 | class ClassPathManager final { 35 | private: 36 | std::list _runtimeClassPath; 37 | 38 | public: 39 | static void initialize(); 40 | 41 | static ClassPathManager *get(); 42 | 43 | void addClassPath(const String &path); 44 | 45 | void addClassPaths(const String &classpath); 46 | 47 | ClassSearchResult searchClass(const String &className); 48 | 49 | void destroy(); 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /include/kivm/native/classNames.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/29. 3 | // 4 | #pragma once 5 | 6 | #define J_OBJECT L"java/lang/Object" 7 | #define J_CLONEABLE L"java/lang/Cloneable" 8 | #define J_SERIALIZABLE L"java/io/Serializable" 9 | #define J_CLASS L"java/lang/Class" 10 | #define J_STRING L"java/lang/String" 11 | #define J_THREAD L"java/lang/Thread" 12 | #define J_THREAD_GROUP L"java/lang/ThreadGroup" 13 | #define J_SYSTEM L"java/lang/System" 14 | 15 | #define J_INPUT_STREAM L"java/io/InputStream" 16 | #define J_PRINT_STREAM L"java/io/PrintStream" 17 | #define J_SECURITY_MANAGER L"java/lang/SecurityManager" 18 | 19 | #define J_FIELD L"java/lang/reflect/Field" 20 | #define J_METHOD L"java/lang/reflect/Method" 21 | #define J_CTOR L"java/lang/reflect/Constructor" 22 | #define J_ACCESSIBLE_OBJECT L"java/lang/reflect/AccessibleObject" 23 | #define J_METHODHANDLE L"java/lang/invoke/MethodHandle" 24 | #define J_METHODTYPE L"java/lang/invoke/MethodType" 25 | 26 | #define J_INTERNAL_ERROR L"java/lang/InternalError" 27 | #define J_NPE L"java/lang/NullPointerException" 28 | #define J_IOEXCEPTION L"java/io/IOException" 29 | #define J_ARRAY_INDEX_OUT_OF_BOUNDS L"java/lang/ArrayIndexOutOfBoundsException" 30 | #define J_CLASS_NOT_FOUND L"java/lang/ClassNotFoundException" 31 | -------------------------------------------------------------------------------- /include/kivm/classpath/classLoader.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/27. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | class Klass; 12 | 13 | class ClassLoader { 14 | public: 15 | static Klass *requireClass(ClassLoader *classLoader, const String &className); 16 | 17 | static ClassLoader* getCurrentClassLoader(); 18 | 19 | virtual Klass *loadClass(const String &className) = 0; 20 | 21 | virtual Klass *loadClass(u1 *classBytes, size_t classSize) = 0; 22 | 23 | ClassLoader() = default; 24 | 25 | ClassLoader(const ClassLoader &) = delete; 26 | 27 | ClassLoader(ClassLoader &&) noexcept = delete; 28 | 29 | virtual ~ClassLoader() = default; 30 | }; 31 | 32 | class BaseClassLoader : public ClassLoader { 33 | public: 34 | Klass *loadClass(const String &className) override; 35 | 36 | Klass *loadClass(u1 *classBytes, size_t classSize) override; 37 | }; 38 | 39 | class BootstrapClassLoader : public BaseClassLoader { 40 | public: 41 | static BootstrapClassLoader *get(); 42 | 43 | Klass *loadClass(const String &className) override; 44 | 45 | Klass *loadClass(u1 *classBytes, size_t classSize) override; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /src/kivm/classfile/annotation.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/11. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | namespace kivm { 9 | ParameterAnnotation::ParameterAnnotation(cp_info **pool, parameter_annotations_t *source) 10 | : _count(source->num_annotations), _annos(nullptr) { 11 | _annos = (Annotation *) Universe::allocCObject(sizeof(Annotation) * _count); 12 | for (int i = 0; i < _count; ++i) { 13 | auto anno = _annos + i; 14 | ::new((void *) anno) Annotation(pool, source->annotations + i); 15 | } 16 | } 17 | 18 | ParameterAnnotation::~ParameterAnnotation() { 19 | for (int i = 0; i < _count; ++i) { 20 | auto anno = _annos + i; 21 | anno->~Annotation(); 22 | } 23 | Universe::deallocCObject(_annos); 24 | } 25 | 26 | TypeAnnotation::TypeAnnotation(cp_info **pool, type_annotation *source) 27 | : _anno(new Annotation(pool, source->annotations)), _target_info(source->target_info) { 28 | } 29 | 30 | TypeAnnotation::~TypeAnnotation() { 31 | delete _anno; 32 | } 33 | 34 | Annotation::Annotation(cp_info **pool, annotation *anno) 35 | : _typeName(requireConstant(pool, anno->type_index)->getConstant()) { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /include/kivm/oop/oopfwd.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | #pragma once 5 | 6 | namespace kivm { 7 | enum oopType { 8 | INSTANCE_OOP, 9 | PRIMITIVE_OOP, 10 | OBJECT_ARRAY_OOP, 11 | TYPE_ARRAY_OOP, 12 | }; 13 | 14 | enum ValueType { 15 | VOID, 16 | BYTE, 17 | BOOLEAN, 18 | CHAR, 19 | SHORT, 20 | INT, 21 | FLOAT, 22 | LONG, 23 | DOUBLE, 24 | OBJECT, 25 | ARRAY, 26 | }; 27 | 28 | class markOopDesc; 29 | 30 | class oopDesc; 31 | 32 | class instanceOopDesc; 33 | 34 | class mirrorOopDesc; 35 | 36 | class arrayOopDesc; 37 | 38 | class typeArrayOopDesc; 39 | 40 | class objectArrayOopDesc; 41 | 42 | class intOopDesc; 43 | 44 | class longOopDesc; 45 | 46 | class floatOopDesc; 47 | 48 | class doubleOopDesc; 49 | 50 | using markOop = markOopDesc *; 51 | using oop = oopDesc *; 52 | using instanceOop = instanceOopDesc *; 53 | using mirrorOop = mirrorOopDesc *; 54 | using arrayOop= arrayOopDesc *; 55 | using typeArrayOop= typeArrayOopDesc *; 56 | using objectArrayOop= objectArrayOopDesc *; 57 | using intOop = intOopDesc *; 58 | using longOop= longOopDesc *; 59 | using floatOop = floatOopDesc *; 60 | using doubleOop = doubleOopDesc *; 61 | } 62 | -------------------------------------------------------------------------------- /src/shared/os/windows/mmap.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019/1/19. 3 | // 4 | 5 | #include 6 | 7 | #if defined(KIVM_PLATFORM_WINDOWS) 8 | 9 | void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) { 10 | size_t len; 11 | struct stat st{}; 12 | uint64_t o = offset; 13 | uint32_t l = o & 0xFFFFFFFF; 14 | uint32_t h = (o >> 32) & 0xFFFFFFFF; 15 | 16 | if (!fstat(fd, &st)) { 17 | len = (size_t) st.st_size; 18 | } else { 19 | fprintf(stderr,"win-mmap: could not determine filesize"); 20 | return nullptr; 21 | } 22 | 23 | if ((length + offset) > len) { 24 | length = len - offset; 25 | } 26 | 27 | if (!(flags & MAP_PRIVATE)) { 28 | fprintf(stderr,"win-mmap: invalid usage of mman\n"); 29 | return nullptr; 30 | } 31 | 32 | HANDLE hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), 0, PAGE_WRITECOPY, 0, 0, 0); 33 | 34 | if (!hmap) { 35 | return MAP_FAILED; 36 | } 37 | 38 | void *temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start); 39 | 40 | if (!CloseHandle(hmap)) { 41 | fprintf(stderr, "win-mmap: unable to close file mapping handle\n"); 42 | } 43 | 44 | return temp ? temp : MAP_FAILED; 45 | } 46 | 47 | 48 | int munmap(void *start, size_t length) { 49 | return !UnmapViewOfFile(start); 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /include/kivm/classfile/annotation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/11. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | struct Annotation { 10 | String _typeName; 11 | annotation *_anno; 12 | 13 | Annotation(cp_info **pool, annotation *anno); 14 | 15 | inline bool checkTypeName(const String &typeName) { 16 | return typeName == _typeName; 17 | } 18 | }; 19 | 20 | struct ParameterAnnotation { 21 | int _count; 22 | Annotation *_annos; 23 | 24 | explicit ParameterAnnotation(cp_info **pool, parameter_annotations_t *source); 25 | 26 | ~ParameterAnnotation(); 27 | 28 | inline bool checkTypeName(const String &typeName) { 29 | for (int i = 0; i < _count; ++i) { 30 | if (_annos[i].checkTypeName(typeName)) { 31 | return true; 32 | } 33 | } 34 | return false; 35 | } 36 | }; 37 | 38 | struct TypeAnnotation { 39 | type_annotation::target_info_t *_target_info; 40 | Annotation *_anno; 41 | 42 | explicit TypeAnnotation(cp_info **pool, type_annotation *source); 43 | 44 | ~TypeAnnotation(); 45 | 46 | inline bool checkTypeName(const String &typeName) { 47 | return _anno->checkTypeName(typeName); 48 | } 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /src/shared/os/macos/osInfo.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/10. 3 | // 4 | 5 | #include 6 | 7 | #if defined(KIVM_PLATFORM_APPLE) 8 | #include 9 | #include 10 | 11 | namespace kivm { 12 | static void *getJRSFramework() { 13 | static void *jrsFwk = nullptr; 14 | if (jrsFwk == nullptr) { 15 | jrsFwk = dlopen( 16 | "/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", 17 | RTLD_LAZY | RTLD_LOCAL); 18 | } 19 | return jrsFwk; 20 | } 21 | 22 | String MacOSInformation::getOSName() { 23 | return L"Mac OS X"; 24 | } 25 | 26 | String MacOSInformation::getOSVersion() { 27 | void *jrsFwk = getJRSFramework(); 28 | if (jrsFwk != nullptr) { 29 | auto copyOSVersion = (char *(*)()) (dlsym(jrsFwk, "JRSCopyOSVersion")); 30 | 31 | if (copyOSVersion != nullptr) { 32 | char *osVersion = copyOSVersion(); 33 | String ver = strings::fromStdString(osVersion); 34 | free(osVersion); 35 | return ver; 36 | } 37 | } 38 | return kivm::String(); 39 | } 40 | 41 | int MacOSInformation::getCpuNumbers() { 42 | static long ncpu = sysconf(_SC_NPROCESSORS_CONF); 43 | return (int) ncpu; 44 | } 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /include/kivm/native/java_lang_Class.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/28. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace kivm { 13 | class CopyingHeap; 14 | 15 | namespace java { 16 | namespace lang { 17 | class Class { 18 | friend class kivm::CopyingHeap; 19 | 20 | private: 21 | static HashMap _primitiveTypeMirrors; 22 | 23 | enum ClassMirrorState { 24 | FIXED, NOT_FIXED 25 | }; 26 | 27 | static HashMap &getPrimitiveTypeMirrors(); 28 | 29 | static std::queue &getDelayedMirrors(); 30 | 31 | static std::queue &getDelayedArrayClassMirrors(); 32 | 33 | static ClassMirrorState &getMirrorState(); 34 | 35 | public: 36 | static void initialize(); 37 | 38 | static void mirrorCoreAndDelayedClasses(); 39 | 40 | static void mirrorDelayedArrayClasses(); 41 | 42 | static void createMirror(Klass *klass, mirrorOop javaLoader); 43 | 44 | static mirrorOop findPrimitiveTypeMirror(const kivm::String &signature); 45 | }; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ExceptionTest3.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | public class ExceptionTest3 { 4 | public static void main(String[] args) throws ClassNotFoundException { 5 | try { 6 | test1(); 7 | } catch (NullPointerException npe) { 8 | npe.printStackTrace(); 9 | } 10 | 11 | try { 12 | test2(); 13 | } catch (ArrayIndexOutOfBoundsException e) { 14 | e.printStackTrace(); 15 | } 16 | 17 | try { 18 | test3(); 19 | } catch (NullPointerException npe) { 20 | npe.printStackTrace(); 21 | } 22 | 23 | try { 24 | test4(); 25 | } catch (ArrayIndexOutOfBoundsException e) { 26 | e.printStackTrace(); 27 | } 28 | } 29 | 30 | 31 | public static void test1() { 32 | // test IALOAD and so on 33 | int[] a = null; 34 | System.out.println(a[0]); 35 | } 36 | 37 | public static void test2() { 38 | // test IALOAD and so on 39 | int[] a = new int[2]; 40 | System.out.println(a[5]); 41 | } 42 | 43 | public static void test3() { 44 | // test AALOAD 45 | String[] s = null; 46 | System.out.println(s[0]); 47 | } 48 | 49 | public static void test4() { 50 | // test AALOAD 51 | String[] s = new String[3]; 52 | System.out.println(s[8]); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /include/kivm/memory/gcThread.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/4. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | enum GCState { 12 | GC_STOPPED, 13 | GC_RUNNING, 14 | ENJOYING_HOLIDAY, 15 | WAITING_FOR_SAFEPOINT, 16 | }; 17 | 18 | enum GCReason { 19 | GC_FOR_MALLOC, 20 | GC_EXPLICIT, 21 | GC_CONCURRENT, 22 | }; 23 | 24 | class GCThread : public VMThread { 25 | private: 26 | static GCThread *sGCThreadInstance; 27 | 28 | public: 29 | inline static GCThread *get() { 30 | if (sGCThreadInstance == nullptr) { 31 | WARN("GCThread not initialized"); 32 | return nullptr; 33 | } 34 | return sGCThreadInstance; 35 | } 36 | 37 | static void initialize(); 38 | 39 | private: 40 | GCState _gcState; 41 | Monitor _triggerMonitor; 42 | Monitor _gcWaitMonitor; 43 | 44 | private: 45 | bool isAllThreadInSafePoint(); 46 | 47 | void doGarbageCollection(); 48 | 49 | protected: 50 | void run() override; 51 | 52 | public: 53 | Monitor *required(); 54 | 55 | void wait(); 56 | 57 | void stop(); 58 | 59 | inline GCState getState() const { 60 | return _gcState; 61 | } 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /src/kivm/bytecode/dynamicCall.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-01-31. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace kivm { 19 | oop JavaCall::invokeDynamic(instanceOop MH, const String &descriptor) { 20 | // TODO: obtain args from stack and call invokeExact with MH 21 | _obtainArgsFromStack = true; 22 | if (_stack == nullptr) { 23 | SHOULD_NOT_REACH_HERE_M("Stack must not be null"); 24 | } 25 | 26 | const std::vector &descriptorMap = parseArgumentValueTypes(descriptor); 27 | ValueType returnType = parseReturnValueType(descriptor); 28 | 29 | // Do not obtain this form stack 30 | // The `this` object is `MH` 31 | if (!fillArguments(descriptorMap, false)) { 32 | // TODO: throw StackOverflow 33 | PANIC("StackOverflow"); 34 | } 35 | 36 | // The `this` 37 | _args.push_front(MH); 38 | 39 | assert(_method->isNative()); 40 | return nullptr; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /include/kivm/bytecode/threadedInterpreter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | #if defined(KIVM_THREADED) && !defined(KIVM_DEBUG) 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace kivm { 17 | class Frame; 18 | 19 | class Method; 20 | 21 | class InstanceKlass; 22 | 23 | class ThreadedInterpreter final { 24 | public: 25 | /** 26 | * Run a thread method 27 | * 28 | * @param thread Java Thread that contains method 29 | * @return method return value(nullptr if void) o 30 | * exception object(if thrown and not handled) 31 | */ 32 | static oop interp(JavaThread *thread); 33 | 34 | static void initialize(); 35 | 36 | 37 | private: 38 | static void *_jumpTable[OPC_NUM_OPCODES]; 39 | 40 | static oop threaded(JavaThread *thread, void **jump, 41 | Frame *currentFrame, 42 | Method *currentMethod, 43 | InstanceKlass *currentClass, 44 | const CodeBlob &codeBlob, 45 | u4 &pc, 46 | Stack &stack, 47 | Locals &locals); 48 | }; 49 | } 50 | #endif 51 | -------------------------------------------------------------------------------- /src/kivm/native/sun_nio_cs_StreamEncoder.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/26. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace kivm; 15 | 16 | JAVA_NATIVE jobject Java_sun_nio_cs_StreamEncoder_forOutputStreamWriter(JNIEnv *env, jclass sun_nio_cs_StreamEncoder, 17 | jobject javaOutputStream, 18 | jobject javaObject, 19 | jstring javaCharsetName) { 20 | auto thread = Threads::currentThread(); 21 | 22 | auto encoder = (InstanceKlass *) BootstrapClassLoader::get() 23 | ->loadClass(L"sun/nio/cs/StreamEncoder"); 24 | auto method = encoder->getThisClassMethod(L"", 25 | L"(Ljava/io/OutputStream;Ljava/lang/Object;Ljava/nio/charset/Charset;)V"); 26 | auto encoderOop = encoder->newInstance(); 27 | JavaCall::withArgs(thread, method, 28 | { 29 | encoderOop, 30 | Resolver::instance(javaOutputStream), 31 | Resolver::instance(javaObject), 32 | Global::DEFAULT_UTF8_CHARSET 33 | }, true); 34 | return encoderOop; 35 | } 36 | -------------------------------------------------------------------------------- /include/kivm/native/java_lang_String.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/29. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | class CopyingHeap; 12 | 13 | namespace java { 14 | namespace lang { 15 | struct StringHash { 16 | int operator()(instanceOop ptr) const noexcept; 17 | 18 | int operator()(const kivm::String &string) const noexcept; 19 | }; 20 | 21 | struct StringEqualTo { 22 | bool operator()(instanceOop lhs, instanceOop rhs) const; 23 | }; 24 | 25 | class InternStringPool { 26 | friend class kivm::CopyingHeap; 27 | 28 | private: 29 | // hash -> string 30 | HashMap _pool; 31 | 32 | public: 33 | static InternStringPool *getGlobal(); 34 | 35 | instanceOop findOrNew(const kivm::String &string); 36 | }; 37 | 38 | class String { 39 | public: 40 | static instanceOop from(const kivm::String &string); 41 | 42 | static kivm::String toNativeString(instanceOop stringOop); 43 | 44 | static inline instanceOop intern(const kivm::String &string) { 45 | return InternStringPool::getGlobal()->findOrNew(string); 46 | } 47 | }; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/shared/os/windows/dl.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/15. 3 | // 4 | #include 5 | 6 | #ifdef KIVM_PLATFORM_WINDOWS 7 | 8 | #include 9 | 10 | namespace kivm { 11 | namespace dl { 12 | 13 | WindowsDLInterface::WindowsDLInterface() : handler(nullptr) { 14 | 15 | } 16 | 17 | WindowsDLInterface::WindowsDLInterface(const std::string &file) : handler(nullptr) { 18 | open(file); 19 | } 20 | 21 | WindowsDLInterface::~WindowsDLInterface() { 22 | close(); 23 | } 24 | 25 | bool WindowsDLInterface::open(const std::string &file) { 26 | auto handler = DLHandler(::LoadLibrary(file.c_str())); 27 | this->handler = handler; 28 | return this->handler != nullptr; 29 | } 30 | 31 | DLSymbol WindowsDLInterface::findSymbol(const std::string &symbolName) const { 32 | auto hmod = HMODULE(handler); 33 | FARPROC sym = ::GetProcAddress(hmod != nullptr ? hmod : GetModuleHandle(nullptr), 34 | symbolName.c_str()); 35 | if (sym != nullptr) { 36 | return DLSymbol(sym); 37 | } 38 | 39 | return nullptr; 40 | } 41 | 42 | void WindowsDLInterface::close() { 43 | if (handler != nullptr) { 44 | ::FreeLibrary(HMODULE(handler)); 45 | handler = nullptr; 46 | } 47 | } 48 | } 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/TableSwitchTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | import sun.misc.Unsafe; 4 | 5 | public class TableSwitchTest { 6 | public static void main(String[] args) { 7 | Unsafe unsafe = Unsafe.getUnsafe(); 8 | long a = unsafe.allocateMemory(8); 9 | 10 | try { 11 | unsafe.putLong(a, 0x0102030405060708L); 12 | byte b = unsafe.getByte(a); 13 | switch (b) { 14 | case 1: 15 | System.out.println("1"); 16 | break; 17 | case 2: 18 | System.out.println("2"); 19 | break; 20 | case 3: 21 | System.out.println("3"); 22 | break; 23 | case 4: 24 | System.out.println("4"); 25 | break; 26 | case 5: 27 | System.out.println("5"); 28 | break; 29 | case 6: 30 | System.out.println("6"); 31 | break; 32 | case 7: 33 | System.out.println("7"); 34 | break; 35 | case 8: 36 | System.out.println("8"); 37 | break; 38 | default: 39 | System.out.println("default"); 40 | break; 41 | } 42 | } finally { 43 | unsafe.freeMemory(a); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/shared/os/unix/dl.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/15. 3 | // 4 | 5 | #include 6 | 7 | #if defined(KIVM_PLATFORM_UNIX) || defined(KIVM_PLATFORM_APPLE) 8 | 9 | // for RTLD_DEFAULT 10 | #ifndef _GNU_SOURCE 11 | #define _GNU_SOURCE 12 | #endif 13 | 14 | #include 15 | 16 | namespace kivm { 17 | namespace dl { 18 | UnixDLInterface::UnixDLInterface() : handler(nullptr) { 19 | } 20 | 21 | UnixDLInterface::UnixDLInterface(const std::string &file) : handler(nullptr) { 22 | open(file); 23 | } 24 | 25 | UnixDLInterface::~UnixDLInterface() { 26 | close(); 27 | } 28 | 29 | bool UnixDLInterface::open(const std::string &file) { 30 | DLHandler handler = ::dlopen(file.c_str(), RTLD_LAZY); 31 | this->handler = handler; 32 | return this->handler != nullptr; 33 | } 34 | 35 | DLSymbol UnixDLInterface::findSymbol(const std::string &symbolName) const { 36 | // Clear errors 37 | (void) ::dlerror(); 38 | 39 | DLSymbol sym = dlsym(handler != nullptr ? handler : RTLD_DEFAULT, symbolName.c_str()); 40 | if (::dlerror() == nullptr) { 41 | return sym; 42 | } 43 | return nullptr; 44 | } 45 | 46 | void UnixDLInterface::close() { 47 | if (handler != nullptr) { 48 | ::dlclose(handler); 49 | handler = nullptr; 50 | } 51 | } 52 | } 53 | } 54 | 55 | #endif -------------------------------------------------------------------------------- /src/kivm/classfile/classFile.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/26. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | namespace kivm { 9 | 10 | field_info::field_info() { 11 | this->attributes = nullptr; 12 | this->attributes_count = 0; 13 | } 14 | 15 | field_info::~field_info() { 16 | AttributeParser::deallocAttributes(&attributes, attributes_count); 17 | } 18 | 19 | void field_info::init(ClassFileStream &stream, cp_info **constant_pool) { 20 | access_flags = stream.get2(); 21 | name_index = stream.get2(); 22 | descriptor_index = stream.get2(); 23 | attributes_count = stream.get2(); 24 | AttributeParser::readAttributes(&attributes, attributes_count, 25 | stream, constant_pool); 26 | } 27 | 28 | method_info::method_info() { 29 | this->attributes = nullptr; 30 | this->attributes_count = 0; 31 | } 32 | 33 | method_info::~method_info() { 34 | AttributeParser::deallocAttributes(&attributes, attributes_count); 35 | } 36 | 37 | void method_info::init(ClassFileStream &stream, cp_info **constant_pool) { 38 | access_flags = stream.get2(); 39 | name_index = stream.get2(); 40 | descriptor_index = stream.get2(); 41 | attributes_count = stream.get2(); 42 | AttributeParser::readAttributes(&attributes, attributes_count, 43 | stream, constant_pool); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /include/shared/arch/arm/atomic.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/13. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | #if KIVM_ARCH_arm 9 | 10 | /* 11 | * Use the __kuser_memory_barrier helper in the CPU helper page. See 12 | * arch/arm/kernel/entry-armv.S in the kernel source for details. 13 | */ 14 | #define mbarrier() ((void(*)(void))0xffff0fa0)() 15 | 16 | #define COMPARE_AND_SWAP_32(addr, old_val, new_val) \ 17 | ({ \ 18 | int result, read_val; \ 19 | __asm__ __volatile__ (" \ 20 | 1: mov %0, #0; \ 21 | ldrex %1, [%2]; \ 22 | cmp %3, %1; \ 23 | bne 2f; \ 24 | strex %0, %4, [%2]; \ 25 | cmp %0, #1; \ 26 | beq 1b; \ 27 | mov %0, #1; \ 28 | 2:" \ 29 | : "=&r" (result), "=&r" (read_val) \ 30 | : "r" (addr), "r" (old_val), "r" (new_val) \ 31 | : "cc", "memory"); \ 32 | result; \ 33 | }) 34 | 35 | #define cmpxchg(addr, old_val, new_val) \ 36 | COMPARE_AND_SWAP_32(addr, old_val, new_val) 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/kivm/jni/nativeLibrary.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/11/11. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | namespace kivm { 9 | using JNIOnLoadFunction = jint(*)(JavaVM *, void *); 10 | using JNIOnUnloadFunction = void (*)(JavaVM *, void *); 11 | 12 | JavaNativeLibrary::JavaNativeLibrary(const String &libraryName) 13 | : _libraryName(libraryName), _linked(false) { 14 | } 15 | 16 | bool JavaNativeLibrary::prepare() { 17 | const String &path = findLibrary(_libraryName); 18 | int javaVersion = JNI_VERSION_UNKNOWN; 19 | if (_sharedLibrary.open(strings::toStdString(path))) { 20 | auto onLoadFunction = (JNIOnLoadFunction) _sharedLibrary.findSymbol("JNI_OnLoad"); 21 | if (onLoadFunction) { 22 | javaVersion = onLoadFunction(KiVM::getJavaVMQuick(), nullptr); 23 | } 24 | } 25 | _linked = KiVM::checkJavaVersion(javaVersion); 26 | return _linked; 27 | } 28 | 29 | void JavaNativeLibrary::dispose() { 30 | if (_linked) { 31 | auto onUnloadFunction = (JNIOnUnloadFunction) _sharedLibrary.findSymbol("JNI_OnUnload"); 32 | if (onUnloadFunction) { 33 | onUnloadFunction(KiVM::getJavaVMQuick(), nullptr); 34 | } 35 | _linked = false; 36 | } 37 | } 38 | 39 | String JavaNativeLibrary::findLibrary(const String &libraryName) { 40 | return kivm::String(); 41 | } 42 | 43 | JavaNativeLibrary::~JavaNativeLibrary() { 44 | dispose(); 45 | } 46 | } -------------------------------------------------------------------------------- /cmake/FindFFI.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find libffi 2 | # 3 | # Once done this will define 4 | # FFI_FOUND - System has libffi 5 | # FFI_INCLUDE_DIRS - The package include directories 6 | # FFI_LIBRARIES - The libraries needed to use this package 7 | 8 | if (NOT WIN32) 9 | # try using pkg-config to get the directories and then use these values 10 | # in the find_path() and find_library() calls 11 | find_package(PkgConfig QUIET) 12 | PKG_CHECK_MODULES(PC_LIBFFI QUIET libffi) 13 | endif () 14 | 15 | mark_as_advanced(GNUTLS_INCLUDE_DIR GNUTLS_LIBRARY) 16 | 17 | find_library(FFI_LIBRARY NAMES ffi libffi 18 | PATHS $ENV{FFI_DIR} ${FFI_DIR} $ENV{WIN32_FFI_DIR} ${WIN32_FFI_DIR} /usr /usr/local /opt/local 19 | PATH_SUFFIXES lib lib64 x86_64-linux-gnu lib/x86_64-linux-gnu 20 | HINTS ${PC_LIBFFI_LIBDIR} ${PC_LIBFFI_LIBRARY_DIRS} 21 | ) 22 | 23 | find_path(FFI_INCLUDE_DIR ffi.h 24 | PATHS $ENV{FFI_DIR} ${FFI_DIR} $ENV{WIN32_FFI_DIR} ${WIN32_FFI_DIR} /usr /usr/local /opt/local 25 | PATH_SUFFIXES include include/ffi include/x86_64-linux-gnu x86_64-linux-gnu 26 | HINTS ${PC_LIBFFI_INCLUDEDIR} ${PC_LIBFFI_INCLUDE_DIRS} 27 | ) 28 | 29 | include(FindPackageHandleStandardArgs) 30 | # handle the QUIETLY and REQUIRED arguments and set FFI_FOUND to TRUE 31 | # if all listed variables are TRUE 32 | find_package_handle_standard_args(FFI DEFAULT_MSG 33 | FFI_LIBRARY FFI_INCLUDE_DIR) 34 | mark_as_advanced(FFI_INCLUDE_DIR FFI_LIBRARY) 35 | 36 | if(FFI_FOUND) 37 | set(FFI_LIBRARIES ${FFI_LIBRARY}) 38 | set(FFI_INCLUDE_DIRS ${FFI_INCLUDE_DIR}) 39 | endif() 40 | -------------------------------------------------------------------------------- /cmake/FindZIP.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find libzip 2 | # 3 | # Once done this will define 4 | # ZIP_FOUND - System has libzip 5 | # ZIP_INCLUDE_DIRS - The package include directories 6 | # ZIP_LIBRARIES - The libraries needed to use this package 7 | 8 | if (NOT WIN32) 9 | # try using pkg-config to get the directories and then use these values 10 | # in the find_path() and find_library() calls 11 | find_package(PkgConfig QUIET) 12 | PKG_CHECK_MODULES(PC_LIBZIP QUIET libzip) 13 | endif () 14 | 15 | mark_as_advanced(GNUTLS_INCLUDE_DIR GNUTLS_LIBRARY) 16 | 17 | find_library(ZIP_LIBRARY NAMES zip libzip 18 | PATHS $ENV{ZIP_DIR} ${ZIP_DIR} $ENV{WIN32_ZIP_DIR} ${WIN32_ZIP_DIR} /usr /usr/local /opt/local 19 | PATH_SUZIPXES lib lib64 x86_64-linux-gnu lib/x86_64-linux-gnu 20 | HINTS ${PC_LIBZIP_LIBDIR} ${PC_LIBZIP_LIBRARY_DIRS} 21 | ) 22 | 23 | find_path(ZIP_INCLUDE_DIR zip.h 24 | PATHS $ENV{ZIP_DIR} ${ZIP_DIR} $ENV{WIN32_ZIP_DIR} ${WIN32_ZIP_DIR} /usr /usr/local /opt/local 25 | PATH_SUZIPXES include include/zip include/x86_64-linux-gnu x86_64-linux-gnu 26 | HINTS ${PC_LIBZIP_INCLUDEDIR} ${PC_LIBZIP_INCLUDE_DIRS} 27 | ) 28 | 29 | include(FindPackageHandleStandardArgs) 30 | # handle the QUIETLY and REQUIRED arguments and set ZIP_FOUND to TRUE 31 | # if all listed variables are TRUE 32 | find_package_handle_standard_args(ZIP DEFAULT_MSG 33 | ZIP_LIBRARY ZIP_INCLUDE_DIR) 34 | mark_as_advanced(ZIP_INCLUDE_DIR ZIP_LIBRARY) 35 | 36 | if(ZIP_FOUND) 37 | set(ZIP_LIBRARIES ${ZIP_LIBRARY}) 38 | set(ZIP_INCLUDE_DIRS ${ZIP_INCLUDE_DIR}) 39 | endif() 40 | -------------------------------------------------------------------------------- /include/shared/monitor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // Modified by mikecovlee on 2018/2/25. 4 | // 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace kivm { 15 | /** 16 | * StackOverflow: 17 | * 18 | * In the case of recursive mutex, 19 | * you do have to ensure that the given thread has only locked the recursive mutex once, 20 | * since the condition variable only will use the unlock method 21 | * on the unique_lock once during the wait. 22 | */ 23 | 24 | class Monitor final { 25 | private: 26 | RecursiveLock _lock; 27 | std::condition_variable_any _cond; 28 | 29 | public: 30 | Monitor() = default; 31 | 32 | Monitor(const Monitor &) = delete; 33 | 34 | Monitor(Monitor &&) noexcept = delete; 35 | 36 | ~Monitor() = default; 37 | 38 | void enter() { 39 | _lock.lock(); 40 | } 41 | 42 | void wait() { 43 | _cond.wait(_lock); 44 | } 45 | 46 | void wait(jlong millisecond) { 47 | _cond.wait_for(_lock, std::chrono::milliseconds(millisecond)); 48 | } 49 | 50 | void notify() { 51 | _cond.notify_one(); 52 | } 53 | 54 | void notifyAll() { 55 | _cond.notify_all(); 56 | } 57 | 58 | void leave() { 59 | _lock.unlock(); 60 | } 61 | 62 | void forceUnlock() { 63 | _lock.try_lock(); 64 | _lock.unlock(); 65 | } 66 | }; 67 | } -------------------------------------------------------------------------------- /src/kivm/runtime/abstractThread.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/25. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #if defined(KIVM_PLATFORM_UNIX) || defined(KIVM_PLATFORM_APPLE) 14 | #include 15 | #endif 16 | 17 | namespace kivm { 18 | AbstractThread::AbstractThread() 19 | : _nativeThread(nullptr), 20 | _state(ThreadState::RUNNING) { 21 | } 22 | 23 | AbstractThread::~AbstractThread() = default; 24 | 25 | void AbstractThread::start() { 26 | this->_nativeThread = new std::thread([this] { 27 | this->run(); 28 | this->onDestroy(); 29 | }); 30 | this->onThreadLaunched(); 31 | } 32 | 33 | void AbstractThread::onThreadLaunched() { 34 | // Do nothing. 35 | } 36 | 37 | void AbstractThread::onDestroy() { 38 | // Do nothing. 39 | } 40 | 41 | long AbstractThread::getNativeHandler() const { 42 | return (long) this->_nativeThread->native_handle(); 43 | } 44 | 45 | void AbstractThread::setThreadName(const String &name) { 46 | #if defined(KIVM_PLATFORM_APPLE) 47 | pthread_setname_np(strings::toStdString(name).c_str()); 48 | #elif defined(KIVM_PLATFORM_UNIX) 49 | pthread_setname_np(pthread_self(), strings::toStdString(name).c_str()); 50 | #elif defined(KIVM_PLATFORM_WINDOWS) 51 | SHOULD_NOT_REACH_HERE(); 52 | #endif 53 | } 54 | 55 | void AbstractThread::setPriority(jint priority) { 56 | // TODO: set thread priority 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/kivm/native/sun_reflect_NativeConstructorAccessorImpl.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/24. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace kivm; 15 | 16 | JAVA_NATIVE jobject Java_sun_reflect_NativeConstructorAccessorImpl_newInstance0(JNIEnv *env, jclass cls, 17 | jobject javaConstructor, 18 | jobjectArray javaArguments) { 19 | auto thread = Threads::currentThread(); 20 | 21 | auto ctorOop = Resolver::instance(javaConstructor); 22 | auto targetClass = getClassFromConstructor(ctorOop); 23 | auto slot = getSlotFromConstructor(ctorOop); 24 | auto mirrorTarget = (InstanceKlass *) targetClass->getTarget(); 25 | 26 | auto instance = mirrorTarget->newInstance(); 27 | auto ctorMethod = mirrorTarget->getDeclaredMethodByOffset(slot); 28 | 29 | if (ctorMethod->getName() != L"") { 30 | SHOULD_NOT_REACH_HERE(); 31 | } 32 | 33 | std::list callingArgs; 34 | callingArgs.push_back(instance); 35 | 36 | if (javaArguments != nullptr) { 37 | auto arguments = Resolver::objectArray(javaArguments); 38 | for (int i = 0; i < arguments->getLength(); ++i) { 39 | callingArgs.push_back(arguments->getElementAt(i)); 40 | } 41 | } 42 | JavaCall::withArgs(thread, ctorMethod, callingArgs, true); 43 | return instance; 44 | } 45 | -------------------------------------------------------------------------------- /tests/test-encode-decode-offset.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/12. 3 | // 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace kivm; 9 | 10 | union OffsetEncoder { 11 | struct { 12 | int isStatic; 13 | int offset; 14 | }; 15 | jlong result; 16 | 17 | std::tuple decode() { 18 | return std::make_tuple(offset, isStatic != 0); 19 | }; 20 | 21 | OffsetEncoder(int offset, bool isStatic) { 22 | this->offset = offset; 23 | this->isStatic = isStatic; 24 | } 25 | 26 | OffsetEncoder(jlong encoded) { 27 | this->result = encoded; 28 | } 29 | }; 30 | 31 | static jlong encodeOffset(int offset, bool isStatic) { 32 | return OffsetEncoder(offset, isStatic).result; 33 | } 34 | 35 | static std::tuple decodeOffset(jlong encoded) { 36 | return OffsetEncoder(encoded).decode(); 37 | }; 38 | 39 | void test(int offset, bool isStatic) { 40 | auto encoded = encodeOffset(offset, isStatic); 41 | int decodedOffset; 42 | bool decodedIsStatic; 43 | std::tie(decodedOffset, decodedIsStatic) = decodeOffset(encoded); 44 | if (decodedOffset != offset 45 | || decodedIsStatic != isStatic) { 46 | printf("expected: offset = %d, isStatic = %s, but got offset = %d, isStatic = %s\n", 47 | offset, isStatic ? "true" : "false", 48 | decodedOffset, decodedIsStatic ? "true" : "false"); 49 | assert(false); 50 | } 51 | } 52 | 53 | int main() { 54 | for (int i = 0; i < INT16_MAX; ++i) { 55 | test(i, true); 56 | test(i, false); 57 | } 58 | 59 | int offset; 60 | bool isStatic; 61 | std::tie(offset, isStatic) = decodeOffset(0); 62 | assert(offset >= 0); 63 | } 64 | -------------------------------------------------------------------------------- /src/shared/filesystem.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/21. 3 | // 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace kivm { 15 | bool FileSystem::isDirectory(const String &path) { 16 | struct stat s{}; 17 | if (stat(strings::toStdString(path).c_str(), &s) == 0) { 18 | return S_ISDIR(s.st_mode); 19 | } 20 | return false; 21 | } 22 | 23 | bool FileSystem::canRead(const String &path) { 24 | int r = access(strings::toStdString(path).c_str(), R_OK); 25 | return r == 0; 26 | } 27 | 28 | void *FileSystem::createFileMapping(const String &path, int *pFd, size_t *pSize) { 29 | int fd = open(strings::toStdString(path).c_str(), O_RDONLY); 30 | if (fd < 0) { 31 | return nullptr; 32 | } 33 | size_t size = FileSystem::getFileSize(path); 34 | auto m = (jbyte *) mmap(nullptr, size, 35 | PROT_READ, 36 | MAP_SHARED, fd, 0); 37 | if (m == MAP_FAILED) { 38 | return nullptr; 39 | } 40 | *pFd = fd; 41 | *pSize = size; 42 | return m; 43 | } 44 | 45 | void FileSystem::destroyFileMapping(void *memory, int fd, size_t size) { 46 | if (memory != nullptr) { 47 | munmap(memory, size); 48 | close(fd); 49 | } 50 | } 51 | 52 | size_t FileSystem::getFileSize(const String &path) { 53 | struct stat s{}; 54 | if (stat(strings::toStdString(path).c_str(), &s) == 0) { 55 | return (size_t) s.st_size; 56 | } 57 | return 0; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /include/kivm/memory/copyingHeap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/19. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace kivm { 13 | class CopyingHeap : public CollectedHeap { 14 | private: 15 | jbyte *_memoryStart = nullptr; 16 | size_t _totalSize; 17 | HeapRegion *_regions = nullptr; 18 | HeapRegion *_currentRegion = nullptr; 19 | HeapRegion *_nextRegion = nullptr; 20 | 21 | private: 22 | void initializeRegions(); 23 | 24 | void copyObject(HeapRegion *newRegion, HashMap &map, oop &target); 25 | 26 | void copyClass(HeapRegion *newRegion, HashMap &map, Klass *klass); 27 | 28 | void copyThread(HeapRegion *newRegion, HashMap &map, JavaThread *thread); 29 | 30 | void copySlotArray(HeapRegion *newRegion, HashMap &map, SlotArray *slotArray, int size); 31 | 32 | public: 33 | CopyingHeap(); 34 | 35 | ~CopyingHeap() override; 36 | 37 | void *allocate(size_t size) override; 38 | 39 | void initializeAll() override; 40 | 41 | void doGarbageCollection() override; 42 | 43 | inline void *getHeapStart() override { 44 | return _memoryStart; 45 | } 46 | 47 | inline void *getHeapEnd() override { 48 | return _memoryStart + getHeapSize(); 49 | } 50 | 51 | inline size_t getHeapSize() override { 52 | return _totalSize; 53 | } 54 | 55 | inline bool isHeapObject(void *addr) override { 56 | return addr >= getHeapStart() && addr < getHeapEnd(); 57 | } 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /tests/bench-map.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/20. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define TIMES 1000000 12 | 13 | using namespace kivm; 14 | 15 | void bench(const char *tag, void(*func)()) { 16 | auto start = std::chrono::system_clock::now(); 17 | func(); 18 | auto end = std::chrono::system_clock::now(); 19 | auto cost = end - start; 20 | printf("benchmark %s: %lld\n", tag, cost.count()); 21 | } 22 | 23 | void benchSppWithString() { 24 | spp::sparse_hash_map m; 25 | for (int i = 0; i < TIMES; ++i) { 26 | m.insert(std::make_pair(std::to_string(i), "hello fuck")); 27 | } 28 | } 29 | 30 | void benchStdWithString() { 31 | std::unordered_map m; 32 | for (int i = 0; i < TIMES; ++i) { 33 | m.insert(std::make_pair(std::to_string(i), "hello fuck")); 34 | } 35 | } 36 | 37 | void benchSppWithWString() { 38 | spp::sparse_hash_map m; 39 | for (int i = 0; i < TIMES; ++i) { 40 | m.insert(std::make_pair(std::to_wstring(i), L"hello fuck")); 41 | } 42 | } 43 | 44 | void benchStdWithWString() { 45 | std::unordered_map m; 46 | for (int i = 0; i < TIMES; ++i) { 47 | m.insert(std::make_pair(std::to_wstring(i), L"hello fuck")); 48 | } 49 | } 50 | 51 | int main() { 52 | bench("spp ", benchSppWithString); 53 | bench("std ", benchStdWithString); 54 | bench("spp", benchSppWithWString); 55 | bench("std", benchStdWithWString); 56 | } 57 | -------------------------------------------------------------------------------- /src/kivm/oop/arrayOop.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | namespace kivm { 9 | arrayOopDesc::arrayOopDesc(ArrayKlass *arrayClass, oopType type, int length) 10 | : oopDesc(arrayClass, type) { 11 | _elements.resize(static_cast(length)); 12 | } 13 | 14 | typeArrayOopDesc::typeArrayOopDesc(TypeArrayKlass *arrayClass, int length) 15 | : arrayOopDesc(arrayClass, oopType::TYPE_ARRAY_OOP, length) { 16 | switch (arrayClass->getComponentType()) { 17 | case ValueType::INT: 18 | case ValueType::CHAR: 19 | case ValueType::BYTE: 20 | case ValueType::SHORT: 21 | case ValueType::BOOLEAN: 22 | for (int i = 0; i < getLength(); ++i) { 23 | this->_elements[i] = new intOopDesc(0); 24 | } 25 | break; 26 | case ValueType::FLOAT: 27 | for (int i = 0; i < getLength(); ++i) { 28 | this->_elements[i] = new floatOopDesc(0.0f); 29 | } 30 | break; 31 | case ValueType::LONG: 32 | for (int i = 0; i < getLength(); ++i) { 33 | this->_elements[i] = new longOopDesc(0L); 34 | } 35 | break; 36 | case ValueType::DOUBLE: 37 | for (int i = 0; i < getLength(); ++i) { 38 | this->_elements[i] = new doubleOopDesc(0.0); 39 | } 40 | break; 41 | 42 | default: 43 | SHOULD_NOT_REACH_HERE(); 44 | } 45 | } 46 | 47 | objectArrayOopDesc::objectArrayOopDesc(ObjectArrayKlass *arrayClass, int length) 48 | : arrayOopDesc(arrayClass, oopType::OBJECT_ARRAY_OOP, length) { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/kivm/native/java_security_AccessController.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/30. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace kivm; 11 | 12 | JAVA_NATIVE jobject Java_java_security_AccessController_doPrivileged(JNIEnv *env, 13 | jclass java_security_AccessController, 14 | jobject javaPrivilegedExceptionAction) { 15 | auto actionOop = Resolver::instance(javaPrivilegedExceptionAction); 16 | if (actionOop == nullptr) { 17 | auto thread = Threads::currentThread(); 18 | assert(thread != nullptr); 19 | thread->throwException(Global::_NullPointerException, false); 20 | return nullptr; 21 | } 22 | 23 | // there are many versions of doPrivileged(). 24 | // but we can do the simplest one 25 | auto actionClass = (InstanceKlass *) actionOop->getClass(); 26 | auto run = actionClass->getVirtualMethod(L"run", L"()Ljava/lang/Object;"); 27 | if (run == nullptr) { 28 | PANIC("no run() method found"); 29 | return nullptr; 30 | } 31 | 32 | auto currentThread = Threads::currentThread(); 33 | if (currentThread == nullptr) { 34 | PANIC("currentThread cannot be null"); 35 | } 36 | 37 | D("native: AccessController.doPrivileged(): performing privileged actions"); 38 | oop result = JavaCall::withArgs(currentThread, run, {actionOop}); 39 | 40 | return result; 41 | } 42 | 43 | JAVA_NATIVE jobject Java_java_security_AccessController_getStackAccessControlContext(JNIEnv *env, 44 | jclass java_security_AccessController) { 45 | return nullptr; 46 | } 47 | -------------------------------------------------------------------------------- /src/kivm/bytecode/bytecodeInterpreter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/21. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "sharedInterpreter.h" 18 | 19 | #define BEGIN(code, pc) \ 20 | while ((code).validateOffset(pc)) \ 21 | switch ((code)[(pc)++]) { 22 | #define OTHERWISE() \ 23 | default: 24 | #define NEXT() break 25 | #define END() } 26 | 27 | #ifdef KIVM_INTERPRETER_DEBUG 28 | #define OPCODE(opcode) \ 29 | case OPC_##opcode: \ 30 | D("interpreter: pc: %d, opcode: %d, name: %s", pc - 1, codeBlob[pc - 1], #opcode); 31 | #else 32 | #define OPCODE(opcode) \ 33 | case OPC_##opcode: 34 | #endif 35 | 36 | namespace kivm { 37 | void ByteCodeInterpreter::initialize() { 38 | // do nothing 39 | } 40 | 41 | oop ByteCodeInterpreter::interp(JavaThread *thread) { 42 | Frame *currentFrame = thread->getCurrentFrame(); 43 | auto currentMethod = currentFrame->getMethod(); 44 | auto currentClass = currentMethod->getClass(); 45 | const CodeBlob &codeBlob = currentMethod->getCodeBlob(); 46 | u4 &pc = thread->_pc; 47 | 48 | D("currentMethod: %S.%S:%S", 49 | (currentClass->getName()).c_str(), 50 | (currentMethod->getName()).c_str(), 51 | (currentMethod->getDescriptor()).c_str()); 52 | 53 | Stack &stack = currentFrame->getStack(); 54 | Locals &locals = currentFrame->getLocals(); 55 | 56 | thread->enterSafepointIfNeeded(); 57 | 58 | #include "instruction.cpp-inc" 59 | 60 | return nullptr; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /include/kivm/oop/arrayOop.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace kivm { 12 | class arrayOopDesc : public oopDesc { 13 | // copyArrayTo() needs to use _elements 14 | friend class TypeArrayKlass; 15 | friend class ObjectArrayKlass; 16 | 17 | friend class CopyingHeap; 18 | 19 | protected: 20 | std::vector _elements; 21 | 22 | private: 23 | explicit arrayOopDesc(arrayOop other) 24 | : oopDesc(other->getClass(), other->getMarkOop()->getOopType()), 25 | _elements(other->_elements) { 26 | } 27 | 28 | public: 29 | explicit arrayOopDesc(ArrayKlass *arrayClass, oopType type, int length); 30 | 31 | inline arrayOop copy() override { 32 | return new arrayOopDesc(this); 33 | } 34 | 35 | inline int getDimension() const { 36 | return ((ArrayKlass *) getClass())->getDimension(); 37 | } 38 | 39 | inline int getLength() const { 40 | return static_cast(_elements.size()); 41 | } 42 | 43 | inline oop getElementAt(int position) const { 44 | assert(position >= 0 && position < getLength()); 45 | return _elements[position]; 46 | } 47 | 48 | inline void setElementAt(int position, oop element) { 49 | assert(position >= 0 && position < getLength()); 50 | _elements[position] = element; 51 | } 52 | 53 | inline oop* getElementUnsafe(int position) { 54 | assert(position >= 0 && position < getLength()); 55 | return &_elements[position]; 56 | } 57 | }; 58 | 59 | class typeArrayOopDesc : public arrayOopDesc { 60 | public: 61 | typeArrayOopDesc(TypeArrayKlass *arrayClass, int length); 62 | }; 63 | 64 | class objectArrayOopDesc : public arrayOopDesc { 65 | public: 66 | objectArrayOopDesc(ObjectArrayKlass *arrayClass, int length); 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /src/kivm/native/java_lang_reflect_Array.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/24. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace kivm; 12 | 13 | JAVA_NATIVE jarray Java_java_lang_reflect_Array_newArray(JNIEnv *env, jclass unused, 14 | jclass componentMirror, jint length) { 15 | auto comp = Resolver::mirror(componentMirror); 16 | 17 | if (comp->isPrimitiveMirror()) { 18 | auto valueType = comp->getPrimitiveType(); 19 | if (valueType == ValueType::VOID) { 20 | PANIC("wtf"); 21 | } 22 | 23 | auto arrayClassName = L"[" + valueTypeToPrimitiveTypeDesc(valueType); 24 | auto klass = (TypeArrayKlass *) BootstrapClassLoader::get()->loadClass(arrayClassName); 25 | return klass->newInstance(length); 26 | } 27 | 28 | auto target = comp->getTarget(); 29 | switch (target->getClassType()) { 30 | case ClassType::INSTANCE_CLASS: { 31 | auto klass = (InstanceKlass *) target; 32 | auto arrayClassName = L"[L" + klass->getName() + L";"; 33 | auto arrayKlass = (ObjectArrayKlass *) klass->getClassLoader()->loadClass(arrayClassName); 34 | return arrayKlass->newInstance(length); 35 | } 36 | 37 | case ClassType::TYPE_ARRAY_CLASS: { 38 | auto klass = (TypeArrayKlass *) target; 39 | auto arrayClassName = L"[" + klass->getName(); 40 | auto arrayKlass = (TypeArrayKlass *) klass->getClassLoader()->loadClass(arrayClassName); 41 | return arrayKlass->newInstance(length); 42 | } 43 | 44 | case ClassType::OBJECT_ARRAY_CLASS: { 45 | auto klass = (ObjectArrayKlass *) target; 46 | auto arrayClassName = L"[" + klass->getName(); 47 | auto arrayKlass = (ObjectArrayKlass *) klass->getClassLoader()->loadClass(arrayClassName); 48 | return arrayKlass->newInstance(length); 49 | } 50 | } 51 | 52 | SHOULD_NOT_REACH_HERE(); 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /include/kivm/bytecode2/template.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-06-28. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace kivm { 12 | class TemplateTable; 13 | 14 | // A Template describes the properties of a code template for a given bytecode 15 | // and provides a generator to generate the code template. 16 | class Template { 17 | friend class TemplateTable; 18 | 19 | private: 20 | enum Flags { 21 | usesBcpBit, // set if template needs the bcp pointing to bytecode 22 | doesDispatchBit, // set if template dispatches on its own 23 | callsVMBit, // set if template calls the vm 24 | wideBit // set if template belongs to a wide instruction 25 | }; 26 | 27 | typedef void (*generator)(int arg); 28 | 29 | int _flags; // describes interpreter template properties (bcp unknown) 30 | TosState _tosIn; // tos cache state before template execution 31 | TosState _tosOut; // tos cache state after template execution 32 | generator _gen; // template code generator 33 | int _arg; // argument for template code generator 34 | 35 | void initialize(int flags, TosState tosIn, TosState tosOut, generator gen, int arg); 36 | 37 | public: 38 | Bytecodes::Code getBytecode() const; 39 | 40 | bool isValid() const { return _gen != nullptr; } 41 | 42 | bool usesBcp() const { return (_flags & (1 << usesBcpBit)) != 0; } 43 | 44 | bool doesDispatch() const { return (_flags & (1 << doesDispatchBit)) != 0; } 45 | 46 | bool callsVM() const { return (_flags & (1 << callsVMBit)) != 0; } 47 | 48 | bool isWide() const { return (_flags & (1 << wideBit)) != 0; } 49 | 50 | TosState tosIn() const { return _tosIn; } 51 | 52 | TosState tosOut() const { return _tosOut; } 53 | 54 | void generate(InterpreterMacroAssembler *masm); 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /src/kivm/native/sun_reflect_Reflection.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/29. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace kivm; 13 | 14 | JAVA_NATIVE jobject Java_sun_reflect_Reflection_getCallerClass(JNIEnv *env, jclass sun_reflect_Reflection) { 15 | auto currentThread = Threads::currentThread(); 16 | if (currentThread == nullptr) { 17 | PANIC("currentThread cannot be null"); 18 | } 19 | 20 | auto currentFrame = currentThread->getCurrentFrame(); 21 | auto previousFrame = currentFrame->getPrevious(); 22 | Frame *found = nullptr; 23 | 24 | if (currentFrame->getMethod()->getName() != L"getCallerClass") { 25 | PANIC("getCallerClass(): current method should be getCallerClass()"); 26 | } 27 | 28 | while (previousFrame != nullptr) { 29 | D("getCallerClass(): walk %S", 30 | (previousFrame->getMethod()->getName()).c_str()); 31 | 32 | // ignore some special methods and annotations (sun/reflect/CallerSensitive, etc.) 33 | if (previousFrame->getMethod()->checkAnnotation(L"Lsun/reflect/CallerSensitive;")) { 34 | previousFrame = previousFrame->getPrevious(); 35 | continue; 36 | } 37 | 38 | found = previousFrame; 39 | break; 40 | } 41 | 42 | if (found == nullptr) { 43 | PANIC("getCallerClass(): not previous frame available"); 44 | } 45 | 46 | D("getCallerClass(): found caller class: %S", 47 | (found->getMethod()->getClass()->getName()).c_str()); 48 | 49 | return found->getMethod()->getClass()->getJavaMirror(); 50 | } 51 | 52 | JAVA_NATIVE jint Java_java_lang_Class_getModifiers(JNIEnv *env, jobject mirror); 53 | 54 | JAVA_NATIVE jint Java_sun_reflect_Reflection_getClassAccessFlags(JNIEnv *env, 55 | jclass sun_reflect_Reflection, 56 | jobject java_lang_Class_mirror) { 57 | return Java_java_lang_Class_getModifiers(env, java_lang_Class_mirror); 58 | } 59 | -------------------------------------------------------------------------------- /include/kivm/runtime/frameWalker.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/6/7. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace kivm { 10 | class FrameIterator : public std::iterator { 11 | private: 12 | Frame *_start = nullptr; 13 | Frame *_current = nullptr; 14 | 15 | public: 16 | explicit FrameIterator(Frame *start) 17 | : _start(start), _current(start) { 18 | } 19 | 20 | FrameIterator &operator=(const FrameIterator &rhs) { 21 | this->_start = rhs._start; 22 | this->_current = rhs._current; 23 | return *this; 24 | } 25 | 26 | bool operator==(const FrameIterator &rhs) const { 27 | return _current == rhs._current; 28 | } 29 | 30 | bool operator!=(const FrameIterator &rhs) const { 31 | return !(rhs == *this); 32 | } 33 | 34 | FrameIterator &operator++() { 35 | if (_current != nullptr) { 36 | _current = _current->getPrevious(); 37 | } 38 | return *this; 39 | } 40 | 41 | FrameIterator &operator--() { 42 | return *this; 43 | } 44 | 45 | Frame *operator*() const { 46 | return _current; 47 | } 48 | 49 | Frame *operator->() const { 50 | return _current; 51 | } 52 | }; 53 | 54 | class FrameWalker final { 55 | private: 56 | FrameIterator _iterator; 57 | size_t _size; 58 | bool _recording; 59 | 60 | public: 61 | explicit FrameWalker(JavaThread *thread) 62 | : _iterator(thread->_frames.getCurrentFrame()), 63 | _size(static_cast(thread->_frames.getSize())), 64 | _recording(false) { 65 | } 66 | 67 | inline void startRecording() { 68 | this->_recording = true; 69 | } 70 | 71 | inline bool isRecording() const { 72 | return this->_recording; 73 | } 74 | 75 | inline size_t getSize() const { 76 | return _size; 77 | } 78 | 79 | inline FrameIterator begin() { 80 | return _iterator; 81 | } 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /src/bin/java.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char **argv) { 10 | using namespace kivm; 11 | using namespace clipp; 12 | 13 | std::string optClassPath; 14 | std::string optClassName; 15 | std::vector optArgs; 16 | bool optShowHelp = false; 17 | 18 | auto cli = ( 19 | option("-h", "-help").call([&]() { optShowHelp = true; }) % "show help", 20 | option("-v", "-version").call([argv]() { 21 | fprintf(stderr, "%s: %s\n", argv[0], KIVM_VERSION_STRING); 22 | }) % "show version", 23 | (option("-cp") & value("path").set(optClassPath)) % "class search path", 24 | value("class-name").set(optClassName), 25 | opt_values("args", optArgs) 26 | ); 27 | 28 | if (!parse(argc, argv, cli) || optShowHelp) { 29 | auto fmt = doc_formatting{}.doc_column(28); 30 | auto filter = param_filter{}.prefix("-"); 31 | std::cerr << "Usage:\n" << usage_lines(cli, argv[0]) << "\n\n" 32 | << "Options:\n" << documentation(cli, fmt, filter) << "\n\n"; 33 | return optShowHelp ? 0 : 1; 34 | } 35 | 36 | 37 | String mainClassName = strings::replaceAll(strings::fromStdString(optClassName), 38 | Global::DOT, Global::SLASH); 39 | D("java: main class name: %S\n", (mainClassName).c_str()); 40 | 41 | JavaVM *javaVM = nullptr; 42 | JNIEnv *env = nullptr; 43 | if (JNI_CreateJavaVM(&javaVM, (void **) &env, nullptr) != JNI_OK) { 44 | PANIC("JNI_CreateJavaVM() failed"); 45 | } 46 | 47 | std::vector arguments; 48 | arguments.reserve(optArgs.size()); 49 | for (const auto &a : optArgs) { 50 | arguments.push_back(strings::fromStdString(a)); 51 | } 52 | 53 | if (!optClassPath.empty()) { 54 | ClassPathManager::get()->addClassPaths(strings::fromStdString(optClassPath)); 55 | } 56 | 57 | JavaMainThread javaMainThread(mainClassName, arguments); 58 | javaMainThread.start(); 59 | 60 | javaVM->DestroyJavaVM(); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | KiVM 2 | ============= 3 | [![Build Status](https://travis-ci.org/imkiva/KiVM.svg?branch=master)](https://travis-ci.org/imkiva/KiVM) 4 | [![GitHub top language](https://img.shields.io/github/languages/top/imkiva/KiVM.svg)](https://github.com/imkiva/KiVM) 5 | [![license](https://img.shields.io/github/license/imkiva/KiVM.svg?colorB=000000)](https://github.com/imkiva/KiVM) 6 | 7 | Kiva's Java Virtual Machine. 8 | 9 | ### Features 10 | - JNI Support 11 | - JAR Class Loading Support (libzip needed) 12 | - Full OracleJDK/OpenJDK compatibility 13 | - Copying Garbage Collector 14 | 15 | ### Build 16 | 1. Requirements 17 | * Linux, macOS, or Windows(untested) . 18 | * JDK (OpenJDK or OracleJDK) (>= 8) 19 | * CMake (>= 3.2) 20 | * libzip (>= 1.5.1) (to support JAR Class Loading) 21 | 22 | 2. Build instructions 23 | * Clone this repo. 24 | * `cd` into your directory that contains KiVM source code. 25 | * Type `cmake . && make` in your terminal app. 26 | * Enjoy it! 27 | 28 | ### Usage 29 | ``` 30 | Usage: 31 | java [-?] [-v] [-cp ] [-classpath ] []... 32 | 33 | Options: 34 | -?, -help show help 35 | -v, -version show version 36 | -cp class search path 37 | -classpath same as -cp 38 | name of the class to run 39 | 40 | ``` 41 | 42 | ### Credit 43 | * Inspired by [wind_jvm](https://github.com/wind2412/wind_jvm) 44 | * Modified version of [libzippp](https://github.com/ctabin/libzippp) 45 | * Command line options parsing using [clipp](https://github.com/muellan/clipp) 46 | 47 | ## Acknowledge 48 | 49 | We would like to thank [JetBrains](https://www.jetbrains.com/?from=mozart++) for sharing free 50 | open-source licences of amazing tools such as [CLion](https://www.jetbrains.com/idea/?from=mozart++). 51 | 52 | [](https://www.jetbrains.com/?from=mozart++) 53 | 54 | ### See Also 55 | * [HiVM](https://github.com/imkiva/HiVM) 56 | * [The Java Virtual Machine Specification Java SE 8 Edition](https://docs.oracle.com/javase/specs/jvms/se8/html/) 57 | * [HotSpot Virtual Machine Garbage Collection Tuning Guide](https://docs.oracle.com/en/java/javase/11/gctuning/preface.html#GUID-5650179B-DC2A-4F25-B2C6-F3961C93FD07) 58 | 59 | -------------------------------------------------------------------------------- /include/sparsepp/spp_timer.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2016 Mariano Gonzalez 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef spp_timer_h_guard 24 | #define spp_timer_h_guard 25 | 26 | #include 27 | 28 | namespace spp 29 | { 30 | template 31 | class Timer 32 | { 33 | public: 34 | Timer() { reset(); } 35 | void reset() { _start = _snap = clock::now(); } 36 | void snap() { _snap = clock::now(); } 37 | 38 | float get_total() const { return get_diff(_start, clock::now()); } 39 | float get_delta() const { return get_diff(_snap, clock::now()); } 40 | 41 | private: 42 | using clock = std::chrono::high_resolution_clock; 43 | using point = std::chrono::time_point; 44 | 45 | template 46 | static T get_diff(const point& start, const point& end) 47 | { 48 | using duration_t = std::chrono::duration; 49 | 50 | return std::chrono::duration_cast(end - start).count(); 51 | } 52 | 53 | point _start; 54 | point _snap; 55 | }; 56 | } 57 | 58 | #endif // spp_timer_h_guard 59 | -------------------------------------------------------------------------------- /tests/test-native-image.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019/8/31. 3 | // 4 | 5 | #include 6 | 7 | #define LINEBREAK 12 8 | #define MAIN_CLASS_BYTES "__MAIN_CLASS_BYTES" 9 | #define MAIN_CLASS_SIZE "__MAIN_CLASS_SIZE" 10 | 11 | void printHeaders() { 12 | printf("#include \n"); 13 | printf("#include \n"); 14 | printf("#include \n"); 15 | } 16 | 17 | void printFiles(const char *fileName) { 18 | FILE *file = fopen(fileName, "rb"); 19 | fseek(file, 0, SEEK_END); 20 | long fileSize = ftell(file); 21 | fseek(file, 0, SEEK_SET); 22 | 23 | int lineBreakCounter = 0; 24 | printf("unsigned char " MAIN_CLASS_BYTES "[] = {\n"); 25 | printf(" "); 26 | while (!feof(file)) { 27 | int c = fgetc(file); 28 | if (c != EOF) { 29 | printf("0x%02x, ", c); 30 | } 31 | ++lineBreakCounter; 32 | if (lineBreakCounter % LINEBREAK == 0) { 33 | printf("\n"); 34 | printf(" "); 35 | } 36 | } 37 | printf("\n};\n"); 38 | 39 | printf("unsigned long " MAIN_CLASS_SIZE " = %ld;\n", fileSize); 40 | } 41 | 42 | void printEntrance() { 43 | printf("\n\n"); 44 | printf("int main(int argc, const char **argv) {\n"); 45 | printf(" using namespace kivm;\n"); 46 | printf(" JavaVM *javaVM = nullptr;\n"); 47 | printf(" JNIEnv *env = nullptr;\n"); 48 | printf(" if (JNI_CreateJavaVM(&javaVM, (void **) &env, nullptr) != JNI_OK) {\n"); 49 | printf(" PANIC(\"JNI_CreateJavaVM() failed\");\n"); 50 | printf(" }\n"); 51 | printf(" std::vector arguments;\n"); 52 | printf(" ++argv;\n"); 53 | printf(" for (const char **p = argv; *p; p++) {\n"); 54 | printf(" arguments.push_back(strings::fromStdString(std::string(*p)));\n"); 55 | printf(" }\n"); 56 | printf("\n"); 57 | printf(" JavaMainThread javaMainThread(" MAIN_CLASS_BYTES ", " MAIN_CLASS_SIZE ", arguments);\n"); 58 | printf(" javaMainThread.start();\n"); 59 | printf("\n"); 60 | printf(" javaVM->DestroyJavaVM();\n"); 61 | printf(" return 0;\n"); 62 | printf("}\n"); 63 | } 64 | 65 | int main(int argc, const char **argv) { 66 | if (argc < 2) { 67 | fprintf(stderr, "Usage: %s \n", argv[0]); 68 | return 1; 69 | } 70 | 71 | printHeaders(); 72 | printFiles(argv[1]); 73 | printEntrance(); 74 | } 75 | -------------------------------------------------------------------------------- /include/sparsepp/spp_smartptr.h: -------------------------------------------------------------------------------- 1 | #if !defined(spp_smartptr_h_guard) 2 | #define spp_smartptr_h_guard 3 | 4 | 5 | /* ----------------------------------------------------------------------------------------------- 6 | * quick version of intrusive_ptr 7 | * ----------------------------------------------------------------------------------------------- 8 | */ 9 | 10 | #include 11 | #include "spp_config.h" 12 | 13 | // ------------------------------------------------------------------------ 14 | class spp_rc 15 | { 16 | public: 17 | spp_rc() : _cnt(0) {} 18 | spp_rc(const spp_rc &) : _cnt(0) {} 19 | void increment() const { ++_cnt; } 20 | void decrement() const { assert(_cnt); if (--_cnt == 0) delete this; } 21 | unsigned count() const { return _cnt; } 22 | 23 | protected: 24 | virtual ~spp_rc() {} 25 | 26 | private: 27 | mutable unsigned _cnt; 28 | }; 29 | 30 | // ------------------------------------------------------------------------ 31 | template 32 | class spp_sptr 33 | { 34 | public: 35 | spp_sptr() : _p(0) {} 36 | spp_sptr(T *p) : _p(p) { if (_p) _p->increment(); } 37 | spp_sptr(const spp_sptr &o) : _p(o._p) { if (_p) _p->increment(); } 38 | #ifndef SPP_NO_CXX11_RVALUE_REFERENCES 39 | spp_sptr(spp_sptr &&o) : _p(o._p) { o._p = (T *)0; } 40 | spp_sptr& operator=(spp_sptr &&o) 41 | { 42 | if (_p) _p->decrement(); 43 | _p = o._p; 44 | o._p = (T *)0; 45 | } 46 | #endif 47 | ~spp_sptr() { if (_p) _p->decrement(); } 48 | spp_sptr& operator=(const spp_sptr &o) { reset(o._p); return *this; } 49 | T* get() const { return _p; } 50 | void swap(spp_sptr &o) { T *tmp = _p; _p = o._p; o._p = tmp; } 51 | void reset(const T *p = 0) 52 | { 53 | if (p == _p) 54 | return; 55 | if (_p) _p->decrement(); 56 | _p = (T *)p; 57 | if (_p) _p->increment(); 58 | } 59 | T* operator->() const { return const_cast(_p); } 60 | bool operator!() const { return _p == 0; } 61 | 62 | private: 63 | T *_p; 64 | }; 65 | 66 | // ------------------------------------------------------------------------ 67 | namespace std 68 | { 69 | template 70 | inline void swap(spp_sptr &a, spp_sptr &b) 71 | { 72 | a.swap(b); 73 | } 74 | } 75 | 76 | #endif // spp_smartptr_h_guard 77 | -------------------------------------------------------------------------------- /include/kivm/oop/oop.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace kivm { 15 | 16 | class GCJavaObject { 17 | public: 18 | GCJavaObject() = default; 19 | 20 | virtual ~GCJavaObject() = default; 21 | 22 | static void *allocate(size_t size); 23 | 24 | static void deallocate(void *ptr); 25 | 26 | static void *operator new(size_t size, bool = true) noexcept; 27 | 28 | static void *operator new(size_t size, const std::nothrow_t &) noexcept = delete; 29 | 30 | static void *operator new[](size_t size, bool = true) throw(); 31 | 32 | static void *operator new[](size_t size, const std::nothrow_t &) noexcept = delete; 33 | 34 | static void operator delete(void *ptr); 35 | 36 | static void operator delete[](void *ptr); 37 | }; 38 | 39 | class markOopDesc final { 40 | private: 41 | oopType _type; 42 | Monitor _monitor; 43 | jint _hash; 44 | 45 | public: 46 | explicit markOopDesc(oopType type); 47 | 48 | oopType getOopType() const { return _type; } 49 | 50 | void monitorEnter() { 51 | _monitor.enter(); 52 | } 53 | 54 | void monitorExit() { 55 | _monitor.leave(); 56 | } 57 | 58 | inline void setHash(jint hash) { 59 | this->_hash = hash; 60 | } 61 | 62 | inline jint getHash() const { 63 | return this->_hash; 64 | } 65 | 66 | inline void wait() { _monitor.wait(); } 67 | 68 | inline void wait(jlong timeout) { _monitor.wait((jlong) timeout); } 69 | 70 | inline void notify() { _monitor.notify(); } 71 | 72 | inline void notifyAll() { _monitor.notifyAll(); } 73 | 74 | inline void forceUnlockWhenExceptionOccurred() { _monitor.forceUnlock(); } 75 | }; 76 | 77 | class oopDesc : public GCJavaObject { 78 | private: 79 | markOop _mark = nullptr; 80 | Klass *_klass = nullptr; 81 | 82 | public: 83 | explicit oopDesc(Klass *klass, oopType type); 84 | 85 | ~oopDesc() override; 86 | 87 | markOop getMarkOop() const { return _mark; } 88 | 89 | Klass *getClass() const { return _klass; } 90 | 91 | virtual oop copy() = 0; 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /src/kivm/classfile/constantPool.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | namespace kivm { 9 | jint CONSTANT_Integer_info::getConstant() const { 10 | return static_cast(bytes); 11 | } 12 | 13 | jfloat CONSTANT_Float_info::getConstant() const { 14 | if (FLOAT_IS_POSITIVE_INFINITY(bytes)) { 15 | return _FLOAT_POSITIVE_INFINITY; 16 | 17 | } else if (FLOAT_IS_NEGATIVE_INFINITY(bytes)) { 18 | return _FLOAT_NEGATIVE_INFINITY; 19 | 20 | } else if (FLOAT_IS_NAN(bytes)) { 21 | return FLOAT_NAN; 22 | 23 | } else { 24 | int s = ((bytes >> 31) == 0) ? 1 : -1; 25 | int e = ((bytes >> 23) & 0xff); 26 | int m = (e == 0) 27 | ? (bytes & 0x7fffff) << 1 28 | : (bytes & 0x7fffff) | 0x800000; 29 | return static_cast(s * m * pow(2, e - 150)); 30 | } 31 | } 32 | 33 | jlong CONSTANT_Long_info::getConstant() const { 34 | return ((jlong) high_bytes << 32) + low_bytes; 35 | } 36 | 37 | jdouble CONSTANT_Double_info::getConstant() const { 38 | jlong bits = ((jlong) high_bytes << 32) + low_bytes; 39 | 40 | if (DOUBLE_IS_POSITIVE_INFINITY(bits)) { 41 | return _DOUBLE_POSITIVE_INFINITY; 42 | 43 | } else if (DOUBLE_IS_NEGATIVE_INFINITY(bits)) { 44 | return _DOUBLE_NEGATIVE_INFINITY; 45 | 46 | } else if (DOUBLE_IS_NAN(bits)) { 47 | return DOUBLE_NAN; 48 | 49 | } else { 50 | int s = ((bits >> 63) == 0) ? 1 : -1; 51 | int e = (int) ((bits >> 52) & 0x7ffL); 52 | long m = (e == 0) 53 | ? (bits & 0xfffffffffffffL) << 1 54 | : (bits & 0xfffffffffffffL) | 0x10000000000000L; 55 | return s * m * pow(2, e - 1075); 56 | } 57 | } 58 | 59 | String CONSTANT_Utf8_info::getConstant() { 60 | // UTF-8 Strings in Java needs to be Unicode in C++ 61 | if (!_cached) { 62 | _cached_string = kivm::strings::fromBytes(bytes, length); 63 | _cached = true; 64 | } 65 | 66 | return _cached_string; 67 | } 68 | 69 | CONSTANT_Utf8_info::CONSTANT_Utf8_info() : cp_info() { 70 | bytes = nullptr; 71 | _cached = false; 72 | } 73 | 74 | CONSTANT_Utf8_info::~CONSTANT_Utf8_info() { 75 | delete[] bytes; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /include/shared/arch/x86/atomic.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/5/13. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | #if KIVM_ARCH_x86 || KIVM_ARCH_x86_64 9 | 10 | #if KIVM_ARCH_x86_64 11 | #define mbarrier() asm volatile("mfence":::"memory") 12 | #define LOCK_PREFIX "\n\tlock; " 13 | #else 14 | #define mbarrier() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") 15 | #endif 16 | 17 | #define __X86_CASE_B 1 18 | #define __X86_CASE_W 2 19 | #define __X86_CASE_L 4 20 | #ifdef KIVM_ARCH_x86_64 21 | #define __X86_CASE_Q 8 22 | #else 23 | #define __X86_CASE_Q (-1) 24 | #endif 25 | 26 | #define __raw_cmpxchg(ptr, old, new_, size, lock) \ 27 | ({ \ 28 | __typeof__(*(ptr)) __ret; \ 29 | __typeof__(*(ptr)) __old = (old); \ 30 | __typeof__(*(ptr)) __new = (new_); \ 31 | switch (size) { \ 32 | case __X86_CASE_B: \ 33 | { \ 34 | volatile uint8_t *__ptr = (volatile uint8_t *)(ptr); \ 35 | asm volatile(lock "cmpxchgb %2,%1" \ 36 | : "=a" (__ret), "+m" (*__ptr) \ 37 | : "q" (__new), "0" (__old) \ 38 | : "memory"); \ 39 | break; \ 40 | } \ 41 | case __X86_CASE_W: \ 42 | { \ 43 | volatile uint16_t *__ptr = (volatile uint16_t *)(ptr); \ 44 | asm volatile(lock "cmpxchgw %2,%1" \ 45 | : "=a" (__ret), "+m" (*__ptr) \ 46 | : "r" (__new), "0" (__old) \ 47 | : "memory"); \ 48 | break; \ 49 | } \ 50 | case __X86_CASE_L: \ 51 | { \ 52 | volatile uint32_t *__ptr = (volatile uint32_t *)(ptr); \ 53 | asm volatile(lock "cmpxchgl %2,%1" \ 54 | : "=a" (__ret), "+m" (*__ptr) \ 55 | : "r" (__new), "0" (__old) \ 56 | : "memory"); \ 57 | break; \ 58 | } \ 59 | case __X86_CASE_Q: \ 60 | { \ 61 | volatile uint64_t *__ptr = (volatile uint64_t *)(ptr); \ 62 | asm volatile(lock "cmpxchgq %2,%1" \ 63 | : "=a" (__ret), "+m" (*__ptr) \ 64 | : "r" (__new), "0" (__old) \ 65 | : "memory"); \ 66 | break; \ 67 | } \ 68 | default: \ 69 | SHOULD_NOT_REACH_HERE(); \ 70 | } \ 71 | __ret; \ 72 | }) 73 | 74 | #define __cmpxchg(ptr, old, new_, size) \ 75 | __raw_cmpxchg((ptr), (old), (new_), (size), LOCK_PREFIX) 76 | 77 | #define cmpxchg(ptr, old, new_) \ 78 | __cmpxchg(ptr, old, new_, sizeof(*(ptr))) 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/kivm/jni/nativeMethod.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/11/13. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace kivm { 12 | class NativeMethodPool { 13 | private: 14 | HashMap _nativeMethods; 15 | 16 | public: 17 | static NativeMethodPool *get() { 18 | static NativeMethodPool pool; 19 | return &pool; 20 | } 21 | 22 | static Lock &nativeMethodPoolLock() { 23 | static Lock lock; 24 | return lock; 25 | } 26 | 27 | void set(Method *method, JavaNativeMethod *nativeMethod) { 28 | if (!method->isNative()) { 29 | return; 30 | } 31 | 32 | LockGuard lg(nativeMethodPoolLock()); 33 | _nativeMethods[method] = nativeMethod; 34 | } 35 | 36 | JavaNativeMethod *resolve(Method *method) { 37 | LockGuard lg(nativeMethodPoolLock()); 38 | auto it = _nativeMethods.find(method); 39 | if (it != _nativeMethods.end()) { 40 | return it->second; 41 | } 42 | 43 | std::wstringstream nativeSymbolBuilder; 44 | 45 | nativeSymbolBuilder 46 | << L"Java_" 47 | << strings::replaceAll(method->getClass()->getName(), Global::SLASH, Global::UNDERLINE) 48 | << Global::UNDERLINE 49 | << strings::replaceAll(method->getName(), Global::SLASH, Global::UNDERLINE); 50 | 51 | const String &nativeSymbolName = nativeSymbolBuilder.str(); 52 | D("Looking up symbol: %S", (nativeSymbolName).c_str()); 53 | dl::DLInterface dlInterface; 54 | dl::DLSymbol nativeSymbol = dlInterface.findSymbol(strings::toStdString(nativeSymbolName)); 55 | if (nativeSymbol != nullptr) { 56 | auto nativeMethod = new JavaNativeMethod(method, nativeSymbol); 57 | _nativeMethods.insert(std::make_pair(method, nativeMethod)); 58 | return nativeMethod; 59 | } 60 | return nullptr; 61 | } 62 | }; 63 | 64 | JavaNativeMethod *JavaNativeMethod::resolve(Method *method) { 65 | return NativeMethodPool::get()->resolve(method); 66 | } 67 | 68 | JavaNativeMethod::JavaNativeMethod(Method *method, JNIMethodPointer target) 69 | : _javaMethod(method), _invocationTarget(target) { 70 | } 71 | 72 | JavaNativeMethod::~JavaNativeMethod() = default; 73 | } 74 | -------------------------------------------------------------------------------- /java-src/com/imkiva/kivm/ThreadTest.java: -------------------------------------------------------------------------------- 1 | package com.imkiva.kivm; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class ThreadTest { 7 | private int nextGood = 0; 8 | private List goods = new ArrayList<>(); 9 | 10 | class Producer extends Thread { 11 | int id; 12 | 13 | public Producer(int id) { 14 | this.id = id; 15 | } 16 | 17 | @Override 18 | public void run() { 19 | while (true) { 20 | synchronized (Main.class) { 21 | while (goods.size() == 10) { 22 | try { 23 | Main.class.wait(); 24 | } catch (Exception ignore) { 25 | } 26 | } 27 | 28 | int good = nextGood++; 29 | goods.add(good); 30 | System.out.println("Producer #" + id + ": produced " + good); 31 | Main.class.notifyAll(); 32 | } 33 | 34 | try { 35 | Thread.sleep(1000); 36 | } catch (Exception e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | } 41 | } 42 | 43 | class Consumer extends Thread { 44 | int id; 45 | 46 | public Consumer(int id) { 47 | this.id = id; 48 | } 49 | 50 | @Override 51 | public void run() { 52 | while (true) { 53 | synchronized (Main.class) { 54 | while (goods.size() == 0) { 55 | try { 56 | Main.class.wait(); 57 | } catch (Exception ignore) { 58 | } 59 | } 60 | int good = goods.get(0); 61 | goods.remove(0); 62 | System.out.println("Consumer #" + id + " consumed " + good); 63 | Main.class.notifyAll(); 64 | } 65 | try { 66 | Thread.sleep(100); 67 | } catch (InterruptedException e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | } 72 | } 73 | 74 | public static void main(String[] args) { 75 | new ThreadTest().test(); 76 | } 77 | 78 | private void test() { 79 | for (int i = 0; i < 1; i++) { 80 | new Producer(i).start(); 81 | } 82 | for (int i = 0; i < 3; i++) { 83 | new Consumer(i).start(); 84 | } 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /src/kivm/native/java_lang_Thread.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/15. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace kivm; 17 | 18 | JAVA_NATIVE void Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass java_lang_Thread) { 19 | D("java/lang/Thread.registerNatives()V"); 20 | } 21 | 22 | JAVA_NATIVE jobject Java_java_lang_Thread_currentThread(JNIEnv *env, jclass java_lang_Thread) { 23 | auto currentThread = Threads::currentThread(); 24 | if (currentThread == nullptr) { 25 | PANIC("currentThread cannot be null"); 26 | } 27 | 28 | return currentThread->getJavaThreadObject(); 29 | } 30 | 31 | JAVA_NATIVE void Java_java_lang_Thread_setPriority0(JNIEnv *env, jobject threadObject, jint priority) { 32 | auto instanceOop = Resolver::instance(threadObject); 33 | auto thread = Threads::searchNativeThread(instanceOop); 34 | if (thread != nullptr) { 35 | // set native thread's priority 36 | thread->setPriority(priority); 37 | } 38 | } 39 | 40 | JAVA_NATIVE jboolean Java_java_lang_Thread_isAlive(JNIEnv *env, jobject threadObject) { 41 | auto threadOop = Resolver::instance(threadObject); 42 | longOop eetopOop = nullptr; 43 | if (!threadOop->getFieldValue(J_THREAD, L"eetop", L"J", (oop *) &eetopOop)) { 44 | SHOULD_NOT_REACH_HERE(); 45 | } 46 | 47 | if (eetopOop == nullptr) { 48 | return JNI_FALSE; 49 | } 50 | 51 | long eetop = eetopOop->getValue(); 52 | int ret = pthread_kill((pthread_t) eetop, 0); 53 | if (ret == 0) { 54 | return JNI_TRUE; 55 | } else if (ret == ESRCH) { 56 | return JNI_FALSE; 57 | } else { 58 | SHOULD_NOT_REACH_HERE(); 59 | } 60 | } 61 | 62 | JAVA_NATIVE void Java_java_lang_Thread_start0(JNIEnv *env, jobject threadObject) { 63 | auto threadOop = Resolver::instance(threadObject); 64 | auto klass = threadOop->getInstanceClass(); 65 | 66 | if (klass->getName() == L"java/lang/ref/Reference$ReferenceHandler") { 67 | return; 68 | } 69 | 70 | auto runMethod = klass->getVirtualMethod(L"run", L"()V"); 71 | assert(runMethod != nullptr); 72 | auto thread = new JavaThread(runMethod, {threadOop}); 73 | thread->start(threadOop); 74 | } 75 | 76 | JAVA_NATIVE void Java_java_lang_Thread_sleep(JNIEnv *env, jclass threadCls, jlong ms) { 77 | std::this_thread::sleep_for(std::chrono::milliseconds(ms)); 78 | } 79 | -------------------------------------------------------------------------------- /src/kivm/bytecode/resolver.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/6. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace kivm { 13 | oop Resolver::javaOop(jobject obj) { 14 | if (obj != nullptr && Universe::isHeapObject(obj)) { 15 | return (oop) obj; 16 | } 17 | return nullptr; 18 | } 19 | 20 | instanceOop Resolver::instance(jobject obj) { 21 | auto n = javaOop(obj); 22 | if (n == nullptr) { 23 | return nullptr; 24 | } 25 | 26 | if (n->getClass()->getClassType() == ClassType::INSTANCE_CLASS) { 27 | return (instanceOop) n; 28 | } 29 | return nullptr; 30 | } 31 | 32 | mirrorOop Resolver::mirror(jobject obj) { 33 | auto n = instance(obj); 34 | return (mirrorOop) n; 35 | } 36 | 37 | arrayOop Resolver::array(jarray obj) { 38 | auto n = javaOop(obj); 39 | if (n == nullptr) { 40 | return nullptr; 41 | } 42 | 43 | if (n->getClass()->getClassType() == ClassType::OBJECT_ARRAY_CLASS 44 | || n->getClass()->getClassType() == ClassType::TYPE_ARRAY_CLASS) { 45 | return (arrayOop) n; 46 | } 47 | return nullptr; 48 | } 49 | 50 | typeArrayOop Resolver::typeArray(jarray obj) { 51 | auto n = javaOop(obj); 52 | if (n == nullptr) { 53 | return nullptr; 54 | } 55 | 56 | if (n->getClass()->getClassType() == ClassType::TYPE_ARRAY_CLASS) { 57 | return (typeArrayOop) n; 58 | } 59 | return nullptr; 60 | } 61 | 62 | objectArrayOop Resolver::objectArray(jobjectArray obj) { 63 | auto n = javaOop(obj); 64 | if (n == nullptr) { 65 | return nullptr; 66 | } 67 | 68 | if (n->getClass()->getClassType() == ClassType::OBJECT_ARRAY_CLASS) { 69 | return (objectArrayOop) n; 70 | } 71 | return nullptr; 72 | } 73 | 74 | Klass *Resolver::javaClass(jclass clazz) { 75 | if (clazz != nullptr) { 76 | return (Klass *) clazz; 77 | } 78 | return nullptr; 79 | } 80 | 81 | InstanceKlass *Resolver::instanceClass(jclass clazz) { 82 | auto klass = Resolver::javaClass(clazz); 83 | if (klass == nullptr) { 84 | return nullptr; 85 | } 86 | 87 | if (klass->getClassType() == ClassType::INSTANCE_CLASS) { 88 | return (InstanceKlass *) klass; 89 | } 90 | return nullptr; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/kivm/classpath/classLoader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/27. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace kivm { 12 | static RecursiveLock &bootstrapLock() { 13 | static RecursiveLock lock; 14 | return lock; 15 | } 16 | 17 | Klass *ClassLoader::requireClass(ClassLoader *classLoader, const String &className) { 18 | if (classLoader == nullptr) { 19 | // This is a bootstrap class 20 | classLoader = BootstrapClassLoader::get(); 21 | } 22 | 23 | Klass *loadedClass = classLoader == nullptr 24 | ? nullptr 25 | : classLoader->loadClass(className); 26 | if (loadedClass == nullptr) { 27 | // TODO: throw LinkageError 28 | PANIC("LinkageError"); 29 | } 30 | return loadedClass; 31 | } 32 | 33 | ClassLoader *ClassLoader::getCurrentClassLoader() { 34 | // TODO: support user-defined class loader 35 | return BootstrapClassLoader::get(); 36 | } 37 | 38 | BootstrapClassLoader *BootstrapClassLoader::get() { 39 | static BootstrapClassLoader classLoader; 40 | return &classLoader; 41 | } 42 | 43 | Klass *BootstrapClassLoader::loadClass(const String &className) { 44 | RecursiveLockGuard guard(bootstrapLock()); 45 | 46 | // check whether class is already loaded 47 | auto iter = SystemDictionary::get()->find(className); 48 | if (iter != nullptr) { 49 | return iter; 50 | } 51 | 52 | // OK, let's find it! 53 | auto *klass = BaseClassLoader::loadClass(className); 54 | if (klass != nullptr) { 55 | SystemDictionary::get()->put(className, klass); 56 | klass->setClassState(ClassState::LOADED); 57 | klass->linkClass(); 58 | } 59 | return klass; 60 | } 61 | 62 | Klass *BootstrapClassLoader::loadClass(u1 *classBytes, size_t classSize) { 63 | RecursiveLockGuard guard(bootstrapLock()); 64 | Klass *klass = BaseClassLoader::loadClass(classBytes, classSize); 65 | if (klass == nullptr) { 66 | return nullptr; 67 | } 68 | 69 | auto iter = SystemDictionary::get()->find(klass->getName()); 70 | if (iter != nullptr) { 71 | delete klass; 72 | return iter; 73 | } 74 | 75 | SystemDictionary::get()->put(klass->getName(), klass); 76 | klass->setClassState(ClassState::LOADED); 77 | klass->linkClass(); 78 | return klass; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/kivm/native/java_lang_Object.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/21. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace kivm; 11 | 12 | JAVA_NATIVE void Java_java_lang_Object_registerNatives(JNIEnv *env, jclass java_lang_Object) { 13 | D("java/lang/Object.registerNatives()V"); 14 | } 15 | 16 | JAVA_NATIVE jint Java_java_lang_Object_hashCode(JNIEnv *env, jobject javaObject) { 17 | D("java/lang/Object.hashCode()I"); 18 | auto obj = Resolver::javaOop(javaObject); 19 | auto hash = obj->getMarkOop()->getHash(); 20 | if (hash != 0) { 21 | return hash; 22 | } 23 | 24 | auto value = intptr_t(javaObject); 25 | obj->getMarkOop()->setHash((jint) value); 26 | return (jint) value; 27 | } 28 | 29 | JAVA_NATIVE jobject Java_java_lang_Object_clone(JNIEnv *env, jobject javaObject) { 30 | static auto java_lang_Cloneable = (InstanceKlass *) BootstrapClassLoader::get() 31 | ->loadClass(L"java/lang/Cloneable"); 32 | auto thisObject = Resolver::javaOop(javaObject); 33 | 34 | if (thisObject->getClass()->getClassType() == ClassType::INSTANCE_CLASS) { 35 | auto instance = (instanceOop) thisObject; 36 | if (instance->getInstanceClass()->checkInterface(java_lang_Cloneable)) { 37 | return ((instanceOop) thisObject)->copy(); 38 | } 39 | PANIC("Clone operation requires class to implement java.lang.Cloneable"); 40 | } 41 | 42 | if (thisObject->getClass()->getClassType() == ClassType::TYPE_ARRAY_CLASS 43 | || thisObject->getClass()->getClassType() == ClassType::OBJECT_ARRAY_CLASS) { 44 | auto array = (arrayOop) thisObject; 45 | return array->copy(); 46 | } 47 | 48 | PANIC("Unknown class type"); 49 | } 50 | 51 | JAVA_NATIVE jclass Java_java_lang_Object_getClass(JNIEnv *env, jobject javaObject) { 52 | auto object = Resolver::javaOop(javaObject); 53 | return object->getClass()->getJavaMirror(); 54 | } 55 | 56 | JAVA_NATIVE void Java_java_lang_Object_notifyAll(JNIEnv *env, jobject javaObject) { 57 | auto object = Resolver::javaOop(javaObject); 58 | object->getMarkOop()->notifyAll(); 59 | } 60 | 61 | JAVA_NATIVE void Java_java_lang_Object_notify(JNIEnv *env, jobject javaObject) { 62 | auto object = Resolver::javaOop(javaObject); 63 | object->getMarkOop()->notify(); 64 | } 65 | 66 | JAVA_NATIVE void Java_java_lang_Object_wait(JNIEnv *env, jobject javaObject, jlong timeout) { 67 | auto object = Resolver::javaOop(javaObject); 68 | if (timeout == 0) { 69 | object->getMarkOop()->wait(); 70 | } else { 71 | object->getMarkOop()->wait(timeout); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /include/kivm/cfg/edge.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019-06-22. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | namespace instr { 12 | enum EdgeType { 13 | /** 14 | * Regular transition. 15 | * 16 | * For conditional jumps, this edge type requires either the string true or false 17 | * as meta-data. 18 | */ 19 | REGULAR, 20 | 21 | /** 22 | * Transition because of caught exception. 23 | * 24 | * This edge type requires the handled exception type as meta-data. 25 | */ 26 | CAUGHT_EXCEPTION, 27 | 28 | /** 29 | * case of a LOOKUPSWITCH instruction. 30 | * 31 | * This edge type requires the case label as meta-data. 32 | */ 33 | LOOKUP_SWITCH, 34 | 35 | /** 36 | * case of a TABLESWITCH instruction. 37 | * 38 | * This edge type requires the case label as meta-data. 39 | */ 40 | TABLE_SWITCH 41 | }; 42 | 43 | using Object = void *; 44 | 45 | class IBlock; 46 | 47 | class Edge { 48 | public: 49 | IBlock *src; 50 | IBlock *dest; 51 | EdgeType type; 52 | Object metaData; 53 | 54 | Edge(IBlock *src, IBlock *dest, EdgeType type, Object metaData) 55 | : src(src), dest(dest), type(type), metaData(metaData) { 56 | if (src == nullptr) { 57 | throw std::invalid_argument("src cannot be null"); 58 | } 59 | 60 | if (dest == nullptr) { 61 | throw std::invalid_argument("dest cannot be null"); 62 | } 63 | } 64 | 65 | 66 | Edge *withSource(IBlock *source) { 67 | this->src = source; 68 | return this; 69 | } 70 | 71 | Edge *withDestination(IBlock *destination) { 72 | this->dest = destination; 73 | return this; 74 | } 75 | 76 | bool isSuccessor(IBlock *block) { 77 | return src == block; 78 | } 79 | 80 | bool isPredecessor(IBlock *block) { 81 | return dest = block; 82 | } 83 | 84 | bool hasType(EdgeType type) { 85 | return this->type == type; 86 | } 87 | 88 | bool equals(Edge *other) { 89 | // TODO 90 | } 91 | }; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/kivm/native/java_io_FileOutputStream.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/28. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace kivm; 15 | 16 | JAVA_NATIVE void Java_java_io_FileOutputStream_initIDs(JNIEnv *env, jclass java_io_FileOutputStream) { 17 | D("java/io/FileOutputStream.initIDs()V"); 18 | } 19 | 20 | JAVA_NATIVE void Java_java_io_FileOutputStream_writeBytes(JNIEnv *env, jobject javaOutputStream, 21 | jbyteArray b, jint off, jint len, jboolean append) { 22 | static auto CLASS = (InstanceKlass *) BootstrapClassLoader::get() 23 | ->loadClass(L"java/io/FileOutputStream"); 24 | static auto FD_CLASS = (InstanceKlass *) BootstrapClassLoader::get() 25 | ->loadClass(L"java/io/FileDescriptor"); 26 | static auto FD_FIELD = CLASS->getInstanceFieldInfo(CLASS->getName(), L"fd", L"Ljava/io/FileDescriptor;"); 27 | static auto FD_INT_FIELD = FD_CLASS->getInstanceFieldInfo(FD_CLASS->getName(), L"fd", L"I"); 28 | 29 | auto byteArray = Resolver::typeArray(b); 30 | if (byteArray == nullptr) { 31 | SHOULD_NOT_REACH_HERE(); 32 | } 33 | 34 | if (byteArray->getLength() <= off && byteArray->getLength() < (off + len)) { 35 | auto thread = Threads::currentThread(); 36 | assert(thread != nullptr); 37 | thread->throwException(Global::_ArrayIndexOutOfBoundsException, 38 | L"length is " 39 | + std::to_wstring(byteArray->getLength()) 40 | + L", but index is " 41 | + std::to_wstring(off), false); 42 | return; 43 | } 44 | 45 | auto streamOop = Resolver::instance(javaOutputStream); 46 | instanceOop fdOop = nullptr; 47 | if (!streamOop->getFieldValue(FD_FIELD, (oop *) &fdOop)) { 48 | SHOULD_NOT_REACH_HERE(); 49 | } 50 | 51 | intOop fdInt = nullptr; 52 | if (!fdOop->getFieldValue(FD_INT_FIELD, (oop *) &fdInt)) { 53 | SHOULD_NOT_REACH_HERE(); 54 | } 55 | 56 | int fd = fdInt->getValue(); 57 | auto *buf = (char *) Universe::allocCObject(sizeof(char) * len); 58 | for (int i = off, j = 0; i < off + len; i++, j++) { 59 | buf[j] = (char) ((intOop) byteArray->getElementAt(i))->getValue(); 60 | } 61 | if (write(fd, buf, (size_t) len) == -1) { 62 | auto thread = Threads::currentThread(); 63 | assert(thread != nullptr); 64 | thread->throwException(Global::_IOException, L"write() failed"); 65 | return; 66 | } 67 | Universe::deallocCObject(buf); 68 | } 69 | -------------------------------------------------------------------------------- /include/shared/types.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // 4 | #pragma once 5 | 6 | #define _JNI_IMPLEMENTATION_ 7 | 8 | #include 9 | 10 | typedef unsigned char u1; 11 | typedef unsigned short u2; 12 | typedef unsigned int u4; 13 | typedef unsigned long long u8; 14 | 15 | #define BYTES_UNIT 1024 16 | #define SIZE_KB(X) ((X) * BYTES_UNIT) 17 | #define SIZE_MB(X) ((X) * SIZE_KB(BYTES_UNIT)) 18 | 19 | #define JAVA_NATIVE extern "C" 20 | 21 | /** 22 | * Declared public; may be accessed from outside its package. 23 | */ 24 | #define ACC_PUBLIC 0x0001 25 | 26 | /** 27 | * Declared private; usable only within the defining class. 28 | */ 29 | #define ACC_PRIVATE 0x0002 30 | 31 | /** 32 | * Declared protected; may be accessed within subclasses. 33 | */ 34 | #define ACC_PROTECTED 0x0004 35 | 36 | /** 37 | * Declared static. 38 | */ 39 | #define ACC_STATIC 0x0008 40 | 41 | /** 42 | * Declared final; never directly assigned to after object construction (JLS §17.5). 43 | */ 44 | #define ACC_FINAL 0x0010 45 | 46 | /** 47 | * Declared synchronized; invocation is wrapped by a monitor use. 48 | */ 49 | #define ACC_SYNCHRONIZED 0x0020 50 | #define ACC_SUPER 0x0020 51 | 52 | /** 53 | * Declared volatile; cannot be cached. 54 | */ 55 | #define ACC_VOLATILE 0x0040 56 | 57 | /** 58 | * A bridge method, generated by the compiler. 59 | */ 60 | #define ACC_BRIDGE 0x0040 61 | 62 | /** 63 | * Declared with variable number of arguments. 64 | */ 65 | #define ACC_VARARGS 0x0080 66 | 67 | /** 68 | * Declared transient; not written or read by a persistent object manager. 69 | */ 70 | #define ACC_TRANSIENT 0x0080 71 | 72 | /** 73 | * Declared native; implemented in a language other than Java. 74 | */ 75 | #define ACC_NATIVE 0x0100 76 | 77 | /** 78 | * Was an interface in source. 79 | */ 80 | #define ACC_INTERFACE 0x0200 81 | 82 | /** 83 | * Declared abstract; no implementation is provided. 84 | */ 85 | #define ACC_ABSTRACT 0x0400 86 | 87 | /** 88 | * Declared strictfp; floating-point mode is FP- strict. 89 | */ 90 | #define ACC_STRICT 0x0800 91 | 92 | /** 93 | * Declared synthetic; not present in the source code. 94 | */ 95 | #define ACC_SYNTHETIC 0x1000 96 | 97 | /** 98 | * Declared as an annotation type. 99 | */ 100 | #define ACC_ANNOTATION 0x2000 101 | 102 | /** 103 | * Declared as an element of an enum. 104 | */ 105 | #define ACC_ENUM 0x4000 106 | 107 | #define ACC_MIRANDA 0x8000 108 | #define ACC_REFLECT_MASK 0xffff 109 | 110 | -------------------------------------------------------------------------------- /src/kivm/native/sun_reflect_NativeMethodAccessorImpl.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2019/9/17. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | using namespace kivm; 16 | 17 | JAVA_NATIVE jobject Java_sun_reflect_NativeMethodAccessorImpl_invoke0(JNIEnv *env, jclass cls, 18 | jobject javaMethod, 19 | jobject javaThis, 20 | jobjectArray javaArguments) { 21 | auto thread = Threads::currentThread(); 22 | 23 | auto methodOop = Resolver::instance(javaMethod); 24 | auto thisOop = Resolver::javaOop(javaThis); 25 | 26 | mirrorOop targetClass; 27 | if (!methodOop->getFieldValue(java::lang::reflect::Method::FIELD_CLAZZ, (oop *) &targetClass)) { 28 | // TODO: throw InternalException 29 | SHOULD_NOT_REACH_HERE(); 30 | } 31 | 32 | intOop targetSlot; 33 | if (!methodOop->getFieldValue(java::lang::reflect::Method::FIELD_SLOT, (oop *) &targetSlot)) { 34 | // TODO: throw InternalException 35 | SHOULD_NOT_REACH_HERE(); 36 | } 37 | 38 | if (targetClass->getTarget() != nullptr 39 | && targetClass->getTarget()->getClassType() == ClassType::INSTANCE_CLASS) { 40 | // Reflection invocation on InstanceKlass 41 | auto *klass = (InstanceKlass *) targetClass->getTarget(); 42 | int slot = targetSlot->getValue(); 43 | 44 | Method *method = klass->getDeclaredMethodByOffset(slot); 45 | 46 | auto argsArray = Resolver::objectArray(javaArguments); 47 | if (argsArray->getLength() != method->getArgumentValueTypes().size()) { 48 | auto exClass = (InstanceKlass *) BootstrapClassLoader::get() 49 | ->loadClass(L"java/lang/IllegalArgumentException"); 50 | thread->throwException(exClass, L"wrong number of arguments", false); 51 | return nullptr; 52 | } 53 | 54 | std::list args; 55 | 56 | // push this if method is not static 57 | if (thisOop != nullptr && !method->isStatic()) { 58 | args.push_back(thisOop); 59 | } 60 | 61 | for (int i = 0; i < argsArray->getLength(); ++i) { 62 | args.push_back(argsArray->getElementAt(i)); 63 | } 64 | 65 | return JavaCall::withArgs(thread, method, args); 66 | } 67 | 68 | // TODO: support invocation on other class types 69 | SHOULD_NOT_REACH_HERE_M("TODO: support invocation on other class types"); 70 | return nullptr; 71 | } 72 | -------------------------------------------------------------------------------- /ext/extension-helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Covariant Script KiVM Extension 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Copyright (C) 2018 Kiva 18 | * Email: libkernelpanic@gmail.com 19 | * Github: https://github.com/imkiva 20 | */ 21 | 22 | #pragma once 23 | #include 24 | #include 25 | 26 | #define __CS_EXTENSION_NS_NAME(NAME) cs_ext_##NAME 27 | #define __CNI_NAME_MIXER(PREFIX, NAME) static cni_register PREFIX##NAME 28 | #define __CNI_REGISTER(NAME, ARGS) __CNI_NAME_MIXER(_cni_register_, NAME)(#NAME, NAME, ARGS); 29 | #define __CNI_NORMAL(NAME) __CNI_REGISTER(NAME, false) 30 | #define __CNI_CONST(NAME) __CNI_REGISTER(NAME, true) 31 | 32 | #define __CNI_EXPAND(MARCO, R, NAME, ...) \ 33 | extern R NAME(__VA_ARGS__); \ 34 | MARCO(NAME); \ 35 | R NAME(__VA_ARGS__) 36 | 37 | #define CS_EXTENSION(NAME) \ 38 | namespace __CS_EXTENSION_NS_NAME(NAME) { \ 39 | static cs::extension __cs_extension_ext; \ 40 | static cs::extension_t __cs_extension_shared = cs::make_shared_extension(__cs_extension_ext); \ 41 | class cni_register final { \ 42 | public: \ 43 | template \ 44 | cni_register(const char *name, _fT &&func, bool is_const) { \ 45 | using namespace cs; \ 46 | __cs_extension_ext.add_var(name, cs::var::make_protect(cs::cni(func), is_const)); \ 47 | } \ 48 | }; \ 49 | } \ 50 | cs::extension *cs_extension() { \ 51 | return &__CS_EXTENSION_NS_NAME(NAME)::__cs_extension_ext; \ 52 | } \ 53 | namespace __CS_EXTENSION_NS_NAME(NAME) { 54 | 55 | #define CS_EXTENSION_END() } 56 | 57 | #define CS_DECLARE_AS_OBJECT(NAME, TYPE) \ 58 | } \ 59 | namespace cs_impl { \ 60 | template<> \ 61 | cs::extension_t &get_ext<__CS_EXTENSION_NS_NAME(NAME)::TYPE>() { \ 62 | return __CS_EXTENSION_NS_NAME(NAME)::__cs_extension_shared; \ 63 | } \ 64 | } \ 65 | namespace __CS_EXTENSION_NS_NAME(NAME) { 66 | 67 | #define CS_OBJECT(NAME) \ 68 | struct NAME 69 | 70 | #define CNI_NORMAL(R, NAME, ...) __CNI_EXPAND(__CNI_NORMAL, R, NAME, ##__VA_ARGS__) 71 | #define CNI_CONST(R, NAME, ...) __CNI_EXPAND(__CNI_CONST, R, NAME, ##__VA_ARGS__) 72 | 73 | -------------------------------------------------------------------------------- /include/kivm/bytecode/javaCall.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/13. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace kivm { 10 | class JavaCall final { 11 | private: 12 | JavaThread *_thread; 13 | Method *_method; 14 | Stack *_stack; 15 | std::list _args; 16 | bool _obtainArgsFromStack; 17 | 18 | InstanceKlass *_instanceKlass; 19 | 20 | private: 21 | static Method *resolveVirtualMethod(oop thisObject, Method *tagMethod); 22 | 23 | private: 24 | bool prepareFrame(Frame *frame); 25 | 26 | bool prepareEnvironment(); 27 | 28 | void prepareSynchronized(oop thisObject); 29 | 30 | bool fillArguments(const std::vector &argTypes, bool hasThis); 31 | 32 | void finishSynchronized(oop thisObject); 33 | 34 | oop invokeNative(bool hasThis, bool resolveTwice); 35 | 36 | oop invokeJava(bool hasThis, bool resolveTwice); 37 | 38 | oop invokeDynamic(instanceOop MH, const String &descriptor); 39 | 40 | oop callInterpreter(); 41 | 42 | inline oop invokeSimple(bool forceNoResolve) { 43 | if (!prepareEnvironment()) { 44 | return nullptr; 45 | } 46 | 47 | bool hasThis = !_method->isStatic(); 48 | bool resolveTwice = forceNoResolve ? false : 49 | _method->isAbstract() 50 | || (_method->isPublic() && !_method->isFinal()); 51 | 52 | 53 | if (_method->isNative()) { 54 | return this->invokeNative(hasThis, resolveTwice); 55 | 56 | } else { 57 | return this->invokeJava(hasThis, resolveTwice); 58 | } 59 | } 60 | 61 | JavaCall(JavaThread *thread, Method *method, Stack *stack); 62 | 63 | JavaCall(JavaThread *thread, Method *method, const std::list &args); 64 | 65 | public: 66 | static inline oop withArgs(JavaThread *thread, Method *method, 67 | const std::list &args, bool forceNoResolve = false) { 68 | return JavaCall(thread, method, args).invokeSimple(forceNoResolve); 69 | } 70 | 71 | static inline oop withStack(JavaThread *thread, Method *method, 72 | Stack *stack, bool forceNoResolve = false) { 73 | return JavaCall(thread, method, stack).invokeSimple(forceNoResolve); 74 | } 75 | 76 | static inline oop withMethodHandle(JavaThread *thread, Method *invokeExact, 77 | Stack *stack, instanceOop MH, 78 | const String &descriptor) { 79 | return JavaCall(thread, invokeExact, stack).invokeDynamic(MH, descriptor); 80 | } 81 | }; 82 | } 83 | -------------------------------------------------------------------------------- /include/kivm/oop/primitiveOop.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace kivm { 9 | template 10 | struct PrimitiveHelper { 11 | constexpr static ValueType getValueType() = delete; 12 | }; 13 | 14 | template<> 15 | struct PrimitiveHelper { 16 | constexpr static ValueType getValueType() { 17 | return ValueType::INT; 18 | } 19 | }; 20 | 21 | template<> 22 | struct PrimitiveHelper { 23 | constexpr static ValueType getValueType() { 24 | return ValueType::LONG; 25 | }; 26 | }; 27 | 28 | template<> 29 | struct PrimitiveHelper { 30 | constexpr static ValueType getValueType() { 31 | return ValueType::FLOAT; 32 | }; 33 | }; 34 | 35 | template<> 36 | struct PrimitiveHelper { 37 | constexpr static ValueType getValueType() { 38 | return ValueType::DOUBLE; 39 | } 40 | }; 41 | 42 | template 43 | class primitiveOopDesc : public oopDesc { 44 | private: 45 | T _value; 46 | 47 | public: 48 | explicit primitiveOopDesc(T value) 49 | : oopDesc(nullptr, oopType::PRIMITIVE_OOP), _value(value) { 50 | } 51 | 52 | ValueType getPrimitiveType() const { 53 | return PrimitiveHelper::getValueType(); 54 | } 55 | 56 | T getValue() const { 57 | return _value; 58 | } 59 | 60 | T getValueVolatile() const { 61 | return *static_cast(&_value); 62 | } 63 | 64 | volatile T *getValueUnsafe() { 65 | return static_cast(&_value); 66 | } 67 | }; 68 | 69 | class intOopDesc : public primitiveOopDesc { 70 | public: 71 | explicit intOopDesc(jint value); 72 | 73 | inline intOop copy() override { 74 | return new intOopDesc(getValue()); 75 | } 76 | }; 77 | 78 | class longOopDesc : public primitiveOopDesc { 79 | public: 80 | explicit longOopDesc(jlong value); 81 | 82 | inline longOop copy() override { 83 | return new longOopDesc(getValue()); 84 | } 85 | }; 86 | 87 | class floatOopDesc : public primitiveOopDesc { 88 | public: 89 | explicit floatOopDesc(jfloat value); 90 | 91 | inline floatOop copy() override { 92 | return new floatOopDesc(getValue()); 93 | } 94 | }; 95 | 96 | class doubleOopDesc : public primitiveOopDesc { 97 | public: 98 | explicit doubleOopDesc(jdouble value); 99 | 100 | inline doubleOop copy() override { 101 | return new doubleOopDesc(getValue()); 102 | } 103 | }; 104 | } 105 | -------------------------------------------------------------------------------- /src/kivm/memory/universe.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/20. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | CollectedHeap *Universe::sCollectedHeapInstance = nullptr; 12 | 13 | struct VirtualMemoryInfo { 14 | size_t memorySize; 15 | }; 16 | 17 | void Universe::initialize() { 18 | Universe::sCollectedHeapInstance = new CopyingHeap; 19 | Universe::sCollectedHeapInstance->initializeAll(); 20 | } 21 | 22 | void Universe::destroy() { 23 | if (Universe::sCollectedHeapInstance != nullptr) { 24 | delete Universe::sCollectedHeapInstance; 25 | Universe::sCollectedHeapInstance = nullptr; 26 | } 27 | } 28 | 29 | void *Universe::allocVirtual(size_t size) { 30 | D("allocVirtual: %zd", size); 31 | 32 | jbyte *memory = nullptr; 33 | jbyte* FAILURE; 34 | 35 | #if defined(KIVM_PLATFORM_WINDOWS) 36 | FAILURE = nullptr; 37 | memory = (jbyte *) VirtualAlloc(nullptr, size, 38 | MEM_RESERVE, PAGE_READWRITE); 39 | #else 40 | FAILURE = (jbyte *) MAP_FAILED; 41 | memory = (jbyte *) mmap(nullptr, 42 | size + sizeof(VirtualMemoryInfo), 43 | PROT_READ | PROT_WRITE, 44 | MAP_ANONYMOUS | MAP_SHARED, -1, 0); 45 | #endif 46 | 47 | if (memory == FAILURE) { 48 | WARN("Universe::allocVirtual(): failed: %s", strerror(errno)); 49 | return nullptr; 50 | } 51 | 52 | auto memoryInfo = (VirtualMemoryInfo *) memory; 53 | memoryInfo->memorySize = size; 54 | return memory + sizeof(VirtualMemoryInfo); 55 | } 56 | 57 | void Universe::deallocVirtual(void *memory) { 58 | jbyte *m = ((jbyte *) memory) - sizeof(VirtualMemoryInfo); 59 | auto memoryInfo = (VirtualMemoryInfo *) m; 60 | munmap(m, memoryInfo->memorySize); 61 | } 62 | 63 | void *Universe::allocHeap(size_t size) { 64 | if (sCollectedHeapInstance == nullptr) { 65 | WARN("heap not initialized"); 66 | return nullptr; 67 | } 68 | return sCollectedHeapInstance->allocate(size); 69 | } 70 | 71 | void *Universe::allocCObject(size_t size) { 72 | void *m = malloc(size); 73 | if (m == nullptr) { 74 | WARN("OutOfMemory: system heap"); 75 | return nullptr; 76 | } 77 | memset(m, '\0', size); 78 | return m; 79 | } 80 | 81 | void Universe::deallocCObject(void *memory) { 82 | if (memory != nullptr) { 83 | free(memory); 84 | } 85 | } 86 | 87 | bool Universe::isHeapObject(void *addr) { 88 | if (sCollectedHeapInstance == nullptr) { 89 | WARN("heap not initialized"); 90 | return false; 91 | } 92 | return sCollectedHeapInstance->isHeapObject(addr); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/kivm/bytecode/javaMethodCall.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/19. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | oop JavaCall::invokeJava(bool hasThis, bool resolveTwice) { 12 | const std::vector &descriptorMap = _method->getArgumentValueTypes(); 13 | 14 | D("javaInvocationContext: %S.%S:%S, static: %s, native: %s, nargs: %zd", 15 | (_instanceKlass->getName()).c_str(), 16 | (_method->getName()).c_str(), 17 | (_method->getDescriptor()).c_str(), 18 | hasThis ? "false" : "true", 19 | _method->isNative() ? "true" : "false", 20 | descriptorMap.size()); 21 | 22 | if (_obtainArgsFromStack && _stack != nullptr) { 23 | if (!fillArguments(descriptorMap, hasThis)) { 24 | SHOULD_NOT_REACH_HERE_M("Unknown value type"); 25 | } 26 | } 27 | 28 | oop thisObject = nullptr; 29 | if (hasThis) { 30 | thisObject = *_args.begin(); 31 | if (thisObject == nullptr) { 32 | _thread->throwException(Global::_NullPointerException, false); 33 | return nullptr; 34 | } 35 | } 36 | 37 | if (resolveTwice && thisObject != nullptr) { 38 | auto resolvedVirtualMethod = resolveVirtualMethod(thisObject, _method); 39 | if (resolvedVirtualMethod == nullptr) { 40 | PANIC("resolveVirtualMethod: failed"); 41 | } 42 | this->_method = resolvedVirtualMethod; 43 | } 44 | 45 | prepareSynchronized(thisObject); 46 | 47 | oop result = callInterpreter(); 48 | 49 | if (_stack != nullptr && !_thread->isExceptionOccurred()) { 50 | switch (_method->getReturnType()) { 51 | case ValueType::INT: 52 | _stack->pushInt(((intOop) result)->getValue()); 53 | break; 54 | case ValueType::LONG: 55 | _stack->pushLong(((longOop) result)->getValue()); 56 | break; 57 | case ValueType::FLOAT: 58 | _stack->pushFloat(((floatOop) result)->getValue()); 59 | break; 60 | case ValueType::DOUBLE: 61 | _stack->pushDouble(((doubleOop) result)->getValue()); 62 | break; 63 | case ValueType::OBJECT: 64 | case ValueType::ARRAY: 65 | _stack->pushReference(result); 66 | break; 67 | case ValueType::VOID: 68 | break; 69 | 70 | default: 71 | PANIC("Unknown value type"); 72 | } 73 | } 74 | finishSynchronized(thisObject); 75 | return result; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /include/kivm/oop/arrayKlass.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace kivm { 10 | class ArrayKlass : public Klass { 11 | friend class CopyingHeap; 12 | 13 | private: 14 | ClassLoader *_classLoader = nullptr; 15 | mirrorOop _javaLoader = nullptr; 16 | 17 | int _dimension; 18 | 19 | public: 20 | ArrayKlass(ClassLoader *classLoader, mirrorOop javaLoader, 21 | int dimension, ClassType classType); 22 | 23 | ClassLoader *getClassLoader() const { 24 | return _classLoader; 25 | } 26 | 27 | int getDimension() const { 28 | return _dimension; 29 | } 30 | 31 | mirrorOop getJavaLoader() { 32 | return _javaLoader; 33 | } 34 | 35 | bool isObjectArray() const { 36 | return getClassType() == ClassType::OBJECT_ARRAY_CLASS; 37 | } 38 | 39 | void linkClass() override; 40 | 41 | void initClass() override; 42 | 43 | virtual void copyArrayTo(arrayOop src, arrayOop desc, int srcPos, int destPos, int length) = 0; 44 | }; 45 | 46 | class TypeArrayKlass : public ArrayKlass { 47 | private: 48 | ValueType _componentType; 49 | 50 | // Only available when dimension > 1 51 | TypeArrayKlass *_downDimensionType = nullptr; 52 | 53 | public: 54 | TypeArrayKlass(ClassLoader *classLoader, mirrorOop javaLoader, 55 | int dimension, ValueType componentType); 56 | 57 | TypeArrayKlass(ClassLoader *classLoader, TypeArrayKlass *downType); 58 | 59 | ValueType getComponentType() const { 60 | return _componentType; 61 | } 62 | 63 | void linkClass() override; 64 | 65 | TypeArrayKlass *getDownDimensionType() const { 66 | return _downDimensionType; 67 | } 68 | 69 | typeArrayOop newInstance(int length); 70 | 71 | void copyArrayTo(arrayOop src, arrayOop dest, int srcPos, int destPos, int length) override; 72 | }; 73 | 74 | class ObjectArrayKlass : public ArrayKlass { 75 | private: 76 | InstanceKlass *_componentType = nullptr; 77 | 78 | // Only available when dimension > 1 79 | ObjectArrayKlass *_downDimensionType; 80 | 81 | public: 82 | ObjectArrayKlass(ClassLoader *classLoader, mirrorOop javaLoader, 83 | int dimension, InstanceKlass *componentType); 84 | 85 | ObjectArrayKlass(ClassLoader *classLoader, ObjectArrayKlass *downType); 86 | 87 | InstanceKlass *getComponentType() const { 88 | return _componentType; 89 | } 90 | 91 | void linkClass() override; 92 | 93 | ObjectArrayKlass *getDownDimensionType() const { 94 | return _downDimensionType; 95 | } 96 | 97 | objectArrayOop newInstance(int length); 98 | 99 | void copyArrayTo(arrayOop src, arrayOop dest, int srcPos, int destPos, int length) override; 100 | }; 101 | } 102 | -------------------------------------------------------------------------------- /include/kivm/runtime/frame.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/23. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace kivm { 10 | class Method; 11 | 12 | class Frame final { 13 | friend class FrameList; 14 | 15 | friend class CopyingHeap; 16 | 17 | private: 18 | Frame *_previous = nullptr; 19 | Method *_method = nullptr; 20 | 21 | bool _nativeFrame = false; 22 | volatile bool _exceptionThrownHere = false; 23 | u4 _returnPc; 24 | 25 | Locals _locals; 26 | Stack _stack; 27 | 28 | public: 29 | Frame(int maxLocals, int maxStacks); 30 | 31 | inline Frame *getPrevious() { 32 | return _previous; 33 | } 34 | 35 | inline Method *getMethod() { 36 | return _method; 37 | } 38 | 39 | inline bool isNativeFrame() const { 40 | return _nativeFrame; 41 | } 42 | 43 | inline Locals &getLocals() { 44 | return _locals; 45 | } 46 | 47 | inline Stack &getStack() { 48 | return _stack; 49 | } 50 | 51 | inline u4 getReturnPc() const { 52 | return this->_returnPc; 53 | } 54 | 55 | inline bool isExceptionThrownHere() const { 56 | return this->_exceptionThrownHere; 57 | } 58 | 59 | inline void setMethod(Method *method) { 60 | this->_method = method; 61 | } 62 | 63 | inline void setNativeFrame(bool isNativeFrame) { 64 | this->_nativeFrame = isNativeFrame; 65 | } 66 | 67 | inline void setReturnPc(u4 returnPc) { 68 | this->_returnPc = returnPc; 69 | } 70 | 71 | inline void setExceptionThrownHere(bool here) { 72 | this->_exceptionThrownHere = here; 73 | } 74 | }; 75 | 76 | struct FrameList { 77 | friend class CopyingHeap; 78 | 79 | private: 80 | int _max_frames; 81 | int _size; 82 | Frame *_current; 83 | 84 | public: 85 | explicit FrameList(int maxFrames); 86 | 87 | inline void push(Frame *frame) { 88 | assert(_size >= 0 && _size < _max_frames); 89 | 90 | frame->_previous = _current; 91 | _current = frame; 92 | ++_size; 93 | } 94 | 95 | inline Frame *pop() { 96 | assert(_size > 0 && _current != nullptr); 97 | 98 | Frame *current = _current; 99 | _current = _current->_previous; 100 | --_size; 101 | 102 | // this frame is not longer belong to this list. 103 | current->_previous = nullptr; 104 | return current; 105 | } 106 | 107 | inline Frame *getCurrentFrame() const { 108 | assert(_size > 0 && _current != nullptr); 109 | return _current; 110 | } 111 | 112 | inline int getSize() const { 113 | return this->_size; 114 | } 115 | 116 | inline int getMaxFrames() const { 117 | return _max_frames; 118 | } 119 | }; 120 | } 121 | -------------------------------------------------------------------------------- /include/kivm/oop/field.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/28. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace kivm { 11 | class Klass; 12 | 13 | class InstanceKlass; 14 | 15 | class field_info; 16 | 17 | class cp_info; 18 | 19 | class ConstantValue_attribute; 20 | 21 | class Field { 22 | friend InstanceKlass; 23 | 24 | public: 25 | static bool isSame(const Field *lhs, const Field *rhs); 26 | 27 | static String makeIdentity(InstanceKlass *belongTo, const Field *f); 28 | 29 | private: 30 | InstanceKlass *_klass = nullptr; 31 | String _name; 32 | String _descriptor; 33 | String _signature; 34 | u2 _accessFlag; 35 | 36 | ValueType _valueType; 37 | 38 | /** 39 | * Only available when _value_type is OBJECT or ARRAY 40 | */ 41 | Klass *_valueClassType = nullptr; 42 | String _valueClassTypeName; 43 | 44 | field_info *_fieldInfo = nullptr; 45 | ConstantValue_attribute *_constantAttr = nullptr; 46 | 47 | bool _linked; 48 | 49 | void linkAttributes(cp_info **pool); 50 | 51 | void postLinkValueType(); 52 | 53 | public: 54 | Field(InstanceKlass *clazz, field_info *fieldInfo); 55 | 56 | void linkField(cp_info **pool); 57 | 58 | InstanceKlass *getClass() const { 59 | return _klass; 60 | } 61 | 62 | Klass *getValueTypeClass(); 63 | 64 | const String &getName() const { 65 | return _name; 66 | } 67 | 68 | const String &getDescriptor() const { 69 | return _descriptor; 70 | } 71 | 72 | const String &getSignature() const { 73 | return _signature; 74 | } 75 | 76 | ConstantValue_attribute *getConstantAttribute() const { 77 | return _constantAttr; 78 | } 79 | 80 | u2 getAccessFlag() const { 81 | return _accessFlag; 82 | } 83 | 84 | ValueType getValueType() const { 85 | return _valueType; 86 | } 87 | 88 | bool isLinked() const { 89 | return _linked; 90 | } 91 | 92 | bool isPublic() const { 93 | return (getAccessFlag() & ACC_PUBLIC) == ACC_PUBLIC; 94 | } 95 | 96 | bool isPrivate() const { 97 | return (getAccessFlag() & ACC_PRIVATE) == ACC_PRIVATE; 98 | } 99 | 100 | bool isProtected() const { 101 | return (getAccessFlag() & ACC_PROTECTED) == ACC_PROTECTED; 102 | } 103 | 104 | bool isFinal() const { 105 | return (getAccessFlag() & ACC_FINAL) == ACC_FINAL; 106 | } 107 | 108 | bool isStatic() { 109 | return (getAccessFlag() & ACC_STATIC) == ACC_STATIC; 110 | } 111 | 112 | bool isVolatile() const { 113 | return (getAccessFlag() & ACC_VOLATILE) == ACC_VOLATILE; 114 | } 115 | }; 116 | 117 | class FieldPool { 118 | private: 119 | static std::list &getEntriesInternal(); 120 | 121 | public: 122 | static void add(Field *method); 123 | 124 | static const std::list &getEntries(); 125 | }; 126 | } 127 | -------------------------------------------------------------------------------- /src/kivm/memory/copyingHeap.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/4/20. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define REGION_COUNT 2 13 | 14 | namespace kivm { 15 | CopyingHeap::CopyingHeap() 16 | : _memoryStart(nullptr), 17 | _totalSize(RuntimeConfig::get().initialHeapSizeInBytes), 18 | _regions(nullptr), 19 | _currentRegion(nullptr), 20 | _nextRegion(nullptr) { 21 | D("CopyingHeap: initialHeapSize: %zd", _totalSize); 22 | } 23 | 24 | CopyingHeap::~CopyingHeap() { 25 | if (_memoryStart != nullptr) { 26 | Universe::deallocVirtual(_memoryStart); 27 | _memoryStart = nullptr; 28 | } 29 | } 30 | 31 | void *CopyingHeap::allocate(size_t size) { 32 | if (_currentRegion->shouldAllocate(size)) { 33 | return _currentRegion->allocate(size); 34 | } 35 | 36 | // out of memory, let's try GC 37 | auto currentThread = Threads::currentThread(); 38 | if (currentThread == nullptr) { 39 | PANIC("OutOfMemoryError: heap (not in JavaThread)"); 40 | } 41 | 42 | auto gc = GCThread::get(); 43 | if (gc != nullptr) { 44 | D("CopyingHeap: out of memory, will retry after GC, required size: %zd", size); 45 | auto triggeredMonitor = gc->required(); 46 | 47 | // this will block current thread until GC is finished 48 | currentThread->enterSafepoint(); 49 | 50 | // GCThread->require() will enter this monitor 51 | // we should leave this monitor for the coming GC 52 | if (triggeredMonitor != nullptr) { 53 | triggeredMonitor->leave(); 54 | } 55 | 56 | // try again 57 | D("CopyingHeap: retry"); 58 | if (_currentRegion->shouldAllocate(size)) { 59 | D("CopyingHeap: successfully allocated %zd bytes after GC", size); 60 | return _currentRegion->allocate(size); 61 | } 62 | } 63 | 64 | PANIC("OutOfMemoryError: heap"); 65 | return nullptr; 66 | } 67 | 68 | void CopyingHeap::initializeAll() { 69 | _memoryStart = (jbyte *) Universe::allocVirtual(_totalSize); 70 | D("CopyingHeap: virtual memory allocated: %p", _memoryStart); 71 | 72 | initializeRegions(); 73 | } 74 | 75 | void CopyingHeap::initializeRegions() { 76 | if (_totalSize < 2 || ((_totalSize & (_totalSize - 1)) != 0)) { 77 | PANIC("Heap size should be power of 2"); 78 | } 79 | 80 | size_t regionSize = _totalSize / REGION_COUNT; 81 | _regions = (HeapRegion *) Universe::allocCObject(sizeof(HeapRegion) * REGION_COUNT); 82 | _currentRegion = _regions; 83 | _nextRegion = _regions + 1; 84 | 85 | jbyte *delivering = _memoryStart; 86 | 87 | // setup current and next region 88 | HeapRegion *hr = nullptr; 89 | for (int i = 0; i < REGION_COUNT; ++i) { 90 | hr = _regions + i; 91 | hr->_regionSize = regionSize; 92 | hr->_regionStart = delivering; 93 | hr->_current = delivering; 94 | delivering += regionSize; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /include/kivm/oop/klass.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/2/25. 3 | // 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace kivm { 13 | enum ClassType { 14 | INSTANCE_CLASS, 15 | OBJECT_ARRAY_CLASS, 16 | TYPE_ARRAY_CLASS, 17 | }; 18 | 19 | enum ClassState { 20 | ALLOCATED, 21 | LOADED, 22 | LINKED, 23 | BEING_INITIALIZED, 24 | FULLY_INITIALIZED, 25 | INITIALIZATION_ERROR, 26 | }; 27 | 28 | class Klass { 29 | friend class CopyingHeap; 30 | 31 | private: 32 | ClassState _state; 33 | u2 _accessFlag; 34 | 35 | protected: 36 | String _name; 37 | ClassType _type; 38 | 39 | mirrorOop _javaMirror = nullptr; 40 | InstanceKlass *_superClass = nullptr; 41 | 42 | public: 43 | mirrorOop getJavaMirror() { 44 | return _javaMirror; 45 | } 46 | 47 | void setJavaMirror(mirrorOop javaMirror) { 48 | this->_javaMirror = javaMirror; 49 | } 50 | 51 | ClassState getClassState() const { 52 | return _state; 53 | } 54 | 55 | void setClassState(ClassState classState) { 56 | this->_state = classState; 57 | } 58 | 59 | u2 getAccessFlag() const { 60 | return _accessFlag; 61 | } 62 | 63 | void setAccessFlag(u2 accessFlag) { 64 | Klass::_accessFlag = accessFlag; 65 | } 66 | 67 | const String &getName() const { 68 | return _name; 69 | } 70 | 71 | void setName(const String &name) { 72 | this->_name = name; 73 | } 74 | 75 | ClassType getClassType() const { 76 | return _type; 77 | } 78 | 79 | void setClassType(ClassType classType) { 80 | this->_type = classType; 81 | } 82 | 83 | InstanceKlass *getSuperClass() const { 84 | return _superClass; 85 | } 86 | 87 | void setSuperClass(InstanceKlass *superClass) { 88 | this->_superClass = superClass; 89 | } 90 | 91 | bool isPublic() const { 92 | return (getAccessFlag() & ACC_PUBLIC) == ACC_PUBLIC; 93 | } 94 | 95 | bool isPrivate() const { 96 | return (getAccessFlag() & ACC_PRIVATE) == ACC_PRIVATE; 97 | } 98 | 99 | bool isProtected() const { 100 | return (getAccessFlag() & ACC_PROTECTED) == ACC_PROTECTED; 101 | } 102 | 103 | bool isFinal() const { 104 | return (getAccessFlag() & ACC_FINAL) == ACC_FINAL; 105 | } 106 | 107 | bool isStatic() { 108 | return (getAccessFlag() & ACC_STATIC) == ACC_STATIC; 109 | } 110 | 111 | bool isAbstract() { 112 | return (getAccessFlag() & ACC_ABSTRACT) == ACC_ABSTRACT; 113 | } 114 | 115 | bool isInterface() { 116 | return (getAccessFlag() & ACC_INTERFACE) == ACC_INTERFACE; 117 | } 118 | 119 | public: 120 | Klass(); 121 | 122 | virtual ~Klass() = default; 123 | 124 | virtual void linkClass() = 0; 125 | 126 | virtual void initClass() = 0; 127 | }; 128 | } 129 | 130 | -------------------------------------------------------------------------------- /src/kivm/classpath/baseClassLoader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by kiva on 2018/3/1. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace kivm { 13 | Klass *BaseClassLoader::loadClass(const String &className) { 14 | // Load array class 15 | if (className[0] == L'[') { 16 | // [I 17 | int dimension = 0; 18 | while (className[++dimension] == L'[') continue; 19 | 20 | // Load 1-dimension array directly 21 | if (dimension == 1) { 22 | // for example: [Ljava/lang/Object; 23 | if (className[1] == L'L') { 24 | // java/lang/Object 25 | const String &component = className.substr(2, className.size() - 3); 26 | auto *component_class = (InstanceKlass *) loadClass(component); 27 | return component_class != nullptr 28 | ? new ObjectArrayKlass(this, nullptr, dimension, component_class) 29 | : nullptr; 30 | } 31 | 32 | // for example: LI -> I, LB -> B 33 | // use primitiveTypeToValueTypeNoWrap() instead of primitiveTypeToValueType() 34 | // because in Java, booleans, chars, shorts and bytes are not ints 35 | ValueType component_type = primitiveTypeToValueTypeNoWrap(className[1]); 36 | return new TypeArrayKlass(this, nullptr, dimension, component_type); 37 | } 38 | 39 | // Load multi-dimension array recursively 40 | // remove the first '[' 41 | const String &down_type_name = className.substr(1); 42 | auto *down_type = (ArrayKlass *) loadClass(down_type_name); 43 | if (down_type == nullptr) { 44 | return nullptr; 45 | } 46 | 47 | if (down_type->isObjectArray()) { 48 | return new ObjectArrayKlass(this, (ObjectArrayKlass *) down_type); 49 | } else { 50 | return new TypeArrayKlass(this, (TypeArrayKlass *) down_type); 51 | } 52 | } 53 | 54 | 55 | // Load instance class 56 | ClassPathManager *cpm = ClassPathManager::get(); 57 | const auto &result = cpm->searchClass(className); 58 | if (result._source == ClassSource::NOT_FOUND) { 59 | return nullptr; 60 | } 61 | 62 | ClassFileParser fileParser(result._file, result._buffer, result._bufferSize); 63 | ClassFile *classFile = fileParser.getParsedClassFile(); 64 | Klass *klass = classFile != nullptr 65 | ? new InstanceKlass(classFile, this, nullptr, ClassType::INSTANCE_CLASS) 66 | : nullptr; 67 | result.closeResource(); 68 | return klass; 69 | } 70 | 71 | Klass *BaseClassLoader::loadClass(u1 *classBytes, size_t classSize) { 72 | if (classBytes == nullptr) { 73 | return nullptr; 74 | } 75 | 76 | ClassFileParser fileParser(L"", classBytes, classSize); 77 | ClassFile *classFile = fileParser.getParsedClassFile(); 78 | return classFile != nullptr 79 | ? new InstanceKlass(classFile, this, nullptr, ClassType::INSTANCE_CLASS) 80 | : nullptr; 81 | } 82 | } 83 | --------------------------------------------------------------------------------