├── .gitignore ├── images ├── Argument.gif └── HelloWorld.png ├── examples ├── HelloWorld.java ├── Calculation.java └── Argument.java ├── jvm-cli.el ├── README.md ├── jvm-class.el ├── jvm-util.el ├── jvm-classfile.el └── jvm-instruction.el /.gitignore: -------------------------------------------------------------------------------- 1 | *.elc 2 | *.class 3 | -------------------------------------------------------------------------------- /images/Argument.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongo/emacs-jvm/HEAD/images/Argument.gif -------------------------------------------------------------------------------- /images/HelloWorld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongo/emacs-jvm/HEAD/images/HelloWorld.png -------------------------------------------------------------------------------- /examples/HelloWorld.java: -------------------------------------------------------------------------------- 1 | class HelloWorld 2 | { 3 | public static void main(String[] args) 4 | { 5 | System.out.println("Hello, World!"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/Calculation.java: -------------------------------------------------------------------------------- 1 | class Calculation 2 | { 3 | public static void main(String[] args) 4 | { 5 | int i = 3; 6 | int j = 4; 7 | 8 | System.out.printf("%d + %d = %d\n", i, j, i * j); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/Argument.java: -------------------------------------------------------------------------------- 1 | class Argument 2 | { 3 | public static void main(String[] args) 4 | { 5 | int a1 = Integer.parseInt(args[0]); 6 | int a2 = Integer.parseInt(args[1]); 7 | System.out.printf("a1 (%d) + a2 (%d) = %d\n", a1, a2, a1 + a2); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /jvm-cli.el: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ":"; exec emacs --quick --script "$0" "$@" # -*- mode: emacs-lisp; lexical-binding: t; -*- 3 | 4 | (let ((current-dir (file-name-directory (or load-file-name (buffer-file-name))))) 5 | (add-to-list 'load-path current-dir)) 6 | 7 | (require 'jvm-classfile) 8 | 9 | (let* ((classfile (jvm--classfile-load (nth 0 command-line-args-left))) 10 | (method (jvm--classfile-find-method classfile "main"))) 11 | (apply #'jvm--classfile-run-method method (cl-subseq command-line-args-left 1))) 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Implement JVM by Emacs 2 | 3 | ## CAUTION 4 | 5 | `emacs-jvm` is an **experimental project** . 6 | 7 | ## DEMONSTRATION 8 | 9 | | HelloWorld.java | Argument.java | 10 | |---------------------------------------------|---------------------------------------------| 11 | | ![HelloWorld.java](./images/HelloWorld.png) | ![Argument.java](./images/Argument.gif) | 12 | 13 | ## USAGE 14 | 15 | 1. Fetch this repository: 16 | 17 | ``` 18 | $ git clone https://github.com/gongo/emacs-jvm.git 19 | $ cd emacs-jvm/ 20 | ``` 21 | 22 | 2. Compile example Java program: 23 | 24 | ``` 25 | $ javac examples/HelloWorld.java 26 | ``` 27 | 28 | 3. Enjoy! 29 | 30 | ``` 31 | $ java -classpath ./examples HelloWorld 32 | $ ./jvm-cli.el ./examples/HelloWorld.class 33 | ``` 34 | 35 | ## LICENSE 36 | 37 | MIT 38 | -------------------------------------------------------------------------------- /jvm-class.el: -------------------------------------------------------------------------------- 1 | (defconst jvm--builtin-class-table (make-hash-table :test #'equal)) 2 | 3 | (defstruct jvm--builtin-class 4 | (constructor (lambda ())) 5 | (fields (make-hash-table :test #'equal)) 6 | (methods (make-hash-table :test #'equal)) 7 | (static-methods (make-hash-table :test #'equal)) 8 | ) 9 | 10 | (puthash "java/lang/Integer" 11 | (let ((class (make-jvm--builtin-class))) 12 | (puthash "valueOf" 13 | (lambda (x) 14 | x) 15 | (jvm--builtin-class-static-methods class)) 16 | (puthash "parseInt" 17 | (lambda (x) 18 | (string-to-number x)) 19 | (jvm--builtin-class-static-methods class)) 20 | class) 21 | jvm--builtin-class-table) 22 | 23 | (puthash "java/io/PrintStream" 24 | (let ((class (make-jvm--builtin-class))) 25 | (puthash "println" 26 | (lambda (x) 27 | (message x)) 28 | (jvm--builtin-class-methods class)) 29 | (puthash "printf" 30 | (lambda (format &optional args) 31 | (apply #'message format (append args nil))) 32 | (jvm--builtin-class-methods class)) 33 | class) 34 | jvm--builtin-class-table) 35 | 36 | (puthash "java/lang/System" 37 | (let ((class (make-jvm--builtin-class))) 38 | (puthash "out" 39 | (gethash "java/io/PrintStream" jvm--builtin-class-table) 40 | (jvm--builtin-class-fields class)) 41 | class) 42 | jvm--builtin-class-table) 43 | 44 | (provide 'jvm-class) 45 | -------------------------------------------------------------------------------- /jvm-util.el: -------------------------------------------------------------------------------- 1 | (defconst jvm--util-signature-type-map 2 | #s(hash-table 3 | data ( 4 | ?B "Byte" 5 | ?C "Char" 6 | ?D "Double" 7 | ?F "Float" 8 | ?I "Int" 9 | ?J "Long" 10 | ?S "Short" 11 | ?V "Void" 12 | ?Z "Boolean" 13 | ?L "class" 14 | ))) 15 | 16 | (defun jvm--util-parse-signature (signature &optional current-index) 17 | (when (null current-index) (setq current-index 0)) 18 | (let ((data nil) 19 | (deep-array 0)) 20 | (while (< current-index (length signature)) 21 | (let ((s (elt signature current-index))) 22 | (case s 23 | ((or ?B ?C ?D ?F ?I ?J ?S ?V ?Z) 24 | (setq data (append data 25 | `(( 26 | (type . ,(gethash s jvm--util-signature-type-map)) 27 | (deep-array . ,deep-array) 28 | )))) 29 | (setq deep-array 0)) 30 | (?L 31 | (incf current-index) 32 | (let ((build "")) 33 | (while (not (char-equal ?\; (elt signature current-index))) 34 | (setq build (concat build (list (elt signature current-index)))) 35 | (incf current-index)) 36 | (setq data (append data 37 | `(( 38 | (type . ,build) 39 | (deep-array . ,deep-array) 40 | )))) 41 | (setq deep-array 0))) 42 | (?\[ 43 | (incf deep-array) 44 | (incf current-index) 45 | (while (char-equal ?\[ (elt signature current-index)) 46 | (incf deep-array) 47 | (incf current-index)) 48 | 49 | ;; Don't increment at the end of while body 50 | (decf current-index)) 51 | (?\( 52 | (incf current-index) 53 | (let ((build "") 54 | arguments) 55 | (while (and 56 | (< current-index (length signature)) 57 | (not (char-equal ?\) (elt signature current-index)))) 58 | (setq build (concat build (list (elt signature current-index)))) 59 | (incf current-index)) 60 | (setq arguments (if (string= build "") 61 | nil 62 | (jvm--util-parse-signature build))) 63 | (setq data (append data 64 | `( 65 | (arguments . ,arguments) 66 | (arguments-count . ,(length arguments)) 67 | ))))) 68 | )) 69 | (incf current-index)) 70 | data)) 71 | 72 | (provide 'jvm-util) 73 | -------------------------------------------------------------------------------- /jvm-classfile.el: -------------------------------------------------------------------------------- 1 | ;; -*- lexical-binding: t -*- 2 | 3 | (require 'bindat) 4 | (require 'let-alist) 5 | (require 'cl) 6 | (require 'cl-lib) 7 | 8 | (require 'jvm-instruction) 9 | 10 | ;; 11 | ;; https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4 12 | ;; 13 | (defconst jvm--classfile-spec-cp-info 14 | '((tag u8) 15 | (union (tag) 16 | (7 ;; CONSTANT_Class_info 17 | (name-index u16)) 18 | (9 ;; CONSTANT_Fieldref_info 19 | (class-index u16) 20 | (name-and-type-index u16)) 21 | (10 ;; CONSTANT_Methodref_info 22 | (class-index u16) 23 | (name-and-type-index u16)) 24 | (11 ;; CONSTANT_InterfaceMethod_info 25 | (class-index u16) 26 | (name-and-type-index u16)) 27 | (8 ;; CONSTANT_String_info 28 | (string-index u16)) 29 | (3 ;; CONSTANT_Integer_info 30 | (bytes u32)) 31 | (4 ;; CONSTANT_Float_info 32 | (bytes u32)) 33 | (5 ;; CONSTANT_Long_info 34 | (high-bytes u32) 35 | (low-bytes u32)) 36 | (6 ;; CONSTANT_Double_info 37 | (high-bytes u32) 38 | (low-bytes u32)) 39 | (12 ;; CONSTANT_NameAndType_info 40 | (name-index u16) 41 | (descriptor-index u16)) 42 | (1 ;; CONSTANT_Utf8_info 43 | (length u16) 44 | (bytes vec (length) u8)) 45 | (15 ;; CONSTANT_MethodHandle_info 46 | (reference-kind u8) 47 | (reference-index u16)) 48 | (16 ;; CONSTANT_MethodType_info 49 | (descriptor-index u16)) 50 | (18 ;; CONSTANT_InvokeDynamic_info 51 | (bootstrap-method-attr-index u16) 52 | (name-and-type-index u16)) 53 | ))) 54 | 55 | ;; 56 | ;; https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1 57 | ;; 58 | (defconst jvm--classfile-spec-classfile 59 | '( 60 | (magic u32) 61 | (minor-version u16) 62 | (major-version u16) 63 | (constant-pool-count u16) 64 | (constant-pool repeat (eval (- last 1)) (struct jvm--classfile-spec-cp-info)) 65 | (access-flags u16) 66 | (this-class u16) 67 | (super-class u16) 68 | (interfaces-count u16) 69 | (interfaces repeat (interfaces-count) u16) 70 | (fields-count u16) 71 | (fields repeat (fields-count) (struct jvm--classfile-spec-field-info)) 72 | (methods-count u16) 73 | (methods repeat (methods-count) (struct jvm--classfile-spec-method-info)) 74 | (attributes-count u16) 75 | (attributes repeat (attributes-count) (struct jvm--classfile-spec-attribute-info)) 76 | )) 77 | 78 | ;; 79 | ;; https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.5 80 | ;; 81 | (defconst jvm--classfile-spec-field-info 82 | '( 83 | (access-flags u16) 84 | (name-index u16) 85 | (descriptor-index u16) 86 | (attributes-count u16) 87 | (attributes repeat (attributes-count) (struct jvm--classfile-spec-attribute-info)) 88 | )) 89 | 90 | ;; 91 | ;; https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6 92 | ;; 93 | (defconst jvm--classfile-spec-method-info 94 | '( 95 | (access-flags u16) 96 | (name-index u16) 97 | (descriptor-index u16) 98 | (attributes-count u16) 99 | (attributes repeat (attributes-count) (struct jvm--classfile-spec-attribute-info)) 100 | )) 101 | 102 | ;; 103 | ;; https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7 104 | ;; 105 | (defconst jvm--classfile-spec-attribute-info 106 | '( 107 | (attribute-name-index u16) 108 | (attribute-length u32) 109 | (info vec (attribute-length) u8) 110 | )) 111 | 112 | (defconst jvm--classfile-spec-code-attribute 113 | '( 114 | (max-stack u16) 115 | (max-locals u16) 116 | (code-length u32) 117 | (codes vec (code-length) u8) 118 | (exception-table-length u16) 119 | (exception-tables repeat (exception-table-length) (struct jvm--classfile-spec-exception-table)) 120 | (attributes-count u16) 121 | (attributes repeat (attributes-count) (struct jvm--classfile-spec-attribute-info)) 122 | )) 123 | 124 | (defconst jvm--classfile-spec-exception-table 125 | '( 126 | (start-pc u16) 127 | (end-pc u16) 128 | (handler-pc u16) 129 | (catch-type u16) 130 | )) 131 | 132 | (defconst jvm--classfile-spec-sourcefile-attribute 133 | '( 134 | (sourcefile-index u16) 135 | )) 136 | 137 | (defstruct jvm--classfile 138 | magic 139 | minor-version 140 | major-version 141 | constant-pool 142 | access-flags 143 | this-class 144 | super-class 145 | interfaces 146 | fields 147 | methods 148 | attributes 149 | (this-class-name (let ((name-index (let-alist (elt constant-pool this-class) .name-index))) 150 | (concat 151 | (let-alist (elt constant-pool name-index) .bytes))) 152 | :read-only t) 153 | ) 154 | 155 | (defstruct jvm--classfile-field 156 | (access-flags nil :read-only t) 157 | (name-index nil :read-only t) 158 | (descriptor-index nil :read-only t) 159 | (attributes nil :read-only t) 160 | (constant-pool nil :read-only t) 161 | (name (concat (let-alist (elt constant-pool name-index) .bytes)) :read-only t) 162 | (descriptor (concat (let-alist (elt constant-pool descriptor-index) .bytes)) :read-only t) 163 | ) 164 | 165 | (defstruct jvm--classfile-method 166 | (access-flags nil :read-only t) 167 | (name-index nil :read-only t) 168 | (descriptor-index nil :read-only t) 169 | (attributes nil :read-only t) 170 | (constant-pool nil :read-only t) 171 | (name (concat (let-alist (elt constant-pool name-index) .bytes)) :read-only t) 172 | (descriptor (concat (let-alist (elt constant-pool descriptor-index) .bytes)) :read-only t) 173 | (operand-stack (let ((code-attribute (cl-find-if (lambda (attr) (jvm--classfile-code-attribute-p attr)) attributes))) 174 | (make-ring (if code-attribute 175 | (jvm--classfile-code-attribute-max-stack code-attribute) 176 | 0)))) 177 | (local-variables (let ((code-attribute (cl-find-if (lambda (attr) (jvm--classfile-code-attribute-p attr)) attributes))) 178 | (make-vector (if code-attribute 179 | (jvm--classfile-code-attribute-max-stack code-attribute) 180 | 0) 181 | nil))) 182 | ) 183 | 184 | (defstruct jvm--classfile-code-attribute 185 | max-stack 186 | max-locals 187 | codes 188 | exception-tables 189 | attributes 190 | ) 191 | 192 | (defun jvm--classfile-load-fields (fields constant-pool) 193 | (map 'vector 194 | (lambda (field) 195 | (let-alist field 196 | (make-jvm--classfile-field 197 | :access-flags .access-flags 198 | :name-index .name-index 199 | :descriptor-index .descriptor-index 200 | :attributes (jvm--classfile-load-attributes .attributes constant-pool) 201 | :constant-pool constant-pool 202 | ))) 203 | fields)) 204 | 205 | (defun jvm--classfile-load-methods (methods constant-pool) 206 | (map 'vector 207 | (lambda (method) 208 | (let-alist method 209 | (make-jvm--classfile-method 210 | :access-flags .access-flags 211 | :name-index .name-index 212 | :descriptor-index .descriptor-index 213 | :attributes (jvm--classfile-load-attributes .attributes constant-pool) 214 | :constant-pool constant-pool 215 | ))) 216 | methods)) 217 | 218 | (defun jvm--classfile-load-attributes (attributes constant-pool) 219 | (map 'vector 220 | (lambda (attr) 221 | (let* ((constant (elt constant-pool (cdr (assq 'attribute-name-index attr)))) 222 | (name (concat (cdr (assq 'bytes constant)))) 223 | (info (cdr (assq 'info attr))) 224 | ) 225 | (cond ((equal name "Code") 226 | (let ((decoded (bindat-unpack jvm--classfile-spec-code-attribute info))) 227 | (make-jvm--classfile-code-attribute 228 | :max-stack (bindat-get-field decoded 'max-stack) 229 | :max-locals (bindat-get-field decoded 'max-locals) 230 | :codes (bindat-get-field decoded 'codes) 231 | :exception-tables (bindat-get-field decoded 'exception-tables) 232 | :attributes (jvm--classfile-load-attributes (bindat-get-field decoded 'attributes) constant-pool) 233 | ))) 234 | ))) 235 | attributes)) 236 | 237 | (defun jvm--classfile-load (filepath) 238 | (let* ((data (with-temp-buffer 239 | (insert-file-contents-literally filepath) 240 | (buffer-substring-no-properties (point-min) (point-max)))) 241 | (decoded (bindat-unpack jvm--classfile-spec-classfile (encode-coding-string data 'raw-text))) 242 | ;; The constant_pool table is indexed from 1 to constant_pool_count-1. 243 | (constant-pool (vconcat [nil] (bindat-get-field decoded 'constant-pool))) 244 | ) 245 | (make-jvm--classfile 246 | :magic (bindat-get-field decoded 'magic) 247 | :minor-version (bindat-get-field decoded 'minor-version) 248 | :major-version (bindat-get-field decoded 'major-version) 249 | :constant-pool constant-pool 250 | :access-flags (bindat-get-field decoded 'access-flags) 251 | :this-class (bindat-get-field decoded 'this-class) 252 | :super-class (bindat-get-field decoded 'super-class) 253 | :interfaces (bindat-get-field decoded 'interfaces) 254 | :fields (jvm--classfile-load-fields (bindat-get-field decoded 'fields) constant-pool) 255 | :methods (jvm--classfile-load-methods (bindat-get-field decoded 'methods) constant-pool) 256 | :attributes (jvm--classfile-load-attributes (bindat-get-field decoded 'attributes) constant-pool) 257 | ))) 258 | 259 | (defun jvm--classfile-find-method (classfile method-name) 260 | (cl-find-if 261 | (lambda (method) 262 | (equal (jvm--classfile-method-name method) method-name)) 263 | (jvm--classfile-methods classfile))) 264 | 265 | (defun jvm--classfile-run-method (method &rest args) 266 | (unless (jvm--classfile-method-p method) 267 | (signal 'wrong-type-argument (list 'jvm--classfile-method-p method))) 268 | 269 | (let* ((code-attribute (cl-find-if 270 | (lambda (attr) 271 | (jvm--classfile-code-attribute-p attr)) 272 | (jvm--classfile-method-attributes method))) 273 | (opcode-and-operands (when code-attribute (jvm--classfile-code-attribute-codes code-attribute))) 274 | (current-code-index 0) 275 | (current-frame (list (cons 'constant-pool (jvm--classfile-method-constant-pool method)) 276 | (cons 'operand-stack (jvm--classfile-method-operand-stack method)) 277 | (cons 'local-variables (jvm--classfile-method-local-variables method)))) 278 | ) 279 | 280 | (aset (let-alist current-frame .local-variables) 0 (vconcat args)) 281 | 282 | (while (not (eq (length opcode-and-operands) current-code-index)) 283 | (let* ((opcode (elt opcode-and-operands current-code-index)) 284 | (instruction (aref jvm--instructions opcode)) 285 | func 286 | operand-count 287 | ) 288 | (when (null instruction) 289 | (error (format "Unknown opcode: %x" opcode))) 290 | (setq func (jvm--instruction-func instruction)) 291 | (setq operand-count (jvm--instruction-operand-count instruction)) 292 | (setq current-code-index (1+ current-code-index)) 293 | (apply func 294 | current-frame 295 | (append (substring opcode-and-operands current-code-index (+ current-code-index operand-count)) nil)) 296 | (setq current-code-index (+ current-code-index operand-count)))) 297 | )) 298 | 299 | (provide 'jvm-classfile) 300 | -------------------------------------------------------------------------------- /jvm-instruction.el: -------------------------------------------------------------------------------- 1 | (require 'let-alist) 2 | 3 | (require 'jvm-util) 4 | (require 'jvm-class) 5 | 6 | (defstruct jvm--instruction 7 | (func nil :read-only t) 8 | (operand-count nil :read-only t) 9 | ) 10 | 11 | (defconst jvm--instructions (make-vector #xFF nil)) 12 | 13 | (aset jvm--instructions #x02 (make-jvm--instruction 14 | :func #'jvm--instruction-iconst-m1 15 | :operand-count 0)) 16 | 17 | (aset jvm--instructions #x03 (make-jvm--instruction 18 | :func #'jvm--instruction-iconst-0 19 | :operand-count 0)) 20 | 21 | (aset jvm--instructions #x04 (make-jvm--instruction 22 | :func #'jvm--instruction-iconst-1 23 | :operand-count 0)) 24 | 25 | (aset jvm--instructions #x05 (make-jvm--instruction 26 | :func #'jvm--instruction-iconst-2 27 | :operand-count 0)) 28 | 29 | (aset jvm--instructions #x06 (make-jvm--instruction 30 | :func #'jvm--instruction-iconst-3 31 | :operand-count 0)) 32 | 33 | (aset jvm--instructions #x07 (make-jvm--instruction 34 | :func #'jvm--instruction-iconst-4 35 | :operand-count 0)) 36 | 37 | (aset jvm--instructions #x08 (make-jvm--instruction 38 | :func #'jvm--instruction-iconst-5 39 | :operand-count 0)) 40 | 41 | (aset jvm--instructions #x12 (make-jvm--instruction 42 | :func #'jvm--instruction-ldc 43 | :operand-count 1)) 44 | 45 | (aset jvm--instructions #x1A (make-jvm--instruction 46 | :func #'jvm--instruction-iload-0 47 | :operand-count 0)) 48 | 49 | (aset jvm--instructions #x1B (make-jvm--instruction 50 | :func #'jvm--instruction-iload-1 51 | :operand-count 0)) 52 | 53 | (aset jvm--instructions #x1C (make-jvm--instruction 54 | :func #'jvm--instruction-iload-2 55 | :operand-count 0)) 56 | 57 | (aset jvm--instructions #x1D (make-jvm--instruction 58 | :func #'jvm--instruction-iload-3 59 | :operand-count 0)) 60 | 61 | (aset jvm--instructions #x2A (make-jvm--instruction 62 | :func #'jvm--instruction-aload-0 63 | :operand-count 0)) 64 | 65 | (aset jvm--instructions #x2B (make-jvm--instruction 66 | :func #'jvm--instruction-aload-1 67 | :operand-count 0)) 68 | 69 | (aset jvm--instructions #x2C (make-jvm--instruction 70 | :func #'jvm--instruction-aload-2 71 | :operand-count 0)) 72 | 73 | (aset jvm--instructions #x2D (make-jvm--instruction 74 | :func #'jvm--instruction-aload-3 75 | :operand-count 0)) 76 | 77 | (aset jvm--instructions #x32 (make-jvm--instruction 78 | :func #'jvm--instruction-aaload 79 | :operand-count 0)) 80 | 81 | (aset jvm--instructions #x3B (make-jvm--instruction 82 | :func #'jvm--instruction-istore-0 83 | :operand-count 0)) 84 | 85 | (aset jvm--instructions #x3C (make-jvm--instruction 86 | :func #'jvm--instruction-istore-1 87 | :operand-count 0)) 88 | 89 | (aset jvm--instructions #x3D (make-jvm--instruction 90 | :func #'jvm--instruction-istore-2 91 | :operand-count 0)) 92 | 93 | (aset jvm--instructions #x3E (make-jvm--instruction 94 | :func #'jvm--instruction-istore-3 95 | :operand-count 0)) 96 | 97 | (aset jvm--instructions #x53 (make-jvm--instruction 98 | :func #'jvm--instruction-aastore 99 | :operand-count 0)) 100 | 101 | (aset jvm--instructions #x57 (make-jvm--instruction 102 | :func #'jvm--instruction-pop 103 | :operand-count 0)) 104 | 105 | (aset jvm--instructions #x59 (make-jvm--instruction 106 | :func #'jvm--instruction-dup 107 | :operand-count 0)) 108 | 109 | (aset jvm--instructions #x60 (make-jvm--instruction 110 | :func #'jvm--instruction-iadd 111 | :operand-count 0)) 112 | 113 | (aset jvm--instructions #x68 (make-jvm--instruction 114 | :func #'jvm--instruction-imul 115 | :operand-count 0)) 116 | 117 | (aset jvm--instructions #xB1 (make-jvm--instruction 118 | :func #'jvm--instruction-return 119 | :operand-count 0)) 120 | 121 | (aset jvm--instructions #xB2 (make-jvm--instruction 122 | :func #'jvm--instruction-getstatic 123 | :operand-count 2)) 124 | 125 | (aset jvm--instructions #xB6 (make-jvm--instruction 126 | :func #'jvm--instruction-invokevirtual 127 | :operand-count 2)) 128 | 129 | (aset jvm--instructions #xB8 (make-jvm--instruction 130 | :func #'jvm--instruction-invokestatic 131 | :operand-count 2)) 132 | 133 | (aset jvm--instructions #xBD (make-jvm--instruction 134 | :func #'jvm--instruction-anewarray 135 | :operand-count 2)) 136 | 137 | (defun jvm--instruction-iconst-m1 (frame) 138 | (ring-insert (let-alist frame .operand-stack) -1)) 139 | 140 | (defun jvm--instruction-iconst-0 (frame) 141 | (ring-insert (let-alist frame .operand-stack) 0)) 142 | 143 | (defun jvm--instruction-iconst-1 (frame) 144 | (ring-insert (let-alist frame .operand-stack) 1)) 145 | 146 | (defun jvm--instruction-iconst-2 (frame) 147 | (ring-insert (let-alist frame .operand-stack) 2)) 148 | 149 | (defun jvm--instruction-iconst-3 (frame) 150 | (ring-insert (let-alist frame .operand-stack) 3)) 151 | 152 | (defun jvm--instruction-iconst-4 (frame) 153 | (ring-insert (let-alist frame .operand-stack) 4)) 154 | 155 | (defun jvm--instruction-iconst-5 (frame) 156 | (ring-insert (let-alist frame .operand-stack) 5)) 157 | 158 | (defun jvm--instruction-aaload (frame) 159 | (let-alist frame 160 | (let ((index (ring-remove .operand-stack 0)) 161 | (arrayref (ring-remove .operand-stack 0))) 162 | (ring-insert .operand-stack (aref arrayref index))))) 163 | 164 | (defun jvm--instruction-istore-0 (frame) 165 | (let-alist frame 166 | (aset .local-variables 0 (ring-remove .operand-stack 0)))) 167 | 168 | (defun jvm--instruction-istore-1 (frame) 169 | (let-alist frame 170 | (aset .local-variables 1 (ring-remove .operand-stack 0)))) 171 | 172 | (defun jvm--instruction-istore-2 (frame) 173 | (let-alist frame 174 | (aset .local-variables 2 (ring-remove .operand-stack 0)))) 175 | 176 | (defun jvm--instruction-istore-3 (frame) 177 | (let-alist frame 178 | (aset .local-variables 3 (ring-remove .operand-stack 0)))) 179 | 180 | (defun jvm--instruction-ldc (frame index) 181 | (let-alist frame 182 | (let* ((constant-pool .constant-pool) 183 | (value (elt constant-pool index))) 184 | (ring-insert .operand-stack 185 | (let-alist value 186 | (case .tag 187 | (8 (concat (let-alist (elt constant-pool .string-index) .bytes))) 188 | (t value))) 189 | )))) 190 | 191 | (defun jvm--instruction-iload-0 (frame) 192 | (let-alist frame 193 | (ring-insert .operand-stack (aref .local-variables 0)))) 194 | 195 | (defun jvm--instruction-iload-1 (frame) 196 | (let-alist frame 197 | (ring-insert .operand-stack (aref .local-variables 1)))) 198 | 199 | (defun jvm--instruction-iload-2 (frame) 200 | (let-alist frame 201 | (ring-insert .operand-stack (aref .local-variables 2)))) 202 | 203 | (defun jvm--instruction-iload-3 (frame) 204 | (let-alist frame 205 | (ring-insert .operand-stack (aref .local-variables 3)))) 206 | 207 | (defun jvm--instruction-aload-0 (frame) 208 | (let-alist frame 209 | (ring-insert .operand-stack (aref .local-variables 0)))) 210 | 211 | (defun jvm--instruction-aload-1 (frame) 212 | (let-alist frame 213 | (ring-insert .operand-stack (aref .local-variables 1)))) 214 | 215 | (defun jvm--instruction-aload-2 (frame) 216 | (let-alist frame 217 | (ring-insert .operand-stack (aref .local-variables 2)))) 218 | 219 | (defun jvm--instruction-aload-3 (frame) 220 | (let-alist frame 221 | (ring-insert .operand-stack (aref .local-variables 3)))) 222 | 223 | (defun jvm--instruction-getstatic (frame indexbyte1 indexbyte2) 224 | (let ((index (logior (lsh indexbyte1 8) indexbyte2))) 225 | (let-alist frame 226 | (ring-insert .operand-stack (elt .constant-pool index))))) 227 | 228 | (defun jvm--instruction-aastore (frame) 229 | (let-alist frame 230 | (let ((value (ring-remove .operand-stack 0)) 231 | (index (ring-remove .operand-stack 0)) 232 | (arrayref (ring-remove .operand-stack 0))) 233 | (aset arrayref index value)))) 234 | 235 | (defun jvm--instruction-pop (frame) 236 | (let-alist frame 237 | (ring-remove .operand-stack 0))) 238 | 239 | (defun jvm--instruction-dup (frame) 240 | (let-alist frame 241 | (let ((v (ring-remove .operand-stack 0))) 242 | (ring-insert .operand-stack v) 243 | (ring-insert .operand-stack v)))) 244 | 245 | (defun jvm--instruction-iadd (frame) 246 | (let-alist frame 247 | (let ((v1 (ring-remove .operand-stack 0)) 248 | (v2 (ring-remove .operand-stack 0))) 249 | (ring-insert .operand-stack (+ v1 v2))))) 250 | 251 | (defun jvm--instruction-imul (frame) 252 | (let-alist frame 253 | (let ((v1 (ring-remove .operand-stack 0)) 254 | (v2 (ring-remove .operand-stack 0))) 255 | (ring-insert .operand-stack (* v1 v2))))) 256 | 257 | (defun jvm--instruction-return (frame) 258 | ;; Nothing to do 259 | ) 260 | 261 | (defun jvm--instruction-invokevirtual (frame indexbyte1 indexbyte2) 262 | (let ((constant-pool (cdr (assoc 'constant-pool frame))) 263 | (operand-stack (cdr (assoc 'operand-stack frame))) 264 | (pool-index (logior (lsh indexbyte1 8) indexbyte2)) 265 | (callee-info nil) 266 | (method-name nil) 267 | (method-arg-descriptor nil) 268 | (method-arg-count nil) 269 | (method-args nil) 270 | (invoker-class nil) 271 | ) 272 | 273 | (setq callee-info (elt constant-pool (let-alist (elt constant-pool pool-index) .name-and-type-index))) 274 | (setq method-name (concat (let-alist (elt constant-pool (let-alist callee-info .name-index)) .bytes))) 275 | (setq method-arg-descriptor (concat (let-alist (elt constant-pool (let-alist callee-info .descriptor-index)) .bytes))) 276 | (setq method-arg-count (let-alist (jvm--util-parse-signature method-arg-descriptor) .arguments-count)) 277 | (setq method-args (make-vector method-arg-count nil)) 278 | 279 | (dotimes (i method-arg-count) 280 | (aset method-args (- method-arg-count i 1) (ring-remove operand-stack 0))) 281 | 282 | (setq callee (ring-remove operand-stack 0)) 283 | 284 | (setq callee-class (concat (let-alist (elt constant-pool (let-alist (elt constant-pool (let-alist callee .class-index)) .name-index)) .bytes))) 285 | (setq callee-field (concat (let-alist (elt constant-pool (let-alist (elt constant-pool (let-alist callee .name-and-type-index)) .name-index)) .bytes))) 286 | 287 | (setq hoge (gethash callee-field (jvm--builtin-class-fields (gethash callee-class jvm--builtin-class-table)))) 288 | (setq func (gethash method-name (jvm--builtin-class-methods hoge))) 289 | 290 | (ring-insert operand-stack (apply func (append method-args nil))) 291 | )) 292 | 293 | (defun jvm--instruction-invokestatic (frame indexbyte1 indexbyte2) 294 | (let ((constant-pool (cdr (assoc 'constant-pool frame))) 295 | (operand-stack (cdr (assoc 'operand-stack frame))) 296 | (pool-index (logior (lsh indexbyte1 8) indexbyte2)) 297 | (callee-info nil) 298 | (method-name nil) 299 | (method-arg-descriptor nil) 300 | (method-arg-count nil) 301 | (method-args nil) 302 | (invoker-class nil) 303 | ) 304 | 305 | (setq class-info (elt constant-pool (let-alist (elt constant-pool pool-index) .class-index))) 306 | (setq class-name (concat (let-alist (elt constant-pool (let-alist class-info .name-index)) .bytes))) 307 | (setq callee-info (elt constant-pool (let-alist (elt constant-pool pool-index) .name-and-type-index))) 308 | (setq method-name (concat (let-alist (elt constant-pool (let-alist callee-info .name-index)) .bytes))) 309 | (setq method-arg-descriptor (concat (let-alist (elt constant-pool (let-alist callee-info .descriptor-index)) .bytes))) 310 | (setq method-arg-count (let-alist (jvm--util-parse-signature method-arg-descriptor) .arguments-count)) 311 | (setq method-args (make-vector method-arg-count nil)) 312 | 313 | (dotimes (i method-arg-count) 314 | (aset method-args (- method-arg-count i 1) (ring-remove operand-stack 0))) 315 | 316 | (setq hoge (gethash class-name jvm--builtin-class-table)) 317 | (setq func (gethash method-name (jvm--builtin-class-static-methods hoge))) 318 | 319 | (ring-insert operand-stack (apply func (append method-args nil))) 320 | )) 321 | 322 | (defun jvm--instruction-anewarray (frame _indexbyte1 _indexbyte2) 323 | (let-alist frame 324 | (let ((count (ring-remove .operand-stack 0))) 325 | (ring-insert .operand-stack (make-vector count nil))))) 326 | 327 | (provide 'jvm-instruction) 328 | --------------------------------------------------------------------------------