├── .gitignore ├── LICENSE ├── README.md ├── examples └── Helloworld.json ├── jvm-assembler-server ├── pom.xml └── src │ ├── assembly │ └── distribution.xml │ └── main │ └── java │ └── com │ └── mmhelloworld │ └── jvmassembler │ └── server │ ├── Asm.java │ ├── AssemblerApp.java │ ├── AssemblerResource.java │ ├── AssemblerResponse.java │ ├── AssemblerServer.java │ ├── Config.java │ └── CreateBytecode.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | ########################## 2 | # those should be ignored 3 | ########################## 4 | *~ 5 | *.class 6 | *.jar 7 | target/ 8 | 9 | ################# 10 | ## Eclipse 11 | ################# 12 | .classpath 13 | .project 14 | .metadata 15 | tmp/ 16 | *.tmp 17 | *.bak 18 | *.swp 19 | *~.nib 20 | local.properties 21 | .settings/ 22 | .loadpath 23 | 24 | # Intellij idea 25 | *.iml 26 | 27 | # External tool builders 28 | .externalToolBuilders/ 29 | 30 | # Locally stored "Eclipse launch configurations" 31 | *.launch 32 | 33 | # CDT-specific 34 | .cproject 35 | 36 | # PDT-specific 37 | .buildpath 38 | 39 | ############ 40 | ## Windows 41 | ############ 42 | 43 | # Windows image file caches 44 | Thumbs.db 45 | 46 | # Folder config file 47 | Desktop.ini 48 | 49 | *.versionsBackup 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Marimuthu Madasamy (c) 2016 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Marimuthu Madasamy nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JVM bytecode assembler server 2 | Assemble JVM bytecode via REST endpoint 3 | 4 | ## Example 5 | 6 | ```bash 7 | $ mvn package 8 | 9 | $ jvm-assembler-server/target/appassembler/bin/jvmasm --port 8080 & 10 | 11 | $ cat examples/Helloworld.json 12 | ``` 13 | ```json 14 | { 15 | "instructions": [ 16 | { 17 | "flags": 1, 18 | "type": "CreateClass" 19 | }, 20 | { 21 | "parent": "java/lang/Object", 22 | "interfaces": [], 23 | "name": "Helloworld", 24 | "version": 52, 25 | "sig": null, 26 | "type": "ClassCodeStart", 27 | "acc": 1 28 | }, 29 | { 30 | "type": "SourceInfo", 31 | "name": "Helloworld.idr" 32 | }, 33 | { 34 | "excs": null, 35 | "name": "", 36 | "sig": null, 37 | "type": "CreateMethod", 38 | "desc": "()V", 39 | "acc": 1 40 | }, 41 | { 42 | "type": "MethodCodeStart" 43 | }, 44 | { 45 | "type": "Aload", 46 | "index": 0 47 | }, 48 | { 49 | "cname": "java/lang/Object", 50 | "isIntf": false, 51 | "mname": "", 52 | "type": "InvokeMethod", 53 | "desc": "()V", 54 | "invType": 183 55 | }, 56 | { 57 | "type": "Return" 58 | }, 59 | { 60 | "nstack": -1, 61 | "type": "MaxStackAndLocal", 62 | "nlocal": -1 63 | }, 64 | { 65 | "type": "MethodCodeEnd" 66 | }, 67 | { 68 | "excs": null, 69 | "name": "main", 70 | "sig": null, 71 | "type": "CreateMethod", 72 | "desc": "([Ljava/lang/String;)V", 73 | "acc": 9 74 | }, 75 | { 76 | "type": "MethodCodeStart" 77 | }, 78 | { 79 | "cname": "java/lang/System", 80 | "ftype": 178, 81 | "type": "Field", 82 | "desc": "Ljava/io/PrintStream;", 83 | "fname": "out" 84 | }, 85 | { 86 | "constType": "StringConst", 87 | "type": "Ldc", 88 | "val": "Hello world!" 89 | }, 90 | { 91 | "cname": "java/io/PrintStream", 92 | "isIntf": false, 93 | "mname": "println", 94 | "type": "InvokeMethod", 95 | "desc": "(Ljava/lang/Object;)V", 96 | "invType": 182 97 | }, 98 | { 99 | "type": "Return" 100 | }, 101 | { 102 | "nstack": -1, 103 | "type": "MaxStackAndLocal", 104 | "nlocal": -1 105 | }, 106 | { 107 | "type": "MethodCodeEnd" 108 | }, 109 | { 110 | "type": "ClassCodeEnd", 111 | "out": "Helloworld.class" 112 | } 113 | ] 114 | } 115 | ``` 116 | 117 | ```bash 118 | $ curl -H "Content-Type: application/json" -X POST -d @examples/Helloworld.json http://localhost:8080/assembler/assemble 119 | {"message":"","success":true} 120 | 121 | $ java Helloworld 122 | Hello world! 123 | ``` 124 | -------------------------------------------------------------------------------- /examples/Helloworld.json: -------------------------------------------------------------------------------- 1 | { 2 | "instructions": [ 3 | { 4 | "flags": 1, 5 | "type": "CreateClass" 6 | }, 7 | { 8 | "parent": "java/lang/Object", 9 | "interfaces": [], 10 | "name": "Helloworld", 11 | "version": 52, 12 | "sig": null, 13 | "type": "ClassCodeStart", 14 | "acc": 1 15 | }, 16 | { 17 | "type": "SourceInfo", 18 | "name": "Helloworld.idr" 19 | }, 20 | { 21 | "excs": null, 22 | "cname": "Helloworld", 23 | "fname": "", 24 | "sig": null, 25 | "type": "CreateMethod", 26 | "desc": "()V", 27 | "acc": 1 28 | }, 29 | { 30 | "type": "MethodCodeStart" 31 | }, 32 | { 33 | "type": "Aload", 34 | "index": 0 35 | }, 36 | { 37 | "cname": "java/lang/Object", 38 | "isIntf": false, 39 | "mname": "", 40 | "type": "InvokeMethod", 41 | "desc": "()V", 42 | "invType": 183 43 | }, 44 | { 45 | "type": "Return" 46 | }, 47 | { 48 | "nstack": -1, 49 | "type": "MaxStackAndLocal", 50 | "nlocal": -1 51 | }, 52 | { 53 | "type": "MethodCodeEnd" 54 | }, 55 | { 56 | "excs": null, 57 | "cname": "Helloworld", 58 | "fname": "main", 59 | "sig": null, 60 | "type": "CreateMethod", 61 | "desc": "([Ljava/lang/String;)V", 62 | "acc": 9 63 | }, 64 | { 65 | "type": "MethodCodeStart" 66 | }, 67 | { 68 | "cname": "java/lang/System", 69 | "ftype": 178, 70 | "type": "Field", 71 | "desc": "Ljava/io/PrintStream;", 72 | "fname": "out" 73 | }, 74 | { 75 | "type": "LdcString", 76 | "val": "Hello world!" 77 | }, 78 | { 79 | "cname": "java/io/PrintStream", 80 | "isIntf": false, 81 | "mname": "println", 82 | "type": "InvokeMethod", 83 | "desc": "(Ljava/lang/Object;)V", 84 | "invType": 182 85 | }, 86 | { 87 | "type": "Return" 88 | }, 89 | { 90 | "nstack": -1, 91 | "type": "MaxStackAndLocal", 92 | "nlocal": -1 93 | }, 94 | { 95 | "type": "MethodCodeEnd" 96 | }, 97 | { 98 | "type": "ClassCodeEnd", 99 | "out": "." 100 | } 101 | ] 102 | } 103 | -------------------------------------------------------------------------------- /jvm-assembler-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | jvm-assembler 7 | com.mmhelloworld 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | jvm-assembler-server 13 | jar 14 | 15 | 16 | 17 | 18 | maven-compiler-plugin 19 | 3.5.1 20 | 21 | 1.8 22 | 1.8 23 | 24 | 25 | 26 | org.codehaus.mojo 27 | appassembler-maven-plugin 28 | 1.10 29 | 30 | 31 | 32 | com.mmhelloworld.jvmassembler.server.AssemblerServer 33 | jvmasm 34 | 35 | 750m 36 | 37 | 38 | 39 | ${basedir}/../LICENSE 40 | lib 41 | 42 | 43 | 44 | package 45 | 46 | assemble 47 | 48 | 49 | 50 | 51 | 52 | maven-assembly-plugin 53 | 2.6 54 | 55 | false 56 | 57 | src/assembly/distribution.xml 58 | 59 | 60 | 61 | 62 | package 63 | 64 | assembly 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | org.glassfish.jersey.containers 76 | jersey-container-servlet-core 77 | 78 | 79 | 80 | org.glassfish.jersey.media 81 | jersey-media-json-jackson 82 | 83 | 84 | 85 | org.eclipse.jetty 86 | jetty-server 87 | 88 | 89 | 90 | com.fasterxml.jackson.core 91 | jackson-core 92 | 93 | 94 | 95 | com.fasterxml.jackson.core 96 | jackson-annotations 97 | 98 | 99 | 100 | com.fasterxml.jackson.core 101 | jackson-databind 102 | 103 | 104 | 105 | org.eclipse.jetty 106 | jetty-servlet 107 | 108 | 109 | 110 | net.sf.jopt-simple 111 | jopt-simple 112 | 113 | 114 | 115 | org.ow2.asm 116 | asm-all 117 | 118 | 119 | 120 | org.projectlombok 121 | lombok 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /jvm-assembler-server/src/assembly/distribution.xml: -------------------------------------------------------------------------------- 1 | 4 | distribution 5 | 6 | zip 7 | 8 | 9 | 10 | ${basedir}/.. 11 | 12 | LICENSE 13 | 14 | 15 | 16 | ${project.build.directory}/appassembler/lib 17 | lib 18 | 19 | 20 | ${project.build.directory}/appassembler/bin 21 | bin 22 | 0755 23 | 24 | 25 | -------------------------------------------------------------------------------- /jvm-assembler-server/src/main/java/com/mmhelloworld/jvmassembler/server/Asm.java: -------------------------------------------------------------------------------- 1 | package com.mmhelloworld.jvmassembler.server; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.annotation.JsonSubTypes; 6 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 7 | import lombok.ToString; 8 | 9 | import java.util.List; 10 | 11 | @JsonTypeInfo( 12 | use = JsonTypeInfo.Id.NAME, 13 | include = JsonTypeInfo.As.PROPERTY, 14 | property = "type", 15 | visible = true) 16 | @JsonSubTypes({ 17 | @JsonSubTypes.Type(value = Asm.Aaload.class, name = "Aaload"), 18 | @JsonSubTypes.Type(value = Asm.Aastore.class, name = "Aastore"), 19 | @JsonSubTypes.Type(value = Asm.Aconstnull.class, name = "Aconstnull"), 20 | @JsonSubTypes.Type(value = Asm.Aload.class, name = "Aload"), 21 | @JsonSubTypes.Type(value = Asm.Anewarray.class, name = "Anewarray"), 22 | @JsonSubTypes.Type(value = Asm.Annotation.class, name = "Annotation"), 23 | @JsonSubTypes.Type(value = Asm.Astore.class, name = "Astore"), 24 | @JsonSubTypes.Type(value = Asm.Areturn.class, name = "Areturn"), 25 | @JsonSubTypes.Type(value = Asm.Checkcast.class, name = "Checkcast"), 26 | @JsonSubTypes.Type(value = Asm.ClassCodeStart.class, name = "ClassCodeStart"), 27 | @JsonSubTypes.Type(value = Asm.ClassCodeEnd.class, name = "ClassCodeEnd"), 28 | @JsonSubTypes.Type(value = Asm.CreateClass.class, name = "CreateClass"), 29 | @JsonSubTypes.Type(value = Asm.CreateField.class, name = "CreateField"), 30 | @JsonSubTypes.Type(value = Asm.CreateLabel.class, name = "CreateLabel"), 31 | @JsonSubTypes.Type(value = Asm.CreateMethod.class, name = "CreateMethod"), 32 | @JsonSubTypes.Type(value = Asm.Dadd.class, name = "Dadd"), 33 | @JsonSubTypes.Type(value = Asm.Ddiv.class, name = "Ddiv"), 34 | @JsonSubTypes.Type(value = Asm.Dload.class, name = "Dload"), 35 | @JsonSubTypes.Type(value = Asm.Dmul.class, name = "Dmul"), 36 | @JsonSubTypes.Type(value = Asm.Drem.class, name = "Drem"), 37 | @JsonSubTypes.Type(value = Asm.Dreturn.class, name = "Dreturn"), 38 | @JsonSubTypes.Type(value = Asm.Dsub.class, name = "Dsub"), 39 | @JsonSubTypes.Type(value = Asm.Dup.class, name = "Dup"), 40 | @JsonSubTypes.Type(value = Asm.F2d.class, name = "F2d"), 41 | @JsonSubTypes.Type(value = Asm.Field.class, name = "Field"), 42 | @JsonSubTypes.Type(value = Asm.FieldEnd.class, name = "FieldEnd"), 43 | @JsonSubTypes.Type(value = Asm.Fload.class, name = "Fload"), 44 | @JsonSubTypes.Type(value = Asm.Frame.class, name = "Frame"), 45 | @JsonSubTypes.Type(value = Asm.Freturn.class, name = "Freturn"), 46 | @JsonSubTypes.Type(value = Asm.Goto.class, name = "Goto"), 47 | @JsonSubTypes.Type(value = Asm.I2c.class, name = "I2c"), 48 | @JsonSubTypes.Type(value = Asm.I2l.class, name = "I2l"), 49 | @JsonSubTypes.Type(value = Asm.Iadd.class, name = "Iadd"), 50 | @JsonSubTypes.Type(value = Asm.Iand.class, name = "Iand"), 51 | @JsonSubTypes.Type(value = Asm.Iconst.class, name = "Iconst"), 52 | @JsonSubTypes.Type(value = Asm.Idiv.class, name = "Idiv"), 53 | @JsonSubTypes.Type(value = Asm.Ifeq.class, name = "Ifeq"), 54 | @JsonSubTypes.Type(value = Asm.Ificmpge.class, name = "Ificmpge"), 55 | @JsonSubTypes.Type(value = Asm.Ificmpgt.class, name = "Ificmpgt"), 56 | @JsonSubTypes.Type(value = Asm.Ificmple.class, name = "Ificmple"), 57 | @JsonSubTypes.Type(value = Asm.Ificmplt.class, name = "Ificmplt"), 58 | @JsonSubTypes.Type(value = Asm.Iload.class, name = "Iload"), 59 | @JsonSubTypes.Type(value = Asm.Imul.class, name = "Imul"), 60 | @JsonSubTypes.Type(value = Asm.InvokeMethod.class, name = "InvokeMethod"), 61 | @JsonSubTypes.Type(value = Asm.InvokeDynamic.class, name = "InvokeDynamic"), 62 | @JsonSubTypes.Type(value = Asm.Irem.class, name = "Irem"), 63 | @JsonSubTypes.Type(value = Asm.Ireturn.class, name = "Ireturn"), 64 | @JsonSubTypes.Type(value = Asm.Ishl.class, name = "Ishl"), 65 | @JsonSubTypes.Type(value = Asm.Ishr.class, name = "Ishr"), 66 | @JsonSubTypes.Type(value = Asm.Istore.class, name = "Istore"), 67 | @JsonSubTypes.Type(value = Asm.Isub.class, name = "Isub"), 68 | @JsonSubTypes.Type(value = Asm.Iushr.class, name = "Iushr"), 69 | @JsonSubTypes.Type(value = Asm.L2i.class, name = "L2i"), 70 | @JsonSubTypes.Type(value = Asm.LabelStart.class, name = "LabelStart"), 71 | @JsonSubTypes.Type(value = Asm.Ladd.class, name = "Ladd"), 72 | @JsonSubTypes.Type(value = Asm.Land.class, name = "Land"), 73 | @JsonSubTypes.Type(value = Asm.LdcDouble.class, name = "LdcDouble"), 74 | @JsonSubTypes.Type(value = Asm.LdcInteger.class, name = "LdcInteger"), 75 | @JsonSubTypes.Type(value = Asm.LdcString.class, name = "LdcString"), 76 | @JsonSubTypes.Type(value = Asm.LdcLong.class, name = "LdcLong"), 77 | @JsonSubTypes.Type(value = Asm.LdcType.class, name = "LdcType"), 78 | @JsonSubTypes.Type(value = Asm.Ldiv.class, name = "Ldiv"), 79 | @JsonSubTypes.Type(value = Asm.Lload.class, name = "Lload"), 80 | @JsonSubTypes.Type(value = Asm.Lmul.class, name = "Lmul"), 81 | @JsonSubTypes.Type(value = Asm.Lreturn.class, name = "Lreturn"), 82 | @JsonSubTypes.Type(value = Asm.Lshl.class, name = "Lshl"), 83 | @JsonSubTypes.Type(value = Asm.Lshr.class, name = "Lshr"), 84 | @JsonSubTypes.Type(value = Asm.LookupSwitch.class, name = "LookupSwitch"), 85 | @JsonSubTypes.Type(value = Asm.Lrem.class, name = "Lrem"), 86 | @JsonSubTypes.Type(value = Asm.Lsub.class, name = "Lsub"), 87 | @JsonSubTypes.Type(value = Asm.Lushr.class, name = "Lushr"), 88 | @JsonSubTypes.Type(value = Asm.MaxStackAndLocal.class, name = "MaxStackAndLocal"), 89 | @JsonSubTypes.Type(value = Asm.MethodCodeStart.class, name = "MethodCodeStart"), 90 | @JsonSubTypes.Type(value = Asm.MethodCodeEnd.class, name = "MethodCodeEnd"), 91 | @JsonSubTypes.Type(value = Asm.New.class, name = "New"), 92 | @JsonSubTypes.Type(value = Asm.Pop.class, name = "Pop"), 93 | @JsonSubTypes.Type(value = Asm.Return.class, name = "Return"), 94 | @JsonSubTypes.Type(value = Asm.SourceInfo.class, name = "SourceInfo") 95 | 96 | }) 97 | public abstract class Asm { 98 | private AsmType type; 99 | 100 | public AsmType getType() { 101 | return type; 102 | } 103 | 104 | public void setType(final AsmType type) { 105 | this.type = type; 106 | } 107 | 108 | public enum AsmType { 109 | Aaload, 110 | Aastore, 111 | Aconstnull, 112 | Aload, 113 | Anewarray, 114 | Annotation, 115 | Astore, 116 | Areturn, 117 | Checkcast, 118 | ClassCodeStart, 119 | ClassCodeEnd, 120 | CreateClass, 121 | CreateField, 122 | CreateLabel, 123 | CreateMethod, 124 | Dadd, 125 | Ddiv, 126 | Dload, 127 | Dmul, 128 | Drem, 129 | Dreturn, 130 | Dsub, 131 | Dup, 132 | F2d, 133 | Field, 134 | FieldEnd, 135 | Fload, 136 | Frame, 137 | Freturn, 138 | Goto, 139 | I2c, 140 | I2l, 141 | Iadd, 142 | Iand, 143 | Iconst, 144 | Idiv, 145 | Ifeq, 146 | Ificmpge, 147 | Ificmpgt, 148 | Ificmple, 149 | Ificmplt, 150 | Iload, 151 | Imul, 152 | InvokeMethod, 153 | InvokeDynamic, 154 | Irem, 155 | Ireturn, 156 | Ishl, 157 | Ishr, 158 | Istore, 159 | Isub, 160 | Iushr, 161 | L2i, 162 | LabelStart, 163 | Ladd, 164 | Land, 165 | LdcDouble, 166 | LdcInteger, 167 | LdcLong, 168 | LdcString, 169 | LdcType, 170 | Ldiv, 171 | Lload, 172 | Lmul, 173 | Lreturn, 174 | Lshl, 175 | Lshr, 176 | LookupSwitch, 177 | Lrem, 178 | Lsub, 179 | Lushr, 180 | MaxStackAndLocal, 181 | MethodCodeStart, 182 | MethodCodeEnd, 183 | New, 184 | Pop, 185 | Return, 186 | SourceInfo 187 | } 188 | 189 | public static final class CreateClass extends Asm { 190 | private final int flags; 191 | 192 | @JsonCreator 193 | public CreateClass(@JsonProperty("flags") int flags) { 194 | this.flags = flags; 195 | } 196 | 197 | public int getFlags() { 198 | return flags; 199 | } 200 | } 201 | 202 | public static final class Aaload extends Asm { 203 | 204 | } 205 | 206 | public static final class Aastore extends Asm { 207 | } 208 | 209 | public static final class CreateLabel extends Asm { 210 | private final String label; 211 | 212 | public CreateLabel(@JsonProperty("name") String label) { 213 | this.label = label; 214 | } 215 | 216 | public String getLabel() { 217 | return label; 218 | } 219 | } 220 | 221 | public static final class Goto extends Asm { 222 | private final String label; 223 | 224 | public Goto(@JsonProperty("name") String label) { 225 | this.label = label; 226 | } 227 | 228 | public String getLabel() { 229 | return label; 230 | } 231 | } 232 | 233 | public static class Aconstnull extends Asm { 234 | } 235 | 236 | public static class Aload extends Asm { 237 | private final int index; 238 | 239 | public Aload(@JsonProperty("index") final int index) { 240 | this.index = index; 241 | } 242 | 243 | public int getIndex() { 244 | return index; 245 | } 246 | } 247 | 248 | public static class Anewarray extends Asm { 249 | private final String desc; 250 | 251 | public Anewarray(@JsonProperty("desc") final String desc) { 252 | this.desc = desc; 253 | } 254 | 255 | public String getDesc() { 256 | return desc; 257 | } 258 | } 259 | 260 | public static class Astore extends Asm { 261 | private final int index; 262 | 263 | public Astore(@JsonProperty("index") final int index) { 264 | this.index = index; 265 | } 266 | 267 | public int getIndex() { 268 | return index; 269 | } 270 | } 271 | 272 | public static class Areturn extends Asm { 273 | } 274 | 275 | public static class Ireturn extends Asm { 276 | } 277 | 278 | public static class Dreturn extends Asm { 279 | } 280 | 281 | public static class Freturn extends Asm { 282 | } 283 | 284 | public static class F2d extends Asm { 285 | } 286 | 287 | public static class Lreturn extends Asm { 288 | } 289 | 290 | public static class Checkcast extends Asm { 291 | private final String desc; 292 | 293 | public Checkcast(@JsonProperty("desc") final String desc) { 294 | this.desc = desc; 295 | } 296 | 297 | public String getDesc() { 298 | return desc; 299 | } 300 | } 301 | 302 | public static class ClassCodeStart extends Asm { 303 | private final int version; 304 | private final int acc; 305 | private final String name; 306 | private final String sig; 307 | private final String parent; 308 | private final String[] interfaces; 309 | private final List annotations; 310 | 311 | public ClassCodeStart(@JsonProperty("version") final int version, 312 | @JsonProperty("acc") final int acc, 313 | @JsonProperty("name") final String name, 314 | @JsonProperty("sig") final String sig, 315 | @JsonProperty("parent") final String parent, 316 | @JsonProperty("interfaces") final String[] interfaces, 317 | @JsonProperty("annotations") final List annotations) { 318 | this.version = version; 319 | this.acc = acc; 320 | this.name = name; 321 | this.sig = sig; 322 | this.parent = parent; 323 | this.interfaces = interfaces; 324 | this.annotations = annotations; 325 | } 326 | 327 | public int getVersion() { 328 | return version; 329 | } 330 | 331 | public int getAcc() { 332 | return acc; 333 | } 334 | 335 | public String getName() { 336 | return name; 337 | } 338 | 339 | public String getSig() { 340 | return sig; 341 | } 342 | 343 | public String getParent() { 344 | return parent; 345 | } 346 | 347 | public String[] getInterfaces() { 348 | return interfaces; 349 | } 350 | 351 | public List getAnnotations() { 352 | return annotations; 353 | } 354 | } 355 | 356 | public static class ClassCodeEnd extends Asm { 357 | private final String out; 358 | 359 | public ClassCodeEnd(@JsonProperty("out") final String out) { 360 | this.out = out; 361 | } 362 | 363 | public String getOut() { 364 | return out; 365 | } 366 | } 367 | 368 | public static class CreateMethod extends Asm { 369 | private final int acc; 370 | private final String cname; 371 | private final String fname; 372 | private final String desc; 373 | private final String sig; 374 | private final String[] excs; 375 | private final List anns; 376 | private final List> paramAnns; 377 | 378 | public CreateMethod(@JsonProperty("acc") final int acc, 379 | @JsonProperty("cname") final String cname, 380 | @JsonProperty("fname") final String fname, 381 | @JsonProperty("desc") final String desc, 382 | @JsonProperty("sig") final String sig, 383 | @JsonProperty("excs") final String[] excs, 384 | @JsonProperty("anns") final List anns, 385 | @JsonProperty("paramAnns") final List> paramAnns) { 386 | this.acc = acc; 387 | this.cname = cname; 388 | this.fname = fname; 389 | this.desc = desc; 390 | this.sig = sig; 391 | this.excs = excs; 392 | this.anns = anns; 393 | this.paramAnns = paramAnns; 394 | } 395 | 396 | public int getAcc() { 397 | return acc; 398 | } 399 | 400 | public String getFname() { 401 | return fname; 402 | } 403 | 404 | public String getCname() { 405 | return cname; 406 | } 407 | 408 | public String getDesc() { 409 | return desc; 410 | } 411 | 412 | public String getSig() { 413 | return sig; 414 | } 415 | 416 | public String[] getExcs() { 417 | return excs; 418 | } 419 | 420 | public List getAnns() { 421 | return anns; 422 | } 423 | 424 | public List> getParamAnns() { 425 | return paramAnns; 426 | } 427 | } 428 | 429 | public static class CreateField extends Asm { 430 | private final int acc; 431 | private final String cname; 432 | private final String name; 433 | private final String desc; 434 | private final String sig; 435 | private final Object value; 436 | 437 | public CreateField(@JsonProperty("acc") final int acc, 438 | @JsonProperty("cname") final String cname, 439 | @JsonProperty("name") final String name, 440 | @JsonProperty("desc") final String desc, 441 | @JsonProperty("sig") final String sig, 442 | @JsonProperty("initVal") final Object value) { 443 | this.acc = acc; 444 | this.cname = cname; 445 | this.name = name; 446 | this.desc = desc; 447 | this.sig = sig; 448 | this.value = value; 449 | } 450 | 451 | public int getAcc() { 452 | return acc; 453 | } 454 | 455 | public String getName() { 456 | return name; 457 | } 458 | 459 | public String getDesc() { 460 | return desc; 461 | } 462 | 463 | public String getSig() { 464 | return sig; 465 | } 466 | 467 | public Object getValue() { 468 | return value; 469 | } 470 | 471 | public String getCname() { 472 | return cname; 473 | } 474 | } 475 | 476 | public static class Dup extends Asm { 477 | } 478 | 479 | public static class Field extends Asm { 480 | private final int ftype; 481 | private final String cname; 482 | private final String fname; 483 | private final String desc; 484 | 485 | public Field(@JsonProperty("ftype") final int ftype, 486 | @JsonProperty("cname") final String cname, 487 | @JsonProperty("fname") final String fname, 488 | @JsonProperty("desc") final String desc) { 489 | this.ftype = ftype; 490 | this.cname = cname; 491 | this.fname = fname; 492 | this.desc = desc; 493 | } 494 | 495 | public int getFtype() { 496 | return ftype; 497 | } 498 | 499 | public String getCname() { 500 | return cname; 501 | } 502 | 503 | public String getFname() { 504 | return fname; 505 | } 506 | 507 | public String getDesc() { 508 | return desc; 509 | } 510 | } 511 | 512 | public static class FieldEnd extends Asm { 513 | 514 | } 515 | 516 | public static class Frame extends Asm { 517 | private final int ftype; 518 | private final int nlocal; 519 | private final String[] local; 520 | private final int nstack; 521 | private final String[] stack; 522 | 523 | public Frame(@JsonProperty("ftype") final int ftype, 524 | @JsonProperty("nlocal") final int nlocal, 525 | @JsonProperty("local") final String[] local, 526 | @JsonProperty("nstack") final int nstack, 527 | @JsonProperty("stack") final String[] stack) { 528 | this.ftype = ftype; 529 | this.nlocal = nlocal; 530 | this.local = local; 531 | this.nstack = nstack; 532 | this.stack = stack; 533 | } 534 | 535 | public int getFtype() { 536 | return ftype; 537 | } 538 | 539 | public int getNlocal() { 540 | return nlocal; 541 | } 542 | 543 | public String[] getLocal() { 544 | return local; 545 | } 546 | 547 | public int getNstack() { 548 | return nstack; 549 | } 550 | 551 | public String[] getStack() { 552 | return stack; 553 | } 554 | } 555 | 556 | public static class I2c extends Asm { 557 | } 558 | 559 | public static class I2l extends Asm { 560 | } 561 | 562 | public static class Iadd extends Asm { 563 | } 564 | 565 | public static class Iand extends Asm { 566 | } 567 | 568 | public static class Iconst extends Asm { 569 | private final int n; 570 | 571 | public Iconst(@JsonProperty("n") final int n) { 572 | this.n = n; 573 | } 574 | 575 | public int getN() { 576 | return n; 577 | } 578 | } 579 | 580 | public static class Idiv extends Asm { 581 | } 582 | 583 | public static class Ifeq extends Asm { 584 | private final String label; 585 | 586 | public Ifeq(@JsonProperty("label") String label) { 587 | this.label = label; 588 | } 589 | 590 | public String getLabel() { 591 | return label; 592 | } 593 | 594 | } 595 | 596 | public static class Ificmpge extends Asm { 597 | private final String label; 598 | 599 | public Ificmpge(@JsonProperty("label") String label) { 600 | this.label = label; 601 | } 602 | 603 | public String getLabel() { 604 | return label; 605 | } 606 | } 607 | 608 | public static class Ificmpgt extends Asm { 609 | private final String label; 610 | 611 | public Ificmpgt(@JsonProperty("label") String label) { 612 | this.label = label; 613 | } 614 | 615 | public String getLabel() { 616 | return label; 617 | } 618 | } 619 | 620 | public static class Ificmple extends Asm { 621 | private final String label; 622 | 623 | public Ificmple(@JsonProperty("label") String label) { 624 | this.label = label; 625 | } 626 | 627 | public String getLabel() { 628 | return label; 629 | } 630 | } 631 | 632 | public static class Ificmplt extends Asm { 633 | private final String label; 634 | 635 | public Ificmplt(@JsonProperty("label") String label) { 636 | this.label = label; 637 | } 638 | 639 | public String getLabel() { 640 | return label; 641 | } 642 | } 643 | 644 | public static class Iload extends Asm { 645 | private final int n; 646 | 647 | public Iload(@JsonProperty("n") final int n) { 648 | this.n = n; 649 | } 650 | 651 | public int getN() { 652 | return n; 653 | } 654 | } 655 | 656 | public static class Imul extends Asm { 657 | } 658 | 659 | public static class InvokeMethod extends Asm { 660 | private final int invocType; 661 | private final String cname; 662 | private final String mname; 663 | private final String desc; 664 | private final boolean isIntf; 665 | 666 | public InvokeMethod(@JsonProperty("invType") final int invocType, 667 | @JsonProperty("cname") final String cname, 668 | @JsonProperty("mname") final String mname, 669 | @JsonProperty("desc") final String desc, 670 | @JsonProperty("isIntf") final boolean isIntf) { 671 | this.invocType = invocType; 672 | this.cname = cname; 673 | this.mname = mname; 674 | this.desc = desc; 675 | this.isIntf = isIntf; 676 | } 677 | 678 | public int getInvocType() { 679 | return invocType; 680 | } 681 | 682 | public String getCname() { 683 | return cname; 684 | } 685 | 686 | public String getMname() { 687 | return mname; 688 | } 689 | 690 | public String getDesc() { 691 | return desc; 692 | } 693 | 694 | public boolean isIntf() { 695 | return isIntf; 696 | } 697 | } 698 | 699 | public static class InvokeDynamic extends Asm { 700 | private final String name; 701 | private final String desc; 702 | private final Handle handle; 703 | private final BsmArg[] args; 704 | 705 | public InvokeDynamic(@JsonProperty("name") final String name, 706 | @JsonProperty("desc") final String desc, 707 | @JsonProperty("handle") final Handle handle, 708 | @JsonProperty("args") final BsmArg[] args) { 709 | this.name = name; 710 | this.desc = desc; 711 | this.handle = handle; 712 | this.args = args; 713 | } 714 | 715 | public String getName() { 716 | return name; 717 | } 718 | 719 | public String getDesc() { 720 | return desc; 721 | } 722 | 723 | public Handle getHandle() { 724 | return handle; 725 | } 726 | 727 | public BsmArg[] getArgs() { 728 | return args; 729 | } 730 | } 731 | 732 | public static class Istore extends Asm { 733 | private final int n; 734 | 735 | public Istore(@JsonProperty("n") final int n) { 736 | this.n = n; 737 | } 738 | 739 | public int getN() { 740 | return n; 741 | } 742 | } 743 | 744 | public static class Isub extends Asm { 745 | } 746 | 747 | public static class LabelStart extends Asm { 748 | private final String label; 749 | 750 | public LabelStart(@JsonProperty("label") String label) { 751 | this.label = label; 752 | } 753 | 754 | public String getLabel() { 755 | return label; 756 | } 757 | } 758 | 759 | public static final class LdcDouble extends Asm { 760 | private final double val; 761 | 762 | public LdcDouble(@JsonProperty("val") final double val) { 763 | this.val = val; 764 | } 765 | 766 | public double getVal() { 767 | return val; 768 | } 769 | } 770 | 771 | public static final class LdcInteger extends Asm { 772 | private final int val; 773 | 774 | public LdcInteger(@JsonProperty("val") final int val) { 775 | this.val = val; 776 | } 777 | 778 | public int getVal() { 779 | return val; 780 | } 781 | } 782 | 783 | public static final class LdcString extends Asm { 784 | private final String val; 785 | 786 | public LdcString(@JsonProperty("val") final String val) { 787 | this.val = val; 788 | } 789 | 790 | public String getVal() { 791 | return val; 792 | } 793 | } 794 | 795 | public static final class LdcLong extends Asm { 796 | private final long val; 797 | 798 | public LdcLong(@JsonProperty("val") final long val) { 799 | this.val = val; 800 | } 801 | 802 | public long getVal() { 803 | return val; 804 | } 805 | } 806 | 807 | public static final class LdcType extends Asm { 808 | private final String val; 809 | 810 | public LdcType(@JsonProperty("val") final String val) { 811 | this.val = val; 812 | } 813 | 814 | public String getVal() { 815 | return val; 816 | } 817 | } 818 | 819 | public static class LookupSwitch extends Asm { 820 | private final String dlabel; 821 | private final String[] clabels; 822 | private final int[] vals; 823 | 824 | public LookupSwitch(@JsonProperty("dlabel") final String dlabel, 825 | @JsonProperty("clabels") final String[] clabels, 826 | @JsonProperty("vals") final int[] vals) { 827 | this.dlabel = dlabel; 828 | this.clabels = clabels; 829 | this.vals = vals; 830 | } 831 | 832 | public String getDlabel() { 833 | return dlabel; 834 | } 835 | 836 | public String[] getClabels() { 837 | return clabels; 838 | } 839 | 840 | public int[] getVals() { 841 | return vals; 842 | } 843 | } 844 | 845 | public static class MaxStackAndLocal extends Asm { 846 | private final int nstack; 847 | private final int nlocal; 848 | 849 | public MaxStackAndLocal(@JsonProperty("nstack") final int nstack, 850 | @JsonProperty("nlocal") final int nlocal) { 851 | this.nstack = nstack; 852 | this.nlocal = nlocal; 853 | } 854 | 855 | public int getNstack() { 856 | return nstack; 857 | } 858 | 859 | public int getNlocal() { 860 | return nlocal; 861 | } 862 | } 863 | 864 | public static class MethodCodeStart extends Asm { 865 | } 866 | 867 | public static class MethodCodeEnd extends Asm { 868 | } 869 | 870 | public static class New extends Asm { 871 | private final String name; 872 | 873 | public New(@JsonProperty("name") final String name) { 874 | this.name = name; 875 | } 876 | 877 | public String getName() { 878 | return name; 879 | } 880 | } 881 | 882 | public static class Pop extends Asm { 883 | } 884 | 885 | public static class Return extends Asm { 886 | } 887 | 888 | public static class SourceInfo extends Asm { 889 | private final String name; 890 | 891 | public SourceInfo(@JsonProperty("name") final String name) { 892 | this.name = name; 893 | } 894 | 895 | public String getName() { 896 | return name; 897 | } 898 | } 899 | 900 | public static final class Handle { 901 | private final int tag; 902 | private final String cname; 903 | private final String mname; 904 | private final String desc; 905 | private final boolean isIntf; 906 | 907 | public Handle(@JsonProperty("tag") final int tag, 908 | @JsonProperty("cname") final String cname, 909 | @JsonProperty("mname") final String mname, 910 | @JsonProperty("desc") final String desc, 911 | @JsonProperty("isIntf") final boolean isIntf) { 912 | this.tag = tag; 913 | this.cname = cname; 914 | this.mname = mname; 915 | this.desc = desc; 916 | this.isIntf = isIntf; 917 | } 918 | 919 | public int getTag() { 920 | return tag; 921 | } 922 | 923 | public String getCname() { 924 | return cname; 925 | } 926 | 927 | public String getMname() { 928 | return mname; 929 | } 930 | 931 | public String getDesc() { 932 | return desc; 933 | } 934 | 935 | public boolean isIntf() { 936 | return isIntf; 937 | } 938 | } 939 | 940 | @JsonTypeInfo( 941 | use = JsonTypeInfo.Id.NAME, 942 | include = JsonTypeInfo.As.PROPERTY, 943 | property = "type", 944 | visible = true) 945 | @JsonSubTypes({ 946 | @JsonSubTypes.Type(value = Asm.BsmArg.BsmArgGetType.class, name = "BsmArgGetType"), 947 | @JsonSubTypes.Type(value = Asm.BsmArg.BsmArgHandle.class, name = "BsmArgHandle") 948 | }) 949 | public static abstract class BsmArg { 950 | private BsmArgType type; 951 | 952 | private BsmArg() { 953 | } 954 | 955 | public BsmArgType getType() { 956 | return type; 957 | } 958 | 959 | public void setType(final BsmArgType type) { 960 | this.type = type; 961 | } 962 | 963 | public enum BsmArgType { 964 | BsmArgGetType, 965 | BsmArgHandle 966 | } 967 | 968 | public static final class BsmArgGetType extends BsmArg { 969 | private final String desc; 970 | 971 | public BsmArgGetType(@JsonProperty("desc") final String desc) { 972 | this.desc = desc; 973 | } 974 | 975 | public String getDesc() { 976 | return desc; 977 | } 978 | } 979 | 980 | public static final class BsmArgHandle extends BsmArg { 981 | private final Handle handle; 982 | 983 | public BsmArgHandle(@JsonProperty("handle") final Handle handle) { 984 | this.handle = handle; 985 | } 986 | 987 | public Handle getHandle() { 988 | return handle; 989 | } 990 | } 991 | 992 | } 993 | 994 | public static class Ladd extends Asm { 995 | } 996 | 997 | public static class Land extends Asm { 998 | } 999 | 1000 | public static class Ldiv extends Asm { 1001 | } 1002 | 1003 | public static class Lmul extends Asm { 1004 | } 1005 | 1006 | public static class Lsub extends Asm { 1007 | } 1008 | 1009 | public static class Ishl extends Asm { 1010 | } 1011 | 1012 | public static class Ishr extends Asm { 1013 | } 1014 | 1015 | public static class Iushr extends Asm { 1016 | } 1017 | 1018 | public static class Lshl extends Asm { 1019 | } 1020 | 1021 | public static class Lshr extends Asm { 1022 | } 1023 | 1024 | public static class Lushr extends Asm { 1025 | } 1026 | 1027 | public static class L2i extends Asm { 1028 | } 1029 | 1030 | public static class Irem extends Asm { 1031 | } 1032 | 1033 | public static class Lrem extends Asm { 1034 | } 1035 | 1036 | public static class Dadd extends Asm { 1037 | } 1038 | 1039 | public static class Ddiv extends Asm { 1040 | } 1041 | 1042 | public static class Dmul extends Asm { 1043 | } 1044 | 1045 | public static class Drem extends Asm { 1046 | } 1047 | 1048 | public static class Dsub extends Asm { 1049 | } 1050 | 1051 | public static class Lload extends Asm { 1052 | private final int n; 1053 | 1054 | public Lload(@JsonProperty("n") final int n) { 1055 | this.n = n; 1056 | } 1057 | 1058 | public int getN() { 1059 | return n; 1060 | } 1061 | } 1062 | 1063 | public static class Fload extends Asm { 1064 | private final int n; 1065 | 1066 | public Fload(@JsonProperty("n") final int n) { 1067 | this.n = n; 1068 | } 1069 | 1070 | public int getN() { 1071 | return n; 1072 | } 1073 | } 1074 | 1075 | public static class Dload extends Asm { 1076 | private final int n; 1077 | 1078 | public Dload(@JsonProperty("n") final int n) { 1079 | this.n = n; 1080 | } 1081 | 1082 | public int getN() { 1083 | return n; 1084 | } 1085 | } 1086 | 1087 | @ToString 1088 | public static class Annotation extends Asm { 1089 | private final String name; 1090 | private final List properties; 1091 | 1092 | public Annotation(@JsonProperty("name") final String name, 1093 | @JsonProperty("props") final List properties) { 1094 | this.name = name; 1095 | this.properties = properties; 1096 | } 1097 | 1098 | public String getName() { 1099 | return name; 1100 | } 1101 | 1102 | public List getProperties() { 1103 | return properties; 1104 | } 1105 | } 1106 | 1107 | @ToString 1108 | public static class AnnotationProperty { 1109 | private final String name; 1110 | private final AnnotationValue value; 1111 | 1112 | public AnnotationProperty(@JsonProperty("name") final String name, 1113 | @JsonProperty("value") final AnnotationValue value) { 1114 | this.name = name; 1115 | this.value = value; 1116 | } 1117 | 1118 | public AnnotationValue getValue() { 1119 | return value; 1120 | } 1121 | 1122 | public String getName() { 1123 | return name; 1124 | } 1125 | } 1126 | 1127 | @JsonTypeInfo( 1128 | use = JsonTypeInfo.Id.NAME, 1129 | include = JsonTypeInfo.As.PROPERTY, 1130 | property = "type", 1131 | visible = true) 1132 | @JsonSubTypes({ 1133 | @JsonSubTypes.Type(value = AnnotationValue.AnnString.class, name = "AnnString"), 1134 | @JsonSubTypes.Type(value = AnnotationValue.AnnInt.class, name = "AnnInt"), 1135 | @JsonSubTypes.Type(value = AnnotationValue.AnnArray.class, name = "AnnArray") 1136 | }) 1137 | public static abstract class AnnotationValue { 1138 | private AnnotationValueType type; 1139 | 1140 | private AnnotationValue() {} 1141 | 1142 | public AnnotationValueType getType() { 1143 | return type; 1144 | } 1145 | 1146 | public void setType(final AnnotationValueType type) { 1147 | this.type = type; 1148 | } 1149 | 1150 | public enum AnnotationValueType { 1151 | AnnString, 1152 | AnnInt, 1153 | AnnArray 1154 | } 1155 | 1156 | @ToString 1157 | public static class AnnString extends AnnotationValue { 1158 | private final String value; 1159 | 1160 | public AnnString(@JsonProperty("value") final String value) { 1161 | this.value = value; 1162 | } 1163 | 1164 | public String getValue() { 1165 | return value; 1166 | } 1167 | } 1168 | 1169 | @ToString 1170 | public static class AnnInt extends AnnotationValue { 1171 | private final int value; 1172 | 1173 | public AnnInt(@JsonProperty("value") final int value) { 1174 | this.value = value; 1175 | } 1176 | 1177 | public int getValue() { 1178 | return value; 1179 | } 1180 | } 1181 | 1182 | @ToString 1183 | public static class AnnArray extends AnnotationValue { 1184 | private final List values; 1185 | 1186 | public AnnArray(@JsonProperty("values") final List values) { 1187 | this.values = values; 1188 | } 1189 | 1190 | public List getValues() { 1191 | return values; 1192 | } 1193 | } 1194 | } 1195 | } 1196 | -------------------------------------------------------------------------------- /jvm-assembler-server/src/main/java/com/mmhelloworld/jvmassembler/server/AssemblerApp.java: -------------------------------------------------------------------------------- 1 | package com.mmhelloworld.jvmassembler.server; 2 | 3 | import javax.ws.rs.core.Application; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | /** 8 | * User: marimuthu 9 | */ 10 | public class AssemblerApp extends Application { 11 | @Override 12 | public Set> getClasses() { 13 | Set> resources = new HashSet<>(); 14 | resources.add(AssemblerResource.class); 15 | return resources; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jvm-assembler-server/src/main/java/com/mmhelloworld/jvmassembler/server/AssemblerResource.java: -------------------------------------------------------------------------------- 1 | package com.mmhelloworld.jvmassembler.server; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.mmhelloworld.jvmassembler.server.Asm.AnnotationValue; 5 | import com.mmhelloworld.jvmassembler.server.Asm.AnnotationValue.AnnotationValueType; 6 | import org.objectweb.asm.AnnotationVisitor; 7 | import org.objectweb.asm.ClassWriter; 8 | import org.objectweb.asm.FieldVisitor; 9 | import org.objectweb.asm.Handle; 10 | import org.objectweb.asm.Label; 11 | import org.objectweb.asm.MethodVisitor; 12 | import org.objectweb.asm.Opcodes; 13 | import org.objectweb.asm.Type; 14 | 15 | import javax.ws.rs.Consumes; 16 | import javax.ws.rs.GET; 17 | import javax.ws.rs.POST; 18 | import javax.ws.rs.Path; 19 | import javax.ws.rs.Produces; 20 | import javax.ws.rs.core.MediaType; 21 | import javax.ws.rs.core.Response; 22 | import java.io.File; 23 | import java.io.FileOutputStream; 24 | import java.io.OutputStream; 25 | import java.util.Arrays; 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS; 31 | import static org.objectweb.asm.Opcodes.AALOAD; 32 | import static org.objectweb.asm.Opcodes.AASTORE; 33 | import static org.objectweb.asm.Opcodes.ACC_PUBLIC; 34 | import static org.objectweb.asm.Opcodes.ACONST_NULL; 35 | import static org.objectweb.asm.Opcodes.ALOAD; 36 | import static org.objectweb.asm.Opcodes.ANEWARRAY; 37 | import static org.objectweb.asm.Opcodes.ARETURN; 38 | import static org.objectweb.asm.Opcodes.ASTORE; 39 | import static org.objectweb.asm.Opcodes.CHECKCAST; 40 | import static org.objectweb.asm.Opcodes.DADD; 41 | import static org.objectweb.asm.Opcodes.DDIV; 42 | import static org.objectweb.asm.Opcodes.DLOAD; 43 | import static org.objectweb.asm.Opcodes.DMUL; 44 | import static org.objectweb.asm.Opcodes.DREM; 45 | import static org.objectweb.asm.Opcodes.DRETURN; 46 | import static org.objectweb.asm.Opcodes.DSUB; 47 | import static org.objectweb.asm.Opcodes.DUP; 48 | import static org.objectweb.asm.Opcodes.F2D; 49 | import static org.objectweb.asm.Opcodes.FLOAD; 50 | import static org.objectweb.asm.Opcodes.FRETURN; 51 | import static org.objectweb.asm.Opcodes.I2C; 52 | import static org.objectweb.asm.Opcodes.I2L; 53 | import static org.objectweb.asm.Opcodes.IADD; 54 | import static org.objectweb.asm.Opcodes.IAND; 55 | import static org.objectweb.asm.Opcodes.ICONST_0; 56 | import static org.objectweb.asm.Opcodes.ICONST_1; 57 | import static org.objectweb.asm.Opcodes.ICONST_2; 58 | import static org.objectweb.asm.Opcodes.ICONST_3; 59 | import static org.objectweb.asm.Opcodes.ICONST_4; 60 | import static org.objectweb.asm.Opcodes.ICONST_5; 61 | import static org.objectweb.asm.Opcodes.ICONST_M1; 62 | import static org.objectweb.asm.Opcodes.IDIV; 63 | import static org.objectweb.asm.Opcodes.ILOAD; 64 | import static org.objectweb.asm.Opcodes.IMUL; 65 | import static org.objectweb.asm.Opcodes.INVOKESPECIAL; 66 | import static org.objectweb.asm.Opcodes.IREM; 67 | import static org.objectweb.asm.Opcodes.IRETURN; 68 | import static org.objectweb.asm.Opcodes.ISHL; 69 | import static org.objectweb.asm.Opcodes.ISHR; 70 | import static org.objectweb.asm.Opcodes.ISTORE; 71 | import static org.objectweb.asm.Opcodes.ISUB; 72 | import static org.objectweb.asm.Opcodes.IUSHR; 73 | import static org.objectweb.asm.Opcodes.L2I; 74 | import static org.objectweb.asm.Opcodes.LADD; 75 | import static org.objectweb.asm.Opcodes.LAND; 76 | import static org.objectweb.asm.Opcodes.LDIV; 77 | import static org.objectweb.asm.Opcodes.LLOAD; 78 | import static org.objectweb.asm.Opcodes.LMUL; 79 | import static org.objectweb.asm.Opcodes.LREM; 80 | import static org.objectweb.asm.Opcodes.LRETURN; 81 | import static org.objectweb.asm.Opcodes.LSHL; 82 | import static org.objectweb.asm.Opcodes.LSHR; 83 | import static org.objectweb.asm.Opcodes.LSUB; 84 | import static org.objectweb.asm.Opcodes.LUSHR; 85 | import static org.objectweb.asm.Opcodes.NEW; 86 | import static org.objectweb.asm.Opcodes.POP; 87 | import static org.objectweb.asm.Opcodes.RETURN; 88 | import static org.objectweb.asm.Opcodes.SIPUSH; 89 | 90 | @Path("/assembler") 91 | public class AssemblerResource { 92 | @GET 93 | @Path("/health") 94 | public Response checkHealth() { 95 | return Response.ok().build(); 96 | } 97 | 98 | @POST 99 | @Path("/assemble") 100 | @Consumes(MediaType.APPLICATION_JSON) 101 | @Produces(MediaType.APPLICATION_JSON) 102 | public AssemblerResponse assemble(CreateBytecode request) throws JsonProcessingException { 103 | Map cws = new HashMap<>(); 104 | ClassWriter cw = null; 105 | MethodVisitor mv = null; 106 | FieldVisitor fv = null; 107 | Map env = new HashMap<>(); 108 | String error = ""; 109 | boolean isSuccess = true; 110 | 111 | try { 112 | for (Asm asm : request.getInstructions()) { 113 | switch (asm.getType()) { 114 | case Aaload: 115 | mv.visitInsn(AALOAD); 116 | break; 117 | case Aastore: 118 | mv.visitInsn(AASTORE); 119 | break; 120 | case Aconstnull: 121 | mv.visitInsn(ACONST_NULL); 122 | break; 123 | case Aload: 124 | Asm.Aload aload = (Asm.Aload) asm; 125 | mv.visitVarInsn(ALOAD, aload.getIndex()); 126 | break; 127 | case Anewarray: 128 | Asm.Anewarray anewarray = (Asm.Anewarray) asm; 129 | mv.visitTypeInsn(ANEWARRAY, anewarray.getDesc()); 130 | break; 131 | case Astore: 132 | Asm.Astore astore = (Asm.Astore) asm; 133 | mv.visitVarInsn(ASTORE, astore.getIndex()); 134 | break; 135 | case Areturn: 136 | mv.visitInsn(ARETURN); 137 | break; 138 | case Checkcast: 139 | Asm.Checkcast checkcast = (Asm.Checkcast) asm; 140 | mv.visitTypeInsn(CHECKCAST, checkcast.getDesc()); 141 | break; 142 | case ClassCodeStart: 143 | handleClassCodeStart(cws, cw, (Asm.ClassCodeStart) asm); 144 | break; 145 | case ClassCodeEnd: 146 | cw.visitEnd(); 147 | Asm.ClassCodeEnd classCodeEnd = (Asm.ClassCodeEnd) asm; 148 | cws.entrySet().parallelStream().forEach(e -> { 149 | String className = e.getKey(); 150 | ClassWriter classWriter = e.getValue(); 151 | File outFile = new File(classCodeEnd.getOut(), className + ".class"); 152 | new File(outFile.getParent()).mkdirs(); 153 | try (OutputStream out = new FileOutputStream(outFile)) { 154 | out.write(classWriter.toByteArray()); 155 | } catch (Exception exception) { 156 | exception.printStackTrace(); 157 | } 158 | }); 159 | 160 | break; 161 | case CreateClass: 162 | cw = new ClassWriter(((Asm.CreateClass) asm).getFlags()); 163 | break; 164 | case CreateField: 165 | Asm.CreateField cf = (Asm.CreateField) asm; 166 | String fieldClassName = cf.getCname(); 167 | cw = cws.computeIfAbsent(fieldClassName, cname -> { 168 | final ClassWriter classWriter = new ClassWriter(COMPUTE_MAXS); 169 | classWriter.visit(52, ACC_PUBLIC, cname, null, "java/lang/Object", null); 170 | createDefaultConstructor(classWriter); 171 | return classWriter; 172 | }); 173 | fv = cw.visitField(cf.getAcc(), cf.getName(), cf.getDesc(), cf.getSig(), cf.getValue()); 174 | break; 175 | case CreateLabel: { 176 | String labelName = ((Asm.CreateLabel) asm).getLabel(); 177 | Label label = new Label(); 178 | env.put(labelName, label); 179 | break; 180 | } 181 | case CreateMethod: 182 | Asm.CreateMethod createMethod = (Asm.CreateMethod) asm; 183 | final String className = createMethod.getCname(); 184 | cw = cws.computeIfAbsent(className, cname -> { 185 | final ClassWriter classWriter = new ClassWriter(COMPUTE_MAXS); 186 | classWriter.visit(52, ACC_PUBLIC, className, null, "java/lang/Object", null); 187 | createDefaultConstructor(classWriter); 188 | return classWriter; 189 | }); 190 | List anns = createMethod.getAnns(); 191 | mv = cw.visitMethod( 192 | createMethod.getAcc(), 193 | createMethod.getFname(), 194 | createMethod.getDesc(), 195 | createMethod.getSig(), 196 | createMethod.getExcs()); 197 | handleCreateMethod(mv, createMethod); 198 | break; 199 | case Dadd: 200 | mv.visitInsn(DADD); 201 | break; 202 | case Ddiv: 203 | mv.visitInsn(DDIV); 204 | break; 205 | case Dload: 206 | mv.visitVarInsn(DLOAD, ((Asm.Dload) asm).getN()); 207 | break; 208 | case Dmul: 209 | mv.visitInsn(DMUL); 210 | break; 211 | case Drem: 212 | mv.visitInsn(DREM); 213 | break; 214 | case Dreturn: 215 | mv.visitInsn(DRETURN); 216 | break; 217 | case Dsub: 218 | mv.visitInsn(DSUB); 219 | break; 220 | case Dup: 221 | mv.visitInsn(DUP); 222 | break; 223 | case F2d: 224 | mv.visitInsn(F2D); 225 | break; 226 | case Field: 227 | Asm.Field field = (Asm.Field) asm; 228 | mv.visitFieldInsn(field.getFtype(), field.getCname(), field.getFname(), field.getDesc()); 229 | break; 230 | case FieldEnd: 231 | fv.visitEnd(); 232 | break; 233 | case Fload: 234 | mv.visitVarInsn(FLOAD, ((Asm.Fload) asm).getN()); 235 | break; 236 | case Frame: 237 | Asm.Frame frame = (Asm.Frame) asm; 238 | mv.visitFrame( 239 | frame.getFtype(), 240 | frame.getNlocal(), 241 | Arrays.stream(frame.getLocal()).map(s -> s.equalsIgnoreCase("opcodes.integer") ? Opcodes.INTEGER : s).toArray(), 242 | frame.getNstack(), 243 | Arrays.stream(frame.getStack()).map(s -> s.equalsIgnoreCase("opcodes.integer") ? Opcodes.INTEGER : s).toArray() 244 | ); 245 | break; 246 | case Freturn: 247 | mv.visitInsn(FRETURN); 248 | break; 249 | case Goto: 250 | String labelName = ((Asm.Goto) asm).getLabel(); 251 | mv.visitJumpInsn(Opcodes.GOTO, (Label) env.get(labelName)); 252 | break; 253 | case I2c: 254 | mv.visitInsn(I2C); 255 | break; 256 | case I2l: 257 | mv.visitInsn(I2L); 258 | break; 259 | case Iadd: 260 | mv.visitInsn(IADD); 261 | break; 262 | case Iand: 263 | mv.visitInsn(IAND); 264 | break; 265 | case Iconst: 266 | Asm.Iconst iconst = (Asm.Iconst) asm; 267 | int n = iconst.getN(); 268 | if (n >= 0 && n <= 5) { 269 | final int[] opcodes = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5}; 270 | mv.visitInsn(opcodes[n]); 271 | } else if (n == -1) { 272 | mv.visitInsn(ICONST_M1); 273 | } else if (n >= (-128) && n <= 127) { 274 | mv.visitIntInsn(Opcodes.BIPUSH, n); 275 | } else if (n >= (-32768) && n <= 32767) { 276 | mv.visitIntInsn(SIPUSH, n); 277 | } else { 278 | mv.visitLdcInsn(n); 279 | } 280 | break; 281 | case Idiv: 282 | mv.visitInsn(IDIV); 283 | break; 284 | case Ifeq: 285 | Asm.Ifeq ifeq = (Asm.Ifeq) asm; 286 | mv.visitJumpInsn(Opcodes.IFEQ, (Label) env.get(ifeq.getLabel())); 287 | break; 288 | case Ificmpge: 289 | Asm.Ificmpge ificmpge = (Asm.Ificmpge) asm; 290 | mv.visitJumpInsn(Opcodes.IF_ICMPGE, (Label) env.get(ificmpge.getLabel())); 291 | break; 292 | case Ificmpgt: 293 | Asm.Ificmpgt ificmpgt = (Asm.Ificmpgt) asm; 294 | mv.visitJumpInsn(Opcodes.IF_ICMPGT, (Label) env.get(ificmpgt.getLabel())); 295 | break; 296 | case Ificmple: 297 | Asm.Ificmple ificmple = (Asm.Ificmple) asm; 298 | mv.visitJumpInsn(Opcodes.IF_ICMPLE, (Label) env.get(ificmple.getLabel())); 299 | break; 300 | case Ificmplt: 301 | Asm.Ificmplt ificmplt = (Asm.Ificmplt) asm; 302 | mv.visitJumpInsn(Opcodes.IF_ICMPLT, (Label) env.get(ificmplt.getLabel())); 303 | break; 304 | case Iload: 305 | mv.visitVarInsn(ILOAD, ((Asm.Iload) asm).getN()); 306 | break; 307 | case Imul: 308 | mv.visitInsn(IMUL); 309 | break; 310 | case InvokeMethod: 311 | Asm.InvokeMethod invokeMethod = (Asm.InvokeMethod) asm; 312 | mv.visitMethodInsn( 313 | invokeMethod.getInvocType(), 314 | invokeMethod.getCname(), 315 | invokeMethod.getMname(), 316 | invokeMethod.getDesc(), 317 | invokeMethod.isIntf()); 318 | break; 319 | case InvokeDynamic: 320 | Asm.InvokeDynamic invokeDynamic = (Asm.InvokeDynamic) asm; 321 | Asm.Handle handle = invokeDynamic.getHandle(); 322 | final Asm.BsmArg[] invokeDynamicArgs = invokeDynamic.getArgs(); 323 | final Object[] bsmArgs = new Object[invokeDynamicArgs.length]; 324 | for (int index = 0; index < bsmArgs.length; index++) { 325 | Asm.BsmArg arg = invokeDynamicArgs[index]; 326 | switch (arg.getType()) { 327 | case BsmArgGetType: 328 | Asm.BsmArg.BsmArgGetType getType = (Asm.BsmArg.BsmArgGetType) arg; 329 | bsmArgs[index] = Type.getType(getType.getDesc()); 330 | break; 331 | case BsmArgHandle: 332 | Asm.BsmArg.BsmArgHandle bsmHandle = (Asm.BsmArg.BsmArgHandle) arg; 333 | bsmArgs[index] = getAsmHandle(bsmHandle.getHandle()); 334 | break; 335 | } 336 | } 337 | 338 | mv.visitInvokeDynamicInsn( 339 | invokeDynamic.getName(), 340 | invokeDynamic.getDesc(), 341 | getAsmHandle(handle), 342 | bsmArgs 343 | ); 344 | break; 345 | case Irem: 346 | mv.visitInsn(IREM); 347 | break; 348 | case Ireturn: 349 | mv.visitInsn(IRETURN); 350 | break; 351 | case Ishl: 352 | mv.visitInsn(ISHL); 353 | break; 354 | case Ishr: 355 | mv.visitInsn(ISHR); 356 | break; 357 | case Istore: 358 | mv.visitVarInsn(ISTORE, ((Asm.Istore) asm).getN()); 359 | break; 360 | case Isub: 361 | mv.visitInsn(ISUB); 362 | break; 363 | case Iushr: 364 | mv.visitInsn(IUSHR); 365 | break; 366 | case L2i: 367 | mv.visitInsn(L2I); 368 | break; 369 | case LabelStart: { 370 | String label = ((Asm.LabelStart) asm).getLabel(); 371 | mv.visitLabel((Label) (env.get(label))); 372 | break; 373 | } 374 | case Ladd: 375 | mv.visitInsn(LADD); 376 | break; 377 | case Land: 378 | mv.visitInsn(LAND); 379 | break; 380 | case LdcDouble: 381 | mv.visitLdcInsn(((Asm.LdcDouble) asm).getVal()); 382 | break; 383 | case LdcInteger: 384 | mv.visitLdcInsn(((Asm.LdcInteger) asm).getVal()); 385 | break; 386 | case LdcLong: 387 | mv.visitLdcInsn(((Asm.LdcLong) asm).getVal()); 388 | break; 389 | case LdcString: 390 | mv.visitLdcInsn(((Asm.LdcString) asm).getVal()); 391 | break; 392 | case LdcType: 393 | mv.visitLdcInsn(Type.getType(((Asm.LdcType) asm).getVal())); 394 | break; 395 | case Ldiv: 396 | mv.visitInsn(LDIV); 397 | break; 398 | case Lload: 399 | mv.visitVarInsn(LLOAD, ((Asm.Lload) asm).getN()); 400 | break; 401 | case Lmul: 402 | mv.visitInsn(LMUL); 403 | break; 404 | case LookupSwitch: 405 | Asm.LookupSwitch lookupSwitch = (Asm.LookupSwitch) asm; 406 | mv.visitLookupSwitchInsn( 407 | (Label) env.get(lookupSwitch.getDlabel()), 408 | lookupSwitch.getVals(), 409 | Arrays.stream(lookupSwitch.getClabels()) 410 | .map(s -> (Label) env.get(s)) 411 | .toArray(Label[]::new) 412 | ); 413 | break; 414 | case Lshl: 415 | mv.visitInsn(LSHL); 416 | break; 417 | case Lrem: 418 | mv.visitInsn(LREM); 419 | break; 420 | case Lreturn: 421 | mv.visitInsn(LRETURN); 422 | break; 423 | case Lshr: 424 | mv.visitInsn(LSHR); 425 | break; 426 | case Lsub: 427 | mv.visitInsn(LSUB); 428 | break; 429 | case Lushr: 430 | mv.visitInsn(LUSHR); 431 | break; 432 | case MaxStackAndLocal: 433 | Asm.MaxStackAndLocal maxStackAndLocal = (Asm.MaxStackAndLocal) asm; 434 | mv.visitMaxs(maxStackAndLocal.getNstack(), maxStackAndLocal.getNlocal()); 435 | break; 436 | case MethodCodeStart: 437 | mv.visitCode(); 438 | break; 439 | case MethodCodeEnd: 440 | mv.visitEnd(); 441 | break; 442 | case New: 443 | Asm.New instantiate = (Asm.New) asm; 444 | mv.visitTypeInsn(NEW, instantiate.getName()); 445 | break; 446 | case Pop: 447 | mv.visitInsn(POP); 448 | break; 449 | case Return: 450 | mv.visitInsn(RETURN); 451 | break; 452 | case SourceInfo: 453 | Asm.SourceInfo sourceInfo = (Asm.SourceInfo) asm; 454 | cw.visitSource(sourceInfo.getName(), null); 455 | break; 456 | } 457 | } 458 | } catch (Exception e) { 459 | isSuccess = false; 460 | e.printStackTrace(); 461 | error = e.getMessage(); 462 | } 463 | return new AssemblerResponse(isSuccess, error); 464 | } 465 | 466 | private void handleCreateMethod(final MethodVisitor mv, final Asm.CreateMethod createMethod) { 467 | createMethod.getAnns().forEach(annotation -> { 468 | final AnnotationVisitor av = mv.visitAnnotation(annotation.getName(), true); 469 | annotation.getProperties().forEach(prop -> addPropertyToAnnotation(av, prop)); 470 | }); 471 | } 472 | 473 | private void handleClassCodeStart(final Map cws, 474 | final ClassWriter cw, 475 | final Asm.ClassCodeStart classCodeStart) { 476 | cw.visit(classCodeStart.getVersion(), 477 | classCodeStart.getAcc(), 478 | classCodeStart.getName(), 479 | classCodeStart.getSig(), 480 | classCodeStart.getParent(), 481 | classCodeStart.getInterfaces()); 482 | cws.put(classCodeStart.getName(), cw); 483 | 484 | final List annotations = classCodeStart.getAnnotations(); 485 | annotations.forEach(annotation -> { 486 | AnnotationVisitor av = cw.visitAnnotation(annotation.getName(), true); 487 | annotation.getProperties().forEach(prop -> addPropertyToAnnotation(av, prop)); 488 | av.visitEnd(); 489 | }); 490 | } 491 | 492 | private void addPropertyToAnnotation(final AnnotationVisitor av, final Asm.AnnotationProperty prop) { 493 | final AnnotationValueType propType = prop.getValue().getType(); 494 | switch (propType) { 495 | case AnnString: 496 | AnnotationValue.AnnString annStr = (AnnotationValue.AnnString) prop.getValue(); 497 | av.visit(prop.getName(), annStr.getValue()); 498 | break; 499 | case AnnInt: 500 | AnnotationValue.AnnInt annInt = (AnnotationValue.AnnInt) prop.getValue(); 501 | av.visit(prop.getName(), annInt.getValue()); 502 | break; 503 | case AnnArray: 504 | break; 505 | } 506 | } 507 | 508 | private MethodVisitor createDefaultConstructor(final ClassWriter cw) { 509 | final MethodVisitor mv; 510 | mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); 511 | mv.visitCode(); 512 | mv.visitVarInsn(ALOAD, 0); 513 | mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); 514 | mv.visitInsn(RETURN); 515 | mv.visitMaxs(1, 1); 516 | mv.visitEnd(); 517 | return mv; 518 | } 519 | 520 | private Handle getAsmHandle(final Asm.Handle handle) { 521 | return new Handle( 522 | handle.getTag(), 523 | handle.getCname(), 524 | handle.getMname(), 525 | handle.getDesc(), 526 | handle.isIntf() 527 | ); 528 | } 529 | } 530 | -------------------------------------------------------------------------------- /jvm-assembler-server/src/main/java/com/mmhelloworld/jvmassembler/server/AssemblerResponse.java: -------------------------------------------------------------------------------- 1 | package com.mmhelloworld.jvmassembler.server; 2 | 3 | public class AssemblerResponse { 4 | 5 | private final boolean isSuccess; 6 | private final String message; 7 | 8 | public AssemblerResponse(final boolean isSuccess, final String message) { 9 | this.isSuccess = isSuccess; 10 | this.message = message; 11 | } 12 | 13 | public boolean isSuccess() { 14 | return isSuccess; 15 | } 16 | 17 | public String getMessage() { 18 | return message; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /jvm-assembler-server/src/main/java/com/mmhelloworld/jvmassembler/server/AssemblerServer.java: -------------------------------------------------------------------------------- 1 | package com.mmhelloworld.jvmassembler.server; 2 | 3 | import joptsimple.OptionException; 4 | import joptsimple.OptionParser; 5 | import joptsimple.OptionSet; 6 | import joptsimple.OptionSpec; 7 | import org.eclipse.jetty.server.Server; 8 | import org.eclipse.jetty.server.ServerConnector; 9 | import org.eclipse.jetty.servlet.ServletContextHandler; 10 | import org.eclipse.jetty.servlet.ServletHolder; 11 | import org.glassfish.jersey.servlet.ServletContainer; 12 | 13 | import java.io.BufferedWriter; 14 | import java.io.File; 15 | import java.io.FileWriter; 16 | import java.io.IOException; 17 | import java.io.InputStream; 18 | import java.net.URL; 19 | import java.nio.file.Files; 20 | import java.util.Optional; 21 | import java.util.Scanner; 22 | 23 | public final class AssemblerServer { 24 | 25 | private final int port; 26 | private final File workingDir; 27 | 28 | public AssemblerServer(int port, File workingDir) { 29 | this.port = port; 30 | this.workingDir = workingDir; 31 | } 32 | 33 | public void start() { 34 | workingDir.mkdirs(); 35 | ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); 36 | context.setContextPath("/"); 37 | 38 | ServletHolder jerseyServlet = context.addServlet(ServletContainer.class, "/*"); 39 | jerseyServlet.setInitOrder(0); 40 | jerseyServlet.setInitParameter("javax.ws.rs.Application", AssemblerApp.class.getCanonicalName()); 41 | 42 | Server jettyServer = new Server(port); 43 | jettyServer.setHandler(context); 44 | 45 | try { 46 | jettyServer.start(); 47 | int runningPort = getPort(jettyServer); 48 | System.out.printf("Server started successfully and is running on port %s.\n", runningPort); 49 | writePort(runningPort); 50 | jettyServer.join(); 51 | } catch (Exception e) { 52 | throw new RuntimeException(e); 53 | } finally { 54 | jettyServer.destroy(); 55 | } 56 | } 57 | 58 | private void writePort(int port) { 59 | final File portInfoFile = getInfoFile(); 60 | try (BufferedWriter out = new BufferedWriter(new FileWriter(portInfoFile))) { 61 | out.append(Integer.toString(port)).append('\n'); 62 | out.flush(); 63 | } catch (IOException e) { 64 | System.err.println("Cannot write port details to " + portInfoFile); 65 | e.printStackTrace(); 66 | } 67 | } 68 | 69 | public Optional getPort() { 70 | return Optional.of(getInfoFile()) 71 | .filter(File::exists) 72 | .flatMap(f -> { 73 | try { 74 | return Files.lines(f.toPath()) 75 | .findFirst() 76 | .flatMap(AssemblerServer::parseInt) 77 | .filter(this::isRunning); 78 | } catch (IOException e) { 79 | return Optional.empty(); 80 | } 81 | }); 82 | } 83 | 84 | private boolean isRunning(int port) { 85 | final String url = String.format("http://localhost:%d/assembler/health", port); 86 | try (InputStream ignored = new URL(url).openStream()) { 87 | return true; 88 | } catch (IOException e) { 89 | return false; 90 | } 91 | } 92 | 93 | private File getInfoFile() { 94 | return new File(workingDir, ".assembler"); 95 | } 96 | 97 | private static Optional parseInt(String portStr) { 98 | try { 99 | return Optional.of(Integer.parseInt(portStr)); 100 | } catch (NumberFormatException e) { 101 | return Optional.empty(); 102 | } 103 | } 104 | 105 | private static File getDefaultWorkingDir() { 106 | final String userHome = System.getProperty("user.home"); 107 | return new File(userHome, ".jvm-assembler"); 108 | } 109 | 110 | private static int getPort(final Server jettyServer) { 111 | return ((ServerConnector) (jettyServer.getConnectors()[0])).getLocalPort(); 112 | } 113 | 114 | public static void start(final String[] args) { 115 | Config config = getConfig(args); 116 | AssemblerServer server = new AssemblerServer(config.getPort(), config.getWorkingDir()); 117 | 118 | server.getPort() 119 | .map(port -> { 120 | System.out.printf("A server may be already running on port %d.%n", port); 121 | if (shouldForceStart(config)) { 122 | server.start(); 123 | } else { 124 | System.err.println("Use option --force to force start a new server."); 125 | } 126 | return false; //ignored 127 | }) 128 | .orElseGet(() -> { 129 | server.start(); 130 | return false; // ignored 131 | }); 132 | } 133 | 134 | private static boolean shouldForceStart(Config config) { 135 | return config.isForceStart() || (config.isInteractive() && userToStartAnother()); 136 | } 137 | 138 | private static Config getConfig(final String[] args) { 139 | OptionParser parser = new OptionParser(); 140 | OptionSpec workDirOpt = parser.accepts("work-dir") 141 | .withOptionalArg() 142 | .describedAs("Working directory") 143 | .ofType(File.class) 144 | .defaultsTo(getDefaultWorkingDir()); 145 | 146 | OptionSpec portOpt = parser.accepts("port") 147 | .withOptionalArg() 148 | .describedAs("Server port; Pass 0 to select a random port") 149 | .ofType(Integer.class) 150 | .defaultsTo(0); 151 | 152 | parser.accepts("non-interactive") 153 | .withOptionalArg() 154 | .describedAs("No user input"); 155 | parser.accepts("force") 156 | .withOptionalArg() 157 | .describedAs("Force start a new server in case a server is already running"); 158 | parser.accepts("help").forHelp(); 159 | 160 | try { 161 | OptionSet options = parser.parse(args); 162 | return new Config(portOpt.value(options), workDirOpt.value(options), !options.has("non-interactive"), 163 | options.has("force")); 164 | } catch (OptionException optException) { 165 | try { 166 | System.err.println("[ERROR] " + optException.getMessage()); 167 | System.out.println(); 168 | System.out.println("Usage:"); 169 | System.out.println("======"); 170 | parser.printHelpOn(System.out); 171 | System.exit(0); 172 | return null; 173 | } catch (IOException e) { 174 | throw new RuntimeException(e); 175 | } 176 | } 177 | } 178 | 179 | private static boolean userToStartAnother() { 180 | System.out.print("Do you really want to start a new server? (y/n): "); 181 | final Scanner in = new Scanner(System.in); 182 | return in.hasNext() && in.nextLine().equalsIgnoreCase("y"); 183 | } 184 | 185 | public static void main(String[] args) { 186 | start(args); 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /jvm-assembler-server/src/main/java/com/mmhelloworld/jvmassembler/server/Config.java: -------------------------------------------------------------------------------- 1 | package com.mmhelloworld.jvmassembler.server; 2 | 3 | import java.io.File; 4 | 5 | public final class Config { 6 | private final int port; 7 | private final File workingDir; 8 | private final boolean isInteractive; 9 | private final boolean forceStart; 10 | 11 | public Config(final int port, final File workingDir, final boolean isInteractive, final boolean forceStart) { 12 | this.port = port; 13 | this.workingDir = workingDir; 14 | this.isInteractive = isInteractive; 15 | this.forceStart = forceStart; 16 | } 17 | 18 | public int getPort() { 19 | return port; 20 | } 21 | 22 | public File getWorkingDir() { 23 | return workingDir; 24 | } 25 | 26 | public boolean isInteractive() { 27 | return isInteractive; 28 | } 29 | 30 | public boolean isForceStart() { 31 | return forceStart; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jvm-assembler-server/src/main/java/com/mmhelloworld/jvmassembler/server/CreateBytecode.java: -------------------------------------------------------------------------------- 1 | package com.mmhelloworld.jvmassembler.server; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * User: marimuthu 9 | */ 10 | public class CreateBytecode { 11 | private final List instructions; 12 | 13 | public CreateBytecode(@JsonProperty("instructions") List instructions) { 14 | this.instructions = instructions; 15 | } 16 | 17 | public List getInstructions() { 18 | return instructions; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.mmhelloworld 8 | jvm-assembler 9 | 1.0-SNAPSHOT 10 | 11 | jvm-assembler-server 12 | 13 | pom 14 | 15 | 16 | 2.23.2 17 | 2.9.5 18 | 9.4.51.v20230217 19 | 5.1 20 | 5.0.2 21 | 1.16.12 22 | 23 | 24 | 25 | 26 | 27 | 28 | maven-compiler-plugin 29 | 3.5.1 30 | 31 | 1.8 32 | 1.8 33 | 34 | 35 | 36 | org.eclipse.jetty 37 | jetty-maven-plugin 38 | ${jetty.version} 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.glassfish.jersey 48 | jersey-bom 49 | ${jersey.version} 50 | pom 51 | import 52 | 53 | 54 | 55 | com.fasterxml.jackson 56 | jackson-bom 57 | ${jackson.version} 58 | pom 59 | import 60 | 61 | 62 | 63 | org.glassfish.jersey.media 64 | jersey-media-moxy 65 | ${jersey.version} 66 | 67 | 68 | 69 | org.glassfish.jersey.media 70 | jersey-media-json-jackson 71 | ${jersey.version} 72 | 73 | 74 | 75 | org.eclipse.jetty 76 | jetty-server 77 | ${jetty.version} 78 | 79 | 80 | 81 | org.eclipse.jetty 82 | jetty-servlet 83 | ${jetty.version} 84 | 85 | 86 | 87 | org.ow2.asm 88 | asm-all 89 | ${asm.version} 90 | 91 | 92 | 93 | net.sf.jopt-simple 94 | jopt-simple 95 | ${joptsimple.version} 96 | 97 | 98 | 99 | org.projectlombok 100 | lombok 101 | ${lombok.version} 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | --------------------------------------------------------------------------------