Compare commits
No commits in common. "008bd06680a69bd69838f31a01766e732d50a3ac" and "c5ce7ac6512aa9c0fd47958ee7b04f17cd81bd10" have entirely different histories.
008bd06680
...
c5ce7ac651
110 changed files with 1887 additions and 2928 deletions
50
README.md
50
README.md
|
|
@ -1,11 +1,9 @@
|
||||||
# bejava compiler
|
# beejava
|
||||||
Bejava (backend java) compiler is a code creation library, somewhat comparable to javassist or bytebuddy.
|
Beejava is a code creation library, somewhat comparable to javassist or bytebuddy.
|
||||||
* It let's you compile bejava-lang' to bytecode. As an alternative a BeSource object can be created programmatically and then compiled.
|
* It let's you compile java 'opcode' to bytecode.
|
||||||
* In this way it is a backend compiler.
|
|
||||||
* Handles creation of the constant pool
|
|
||||||
* It does not inspect or enhance existing bytecode, though it could be part of such functionality.
|
* It does not inspect or enhance existing bytecode, though it could be part of such functionality.
|
||||||
|
|
||||||
What is 'bejava lang'?
|
What is 'opcode'?
|
||||||
|
|
||||||
The goal of the project is to let developers dynamically create classes, using a simplified version of standard java opcodes. For instance:
|
The goal of the project is to let developers dynamically create classes, using a simplified version of standard java opcodes. For instance:
|
||||||
instead of having to choose between:
|
instead of having to choose between:
|
||||||
|
|
@ -39,49 +37,17 @@ BeeConstructor createDefaultConstructor() {
|
||||||
return BeeConstructor.builder()
|
return BeeConstructor.builder()
|
||||||
.withAccessFlags(MethodAccessFlags.PUBLIC)
|
.withAccessFlags(MethodAccessFlags.PUBLIC)
|
||||||
.withCode(
|
.withCode(
|
||||||
line(LD_VAR, Ref.THIS),
|
line(0, LD_VAR, Ref.THIS),
|
||||||
line(INVOKE, Ref.SUPER, "<init>", "()"),
|
line(1, INVOKE, Ref.SUPER, "<init>", "()"),
|
||||||
line(RETURN))
|
line(5, RETURN))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
and
|
|
||||||
```
|
|
||||||
BeeMethod print2 = BeeMethod.builder()
|
|
||||||
.withName("print2")
|
|
||||||
.withAccessFlags(MethodAccessFlags.PUBLIC)
|
|
||||||
.withCode(
|
|
||||||
line(GET, "java.lang.System","out"),
|
|
||||||
line(LD_CONST, "2"),
|
|
||||||
line(INVOKE, "java.io.PrintStream", "println", "java.lang.String"),
|
|
||||||
line(RETURN))
|
|
||||||
.build();
|
|
||||||
```
|
|
||||||
|
|
||||||
The latest commits are centered around the new feature that let's you write code like this:
|
|
||||||
```
|
|
||||||
class com.acme.SimpleBean(V15)
|
|
||||||
field private int value
|
|
||||||
constructor public()
|
|
||||||
INVOKE super()
|
|
||||||
RETURN
|
|
||||||
method public getValue() -> int
|
|
||||||
RETURN this.value
|
|
||||||
method public setValue(int newValue)
|
|
||||||
LOAD newValue
|
|
||||||
PUT this.value
|
|
||||||
RETURN
|
|
||||||
```
|
|
||||||
* text based instead of programmatic, although that will still be possible
|
|
||||||
* abstracts away most of the intricacies of working with a stack (although like bytecode it will still be stack based)
|
|
||||||
* indent-aware like python ;)
|
|
||||||
|
|
||||||
|
|
||||||
*Ideas about what's next*
|
*Ideas about what's next*
|
||||||
* MORE opcodes
|
* MORE opcodes
|
||||||
* invoke dynamic support (also in constant pool)
|
* invoke dynamic support (also in constant pool)
|
||||||
* support for exceptions, class attributes
|
* support for exceptions, class attributes
|
||||||
* figure out a nicer, better api
|
* figure out a nicer, better api, drop the line numbers
|
||||||
* or instead drop this idea and let the developer write the raw bytecode. The constant pool would then be the only thing Beejava adds.
|
* or instead drop this idea and let the developer write the raw bytecode. The constant pool would then be the only thing Beejava adds.
|
||||||
* create a readable file format for opcode files
|
* create a readable file format for opcode files
|
||||||
|
|
|
||||||
719
out
719
out
|
|
@ -1,719 +0,0 @@
|
||||||
Classfile /Users/Shautvast/IdeaProjects/beejava/target/classes/nl/sander/beejava/Compiler.class
|
|
||||||
Last modified 19 Nov 2020; size 6572 bytes
|
|
||||||
SHA-256 checksum 0fb294ea8b397e1710dc3017a3c9c31e9bbda5f5219ef646af238a9a0aa62e0a
|
|
||||||
Compiled from "Compiler.java"
|
|
||||||
public class nl.sander.beejava.Compiler
|
|
||||||
minor version: 0
|
|
||||||
major version: 59
|
|
||||||
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
|
|
||||||
this_class: #11 // nl/sander/beejava/Compiler
|
|
||||||
super_class: #2 // java/lang/Object
|
|
||||||
interfaces: 0, fields: 4, methods: 9, attributes: 3
|
|
||||||
Constant pool:
|
|
||||||
#1 = Methodref #2.#3 // java/lang/Object."<init>":()V
|
|
||||||
#2 = Class #4 // java/lang/Object
|
|
||||||
#3 = NameAndType #5:#6 // "<init>":()V
|
|
||||||
#4 = Utf8 java/lang/Object
|
|
||||||
#5 = Utf8 <init>
|
|
||||||
#6 = Utf8 ()V
|
|
||||||
#7 = Class #8 // nl/sander/beejava/ConstantPoolCreator
|
|
||||||
#8 = Utf8 nl/sander/beejava/ConstantPoolCreator
|
|
||||||
#9 = Methodref #7.#3 // nl/sander/beejava/ConstantPoolCreator."<init>":()V
|
|
||||||
#10 = Fieldref #11.#12 // nl/sander/beejava/Compiler.constantPoolCreator:Lnl/sander/beejava/ConstantPoolCreator;
|
|
||||||
#11 = Class #13 // nl/sander/beejava/Compiler
|
|
||||||
#12 = NameAndType #14:#15 // constantPoolCreator:Lnl/sander/beejava/ConstantPoolCreator;
|
|
||||||
#13 = Utf8 nl/sander/beejava/Compiler
|
|
||||||
#14 = Utf8 constantPoolCreator
|
|
||||||
#15 = Utf8 Lnl/sander/beejava/ConstantPoolCreator;
|
|
||||||
#16 = Fieldref #11.#17 // nl/sander/beejava/Compiler.compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
#17 = NameAndType #18:#19 // compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
#18 = Utf8 compiledClass
|
|
||||||
#19 = Utf8 Lnl/sander/beejava/CompiledClass;
|
|
||||||
#20 = Class #21 // nl/sander/beejava/ConstantPoolEntryCreator
|
|
||||||
#21 = Utf8 nl/sander/beejava/ConstantPoolEntryCreator
|
|
||||||
#22 = Methodref #20.#23 // nl/sander/beejava/ConstantPoolEntryCreator."<init>":(Lnl/sander/beejava/CompiledClass;)V
|
|
||||||
#23 = NameAndType #5:#24 // "<init>":(Lnl/sander/beejava/CompiledClass;)V
|
|
||||||
#24 = Utf8 (Lnl/sander/beejava/CompiledClass;)V
|
|
||||||
#25 = Fieldref #11.#26 // nl/sander/beejava/Compiler.constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
#26 = NameAndType #27:#28 // constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
#27 = Utf8 constantPoolEntryCreator
|
|
||||||
#28 = Utf8 Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
#29 = Class #30 // nl/sander/beejava/CompiledClass
|
|
||||||
#30 = Utf8 nl/sander/beejava/CompiledClass
|
|
||||||
#31 = Methodref #29.#32 // nl/sander/beejava/CompiledClass."<init>":(Lnl/sander/beejava/api/BeeSource;)V
|
|
||||||
#32 = NameAndType #5:#33 // "<init>":(Lnl/sander/beejava/api/BeeSource;)V
|
|
||||||
#33 = Utf8 (Lnl/sander/beejava/api/BeeSource;)V
|
|
||||||
#34 = Methodref #11.#23 // nl/sander/beejava/Compiler."<init>":(Lnl/sander/beejava/CompiledClass;)V
|
|
||||||
#35 = Methodref #11.#36 // nl/sander/beejava/Compiler.compile:()Lnl/sander/beejava/CompiledClass;
|
|
||||||
#36 = NameAndType #37:#38 // compile:()Lnl/sander/beejava/CompiledClass;
|
|
||||||
#37 = Utf8 compile
|
|
||||||
#38 = Utf8 ()Lnl/sander/beejava/CompiledClass;
|
|
||||||
#39 = Methodref #11.#40 // nl/sander/beejava/Compiler.createConstantPool:()Lnl/sander/beejava/constantpool/ConstantPool;
|
|
||||||
#40 = NameAndType #41:#42 // createConstantPool:()Lnl/sander/beejava/constantpool/ConstantPool;
|
|
||||||
#41 = Utf8 createConstantPool
|
|
||||||
#42 = Utf8 ()Lnl/sander/beejava/constantpool/ConstantPool;
|
|
||||||
#43 = Methodref #29.#44 // nl/sander/beejava/CompiledClass.setConstantPool:(Lnl/sander/beejava/constantpool/ConstantPool;)V
|
|
||||||
#44 = NameAndType #45:#46 // setConstantPool:(Lnl/sander/beejava/constantpool/ConstantPool;)V
|
|
||||||
#45 = Utf8 setConstantPool
|
|
||||||
#46 = Utf8 (Lnl/sander/beejava/constantpool/ConstantPool;)V
|
|
||||||
#47 = Methodref #20.#48 // nl/sander/beejava/ConstantPoolEntryCreator.addInterfaces:()V
|
|
||||||
#48 = NameAndType #49:#6 // addInterfaces:()V
|
|
||||||
#49 = Utf8 addInterfaces
|
|
||||||
#50 = Methodref #20.#51 // nl/sander/beejava/ConstantPoolEntryCreator.addFields:()V
|
|
||||||
#51 = NameAndType #52:#6 // addFields:()V
|
|
||||||
#52 = Utf8 addFields
|
|
||||||
#53 = Methodref #11.#54 // nl/sander/beejava/Compiler.addConstructors:()V
|
|
||||||
#54 = NameAndType #55:#6 // addConstructors:()V
|
|
||||||
#55 = Utf8 addConstructors
|
|
||||||
#56 = Methodref #11.#57 // nl/sander/beejava/Compiler.addMethods:()V
|
|
||||||
#57 = NameAndType #58:#6 // addMethods:()V
|
|
||||||
#58 = Utf8 addMethods
|
|
||||||
#59 = Methodref #29.#60 // nl/sander/beejava/CompiledClass.getSource:()Lnl/sander/beejava/api/BeeSource;
|
|
||||||
#60 = NameAndType #61:#62 // getSource:()Lnl/sander/beejava/api/BeeSource;
|
|
||||||
#61 = Utf8 getSource
|
|
||||||
#62 = Utf8 ()Lnl/sander/beejava/api/BeeSource;
|
|
||||||
#63 = Methodref #64.#65 // nl/sander/beejava/api/BeeSource.getConstructors:()Ljava/util/Set;
|
|
||||||
#64 = Class #66 // nl/sander/beejava/api/BeeSource
|
|
||||||
#65 = NameAndType #67:#68 // getConstructors:()Ljava/util/Set;
|
|
||||||
#66 = Utf8 nl/sander/beejava/api/BeeSource
|
|
||||||
#67 = Utf8 getConstructors
|
|
||||||
#68 = Utf8 ()Ljava/util/Set;
|
|
||||||
#69 = InvokeDynamic #0:#70 // #0:accept:(Lnl/sander/beejava/Compiler;)Ljava/util/function/Consumer;
|
|
||||||
#70 = NameAndType #71:#72 // accept:(Lnl/sander/beejava/Compiler;)Ljava/util/function/Consumer;
|
|
||||||
#71 = Utf8 accept
|
|
||||||
#72 = Utf8 (Lnl/sander/beejava/Compiler;)Ljava/util/function/Consumer;
|
|
||||||
#73 = InterfaceMethodref #74.#75 // java/util/Set.forEach:(Ljava/util/function/Consumer;)V
|
|
||||||
#74 = Class #76 // java/util/Set
|
|
||||||
#75 = NameAndType #77:#78 // forEach:(Ljava/util/function/Consumer;)V
|
|
||||||
#76 = Utf8 java/util/Set
|
|
||||||
#77 = Utf8 forEach
|
|
||||||
#78 = Utf8 (Ljava/util/function/Consumer;)V
|
|
||||||
#79 = Methodref #64.#80 // nl/sander/beejava/api/BeeSource.getMethods:()Ljava/util/Set;
|
|
||||||
#80 = NameAndType #81:#68 // getMethods:()Ljava/util/Set;
|
|
||||||
#81 = Utf8 getMethods
|
|
||||||
#82 = InvokeDynamic #1:#70 // #1:accept:(Lnl/sander/beejava/Compiler;)Ljava/util/function/Consumer;
|
|
||||||
#83 = Methodref #20.#84 // nl/sander/beejava/ConstantPoolEntryCreator.addThisClass:()Lnl/sander/beejava/constantpool/entry/ClassEntry;
|
|
||||||
#84 = NameAndType #85:#86 // addThisClass:()Lnl/sander/beejava/constantpool/entry/ClassEntry;
|
|
||||||
#85 = Utf8 addThisClass
|
|
||||||
#86 = Utf8 ()Lnl/sander/beejava/constantpool/entry/ClassEntry;
|
|
||||||
#87 = Methodref #29.#88 // nl/sander/beejava/CompiledClass.setThisClass:(Lnl/sander/beejava/constantpool/entry/ClassEntry;)V
|
|
||||||
#88 = NameAndType #89:#90 // setThisClass:(Lnl/sander/beejava/constantpool/entry/ClassEntry;)V
|
|
||||||
#89 = Utf8 setThisClass
|
|
||||||
#90 = Utf8 (Lnl/sander/beejava/constantpool/entry/ClassEntry;)V
|
|
||||||
#91 = String #92 // Code
|
|
||||||
#92 = Utf8 Code
|
|
||||||
#93 = Methodref #20.#94 // nl/sander/beejava/ConstantPoolEntryCreator.getOrCreateUtf8:(Ljava/lang/String;)Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
#94 = NameAndType #95:#96 // getOrCreateUtf8:(Ljava/lang/String;)Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
#95 = Utf8 getOrCreateUtf8
|
|
||||||
#96 = Utf8 (Ljava/lang/String;)Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
#97 = Fieldref #11.#98 // nl/sander/beejava/Compiler.codeAttributeNameEntry:Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
#98 = NameAndType #99:#100 // codeAttributeNameEntry:Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
#99 = Utf8 codeAttributeNameEntry
|
|
||||||
#100 = Utf8 Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
#101 = Methodref #29.#102 // nl/sander/beejava/CompiledClass.addConstantPoolEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
#102 = NameAndType #103:#104 // addConstantPoolEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
#103 = Utf8 addConstantPoolEntry
|
|
||||||
#104 = Utf8 (Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
#105 = Methodref #29.#106 // nl/sander/beejava/CompiledClass.getConstantTree:()Ljava/util/Set;
|
|
||||||
#106 = NameAndType #107:#68 // getConstantTree:()Ljava/util/Set;
|
|
||||||
#107 = Utf8 getConstantTree
|
|
||||||
#108 = Methodref #7.#109 // nl/sander/beejava/ConstantPoolCreator.createConstantPool:(Ljava/util/Set;)Lnl/sander/beejava/constantpool/ConstantPool;
|
|
||||||
#109 = NameAndType #41:#110 // createConstantPool:(Ljava/util/Set;)Lnl/sander/beejava/constantpool/ConstantPool;
|
|
||||||
#110 = Utf8 (Ljava/util/Set;)Lnl/sander/beejava/constantpool/ConstantPool;
|
|
||||||
#111 = InterfaceMethodref #74.#112 // java/util/Set.stream:()Ljava/util/stream/Stream;
|
|
||||||
#112 = NameAndType #113:#114 // stream:()Ljava/util/stream/Stream;
|
|
||||||
#113 = Utf8 stream
|
|
||||||
#114 = Utf8 ()Ljava/util/stream/Stream;
|
|
||||||
#115 = InvokeDynamic #2:#116 // #2:apply:(Lnl/sander/beejava/Compiler;)Ljava/util/function/Function;
|
|
||||||
#116 = NameAndType #117:#118 // apply:(Lnl/sander/beejava/Compiler;)Ljava/util/function/Function;
|
|
||||||
#117 = Utf8 apply
|
|
||||||
#118 = Utf8 (Lnl/sander/beejava/Compiler;)Ljava/util/function/Function;
|
|
||||||
#119 = InterfaceMethodref #120.#121 // java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
|
|
||||||
#120 = Class #122 // java/util/stream/Stream
|
|
||||||
#121 = NameAndType #123:#124 // map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
|
|
||||||
#122 = Utf8 java/util/stream/Stream
|
|
||||||
#123 = Utf8 map
|
|
||||||
#124 = Utf8 (Ljava/util/function/Function;)Ljava/util/stream/Stream;
|
|
||||||
#125 = Methodref #126.#127 // java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
|
|
||||||
#126 = Class #128 // java/util/Objects
|
|
||||||
#127 = NameAndType #129:#130 // requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
|
|
||||||
#128 = Utf8 java/util/Objects
|
|
||||||
#129 = Utf8 requireNonNull
|
|
||||||
#130 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object;
|
|
||||||
#131 = InvokeDynamic #3:#132 // #3:accept:(Lnl/sander/beejava/CompiledClass;)Ljava/util/function/Consumer;
|
|
||||||
#132 = NameAndType #71:#133 // accept:(Lnl/sander/beejava/CompiledClass;)Ljava/util/function/Consumer;
|
|
||||||
#133 = Utf8 (Lnl/sander/beejava/CompiledClass;)Ljava/util/function/Consumer;
|
|
||||||
#134 = InterfaceMethodref #120.#75 // java/util/stream/Stream.forEach:(Ljava/util/function/Consumer;)V
|
|
||||||
#135 = InterfaceMethodref #74.#136 // java/util/Set.iterator:()Ljava/util/Iterator;
|
|
||||||
#136 = NameAndType #137:#138 // iterator:()Ljava/util/Iterator;
|
|
||||||
#137 = Utf8 iterator
|
|
||||||
#138 = Utf8 ()Ljava/util/Iterator;
|
|
||||||
#139 = InterfaceMethodref #140.#141 // java/util/Iterator.hasNext:()Z
|
|
||||||
#140 = Class #142 // java/util/Iterator
|
|
||||||
#141 = NameAndType #143:#144 // hasNext:()Z
|
|
||||||
#142 = Utf8 java/util/Iterator
|
|
||||||
#143 = Utf8 hasNext
|
|
||||||
#144 = Utf8 ()Z
|
|
||||||
#145 = InterfaceMethodref #140.#146 // java/util/Iterator.next:()Ljava/lang/Object;
|
|
||||||
#146 = NameAndType #147:#148 // next:()Ljava/lang/Object;
|
|
||||||
#147 = Utf8 next
|
|
||||||
#148 = Utf8 ()Ljava/lang/Object;
|
|
||||||
#149 = Class #150 // nl/sander/beejava/api/BeeMethod
|
|
||||||
#150 = Utf8 nl/sander/beejava/api/BeeMethod
|
|
||||||
#151 = Methodref #11.#152 // nl/sander/beejava/Compiler.createMethod:(Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
#152 = NameAndType #153:#154 // createMethod:(Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
#153 = Utf8 createMethod
|
|
||||||
#154 = Utf8 (Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
#155 = Methodref #29.#156 // nl/sander/beejava/CompiledClass.addMethod:(Lnl/sander/beejava/classinfo/MethodInfo;)V
|
|
||||||
#156 = NameAndType #157:#158 // addMethod:(Lnl/sander/beejava/classinfo/MethodInfo;)V
|
|
||||||
#157 = Utf8 addMethod
|
|
||||||
#158 = Utf8 (Lnl/sander/beejava/classinfo/MethodInfo;)V
|
|
||||||
#159 = Class #160 // nl/sander/beejava/classinfo/MethodInfo
|
|
||||||
#160 = Utf8 nl/sander/beejava/classinfo/MethodInfo
|
|
||||||
#161 = Methodref #162.#163 // nl/sander/beejava/CodeContainer.getName:()Ljava/lang/String;
|
|
||||||
#162 = Class #164 // nl/sander/beejava/CodeContainer
|
|
||||||
#163 = NameAndType #165:#166 // getName:()Ljava/lang/String;
|
|
||||||
#164 = Utf8 nl/sander/beejava/CodeContainer
|
|
||||||
#165 = Utf8 getName
|
|
||||||
#166 = Utf8 ()Ljava/lang/String;
|
|
||||||
#167 = Methodref #162.#168 // nl/sander/beejava/CodeContainer.getSignature:()Ljava/lang/String;
|
|
||||||
#168 = NameAndType #169:#166 // getSignature:()Ljava/lang/String;
|
|
||||||
#169 = Utf8 getSignature
|
|
||||||
#170 = Methodref #159.#171 // nl/sander/beejava/classinfo/MethodInfo."<init>":(Lnl/sander/beejava/constantpool/entry/Utf8Entry;Lnl/sander/beejava/constantpool/entry/Utf8Entry;)V
|
|
||||||
#171 = NameAndType #5:#172 // "<init>":(Lnl/sander/beejava/constantpool/entry/Utf8Entry;Lnl/sander/beejava/constantpool/entry/Utf8Entry;)V
|
|
||||||
#172 = Utf8 (Lnl/sander/beejava/constantpool/entry/Utf8Entry;Lnl/sander/beejava/constantpool/entry/Utf8Entry;)V
|
|
||||||
#173 = Methodref #162.#174 // nl/sander/beejava/CodeContainer.getAccessFlags:()Ljava/util/Set;
|
|
||||||
#174 = NameAndType #175:#68 // getAccessFlags:()Ljava/util/Set;
|
|
||||||
#175 = Utf8 getAccessFlags
|
|
||||||
#176 = Methodref #159.#177 // nl/sander/beejava/classinfo/MethodInfo.addAccessFlags:(Ljava/util/Set;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
#177 = NameAndType #178:#179 // addAccessFlags:(Ljava/util/Set;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
#178 = Utf8 addAccessFlags
|
|
||||||
#179 = Utf8 (Ljava/util/Set;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
#180 = Methodref #181.#182 // nl/sander/beejava/MethodCodeCreator.createCodeAttribute:(Lnl/sander/beejava/constantpool/entry/Utf8Entry;Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/attributes/CodeAttribute;
|
|
||||||
#181 = Class #183 // nl/sander/beejava/MethodCodeCreator
|
|
||||||
#182 = NameAndType #184:#185 // createCodeAttribute:(Lnl/sander/beejava/constantpool/entry/Utf8Entry;Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/attributes/CodeAttribute;
|
|
||||||
#183 = Utf8 nl/sander/beejava/MethodCodeCreator
|
|
||||||
#184 = Utf8 createCodeAttribute
|
|
||||||
#185 = Utf8 (Lnl/sander/beejava/constantpool/entry/Utf8Entry;Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/attributes/CodeAttribute;
|
|
||||||
#186 = Methodref #159.#187 // nl/sander/beejava/classinfo/MethodInfo.addAttribute:(Lnl/sander/beejava/classinfo/attributes/Attribute;)Lnl/sander/beejava/classinfo/Info;
|
|
||||||
#187 = NameAndType #188:#189 // addAttribute:(Lnl/sander/beejava/classinfo/attributes/Attribute;)Lnl/sander/beejava/classinfo/Info;
|
|
||||||
#188 = Utf8 addAttribute
|
|
||||||
#189 = Utf8 (Lnl/sander/beejava/classinfo/attributes/Attribute;)Lnl/sander/beejava/classinfo/Info;
|
|
||||||
#190 = Methodref #162.#191 // nl/sander/beejava/CodeContainer.getCode:()Ljava/util/List;
|
|
||||||
#191 = NameAndType #192:#193 // getCode:()Ljava/util/List;
|
|
||||||
#192 = Utf8 getCode
|
|
||||||
#193 = Utf8 ()Ljava/util/List;
|
|
||||||
#194 = InvokeDynamic #4:#70 // #4:accept:(Lnl/sander/beejava/Compiler;)Ljava/util/function/Consumer;
|
|
||||||
#195 = InterfaceMethodref #196.#75 // java/util/List.forEach:(Ljava/util/function/Consumer;)V
|
|
||||||
#196 = Class #197 // java/util/List
|
|
||||||
#197 = Utf8 java/util/List
|
|
||||||
#198 = Methodref #199.#200 // nl/sander/beejava/api/CodeLine.hasMethodCall:()Z
|
|
||||||
#199 = Class #201 // nl/sander/beejava/api/CodeLine
|
|
||||||
#200 = NameAndType #202:#144 // hasMethodCall:()Z
|
|
||||||
#201 = Utf8 nl/sander/beejava/api/CodeLine
|
|
||||||
#202 = Utf8 hasMethodCall
|
|
||||||
#203 = Methodref #20.#204 // nl/sander/beejava/ConstantPoolEntryCreator.getOrCreateMethodRefEntry:(Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/MethodRefEntry;
|
|
||||||
#204 = NameAndType #205:#206 // getOrCreateMethodRefEntry:(Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/MethodRefEntry;
|
|
||||||
#205 = Utf8 getOrCreateMethodRefEntry
|
|
||||||
#206 = Utf8 (Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/MethodRefEntry;
|
|
||||||
#207 = Methodref #199.#208 // nl/sander/beejava/api/CodeLine.setAssignedEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
#208 = NameAndType #209:#104 // setAssignedEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
#209 = Utf8 setAssignedEntry
|
|
||||||
#210 = Methodref #199.#211 // nl/sander/beejava/api/CodeLine.hasRefToOwnField:()Z
|
|
||||||
#211 = NameAndType #212:#144 // hasRefToOwnField:()Z
|
|
||||||
#212 = Utf8 hasRefToOwnField
|
|
||||||
#213 = Methodref #199.#214 // nl/sander/beejava/api/CodeLine.hasRefToExternalField:()Z
|
|
||||||
#214 = NameAndType #215:#144 // hasRefToExternalField:()Z
|
|
||||||
#215 = Utf8 hasRefToExternalField
|
|
||||||
#216 = Methodref #20.#217 // nl/sander/beejava/ConstantPoolEntryCreator.getOrCreateFieldRefEntry:(Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/FieldRefEntry;
|
|
||||||
#217 = NameAndType #218:#219 // getOrCreateFieldRefEntry:(Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/FieldRefEntry;
|
|
||||||
#218 = Utf8 getOrCreateFieldRefEntry
|
|
||||||
#219 = Utf8 (Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/FieldRefEntry;
|
|
||||||
#220 = Methodref #199.#221 // nl/sander/beejava/api/CodeLine.hasConstValue:()Z
|
|
||||||
#221 = NameAndType #222:#144 // hasConstValue:()Z
|
|
||||||
#222 = Utf8 hasConstValue
|
|
||||||
#223 = Methodref #20.#224 // nl/sander/beejava/ConstantPoolEntryCreator.getOrCreatePrimitiveEntry:(Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;
|
|
||||||
#224 = NameAndType #225:#226 // getOrCreatePrimitiveEntry:(Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;
|
|
||||||
#225 = Utf8 getOrCreatePrimitiveEntry
|
|
||||||
#226 = Utf8 (Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;
|
|
||||||
#227 = Utf8 LineNumberTable
|
|
||||||
#228 = Utf8 LocalVariableTable
|
|
||||||
#229 = Utf8 this
|
|
||||||
#230 = Utf8 Lnl/sander/beejava/Compiler;
|
|
||||||
#231 = Utf8 (Lnl/sander/beejava/api/BeeSource;)Lnl/sander/beejava/CompiledClass;
|
|
||||||
#232 = Utf8 beSource
|
|
||||||
#233 = Utf8 Lnl/sander/beejava/api/BeeSource;
|
|
||||||
#234 = Utf8 method
|
|
||||||
#235 = Utf8 Lnl/sander/beejava/api/BeeMethod;
|
|
||||||
#236 = Utf8 StackMapTable
|
|
||||||
#237 = Utf8 Lnl/sander/beejava/CodeContainer;
|
|
||||||
#238 = Utf8 updateConstantPool
|
|
||||||
#239 = Utf8 (Lnl/sander/beejava/CodeContainer;)V
|
|
||||||
#240 = Utf8 codeContainer
|
|
||||||
#241 = Utf8 (Lnl/sander/beejava/api/CodeLine;)V
|
|
||||||
#242 = Utf8 methodRefEntry
|
|
||||||
#243 = Utf8 Lnl/sander/beejava/constantpool/entry/MethodRefEntry;
|
|
||||||
#244 = Utf8 fieldRefEntry
|
|
||||||
#245 = Utf8 Lnl/sander/beejava/constantpool/entry/FieldRefEntry;
|
|
||||||
#246 = Utf8 primitiveEntry
|
|
||||||
#247 = Utf8 Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;
|
|
||||||
#248 = Utf8 codeline
|
|
||||||
#249 = Utf8 Lnl/sander/beejava/api/CodeLine;
|
|
||||||
#250 = Utf8 SourceFile
|
|
||||||
#251 = Utf8 Compiler.java
|
|
||||||
#252 = Utf8 BootstrapMethods
|
|
||||||
#253 = MethodHandle 6:#254 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
|
|
||||||
#254 = Methodref #255.#256 // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
|
|
||||||
#255 = Class #257 // java/lang/invoke/LambdaMetafactory
|
|
||||||
#256 = NameAndType #258:#259 // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
|
|
||||||
#257 = Utf8 java/lang/invoke/LambdaMetafactory
|
|
||||||
#258 = Utf8 metafactory
|
|
||||||
#259 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
|
|
||||||
#260 = MethodType #261 // (Ljava/lang/Object;)V
|
|
||||||
#261 = Utf8 (Ljava/lang/Object;)V
|
|
||||||
#262 = MethodHandle 5:#263 // REF_invokeVirtual nl/sander/beejava/Compiler.updateConstantPool:(Lnl/sander/beejava/CodeContainer;)V
|
|
||||||
#263 = Methodref #11.#264 // nl/sander/beejava/Compiler.updateConstantPool:(Lnl/sander/beejava/CodeContainer;)V
|
|
||||||
#264 = NameAndType #238:#239 // updateConstantPool:(Lnl/sander/beejava/CodeContainer;)V
|
|
||||||
#265 = MethodType #266 // (Lnl/sander/beejava/api/BeeConstructor;)V
|
|
||||||
#266 = Utf8 (Lnl/sander/beejava/api/BeeConstructor;)V
|
|
||||||
#267 = MethodType #268 // (Lnl/sander/beejava/api/BeeMethod;)V
|
|
||||||
#268 = Utf8 (Lnl/sander/beejava/api/BeeMethod;)V
|
|
||||||
#269 = MethodType #130 // (Ljava/lang/Object;)Ljava/lang/Object;
|
|
||||||
#270 = MethodHandle 5:#151 // REF_invokeVirtual nl/sander/beejava/Compiler.createMethod:(Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
#271 = MethodType #272 // (Lnl/sander/beejava/api/BeeConstructor;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
#272 = Utf8 (Lnl/sander/beejava/api/BeeConstructor;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
#273 = MethodHandle 5:#155 // REF_invokeVirtual nl/sander/beejava/CompiledClass.addMethod:(Lnl/sander/beejava/classinfo/MethodInfo;)V
|
|
||||||
#274 = MethodType #158 // (Lnl/sander/beejava/classinfo/MethodInfo;)V
|
|
||||||
#275 = MethodHandle 5:#276 // REF_invokeVirtual nl/sander/beejava/Compiler.updateConstantPool:(Lnl/sander/beejava/api/CodeLine;)V
|
|
||||||
#276 = Methodref #11.#277 // nl/sander/beejava/Compiler.updateConstantPool:(Lnl/sander/beejava/api/CodeLine;)V
|
|
||||||
#277 = NameAndType #238:#241 // updateConstantPool:(Lnl/sander/beejava/api/CodeLine;)V
|
|
||||||
#278 = MethodType #241 // (Lnl/sander/beejava/api/CodeLine;)V
|
|
||||||
#279 = Utf8 InnerClasses
|
|
||||||
#280 = Class #281 // java/lang/invoke/MethodHandles$Lookup
|
|
||||||
#281 = Utf8 java/lang/invoke/MethodHandles$Lookup
|
|
||||||
#282 = Class #283 // java/lang/invoke/MethodHandles
|
|
||||||
#283 = Utf8 java/lang/invoke/MethodHandles
|
|
||||||
#284 = Utf8 Lookup
|
|
||||||
{
|
|
||||||
private final nl.sander.beejava.CompiledClass compiledClass;
|
|
||||||
descriptor: Lnl/sander/beejava/CompiledClass;
|
|
||||||
flags: (0x0012) ACC_PRIVATE, ACC_FINAL
|
|
||||||
|
|
||||||
private final nl.sander.beejava.ConstantPoolEntryCreator constantPoolEntryCreator;
|
|
||||||
descriptor: Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
flags: (0x0012) ACC_PRIVATE, ACC_FINAL
|
|
||||||
|
|
||||||
private final nl.sander.beejava.ConstantPoolCreator constantPoolCreator;
|
|
||||||
descriptor: Lnl/sander/beejava/ConstantPoolCreator;
|
|
||||||
flags: (0x0012) ACC_PRIVATE, ACC_FINAL
|
|
||||||
|
|
||||||
private nl.sander.beejava.constantpool.entry.Utf8Entry codeAttributeNameEntry;
|
|
||||||
descriptor: Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
flags: (0x0002) ACC_PRIVATE
|
|
||||||
|
|
||||||
public nl.sander.beejava.Compiler(nl.sander.beejava.CompiledClass);
|
|
||||||
descriptor: (Lnl/sander/beejava/CompiledClass;)V
|
|
||||||
flags: (0x0001) ACC_PUBLIC
|
|
||||||
Code:
|
|
||||||
stack=4, locals=2, args_size=2
|
|
||||||
0: aload_0
|
|
||||||
1: invokespecial #1 // Method java/lang/Object."<init>":()V
|
|
||||||
4: aload_0
|
|
||||||
5: new #7 // class nl/sander/beejava/ConstantPoolCreator
|
|
||||||
8: dup
|
|
||||||
9: invokespecial #9 // Method nl/sander/beejava/ConstantPoolCreator."<init>":()V
|
|
||||||
12: putfield #10 // Field constantPoolCreator:Lnl/sander/beejava/ConstantPoolCreator;
|
|
||||||
15: aload_0
|
|
||||||
16: aload_1
|
|
||||||
17: putfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
20: aload_0
|
|
||||||
21: new #20 // class nl/sander/beejava/ConstantPoolEntryCreator
|
|
||||||
24: dup
|
|
||||||
25: aload_1
|
|
||||||
26: invokespecial #22 // Method nl/sander/beejava/ConstantPoolEntryCreator."<init>":(Lnl/sander/beejava/CompiledClass;)V
|
|
||||||
29: putfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
32: return
|
|
||||||
LineNumberTable:
|
|
||||||
line 34: 0
|
|
||||||
line 25: 4
|
|
||||||
line 35: 15
|
|
||||||
line 36: 20
|
|
||||||
line 37: 32
|
|
||||||
LocalVariableTable:
|
|
||||||
Start Length Slot Name Signature
|
|
||||||
0 33 0 this Lnl/sander/beejava/Compiler;
|
|
||||||
0 33 1 compiledClass Lnl/sander/beejava/CompiledClass;
|
|
||||||
|
|
||||||
public static nl.sander.beejava.CompiledClass compile(nl.sander.beejava.api.BeeSource);
|
|
||||||
descriptor: (Lnl/sander/beejava/api/BeeSource;)Lnl/sander/beejava/CompiledClass;
|
|
||||||
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
|
|
||||||
Code:
|
|
||||||
stack=5, locals=1, args_size=1
|
|
||||||
0: new #11 // class nl/sander/beejava/Compiler
|
|
||||||
3: dup
|
|
||||||
4: new #29 // class nl/sander/beejava/CompiledClass
|
|
||||||
7: dup
|
|
||||||
8: aload_0
|
|
||||||
9: invokespecial #31 // Method nl/sander/beejava/CompiledClass."<init>":(Lnl/sander/beejava/api/BeeSource;)V
|
|
||||||
12: invokespecial #34 // Method "<init>":(Lnl/sander/beejava/CompiledClass;)V
|
|
||||||
15: invokevirtual #35 // Method compile:()Lnl/sander/beejava/CompiledClass;
|
|
||||||
18: areturn
|
|
||||||
LineNumberTable:
|
|
||||||
line 46: 0
|
|
||||||
LocalVariableTable:
|
|
||||||
Start Length Slot Name Signature
|
|
||||||
0 19 0 beSource Lnl/sander/beejava/api/BeeSource;
|
|
||||||
|
|
||||||
public nl.sander.beejava.CompiledClass compile();
|
|
||||||
descriptor: ()Lnl/sander/beejava/CompiledClass;
|
|
||||||
flags: (0x0001) ACC_PUBLIC
|
|
||||||
Code:
|
|
||||||
stack=2, locals=1, args_size=1
|
|
||||||
0: aload_0
|
|
||||||
1: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
4: aload_0
|
|
||||||
5: invokevirtual #39 // Method createConstantPool:()Lnl/sander/beejava/constantpool/ConstantPool;
|
|
||||||
8: invokevirtual #43 // Method nl/sander/beejava/CompiledClass.setConstantPool:(Lnl/sander/beejava/constantpool/ConstantPool;)V
|
|
||||||
11: aload_0
|
|
||||||
12: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
15: invokevirtual #47 // Method nl/sander/beejava/ConstantPoolEntryCreator.addInterfaces:()V
|
|
||||||
18: aload_0
|
|
||||||
19: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
22: invokevirtual #50 // Method nl/sander/beejava/ConstantPoolEntryCreator.addFields:()V
|
|
||||||
25: aload_0
|
|
||||||
26: invokevirtual #53 // Method addConstructors:()V
|
|
||||||
29: aload_0
|
|
||||||
30: invokevirtual #56 // Method addMethods:()V
|
|
||||||
33: aload_0
|
|
||||||
34: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
37: areturn
|
|
||||||
LineNumberTable:
|
|
||||||
line 53: 0
|
|
||||||
line 55: 11
|
|
||||||
line 56: 18
|
|
||||||
line 57: 25
|
|
||||||
line 58: 29
|
|
||||||
line 60: 33
|
|
||||||
LocalVariableTable:
|
|
||||||
Start Length Slot Name Signature
|
|
||||||
0 38 0 this Lnl/sander/beejava/Compiler;
|
|
||||||
|
|
||||||
private nl.sander.beejava.constantpool.ConstantPool createConstantPool();
|
|
||||||
descriptor: ()Lnl/sander/beejava/constantpool/ConstantPool;
|
|
||||||
flags: (0x0002) ACC_PRIVATE
|
|
||||||
Code:
|
|
||||||
stack=3, locals=1, args_size=1
|
|
||||||
0: aload_0
|
|
||||||
1: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
4: invokevirtual #59 // Method nl/sander/beejava/CompiledClass.getSource:()Lnl/sander/beejava/api/BeeSource;
|
|
||||||
7: invokevirtual #63 // Method nl/sander/beejava/api/BeeSource.getConstructors:()Ljava/util/Set;
|
|
||||||
10: aload_0
|
|
||||||
11: invokedynamic #69, 0 // InvokeDynamic #0:accept:(Lnl/sander/beejava/Compiler;)Ljava/util/function/Consumer;
|
|
||||||
16: invokeinterface #73, 2 // InterfaceMethod java/util/Set.forEach:(Ljava/util/function/Consumer;)V
|
|
||||||
21: aload_0
|
|
||||||
22: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
25: invokevirtual #59 // Method nl/sander/beejava/CompiledClass.getSource:()Lnl/sander/beejava/api/BeeSource;
|
|
||||||
28: invokevirtual #79 // Method nl/sander/beejava/api/BeeSource.getMethods:()Ljava/util/Set;
|
|
||||||
31: aload_0
|
|
||||||
32: invokedynamic #82, 0 // InvokeDynamic #1:accept:(Lnl/sander/beejava/Compiler;)Ljava/util/function/Consumer;
|
|
||||||
37: invokeinterface #73, 2 // InterfaceMethod java/util/Set.forEach:(Ljava/util/function/Consumer;)V
|
|
||||||
42: aload_0
|
|
||||||
43: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
46: aload_0
|
|
||||||
47: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
50: invokevirtual #83 // Method nl/sander/beejava/ConstantPoolEntryCreator.addThisClass:()Lnl/sander/beejava/constantpool/entry/ClassEntry;
|
|
||||||
53: invokevirtual #87 // Method nl/sander/beejava/CompiledClass.setThisClass:(Lnl/sander/beejava/constantpool/entry/ClassEntry;)V
|
|
||||||
56: aload_0
|
|
||||||
57: aload_0
|
|
||||||
58: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
61: ldc #91 // String Code
|
|
||||||
63: invokevirtual #93 // Method nl/sander/beejava/ConstantPoolEntryCreator.getOrCreateUtf8:(Ljava/lang/String;)Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
66: putfield #97 // Field codeAttributeNameEntry:Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
69: aload_0
|
|
||||||
70: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
73: aload_0
|
|
||||||
74: getfield #97 // Field codeAttributeNameEntry:Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
77: invokevirtual #101 // Method nl/sander/beejava/CompiledClass.addConstantPoolEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
80: aload_0
|
|
||||||
81: getfield #10 // Field constantPoolCreator:Lnl/sander/beejava/ConstantPoolCreator;
|
|
||||||
84: aload_0
|
|
||||||
85: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
88: invokevirtual #105 // Method nl/sander/beejava/CompiledClass.getConstantTree:()Ljava/util/Set;
|
|
||||||
91: invokevirtual #108 // Method nl/sander/beejava/ConstantPoolCreator.createConstantPool:(Ljava/util/Set;)Lnl/sander/beejava/constantpool/ConstantPool;
|
|
||||||
94: areturn
|
|
||||||
LineNumberTable:
|
|
||||||
line 64: 0
|
|
||||||
line 65: 21
|
|
||||||
line 67: 42
|
|
||||||
line 69: 56
|
|
||||||
line 70: 69
|
|
||||||
line 72: 80
|
|
||||||
LocalVariableTable:
|
|
||||||
Start Length Slot Name Signature
|
|
||||||
0 95 0 this Lnl/sander/beejava/Compiler;
|
|
||||||
|
|
||||||
public void addConstructors();
|
|
||||||
descriptor: ()V
|
|
||||||
flags: (0x0001) ACC_PUBLIC
|
|
||||||
Code:
|
|
||||||
stack=3, locals=1, args_size=1
|
|
||||||
0: aload_0
|
|
||||||
1: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
4: invokevirtual #59 // Method nl/sander/beejava/CompiledClass.getSource:()Lnl/sander/beejava/api/BeeSource;
|
|
||||||
7: invokevirtual #63 // Method nl/sander/beejava/api/BeeSource.getConstructors:()Ljava/util/Set;
|
|
||||||
10: invokeinterface #111, 1 // InterfaceMethod java/util/Set.stream:()Ljava/util/stream/Stream;
|
|
||||||
15: aload_0
|
|
||||||
16: invokedynamic #115, 0 // InvokeDynamic #2:apply:(Lnl/sander/beejava/Compiler;)Ljava/util/function/Function;
|
|
||||||
21: invokeinterface #119, 2 // InterfaceMethod java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
|
|
||||||
26: aload_0
|
|
||||||
27: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
30: dup
|
|
||||||
31: invokestatic #125 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
|
|
||||||
34: pop
|
|
||||||
35: invokedynamic #131, 0 // InvokeDynamic #3:accept:(Lnl/sander/beejava/CompiledClass;)Ljava/util/function/Consumer;
|
|
||||||
40: invokeinterface #134, 2 // InterfaceMethod java/util/stream/Stream.forEach:(Ljava/util/function/Consumer;)V
|
|
||||||
45: return
|
|
||||||
LineNumberTable:
|
|
||||||
line 76: 0
|
|
||||||
line 77: 21
|
|
||||||
line 78: 31
|
|
||||||
line 79: 45
|
|
||||||
LocalVariableTable:
|
|
||||||
Start Length Slot Name Signature
|
|
||||||
0 46 0 this Lnl/sander/beejava/Compiler;
|
|
||||||
|
|
||||||
public void addMethods();
|
|
||||||
descriptor: ()V
|
|
||||||
flags: (0x0001) ACC_PUBLIC
|
|
||||||
Code:
|
|
||||||
stack=3, locals=3, args_size=1
|
|
||||||
0: aload_0
|
|
||||||
1: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
4: aload_0
|
|
||||||
5: getfield #97 // Field codeAttributeNameEntry:Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
8: invokevirtual #101 // Method nl/sander/beejava/CompiledClass.addConstantPoolEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
11: aload_0
|
|
||||||
12: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
15: invokevirtual #59 // Method nl/sander/beejava/CompiledClass.getSource:()Lnl/sander/beejava/api/BeeSource;
|
|
||||||
18: invokevirtual #79 // Method nl/sander/beejava/api/BeeSource.getMethods:()Ljava/util/Set;
|
|
||||||
21: invokeinterface #135, 1 // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator;
|
|
||||||
26: astore_1
|
|
||||||
27: aload_1
|
|
||||||
28: invokeinterface #139, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
|
|
||||||
33: ifeq 61
|
|
||||||
36: aload_1
|
|
||||||
37: invokeinterface #145, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
|
|
||||||
42: checkcast #149 // class nl/sander/beejava/api/BeeMethod
|
|
||||||
45: astore_2
|
|
||||||
46: aload_0
|
|
||||||
47: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
50: aload_0
|
|
||||||
51: aload_2
|
|
||||||
52: invokevirtual #151 // Method createMethod:(Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
55: invokevirtual #155 // Method nl/sander/beejava/CompiledClass.addMethod:(Lnl/sander/beejava/classinfo/MethodInfo;)V
|
|
||||||
58: goto 27
|
|
||||||
61: return
|
|
||||||
LineNumberTable:
|
|
||||||
line 86: 0
|
|
||||||
line 87: 11
|
|
||||||
line 88: 46
|
|
||||||
line 89: 58
|
|
||||||
line 94: 61
|
|
||||||
LocalVariableTable:
|
|
||||||
Start Length Slot Name Signature
|
|
||||||
46 12 2 method Lnl/sander/beejava/api/BeeMethod;
|
|
||||||
0 62 0 this Lnl/sander/beejava/Compiler;
|
|
||||||
StackMapTable: number_of_entries = 2
|
|
||||||
frame_type = 252 /* append */
|
|
||||||
offset_delta = 27
|
|
||||||
locals = [ class java/util/Iterator ]
|
|
||||||
frame_type = 250 /* chop */
|
|
||||||
offset_delta = 33
|
|
||||||
|
|
||||||
private nl.sander.beejava.classinfo.MethodInfo createMethod(nl.sander.beejava.api.CodeContainer);
|
|
||||||
descriptor: (Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
flags: (0x0002) ACC_PRIVATE
|
|
||||||
Code:
|
|
||||||
stack=5, locals=2, args_size=2
|
|
||||||
0: new #159 // class nl/sander/beejava/classinfo/MethodInfo
|
|
||||||
3: dup
|
|
||||||
4: aload_0
|
|
||||||
5: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
8: aload_1
|
|
||||||
9: invokevirtual #161 // Method nl/sander/beejava/CodeContainer.getName:()Ljava/lang/String;
|
|
||||||
12: invokevirtual #93 // Method nl/sander/beejava/ConstantPoolEntryCreator.getOrCreateUtf8:(Ljava/lang/String;)Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
15: aload_0
|
|
||||||
16: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
19: aload_1
|
|
||||||
20: invokevirtual #167 // Method nl/sander/beejava/CodeContainer.getSignature:()Ljava/lang/String;
|
|
||||||
23: invokevirtual #93 // Method nl/sander/beejava/ConstantPoolEntryCreator.getOrCreateUtf8:(Ljava/lang/String;)Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
26: invokespecial #170 // Method nl/sander/beejava/classinfo/MethodInfo."<init>":(Lnl/sander/beejava/constantpool/entry/Utf8Entry;Lnl/sander/beejava/constantpool/entry/Utf8Entry;)V
|
|
||||||
29: aload_1
|
|
||||||
30: invokevirtual #173 // Method nl/sander/beejava/CodeContainer.getAccessFlags:()Ljava/util/Set;
|
|
||||||
33: invokevirtual #176 // Method nl/sander/beejava/classinfo/MethodInfo.addAccessFlags:(Ljava/util/Set;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
36: aload_0
|
|
||||||
37: getfield #97 // Field codeAttributeNameEntry:Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
40: aload_1
|
|
||||||
41: invokestatic #180 // Method nl/sander/beejava/MethodCodeCreator.createCodeAttribute:(Lnl/sander/beejava/constantpool/entry/Utf8Entry;Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/attributes/CodeAttribute;
|
|
||||||
44: invokevirtual #186 // Method nl/sander/beejava/classinfo/MethodInfo.addAttribute:(Lnl/sander/beejava/classinfo/attributes/Attribute;)Lnl/sander/beejava/classinfo/Info;
|
|
||||||
47: checkcast #159 // class nl/sander/beejava/classinfo/MethodInfo
|
|
||||||
50: areturn
|
|
||||||
LineNumberTable:
|
|
||||||
line 101: 0
|
|
||||||
line 102: 9
|
|
||||||
line 103: 20
|
|
||||||
line 104: 30
|
|
||||||
line 105: 41
|
|
||||||
line 101: 50
|
|
||||||
LocalVariableTable:
|
|
||||||
Start Length Slot Name Signature
|
|
||||||
0 51 0 this Lnl/sander/beejava/Compiler;
|
|
||||||
0 51 1 method Lnl/sander/beejava/CodeContainer;
|
|
||||||
|
|
||||||
private void updateConstantPool(nl.sander.beejava.api.CodeContainer);
|
|
||||||
descriptor: (Lnl/sander/beejava/CodeContainer;)V
|
|
||||||
flags: (0x0002) ACC_PRIVATE
|
|
||||||
Code:
|
|
||||||
stack=3, locals=2, args_size=2
|
|
||||||
0: aload_0
|
|
||||||
1: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
4: aload_0
|
|
||||||
5: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
8: aload_1
|
|
||||||
9: invokevirtual #161 // Method nl/sander/beejava/CodeContainer.getName:()Ljava/lang/String;
|
|
||||||
12: invokevirtual #93 // Method nl/sander/beejava/ConstantPoolEntryCreator.getOrCreateUtf8:(Ljava/lang/String;)Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
15: invokevirtual #101 // Method nl/sander/beejava/CompiledClass.addConstantPoolEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
18: aload_0
|
|
||||||
19: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
22: aload_0
|
|
||||||
23: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
26: aload_1
|
|
||||||
27: invokevirtual #167 // Method nl/sander/beejava/CodeContainer.getSignature:()Ljava/lang/String;
|
|
||||||
30: invokevirtual #93 // Method nl/sander/beejava/ConstantPoolEntryCreator.getOrCreateUtf8:(Ljava/lang/String;)Lnl/sander/beejava/constantpool/entry/Utf8Entry;
|
|
||||||
33: invokevirtual #101 // Method nl/sander/beejava/CompiledClass.addConstantPoolEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
36: aload_1
|
|
||||||
37: invokevirtual #190 // Method nl/sander/beejava/CodeContainer.getCode:()Ljava/util/List;
|
|
||||||
40: aload_0
|
|
||||||
41: invokedynamic #194, 0 // InvokeDynamic #4:accept:(Lnl/sander/beejava/Compiler;)Ljava/util/function/Consumer;
|
|
||||||
46: invokeinterface #195, 2 // InterfaceMethod java/util/List.forEach:(Ljava/util/function/Consumer;)V
|
|
||||||
51: return
|
|
||||||
LineNumberTable:
|
|
||||||
line 112: 0
|
|
||||||
line 113: 18
|
|
||||||
line 114: 36
|
|
||||||
line 115: 51
|
|
||||||
LocalVariableTable:
|
|
||||||
Start Length Slot Name Signature
|
|
||||||
0 52 0 this Lnl/sander/beejava/Compiler;
|
|
||||||
0 52 1 codeContainer Lnl/sander/beejava/CodeContainer;
|
|
||||||
|
|
||||||
private void updateConstantPool(nl.sander.beejava.api.CodeLine);
|
|
||||||
descriptor: (Lnl/sander/beejava/api/CodeLine;)V
|
|
||||||
flags: (0x0002) ACC_PRIVATE
|
|
||||||
Code:
|
|
||||||
stack=2, locals=3, args_size=2
|
|
||||||
0: aload_1
|
|
||||||
1: invokevirtual #198 // Method nl/sander/beejava/api/CodeLine.hasMethodCall:()Z
|
|
||||||
4: ifeq 29
|
|
||||||
7: aload_0
|
|
||||||
8: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
11: aload_1
|
|
||||||
12: invokevirtual #203 // Method nl/sander/beejava/ConstantPoolEntryCreator.getOrCreateMethodRefEntry:(Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/MethodRefEntry;
|
|
||||||
15: astore_2
|
|
||||||
16: aload_1
|
|
||||||
17: aload_2
|
|
||||||
18: invokevirtual #207 // Method nl/sander/beejava/api/CodeLine.setAssignedEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
21: aload_0
|
|
||||||
22: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
25: aload_2
|
|
||||||
26: invokevirtual #101 // Method nl/sander/beejava/CompiledClass.addConstantPoolEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
29: aload_1
|
|
||||||
30: invokevirtual #210 // Method nl/sander/beejava/api/CodeLine.hasRefToOwnField:()Z
|
|
||||||
33: ifne 43
|
|
||||||
36: aload_1
|
|
||||||
37: invokevirtual #213 // Method nl/sander/beejava/api/CodeLine.hasRefToExternalField:()Z
|
|
||||||
40: ifeq 65
|
|
||||||
43: aload_0
|
|
||||||
44: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
47: aload_1
|
|
||||||
48: invokevirtual #216 // Method nl/sander/beejava/ConstantPoolEntryCreator.getOrCreateFieldRefEntry:(Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/FieldRefEntry;
|
|
||||||
51: astore_2
|
|
||||||
52: aload_1
|
|
||||||
53: aload_2
|
|
||||||
54: invokevirtual #207 // Method nl/sander/beejava/api/CodeLine.setAssignedEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
57: aload_0
|
|
||||||
58: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
61: aload_2
|
|
||||||
62: invokevirtual #101 // Method nl/sander/beejava/CompiledClass.addConstantPoolEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
65: aload_1
|
|
||||||
66: invokevirtual #220 // Method nl/sander/beejava/api/CodeLine.hasConstValue:()Z
|
|
||||||
69: ifeq 94
|
|
||||||
72: aload_0
|
|
||||||
73: getfield #25 // Field constantPoolEntryCreator:Lnl/sander/beejava/ConstantPoolEntryCreator;
|
|
||||||
76: aload_1
|
|
||||||
77: invokevirtual #223 // Method nl/sander/beejava/ConstantPoolEntryCreator.getOrCreatePrimitiveEntry:(Lnl/sander/beejava/api/CodeLine;)Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;
|
|
||||||
80: astore_2
|
|
||||||
81: aload_1
|
|
||||||
82: aload_2
|
|
||||||
83: invokevirtual #207 // Method nl/sander/beejava/api/CodeLine.setAssignedEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
86: aload_0
|
|
||||||
87: getfield #16 // Field compiledClass:Lnl/sander/beejava/CompiledClass;
|
|
||||||
90: aload_2
|
|
||||||
91: invokevirtual #101 // Method nl/sander/beejava/CompiledClass.addConstantPoolEntry:(Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;)V
|
|
||||||
94: return
|
|
||||||
LineNumberTable:
|
|
||||||
line 127: 0
|
|
||||||
line 128: 7
|
|
||||||
line 129: 16
|
|
||||||
line 130: 21
|
|
||||||
line 133: 29
|
|
||||||
line 134: 43
|
|
||||||
line 135: 52
|
|
||||||
line 136: 57
|
|
||||||
line 139: 65
|
|
||||||
line 140: 72
|
|
||||||
line 141: 81
|
|
||||||
line 142: 86
|
|
||||||
line 144: 94
|
|
||||||
LocalVariableTable:
|
|
||||||
Start Length Slot Name Signature
|
|
||||||
16 13 2 methodRefEntry Lnl/sander/beejava/constantpool/entry/MethodRefEntry;
|
|
||||||
52 13 2 fieldRefEntry Lnl/sander/beejava/constantpool/entry/FieldRefEntry;
|
|
||||||
81 13 2 primitiveEntry Lnl/sander/beejava/constantpool/entry/ConstantPoolEntry;
|
|
||||||
0 95 0 this Lnl/sander/beejava/Compiler;
|
|
||||||
0 95 1 codeline Lnl/sander/beejava/api/CodeLine;
|
|
||||||
StackMapTable: number_of_entries = 4
|
|
||||||
frame_type = 29 /* same */
|
|
||||||
frame_type = 13 /* same */
|
|
||||||
frame_type = 21 /* same */
|
|
||||||
frame_type = 28 /* same */
|
|
||||||
}
|
|
||||||
SourceFile: "Compiler.java"
|
|
||||||
BootstrapMethods:
|
|
||||||
0: #253 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
|
|
||||||
Method arguments:
|
|
||||||
#260 (Ljava/lang/Object;)V
|
|
||||||
#262 REF_invokeVirtual nl/sander/beejava/Compiler.updateConstantPool:(Lnl/sander/beejava/CodeContainer;)V
|
|
||||||
#265 (Lnl/sander/beejava/api/BeeConstructor;)V
|
|
||||||
1: #253 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
|
|
||||||
Method arguments:
|
|
||||||
#260 (Ljava/lang/Object;)V
|
|
||||||
#262 REF_invokeVirtual nl/sander/beejava/Compiler.updateConstantPool:(Lnl/sander/beejava/CodeContainer;)V
|
|
||||||
#267 (Lnl/sander/beejava/api/BeeMethod;)V
|
|
||||||
2: #253 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
|
|
||||||
Method arguments:
|
|
||||||
#269 (Ljava/lang/Object;)Ljava/lang/Object;
|
|
||||||
#270 REF_invokeVirtual nl/sander/beejava/Compiler.createMethod:(Lnl/sander/beejava/CodeContainer;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
#271 (Lnl/sander/beejava/api/BeeConstructor;)Lnl/sander/beejava/classinfo/MethodInfo;
|
|
||||||
3: #253 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
|
|
||||||
Method arguments:
|
|
||||||
#260 (Ljava/lang/Object;)V
|
|
||||||
#273 REF_invokeVirtual nl/sander/beejava/CompiledClass.addMethod:(Lnl/sander/beejava/classinfo/MethodInfo;)V
|
|
||||||
#274 (Lnl/sander/beejava/classinfo/MethodInfo;)V
|
|
||||||
4: #253 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
|
|
||||||
Method arguments:
|
|
||||||
#260 (Ljava/lang/Object;)V
|
|
||||||
#275 REF_invokeVirtual nl/sander/beejava/Compiler.updateConstantPool:(Lnl/sander/beejava/api/CodeLine;)V
|
|
||||||
#278 (Lnl/sander/beejava/api/CodeLine;)V
|
|
||||||
InnerClasses:
|
|
||||||
public static final #284= #280 of #282; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
|
|
||||||
18
pom.xml
18
pom.xml
|
|
@ -2,25 +2,35 @@
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<name>bejava</name>
|
<name>beejava</name>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.8.0</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<release>15</release>
|
<source>15</source>
|
||||||
|
<target>15</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>14</source>
|
||||||
|
<target>14</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
<groupId>nl.sander</groupId>
|
<groupId>nl.sander</groupId>
|
||||||
<artifactId>bejava</artifactId>
|
<artifactId>beejava</artifactId>
|
||||||
<version>0.1-SNAPSHOT</version>
|
<version>0.1-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<maven.compiler.source>14</maven.compiler.source>
|
||||||
|
<maven.compiler.target>14</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
package nl.sander.bejava;
|
package nl.sander.beejava;
|
||||||
|
|
||||||
import nl.sander.bejava.flags.AccessFlags;
|
import nl.sander.beejava.constantpool.ConstantPool;
|
||||||
import nl.sander.bejava.util.ByteBuf;
|
import nl.sander.beejava.flags.AccessFlags;
|
||||||
|
import nl.sander.beejava.util.ByteBuf;
|
||||||
|
|
||||||
public class BytecodeGenerator {
|
public class BytecodeGenerator {
|
||||||
|
|
||||||
|
|
@ -12,12 +13,12 @@ public class BytecodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] generate(CompiledClass compiledClass) {
|
public static byte[] generate(CompiledClass compiledClass) {
|
||||||
var bytecodeGenerator = new BytecodeGenerator(compiledClass);
|
BytecodeGenerator bytecodeGenerator = new BytecodeGenerator(compiledClass);
|
||||||
return bytecodeGenerator.generate();
|
return bytecodeGenerator.generate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] generate() {
|
private byte[] generate() {
|
||||||
var buf = new ByteBuf();
|
ByteBuf buf = new ByteBuf();
|
||||||
buf.addU8(0xCA, 0xFE, 0xBA, 0xBE);
|
buf.addU8(0xCA, 0xFE, 0xBA, 0xBE);
|
||||||
buf.addU16(compiledClass.getSource().getClassFileVersion().getMinor());
|
buf.addU16(compiledClass.getSource().getClassFileVersion().getMinor());
|
||||||
buf.addU16(compiledClass.getSource().getClassFileVersion().getMajor());
|
buf.addU16(compiledClass.getSource().getClassFileVersion().getMajor());
|
||||||
59
src/main/java/nl/sander/beejava/CodeContainer.java
Normal file
59
src/main/java/nl/sander/beejava/CodeContainer.java
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
package nl.sander.beejava;
|
||||||
|
|
||||||
|
import nl.sander.beejava.api.BeeParameter;
|
||||||
|
import nl.sander.beejava.api.BeeSource;
|
||||||
|
import nl.sander.beejava.api.CodeLine;
|
||||||
|
import nl.sander.beejava.flags.MethodAccessFlags;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parent of a constructor or a method.
|
||||||
|
*/
|
||||||
|
public abstract class CodeContainer {
|
||||||
|
|
||||||
|
protected final List<CodeLine> code = new LinkedList<>();
|
||||||
|
protected final Set<BeeParameter> formalParameters = new HashSet<>();
|
||||||
|
protected final Set<MethodAccessFlags> accessFlags = new HashSet<>();
|
||||||
|
private BeeSource owner;
|
||||||
|
|
||||||
|
public List<CodeLine> getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignature() {
|
||||||
|
return getParametersSignature() + TypeMapper.map(getReturnType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String getName();
|
||||||
|
|
||||||
|
public abstract Class<?> getReturnType();
|
||||||
|
|
||||||
|
private String getParametersSignature() {
|
||||||
|
return formalParameters.stream()
|
||||||
|
.map(BeeParameter::getType)
|
||||||
|
.map(TypeMapper::map)
|
||||||
|
.collect(Collectors.joining(",", "(", ")"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<MethodAccessFlags> getAccessFlags() {
|
||||||
|
return accessFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeSource getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOwner(BeeSource beeSource) {
|
||||||
|
if (owner != null) {
|
||||||
|
throw new IllegalStateException("Owner set twice. Sue the developer!");
|
||||||
|
}
|
||||||
|
this.owner = beeSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean isConstructor();
|
||||||
|
}
|
||||||
|
|
@ -1,32 +1,29 @@
|
||||||
package nl.sander.bejava;
|
package nl.sander.beejava;
|
||||||
|
|
||||||
import nl.sander.bejava.api.BeSource;
|
import nl.sander.beejava.api.BeeSource;
|
||||||
import nl.sander.bejava.classinfo.FieldInfo;
|
import nl.sander.beejava.classinfo.FieldInfo;
|
||||||
import nl.sander.bejava.classinfo.MethodInfo;
|
import nl.sander.beejava.classinfo.MethodInfo;
|
||||||
import nl.sander.bejava.constantpool.ConstantPool;
|
import nl.sander.beejava.constantpool.ConstantPool;
|
||||||
import nl.sander.bejava.constantpool.entry.ClassEntry;
|
import nl.sander.beejava.constantpool.entry.ClassEntry;
|
||||||
import nl.sander.bejava.constantpool.entry.ConstantPoolEntry;
|
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
|
||||||
* Eventually contains all information for generation of the actual bytecode.
|
|
||||||
* Output of the {@link Compiler} class.
|
|
||||||
*/
|
|
||||||
public class CompiledClass {
|
public class CompiledClass {
|
||||||
private final Set<ConstantPoolEntry> constantTree = new LinkedHashSet<>();
|
private final Set<ConstantPoolEntry> constantTree = new LinkedHashSet<>();
|
||||||
private final Set<ClassEntry> interfaces = new HashSet<>();
|
private final Set<ClassEntry> interfaces = new HashSet<>();
|
||||||
private final Set<FieldInfo> fields = new HashSet<>();
|
private final Set<FieldInfo> fields = new HashSet<>();
|
||||||
private final Set<MethodInfo> methods = new HashSet<>();
|
private final Set<MethodInfo> methods = new HashSet<>();
|
||||||
private final BeSource beSource;
|
private final BeeSource beeSource;
|
||||||
private ClassEntry thisClass;
|
private ClassEntry thisClass;
|
||||||
private ClassEntry superClass;
|
private ClassEntry superClass;
|
||||||
private ConstantPool constantPool;
|
private ConstantPool constantPool;
|
||||||
|
|
||||||
CompiledClass(BeSource beSource) {
|
CompiledClass(BeeSource beeSource) {
|
||||||
this.beSource = beSource;
|
this.beeSource = beeSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getSuperIndex() {
|
int getSuperIndex() {
|
||||||
|
|
@ -59,8 +56,8 @@ public class CompiledClass {
|
||||||
interfaces.add(interfaceEntry);
|
interfaces.add(interfaceEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
BeSource getSource() {
|
BeeSource getSource() {
|
||||||
return beSource;
|
return beeSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setThisClass(ClassEntry newThisClass) {
|
public void setThisClass(ClassEntry newThisClass) {
|
||||||
140
src/main/java/nl/sander/beejava/Compiler.java
Normal file
140
src/main/java/nl/sander/beejava/Compiler.java
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
package nl.sander.beejava;
|
||||||
|
|
||||||
|
import nl.sander.beejava.api.BeeSource;
|
||||||
|
import nl.sander.beejava.api.CodeLine;
|
||||||
|
import nl.sander.beejava.classinfo.MethodInfo;
|
||||||
|
import nl.sander.beejava.constantpool.ConstantPool;
|
||||||
|
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||||
|
import nl.sander.beejava.constantpool.entry.FieldRefEntry;
|
||||||
|
import nl.sander.beejava.constantpool.entry.MethodRefEntry;
|
||||||
|
import nl.sander.beejava.constantpool.entry.Utf8Entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a set of a tree of constant pool entries that refer to each other.
|
||||||
|
* <p>
|
||||||
|
* A client must supply a {@link BeeSource} containing a set of {@link CodeLine}s that is assumed to be correct.
|
||||||
|
* It doesn't check if a valid state is reached.
|
||||||
|
*/
|
||||||
|
/* So the name isn't entirely correct. Waiting for inspiration.
|
||||||
|
* also TODO make sure entries aren't duplicates
|
||||||
|
*/
|
||||||
|
public class Compiler {
|
||||||
|
private final CompiledClass compiledClass;
|
||||||
|
private final ConstantPoolEntryCreator constantPoolEntryCreator;
|
||||||
|
private final ConstantPoolCreator constantPoolCreator = new ConstantPoolCreator();
|
||||||
|
private Utf8Entry codeAttributeNameEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* construct a compiler object.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* At this moment I'm not sure if this class will be able to reused.
|
||||||
|
*/
|
||||||
|
public Compiler(CompiledClass compiledClass) {
|
||||||
|
this.compiledClass = compiledClass;
|
||||||
|
this.constantPoolEntryCreator = new ConstantPoolEntryCreator(compiledClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compile a BeeSource object into a CompiledClass object.
|
||||||
|
*
|
||||||
|
* @param beeSource the Class object for which the constant pool needs to be created
|
||||||
|
* @return a CompiledClass object (that can be turned into bytecode)
|
||||||
|
*/
|
||||||
|
public static CompiledClass compile(BeeSource beeSource) {
|
||||||
|
return new Compiler(new CompiledClass(beeSource)).compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* construct a CompiledClass object that contains all information for generating the bytecode
|
||||||
|
*/
|
||||||
|
public CompiledClass compile() {
|
||||||
|
compiledClass.setConstantPool(createConstantPool());
|
||||||
|
|
||||||
|
constantPoolEntryCreator.addInterfaces();
|
||||||
|
constantPoolEntryCreator.addFields();
|
||||||
|
addConstructors();
|
||||||
|
addMethods();
|
||||||
|
|
||||||
|
return compiledClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConstantPool createConstantPool() {
|
||||||
|
compiledClass.getSource().getConstructors().forEach(this::updateConstantPool);
|
||||||
|
compiledClass.getSource().getMethods().forEach(this::updateConstantPool); // compiledClass.getSource() ?
|
||||||
|
|
||||||
|
compiledClass.setThisClass(constantPoolEntryCreator.addThisClass());
|
||||||
|
|
||||||
|
this.codeAttributeNameEntry = constantPoolEntryCreator.getOrCreateUtf8("Code");
|
||||||
|
compiledClass.addConstantPoolEntry(codeAttributeNameEntry);
|
||||||
|
|
||||||
|
return constantPoolCreator.createConstantPool(compiledClass.getConstantTree());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addConstructors() {
|
||||||
|
compiledClass.getSource().getConstructors().stream()
|
||||||
|
.map(this::createMethod)
|
||||||
|
.forEach(compiledClass::addMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* maps methods from the source to a MethodInfo and adds that to the CompiledClass.
|
||||||
|
*/
|
||||||
|
public void addMethods() {
|
||||||
|
compiledClass.addConstantPoolEntry(codeAttributeNameEntry);
|
||||||
|
compiledClass.getSource().getMethods().stream()
|
||||||
|
.map(this::createMethod)
|
||||||
|
.forEach(compiledClass::addMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create bytecode for method
|
||||||
|
* create methodInfo object for classfile
|
||||||
|
*/
|
||||||
|
private MethodInfo createMethod(CodeContainer method) {
|
||||||
|
return new MethodInfo(
|
||||||
|
constantPoolEntryCreator.getOrCreateUtf8(method.getName()),
|
||||||
|
constantPoolEntryCreator.getOrCreateUtf8(method.getSignature()))
|
||||||
|
.addAccessFlags(method.getAccessFlags())
|
||||||
|
.addAttribute(MethodCodeCreator.createCodeAttribute(codeAttributeNameEntry, method));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* inspect a method or constructor, extract items that need to be added, and add them to the constant pool
|
||||||
|
*/
|
||||||
|
private void updateConstantPool(CodeContainer codeContainer) {
|
||||||
|
compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateUtf8(codeContainer.getName()));
|
||||||
|
compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateUtf8(codeContainer.getSignature()));
|
||||||
|
codeContainer.getCode().forEach(this::updateConstantPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan code line for items that need adding to the constant pool
|
||||||
|
*
|
||||||
|
* Constantpool uniqueness is maintained in two ways:
|
||||||
|
* 1. ConstantPoolEntryCreator.getOrCreateMethodRefEntry (and other methods) return a tree of entries.
|
||||||
|
* Sub-entries are kept in cache by the ConstantPoolEntryCreator and it returns a cached entry over a new one, if deemed equal.
|
||||||
|
* 2. the root node (also in aforementioned cache) is not symmetric because it is the only one that can be added to The compiledClass.
|
||||||
|
* So Compiled class also contains a set of unique root nodes.
|
||||||
|
*/
|
||||||
|
private void updateConstantPool(CodeLine codeline) {
|
||||||
|
if (codeline.hasMethodCall()) {
|
||||||
|
MethodRefEntry methodRefEntry = constantPoolEntryCreator.getOrCreateMethodRefEntry(codeline);
|
||||||
|
codeline.setAssignedEntry(methodRefEntry);
|
||||||
|
compiledClass.addConstantPoolEntry(methodRefEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codeline.hasRefToOwnField() || codeline.hasRefToExternalField()) {
|
||||||
|
FieldRefEntry fieldRefEntry = constantPoolEntryCreator.getOrCreateFieldRefEntry(codeline);
|
||||||
|
codeline.setAssignedEntry(fieldRefEntry);
|
||||||
|
compiledClass.addConstantPoolEntry(fieldRefEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codeline.hasConstValue()) {
|
||||||
|
ConstantPoolEntry primitiveEntry = constantPoolEntryCreator.getOrCreatePrimitiveEntry(codeline);
|
||||||
|
codeline.setAssignedEntry(primitiveEntry);
|
||||||
|
compiledClass.addConstantPoolEntry(primitiveEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package nl.sander.bejava;
|
package nl.sander.beejava;
|
||||||
|
|
||||||
import nl.sander.bejava.constantpool.ConstantPool;
|
import nl.sander.beejava.constantpool.ConstantPool;
|
||||||
import nl.sander.bejava.constantpool.entry.ConstantPoolEntry;
|
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ public class ConstantPoolCreator {
|
||||||
* - then add grandchildren (I don't think there's more levels)
|
* - then add grandchildren (I don't think there's more levels)
|
||||||
*/
|
*/
|
||||||
private void updateToplevelElements(Set<ConstantPoolEntry> children) {
|
private void updateToplevelElements(Set<ConstantPoolEntry> children) {
|
||||||
for (var topElement : children) {
|
for (ConstantPoolEntry topElement : children) {
|
||||||
addToPool(topElement); // grandparents
|
addToPool(topElement); // grandparents
|
||||||
updateChildElements(topElement.getChildren());
|
updateChildElements(topElement.getChildren());
|
||||||
}
|
}
|
||||||
|
|
@ -52,11 +52,11 @@ public class ConstantPoolCreator {
|
||||||
|
|
||||||
private void updateChildElements(Set<ConstantPoolEntry> children) {
|
private void updateChildElements(Set<ConstantPoolEntry> children) {
|
||||||
// parents
|
// parents
|
||||||
for (var child : children) {
|
for (ConstantPoolEntry child : children) {
|
||||||
addToPool(child);
|
addToPool(child);
|
||||||
}
|
}
|
||||||
// then grandchildren
|
// then grandchildren
|
||||||
for (var child : children) {
|
for (ConstantPoolEntry child : children) {
|
||||||
updateChildElements(child.getChildren()); // no problem if there are great grand children
|
updateChildElements(child.getChildren()); // no problem if there are great grand children
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
165
src/main/java/nl/sander/beejava/ConstantPoolEntryCreator.java
Normal file
165
src/main/java/nl/sander/beejava/ConstantPoolEntryCreator.java
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
package nl.sander.beejava;
|
||||||
|
|
||||||
|
import nl.sander.beejava.api.CodeLine;
|
||||||
|
import nl.sander.beejava.api.Ref;
|
||||||
|
import nl.sander.beejava.classinfo.FieldInfo;
|
||||||
|
import nl.sander.beejava.classinfo.attributes.CodeAttribute;
|
||||||
|
import nl.sander.beejava.constantpool.entry.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsible for creating unique constant pool entries
|
||||||
|
*/
|
||||||
|
class ConstantPoolEntryCreator {
|
||||||
|
private final Map<Integer, ConstantPoolEntry> cache = new HashMap<>();
|
||||||
|
private final CompiledClass compiledClass;
|
||||||
|
|
||||||
|
public ConstantPoolEntryCreator(CompiledClass compiledClass) {
|
||||||
|
this.compiledClass = compiledClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* creates a FieldRefEntry when not found in cache, otherwise gets it from there
|
||||||
|
*/
|
||||||
|
FieldRefEntry getOrCreateFieldRefEntry(CodeLine codeLine) {
|
||||||
|
return cache(new FieldRefEntry(getOrCreateClassEntry(codeLine), getOrCreateFieldNameAndType(codeLine)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* creates a MethodRefEntry when not found in cache, otherwise gets it from there
|
||||||
|
*/
|
||||||
|
MethodRefEntry getOrCreateMethodRefEntry(CodeLine codeline) {
|
||||||
|
ClassEntry classEntry = getOrCreateClassEntry(codeline);
|
||||||
|
return cache(new MethodRefEntry(classEntry, getOrCreateMethodNameAndType(codeline)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* creates a NamAndTypeEntry for a field when not found in cache, otherwise gets it from there
|
||||||
|
*/
|
||||||
|
private NameAndTypeEntry getOrCreateFieldNameAndType(CodeLine codeline) {
|
||||||
|
if (codeline.hasRefToOwnField()) {
|
||||||
|
return cache(new NameAndTypeEntry(
|
||||||
|
cache(new Utf8Entry(codeline.getOwnfield().getName())),
|
||||||
|
cache(new Utf8Entry(TypeMapper.map(codeline.getOwnfield().getType()))))); // is actually a shortcut
|
||||||
|
} else {//TODO this method may need some work
|
||||||
|
return cache(new NameAndTypeEntry(
|
||||||
|
cache(new Utf8Entry(codeline.getExternalfield().getName())),
|
||||||
|
cache(new Utf8Entry(TypeMapper.map(codeline.getExternalfield().getType())))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* creates a NamAndTypeEntry for a method when not found in cache, otherwise gets it from there
|
||||||
|
*/
|
||||||
|
private NameAndTypeEntry getOrCreateMethodNameAndType(CodeLine codeline) {
|
||||||
|
return new NameAndTypeEntry(
|
||||||
|
cache(new Utf8Entry(codeline.getMethodName())),
|
||||||
|
cache(new Utf8Entry(codeline.getMethodSignature())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* creates a ClassEntry when not found in cache, otherwise gets it from there
|
||||||
|
*/
|
||||||
|
private ClassEntry getOrCreateClassEntry(CodeLine codeline) {
|
||||||
|
if (codeline.hasRef()) {
|
||||||
|
if (codeline.getRef() == Ref.SUPER) { // this and super are rather special
|
||||||
|
ClassEntry superClass = getClassEntry(compiledClass.getSource().getSuperClass().getName());
|
||||||
|
compiledClass.setSuperClass(superClass);
|
||||||
|
return superClass;
|
||||||
|
|
||||||
|
} else if (codeline.getRef() == Ref.THIS) {
|
||||||
|
return addThisClass();
|
||||||
|
}
|
||||||
|
} else if (codeline.hasClassName()) {
|
||||||
|
return getClassEntry(codeline.getClassName());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException("shouldn't be here");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this method gives me a headache. It adds, but also creates a classEntry for the this class
|
||||||
|
*/
|
||||||
|
ClassEntry addThisClass() {
|
||||||
|
ClassEntry classEntry = getClassEntry(compiledClass.getSource().getName());
|
||||||
|
compiledClass.addConstantPoolEntry(classEntry);
|
||||||
|
return classEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get or create a ClassEntry
|
||||||
|
*/
|
||||||
|
private ClassEntry getClassEntry(String externalClassName) {
|
||||||
|
return cache(new ClassEntry(cache(new Utf8Entry(internalName(externalClassName)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds interfaces to the constant pool as well as the class.
|
||||||
|
*
|
||||||
|
* interfaces[] in the class file is an array of cp entries
|
||||||
|
*/
|
||||||
|
public void addInterfaces() {
|
||||||
|
compiledClass.getSource().getInterfaces().forEach(interfase -> {
|
||||||
|
ClassEntry interfaceEntry = cache(new ClassEntry(cache(new Utf8Entry(internalName(interfase.getName())))));
|
||||||
|
compiledClass.addInterface(interfaceEntry);
|
||||||
|
compiledClass.addConstantPoolEntry(interfaceEntry);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a constant is in the codeline, it needs to be added to the constant pool.
|
||||||
|
*/
|
||||||
|
public ConstantPoolEntry getOrCreatePrimitiveEntry(CodeLine codeline) {
|
||||||
|
Object v = codeline.getConstValue();
|
||||||
|
|
||||||
|
if (v instanceof String) {
|
||||||
|
return cache(new StringEntry(cache(new Utf8Entry((String) v))));
|
||||||
|
} else if (v instanceof Integer) {
|
||||||
|
return cache(new IntegerEntry((Integer) v));
|
||||||
|
} else if (v instanceof Long) {
|
||||||
|
return cache(new LongEntry((Long) v));
|
||||||
|
} else if (v instanceof Float) {
|
||||||
|
return cache(new FloatEntry((Float) v));
|
||||||
|
} else if (v instanceof Double) {
|
||||||
|
return cache(new DoubleEntry((Double) v));
|
||||||
|
}
|
||||||
|
throw new RuntimeException(); // TODO find out why are you here
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* maps a field from the source to a FieldInfo and adds that to the CompiledClass.
|
||||||
|
*/
|
||||||
|
public void addFields() {
|
||||||
|
compiledClass.getSource().getFields().stream()
|
||||||
|
.map(field -> new FieldInfo(
|
||||||
|
cache(new Utf8Entry(field.getName())),
|
||||||
|
cache(new Utf8Entry(internalName(field.getType().getName())))
|
||||||
|
).addAccessFlags(field.getAccessFlags())
|
||||||
|
)
|
||||||
|
.forEach(compiledClass::addField);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Utf8Entry getOrCreateUtf8(String utf8) {
|
||||||
|
return cache(new Utf8Entry(utf8));
|
||||||
|
}
|
||||||
|
|
||||||
|
// why not put this everywhere, it's not like it's ever going to change
|
||||||
|
private String internalName(String name) {
|
||||||
|
return name.replaceAll("\\.", "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
<T extends ConstantPoolEntry> T cache(T newEntry) {
|
||||||
|
// First create an object using the supplier, but if it's found in cache, return the cached entry and discard the first.
|
||||||
|
// Can't check for equality unless you create a potential new entry first
|
||||||
|
int hash = newEntry.hashCode();
|
||||||
|
return (T) cache.computeIfAbsent(hash, k -> newEntry);
|
||||||
|
// a hashmap with key hash of value is weird right?
|
||||||
|
// A HashSet is a HashMap with entry: key = value, which would work, but I cannot _get_ anything from a set.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,24 +1,12 @@
|
||||||
package nl.sander.bejava;
|
package nl.sander.beejava;
|
||||||
|
|
||||||
public enum JavaOpcode {
|
public enum JavaOpcode {
|
||||||
LDC(0x12, false, +1),
|
LDC(0x12, false, +1),
|
||||||
LDC_W(0x13,true, +1),
|
LDC_W(0x13,true, +1),
|
||||||
LDC2_W ( 0x14, true, +2),
|
LDC2_W ( 0x14, true, +2),
|
||||||
|
|
||||||
ALOAD ( 0x19, false, +1),
|
|
||||||
ALOAD_0 ( 0x2a, false, +1),
|
ALOAD_0 ( 0x2a, false, +1),
|
||||||
ALOAD_1 ( 0x2b, false, +1),
|
|
||||||
ALOAD_2 ( 0x2c, false, +1),
|
|
||||||
ALOAD_3 ( 0x2d, false, +1),
|
|
||||||
|
|
||||||
IRETURN ( 0xac,false, -1),
|
|
||||||
LRETURN(0xad, false, -2),
|
|
||||||
FRETURN(0xae,false,-1),
|
|
||||||
DRETURN(0xaf,false,-2),
|
|
||||||
ARETURN ( 0xb0,false, -1),
|
|
||||||
|
|
||||||
RETURN ( 0xb1,false, 0),
|
RETURN ( 0xb1,false, 0),
|
||||||
|
|
||||||
GETSTATIC ( 0xb2,true, +1),
|
GETSTATIC ( 0xb2,true, +1),
|
||||||
GETFIELD ( 0xb4,true, +1),
|
GETFIELD ( 0xb4,true, +1),
|
||||||
|
|
||||||
|
|
@ -26,10 +14,7 @@ public enum JavaOpcode {
|
||||||
INVOKEVIRTUAL ( 0xb6, true, -1),
|
INVOKEVIRTUAL ( 0xb6, true, -1),
|
||||||
INVOKESPECIAL ( 0xb7, true, -1),
|
INVOKESPECIAL ( 0xb7, true, -1),
|
||||||
INVOKESTATIC ( 0xb8, true, -1),
|
INVOKESTATIC ( 0xb8, true, -1),
|
||||||
INVOKEDYNAMIC ( 0xba,true,-1),
|
INVOKEDYNAMIC ( 0xba,true,-1);
|
||||||
|
|
||||||
PUTFIELD(0xb5, true, -2);
|
|
||||||
|
|
||||||
|
|
||||||
private final int opcode;
|
private final int opcode;
|
||||||
private final boolean wide;
|
private final boolean wide;
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
package nl.sander.bejava;
|
package nl.sander.beejava;
|
||||||
|
|
||||||
import nl.sander.bejava.api.CodeContainer;
|
import nl.sander.beejava.api.CodeLine;
|
||||||
import nl.sander.bejava.classinfo.attributes.CodeAttribute;
|
import nl.sander.beejava.classinfo.attributes.CodeAttribute;
|
||||||
import nl.sander.bejava.constantpool.entry.ConstantPoolEntry;
|
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||||
import nl.sander.bejava.constantpool.entry.MethodRefEntry;
|
import nl.sander.beejava.constantpool.entry.MethodRefEntry;
|
||||||
import nl.sander.bejava.constantpool.entry.Utf8Entry;
|
import nl.sander.beejava.constantpool.entry.Utf8Entry;
|
||||||
import nl.sander.bejava.util.ByteBuf;
|
import nl.sander.beejava.util.ByteBuf;
|
||||||
|
|
||||||
public class MethodCodeAttributeCreator {
|
public class MethodCodeCreator {
|
||||||
|
|
||||||
public static CodeAttribute createCodeAttribute(Utf8Entry codeAttributeNameEntry, CodeContainer codeContainer) {
|
public static CodeAttribute createCodeAttribute(Utf8Entry codeAttributeNameEntry, CodeContainer codeContainer) {
|
||||||
var codeAttribute = new CodeAttribute(codeAttributeNameEntry);
|
CodeAttribute codeAttribute = new CodeAttribute(codeAttributeNameEntry);
|
||||||
codeAttribute.setMaxStack(calculateMaxStack(codeContainer));
|
codeAttribute.setMaxStack(calculateMaxStack(codeContainer));
|
||||||
codeAttribute.setMaxLocals(codeContainer.getFormalParameters().size() + 1);
|
codeAttribute.setMaxLocals(codeContainer.formalParameters.size() + 1);
|
||||||
var byteBuf = new ByteBuf();
|
ByteBuf byteBuf = new ByteBuf();
|
||||||
|
|
||||||
codeContainer.getExpandedCode().forEach(instruction -> {
|
codeContainer.getCode().forEach(codeLine -> {
|
||||||
var javaOpcode = instruction.getOpcode();
|
JavaOpcode javaOpcode = codeLine.getJavaOpcode(); // the opcode we determined in calculateMaxStack
|
||||||
byteBuf.addU8(javaOpcode.getByteCode());
|
byteBuf.addU8(javaOpcode.getByteCode());
|
||||||
var constantPoolEntry = instruction.getEntry();
|
ConstantPoolEntry constantPoolEntry = codeLine.getAssignedEntry();
|
||||||
if (constantPoolEntry != null) {
|
if (constantPoolEntry != null) {
|
||||||
if (javaOpcode.isWide()) {
|
if (javaOpcode.isWide()) {
|
||||||
byteBuf.addU16(constantPoolEntry.getIndex());
|
byteBuf.addU16(constantPoolEntry.getIndex());
|
||||||
|
|
@ -36,12 +36,14 @@ public class MethodCodeAttributeCreator {
|
||||||
private static int calculateMaxStack(CodeContainer codeContainer) {
|
private static int calculateMaxStack(CodeContainer codeContainer) {
|
||||||
int stackSize = 0;
|
int stackSize = 0;
|
||||||
int maxStackSize = 0;
|
int maxStackSize = 0;
|
||||||
for (var instruction : codeContainer.getExpandedCode()) {
|
for (CodeLine codeLine : codeContainer.getCode()) {
|
||||||
stackSize += instruction.getOpcode().getStackDif();
|
JavaOpcode javaOpcode = OpcodeMapper.mapOpcode(codeLine);
|
||||||
var assignedEntry = instruction.getEntry();
|
codeLine.setJavaOpcode(javaOpcode); //not really nice that we mutate codeLine, but this way we don't have to calculate the JavaOpcode twice
|
||||||
|
stackSize += javaOpcode.getStackDif();
|
||||||
|
ConstantPoolEntry assignedEntry = codeLine.getAssignedEntry();
|
||||||
if (assignedEntry instanceof MethodRefEntry) {
|
if (assignedEntry instanceof MethodRefEntry) {
|
||||||
var methodRefEntry = (MethodRefEntry) assignedEntry;
|
MethodRefEntry methodRefEntry = (MethodRefEntry) assignedEntry;
|
||||||
var argumentTypes = methodRefEntry.getNameAndType().getType();
|
String argumentTypes = methodRefEntry.getNameAndType().getType();
|
||||||
stackSize -= getNrArguments(argumentTypes);
|
stackSize -= getNrArguments(argumentTypes);
|
||||||
}
|
}
|
||||||
if (stackSize > maxStackSize) {
|
if (stackSize > maxStackSize) {
|
||||||
54
src/main/java/nl/sander/beejava/OpcodeMapper.java
Normal file
54
src/main/java/nl/sander/beejava/OpcodeMapper.java
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
package nl.sander.beejava;
|
||||||
|
|
||||||
|
import nl.sander.beejava.api.BeeSource;
|
||||||
|
import nl.sander.beejava.api.CodeLine;
|
||||||
|
import nl.sander.beejava.api.Opcode;
|
||||||
|
import nl.sander.beejava.flags.ClassAccessFlags;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
|
import static nl.sander.beejava.JavaOpcode.*;
|
||||||
|
|
||||||
|
public class OpcodeMapper {
|
||||||
|
|
||||||
|
public static JavaOpcode mapOpcode(CodeLine codeLine) {
|
||||||
|
Opcode opcode = codeLine.getOpcode();
|
||||||
|
return switch (opcode) {
|
||||||
|
case GET -> isStatic(codeLine.getExternalfield()) ? GETSTATIC : GETFIELD;
|
||||||
|
case LD_VAR -> ALOAD_0;
|
||||||
|
case LD_CONST -> loadConst(codeLine);
|
||||||
|
case INVOKE -> invoke(codeLine);
|
||||||
|
case RETURN -> JavaOpcode.RETURN; //TODO not complete yet
|
||||||
|
default -> throw new IllegalStateException("something not implemented");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO cover more cases */
|
||||||
|
private static JavaOpcode invoke(CodeLine codeLine) {
|
||||||
|
BeeSource source = codeLine.getOwner().getOwner();
|
||||||
|
if (source.getAccessFlags().contains(ClassAccessFlags.SUPER) && codeLine.getOwner().isConstructor()) {
|
||||||
|
return INVOKESPECIAL;
|
||||||
|
} else {
|
||||||
|
return INVOKEVIRTUAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JavaOpcode loadConst(CodeLine codeLine) {
|
||||||
|
Object constValue = codeLine.getConstValue();
|
||||||
|
int index = codeLine.getAssignedEntry().getIndex();
|
||||||
|
if (constValue instanceof Double || constValue instanceof Long) {
|
||||||
|
return LDC2_W;
|
||||||
|
} else {
|
||||||
|
if (index > 0xff) {
|
||||||
|
return LDC_W;
|
||||||
|
} else {
|
||||||
|
return LDC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isStatic(Field field) {
|
||||||
|
return (field.getModifiers() & Modifier.STATIC) == Modifier.STATIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/main/java/nl/sander/beejava/StackOp.java
Normal file
5
src/main/java/nl/sander/beejava/StackOp.java
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
package nl.sander.beejava;
|
||||||
|
|
||||||
|
public enum StackOp {
|
||||||
|
PUSH,POP
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava;
|
package nl.sander.beejava;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -16,7 +16,8 @@ public class TypeMapper {
|
||||||
MAP.put(long.class, "J");
|
MAP.put(long.class, "J");
|
||||||
MAP.put(short.class, "S");
|
MAP.put(short.class, "S");
|
||||||
MAP.put(boolean.class, "Z");
|
MAP.put(boolean.class, "Z");
|
||||||
MAP.put(void.class, "V");
|
MAP.put(Void.class, "V");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO something with arrays
|
//TODO something with arrays
|
||||||
89
src/main/java/nl/sander/beejava/api/BeeConstructor.java
Normal file
89
src/main/java/nl/sander/beejava/api/BeeConstructor.java
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
package nl.sander.beejava.api;
|
||||||
|
|
||||||
|
import nl.sander.beejava.CodeContainer;
|
||||||
|
import nl.sander.beejava.flags.MethodAccessFlags;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models a constructor
|
||||||
|
*/
|
||||||
|
public final class BeeConstructor extends CodeContainer {
|
||||||
|
|
||||||
|
private BeeConstructor(Set<MethodAccessFlags> accessFlags,
|
||||||
|
List<BeeParameter> formalParameters,
|
||||||
|
List<CodeLine> code) {
|
||||||
|
this.formalParameters.addAll(formalParameters);
|
||||||
|
this.accessFlags.addAll(accessFlags);
|
||||||
|
super.code.addAll(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return "<init>";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "BeeConstructor{" +
|
||||||
|
"formalParameters=" + formalParameters +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getReturnType() {
|
||||||
|
return Void.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConstructor() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
BeeConstructor that = (BeeConstructor) o;
|
||||||
|
return formalParameters.equals(that.formalParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(formalParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private final Set<MethodAccessFlags> accessFlags = new HashSet<>();
|
||||||
|
private final List<BeeParameter> formalParameters = new LinkedList<>();
|
||||||
|
private final List<CodeLine> code = new LinkedList<>();
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withFormalParameters(BeeParameter... formalParameters) {
|
||||||
|
this.formalParameters.addAll(Arrays.asList(formalParameters));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withAccessFlags(MethodAccessFlags... accessFlags) {
|
||||||
|
this.accessFlags.addAll(Arrays.asList(accessFlags));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withCode(CodeLine... lines) {
|
||||||
|
this.code.addAll(Arrays.asList(lines));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeConstructor build() {
|
||||||
|
BeeConstructor beeConstructor = new BeeConstructor(accessFlags, formalParameters, code);
|
||||||
|
code.forEach(line -> line.setOwner(beeConstructor));
|
||||||
|
return beeConstructor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/main/java/nl/sander/beejava/api/BeeField.java
Normal file
82
src/main/java/nl/sander/beejava/api/BeeField.java
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
package nl.sander.beejava.api;
|
||||||
|
|
||||||
|
import nl.sander.beejava.flags.FieldAccessFlags;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models a field in a BeeClass
|
||||||
|
*/
|
||||||
|
public final class BeeField {
|
||||||
|
|
||||||
|
private final Set<FieldAccessFlags> accessFlags = new HashSet<>();
|
||||||
|
private final Class<?> type;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private BeeField(Set<FieldAccessFlags> accessFlags, Class<?> type, String name) {
|
||||||
|
this.accessFlags.addAll(accessFlags);
|
||||||
|
this.type = type;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BeeField.Builder builder(){
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<FieldAccessFlags> getAccessFlags() {
|
||||||
|
return accessFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
BeeField beeField = (BeeField) o;
|
||||||
|
return name.equals(beeField.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private final Set<FieldAccessFlags> accessFlags = new HashSet<>();
|
||||||
|
private Class<?> type;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private Builder(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeField.Builder withAccessFlags(FieldAccessFlags... accessFlags) {
|
||||||
|
this.accessFlags.addAll(Arrays.asList(accessFlags));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeField.Builder withType(Class<?> type) {
|
||||||
|
this.type=type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeField.Builder withName(String name) {
|
||||||
|
this.name=name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeField build() {
|
||||||
|
return new BeeField(accessFlags, type, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/main/java/nl/sander/beejava/api/BeeMethod.java
Normal file
95
src/main/java/nl/sander/beejava/api/BeeMethod.java
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
package nl.sander.beejava.api;
|
||||||
|
|
||||||
|
import nl.sander.beejava.CodeContainer;
|
||||||
|
import nl.sander.beejava.TypeMapper;
|
||||||
|
import nl.sander.beejava.flags.MethodAccessFlags;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models a method in a BeeClass
|
||||||
|
*/
|
||||||
|
public final class BeeMethod extends CodeContainer {
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final Class<?> returnType;
|
||||||
|
|
||||||
|
private BeeMethod(String name, Set<MethodAccessFlags> accessFlags,
|
||||||
|
List<BeeParameter> formalParameters,
|
||||||
|
Class<?> returnType, List<CodeLine> code) {
|
||||||
|
this.name = name;
|
||||||
|
this.accessFlags.addAll(accessFlags);
|
||||||
|
this.formalParameters.addAll(formalParameters);
|
||||||
|
this.returnType = returnType;
|
||||||
|
super.code.addAll(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getReturnType() {
|
||||||
|
return returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConstructor() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validate() {
|
||||||
|
//TODO
|
||||||
|
/*
|
||||||
|
* here we could add checks like:
|
||||||
|
* -If this method is in a class rather than an interface, and the name of the method is <init>, then the descriptor must denote a void method.
|
||||||
|
* -If the name of the method is <clinit>, then the descriptor must denote avoid method, and, in a class file whose version number is 51.0 or above,a method that takes no arguments
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private final Set<MethodAccessFlags> accessFlags = new HashSet<>();
|
||||||
|
private final List<BeeParameter> formalParameters = new LinkedList<>();
|
||||||
|
private final List<CodeLine> code = new LinkedList<>();
|
||||||
|
private String name;
|
||||||
|
private Class<?> returnType = Void.class;
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withAccessFlags(MethodAccessFlags... accessFlags) {
|
||||||
|
this.accessFlags.addAll(Arrays.asList(accessFlags));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withFormalParameters(BeeParameter... formalParameters) {
|
||||||
|
this.formalParameters.addAll(Arrays.asList(formalParameters));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withReturnType(Class<?> returnType) {
|
||||||
|
this.returnType = returnType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withCode(CodeLine... lines) {
|
||||||
|
this.code.addAll(Arrays.asList(lines));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeMethod build() {
|
||||||
|
BeeMethod beeMethod = new BeeMethod(name, accessFlags, formalParameters, returnType, code);
|
||||||
|
code.forEach(line -> line.setOwner(beeMethod));
|
||||||
|
return beeMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/main/java/nl/sander/beejava/api/BeePackage.java
Normal file
17
src/main/java/nl/sander/beejava/api/BeePackage.java
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
package nl.sander.beejava.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the name of the package for a class
|
||||||
|
*/
|
||||||
|
public final class BeePackage {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
BeePackage(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,25 +1,21 @@
|
||||||
package nl.sander.bejava.api;
|
package nl.sander.beejava.api;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models a formal parameter in a method declaration.
|
* Models a formal parameter in a method declaration.
|
||||||
*/
|
*/
|
||||||
public final class BeParameter {
|
public final class BeeParameter {
|
||||||
private final Class<?> type;
|
private final Class<?> type;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final int index;
|
|
||||||
|
|
||||||
public BeParameter(Class<?> type, String name) {
|
private BeeParameter(Class<?> type, String name) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.index = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BeParameter(Class<?> type, String name, int index) {
|
public static BeeParameter create(Class<?> type, String name) {
|
||||||
this.type = type;
|
return new BeeParameter(type, Objects.requireNonNull(name));
|
||||||
this.name = name;
|
|
||||||
this.index = index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<?> getType() {
|
public Class<?> getType() {
|
||||||
|
|
@ -34,14 +30,10 @@ public final class BeParameter {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (BeParameter) o;
|
BeeParameter that = (BeeParameter) o;
|
||||||
return name.equals(that.name);
|
return name.equals(that.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getIndex() {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(name);
|
return Objects.hash(name);
|
||||||
190
src/main/java/nl/sander/beejava/api/BeeSource.java
Normal file
190
src/main/java/nl/sander/beejava/api/BeeSource.java
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
package nl.sander.beejava.api;
|
||||||
|
|
||||||
|
import nl.sander.beejava.flags.ClassAccessFlags;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains all information needed for compilation
|
||||||
|
*
|
||||||
|
* End users need to create an instance of this class (using the Builder) and add all fields, methods etc.
|
||||||
|
* Once created the BeeSource object is immutable.
|
||||||
|
*/
|
||||||
|
public final class BeeSource {
|
||||||
|
private final Version classFileVersion;
|
||||||
|
private final BeePackage beePackage;
|
||||||
|
private final Set<ClassAccessFlags> accessFlags = new HashSet<>();
|
||||||
|
private final String simpleName;
|
||||||
|
private final Class<?> superClass;
|
||||||
|
private final Set<Class<?>> interfaces = new HashSet<>();
|
||||||
|
private final Set<BeeField> fields = new HashSet<>();
|
||||||
|
private final Set<BeeConstructor> constructors = new HashSet<>();
|
||||||
|
private final Set<BeeMethod> methods = new HashSet<>();
|
||||||
|
|
||||||
|
private BeeSource(Version classFileVersion,
|
||||||
|
BeePackage beePackage, Set<ClassAccessFlags> accessFlags, String simpleName, Class<?> superClass,
|
||||||
|
Set<Class<?>> interfaces, Set<BeeField> fields, Set<BeeConstructor> constructors, Set<BeeMethod> methods) {
|
||||||
|
this.classFileVersion = classFileVersion;
|
||||||
|
this.beePackage = beePackage;
|
||||||
|
this.accessFlags.addAll(accessFlags);
|
||||||
|
this.simpleName = simpleName;
|
||||||
|
this.superClass = superClass;
|
||||||
|
this.interfaces.addAll(interfaces);
|
||||||
|
this.fields.addAll(fields);
|
||||||
|
this.constructors.addAll(constructors);
|
||||||
|
this.methods.addAll(methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new BeeSource Builder class.
|
||||||
|
*
|
||||||
|
* @return a new instance of a Builder
|
||||||
|
*/
|
||||||
|
public static BeeSource.Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The classfile version
|
||||||
|
*/
|
||||||
|
public Version getClassFileVersion() {
|
||||||
|
return classFileVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The package in which the compiled class will reside.
|
||||||
|
*/
|
||||||
|
public BeePackage getPackage() {
|
||||||
|
return beePackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the unqualified name, like java.lang.Class
|
||||||
|
*/
|
||||||
|
public String getSimpleName() {
|
||||||
|
return simpleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return all constructors that are provided with the class
|
||||||
|
*/
|
||||||
|
public Set<BeeConstructor> getConstructors() {
|
||||||
|
return Collections.unmodifiableSet(constructors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return all methods that are provided with the class
|
||||||
|
*/
|
||||||
|
public Set<BeeMethod> getMethods() {
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The access flags for the class
|
||||||
|
*/
|
||||||
|
public Set<ClassAccessFlags> getAccessFlags() {
|
||||||
|
return Collections.unmodifiableSet(accessFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The full name, like java.lang.Class
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return beePackage.getName() + "." + simpleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The superclass
|
||||||
|
*/
|
||||||
|
public Class<?> getSuperClass() {
|
||||||
|
return superClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a list of unique interfaces that the class will implements
|
||||||
|
*/
|
||||||
|
public Set<Class<?>> getInterfaces() {
|
||||||
|
return Collections.unmodifiableSet(interfaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a list of unique fields that the class will contain
|
||||||
|
*/
|
||||||
|
public Set<BeeField> getFields() {
|
||||||
|
return Collections.unmodifiableSet(fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for creating BeeSource classes
|
||||||
|
*/
|
||||||
|
public static class Builder {
|
||||||
|
private final Set<ClassAccessFlags> accessFlags = new HashSet<>();
|
||||||
|
private final Set<Class<?>> interfaces = new HashSet<>();
|
||||||
|
private final Set<BeeField> fields = new HashSet<>();
|
||||||
|
private Version version;
|
||||||
|
private BeePackage beePackage;
|
||||||
|
private Class<?> superClass = Object.class;
|
||||||
|
private String simpleName;
|
||||||
|
private final Set<BeeConstructor> constructors = new HashSet<>();
|
||||||
|
private final Set<BeeMethod> methods = new HashSet<>();
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withClassFileVersion(Version version) {
|
||||||
|
this.version = version;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeSource.Builder withPackage(String beePackage) {
|
||||||
|
this.beePackage = new BeePackage(beePackage);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeSource.Builder withAccessFlags(ClassAccessFlags... accessFlags) {
|
||||||
|
this.accessFlags.addAll(Arrays.asList(accessFlags));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeSource.Builder withSimpleName(String simpleName) {
|
||||||
|
this.simpleName = simpleName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withSuperClass(Class<?> superClass) {
|
||||||
|
this.superClass = superClass;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withInterfaces(Class<?>... interfaces) {
|
||||||
|
this.interfaces.addAll(Arrays.asList(interfaces));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withFields(BeeField... fields) {
|
||||||
|
this.fields.addAll(Arrays.asList(fields));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withConstructors(BeeConstructor... constructors) {
|
||||||
|
this.constructors.addAll(Arrays.asList(constructors));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withMethods(BeeMethod... methods) {
|
||||||
|
this.methods.addAll(Arrays.asList(methods));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeSource build() {
|
||||||
|
BeeSource beeSource = new BeeSource(version, beePackage, accessFlags, simpleName, superClass, interfaces, fields, constructors, methods);
|
||||||
|
constructors.forEach(c -> c.setOwner(beeSource));
|
||||||
|
methods.forEach(m -> m.setOwner(beeSource));
|
||||||
|
return beeSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
252
src/main/java/nl/sander/beejava/api/CodeLine.java
Normal file
252
src/main/java/nl/sander/beejava/api/CodeLine.java
Normal file
|
|
@ -0,0 +1,252 @@
|
||||||
|
package nl.sander.beejava.api;
|
||||||
|
|
||||||
|
|
||||||
|
import nl.sander.beejava.CodeContainer;
|
||||||
|
import nl.sander.beejava.JavaOpcode;
|
||||||
|
import nl.sander.beejava.TypeMapper;
|
||||||
|
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public final class CodeLine {
|
||||||
|
private final int linenumber;
|
||||||
|
private final Opcode opcode;
|
||||||
|
private Ref ref;
|
||||||
|
private BeeParameter parameter;
|
||||||
|
private Class<?> type;
|
||||||
|
private String methodName;
|
||||||
|
private List<Class<?>> inputSignature;
|
||||||
|
private String outputSignature;
|
||||||
|
private BeeField ownfield; // when you create a class with a field, you can refer to it
|
||||||
|
private Field externalfield; // when you refer to a field from another class
|
||||||
|
private Object constValue;
|
||||||
|
private ConstantPoolEntry assignedEntry;
|
||||||
|
private CodeContainer owner;
|
||||||
|
private JavaOpcode javaOpcode;
|
||||||
|
|
||||||
|
CodeLine(int linenumber, Opcode opcode) {
|
||||||
|
this.linenumber = linenumber;
|
||||||
|
this.opcode = opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodeLine line(int nr, Opcode opcode, Ref ref) {
|
||||||
|
return new CodeLine(nr, opcode).withRef(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodeLine line(int nr, Opcode opcode, String fieldClass, String fieldName) {
|
||||||
|
return new CodeLine(nr, opcode).withExternalFieldRef(fieldClass, fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodeLine line(int nr, Opcode opcode, Object constValue) {
|
||||||
|
return new CodeLine(nr, opcode).withConstValue(constValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodeLine line(int nr, Opcode opcode, String className, String methodName, String inputSignature) throws ClassNotFoundException {
|
||||||
|
return new CodeLine(nr, opcode).withClassName(className).withMethodName(methodName).withInput(parse(inputSignature)).withVoidOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Class<?>> parse(String inputSignature) throws ClassNotFoundException {
|
||||||
|
if ("()".equals(inputSignature)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
} else {
|
||||||
|
String[] params = inputSignature.split(",");
|
||||||
|
List<Class<?>> paramClasses = new ArrayList<>();
|
||||||
|
for (String param : params) {
|
||||||
|
paramClasses.add(Class.forName(param));
|
||||||
|
}
|
||||||
|
return paramClasses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodeLine line(int nr, Opcode opcode,
|
||||||
|
Ref ref, String methodNameRef, String inputSignature) throws ClassNotFoundException {
|
||||||
|
return new CodeLine(nr, opcode).withRef(ref).withMethodName(methodNameRef).withInput(parse(inputSignature)).withVoidOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodeLine line(int nr, Opcode opcode,
|
||||||
|
Ref ref, String methodNameRef, String inputSignature, String outputSignature) throws ClassNotFoundException {
|
||||||
|
return new CodeLine(nr, opcode).withRef(ref).withMethodName(methodNameRef).withInput(parse(inputSignature)).withOutput(outputSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodeLine line(int nr, Opcode opcode) {
|
||||||
|
return new CodeLine(nr, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodeLine line(int nr, Opcode opcode, BeeParameter parameter) {
|
||||||
|
return new CodeLine(nr, opcode).withParameter(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodeLine line(int nr, Opcode opcode, BeeField intField) {
|
||||||
|
return new CodeLine(nr, opcode).withRef(Ref.THIS).withOwnField(intField);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeLine withRef(Ref ref) {
|
||||||
|
this.ref = ref;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeLine withClassName(String className) {
|
||||||
|
this.type = loadClass(className);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeLine withMethodName(String methodName) {
|
||||||
|
this.methodName = methodName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeLine withInput(List<Class<?>> inputSignature) {
|
||||||
|
this.inputSignature = inputSignature;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeLine withVoidOutput() {
|
||||||
|
return withOutput("V");
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeLine withOutput(String outputSignature) {
|
||||||
|
this.outputSignature = outputSignature;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeLine withParameter(BeeParameter parameter) {
|
||||||
|
this.parameter = parameter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeLine withConstValue(Object constValue) {
|
||||||
|
this.constValue = constValue;
|
||||||
|
return this; //TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeLine withOwnField(BeeField beeField) {
|
||||||
|
this.ownfield = beeField;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeLine withExternalFieldRef(String className, String field) {
|
||||||
|
this.type = loadClass(className);
|
||||||
|
this.externalfield = loadField(field);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO decide whether to work with Strings or class objects...
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up the type of a field in a class
|
||||||
|
*
|
||||||
|
* Assumes field is accessible
|
||||||
|
*
|
||||||
|
* @param className the class containing a field
|
||||||
|
* @param field name of the field
|
||||||
|
* @return the field type
|
||||||
|
*/
|
||||||
|
private Field loadField(String field) {
|
||||||
|
try {
|
||||||
|
return type.getField(field);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasClassName() {
|
||||||
|
return type != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getClassName() {
|
||||||
|
return type.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMethodName() {
|
||||||
|
return methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasMethodCall() {
|
||||||
|
return methodName != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMethodSignature() {
|
||||||
|
return inputSignature.stream()
|
||||||
|
.map(TypeMapper::map)
|
||||||
|
.collect(Collectors.joining(",", "(", ")")) + outputSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ref getRef() {
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasRef() {
|
||||||
|
return ref != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasRefToOwnField() {
|
||||||
|
return ownfield != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Object getConstValue() {
|
||||||
|
return constValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasConstValue() {
|
||||||
|
return constValue != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeField getOwnfield() {
|
||||||
|
return ownfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeeParameter getParameter() {
|
||||||
|
return parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean hasRefToExternalField() {
|
||||||
|
return externalfield != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Field getExternalfield() {
|
||||||
|
return externalfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstantPoolEntry getAssignedEntry() {
|
||||||
|
return assignedEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssignedEntry(ConstantPoolEntry assignedEntry) {
|
||||||
|
this.assignedEntry = assignedEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Opcode getOpcode() {
|
||||||
|
return opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<?> loadClass(String className) {
|
||||||
|
try {
|
||||||
|
return Class.forName(className);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new RuntimeException(e); //TODO specific exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CodeContainer getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOwner(CodeContainer codeContainer) {
|
||||||
|
this.owner = codeContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaOpcode getJavaOpcode() {
|
||||||
|
return javaOpcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJavaOpcode(JavaOpcode javaOpcode) {
|
||||||
|
this.javaOpcode = javaOpcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
71
src/main/java/nl/sander/beejava/api/Opcode.java
Normal file
71
src/main/java/nl/sander/beejava/api/Opcode.java
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
package nl.sander.beejava.api;
|
||||||
|
|
||||||
|
public enum Opcode {
|
||||||
|
LD_VAR("ld_var"),
|
||||||
|
LD_CONST("ld_const"),
|
||||||
|
LD_FIELD("ld_field"),
|
||||||
|
STORE("store"),
|
||||||
|
CONST("const"),
|
||||||
|
NEWARRAY("new"),
|
||||||
|
RETURN("return"),
|
||||||
|
ARRAYLENGTH("length"),
|
||||||
|
THROW("throw"),
|
||||||
|
PUSH("push"),
|
||||||
|
CHECKCAST("checkcast"),
|
||||||
|
ADD("add"),
|
||||||
|
COMPARE("cmp"),
|
||||||
|
DIVIDE("div"),
|
||||||
|
MULTIPLY("mul"),
|
||||||
|
NEGATE("neg"),
|
||||||
|
REMAINDER("rem"),
|
||||||
|
SUBTRACT("sub"),
|
||||||
|
DUPLICATE("dup"),
|
||||||
|
DUPLICATE_DOWN("dup_x1"),
|
||||||
|
DUPLICATE2("dup2"),
|
||||||
|
DUPLICATE2_DOWN("dup2_x1"),
|
||||||
|
GET("get"),
|
||||||
|
GOTO("goto"),
|
||||||
|
GOTO_W("goto_w"),
|
||||||
|
TO_DOUBLE("2d"),
|
||||||
|
TO_INT("2i"),
|
||||||
|
TO_LONG("2l"),
|
||||||
|
TO_BYTE("2b"),
|
||||||
|
TO_CHAR("2c"),
|
||||||
|
TO_FLOAT("2f"),
|
||||||
|
TO_SHORT("2s"),
|
||||||
|
AND("and"),
|
||||||
|
IF_EQUAL("ifeq"),
|
||||||
|
IF_NOT_EQUAL("ifneq"),
|
||||||
|
IF_LESS_THAN("iflt"),
|
||||||
|
IF_GREATER_OR_EQUAL("ifge"),
|
||||||
|
IF_GREATER_THAN("ifgt"),
|
||||||
|
IF_LESS_OR_EQUAL("ifle"),
|
||||||
|
IF_NOT_NULL("ifnotnull"),
|
||||||
|
IF_NULL("ifnull"),
|
||||||
|
INCREMENT("inc"),
|
||||||
|
INSTANCEOF("instanceof"),
|
||||||
|
INVOKE("invoke"),
|
||||||
|
OR("or"),
|
||||||
|
SHIFT_LEFT("shr"),
|
||||||
|
SHIFT_RIGHT("shl"),
|
||||||
|
LOGICAL_SHIFT_RIGHT("ushr"),
|
||||||
|
XOR("xor"),
|
||||||
|
LOOKUPSWITCH("lookupswitch"),
|
||||||
|
MONITORENTER("monitorenter"),
|
||||||
|
MONITOREXIT("monitorexit"),
|
||||||
|
MULTIANEWARRAY("multinewarray"),
|
||||||
|
NEW("new"),
|
||||||
|
NOP("nop"),
|
||||||
|
POP("pop"),
|
||||||
|
POP2("pop2"),
|
||||||
|
PUT("put"),
|
||||||
|
SWAP("swap"),
|
||||||
|
TABLESWITCH("tableswitch"),
|
||||||
|
WIDE("wide");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
Opcode(String name) {
|
||||||
|
this.name=name;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/main/java/nl/sander/beejava/api/Ref.java
Normal file
9
src/main/java/nl/sander/beejava/api/Ref.java
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
package nl.sander.beejava.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used to indicate this, super, or none of those, in which case it's class
|
||||||
|
*/
|
||||||
|
public enum Ref {
|
||||||
|
THIS,
|
||||||
|
SUPER
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
package nl.sander.bejava.api;
|
package nl.sander.beejava.api;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public enum Version {
|
public enum Version {
|
||||||
V1_0_2(45),
|
V1_0_2(45),
|
||||||
|
|
@ -33,13 +31,4 @@ public enum Version {
|
||||||
public int getMinor(){
|
public int getMinor(){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<Version> get(String text){
|
|
||||||
for (Version version : Version.values()) {
|
|
||||||
if (version.toString().equals(text)) {
|
|
||||||
return Optional.of(version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,29 +1,29 @@
|
||||||
package nl.sander.bejava.classinfo;
|
package nl.sander.beejava.classinfo;
|
||||||
|
|
||||||
import nl.sander.bejava.constantpool.entry.Utf8Entry;
|
import nl.sander.beejava.constantpool.entry.Utf8Entry;
|
||||||
import nl.sander.bejava.flags.AccessFlags;
|
import nl.sander.beejava.flags.AccessFlags;
|
||||||
import nl.sander.bejava.flags.FieldAccessFlag;
|
import nl.sander.beejava.flags.FieldAccessFlags;
|
||||||
import nl.sander.bejava.util.ByteBuf;
|
import nl.sander.beejava.util.ByteBuf;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
|
||||||
* Conforms to field_info struct in JVM specification
|
|
||||||
* See 4.1 The ClassFile Structure
|
|
||||||
*/
|
|
||||||
public class FieldInfo extends Info<FieldInfo> {
|
public class FieldInfo extends Info<FieldInfo> {
|
||||||
private final Set<FieldAccessFlag> accessFlags = new HashSet<>();
|
private final Set<FieldAccessFlags> accessFlags = new HashSet<>();
|
||||||
|
|
||||||
public FieldInfo(Utf8Entry nameEntry, Utf8Entry descriptorEntry) {
|
public FieldInfo(Utf8Entry nameEntry, Utf8Entry descriptorEntry) {
|
||||||
super(nameEntry, descriptorEntry);
|
super(nameEntry, descriptorEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldInfo addAccessFlags(Set<FieldAccessFlag> accessFlags) {
|
public FieldInfo addAccessFlags(Set<FieldAccessFlags> accessFlags) {
|
||||||
this.accessFlags.addAll(accessFlags);
|
this.accessFlags.addAll(accessFlags);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<FieldAccessFlags> getAccessFlags() {
|
||||||
|
return accessFlags;
|
||||||
|
}
|
||||||
|
|
||||||
public void addBytes(ByteBuf buf) {
|
public void addBytes(ByteBuf buf) {
|
||||||
buf.addU16(AccessFlags.combine(accessFlags));
|
buf.addU16(AccessFlags.combine(accessFlags));
|
||||||
buf.addU16(nameEntry.getIndex());
|
buf.addU16(nameEntry.getIndex());
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
package nl.sander.bejava.classinfo;
|
package nl.sander.beejava.classinfo;
|
||||||
|
|
||||||
import nl.sander.bejava.classinfo.attributes.Attribute;
|
import nl.sander.beejava.classinfo.attributes.Attribute;
|
||||||
import nl.sander.bejava.constantpool.entry.Utf8Entry;
|
import nl.sander.beejava.constantpool.entry.Utf8Entry;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public abstract class Info<T extends Info<T>> {
|
public abstract class Info<T extends Info> {
|
||||||
|
|
||||||
protected final Utf8Entry nameEntry;
|
protected final Utf8Entry nameEntry;
|
||||||
protected final Utf8Entry descriptorEntry;
|
protected final Utf8Entry descriptorEntry;
|
||||||
|
|
@ -17,6 +17,14 @@ public abstract class Info<T extends Info<T>> {
|
||||||
this.descriptorEntry = descriptorEntry;
|
this.descriptorEntry = descriptorEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Utf8Entry getNameEntry() {
|
||||||
|
return nameEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Utf8Entry getDescriptorEntry() {
|
||||||
|
return descriptorEntry;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<Attribute> getAttributes() {
|
public Set<Attribute> getAttributes() {
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
@ -1,24 +1,20 @@
|
||||||
package nl.sander.bejava.classinfo;
|
package nl.sander.beejava.classinfo;
|
||||||
|
|
||||||
import nl.sander.bejava.constantpool.entry.Utf8Entry;
|
import nl.sander.beejava.constantpool.entry.Utf8Entry;
|
||||||
import nl.sander.bejava.flags.AccessFlags;
|
import nl.sander.beejava.flags.AccessFlags;
|
||||||
import nl.sander.bejava.flags.MethodAccessFlag;
|
import nl.sander.beejava.flags.MethodAccessFlags;
|
||||||
import nl.sander.bejava.util.ByteBuf;
|
import nl.sander.beejava.util.ByteBuf;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
|
||||||
* Conforms to method_info struct in JVM specification
|
|
||||||
* See 4.1 The ClassFile Structure
|
|
||||||
*/
|
|
||||||
public class MethodInfo extends Info<MethodInfo> {
|
public class MethodInfo extends Info<MethodInfo> {
|
||||||
private final Set<MethodAccessFlag> accessFlags = new HashSet<>();
|
private final Set<MethodAccessFlags> accessFlags = new HashSet<>();
|
||||||
|
|
||||||
public MethodInfo(Utf8Entry nameEntry, Utf8Entry descriptorEntry) {
|
public MethodInfo(Utf8Entry nameEntry, Utf8Entry descriptorEntry) {
|
||||||
super(nameEntry, descriptorEntry);
|
super(nameEntry, descriptorEntry);
|
||||||
}
|
}
|
||||||
public MethodInfo addAccessFlags(Set<MethodAccessFlag> accessFlags) {
|
public MethodInfo addAccessFlags(Set<MethodAccessFlags> accessFlags) {
|
||||||
this.accessFlags.addAll(accessFlags);
|
this.accessFlags.addAll(accessFlags);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
package nl.sander.bejava.classinfo.attributes;
|
package nl.sander.beejava.classinfo.attributes;
|
||||||
|
|
||||||
import nl.sander.bejava.constantpool.entry.Utf8Entry;
|
import nl.sander.beejava.constantpool.entry.Utf8Entry;
|
||||||
import nl.sander.bejava.util.ByteBuf;
|
import nl.sander.beejava.util.ByteBuf;
|
||||||
|
|
||||||
/**
|
|
||||||
* attribute_info struct as in the JVM spec.
|
|
||||||
* See 4.1 The ClassFile Structure.
|
|
||||||
*/
|
|
||||||
public abstract class Attribute {
|
public abstract class Attribute {
|
||||||
protected final Utf8Entry nameEntry;
|
protected final Utf8Entry nameEntry;
|
||||||
protected int length;
|
protected int length;
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package nl.sander.bejava.classinfo.attributes;
|
package nl.sander.beejava.classinfo.attributes;
|
||||||
|
|
||||||
import nl.sander.bejava.constantpool.entry.Utf8Entry;
|
import nl.sander.beejava.constantpool.entry.Utf8Entry;
|
||||||
import nl.sander.bejava.util.ByteBuf;
|
import nl.sander.beejava.util.ByteBuf;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
@ -19,7 +19,7 @@ public class CodeAttribute extends Attribute {
|
||||||
private static final int EXCEPTION_HANDLER_SIZE = 8; // nr of bytes per exception_hander
|
private static final int EXCEPTION_HANDLER_SIZE = 8; // nr of bytes per exception_hander
|
||||||
|
|
||||||
private final Set<Attribute> attributes = new HashSet<>();
|
private final Set<Attribute> attributes = new HashSet<>();
|
||||||
private final Set<ExceptionHandler> exceptionHandlers = new HashSet<>(); //TODO exception handlers are yet to be implemented
|
private final Set<ExceptionHandler> exceptionHandlers = new HashSet<>();
|
||||||
private int maxStack; // u2
|
private int maxStack; // u2
|
||||||
private int maxLocals; // u2
|
private int maxLocals; // u2
|
||||||
private byte[] code;
|
private byte[] code;
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
package nl.sander.bejava.classinfo.attributes;
|
package nl.sander.beejava.classinfo.attributes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* see §4.7.3 The code attribute
|
* see §4.7.3 The code attribute
|
||||||
* TODO implement exception handlers
|
|
||||||
*/
|
*/
|
||||||
public class ExceptionHandler {
|
public class ExceptionHandler {
|
||||||
private int startPc; //u2
|
private int startPc; //u2
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package nl.sander.bejava.constantpool;
|
package nl.sander.beejava.constantpool;
|
||||||
|
|
||||||
import nl.sander.bejava.constantpool.entry.ConstantPoolEntry;
|
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||||
import nl.sander.bejava.util.ByteBuf;
|
import nl.sander.beejava.util.ByteBuf;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ public class ClassEntry extends ConstantPoolEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (ClassEntry) o;
|
ClassEntry that = (ClassEntry) o;
|
||||||
return name.equals(that.name);
|
return name.equals(that.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
|
@ -29,19 +29,10 @@ public abstract class ConstantPoolEntry {
|
||||||
return getBytes()[0];
|
return getBytes()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The output of this ends up in the class file as the constantpool index of the entry.
|
|
||||||
*
|
|
||||||
* @return the cp index of the entry.
|
|
||||||
*/
|
|
||||||
public int getIndex() {
|
public int getIndex() {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* With this the ConstantPoolCreator sets the calculated index.
|
|
||||||
* @param index the cp index to assign to the entry
|
|
||||||
*/
|
|
||||||
public void setIndex(int index) {
|
public void setIndex(int index) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
@ -70,20 +61,8 @@ public abstract class ConstantPoolEntry {
|
||||||
return (byte) (u16 >>> 8);
|
return (byte) (u16 >>> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected byte getByte(long bits, int positions) {
|
||||||
* get the Nth byte in an "array" of bits encoded in a long (i64). Used to create the stream representation of 64bit numbers
|
return (byte) ((bits >>> (positions * 8)) & 0xFF);
|
||||||
*
|
|
||||||
* @param bits a long in which a long or a double is encoded.
|
|
||||||
* @param position the index of the byte (0..7) in the array of bits
|
|
||||||
* @return the Nth byte in the long
|
|
||||||
*/
|
|
||||||
protected byte getByte(long bits, int position) {
|
|
||||||
if (position > 0 && position < 8) {
|
|
||||||
return (byte) ((bits >>> (position * 8)) & 0xFF);
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("position must be 0..7");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ public class DoubleEntry extends LeafEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (DoubleEntry) o;
|
DoubleEntry that = (DoubleEntry) o;
|
||||||
return Double.compare(that.doubleVal, doubleVal) == 0;
|
return Double.compare(that.doubleVal, doubleVal) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class DynamicEntry extends ConstantPoolEntry {
|
public class DynamicEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 17;
|
private static final byte TAG = 17;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ public class FieldRefEntry extends ConstantPoolEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (FieldRefEntry) o;
|
FieldRefEntry that = (FieldRefEntry) o;
|
||||||
return classEntry.equals(that.classEntry) &&
|
return classEntry.equals(that.classEntry) &&
|
||||||
nameAndTypeEntry.equals(that.nameAndTypeEntry);
|
nameAndTypeEntry.equals(that.nameAndTypeEntry);
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -7,24 +7,20 @@ public class FloatEntry extends LeafEntry {
|
||||||
|
|
||||||
private final float floatVal;
|
private final float floatVal;
|
||||||
|
|
||||||
public FloatEntry(String floatVal) {
|
|
||||||
this.floatVal = Float.parseFloat(floatVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FloatEntry(float floatVal) {
|
public FloatEntry(float floatVal) {
|
||||||
this.floatVal = floatVal;
|
this.floatVal = floatVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Float\t\t" + floatVal;
|
return "Float\t\t" +floatVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (FloatEntry) o;
|
FloatEntry that = (FloatEntry) o;
|
||||||
return Float.compare(that.floatVal, floatVal) == 0;
|
return Float.compare(that.floatVal, floatVal) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -7,12 +7,8 @@ public class IntegerEntry extends LeafEntry {
|
||||||
|
|
||||||
private final int intVal;
|
private final int intVal;
|
||||||
|
|
||||||
public IntegerEntry(String integerVal) {
|
public IntegerEntry(int integer) {
|
||||||
this.intVal = Integer.parseInt(integerVal);
|
this.intVal = integer;
|
||||||
}
|
|
||||||
|
|
||||||
public IntegerEntry(int integerVal) {
|
|
||||||
this.intVal = integerVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -29,7 +25,7 @@ public class IntegerEntry extends LeafEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (IntegerEntry) o;
|
IntegerEntry that = (IntegerEntry) o;
|
||||||
return intVal == that.intVal;
|
return intVal == that.intVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -32,7 +32,7 @@ public class InterfaceMethodRefEntry extends ConstantPoolEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (InterfaceMethodRefEntry) o;
|
InterfaceMethodRefEntry that = (InterfaceMethodRefEntry) o;
|
||||||
return classEntry.equals(that.classEntry) &&
|
return classEntry.equals(that.classEntry) &&
|
||||||
nameAndTypeEntry.equals(that.nameAndTypeEntry);
|
nameAndTypeEntry.equals(that.nameAndTypeEntry);
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class InvokeDynamicEntry extends ConstantPoolEntry {
|
public class InvokeDynamicEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 18;
|
private static final byte TAG = 18;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -27,7 +27,7 @@ public class LongEntry extends LeafEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var longEntry = (LongEntry) o;
|
LongEntry longEntry = (LongEntry) o;
|
||||||
return longVal == longEntry.longVal;
|
return longVal == longEntry.longVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
//TODO implement later
|
//TODO implement later
|
||||||
public class MethodHandleEntry extends ConstantPoolEntry {
|
public class MethodHandleEntry extends ConstantPoolEntry {
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ public class MethodRefEntry extends ConstantPoolEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (MethodRefEntry) o;
|
MethodRefEntry that = (MethodRefEntry) o;
|
||||||
return classRef.equals(that.classRef) &&
|
return classRef.equals(that.classRef) &&
|
||||||
nameAndType.equals(that.nameAndType);
|
nameAndType.equals(that.nameAndType);
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ public class MethodTypeEntry extends ConstantPoolEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (MethodTypeEntry) o;
|
MethodTypeEntry that = (MethodTypeEntry) o;
|
||||||
return methodDescriptor.equals(that.methodDescriptor);
|
return methodDescriptor.equals(that.methodDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ public class ModuleEntry extends ConstantPoolEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (ModuleEntry) o;
|
ModuleEntry that = (ModuleEntry) o;
|
||||||
return nameEntry.equals(that.nameEntry);
|
return nameEntry.equals(that.nameEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ public final class NameAndTypeEntry extends ConstantPoolEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (NameAndTypeEntry) o;
|
NameAndTypeEntry that = (NameAndTypeEntry) o;
|
||||||
return name.equals(that.name) &&
|
return name.equals(that.name) &&
|
||||||
descriptor.equals(that.descriptor);
|
descriptor.equals(that.descriptor);
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -23,7 +23,7 @@ public final class PackageEntry extends ConstantPoolEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (PackageEntry) o;
|
PackageEntry that = (PackageEntry) o;
|
||||||
return nameEntry.equals(that.nameEntry);
|
return nameEntry.equals(that.nameEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -23,7 +23,7 @@ public final class StringEntry extends ConstantPoolEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var that = (StringEntry) o;
|
StringEntry that = (StringEntry) o;
|
||||||
return utf8Entry.equals(that.utf8Entry);
|
return utf8Entry.equals(that.utf8Entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
@ -16,8 +16,8 @@ public final class Utf8Entry extends LeafEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getBytes() {
|
public byte[] getBytes() {
|
||||||
var utf8Bytes = value.getBytes(StandardCharsets.UTF_8);
|
byte[] utf8Bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||||
var bytes = new byte[utf8Bytes.length + 3];
|
byte[] bytes = new byte[utf8Bytes.length + 3];
|
||||||
bytes[0] = TAG;
|
bytes[0] = TAG;
|
||||||
bytes[1] = upperByte(utf8Bytes.length);
|
bytes[1] = upperByte(utf8Bytes.length);
|
||||||
bytes[2] = lowerByte(utf8Bytes.length);
|
bytes[2] = lowerByte(utf8Bytes.length);
|
||||||
|
|
@ -29,7 +29,7 @@ public final class Utf8Entry extends LeafEntry {
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
var utf8Entry = (Utf8Entry) o;
|
Utf8Entry utf8Entry = (Utf8Entry) o;
|
||||||
return value.equals(utf8Entry.value);
|
return value.equals(utf8Entry.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.flags;
|
package nl.sander.beejava.flags;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
@ -9,5 +9,4 @@ public interface AccessFlags {
|
||||||
|
|
||||||
int getBytecode();
|
int getBytecode();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.flags;
|
package nl.sander.beejava.flags;
|
||||||
|
|
||||||
public enum ClassAccessFlags implements AccessFlags {
|
public enum ClassAccessFlags implements AccessFlags {
|
||||||
PUBLIC(0x0001), // Declared public; may be accessed from outside its package.
|
PUBLIC(0x0001), // Declared public; may be accessed from outside its package.
|
||||||
|
|
@ -11,15 +11,17 @@ public enum ClassAccessFlags implements AccessFlags {
|
||||||
ENUM(0x4000), // Declared as an enum type.
|
ENUM(0x4000), // Declared as an enum type.
|
||||||
MODULE(0x8000); // Is a module, not a class or interface.
|
MODULE(0x8000); // Is a module, not a class or interface.
|
||||||
|
|
||||||
|
|
||||||
private final int bytecode;
|
private final int bytecode;
|
||||||
|
|
||||||
ClassAccessFlags(int bytecode) {
|
ClassAccessFlags(int bytecode) {
|
||||||
this.bytecode = bytecode;
|
this.bytecode = bytecode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBytecode() {
|
public int getBytecode() {
|
||||||
return bytecode;
|
return bytecode;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package nl.sander.bejava.flags;
|
package nl.sander.beejava.flags;
|
||||||
|
|
||||||
import java.util.Optional;
|
public enum FieldAccessFlags implements AccessFlags {
|
||||||
|
|
||||||
public enum FieldAccessFlag implements AccessFlags {
|
|
||||||
PUBLIC(0x0001), // Declared public; may be accessed from outside itspackage.
|
PUBLIC(0x0001), // Declared public; may be accessed from outside itspackage.
|
||||||
PRIVATE(0x0002), // Declared private; accessible only within the defining class and other classes belonging to the samenest (§5.4.4).
|
PRIVATE(0x0002), // Declared private; accessible only within the defining class and other classes belonging to the samenest (§5.4.4).
|
||||||
PROTECTED(0x0004), // Declared protected; may be accessed within subclasses.
|
PROTECTED(0x0004), // Declared protected; may be accessed within subclasses.
|
||||||
|
|
@ -15,20 +13,11 @@ public enum FieldAccessFlag implements AccessFlags {
|
||||||
|
|
||||||
private final int bytecode;
|
private final int bytecode;
|
||||||
|
|
||||||
FieldAccessFlag(int bytecode) {
|
FieldAccessFlags(int bytecode) {
|
||||||
this.bytecode = bytecode;
|
this.bytecode = bytecode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBytecode() {
|
public int getBytecode() {
|
||||||
return bytecode;
|
return bytecode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<FieldAccessFlag> get(String text) {
|
|
||||||
for (FieldAccessFlag flag : FieldAccessFlag.values()) {
|
|
||||||
if (flag.toString().equals(text)) {
|
|
||||||
return Optional.of(flag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package nl.sander.bejava.flags;
|
package nl.sander.beejava.flags;
|
||||||
|
|
||||||
import java.util.Optional;
|
public enum MethodAccessFlags implements AccessFlags {
|
||||||
|
|
||||||
public enum MethodAccessFlag implements AccessFlags {
|
|
||||||
PUBLIC(0x0001), // Declared public; may be accessed from outside its package.
|
PUBLIC(0x0001), // Declared public; may be accessed from outside its package.
|
||||||
PRIVATE(0x0002), // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4).
|
PRIVATE(0x0002), // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4).
|
||||||
PROTECTED(0x0004), // Declared protected; may be accessed within subclasses.
|
PROTECTED(0x0004), // Declared protected; may be accessed within subclasses.
|
||||||
|
|
@ -18,20 +16,11 @@ public enum MethodAccessFlag implements AccessFlags {
|
||||||
|
|
||||||
private final int bytecode;
|
private final int bytecode;
|
||||||
|
|
||||||
MethodAccessFlag(int bytecode) {
|
MethodAccessFlags(int bytecode) {
|
||||||
this.bytecode = bytecode;
|
this.bytecode = bytecode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBytecode() {
|
public int getBytecode() {
|
||||||
return bytecode;
|
return bytecode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<MethodAccessFlag> get(String text) {
|
|
||||||
for (MethodAccessFlag flag : MethodAccessFlag.values()) {
|
|
||||||
if (flag.toString().equals(text)) {
|
|
||||||
return Optional.of(flag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.util;
|
package nl.sander.beejava.util;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.*;
|
import java.nio.charset.*;
|
||||||
|
|
@ -29,7 +29,7 @@ public class ByteBuf {
|
||||||
if (data.remaining() < ints.length) {
|
if (data.remaining() < ints.length) {
|
||||||
enlarge(ints.length);
|
enlarge(ints.length);
|
||||||
}
|
}
|
||||||
var bytes = new byte[ints.length];
|
byte[] bytes = new byte[ints.length];
|
||||||
for (int i = 0; i < ints.length; i++) {
|
for (int i = 0; i < ints.length; i++) {
|
||||||
bytes[i] = (byte) (ints[i] & 0xFF);
|
bytes[i] = (byte) (ints[i] & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
@ -45,9 +45,9 @@ public class ByteBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enlarge(final int size) {
|
private void enlarge(final int size) {
|
||||||
final var length1 = 2 * data.limit();
|
final int length1 = 2 * data.limit();
|
||||||
final var length2 = data.limit() + size;
|
final int length2 = data.limit() + size;
|
||||||
var newData = ByteBuffer.allocate(Math.max(length1, length2));
|
ByteBuffer newData = ByteBuffer.allocate(Math.max(length1, length2));
|
||||||
data.flip();
|
data.flip();
|
||||||
newData.put(data);
|
newData.put(data);
|
||||||
data = newData;
|
data = newData;
|
||||||
|
|
@ -61,25 +61,25 @@ public class ByteBuf {
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public String toString() {
|
public String toString() {
|
||||||
// return toString(StandardCharsets.UTF_8);
|
return toString(StandardCharsets.UTF_8);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// public String toString(Charset charset) {
|
public String toString(Charset charset) {
|
||||||
// data.flip();
|
data.flip();
|
||||||
//
|
|
||||||
// CharsetDecoder decoder = charset.newDecoder(); // decode is not threadsafe, might put it in threadlocal
|
CharsetDecoder decoder = charset.newDecoder(); // decode is not threadsafe, might put it in threadlocal
|
||||||
// // but I don't think this (newDecoder()+config) is expensive
|
// but I don't think this (newDecoder()+config) is expensive
|
||||||
//
|
|
||||||
// decoder.onMalformedInput(CodingErrorAction.REPLACE)
|
decoder.onMalformedInput(CodingErrorAction.REPLACE)
|
||||||
// .onUnmappableCharacter(CodingErrorAction.REPLACE);
|
.onUnmappableCharacter(CodingErrorAction.REPLACE);
|
||||||
//
|
|
||||||
// try {
|
try {
|
||||||
// return decoder.decode(data).toString();
|
return decoder.decode(data).toString();
|
||||||
// } catch (CharacterCodingException e) {
|
} catch (CharacterCodingException e) {
|
||||||
// throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,158 +0,0 @@
|
||||||
package nl.sander.bejava;
|
|
||||||
|
|
||||||
import nl.sander.bejava.api.*;
|
|
||||||
import nl.sander.bejava.classinfo.FieldInfo;
|
|
||||||
import nl.sander.bejava.classinfo.MethodInfo;
|
|
||||||
import nl.sander.bejava.constantpool.entry.Utf8Entry;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms BeeSource to CompiledClass
|
|
||||||
* A client must supply a {@link BeSource} containing a set of {@link CodeLine}s that is assumed to be correct.
|
|
||||||
* It doesn't check if a valid state is reached.
|
|
||||||
*/
|
|
||||||
public class Compiler {
|
|
||||||
private final CompiledClass compiledClass;
|
|
||||||
private final ConstantPoolCreator constantPoolCreator = new ConstantPoolCreator();
|
|
||||||
private Utf8Entry codeAttributeNameEntry;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* construct a compiler object.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* At this moment I'm not sure if this class will be able to reused.
|
|
||||||
*/
|
|
||||||
public Compiler(CompiledClass compiledClass) {
|
|
||||||
this.compiledClass = compiledClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* compile a BeeSource object into a CompiledClass object.
|
|
||||||
*
|
|
||||||
* @param beSource the Class object for which the constant pool needs to be created
|
|
||||||
* @return a CompiledClass object (that can be turned into bytecode)
|
|
||||||
*/
|
|
||||||
public static CompiledClass compile(BeSource beSource) {
|
|
||||||
return new Compiler(new CompiledClass(beSource)).compile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* construct a CompiledClass object that contains all information for generating the bytecode
|
|
||||||
*/
|
|
||||||
public CompiledClass compile() {
|
|
||||||
compiledClass.getSource().getFields().forEach(this::addToConstantPool);
|
|
||||||
compiledClass.getSource().getConstructors().forEach(this::addToConstantPool);
|
|
||||||
compiledClass.getSource().getMethods().forEach(this::addToConstantPool); // compiledClass.getSource() ?
|
|
||||||
|
|
||||||
addClassAndSuperClassEntriesToCompiledClass();
|
|
||||||
|
|
||||||
var constantPool = constantPoolCreator.createConstantPool(compiledClass.getConstantTree());
|
|
||||||
|
|
||||||
compiledClass.setConstantPool(constantPool);
|
|
||||||
|
|
||||||
// add refs to super interfaces to class descriptor and constantpool
|
|
||||||
compiledClass.getSource().getInterfaces().forEach(interfase -> {
|
|
||||||
var interfaceEntry = ConstantPoolEntryCreator.getOrCreateClassEntry(interfase);
|
|
||||||
compiledClass.addInterface(interfaceEntry);
|
|
||||||
compiledClass.addConstantPoolEntry(interfaceEntry);
|
|
||||||
});
|
|
||||||
|
|
||||||
// add refs to fields to class descriptor
|
|
||||||
compiledClass.getSource().getFields().stream()
|
|
||||||
.map(field ->
|
|
||||||
new FieldInfo(ConstantPoolEntryCreator.getOrCreateUtf8(field.getName()),
|
|
||||||
ConstantPoolEntryCreator.getOrCreateUtf8(internalName(field.getType().getName())))
|
|
||||||
.addAccessFlags(field.getAccessFlags())
|
|
||||||
)
|
|
||||||
.forEach(compiledClass::addField);
|
|
||||||
|
|
||||||
addConstructors();
|
|
||||||
addMethods();
|
|
||||||
|
|
||||||
return compiledClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
// why not put this everywhere, it's not like it's ever going to change
|
|
||||||
private String internalName(String name) {
|
|
||||||
return name.replaceAll("\\.", "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void addClassAndSuperClassEntriesToCompiledClass() {
|
|
||||||
var classEntry = ConstantPoolEntryCreator.getOrCreateClassEntry(compiledClass.getSource().getName());
|
|
||||||
compiledClass.setThisClass(classEntry);
|
|
||||||
compiledClass.addConstantPoolEntry(classEntry);
|
|
||||||
|
|
||||||
var superClass = ConstantPoolEntryCreator.getOrCreateClassEntry(compiledClass.getSource().getSuperClass());
|
|
||||||
compiledClass.addConstantPoolEntry(superClass);
|
|
||||||
compiledClass.setSuperClass(superClass);
|
|
||||||
|
|
||||||
|
|
||||||
this.codeAttributeNameEntry = ConstantPoolEntryCreator.getOrCreateUtf8("Code");
|
|
||||||
compiledClass.addConstantPoolEntry(codeAttributeNameEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addConstructors() {
|
|
||||||
compiledClass.getSource().getConstructors().stream()
|
|
||||||
.map(this::createMethod)
|
|
||||||
.forEach(compiledClass::addMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* maps methods from the source to a MethodInfo and adds that to the CompiledClass.
|
|
||||||
*/
|
|
||||||
public void addMethods() {
|
|
||||||
compiledClass.addConstantPoolEntry(codeAttributeNameEntry);
|
|
||||||
for (var method : compiledClass.getSource().getMethods()) {
|
|
||||||
compiledClass.addMethod(createMethod(method));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create methodInfo object for classfile
|
|
||||||
*/
|
|
||||||
private MethodInfo createMethod(CodeContainer method) {
|
|
||||||
return new MethodInfo(
|
|
||||||
ConstantPoolEntryCreator.getOrCreateUtf8(method.getName()),
|
|
||||||
ConstantPoolEntryCreator.getOrCreateUtf8(method.getSignature()))
|
|
||||||
.addAccessFlags(method.getAccessFlags())
|
|
||||||
.addAttribute(MethodCodeAttributeCreator.createCodeAttribute(codeAttributeNameEntry, method));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addToConstantPool(BeField field) {
|
|
||||||
var fieldRefEntry = ConstantPoolEntryCreator.getOrCreateFieldRefEntry(compiledClass.getSource().getName(), field.getName(), field.getType());
|
|
||||||
compiledClass.addConstantPoolEntry(fieldRefEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* inspect a method or constructor, extract items that need to be added, and add them to the constant pool
|
|
||||||
*/
|
|
||||||
private void addToConstantPool(CodeContainer codeContainer) {
|
|
||||||
compiledClass.addConstantPoolEntry(ConstantPoolEntryCreator.getOrCreateUtf8(codeContainer.getName()));
|
|
||||||
compiledClass.addConstantPoolEntry(ConstantPoolEntryCreator.getOrCreateUtf8(codeContainer.getSignature()));
|
|
||||||
codeContainer.getExpandedCode().forEach(this::updateConstantPool);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scan code line for items that need adding to the constant pool
|
|
||||||
*
|
|
||||||
* Constantpool uniqueness is maintained in two ways:
|
|
||||||
* 1. ConstantPoolEntryCreator.getOrCreateMethodRefEntry (and other methods) return a tree of entries.
|
|
||||||
* Sub-entries are kept in cache by the ConstantPoolEntryCreator and it returns a cached entry over a new one, if deemed equal.
|
|
||||||
* 2. the root node (also in aforementioned cache) is not symmetric because it is the only one that can be added to The compiledClass.
|
|
||||||
* So Compiled class also contains a set of unique root nodes.
|
|
||||||
*/
|
|
||||||
private void updateConstantPool(JavaInstruction instruction) {
|
|
||||||
if (instruction.hasMethodRef()) {
|
|
||||||
compiledClass.addConstantPoolEntry(instruction.getMethodRef());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instruction.hasFieldRef()) {
|
|
||||||
compiledClass.addConstantPoolEntry(instruction.getFieldRef());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instruction.hasConstantRef()) {
|
|
||||||
compiledClass.addConstantPoolEntry(instruction.getConstantEntry());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
package nl.sander.bejava;
|
|
||||||
|
|
||||||
import nl.sander.bejava.constantpool.entry.*;
|
|
||||||
import nl.sander.bejava.operands.ConstantOperand;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responsible for creating unique constant pool entries
|
|
||||||
*/
|
|
||||||
class ConstantPoolEntryCreator {
|
|
||||||
|
|
||||||
private static final Map<Integer, ConstantPoolEntry> cache = new HashMap<>();
|
|
||||||
|
|
||||||
private ConstantPoolEntryCreator() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* creates a FieldRefEntry when not found in cache, otherwise gets it from there
|
|
||||||
*/
|
|
||||||
static FieldRefEntry getOrCreateFieldRefEntry(String declaringClassName, String fieldName, Class<?> fieldType) {
|
|
||||||
return cache(new FieldRefEntry(getOrCreateClassEntry(declaringClassName), getOrCreateFieldNameAndType(fieldName, fieldType)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* creates a MethodRefEntry when not found in cache, otherwise gets it from there
|
|
||||||
*/
|
|
||||||
static MethodRefEntry getOrCreateMethodRefEntry(String className, String methodName, String signature) {
|
|
||||||
ClassEntry classEntry = getOrCreateClassEntry(className);
|
|
||||||
return cache(new MethodRefEntry(classEntry, getOrCreateMethodNameAndType(methodName, signature)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* creates a NamAndTypeEntry for a field when not found in cache, otherwise gets it from there
|
|
||||||
*/
|
|
||||||
private static NameAndTypeEntry getOrCreateFieldNameAndType(String name, Class<?> type) {
|
|
||||||
return cache(new NameAndTypeEntry(
|
|
||||||
cache(new Utf8Entry(name)),
|
|
||||||
cache(new Utf8Entry(TypeMapper.map(type)))));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* creates a NamAndTypeEntry for a method when not found in cache, otherwise gets it from there
|
|
||||||
*/
|
|
||||||
private static NameAndTypeEntry getOrCreateMethodNameAndType(String methodName, String methodSignature) {
|
|
||||||
return new NameAndTypeEntry(
|
|
||||||
cache(new Utf8Entry(methodName)),
|
|
||||||
cache(new Utf8Entry(methodSignature)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get or create a ClassEntry
|
|
||||||
*/
|
|
||||||
public static ClassEntry getOrCreateClassEntry(String externalClassName) {
|
|
||||||
return cache(new ClassEntry(cache(new Utf8Entry(internalName(externalClassName)))));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ClassEntry getOrCreateClassEntry(Class<?> type) {
|
|
||||||
return getOrCreateClassEntry(type.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If a constant is in the codeline, it needs to be added to the constant pool.
|
|
||||||
*/
|
|
||||||
public static ConstantPoolEntry getOrCreatePrimitiveConstantEntry(ConstantOperand operand) {
|
|
||||||
return cache(switch (operand.getType()) {
|
|
||||||
case STRING -> new StringEntry(cache(new Utf8Entry(operand.getValue())));
|
|
||||||
case INT, BYTE, SHORT -> new IntegerEntry(operand.getValue());
|
|
||||||
case LONG -> new LongEntry(Long.parseLong(operand.getValue()));
|
|
||||||
case FLOAT -> new FloatEntry(operand.getValue());
|
|
||||||
case DOUBLE -> new DoubleEntry(Double.parseDouble(operand.getValue()));
|
|
||||||
case CHAR -> new IntegerEntry(Character.codePointAt(operand.getValue(), 0));
|
|
||||||
case BOOLEAN -> new IntegerEntry(Boolean.parseBoolean(operand.getValue()) ? 1 : 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Utf8Entry getOrCreateUtf8(String utf8) {
|
|
||||||
return cache(new Utf8Entry(utf8));
|
|
||||||
}
|
|
||||||
|
|
||||||
// why not put this everywhere, it's not like it's ever going to change
|
|
||||||
private static String internalName(String name) {
|
|
||||||
return name.replaceAll("\\.", "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
static <T extends ConstantPoolEntry> T cache(T newEntry) {
|
|
||||||
// if the argument newEntry is found in cache, return the cached entry and discard the argument
|
|
||||||
// Otherwise store it.
|
|
||||||
// Can't check for equality unless you create a potential new entry first
|
|
||||||
int hash = newEntry.hashCode();
|
|
||||||
return (T) cache.computeIfAbsent(hash, k -> newEntry);
|
|
||||||
// a hashmap with key hash of value is weird right?
|
|
||||||
// A HashSet is a HashMap with entry: key = value, which would work, but I cannot _get_ anything from a set.
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
package nl.sander.bejava;
|
|
||||||
|
|
||||||
import nl.sander.bejava.api.BeField;
|
|
||||||
import nl.sander.bejava.flags.AccessFlags;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Union type for an existing standard java field (already loaded) or a field for the class that is being compiled
|
|
||||||
*/
|
|
||||||
public class FieldWrapper {
|
|
||||||
private final Field reflectField;
|
|
||||||
private final BeField beefield;
|
|
||||||
|
|
||||||
public FieldWrapper(Field reflectField, BeField beefield) {
|
|
||||||
this.reflectField = reflectField;
|
|
||||||
this.beefield = beefield;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<?> getType() {
|
|
||||||
if (reflectField != null) {
|
|
||||||
return reflectField.getType();
|
|
||||||
} else {
|
|
||||||
return beefield.getType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
if (reflectField != null) {
|
|
||||||
return reflectField.getName();
|
|
||||||
} else {
|
|
||||||
return beefield.getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getModifiers() {
|
|
||||||
if (reflectField != null) {
|
|
||||||
return reflectField.getModifiers();
|
|
||||||
} else {
|
|
||||||
return AccessFlags.combine(beefield.getAccessFlags());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
package nl.sander.bejava;
|
|
||||||
|
|
||||||
import nl.sander.bejava.constantpool.entry.ConstantPoolEntry;
|
|
||||||
import nl.sander.bejava.constantpool.entry.FieldRefEntry;
|
|
||||||
import nl.sander.bejava.constantpool.entry.MethodRefEntry;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bejava opcodes translate to real java opcodes. A JavaInstruct
|
|
||||||
*/
|
|
||||||
public class JavaInstruction {
|
|
||||||
private final JavaOpcode opcode;
|
|
||||||
private final MethodRefEntry methodRefEntry;
|
|
||||||
private final FieldRefEntry fieldRefEntry;
|
|
||||||
private final ConstantPoolEntry constantEntry;
|
|
||||||
private Integer localVariableIndex; // TODO not used yet
|
|
||||||
|
|
||||||
public JavaInstruction(JavaOpcode opcode) {
|
|
||||||
this(opcode, null, null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JavaInstruction(JavaOpcode opcode, int localVariableIndex) {
|
|
||||||
this(opcode, localVariableIndex, null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JavaInstruction(JavaOpcode opcode, ConstantPoolEntry constantEntry) {
|
|
||||||
this(opcode, null, null, null, constantEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JavaInstruction(JavaOpcode opcode, MethodRefEntry methodRefEntry) {
|
|
||||||
this(opcode, null, methodRefEntry, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JavaInstruction(JavaOpcode opcode, FieldRefEntry fieldRefEntry) {
|
|
||||||
this(opcode, null, null, fieldRefEntry, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private JavaInstruction(JavaOpcode opcode, Integer localVariableIndex, MethodRefEntry methodRefEntry, FieldRefEntry fieldRefEntry, ConstantPoolEntry constantEntry) {
|
|
||||||
this.opcode = opcode;
|
|
||||||
this.localVariableIndex = localVariableIndex;
|
|
||||||
this.methodRefEntry = methodRefEntry;
|
|
||||||
this.fieldRefEntry = fieldRefEntry;
|
|
||||||
this.constantEntry = constantEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JavaOpcode getOpcode() {
|
|
||||||
return opcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MethodRefEntry getMethodRef() {
|
|
||||||
return methodRefEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FieldRefEntry getFieldRef() {
|
|
||||||
return fieldRefEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasMethodRef() {
|
|
||||||
return methodRefEntry != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasFieldRef() {
|
|
||||||
return fieldRefEntry != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConstantPoolEntry getEntry() {
|
|
||||||
if (methodRefEntry != null) {
|
|
||||||
return methodRefEntry;
|
|
||||||
} else if (fieldRefEntry != null) {
|
|
||||||
return fieldRefEntry;
|
|
||||||
} else if (constantEntry!=null){
|
|
||||||
return constantEntry;
|
|
||||||
} else {
|
|
||||||
return null; // Not sure yet what to do here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasConstantRef() {
|
|
||||||
return constantEntry !=null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConstantPoolEntry getConstantEntry() {
|
|
||||||
return constantEntry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,209 +0,0 @@
|
||||||
package nl.sander.bejava;
|
|
||||||
|
|
||||||
import nl.sander.bejava.api.*;
|
|
||||||
import nl.sander.bejava.operands.*;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates from BeeJava opcodes to actual java opcodes.
|
|
||||||
*/
|
|
||||||
public class OpcodeTranslator {
|
|
||||||
private final static OpcodeTranslator instance = new OpcodeTranslator();
|
|
||||||
private final Parser parser = new Parser();
|
|
||||||
private BeSource beSource;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* trying to make SourceExpander reusable.
|
|
||||||
* @not_multithreaded.
|
|
||||||
* //TODO should not mutate beesource
|
|
||||||
*/
|
|
||||||
public static void translate(BeSource beSource) {
|
|
||||||
instance.init(beSource);
|
|
||||||
instance.doExpand();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init(BeSource beSource) {
|
|
||||||
this.beSource = beSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doExpand() {
|
|
||||||
beSource.getConstructors().forEach(this::translate);
|
|
||||||
beSource.getMethods().forEach(this::translate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void translate(CodeContainer codeContainer) {
|
|
||||||
var methodInstructions = codeContainer.getCode().stream()
|
|
||||||
.flatMap(o -> translate(codeContainer, o).stream())
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
codeContainer.setExpandedCode(methodInstructions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<JavaInstruction> translate(CodeContainer codeContainer, CodeLine codeLine) {
|
|
||||||
var operand = parser.parse(codeLine);
|
|
||||||
return translate(codeContainer, codeLine.getOpcode(), operand);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<JavaInstruction> translate(CodeContainer codeContainer, Opcode opcode, Operand operand) {
|
|
||||||
List<JavaInstruction> instructions = new ArrayList<>();
|
|
||||||
if (operand instanceof MethodOperand) {
|
|
||||||
var mo = (MethodOperand) operand;
|
|
||||||
if ("this".equals(mo.className)) {
|
|
||||||
instructions.add(new JavaInstruction(JavaOpcode.ALOAD_0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opcode == Opcode.LOAD) {
|
|
||||||
if (operand instanceof ConstantOperand) {
|
|
||||||
var constantEntry = ConstantPoolEntryCreator.getOrCreatePrimitiveConstantEntry((ConstantOperand) operand);
|
|
||||||
instructions.add(new JavaInstruction(JavaOpcode.LDC, constantEntry));
|
|
||||||
}
|
|
||||||
} else if (opcode == Opcode.RETURN && operand instanceof VoidOperand) {
|
|
||||||
instructions.add(new JavaInstruction(JavaOpcode.RETURN));
|
|
||||||
} else if (opcode == Opcode.GET) {
|
|
||||||
assert operand instanceof FieldOperand;
|
|
||||||
|
|
||||||
var fieldOperand = (FieldOperand) operand;
|
|
||||||
var field = getField(codeContainer, fieldOperand);
|
|
||||||
instructions.add(new JavaInstruction(getJavaOpcodeForGet(field),
|
|
||||||
ConstantPoolEntryCreator.getOrCreateFieldRefEntry(getType(codeContainer, fieldOperand), field.getName(), field.getType())));
|
|
||||||
} else if (opcode == Opcode.INVOKE) {
|
|
||||||
assert operand instanceof MethodOperand;
|
|
||||||
var mo = (MethodOperand) operand;
|
|
||||||
if ("super".equals(mo.methodName)) {
|
|
||||||
instructions.add(new JavaInstruction(JavaOpcode.INVOKESPECIAL,
|
|
||||||
ConstantPoolEntryCreator.getOrCreateMethodRefEntry(beSource.getSuperClass().getName(), "<init>", "()V")));
|
|
||||||
} else {
|
|
||||||
instructions.add(new JavaInstruction(JavaOpcode.INVOKEVIRTUAL, ConstantPoolEntryCreator.getOrCreateMethodRefEntry(mo.className, mo.methodName, mo.signature)));
|
|
||||||
}
|
|
||||||
} else if (operand instanceof FieldOperand) {
|
|
||||||
var fieldOperand = (FieldOperand) operand;
|
|
||||||
if (fieldOperand.className.equals("this")) {
|
|
||||||
instructions.add(new JavaInstruction(JavaOpcode.ALOAD_0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opcode == Opcode.RETURN) {
|
|
||||||
instructions.add(getReturnInstruction(codeContainer, fieldOperand));
|
|
||||||
}
|
|
||||||
} else if (operand instanceof LocalVariableOperand) {
|
|
||||||
var localVariable = (LocalVariableOperand) operand;
|
|
||||||
instructions.add(codeContainer.getParameter(localVariable.name)
|
|
||||||
.map(this::getJavaLoadInstruction)
|
|
||||||
.orElse(null)); //else case
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO continue here. finish simpleBean
|
|
||||||
return instructions;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JavaOpcode getJavaOpcodeForGet(FieldWrapper field) {
|
|
||||||
JavaOpcode get;
|
|
||||||
if (Modifier.isStatic(field.getModifiers())) {
|
|
||||||
get = JavaOpcode.GETSTATIC;
|
|
||||||
} else {
|
|
||||||
get = JavaOpcode.GETFIELD;
|
|
||||||
}
|
|
||||||
return get;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JavaInstruction getReturnInstruction(CodeContainer codeContainer, FieldOperand fo) {
|
|
||||||
var field = getField(codeContainer, fo);
|
|
||||||
|
|
||||||
var javaOpcode = switch (field.getName()) {
|
|
||||||
case "int", "byte", "boolean", "short" -> JavaOpcode.IRETURN;
|
|
||||||
case "long" -> JavaOpcode.LRETURN;
|
|
||||||
case "float" -> JavaOpcode.FRETURN;
|
|
||||||
case "double" -> JavaOpcode.DRETURN;
|
|
||||||
default -> JavaOpcode.ARETURN;
|
|
||||||
};
|
|
||||||
return new JavaInstruction(javaOpcode);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getType(CodeContainer codeContainer, FieldOperand fo) {
|
|
||||||
if (fo.className.equals("this")) {
|
|
||||||
return codeContainer.getName();
|
|
||||||
} else {
|
|
||||||
return fo.className;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private FieldWrapper getField(CodeContainer codeContainer, FieldOperand fo) {
|
|
||||||
try {
|
|
||||||
Field javaField = null;
|
|
||||||
BeField beField = null;
|
|
||||||
if (fo.className.equals("this")) {
|
|
||||||
beField = codeContainer.getOwner().getField(fo.fieldName);
|
|
||||||
} else {
|
|
||||||
var type = Class.forName(fo.className);
|
|
||||||
javaField = type.getDeclaredField(fo.fieldName);
|
|
||||||
}
|
|
||||||
return new FieldWrapper(javaField, beField);
|
|
||||||
} catch (ClassNotFoundException | NoSuchFieldException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JavaInstruction getJavaLoadInstruction(BeParameter parameter) {
|
|
||||||
return switch (parameter.getIndex()) {
|
|
||||||
case 0 -> new JavaInstruction(JavaOpcode.ALOAD_0);
|
|
||||||
case 1 -> new JavaInstruction(JavaOpcode.ALOAD_1);
|
|
||||||
case 2 -> new JavaInstruction(JavaOpcode.ALOAD_2);
|
|
||||||
case 3 -> new JavaInstruction(JavaOpcode.ALOAD_3);
|
|
||||||
default -> new JavaInstruction(JavaOpcode.ALOAD, parameter.getIndex());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Parser {
|
|
||||||
|
|
||||||
Operand parse(CodeLine codeLine) {
|
|
||||||
var operand = codeLine.getOperand();
|
|
||||||
if (operand == null) {
|
|
||||||
return VoidOperand.INSTANCE;
|
|
||||||
} else {
|
|
||||||
if (operand.contains("(")) {
|
|
||||||
var parenIndex = operand.indexOf('(');
|
|
||||||
var signature = operand.substring(parenIndex);
|
|
||||||
var classAndMethodeName = operand.substring(0, parenIndex);
|
|
||||||
int lastDotIndex = classAndMethodeName.lastIndexOf('.');
|
|
||||||
var className = classAndMethodeName.substring(0, lastDotIndex);
|
|
||||||
var methodName = classAndMethodeName.substring(lastDotIndex + 1);
|
|
||||||
return new MethodOperand(className, methodName, signature);
|
|
||||||
} else {
|
|
||||||
int index = operand.lastIndexOf('.');
|
|
||||||
if (index < 0) {
|
|
||||||
var constantOperandOrNull = asConstantOperand(operand);
|
|
||||||
return Objects.requireNonNullElseGet(constantOperandOrNull, () -> new LocalVariableOperand(operand));
|
|
||||||
} else if (index < operand.length() - 1) {
|
|
||||||
var className = operand.substring(0, index);
|
|
||||||
var fieldName = operand.substring(index + 1);
|
|
||||||
return new FieldOperand(className, fieldName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("compile error");
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstantOperand asConstantOperand(String value) {
|
|
||||||
//TODO add boxed types
|
|
||||||
var tokens = value.split(" ");
|
|
||||||
var type = Primitive.from(tokens[0].toUpperCase(Locale.ROOT));
|
|
||||||
if (tokens.length == 2 && type != null) {
|
|
||||||
return new ConstantOperand(type, tokens[1]);
|
|
||||||
} else if (value.startsWith("\"")) {
|
|
||||||
if (value.endsWith("\"")) {
|
|
||||||
return new ConstantOperand(Primitive.STRING, value.substring(1, value.length() - 1));
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Unterminated String value");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package nl.sander.bejava;
|
|
||||||
|
|
||||||
import nl.sander.bejava.api.BeSource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains all four passes necessary to go from source as text to bytecode.
|
|
||||||
*/
|
|
||||||
public final class OverallCompiler {
|
|
||||||
|
|
||||||
private OverallCompiler() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] compile(String sourcecode) {
|
|
||||||
BeSource beSource = SourceCompiler.compile(sourcecode);
|
|
||||||
OpcodeTranslator.translate(beSource);
|
|
||||||
CompiledClass compiledClass = Compiler.compile(beSource);
|
|
||||||
return BytecodeGenerator.generate(compiledClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package nl.sander.bejava;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public enum Primitive {
|
|
||||||
INT, SHORT, BYTE, LONG, FLOAT, DOUBLE, CHAR, BOOLEAN, STRING;
|
|
||||||
|
|
||||||
public static Primitive from(String value) {
|
|
||||||
return Arrays.stream(values())
|
|
||||||
.filter(e -> e.toString().equals(value))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,282 +0,0 @@
|
||||||
package nl.sander.bejava;
|
|
||||||
|
|
||||||
import nl.sander.bejava.api.*;
|
|
||||||
import nl.sander.bejava.flags.ClassAccessFlags;
|
|
||||||
import nl.sander.bejava.flags.FieldAccessFlag;
|
|
||||||
import nl.sander.bejava.flags.MethodAccessFlag;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses code as text to a BeeSource object
|
|
||||||
*/
|
|
||||||
public class SourceCompiler {
|
|
||||||
private final static Pattern firstBlanksplitter = Pattern.compile("(.+?) (.+)");
|
|
||||||
private final static Pattern parensplitter = Pattern.compile("(.+?)\\((.*?)\\)");
|
|
||||||
private final static Pattern returntypesplitter = Pattern.compile("->");
|
|
||||||
private final String sourcecode;
|
|
||||||
private final List<Instruction> instructions = new ArrayList<>();
|
|
||||||
private int currentLine = 0;
|
|
||||||
|
|
||||||
public SourceCompiler(String sourcecode) {
|
|
||||||
this.sourcecode = sourcecode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BeSource compile(String sourcecode) {
|
|
||||||
return new SourceCompiler(sourcecode).doCompile();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BeSource doCompile() {
|
|
||||||
Arrays.stream(sourcecode.split("\n"))
|
|
||||||
.map(this::compileLine)
|
|
||||||
.forEach(instructions::add);
|
|
||||||
|
|
||||||
BeSource beSource = new BeSource();
|
|
||||||
|
|
||||||
for (currentLine = 0; currentLine < instructions.size(); ) {
|
|
||||||
Instruction ins = instructions.get(currentLine);
|
|
||||||
if (currentLine == 0) {
|
|
||||||
parseClassDeclaration(ins, beSource);
|
|
||||||
} else {
|
|
||||||
parseInstruction(ins, beSource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return beSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseInstruction(Instruction instruction, BeSource beSource) {
|
|
||||||
if (instruction instanceof ClassInstruction) {
|
|
||||||
ClassInstruction classInstruction = (ClassInstruction) instruction;
|
|
||||||
String operand = classInstruction.getOperand();
|
|
||||||
switch (classInstruction.getOperation()) {
|
|
||||||
case FIELD -> beSource.addFields(parseField(beSource, operand));
|
|
||||||
case CONSTRUCTOR -> beSource.addConstructors(parseConstructor(beSource, operand));
|
|
||||||
case METHOD -> beSource.addMethods(parseMethod(beSource, operand));
|
|
||||||
default -> throw new IllegalArgumentException("Not allowed here");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private BeMethod parseMethod(BeSource beSource, String text) {
|
|
||||||
String[] tokens = returntypesplitter.split(text);
|
|
||||||
final String first;
|
|
||||||
final Class<?> returnType;
|
|
||||||
if (tokens.length > 1) {
|
|
||||||
returnType = getType(tokens[1].trim());
|
|
||||||
first = tokens[0].trim();
|
|
||||||
} else {
|
|
||||||
first = text;
|
|
||||||
returnType = Void.TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] flagsNameParameters = split(first, firstBlanksplitter);
|
|
||||||
|
|
||||||
Set<MethodAccessFlag> flags = new HashSet<>();
|
|
||||||
int i = 0;
|
|
||||||
Optional<MethodAccessFlag> maybeFlag = MethodAccessFlag.get(flagsNameParameters[i].toUpperCase());
|
|
||||||
while (maybeFlag.isPresent()) {
|
|
||||||
flags.add(maybeFlag.get());
|
|
||||||
i += 1;
|
|
||||||
maybeFlag = MethodAccessFlag.get(flagsNameParameters[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] nameParams = split(flagsNameParameters[i], parensplitter);
|
|
||||||
Set<BeParameter> parameters = new HashSet<>();
|
|
||||||
String methodName = null;
|
|
||||||
if (nameParams.length > 0) {
|
|
||||||
methodName = nameParams[0];
|
|
||||||
if (nameParams[1].length() > 0) {
|
|
||||||
int index = 0;
|
|
||||||
String params = nameParams[1];
|
|
||||||
String[] paramTokens = params.split(",");
|
|
||||||
for (String paramToken : paramTokens) {
|
|
||||||
String[] declaration = paramToken.trim().split(" ");
|
|
||||||
String type = declaration[0];
|
|
||||||
String name = declaration[1];
|
|
||||||
parameters.add(new BeParameter(getType(type), name, index++));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (methodName == null) {
|
|
||||||
throw new IllegalArgumentException("method name not found");
|
|
||||||
}
|
|
||||||
currentLine += 1;
|
|
||||||
List<nl.sander.bejava.api.CodeLine> lines = new ArrayList<>();
|
|
||||||
Instruction nextInstruction = instructions.get(currentLine);
|
|
||||||
while (currentLine < instructions.size() && nextInstruction instanceof CodeLine) {
|
|
||||||
nextInstruction = instructions.get(currentLine);
|
|
||||||
if (nextInstruction instanceof CodeLine) {
|
|
||||||
lines.add((CodeLine) nextInstruction);
|
|
||||||
currentLine += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return new BeMethod(beSource, methodName, flags, parameters, returnType, lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
private BeConstructor parseConstructor(BeSource beSource, String text) {
|
|
||||||
String[] tokens = split(text, parensplitter);
|
|
||||||
String flag = tokens[0];
|
|
||||||
MethodAccessFlag methodAccessFlag = MethodAccessFlag.get(flag.toUpperCase()).orElseThrow(illegalArgument("Not a valid flag " + flag));
|
|
||||||
|
|
||||||
String params = tokens[1];
|
|
||||||
Set<BeParameter> parameters = new HashSet<>();
|
|
||||||
if (params.length() > 0) {
|
|
||||||
String[] paramTokens = params.split(",");
|
|
||||||
int index = 0;
|
|
||||||
for (String paramToken : paramTokens) {
|
|
||||||
String[] declaration = paramToken.trim().split(" ");
|
|
||||||
String type = declaration[0];
|
|
||||||
String name = declaration[1];
|
|
||||||
parameters.add(new BeParameter(getType(type), name, index++));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentLine += 1;
|
|
||||||
List<CodeLine> lines = new ArrayList<>();
|
|
||||||
Instruction nextInstruction = instructions.get(currentLine);
|
|
||||||
while (currentLine < instructions.size() && nextInstruction instanceof CodeLine) {
|
|
||||||
nextInstruction = instructions.get(currentLine);
|
|
||||||
if (nextInstruction instanceof CodeLine) {
|
|
||||||
lines.add((CodeLine) nextInstruction);
|
|
||||||
currentLine += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BeConstructor(beSource, Set.of(methodAccessFlag), parameters, lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
private BeField parseField(BeSource beSource, String operand) {
|
|
||||||
String[] tokens = operand.split(" ");
|
|
||||||
Set<FieldAccessFlag> flags = new HashSet<>();
|
|
||||||
String type = null;
|
|
||||||
String name = null;
|
|
||||||
for (String token : tokens) {
|
|
||||||
Optional<FieldAccessFlag> maybeFlag = FieldAccessFlag.get(token.toUpperCase());
|
|
||||||
if (maybeFlag.isPresent()) {
|
|
||||||
flags.add(maybeFlag.get());
|
|
||||||
} else {
|
|
||||||
if (type == null) {
|
|
||||||
type = token;
|
|
||||||
} else {
|
|
||||||
name = token;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentLine += 1;
|
|
||||||
return new BeField(beSource.getName(), flags, getType(type), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void parseClassDeclaration(Instruction instruction, BeSource beSource) {
|
|
||||||
if (instruction instanceof ClassInstruction) {
|
|
||||||
ClassInstruction classDeclaration = (ClassInstruction) instruction;
|
|
||||||
ClassOperation operation = classDeclaration.getOperation();
|
|
||||||
switch (operation) {
|
|
||||||
case CLASS -> {
|
|
||||||
beSource.addAccessFlags(ClassAccessFlags.SUPER);
|
|
||||||
beSource.setClassFileVersion(getVersion(classDeclaration));
|
|
||||||
|
|
||||||
String[] tokens = split(classDeclaration.getOperand(), parensplitter);
|
|
||||||
String rightHand = classDeclaration.getOperand();
|
|
||||||
if (tokens.length > 0) { // has Version tag
|
|
||||||
rightHand = tokens[0];
|
|
||||||
}
|
|
||||||
tokens = rightHand.split(" ");
|
|
||||||
|
|
||||||
if (tokens.length == 2) { // has access flag
|
|
||||||
beSource.addAccessFlags(ClassAccessFlags.valueOf(tokens[0].toUpperCase()));
|
|
||||||
}
|
|
||||||
beSource.setName(getClassName(tokens));
|
|
||||||
}
|
|
||||||
case INTERFACE -> {
|
|
||||||
}//TODO
|
|
||||||
case ENUM -> {
|
|
||||||
}//TODO
|
|
||||||
default -> throw new IllegalArgumentException("Not allowed here");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("class must start with 'class name(target.jdk.version)'");
|
|
||||||
}
|
|
||||||
currentLine += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Version getVersion(ClassInstruction classDeclaration) {
|
|
||||||
String[] tokens2 = split(classDeclaration.getOperand(), parensplitter);
|
|
||||||
if (tokens2.length == 0) {
|
|
||||||
return Version.V8;
|
|
||||||
} else {
|
|
||||||
return Version.get(tokens2[1]).orElseThrow(illegalArgument(tokens2[1]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getClassName(String[] tokens) {
|
|
||||||
if (tokens.length == 2) {
|
|
||||||
return tokens[1];
|
|
||||||
} else {
|
|
||||||
return tokens[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Instruction compileLine(String line) {
|
|
||||||
if (!line.startsWith(" ")) {
|
|
||||||
String[] tokens = split(line, firstBlanksplitter);
|
|
||||||
String operation = tokens[0];
|
|
||||||
String operand = tokens[1];
|
|
||||||
ClassOperation classOperation = ClassOperation.get(operation).orElseThrow(illegalArgument(operation));
|
|
||||||
return new ClassInstruction(classOperation, operand);
|
|
||||||
} else {
|
|
||||||
line = line.substring(2);
|
|
||||||
if (line.startsWith(" ")) {
|
|
||||||
throw new IllegalArgumentException("Illegal indent -> must be 2 spaces");
|
|
||||||
}
|
|
||||||
String operation;
|
|
||||||
String operand;
|
|
||||||
if (line.indexOf(' ') > -1) {
|
|
||||||
String[] tokens = split(line, firstBlanksplitter);
|
|
||||||
|
|
||||||
operation = tokens[0];
|
|
||||||
operand = tokens[1];
|
|
||||||
} else {
|
|
||||||
operation = line;
|
|
||||||
operand = null;
|
|
||||||
}
|
|
||||||
Opcode opcode = Opcode.get(operation).orElseThrow(illegalArgument("Illegal opcode: " + operation));
|
|
||||||
return new CodeLine(opcode, operand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Supplier<IllegalArgumentException> illegalArgument(String text) {
|
|
||||||
return () -> new IllegalArgumentException(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] split(String text, Pattern splitter) {
|
|
||||||
Matcher matcher = splitter.matcher(text);
|
|
||||||
if (matcher.find()) {
|
|
||||||
return new String[]{matcher.group(1), matcher.group(2)};
|
|
||||||
} else {
|
|
||||||
return new String[]{};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Class<?> getType(String type) {
|
|
||||||
try {
|
|
||||||
return switch (type) {
|
|
||||||
case "int" -> int.class;
|
|
||||||
case "short" -> short.class;
|
|
||||||
case "byte" -> byte.class;
|
|
||||||
case "long" -> long.class;
|
|
||||||
case "float" -> float.class;
|
|
||||||
case "double" -> double.class;
|
|
||||||
case "boolean" -> boolean.class;
|
|
||||||
case "char" -> char.class;
|
|
||||||
default -> Class.forName(type);
|
|
||||||
};
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new IllegalArgumentException("Not a valid type: " + type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
package nl.sander.bejava.api;
|
|
||||||
|
|
||||||
import nl.sander.bejava.flags.MethodAccessFlag;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Models a constructor
|
|
||||||
*/
|
|
||||||
public final class BeConstructor extends CodeContainer {
|
|
||||||
|
|
||||||
public BeConstructor(BeSource beSource, Set<MethodAccessFlag> accessFlags,
|
|
||||||
Set<BeParameter> formalParameters,
|
|
||||||
List<CodeLine> code) {
|
|
||||||
this.formalParameters.addAll(formalParameters);
|
|
||||||
this.accessFlags.addAll(accessFlags);
|
|
||||||
super.code.addAll(code);
|
|
||||||
setOwner(beSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return "<init>";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "BeeConstructor{" +
|
|
||||||
"formalParameters=" + formalParameters +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<?> getReturnType() {
|
|
||||||
return void.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
var that = (BeConstructor) o;
|
|
||||||
return formalParameters.equals(that.formalParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(formalParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
package nl.sander.bejava.api;
|
|
||||||
|
|
||||||
import nl.sander.bejava.flags.FieldAccessFlag;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Models a field in a BeeClass
|
|
||||||
*/
|
|
||||||
public final class BeField {
|
|
||||||
|
|
||||||
private final String declaringClass;
|
|
||||||
private final Set<FieldAccessFlag> accessFlags = new HashSet<>();
|
|
||||||
private final Class<?> type;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param declaringClass class that declares the field. Can be existing class, or the one that is under construction
|
|
||||||
* @param accessFlags
|
|
||||||
* @param type field type. Must be existing type.
|
|
||||||
* @param name
|
|
||||||
*/
|
|
||||||
public BeField(String declaringClass, Set<FieldAccessFlag> accessFlags, Class<?> type, String name) {
|
|
||||||
this.declaringClass = declaringClass;
|
|
||||||
this.accessFlags.addAll(accessFlags);
|
|
||||||
this.type = type;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<FieldAccessFlag> getAccessFlags() {
|
|
||||||
return accessFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<?> getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeclaringClass() {
|
|
||||||
return declaringClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
var beeField = (BeField) o;
|
|
||||||
return name.equals(beeField.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
package nl.sander.bejava.api;
|
|
||||||
|
|
||||||
import nl.sander.bejava.flags.MethodAccessFlag;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Models a method in a BeeClass
|
|
||||||
*/
|
|
||||||
public final class BeMethod extends CodeContainer {
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
private final Class<?> returnType;
|
|
||||||
|
|
||||||
public BeMethod(BeSource beSource, String name, Set<MethodAccessFlag> accessFlags,
|
|
||||||
Set<BeParameter> formalParameters,
|
|
||||||
Class<?> returnType, List<CodeLine> code) {
|
|
||||||
this.name = name;
|
|
||||||
this.accessFlags.addAll(accessFlags);
|
|
||||||
this.formalParameters.addAll(formalParameters);
|
|
||||||
this.returnType = returnType;
|
|
||||||
super.code.addAll(code);
|
|
||||||
setOwner(beSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<?> getReturnType() {
|
|
||||||
return returnType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void validate() {
|
|
||||||
// //TODO
|
|
||||||
// /*
|
|
||||||
// * here we could add checks like:
|
|
||||||
// * -If this method is in a class rather than an interface, and the name of the method is <init>, then the descriptor must denote a void method.
|
|
||||||
// * -If the name of the method is <clinit>, then the descriptor must denote avoid method, and, in a class file whose version number is 51.0 or above,a method that takes no arguments
|
|
||||||
// */
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
if (!super.equals(o)) return false;
|
|
||||||
BeMethod beMethod = (BeMethod) o;
|
|
||||||
return name.equals(beMethod.name) &&
|
|
||||||
returnType.equals(beMethod.returnType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(super.hashCode(), name, returnType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
package nl.sander.bejava.api;
|
|
||||||
|
|
||||||
import nl.sander.bejava.flags.ClassAccessFlags;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains parsed class elements like constructors and methods, but the opcode is not compiled to bytecode yet.
|
|
||||||
*/
|
|
||||||
public final class BeSource {
|
|
||||||
private final Set<ClassAccessFlags> accessFlags = new HashSet<>();
|
|
||||||
private final Set<Class<?>> interfaces = new HashSet<>();
|
|
||||||
private final Set<BeField> fields = new HashSet<>();
|
|
||||||
private final Set<BeConstructor> constructors = new HashSet<>();
|
|
||||||
private final Set<BeMethod> methods = new HashSet<>();
|
|
||||||
private Version classFileVersion;
|
|
||||||
private String name;
|
|
||||||
private Class<?> superClass = Object.class;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The classfile version
|
|
||||||
*/
|
|
||||||
public Version getClassFileVersion() {
|
|
||||||
return classFileVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClassFileVersion(Version classFileVersion) {
|
|
||||||
this.classFileVersion = classFileVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return all constructors that are provided with the class
|
|
||||||
*/
|
|
||||||
public Set<BeConstructor> getConstructors() {
|
|
||||||
return Collections.unmodifiableSet(constructors);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addConstructors(BeConstructor... constructors) {
|
|
||||||
this.constructors.addAll(Set.of(constructors));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return all methods that are provided with the class
|
|
||||||
*/
|
|
||||||
public Set<BeMethod> getMethods() {
|
|
||||||
return methods;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addMethods(BeMethod... methods) {
|
|
||||||
this.methods.addAll(Set.of(methods));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The access flags for the class
|
|
||||||
*/
|
|
||||||
public Set<ClassAccessFlags> getAccessFlags() {
|
|
||||||
return Collections.unmodifiableSet(accessFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add access flag eg public static etc
|
|
||||||
*
|
|
||||||
* @param classAccessFlags varargs of access flag
|
|
||||||
*/
|
|
||||||
public void addAccessFlags(ClassAccessFlags... classAccessFlags) {
|
|
||||||
this.accessFlags.addAll(Set.of(classAccessFlags));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The full name, like java.lang.Class
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The superclass
|
|
||||||
*/
|
|
||||||
public Class<?> getSuperClass() {
|
|
||||||
return superClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the super class. Default superclass is Object
|
|
||||||
* @param superClass The class to extend from.
|
|
||||||
*/
|
|
||||||
public void setSuperClass(Class<?> superClass) {
|
|
||||||
this.superClass = superClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return a list of unique interfaces that the class will implements
|
|
||||||
*/
|
|
||||||
public Set<Class<?>> getInterfaces() {
|
|
||||||
return Collections.unmodifiableSet(interfaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an interface to implement
|
|
||||||
* @param interfaces varargs array of interface class
|
|
||||||
*/
|
|
||||||
public void addInterfaces(Class<?>... interfaces) {
|
|
||||||
this.interfaces.addAll(Set.of(interfaces));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return a list of unique fields that the class will contain
|
|
||||||
*/
|
|
||||||
public Set<BeField> getFields() {
|
|
||||||
return Collections.unmodifiableSet(fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addFields(BeField... fields) {
|
|
||||||
this.fields.addAll(Set.of(fields));
|
|
||||||
}
|
|
||||||
|
|
||||||
public BeField getField(String fieldName) {
|
|
||||||
return fields.stream()
|
|
||||||
.filter(f -> f.getName().equals(fieldName))
|
|
||||||
.findAny()
|
|
||||||
.orElseThrow(() -> new IllegalArgumentException("field " + fieldName + " not found in " + getName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package nl.sander.bejava.api;
|
|
||||||
|
|
||||||
public class ClassInstruction extends Instruction {
|
|
||||||
private final ClassOperation classOperation;
|
|
||||||
|
|
||||||
public ClassInstruction(ClassOperation classOperation, String operand) {
|
|
||||||
super(operand);
|
|
||||||
this.classOperation = classOperation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOperand() {
|
|
||||||
return operand;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClassOperation getOperation() {
|
|
||||||
return classOperation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
package nl.sander.bejava.api;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public enum ClassOperation {
|
|
||||||
CLASS,
|
|
||||||
INTERFACE,
|
|
||||||
ENUM,
|
|
||||||
FIELD,
|
|
||||||
CONSTRUCTOR,
|
|
||||||
METHOD;
|
|
||||||
|
|
||||||
public static Optional<ClassOperation> get(String text){
|
|
||||||
String upper = text.toUpperCase();
|
|
||||||
for (ClassOperation val: ClassOperation.values()){
|
|
||||||
if (val.toString().equals(upper)){
|
|
||||||
return Optional.of(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
package nl.sander.bejava.api;
|
|
||||||
|
|
||||||
import nl.sander.bejava.JavaInstruction;
|
|
||||||
import nl.sander.bejava.TypeMapper;
|
|
||||||
import nl.sander.bejava.flags.MethodAccessFlag;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* parent of a constructor or a method.
|
|
||||||
*/
|
|
||||||
public abstract class CodeContainer {
|
|
||||||
|
|
||||||
protected final List<CodeLine> code = new LinkedList<>();
|
|
||||||
protected final Set<BeParameter> formalParameters = new HashSet<>();
|
|
||||||
protected final Set<MethodAccessFlag> accessFlags = new HashSet<>();
|
|
||||||
private final List<JavaInstruction> expandedCode = new ArrayList<>();
|
|
||||||
private BeSource owner;
|
|
||||||
|
|
||||||
public List<CodeLine> getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSignature() {
|
|
||||||
return getParametersSignature() + TypeMapper.map(getReturnType());
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract String getName();
|
|
||||||
|
|
||||||
public abstract Class<?> getReturnType();
|
|
||||||
|
|
||||||
private String getParametersSignature() {
|
|
||||||
return formalParameters.stream()
|
|
||||||
.map(BeParameter::getType)
|
|
||||||
.map(TypeMapper::map)
|
|
||||||
.collect(Collectors.joining(",", "(", ")"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<MethodAccessFlag> getAccessFlags() {
|
|
||||||
return accessFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BeSource getOwner() {
|
|
||||||
return owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOwner(BeSource beSource) {
|
|
||||||
if (owner != null) {
|
|
||||||
throw new IllegalStateException("Owner set twice. Sue the developer!");
|
|
||||||
}
|
|
||||||
this.owner = beSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<JavaInstruction> getExpandedCode() {
|
|
||||||
return Collections.unmodifiableList(expandedCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExpandedCode(List<JavaInstruction> instructions) {
|
|
||||||
expandedCode.clear();
|
|
||||||
expandedCode.addAll(instructions);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<BeParameter> getFormalParameters() {
|
|
||||||
return formalParameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<BeParameter> getParameter(String parameterName) {
|
|
||||||
return formalParameters.stream().filter(p -> parameterName.equals(p.getName())).findAny();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
CodeContainer that = (CodeContainer) o;
|
|
||||||
return formalParameters.equals(that.formalParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(formalParameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package nl.sander.bejava.api;
|
|
||||||
|
|
||||||
|
|
||||||
public class CodeLine extends Instruction {
|
|
||||||
private final Opcode opcode;
|
|
||||||
private CodeContainer owner;
|
|
||||||
|
|
||||||
public CodeLine(Opcode opcode, String operand) {
|
|
||||||
super(operand);
|
|
||||||
this.opcode = opcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOperand() {
|
|
||||||
return operand;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Opcode getOpcode() {
|
|
||||||
return opcode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
package nl.sander.bejava.api;
|
|
||||||
|
|
||||||
public class Instruction {
|
|
||||||
protected final String operand;
|
|
||||||
|
|
||||||
public Instruction(String operand) {
|
|
||||||
this.operand = operand;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
package nl.sander.bejava.api;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public enum Opcode {
|
|
||||||
LOAD,
|
|
||||||
STORE,
|
|
||||||
CONST,
|
|
||||||
RETURN,
|
|
||||||
ARRAYLENGTH,
|
|
||||||
THROW,
|
|
||||||
CAST,
|
|
||||||
ADD,
|
|
||||||
COMPARE,
|
|
||||||
DIVIDE,
|
|
||||||
MULTIPLY,
|
|
||||||
NEGATE,
|
|
||||||
REMAINDER,
|
|
||||||
SUBTRACT,
|
|
||||||
GET,
|
|
||||||
GOTO,
|
|
||||||
TO_DOUBLE,
|
|
||||||
TO_INT,
|
|
||||||
TO_LONG,
|
|
||||||
TO_BYTE,
|
|
||||||
TO_CHAR,
|
|
||||||
TO_FLOAT,
|
|
||||||
TO_SHORT,
|
|
||||||
AND,
|
|
||||||
IF_EQUAL,
|
|
||||||
IF_NOT_EQUAL,
|
|
||||||
IF_LESS_THAN,
|
|
||||||
IF_GREATER_OR_EQUAL,
|
|
||||||
IF_GREATER_THAN,
|
|
||||||
IF_LESS_OR_EQUAL,
|
|
||||||
IF_NOT_NULL,
|
|
||||||
IF_NULL,
|
|
||||||
INCREMENT,
|
|
||||||
INSTANCEOF,
|
|
||||||
INVOKE,
|
|
||||||
OR,
|
|
||||||
SHIFT_LEFT,
|
|
||||||
SHIFT_RIGHT,
|
|
||||||
LOGICAL_SHIFT_RIGHT,
|
|
||||||
XOR,
|
|
||||||
LOOKUPSWITCH,
|
|
||||||
MONITORENTER,
|
|
||||||
MONITOREXIT,
|
|
||||||
NEW,
|
|
||||||
NEWARRAY,
|
|
||||||
MULTIANEWARRAY,
|
|
||||||
PUT,
|
|
||||||
SWAP,
|
|
||||||
TABLESWITCH,
|
|
||||||
WIDE;
|
|
||||||
|
|
||||||
public static Optional<Opcode> get(String text) {
|
|
||||||
for (Opcode opcode : Opcode.values()) {
|
|
||||||
if (opcode.toString().equals(text)) {
|
|
||||||
return Optional.of(opcode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package nl.sander.bejava.operands;
|
|
||||||
|
|
||||||
import nl.sander.bejava.Primitive;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The operand is a constant
|
|
||||||
*/
|
|
||||||
public class ConstantOperand extends Operand {
|
|
||||||
private final Primitive type;
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
|
|
||||||
public ConstantOperand(Primitive type, String value) {
|
|
||||||
this.type = type;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Primitive getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package nl.sander.bejava.operands;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The operand is a field member of the class
|
|
||||||
*/
|
|
||||||
public class FieldOperand extends Operand{
|
|
||||||
public final String className;
|
|
||||||
public final String fieldName;
|
|
||||||
|
|
||||||
public FieldOperand(String className, String fieldName) {
|
|
||||||
this.className = className;
|
|
||||||
this.fieldName = fieldName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
package nl.sander.bejava.operands;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The operand is a local variable
|
|
||||||
*/
|
|
||||||
public class LocalVariableOperand extends Operand{
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
public LocalVariableOperand(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package nl.sander.bejava.operands;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The operand is a method call.
|
|
||||||
*/
|
|
||||||
public class MethodOperand extends Operand{
|
|
||||||
public final String className;
|
|
||||||
public final String methodName;
|
|
||||||
public final String signature;
|
|
||||||
|
|
||||||
public MethodOperand(String className, String methodName, String signature) {
|
|
||||||
this.className = className;
|
|
||||||
this.methodName = methodName;
|
|
||||||
this.signature = signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "MethodOperand{" +
|
|
||||||
"className='" + className + '\'' +
|
|
||||||
", methodName='" + methodName + '\'' +
|
|
||||||
", signature='" + signature + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
package nl.sander.bejava.operands;
|
|
||||||
|
|
||||||
public abstract class Operand {
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package nl.sander.bejava.operands;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The operand is void. An operand is compulsory in a {@link nl.sander.bejava.JavaInstruction}.
|
|
||||||
* Used when the opcode is RETURN and the return type is void.
|
|
||||||
*/
|
|
||||||
public class VoidOperand extends Operand{
|
|
||||||
public final static VoidOperand INSTANCE = new VoidOperand();
|
|
||||||
|
|
||||||
private VoidOperand() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java
Normal file
29
src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package nl.sander.beejava;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class BytecodeGeneratorTests {
|
||||||
|
@Test
|
||||||
|
public void testEmpty() throws IOException, ClassNotFoundException {
|
||||||
|
byte[] bytecode = BytecodeGenerator.generate(Compiler.compile(TestData.createEmptyClass()));
|
||||||
|
File dir = new File("target/nl/sander/beejava/test");
|
||||||
|
dir.mkdirs();
|
||||||
|
try (FileOutputStream outputStream = new FileOutputStream(new File(dir, "EmptyBean.class"))) {
|
||||||
|
outputStream.write(bytecode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInterface() throws ClassNotFoundException {
|
||||||
|
BytecodeGenerator.generate(Compiler.compile(TestData.emptyClassWithInterface()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFields() throws ClassNotFoundException {
|
||||||
|
BytecodeGenerator.generate(Compiler.compile(TestData.createClassWithField(int.class)));
|
||||||
|
}
|
||||||
|
}
|
||||||
66
src/test/java/nl/sander/beejava/CompilerTests.java
Normal file
66
src/test/java/nl/sander/beejava/CompilerTests.java
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
package nl.sander.beejava;
|
||||||
|
|
||||||
|
import nl.sander.beejava.api.*;
|
||||||
|
import nl.sander.beejava.constantpool.entry.*;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static nl.sander.beejava.api.CodeLine.line;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class CompilerTests {
|
||||||
|
|
||||||
|
// creates simplest class possible and checks the tree, that the ConstantTreeCreator emits
|
||||||
|
@Test // This is not a maintainable test
|
||||||
|
public void testMethodRefEntryForSuperConstructor() throws ClassNotFoundException {
|
||||||
|
// Arrange
|
||||||
|
BeeSource classWithIntField = TestData.createEmptyClass();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
CompiledClass compiledClass = Compiler.compile(classWithIntField);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Set<ConstantPoolEntry> constantTree = compiledClass.getConstantTree();
|
||||||
|
assertEquals(3, constantTree.size());
|
||||||
|
ConstantPoolEntry superConstructor = constantTree.iterator().next();
|
||||||
|
|
||||||
|
assertEquals(MethodRefEntry.class, superConstructor.getClass());
|
||||||
|
MethodRefEntry methodRefEntry = (MethodRefEntry) superConstructor;
|
||||||
|
|
||||||
|
Set<ConstantPoolEntry> methodRefEntryChildren = methodRefEntry.getChildren();
|
||||||
|
assertEquals(2, methodRefEntryChildren.size());
|
||||||
|
|
||||||
|
Iterator<ConstantPoolEntry> firstChildren = methodRefEntryChildren.iterator();
|
||||||
|
ConstantPoolEntry child1 = firstChildren.next();
|
||||||
|
assertEquals(ClassEntry.class, child1.getClass());
|
||||||
|
ClassEntry classEntry = (ClassEntry) child1;
|
||||||
|
|
||||||
|
Set<ConstantPoolEntry> classEntryChildren = classEntry.getChildren();
|
||||||
|
assertEquals(1, classEntryChildren.size());
|
||||||
|
ConstantPoolEntry child2 = classEntryChildren.iterator().next();
|
||||||
|
|
||||||
|
assertEquals(Utf8Entry.class, child2.getClass());
|
||||||
|
Utf8Entry className = (Utf8Entry) child2;
|
||||||
|
assertEquals("java/lang/Object", className.getUtf8());
|
||||||
|
|
||||||
|
ConstantPoolEntry child3 = firstChildren.next();
|
||||||
|
assertEquals(NameAndTypeEntry.class, child3.getClass());
|
||||||
|
NameAndTypeEntry nameAndTypeEntry = (NameAndTypeEntry) child3;
|
||||||
|
|
||||||
|
Set<ConstantPoolEntry> nameAndTypeEntryChildren = nameAndTypeEntry.getChildren();
|
||||||
|
assertEquals(2, nameAndTypeEntryChildren.size());
|
||||||
|
Iterator<ConstantPoolEntry> nameAndTypeChildrenIterator = nameAndTypeEntryChildren.iterator();
|
||||||
|
|
||||||
|
ConstantPoolEntry child4 = nameAndTypeChildrenIterator.next();
|
||||||
|
assertEquals(Utf8Entry.class, child4.getClass());
|
||||||
|
Utf8Entry name = (Utf8Entry) child4;
|
||||||
|
assertEquals("<init>", name.getUtf8());
|
||||||
|
|
||||||
|
ConstantPoolEntry child5 = nameAndTypeChildrenIterator.next();
|
||||||
|
assertEquals(Utf8Entry.class, child5.getClass());
|
||||||
|
Utf8Entry type = (Utf8Entry) child5;
|
||||||
|
assertEquals("()V", type.getUtf8());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
package nl.sander.beejava;
|
||||||
|
|
||||||
|
import nl.sander.beejava.api.BeeSource;
|
||||||
|
import nl.sander.beejava.constantpool.ConstantPool;
|
||||||
|
import nl.sander.beejava.constantpool.entry.ClassEntry;
|
||||||
|
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class ConstantPoolUniquenessTests {
|
||||||
|
@Test
|
||||||
|
public void test() throws Exception {
|
||||||
|
// Arrange
|
||||||
|
BeeSource someClass = TestData.createEmptyClass();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
CompiledClass compiledClass = Compiler.compile(someClass);
|
||||||
|
ConstantPool constantPool = new ConstantPoolCreator().createConstantPool(compiledClass.getConstantTree());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
List<ClassEntry> refsToSystem = constantPool.stream()
|
||||||
|
.filter(cpe -> cpe instanceof ClassEntry)
|
||||||
|
.map(cpe -> (ClassEntry) cpe)
|
||||||
|
.filter(ce -> ce.getName().equals("java/lang/System"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
assertEquals(0, refsToSystem.size());
|
||||||
|
|
||||||
|
|
||||||
|
byte[] bytecode = BytecodeGenerator.generate(compiledClass);
|
||||||
|
|
||||||
|
int x = 1;
|
||||||
|
for (ConstantPoolEntry e : constantPool) {
|
||||||
|
System.out.println((x++) + ":" + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
x = 1;
|
||||||
|
for (ConstantPoolEntry e : constantPool) {
|
||||||
|
System.out.print((x++) + ":");
|
||||||
|
printBytes(e.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File dir = new File("target/nl/sander/beejava/test");
|
||||||
|
dir.mkdirs();
|
||||||
|
try (FileOutputStream outputStream = new FileOutputStream(new File(dir, "EmptyBean.class"))) {
|
||||||
|
outputStream.write(bytecode);
|
||||||
|
}
|
||||||
|
printBytes2(bytecode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO remove
|
||||||
|
private void printBytes(byte[] bytes) {
|
||||||
|
for (byte b : bytes) {
|
||||||
|
System.out.print(String.format("%2s", Integer.toHexString(b & 0xFF)).replace(' ', '0') + " ");
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printBytes2(byte[] bytes) {
|
||||||
|
int count = 0;
|
||||||
|
for (byte b : bytes) {
|
||||||
|
System.out.print(String.format("%2s", Integer.toHexString(b & 0xFF)).replace(' ', '0') + (count % 2 == 0 ? "" : " "));
|
||||||
|
count += 1;
|
||||||
|
if (count > 15) {
|
||||||
|
count = 0;
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
113
src/test/java/nl/sander/beejava/TestData.java
Normal file
113
src/test/java/nl/sander/beejava/TestData.java
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
package nl.sander.beejava;
|
||||||
|
|
||||||
|
import nl.sander.beejava.api.*;
|
||||||
|
import nl.sander.beejava.flags.FieldAccessFlags;
|
||||||
|
import nl.sander.beejava.flags.MethodAccessFlags;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import static nl.sander.beejava.api.CodeLine.line;
|
||||||
|
import static nl.sander.beejava.api.Opcode.*;
|
||||||
|
import static nl.sander.beejava.flags.ClassAccessFlags.PUBLIC;
|
||||||
|
import static nl.sander.beejava.flags.ClassAccessFlags.SUPER;
|
||||||
|
|
||||||
|
public class TestData {
|
||||||
|
public static BeeSource createEmptyClass() throws ClassNotFoundException {
|
||||||
|
return BeeSource.builder()
|
||||||
|
.withClassFileVersion(Version.V14)
|
||||||
|
.withPackage("nl.sander.beejava.test")
|
||||||
|
.withAccessFlags(PUBLIC, SUPER)
|
||||||
|
.withSimpleName("EmptyBean")
|
||||||
|
.withSuperClass(Object.class) // Not mandatory, like in java sourcecode
|
||||||
|
.withConstructors(createDefaultConstructor()) // There's no default constructor in beejava. The user must always add them
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BeeSource emptyClassWithInterface() throws ClassNotFoundException {
|
||||||
|
return BeeSource.builder()
|
||||||
|
.withClassFileVersion(Version.V14)
|
||||||
|
.withPackage("nl.sander.beejava.test")
|
||||||
|
.withAccessFlags(PUBLIC)
|
||||||
|
.withSimpleName("EmptyBean")
|
||||||
|
.withSuperClass(Object.class) // Not mandatory, like in java sourcecode
|
||||||
|
.withInterfaces(Serializable.class)
|
||||||
|
.withConstructors(createDefaultConstructor()) // There's no default constructor in beejava. The user must always add them
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BeeSource createClassWithTwoReferencesToSomeClass() throws ClassNotFoundException {
|
||||||
|
BeeMethod print1 = BeeMethod.builder()
|
||||||
|
.withName("print1")
|
||||||
|
.withAccessFlags(MethodAccessFlags.PUBLIC)
|
||||||
|
.withCode(
|
||||||
|
line(0, GET, "java.lang.System","out"),
|
||||||
|
line(1, LD_CONST, "1"),
|
||||||
|
line(2, INVOKE, "java.io.PrintStream", "println", "java.lang.String"),
|
||||||
|
line(3, RETURN))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// INVOKE System.out.println("1")
|
||||||
|
|
||||||
|
|
||||||
|
BeeMethod print2 = BeeMethod.builder()
|
||||||
|
.withName("print2")
|
||||||
|
.withAccessFlags(MethodAccessFlags.PUBLIC)
|
||||||
|
.withCode(
|
||||||
|
line(0, GET, "java.lang.System","out"),
|
||||||
|
line(1, LD_CONST, "2"),
|
||||||
|
line(2, INVOKE, "java.io.PrintStream", "println", "java.lang.String"),
|
||||||
|
line(3, RETURN))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return BeeSource.builder()
|
||||||
|
.withClassFileVersion(Version.V14)
|
||||||
|
.withPackage("nl.sander.beejava.test")
|
||||||
|
.withAccessFlags(PUBLIC, SUPER)
|
||||||
|
.withSimpleName("ClassWithReferences")
|
||||||
|
.withConstructors(createDefaultConstructor()) // There's no default constructor in beejava. The user must always add them
|
||||||
|
.withMethods(print1, print2)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BeeSource createClassWithField(Class<?> fieldType) throws ClassNotFoundException {
|
||||||
|
BeeField field = BeeField.builder()
|
||||||
|
.withAccessFlags(FieldAccessFlags.PRIVATE)
|
||||||
|
.withType(fieldType)
|
||||||
|
.withName("field")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
BeeParameter parameter = BeeParameter.create(fieldType, "value");
|
||||||
|
|
||||||
|
BeeConstructor constructor = BeeConstructor.builder()
|
||||||
|
.withAccessFlags(MethodAccessFlags.PUBLIC)
|
||||||
|
.withFormalParameters(parameter)
|
||||||
|
.withCode(
|
||||||
|
line(0, LD_VAR, Ref.THIS),
|
||||||
|
line(1, INVOKE, Ref.SUPER, "<init>", "()"),
|
||||||
|
line(2, LD_VAR, Ref.THIS),
|
||||||
|
line(3, LD_VAR, parameter),
|
||||||
|
line(4, PUT, field),
|
||||||
|
line(5, RETURN))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return BeeSource.builder()
|
||||||
|
.withClassFileVersion(Version.V14)
|
||||||
|
.withPackage("nl.sander.beejava.test")
|
||||||
|
.withAccessFlags(PUBLIC)
|
||||||
|
.withSimpleName("Bean")
|
||||||
|
.withSuperClass(Object.class)
|
||||||
|
.withFields(field)
|
||||||
|
.withConstructors(constructor)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BeeConstructor createDefaultConstructor() throws ClassNotFoundException {
|
||||||
|
return BeeConstructor.builder()
|
||||||
|
.withAccessFlags(MethodAccessFlags.PUBLIC)
|
||||||
|
.withCode(
|
||||||
|
line(0, LD_VAR, Ref.THIS),
|
||||||
|
line(1, INVOKE, Ref.SUPER, "<init>", "()"),
|
||||||
|
line(5, RETURN))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package nl.sander.bejava;
|
package nl.sander.beejava;
|
||||||
|
|
||||||
import nl.sander.bejava.api.BeSource;
|
import nl.sander.beejava.api.BeeSource;
|
||||||
import nl.sander.bejava.constantpool.ConstantPool;
|
import nl.sander.beejava.constantpool.ConstantPool;
|
||||||
import nl.sander.bejava.constantpool.entry.NameAndTypeEntry;
|
import nl.sander.beejava.constantpool.entry.NameAndTypeEntry;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
@ -11,12 +11,12 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||||
public class TypeMapperTest {
|
public class TypeMapperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_int() {
|
public void test_int() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(int.class);
|
BeeSource beeSource = TestData.createClassWithField(int.class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
|
|
@ -24,12 +24,12 @@ public class TypeMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_double() {
|
public void test_double() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(double.class);
|
BeeSource beeSource = TestData.createClassWithField(double.class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
|
|
@ -37,12 +37,12 @@ public class TypeMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_float() {
|
public void test_float() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(float.class);
|
BeeSource beeSource = TestData.createClassWithField(float.class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
|
|
@ -50,12 +50,12 @@ public class TypeMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_byte() {
|
public void test_byte() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(byte.class);
|
BeeSource beeSource = TestData.createClassWithField(byte.class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
|
|
@ -63,12 +63,12 @@ public class TypeMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_short() {
|
public void test_short() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(short.class);
|
BeeSource beeSource = TestData.createClassWithField(short.class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
|
|
@ -76,12 +76,12 @@ public class TypeMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_long() {
|
public void test_long() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(long.class);
|
BeeSource beeSource = TestData.createClassWithField(long.class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
|
|
@ -89,12 +89,12 @@ public class TypeMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_char() {
|
public void test_char() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(char.class);
|
BeeSource beeSource = TestData.createClassWithField(char.class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
|
|
@ -102,12 +102,12 @@ public class TypeMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_boolean() {
|
public void test_boolean() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(boolean.class);
|
BeeSource beeSource = TestData.createClassWithField(boolean.class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
|
|
@ -115,12 +115,12 @@ public class TypeMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_Object() {
|
public void test_Object() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(Object.class);
|
BeeSource beeSource = TestData.createClassWithField(Object.class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
|
|
@ -128,12 +128,12 @@ public class TypeMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_int_array() {
|
public void test_int_array() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(int[].class);
|
BeeSource beeSource = TestData.createClassWithField(int[].class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
|
|
@ -141,20 +141,20 @@ public class TypeMapperTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_Object_array() {
|
public void test_Object_array() throws ClassNotFoundException {
|
||||||
// Arrange
|
// Arrange
|
||||||
BeSource beSource = createClassWithField(String[].class);
|
BeeSource beeSource = TestData.createClassWithField(String[].class);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
ConstantPool constantPool = createConstantPool(beSource);
|
ConstantPool constantPool = createConstantPool(beeSource);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
|
||||||
assertEquals("[Ljava/lang/String;", fieldEntry.getType());
|
assertEquals("[Ljava/lang/String;", fieldEntry.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConstantPool createConstantPool(BeSource beSource) {
|
private ConstantPool createConstantPool(BeeSource beeSource) {
|
||||||
CompiledClass compiledClass = Compiler.compile(beSource);
|
CompiledClass compiledClass = Compiler.compile(beeSource);
|
||||||
return ConstantPoolCreator.create(compiledClass.getConstantTree());
|
return ConstantPoolCreator.create(compiledClass.getConstantTree());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,18 +165,4 @@ public class TypeMapperTest {
|
||||||
.filter(nate -> nate.getName().equals("field"))
|
.filter(nate -> nate.getName().equals("field"))
|
||||||
.findAny().orElseGet(() -> fail("'field' not found"));
|
.findAny().orElseGet(() -> fail("'field' not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeSource createClassWithField(Class<?> fieldType) {
|
|
||||||
String template = """
|
|
||||||
class com.acme.SimpleBean(V15)
|
|
||||||
field private %s field
|
|
||||||
constructor public(%s arg)
|
|
||||||
INVOKE this.super()V
|
|
||||||
LOAD arg
|
|
||||||
PUT this.field
|
|
||||||
RETURN
|
|
||||||
""";
|
|
||||||
|
|
||||||
return SourceCompiler.compile(String.format(template, fieldType.getName(), fieldType.getName()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ public class TagCorrectnessTest {
|
||||||
public void testSpec() {
|
public void testSpec() {
|
||||||
assertEquals(1, utf8().getTag());
|
assertEquals(1, utf8().getTag());
|
||||||
assertEquals(3, new IntegerEntry(0).getTag());
|
assertEquals(3, new IntegerEntry(0).getTag());
|
||||||
assertEquals(4, new FloatEntry(0F).getTag());
|
assertEquals(4, new FloatEntry(0).getTag());
|
||||||
assertEquals(5, new LongEntry(0).getTag());
|
assertEquals(5, new LongEntry(0).getTag());
|
||||||
assertEquals(6, new DoubleEntry(0).getTag());
|
assertEquals(6, new DoubleEntry(0).getTag());
|
||||||
assertEquals(7, classEntry().getTag());
|
assertEquals(7, classEntry().getTag());
|
||||||
48
src/test/java/nl/sander/beejava/e2e/BeanWithMethodsTest.java
Normal file
48
src/test/java/nl/sander/beejava/e2e/BeanWithMethodsTest.java
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
package nl.sander.beejava.e2e;
|
||||||
|
|
||||||
|
import nl.sander.beejava.BytecodeGenerator;
|
||||||
|
import nl.sander.beejava.CompiledClass;
|
||||||
|
import nl.sander.beejava.Compiler;
|
||||||
|
import nl.sander.beejava.TestData;
|
||||||
|
import nl.sander.beejava.api.BeeSource;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A rather simple case, still meaningful nonetheless.
|
||||||
|
* Green means class can be loaded, so the class file structure is valid.
|
||||||
|
* The EmptyBean class just contains a default constructor.
|
||||||
|
*/
|
||||||
|
public class BeanWithMethodsTest {
|
||||||
|
@Test
|
||||||
|
public void testEmptyBean() throws Exception {
|
||||||
|
// Arrange
|
||||||
|
BeeSource emptyClass = TestData.createClassWithTwoReferencesToSomeClass();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
CompiledClass compiledClass = Compiler.compile(emptyClass);
|
||||||
|
byte[] bytecode = BytecodeGenerator.generate(compiledClass);
|
||||||
|
|
||||||
|
ByteClassLoader classLoader = new ByteClassLoader();
|
||||||
|
classLoader.setByteCode("nl.sander.beejava.test.ClassWithReferences", bytecode);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Class<?> classWithReferences = classLoader.loadClass("nl.sander.beejava.test.ClassWithReferences");
|
||||||
|
assertNotNull(classWithReferences);
|
||||||
|
|
||||||
|
Method[] methods = classWithReferences.getDeclaredMethods();
|
||||||
|
assertEquals(2, methods.length);
|
||||||
|
assertEquals("print1", methods[0].getName());
|
||||||
|
assertTrue(Modifier.isPublic(methods[0].getModifiers()));
|
||||||
|
assertEquals(0,methods[0].getParameterCount());
|
||||||
|
|
||||||
|
assertEquals("print2", methods[1].getName()); // ordering may cause failures
|
||||||
|
assertTrue(Modifier.isPublic(methods[1].getModifiers()));
|
||||||
|
assertEquals(0,methods[1].getParameterCount());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.e2e;
|
package nl.sander.beejava.e2e;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
69
src/test/java/nl/sander/beejava/e2e/EmptyBeanTest.java
Normal file
69
src/test/java/nl/sander/beejava/e2e/EmptyBeanTest.java
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
package nl.sander.beejava.e2e;
|
||||||
|
|
||||||
|
import nl.sander.beejava.BytecodeGenerator;
|
||||||
|
import nl.sander.beejava.CompiledClass;
|
||||||
|
import nl.sander.beejava.Compiler;
|
||||||
|
import nl.sander.beejava.TestData;
|
||||||
|
import nl.sander.beejava.api.BeeConstructor;
|
||||||
|
import nl.sander.beejava.api.BeeSource;
|
||||||
|
import nl.sander.beejava.api.Ref;
|
||||||
|
import nl.sander.beejava.api.Version;
|
||||||
|
import nl.sander.beejava.flags.MethodAccessFlags;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
|
import static nl.sander.beejava.api.CodeLine.line;
|
||||||
|
import static nl.sander.beejava.api.Opcode.*;
|
||||||
|
import static nl.sander.beejava.flags.ClassAccessFlags.PUBLIC;
|
||||||
|
import static nl.sander.beejava.flags.ClassAccessFlags.SUPER;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A rather simple case, still meaningful nonetheless.
|
||||||
|
* Green means class can be loaded, so the class file structure is valid.
|
||||||
|
* The EmptyBean class just contains a default constructor.
|
||||||
|
*/
|
||||||
|
public class EmptyBeanTest {
|
||||||
|
@Test
|
||||||
|
public void testEmptyBean() throws Exception {
|
||||||
|
// Arrange
|
||||||
|
BeeSource emptyClass = createEmptyClass();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
CompiledClass compiledClass = Compiler.compile(emptyClass);
|
||||||
|
byte[] bytecode = BytecodeGenerator.generate(compiledClass);
|
||||||
|
|
||||||
|
ByteClassLoader classLoader = new ByteClassLoader();
|
||||||
|
classLoader.setByteCode("nl.sander.beejava.test.EmptyBean", bytecode);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Constructor<?> constructor = classLoader.loadClass("nl.sander.beejava.test.EmptyBean").getConstructor();
|
||||||
|
assertNotNull(constructor);
|
||||||
|
|
||||||
|
Object instance = constructor.newInstance();
|
||||||
|
assertNotNull(instance);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private BeeSource createEmptyClass() throws ClassNotFoundException {
|
||||||
|
return BeeSource.builder()
|
||||||
|
.withClassFileVersion(Version.V14)
|
||||||
|
.withPackage("nl.sander.beejava.test")
|
||||||
|
.withAccessFlags(PUBLIC, SUPER)
|
||||||
|
.withSimpleName("EmptyBean")
|
||||||
|
.withSuperClass(Object.class) // Not mandatory, like in java sourcecode
|
||||||
|
.withConstructors(createDefaultConstructor()) // There's no default constructor in beejava. The user must always add them
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BeeConstructor createDefaultConstructor() throws ClassNotFoundException {
|
||||||
|
return BeeConstructor.builder()
|
||||||
|
.withAccessFlags(MethodAccessFlags.PUBLIC)
|
||||||
|
.withCode(
|
||||||
|
line(0, LD_VAR, Ref.THIS),
|
||||||
|
line(1, INVOKE, Ref.SUPER, "<init>", "()"),
|
||||||
|
line(5, RETURN))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.flags;
|
package nl.sander.beejava.flags;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.testclasses;
|
package nl.sander.beejava.testclasses;
|
||||||
|
|
||||||
// two references to System. System should not be in the constant pool twice.
|
// two references to System. System should not be in the constant pool twice.
|
||||||
public class BeanWithClassReferences {
|
public class BeanWithClassReferences {
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package nl.sander.bejava.testclasses;
|
package nl.sander.beejava.testclasses;
|
||||||
|
|
||||||
public class Dummy {
|
public class Dummy {
|
||||||
public String hello(String goodbye){
|
public String hello(String goodbye){
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue