├── .gitignore ├── COPYING ├── README.md ├── TODO ├── backend ├── .gitignore ├── Doxyfile ├── Makefile ├── backend.cpp ├── backend.h ├── block.cpp ├── branch.cpp ├── const.cpp ├── function.cpp ├── instruction.cpp ├── loadstore.cpp ├── main.cpp ├── name.cpp ├── printinst.cpp ├── sections.cpp └── types.cpp ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src ├── main └── java │ └── lljvm │ ├── io │ ├── AbstractFileHandle.java │ ├── DefaultStandardHandleFactory.java │ ├── FileHandle.java │ ├── FileSystem.java │ ├── InputStreamFileHandle.java │ ├── NativeFileSystem.java │ ├── OutputStreamFileHandle.java │ ├── RandomAccessFileHandle.java │ ├── StandardHandleFactory.java │ ├── StreamStandardHandleFactory.java │ └── package-info.java │ ├── runtime │ ├── Error.java │ ├── IO.java │ ├── Instruction.java │ ├── Jump.java │ ├── JumpFunctions.java │ ├── Math.java │ ├── Memory.java │ ├── Posix.java │ └── System.java │ └── util │ ├── ClassInfo.java │ ├── ClassName.java │ ├── FieldInfo.java │ ├── MemberInfo.java │ ├── MethodInfo.java │ ├── ReflectionUtils.java │ ├── StreamUtils.java │ └── package-info.java └── test └── java └── ghcjvm └── tests └── runtime ├── ErrorTests.java └── MemoryTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | doc/ 2 | /lib/ 3 | lljvm-*.jar 4 | lljvm-demo-*.jar 5 | lljvm-doc-*.zip 6 | lljvm-backend 7 | *~ 8 | Session.vim 9 | 10 | #gradle files 11 | build/ 12 | .gradle/ 13 | 14 | #ctags 15 | tags 16 | 17 | #vim swap 18 | *.swp 19 | 20 | #eclipse project files 21 | #regenerate with `gradle eclipse` 22 | .classpath 23 | .settings/ 24 | .project 25 | bin/ 26 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2009-2010 David Roberts 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **LLJVM** provides a set of tools and libraries for running comparatively low level 2 | languages (such as C) on the JVM. 3 | 4 | The C to JVM bytecode compilation provided by LLJVM involves several steps. Source code is first compiled to [LLVM][llvm] intermediate representation (IR) by a frontend such as `llvm-gcc` or [clang][clang]. LLVM IR is then translated to [Jasmin][jasmin] assembly code, linked against other Java classes, and then assembled to JVM bytecode. 5 | 6 | The use of LLVM IR as the intermediate representation allows more information about the source program to be preserved, compared to other methods which use MIPS binary as the intermediate representation (such as [NestedVM][nestedvm] and [Cibyl][cibyl]). For example, functions are mapped to individual JVM methods, and all function calls are made with native JVM invocation instructions. This allows compiled code to be linked against arbitrary Java classes, and Java programs to natively call individual functions in the compiled code. It also allows programs to be split across multiple classes (comparable to dynamic linking), rather than statically linking everything into a single class. 7 | 8 | Also note that while C is currently the only supported input language, any language with a compiler targeting LLVM IR could potentially be supported. 9 | 10 | For a **quick demonstration** of some pre-compiled classes, download the [runtime library][lljvm-jar] and the [demo package][lljvm-demo-jar] to a directory on your machine, and run `java -jar lljvm-demo-0.2.jar`. 11 | 12 | To **quickly start** translating your own programs you might want to use [Docker][docker]. Getting LLJVM to run on modern machines (and keeping it running) can be quite tricky as it depends heavily on an old version of LLVM. As an alternative, Martin Haye has set up a virtual machine image [here][mhaye-lljvm] that is pre-configured for and includes LLJVM. Install Docker (you may need Boot2Docker) and start it this way: `docker run -i -v /your/project/dir:/project -t mhaye/lljvm /bin/bash` 13 | 14 | To compile LLJVM from source, follow the instructions below. If you have problems compiling from source and are running Linux on an i386-compatible platform, download the [binary release][lljvm-bin], extract it, and download the [runtime library][lljvm-jar] into the resulting directory. 15 | 16 | - [HN comments][hn-lljvm] 17 | - 2009-2015 [David A Roberts](https://davidar.io) 18 | 19 | 20 | ## INSTALLATION 21 | [LLVM 2.7][llvm] must be installed to compile and run LLJVM. [Jasmin][jasmin] is needed for 22 | assembling JVM bytecode. 23 | 24 | To compile LLJVM, simply call `make` in the project root directory, and call 25 | `make check` to run the testsuite. 26 | 27 | To generate the the documentation for the java packages and the backend, call 28 | `make doc`, which will generate HTML documentation in `doc/java/` and 29 | `doc/backend/` respectively. PDF documentation for the backend can be obtained by 30 | calling `make doc-pdf` (requires PDFLaTeX), which will generate 31 | `doc/backend.pdf`. A zip archive containing all of the documentation can be 32 | created by calling `make doc-zip`. 33 | 34 | 35 | ## C COMPILER 36 | The `lljvm-cc` frontend ties together several components to provide a C source 37 | code to JVM class file compiler. 38 | 39 | In order to use the frontend, either `llvm-gcc` or `clang` must be installed. 40 | `llvm-gcc` is recommended, and is used instead of `clang` if both are available. 41 | It is also required that the classpath contain [jasmin.jar][jasmin-jar]. 42 | 43 | To compile a small number of source files to a class file, the following style 44 | of command can be used: 45 | 46 | lljvm-cc foo.c bar.c -o foo 47 | 48 | This will generate `foo.class`, as well as a shell script `foo`, which sets the 49 | classpath appropriately and executes the classfile with the arguments passed to 50 | it. This allows the class to be called in the same way as any other executable. 51 | If calling the class without the shell script, note that the entire list of 52 | arguments must be passed to the class, including argument 0 (the name of the 53 | command). 54 | 55 | For a larger number of source files, it is often more efficient to separately 56 | compile each file to an object file as needed: 57 | 58 | lljvm-cc -c foo.c 59 | then link the object files together into a class file: 60 | 61 | lljvm-cc -link foo.o bar.o baz.o -o foo 62 | Note that the -link flag must be used if object files are being supplied 63 | instead of source files. 64 | 65 | To link the object files together as a library instead of an executable, 66 | `-link-as-library` can be passed instead of `-link`. In this case the shell script 67 | will not be generated. 68 | 69 | To link against a library generated by `lljvm-cc`, the `-l` flag can be used. 70 | This will search for a library in the classpath called `lib.class`. 71 | Additional directories can be added to the classpath with the `-L` flag. 72 | Such additions to the classpath will also be added to the shell script, so 73 | when linking an executable, the `-L` flag must be passed for each directory 74 | containing libraries needed by the executable (except the current directory and 75 | directories in the system classpath). 76 | 77 | An exception to the above is the `-lm` flag. This will not search for `libm.class`, 78 | but will rather link against `java.lang.Math` and `lljvm.runtime.Math`. Also, `-lc` 79 | should not be used as `libc` is linked by default. If this is not desired, then 80 | the `-nostdlib` flag can be used. 81 | 82 | By default all classes generated are placed in the default package. To assign 83 | the class to a specific package, the `-classname` flag can be used. For example, 84 | the following command: 85 | 86 | lljvm-cc ... -classname=com.example.foo -o bar/baz 87 | will create a class named foo, in the package com.example, placing it in the 88 | directory `bar/com/example/`. The shell script will be output to `bar/baz`. 89 | 90 | If the `-g3` flag is used, then Jasmin assembly with full debugging information 91 | will be output to `.j`. 92 | 93 | In addition to the above flags, any flag accepted by `gcc` or `ld` can also be 94 | used. However, sometimes these flags may not be passed to the correct 95 | component (this is a bug with `lljvm-cc` and should be reported). 96 | 97 | The frontend can also be used to compile `autoconf`-based projects relatively 98 | easily (although sometimes some changes to the project's build system may be 99 | required): 100 | 101 | ./configure CC=lljvm-cc LD='lljvm-cc -link' 102 | make CCLD='lljvm-cc -link' 103 | 104 | 105 | ## DEMO 106 | To demonstrate the capabilities of LLJVM, several common software packages can 107 | be compiled with `lljvm-cc` by entering the `demo/` subdirectory and calling 108 | `make`. To verify that all of these compiled correctly, call `make check`. 109 | 110 | A JAR archive containing all of the demo programs can be created by calling 111 | `make demo` in the project root directory. For usage information, execute the 112 | JAR in the project root directory with no arguments: 113 | 114 | java -jar lljvm-demo.jar 115 | 116 | 117 | ## BACKEND 118 | The LLJVM Backend transforms LLVM IR into Jasmin assembly code. 119 | It can be invoked by: 120 | 121 | lljvm-backend foo.bc > foo.j 122 | 123 | There are two flags that are accepted by the backend: `-classname` and `-g`. 124 | Run `lljvm-backend --help` for more information. 125 | 126 | The output file should then be linked by the LLJVM Linker (see below), and 127 | assembled into a class file by [Jasmin][jasmin]: 128 | 129 | java -jar jasmin.jar foo.j 130 | 131 | 132 | ## RUNTIME 133 | The LLVJM Runtime has three components, the Core Runtime (`lljvm.runtime`), the 134 | I/O Support Library (`lljvm.io`), and the C Standard Library (`lljvm.lib.c`). See 135 | the JavaDoc documentation for further details on the former two. The latter is 136 | [Newlib][newlib] compiled to JVM bytecode by `lljvm-cc`. 137 | 138 | 139 | ## TOOLS 140 | There are two command-line tools available: the linker, and the info utility. 141 | There are several ways to invoke these tools. The simplest way is to call them 142 | directly from the jar archive: 143 | 144 | java -jar lljvm.jar args... 145 | 146 | Alternatively, if `lljvm.jar` is already in the classpath, one of the following 147 | can be used: 148 | 149 | java lljvm.tools.Main args... 150 | java lljvm.tools..Main args... 151 | 152 | 153 | ## LINKER 154 | The LLJVM Linker qualifies references to external methods and fields in Jasmin 155 | assembly code. At the top of the code (before any `.method` directives), external 156 | references should be specified through the `.extern` pseudo-directive, such as: 157 | 158 | .extern field foo I 159 | .extern method bar(I)V 160 | 161 | Then the linker can be invoked by: 162 | 163 | java -jar lljvm.jar ld LIBRARY... < INPUT.j > OUTPUT.j 164 | 165 | For example, the following assembly code: 166 | 167 | .extern method cos(D)D 168 | .extern field NULL I 169 | ... 170 | invokestatic cos(D)D 171 | getstatic NULL I 172 | CLASSFORMETHOD cos(D)D 173 | linked with the command: 174 | 175 | java -jar lljvm.jar ld java.lang.Math lljvm.runtime.Memory 176 | would produce: 177 | 178 | ... 179 | invokestatic java/lang/Math/cos(D)D 180 | getstatic lljvm/runtime/Memory/NULL I 181 | ldc "java/lang/Math" 182 | 183 | 184 | ## INFO 185 | The info utility lists the type signatures of the public static fields and 186 | methods provided by a class. For example, to list those provided by `libc`: 187 | 188 | java -jar lljvm.jar info lljvm.lib.c 189 | 190 | By default, any identifiers beginning with an underscore are omitted. To 191 | disable this behaviour, pass the `-v` flag: 192 | 193 | java -jar lljvm.jar info -v lljvm.lib.c 194 | 195 | 196 | [llvm]: http://llvm.org/ 197 | [jasmin]: https://github.com/davidar/jasmin 198 | [jasmin-jar]: https://github.com/davidar/jasmin/raw/master/jasmin.jar 199 | [newlib]: http://sourceware.org/newlib/ 200 | [hn-lljvm]: http://news.ycombinator.com/item?id=961834 201 | [lljvm-jar]: https://github.com/davidar/lljvm/releases/download/0.2/lljvm-0.2.jar 202 | [docker]: https://www.docker.com/ 203 | [mhaye-lljvm]: https://registry.hub.docker.com/u/mhaye/lljvm/ 204 | [lljvm-demo-jar]: https://github.com/davidar/lljvm/releases/download/0.2/lljvm-demo-0.2.jar 205 | [lljvm-bin]: https://github.com/davidar/lljvm/releases/download/0.2/lljvm-bin-linux-i386-0.2.tar.gz 206 | [clang]: http://clang.llvm.org/ 207 | [nestedvm]: http://nestedvm.ibex.org/ 208 | [cibyl]: https://github.com/SimonKagstrom/cibyl 209 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Execute this script to generate the TODO list 3 | 4 | grep -nR TODO \ 5 | backend/{*.cpp,*.h,Makefile} demo/ include/lljvm/ java/ libc/ test/ \ 6 | lljvm-cc Makefile \ 7 | | sed 's/\s*[\/\*#]*\s*TODO:*//g' | less 8 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | doc/ 2 | *.o 3 | lljvm-backend 4 | -------------------------------------------------------------------------------- /backend/Makefile: -------------------------------------------------------------------------------- 1 | CXX := c++ 2 | CFLAGS := $(shell llvm-config --cxxflags --ldflags \ 3 | --libs bitreader codegen selectiondag) 4 | OBJS := \ 5 | main.o \ 6 | backend.o \ 7 | block.o \ 8 | branch.o \ 9 | const.o \ 10 | function.o \ 11 | instruction.o \ 12 | loadstore.o \ 13 | name.o \ 14 | printinst.o \ 15 | sections.o \ 16 | types.o 17 | 18 | .PHONY: all doc clean 19 | 20 | all: lljvm-backend 21 | 22 | lljvm-backend: ${OBJS} 23 | $(CXX) ${OBJS} ${CFLAGS} -o lljvm-backend 24 | 25 | doc: 26 | doxygen 27 | 28 | clean: 29 | rm -f *.o lljvm-backend 30 | rm -rf doc 31 | 32 | .cpp.o: 33 | $(CXX) ${CFLAGS} -c $< 34 | 35 | ${OBJS}: backend.h 36 | -------------------------------------------------------------------------------- /backend/backend.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | char JVMWriter::id = 0; 26 | 27 | /** 28 | * Constructor. 29 | * 30 | * @param td the target data for the platform 31 | * @param o the output stream to be written to 32 | * @param cls the binary name of the class to generate 33 | * @param src the name of the source file, to use in the '.source' 34 | * directive. If empty, one will be generated 35 | * @param dbg the debugging level 36 | * @param trc stream to output trace lines too. JVMWriter takes 37 | * ownership of the pointer 38 | */ 39 | JVMWriter::JVMWriter(const TargetData *td, formatted_raw_ostream &o, 40 | const std::string &cls, const std::string &src, 41 | unsigned int dbg, raw_fd_ostream *trc) 42 | : FunctionPass(&id), targetData(td), out(o), classname(cls) 43 | , sourcename(src), debug(dbg), trace(trc) {} 44 | 45 | 46 | JVMWriter::~JVMWriter() { 47 | if (trace) 48 | delete trace; 49 | } 50 | 51 | /** 52 | * Register required analysis information. 53 | * 54 | * @param au AnalysisUsage object representing the analysis usage information 55 | * of this pass. 56 | */ 57 | void JVMWriter::getAnalysisUsage(AnalysisUsage &au) const { 58 | au.addRequired(); 59 | au.setPreservesAll(); 60 | } 61 | 62 | /** 63 | * Process the given function. 64 | * 65 | * @param f the function to process 66 | * @return whether the function was modified (always false) 67 | */ 68 | bool JVMWriter::runOnFunction(Function &f) { 69 | if(!f.isDeclaration() && !f.hasAvailableExternallyLinkage()) 70 | printFunction(f); 71 | return false; 72 | } 73 | 74 | /** 75 | * Perform per-module initialization. 76 | * 77 | * @param m the module 78 | * @return whether the module was modified (always false) 79 | */ 80 | bool JVMWriter::doInitialization(Module &m) { 81 | module = &m; 82 | instNum = 0; 83 | trcLineNum = 0; 84 | 85 | if (sourcename.empty()) { 86 | std::string modID = module->getModuleIdentifier(); 87 | size_t slashPos = modID.rfind('/'); 88 | if(slashPos == std::string::npos) 89 | sourcename = modID; 90 | else 91 | sourcename = modID.substr(slashPos + 1); 92 | } 93 | 94 | if(!classname.empty()) { 95 | for(std::string::iterator i = classname.begin(), 96 | e = classname.end(); i != e; i++) 97 | if(*i == '.') *i = '/'; 98 | } else { 99 | classname = sourcename.substr(0, sourcename.rfind('.')); 100 | for(std::string::iterator i = classname.begin(), 101 | e = classname.end(); i != e; i++) 102 | if(*i == '.') *i = '_'; 103 | } 104 | 105 | printHeader(); 106 | printFields(); 107 | printExternalMethods(); 108 | printConstructor(); 109 | printMainMethod(); 110 | return false; 111 | } 112 | 113 | /** 114 | * Perform per-module finalization. 115 | * 116 | * @param m the module 117 | * @return whether the module was modified (always false) 118 | */ 119 | bool JVMWriter::doFinalization(Module &m) { 120 | if (trace) 121 | trace->close(); 122 | return false; 123 | } 124 | -------------------------------------------------------------------------------- /backend/backend.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2010 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef BACKEND_H 24 | #define BACKEND_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | using namespace llvm; 40 | 41 | /** 42 | * A FunctionPass for generating Jasmin-style assembly for the JVM. 43 | * 44 | * @author David Roberts 45 | */ 46 | class JVMWriter : public FunctionPass { 47 | /** The output stream */ 48 | formatted_raw_ostream &out; 49 | /** Optional stream for generating trace file*/ 50 | raw_fd_ostream * const trace; 51 | /** The name of the source file */ 52 | std::string sourcename; 53 | /** The binary name of the generated class */ 54 | std::string classname; 55 | /** The debugging level */ 56 | unsigned int debug; 57 | /** The current module */ 58 | Module *module; 59 | /** The target data for the platform */ 60 | const TargetData *targetData; 61 | /** Pass ID */ 62 | static char id; 63 | 64 | /** Set of external references */ 65 | DenseSet externRefs; 66 | /** Mapping of blocks to unique IDs */ 67 | DenseMap blockIDs; 68 | /** Mapping of values to local variable numbers */ 69 | DenseMap localVars; 70 | /** Mapping of unnamed values to number used to generate a temporary name */ 71 | DenseMap temporaryNames; 72 | /** Number of registers allocated for the function */ 73 | unsigned int usedRegisters; 74 | /** Local variable number of the pointer to the packed list of varargs */ 75 | unsigned int vaArgNum; 76 | /** Current instruction number */ 77 | unsigned int instNum; 78 | /** Current line num of trace file" */ 79 | unsigned int trcLineNum; 80 | 81 | public: 82 | //Note that JVMWriter takes ownership of trc and will 83 | //delete it once it is destroyed 84 | JVMWriter(const TargetData *td, formatted_raw_ostream &o, 85 | const std::string &cls, const std::string &src, 86 | unsigned int dbg, raw_fd_ostream *trc); 87 | 88 | virtual ~JVMWriter(); 89 | 90 | private: 91 | // backend.cpp 92 | void getAnalysisUsage(AnalysisUsage &au) const; 93 | bool runOnFunction(Function &f); 94 | bool doInitialization(Module &m); 95 | bool doFinalization(Module &m); 96 | 97 | // block.cpp 98 | void printBasicBlock(const BasicBlock *block); 99 | void printInstruction(const Instruction *inst); 100 | 101 | // branch.cpp 102 | void printPHICopy(const BasicBlock *src, const BasicBlock *dest); 103 | void printBranchInstruction(const BasicBlock *curBlock, 104 | const BasicBlock *destBlock); 105 | void printBranchInstruction(const BasicBlock *curBlock, 106 | const BasicBlock *trueBlock, 107 | const BasicBlock *falseBlock); 108 | void printBranchInstruction(const BranchInst *inst); 109 | void printSelectInstruction(const Value *cond, 110 | const Value *trueVal, 111 | const Value *falseVal); 112 | void printSwitchInstruction(const SwitchInst *inst); 113 | void printLoop(const Loop *l); 114 | 115 | // const.cpp 116 | void printPtrLoad(uint64_t n); 117 | void printConstLoad(const APInt &i); 118 | void printConstLoad(float f); 119 | void printConstLoad(double d); 120 | void printConstLoad(const Constant *c); 121 | void printConstLoad(const std::string &str, bool cstring); 122 | void printStaticConstant(const Constant *c); 123 | void printConstantExpr(const ConstantExpr *ce); 124 | 125 | // function.cpp 126 | std::string getCallSignature(const FunctionType *ty); 127 | void printOperandPack(const Instruction *inst, 128 | unsigned int minOperand, 129 | unsigned int maxOperand); 130 | void printFunctionCall(const Value *functionVal, const Instruction *inst); 131 | void printIntrinsicCall(const IntrinsicInst *inst); 132 | void printCallInstruction(const Instruction *inst); 133 | void printInvokeInstruction(const InvokeInst *inst); 134 | void printLocalVariable(const Function &f, const Instruction *inst); 135 | void printFunctionBody(const Function &f); 136 | unsigned int getLocalVarNumber(const Value *v); 137 | void printCatchJump(unsigned int numJumps); 138 | void printFunction(const Function &f); 139 | 140 | // instruction.cpp 141 | void printCmpInstruction(unsigned int predicate, 142 | const Value *left, 143 | const Value *right); 144 | void printArithmeticInstruction(unsigned int op, 145 | const Value *left, 146 | const Value *right); 147 | void printBitCastInstruction(const Type *ty, const Type *srcTy); 148 | void printCastInstruction(const std::string &typePrefix, 149 | const std::string &srcTypePrefix); 150 | void printCastInstruction(unsigned int op, const Value *v, 151 | const Type *ty, const Type *srcTy); 152 | void printGepInstruction(const Value *v, 153 | gep_type_iterator i, 154 | gep_type_iterator e); 155 | void printAllocaInstruction(const AllocaInst *inst); 156 | void printVAArgInstruction(const VAArgInst *inst); 157 | void printVAIntrinsic(const IntrinsicInst *inst); 158 | void printMemIntrinsic(const MemIntrinsic *inst); 159 | void printMathIntrinsic(const IntrinsicInst *inst); 160 | void printBitIntrinsic(const IntrinsicInst *inst); 161 | 162 | // loadstore.cpp 163 | void printValueLoad(const Value *v); 164 | void printValueStore(const Value *v); 165 | void printIndirectLoad(const Value *v); 166 | void printIndirectLoad(const Type *ty); 167 | void printIndirectStore(const Value *ptr, const Value *val); 168 | 169 | // name.cpp 170 | std::string sanitizeName(std::string name); 171 | std::string getValueName(const Value *v); 172 | std::string getLabelName(const BasicBlock *block); 173 | 174 | // printinst.cpp 175 | void printBinaryInstruction(const char *name, 176 | const Value *left, 177 | const Value *right); 178 | void printBinaryInstruction(const std::string &name, 179 | const Value *left, 180 | const Value *right); 181 | void printSimpleInstruction(const char *inst); 182 | void printSimpleInstruction(const char *inst, const char *operand); 183 | void printSimpleInstruction(const std::string &inst); 184 | void printSimpleInstruction(const std::string &inst, 185 | const std::string &operand); 186 | void printVirtualInstruction(const char *sig); 187 | void printVirtualInstruction(const char *sig, const Value *operand); 188 | void printVirtualInstruction(const char *sig, 189 | const Value *left, 190 | const Value *right); 191 | void printVirtualInstruction(const std::string &sig); 192 | void printVirtualInstruction(const std::string &sig, const Value *operand); 193 | void printVirtualInstruction(const std::string &sig, 194 | const Value *left, 195 | const Value *right); 196 | void printLabel(const char *label); 197 | void printLabel(const std::string &label); 198 | 199 | void printStartInvocationTag(int includeStackSize = 0); 200 | void printEndInvocationTag(const std::string &sig, bool local=false); 201 | void printGetField(const std::string &sig, bool local=false); 202 | void printLoadClassNameForMethod(const std::string &sig); 203 | void printDeclareLinkerFields(); 204 | void printInitLinkerFields(); 205 | void printTrc(const std::string &sig); 206 | 207 | // sections.cpp 208 | void printHeader(); 209 | void printFields(); 210 | void printExternalMethods(); 211 | void printConstructor(); 212 | void printMainMethod(); 213 | 214 | // types.cpp 215 | unsigned int getBitWidth( const Type *ty, bool expand = false); 216 | char getTypeID( const Type *ty, bool expand = false); 217 | std::string getTypeName( const Type *ty, bool expand = false); 218 | std::string getTypeDescriptor(const Type *ty, bool expand = false); 219 | std::string getTypePostfix( const Type *ty, bool expand = false); 220 | std::string getTypePrefix( const Type *ty, bool expand = false); 221 | }; 222 | 223 | #endif 224 | -------------------------------------------------------------------------------- /backend/block.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2010 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | /** 26 | * Print the given basic block. 27 | * 28 | * @param block the basic block 29 | */ 30 | void JVMWriter::printBasicBlock(const BasicBlock *block) { 31 | printLabel(getLabelName(block)); 32 | if (trace) { 33 | if (block->hasName()) { 34 | std::string n = block->getName(); 35 | printTrc(n + ":"); 36 | } 37 | } 38 | for(BasicBlock::const_iterator i = block->begin(), e = block->end(); 39 | i != e; i++) { 40 | instNum++; 41 | 42 | if (trace) 43 | printSimpleInstruction(".line", utostr(trcLineNum+1)); 44 | else if(debug >= 1) 45 | printSimpleInstruction(".line", utostr(instNum)); 46 | 47 | if(debug >= 3 || trace) { 48 | // print current instruction as comment 49 | // note that this block of code significantly increases 50 | // code generation time 51 | std::string str; 52 | raw_string_ostream ss(str); ss << *i; 53 | ss.flush(); 54 | if (trace) 55 | printTrc(str); 56 | if (debug >= 3) { 57 | std::string::size_type pos = 0; 58 | while((pos = str.find("\n", pos)) != std::string::npos) 59 | str.replace(pos++, 1, "\n;"); 60 | out << ';' << str << '\n'; 61 | } 62 | } 63 | 64 | if(i->getOpcode() == Instruction::PHI) 65 | // don't handle phi instruction in current block 66 | continue; 67 | printInstruction(i); 68 | if(i->getType() != Type::getVoidTy(block->getContext()) 69 | && i->getOpcode() != Instruction::Invoke) 70 | // instruction doesn't return anything, or is an invoke instruction 71 | // which handles storing the return value itself 72 | printValueStore(i); 73 | } 74 | } 75 | 76 | /** 77 | * Print the given instruction. 78 | * 79 | * @param inst the instruction 80 | */ 81 | void JVMWriter::printInstruction(const Instruction *inst) { 82 | const Value *left, *right; 83 | if(inst->getNumOperands() >= 1) left = inst->getOperand(0); 84 | if(inst->getNumOperands() >= 2) right = inst->getOperand(1); 85 | switch(inst->getOpcode()) { 86 | case Instruction::Ret: 87 | printStartInvocationTag(); 88 | printEndInvocationTag("lljvm/runtime/Memory/destroyStackFrame()V"); 89 | if(inst->getNumOperands() >= 1) { 90 | printValueLoad(left); 91 | printSimpleInstruction( 92 | getTypePrefix(left->getType(), true) + "return"); 93 | } else { 94 | printSimpleInstruction("return"); 95 | } 96 | break; 97 | case Instruction::Unwind: 98 | printSimpleInstruction("getstatic", 99 | "lljvm/runtime/Instruction$Unwind/instance " 100 | "Llljvm/runtime/Instruction$Unwind;"); 101 | printSimpleInstruction("athrow"); 102 | // TODO: need to destroy stack frames 103 | break; 104 | case Instruction::Unreachable: 105 | printSimpleInstruction("getstatic", 106 | "lljvm/runtime/Instruction$Unreachable/instance " 107 | "Llljvm/runtime/Instruction$Unreachable;"); 108 | printSimpleInstruction("athrow"); 109 | break; 110 | case Instruction::Add: 111 | case Instruction::FAdd: 112 | case Instruction::Sub: 113 | case Instruction::FSub: 114 | case Instruction::Mul: 115 | case Instruction::FMul: 116 | case Instruction::UDiv: 117 | case Instruction::SDiv: 118 | case Instruction::FDiv: 119 | case Instruction::URem: 120 | case Instruction::SRem: 121 | case Instruction::FRem: 122 | case Instruction::And: 123 | case Instruction::Or: 124 | case Instruction::Xor: 125 | case Instruction::Shl: 126 | case Instruction::LShr: 127 | case Instruction::AShr: 128 | printArithmeticInstruction(inst->getOpcode(), left, right); 129 | break; 130 | case Instruction::SExt: 131 | case Instruction::Trunc: 132 | case Instruction::ZExt: 133 | case Instruction::FPTrunc: 134 | case Instruction::FPExt: 135 | case Instruction::UIToFP: 136 | case Instruction::SIToFP: 137 | case Instruction::FPToUI: 138 | case Instruction::FPToSI: 139 | case Instruction::PtrToInt: 140 | case Instruction::IntToPtr: 141 | case Instruction::BitCast: 142 | printCastInstruction(inst->getOpcode(), left, 143 | cast(inst)->getDestTy(), 144 | cast(inst)->getSrcTy()); break; 145 | case Instruction::ICmp: 146 | case Instruction::FCmp: 147 | printCmpInstruction(cast(inst)->getPredicate(), 148 | left, right); break; 149 | case Instruction::Br: 150 | printBranchInstruction(cast(inst)); break; 151 | case Instruction::Select: 152 | printSelectInstruction(inst->getOperand(0), 153 | inst->getOperand(1), 154 | inst->getOperand(2)); break; 155 | case Instruction::Load: 156 | printIndirectLoad(inst->getOperand(0)); break; 157 | case Instruction::Store: 158 | printIndirectStore(inst->getOperand(1), inst->getOperand(0)); break; 159 | case Instruction::GetElementPtr: 160 | printGepInstruction(inst->getOperand(0), 161 | gep_type_begin(inst), 162 | gep_type_end(inst)); break; 163 | case Instruction::Call: 164 | printCallInstruction(cast(inst)); break; 165 | case Instruction::Invoke: 166 | printInvokeInstruction(cast(inst)); break; 167 | case Instruction::Switch: 168 | printSwitchInstruction(cast(inst)); break; 169 | case Instruction::Alloca: 170 | printAllocaInstruction(cast(inst)); break; 171 | case Instruction::VAArg: 172 | printVAArgInstruction(cast(inst)); break; 173 | default: 174 | errs() << "Instruction = " << *inst << '\n'; 175 | llvm_unreachable("Unsupported instruction"); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /backend/branch.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | /** 26 | * Return a unique ID. 27 | * 28 | * @return a unique ID 29 | */ 30 | static uint64_t getUID() { 31 | static uint64_t x = 0; 32 | return ++x; 33 | } 34 | 35 | /** 36 | * Replace PHI instructions with copy instructions (load-store pairs). 37 | * 38 | * @param src the predecessor block 39 | * @param dest the destination block 40 | */ 41 | void JVMWriter::printPHICopy(const BasicBlock *src, const BasicBlock *dest) { 42 | for(BasicBlock::const_iterator i = dest->begin(); isa(i); i++) { 43 | const PHINode *phi = cast(i); 44 | const Value *val = phi->getIncomingValueForBlock(src); 45 | if(isa(val)) 46 | continue; 47 | printValueLoad(val); 48 | printValueStore(phi); 49 | } 50 | } 51 | 52 | /** 53 | * Print an unconditional branch instruction. 54 | * 55 | * @param curBlock the current block 56 | * @param destBlock the destination block 57 | */ 58 | void JVMWriter::printBranchInstruction(const BasicBlock *curBlock, 59 | const BasicBlock *destBlock) { 60 | printPHICopy(curBlock, destBlock); 61 | printSimpleInstruction("goto", getLabelName(destBlock)); 62 | } 63 | 64 | /** 65 | * Print a conditional branch instruction. 66 | * 67 | * @param curBlock the current block 68 | * @param trueBlock the destination block if the value on top of the stack is 69 | * non-zero 70 | * @param falseBlock the destination block if the value on top of the stack is 71 | * zero 72 | */ 73 | void JVMWriter::printBranchInstruction(const BasicBlock *curBlock, 74 | const BasicBlock *trueBlock, 75 | const BasicBlock *falseBlock) { 76 | if(trueBlock == falseBlock) { 77 | printSimpleInstruction("pop"); 78 | printBranchInstruction(curBlock, trueBlock); 79 | } else if(!falseBlock) { 80 | printPHICopy(curBlock, trueBlock); 81 | printSimpleInstruction("ifne", getLabelName(trueBlock)); 82 | } else { 83 | std::string labelname = getLabelName(trueBlock); 84 | if(isa(trueBlock->begin())) 85 | labelname += "$phi" + utostr(getUID()); 86 | printSimpleInstruction("ifne", labelname); 87 | 88 | if(isa(falseBlock->begin())) 89 | printPHICopy(curBlock, falseBlock); 90 | printSimpleInstruction("goto", getLabelName(falseBlock)); 91 | 92 | if(isa(trueBlock->begin())) { 93 | printLabel(labelname); 94 | printPHICopy(curBlock, trueBlock); 95 | printSimpleInstruction("goto", getLabelName(trueBlock)); 96 | } 97 | } 98 | } 99 | 100 | /** 101 | * Print a branch instruction. 102 | * 103 | * @param inst the branch instrtuction 104 | */ 105 | void JVMWriter::printBranchInstruction(const BranchInst *inst) { 106 | if(inst->isUnconditional()) { 107 | printBranchInstruction(inst->getParent(), inst->getSuccessor(0)); 108 | } else { 109 | printValueLoad(inst->getCondition()); 110 | printBranchInstruction( 111 | inst->getParent(), inst->getSuccessor(0), inst->getSuccessor(1)); 112 | } 113 | } 114 | 115 | /** 116 | * Print a select instruction. 117 | * 118 | * @param cond the condition 119 | * @param trueVal the return value of the instruction if the condition is 120 | * non-zero 121 | * @param falseVal the return value of the instruction if the condition is 122 | * zero 123 | */ 124 | void JVMWriter::printSelectInstruction(const Value *cond, 125 | const Value *trueVal, 126 | const Value *falseVal) { 127 | std::string labelname = "select" + utostr(getUID()); 128 | printValueLoad(cond); 129 | printSimpleInstruction("ifeq", labelname + "a"); 130 | printValueLoad(trueVal); 131 | printSimpleInstruction("goto", labelname + "b"); 132 | printLabel(labelname + "a"); 133 | printValueLoad(falseVal); 134 | printLabel(labelname + "b"); 135 | } 136 | 137 | /** 138 | * Print a switch instruction. 139 | * 140 | * @param inst the switch instruction 141 | */ 142 | void JVMWriter::printSwitchInstruction(const SwitchInst *inst) { 143 | // TODO: This method does not handle switch statements when the 144 | // successor contains phi instructions (the value of the phi instruction 145 | // should be set before branching to the successor). Therefore, it has 146 | // been replaced by the switch lowering pass. Once this method is 147 | // fixed the switch lowering pass should be removed. 148 | 149 | std::map cases; 150 | for(unsigned int i = 1, e = inst->getNumCases(); i < e; i++) 151 | cases[(int) inst->getCaseValue(i)->getValue().getSExtValue()] = i; 152 | 153 | // TODO: tableswitch in cases where it won't increase the size of the 154 | // class file 155 | printValueLoad(inst->getCondition()); 156 | out << "\tlookupswitch\n"; 157 | for(std::map::const_iterator 158 | i = cases.begin(), e = cases.end(); i != e; i++) 159 | out << "\t\t" << i->first << " : " 160 | << getLabelName(inst->getSuccessor(i->second)) << '\n'; 161 | out << "\t\tdefault : " << getLabelName(inst->getDefaultDest()) << '\n'; 162 | } 163 | 164 | /** 165 | * Print a loop. 166 | * 167 | * @param l the loop 168 | */ 169 | void JVMWriter::printLoop(const Loop *l) { 170 | printLabel(getLabelName(l->getHeader())); 171 | for(Loop::block_iterator i = l->block_begin(), 172 | e = l->block_end(); i != e; i++) { 173 | const BasicBlock *block = *i; 174 | Loop *blockLoop = getAnalysis().getLoopFor(block); 175 | if(l == blockLoop) 176 | // the loop is the innermost parent of this block 177 | printBasicBlock(block); 178 | else if(block == blockLoop->getHeader() 179 | && l == blockLoop->getParentLoop()) 180 | // this block is the header of its innermost parent loop, 181 | // and the loop is the parent of that loop 182 | printLoop(blockLoop); 183 | } 184 | printSimpleInstruction("goto", getLabelName(l->getHeader())); 185 | } 186 | -------------------------------------------------------------------------------- /backend/const.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | /** 26 | * Load the given pointer. 27 | * 28 | * @param n the value of the pointer 29 | */ 30 | void JVMWriter::printPtrLoad(uint64_t n) { 31 | if(module->getPointerSize() != Module::Pointer32) 32 | llvm_unreachable("Only 32-bit pointers are allowed"); 33 | printConstLoad(APInt(32, n, false)); 34 | } 35 | 36 | /** 37 | * Load the given integer. 38 | * 39 | * @param i the integer 40 | */ 41 | void JVMWriter::printConstLoad(const APInt &i) { 42 | if(i.getBitWidth() <= 32) { 43 | int64_t value = i.getSExtValue(); 44 | if(value == -1) 45 | printSimpleInstruction("iconst_m1"); 46 | else if(0 <= value && value <= 5) 47 | printSimpleInstruction("iconst_" + i.toString(10, true)); 48 | else if(-0x80 <= value && value <= 0x7f) 49 | printSimpleInstruction("bipush", i.toString(10, true)); 50 | else if(-0x8000 <= value && value <= 0x7fff) 51 | printSimpleInstruction("sipush", i.toString(10, true)); 52 | else 53 | printSimpleInstruction("ldc", i.toString(10, true)); 54 | } else { 55 | if(i == 0) 56 | printSimpleInstruction("lconst_0"); 57 | else if(i == 1) 58 | printSimpleInstruction("lconst_1"); 59 | else 60 | printSimpleInstruction("ldc2_w", i.toString(10, true)); 61 | } 62 | } 63 | 64 | /** 65 | * Load the given single-precision floating point value. 66 | * 67 | * @param f the value 68 | */ 69 | void JVMWriter::printConstLoad(float f) { 70 | if(f == 0.0) 71 | printSimpleInstruction("fconst_0"); 72 | else if(f == 1.0) 73 | printSimpleInstruction("fconst_1"); 74 | else if(f == 2.0) 75 | printSimpleInstruction("fconst_2"); 76 | else if(IsNAN(f)) 77 | printSimpleInstruction("getstatic", "java/lang/Float/NaN F"); 78 | else if(IsInf(f) > 0) 79 | printSimpleInstruction("getstatic", 80 | "java/lang/Float/POSITIVE_INFINITY F"); 81 | else if(IsInf(f) < 0) 82 | printSimpleInstruction("getstatic", 83 | "java/lang/Float/NEGATIVE_INFINITY F"); 84 | else 85 | printSimpleInstruction("ldc", ftostr(f)); 86 | } 87 | 88 | /** 89 | * Load the given double-precision floating point value. 90 | * 91 | * @param d the value 92 | */ 93 | void JVMWriter::printConstLoad(double d) { 94 | if(d == 0.0) 95 | printSimpleInstruction("dconst_0"); 96 | else if(d == 1.0) 97 | printSimpleInstruction("dconst_1"); 98 | else if(IsNAN(d)) 99 | printSimpleInstruction("getstatic", "java/lang/Double/NaN D"); 100 | else if(IsInf(d) > 0) 101 | printSimpleInstruction("getstatic", 102 | "java/lang/Double/POSITIVE_INFINITY D"); 103 | else if(IsInf(d) < 0) 104 | printSimpleInstruction("getstatic", 105 | "java/lang/Double/NEGATIVE_INFINITY D"); 106 | else 107 | printSimpleInstruction("ldc2_w", ftostr(d)); 108 | } 109 | 110 | /** 111 | * Load the given constant. 112 | * 113 | * @param c the constant 114 | */ 115 | void JVMWriter::printConstLoad(const Constant *c) { 116 | if(const ConstantInt *i = dyn_cast(c)) { 117 | printConstLoad(i->getValue()); 118 | } else if(const ConstantFP *fp = dyn_cast(c)) { 119 | if(fp->getType()->getTypeID() == Type::FloatTyID) 120 | printConstLoad(fp->getValueAPF().convertToFloat()); 121 | else 122 | printConstLoad(fp->getValueAPF().convertToDouble()); 123 | } else if(isa(c)) { 124 | printPtrLoad(0); 125 | } else { 126 | errs() << "Constant = " << *c << '\n'; 127 | llvm_unreachable("Invalid constant value"); 128 | } 129 | } 130 | 131 | /** 132 | * Load the given string. 133 | * 134 | * @param str the string 135 | * @param cstring true iff the string contains a single null character at the 136 | * end 137 | */ 138 | void JVMWriter::printConstLoad(const std::string &str, bool cstring) { 139 | out << "\tldc \""; 140 | if(cstring) 141 | for(std::string::const_iterator i = str.begin(), 142 | e = str.end()-1; i != e; i++) 143 | switch(*i) { 144 | case '\\': out << "\\\\"; break; 145 | case '\b': out << "\\b"; break; 146 | case '\t': out << "\\t"; break; 147 | case '\n': out << "\\n"; break; 148 | case '\f': out << "\\f"; break; 149 | case '\r': out << "\\r"; break; 150 | case '\"': out << "\\\""; break; 151 | case '\'': out << "\\\'"; break; 152 | default: out << *i; break; 153 | } 154 | else 155 | for(std::string::const_iterator i = str.begin(), 156 | e = str.end(); i != e; i++) { 157 | const char c = *i; 158 | out << "\\u00" << hexdigit((c>>4) & 0xf) << hexdigit(c & 0xf); 159 | } 160 | out << "\"\n"; 161 | } 162 | 163 | /** 164 | * Store the given static constant. The constant is stored to the address 165 | * currently on top of the stack, pushing the first address following the 166 | * constant onto the stack afterwards. 167 | * 168 | * @param c the constant 169 | */ 170 | void JVMWriter::printStaticConstant(const Constant *c) { 171 | if(isa(c) || c->isNullValue()) { 172 | // zero initialised constant 173 | printStartInvocationTag(1); 174 | printPtrLoad(targetData->getTypeAllocSize(c->getType())); 175 | printEndInvocationTag("lljvm/runtime/Memory/zero(II)I"); 176 | return; 177 | } 178 | std::string typeDescriptor = getTypeDescriptor(c->getType()); 179 | switch(c->getType()->getTypeID()) { 180 | case Type::IntegerTyID: 181 | case Type::FloatTyID: 182 | case Type::DoubleTyID: 183 | printStartInvocationTag(1); 184 | printConstLoad(c); 185 | printEndInvocationTag("lljvm/runtime/Memory/pack(I" + typeDescriptor + ")I"); 186 | break; 187 | case Type::ArrayTyID: 188 | if(const ConstantArray *ca = dyn_cast(c)) 189 | if(ca->isString()) { 190 | printStartInvocationTag(1); 191 | bool cstring = ca->isCString(); 192 | printConstLoad(ca->getAsString(), cstring); 193 | if(cstring) 194 | printEndInvocationTag("lljvm/runtime/Memory/pack(ILjava/lang/String;)I"); 195 | else { 196 | printSimpleInstruction("invokevirtual", 197 | "java/lang/String/toCharArray()[C"); 198 | printEndInvocationTag("lljvm/runtime/Memory/pack(I[C)I"); 199 | } 200 | break; 201 | } 202 | // else fall through 203 | case Type::VectorTyID: 204 | case Type::StructTyID: 205 | for(unsigned int i = 0, e = c->getNumOperands(); i < e; i++) 206 | printStaticConstant(cast(c->getOperand(i))); 207 | break; 208 | case Type::PointerTyID: 209 | printStartInvocationTag(1); 210 | if(const Function *f = dyn_cast(c)) 211 | printValueLoad(f); 212 | else if(const GlobalVariable *g = dyn_cast(c)) 213 | // initialise with address of global variable 214 | printValueLoad(g); 215 | else if(isa(c) || c->isNullValue()) 216 | printSimpleInstruction("iconst_0"); 217 | else if(const ConstantExpr *ce = dyn_cast(c)) 218 | printConstantExpr(ce); 219 | else { 220 | errs() << "Constant = " << *c << '\n'; 221 | llvm_unreachable("Invalid static initializer"); 222 | } 223 | printEndInvocationTag( "lljvm/runtime/Memory/pack(I" + typeDescriptor + ")I"); 224 | break; 225 | default: 226 | errs() << "TypeID = " << c->getType()->getTypeID() << '\n'; 227 | llvm_unreachable("Invalid type in printStaticConstant()"); 228 | } 229 | } 230 | 231 | /** 232 | * Print the given constant expression. 233 | * 234 | * @param ce the constant expression 235 | */ 236 | void JVMWriter::printConstantExpr(const ConstantExpr *ce) { 237 | const Value *left, *right; 238 | if(ce->getNumOperands() >= 1) left = ce->getOperand(0); 239 | if(ce->getNumOperands() >= 2) right = ce->getOperand(1); 240 | switch(ce->getOpcode()) { 241 | case Instruction::Trunc: 242 | case Instruction::ZExt: 243 | case Instruction::SExt: 244 | case Instruction::FPTrunc: 245 | case Instruction::FPExt: 246 | case Instruction::UIToFP: 247 | case Instruction::SIToFP: 248 | case Instruction::FPToUI: 249 | case Instruction::FPToSI: 250 | case Instruction::PtrToInt: 251 | case Instruction::IntToPtr: 252 | case Instruction::BitCast: 253 | printCastInstruction(ce->getOpcode(), left, 254 | ce->getType(), left->getType()); break; 255 | case Instruction::Add: 256 | case Instruction::FAdd: 257 | case Instruction::Sub: 258 | case Instruction::FSub: 259 | case Instruction::Mul: 260 | case Instruction::FMul: 261 | case Instruction::UDiv: 262 | case Instruction::SDiv: 263 | case Instruction::FDiv: 264 | case Instruction::URem: 265 | case Instruction::SRem: 266 | case Instruction::FRem: 267 | case Instruction::And: 268 | case Instruction::Or: 269 | case Instruction::Xor: 270 | case Instruction::Shl: 271 | case Instruction::LShr: 272 | case Instruction::AShr: 273 | printArithmeticInstruction(ce->getOpcode(), left, right); break; 274 | case Instruction::ICmp: 275 | case Instruction::FCmp: 276 | printCmpInstruction(ce->getPredicate(), left, right); break; 277 | case Instruction::GetElementPtr: 278 | printGepInstruction(ce->getOperand(0), 279 | gep_type_begin(ce), 280 | gep_type_end(ce)); break; 281 | case Instruction::Select: 282 | printSelectInstruction(ce->getOperand(0), 283 | ce->getOperand(1), 284 | ce->getOperand(2)); break; 285 | default: 286 | errs() << "Expression = " << *ce << '\n'; 287 | llvm_unreachable("Invalid constant expression"); 288 | } 289 | } 290 | -------------------------------------------------------------------------------- /backend/function.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2010 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | /** 26 | * Return a unique ID. 27 | * 28 | * @return a unique ID 29 | */ 30 | static uint64_t getUID() { 31 | static uint64_t x = 0; 32 | return ++x; 33 | } 34 | 35 | /** 36 | * Return the call signature of the given function type. An empty string is 37 | * returned if the function type appears to be non-prototyped. 38 | * 39 | * @param ty the function type 40 | * @return the call signature 41 | */ 42 | std::string JVMWriter::getCallSignature(const FunctionType *ty) { 43 | if(ty->isVarArg() && ty->getNumParams() == 0) 44 | // non-prototyped function 45 | return ""; 46 | std::string sig; 47 | sig += '('; 48 | for(unsigned int i = 0, e = ty->getNumParams(); i < e; i++) 49 | sig += getTypeDescriptor(ty->getParamType(i)); 50 | if(ty->isVarArg()) sig += "I"; 51 | sig += ')'; 52 | sig += getTypeDescriptor(ty->getReturnType()); 53 | return sig; 54 | } 55 | 56 | /** 57 | * Pack the specified operands of the given instruction into memory. The 58 | * address of the packed values is left on the top of the stack. 59 | * 60 | * @param inst the given instruction 61 | * @param minOperand the lower bound on the operands to pack (inclusive) 62 | * @param maxOperand the upper bound on the operands to pack (exclusive) 63 | */ 64 | void JVMWriter::printOperandPack(const Instruction *inst, 65 | unsigned int minOperand, 66 | unsigned int maxOperand) { 67 | unsigned int size = 0; 68 | for(unsigned int i = minOperand; i < maxOperand; i++) 69 | size += targetData->getTypeAllocSize( 70 | inst->getOperand(i)->getType()); 71 | 72 | printStartInvocationTag(); 73 | printSimpleInstruction("bipush", utostr(size)); 74 | printEndInvocationTag("lljvm/runtime/Memory/allocateStack(I)I"); 75 | printSimpleInstruction("dup"); 76 | 77 | for(unsigned int i = minOperand; i < maxOperand; i++) { 78 | const Value *v = inst->getOperand(i); 79 | printStartInvocationTag(1); 80 | printValueLoad(v); 81 | printEndInvocationTag("lljvm/runtime/Memory/pack(I" 82 | + getTypeDescriptor(v->getType()) + ")I"); 83 | } 84 | printSimpleInstruction("pop"); 85 | } 86 | 87 | /** 88 | * Print a call/invoke instruction. 89 | * 90 | * @param functionVal the function to call 91 | * @param inst the instruction 92 | */ 93 | void JVMWriter::printFunctionCall(const Value *functionVal, 94 | const Instruction *inst) { 95 | unsigned int origin = isa(inst) ? 3 : 1; 96 | if(const Function *f = dyn_cast(functionVal)) { // direct call 97 | const FunctionType *ty = f->getFunctionType(); 98 | 99 | printStartInvocationTag(); 100 | //for(unsigned int i = origin, e = inst->getNumOperands(); i < e; i++) 101 | // printValueLoad(inst->getOperand(i)); 102 | 103 | for(unsigned int i = 0, e = ty->getNumParams(); i < e; i++) 104 | printValueLoad(inst->getOperand(i + origin)); 105 | if(ty->isVarArg() && inst) 106 | printOperandPack(inst, ty->getNumParams() + origin, 107 | inst->getNumOperands()); 108 | 109 | if(externRefs.count(f)) 110 | printEndInvocationTag( 111 | getValueName(f) + getCallSignature(ty)); 112 | else 113 | printEndInvocationTag( 114 | classname + "/" + getValueName(f) + getCallSignature(ty), true); 115 | 116 | if(getValueName(f) == "setjmp") { 117 | unsigned int varNum = usedRegisters++; 118 | printSimpleInstruction("istore", utostr(varNum)); 119 | printSimpleInstruction("iconst_0"); 120 | printLabel("setjmp$" + utostr(varNum)); 121 | } 122 | } else { // indirect call 123 | printStartInvocationTag(); 124 | printValueLoad(functionVal); 125 | const FunctionType *ty = cast( 126 | cast(functionVal->getType())->getElementType()); 127 | printOperandPack(inst, origin, inst->getNumOperands()); 128 | printEndInvocationTag("lljvm/runtime/Function/invoke_" 129 | + getTypePostfix(ty->getReturnType()) + "(II)" 130 | + getTypeDescriptor(ty->getReturnType())); 131 | } 132 | } 133 | 134 | /** 135 | * Print a call to an intrinsic function. 136 | * 137 | * @param inst the instruction 138 | */ 139 | void JVMWriter::printIntrinsicCall(const IntrinsicInst *inst) { 140 | switch(inst->getIntrinsicID()) { 141 | case Intrinsic::vastart: 142 | case Intrinsic::vacopy: 143 | case Intrinsic::vaend: 144 | printVAIntrinsic(inst); break; 145 | case Intrinsic::memcpy: 146 | case Intrinsic::memmove: 147 | case Intrinsic::memset: 148 | printMemIntrinsic(cast(inst)); break; 149 | case Intrinsic::flt_rounds: 150 | printSimpleInstruction("iconst_m1"); break; 151 | case Intrinsic::dbg_declare: 152 | // ignore debugging intrinsics 153 | break; 154 | case Intrinsic::pow: 155 | case Intrinsic::exp: 156 | case Intrinsic::log10: 157 | case Intrinsic::log: 158 | case Intrinsic::sqrt: 159 | printMathIntrinsic(inst); break; 160 | case Intrinsic::bswap: 161 | printBitIntrinsic(inst); break; 162 | default: 163 | errs() << "Intrinsic = " << *inst << '\n'; 164 | llvm_unreachable("Invalid intrinsic function"); 165 | } 166 | } 167 | 168 | /** 169 | * Print a call instruction. 170 | * 171 | * @param inst the instruction 172 | */ 173 | void JVMWriter::printCallInstruction(const Instruction *inst) { 174 | if(isa(inst)) 175 | printIntrinsicCall(cast(inst)); 176 | else 177 | printFunctionCall(inst->getOperand(0), inst); 178 | } 179 | 180 | /** 181 | * Print an invoke instruction. 182 | * 183 | * @param inst the instruction 184 | */ 185 | void JVMWriter::printInvokeInstruction(const InvokeInst *inst) { 186 | std::string labelname = getUID() + "$invoke"; 187 | printLabel(labelname + "_begin"); 188 | printFunctionCall(inst->getOperand(0), inst); 189 | if(!inst->getType()->isVoidTy()) 190 | printValueStore(inst); // save return value 191 | printLabel(labelname + "_end"); 192 | printBranchInstruction(inst->getParent(), inst->getNormalDest()); 193 | printLabel(labelname + "_catch"); 194 | printSimpleInstruction("pop"); 195 | printBranchInstruction(inst->getParent(), inst->getUnwindDest()); 196 | printSimpleInstruction(".catch lljvm/runtime/System$Unwind", 197 | "from " + labelname + "_begin " 198 | + "to " + labelname + "_end " 199 | + "using " + labelname + "_catch"); 200 | } 201 | 202 | /** 203 | * Allocate a local variable for the given function. Variable initialisation 204 | * and any applicable debugging information is printed. 205 | * 206 | * @param f the parent function of the variable 207 | * @param inst the instruction assigned to the variable 208 | */ 209 | void JVMWriter::printLocalVariable(const Function &f, 210 | const Instruction *inst) { 211 | const Type *ty; 212 | if(isa(inst) && !isa(inst)) 213 | // local variable allocation 214 | ty = PointerType::getUnqual( 215 | cast(inst)->getAllocatedType()); 216 | else // operation result 217 | ty = inst->getType(); 218 | // getLocalVarNumber must be called at least once in this method 219 | unsigned int varNum = getLocalVarNumber(inst); 220 | if(debug >= 2) 221 | printSimpleInstruction(".var " + utostr(varNum) + " is " 222 | + getValueName(inst) + ' ' + getTypeDescriptor(ty) 223 | + " from begin_method to end_method"); 224 | // initialise variable to avoid class verification errors 225 | printSimpleInstruction(getTypePrefix(ty, true) + "const_0"); 226 | printSimpleInstruction(getTypePrefix(ty, true) + "store", utostr(varNum)); 227 | } 228 | 229 | /** 230 | * Print the body of the given function. 231 | * 232 | * @param f the function 233 | */ 234 | void JVMWriter::printFunctionBody(const Function &f) { 235 | for(Function::const_iterator i = f.begin(), e = f.end(); i != e; i++) { 236 | if(Loop *l = getAnalysis().getLoopFor(i)) { 237 | if(l->getHeader() == i && l->getParentLoop() == 0) 238 | printLoop(l); 239 | } else 240 | printBasicBlock(i); 241 | } 242 | } 243 | 244 | /** 245 | * Return the local variable number of the given value. Register/s are 246 | * allocated for the variable if necessary. 247 | * 248 | * @param v the value 249 | * @return the local variable number 250 | */ 251 | unsigned int JVMWriter::getLocalVarNumber(const Value *v) { 252 | if(!localVars.count(v)) { 253 | localVars[v] = usedRegisters++; 254 | if(getBitWidth(v->getType()) == 64) 255 | usedRegisters++; // 64 bit types occupy 2 registers 256 | } 257 | return localVars[v]; 258 | } 259 | 260 | /** 261 | * Print the block to catch Jump objects (thrown by longjmp). 262 | * 263 | * @param numJumps the number of setjmp calls made by the current function 264 | */ 265 | void JVMWriter::printCatchJump(unsigned int numJumps) { 266 | unsigned int jumpVarNum = usedRegisters++; 267 | printSimpleInstruction(".catch lljvm/runtime/Jump " 268 | "from begin_method to catch_jump using catch_jump"); 269 | printLabel("catch_jump"); 270 | printSimpleInstruction("astore", utostr(jumpVarNum)); 271 | printSimpleInstruction("aload", utostr(jumpVarNum)); 272 | printSimpleInstruction("getfield", "lljvm/runtime/Jump/value I"); 273 | for(unsigned int i = usedRegisters-1 - numJumps, 274 | e = usedRegisters-1; i < e; i++) { 275 | if(debug >= 2) 276 | printSimpleInstruction(".var " + utostr(i) + " is setjmp_id_" 277 | + utostr(i) + " I from begin_method to end_method"); 278 | printSimpleInstruction("aload", utostr(jumpVarNum)); 279 | printSimpleInstruction("getfield", "lljvm/runtime/Jump/id I"); 280 | printSimpleInstruction("iload", utostr(i)); 281 | printSimpleInstruction("if_icmpeq", "setjmp$" + utostr(i)); 282 | } 283 | printSimpleInstruction("pop"); 284 | printSimpleInstruction("aload", utostr(jumpVarNum)); 285 | printSimpleInstruction("athrow"); 286 | if(debug >= 2) 287 | printSimpleInstruction(".var " + utostr(jumpVarNum) + " is jump " 288 | "Llljvm/runtime/Jump; from begin_method to end_method"); 289 | } 290 | 291 | /** 292 | * Print the given function. 293 | * 294 | * @param f the function 295 | */ 296 | void JVMWriter::printFunction(const Function &f) { 297 | localVars.clear(); 298 | temporaryNames.clear(); 299 | 300 | out << '\n'; 301 | 302 | std::string method; 303 | raw_string_ostream methodstrm(method); 304 | 305 | methodstrm << ".method " << (f.hasLocalLinkage() ? "private " : "public ") 306 | << getValueName(&f) << '('; 307 | for(Function::const_arg_iterator i = f.arg_begin(), e = f.arg_end(); 308 | i != e; i++) 309 | methodstrm << getTypeDescriptor(i->getType()); 310 | if(f.isVarArg()) 311 | methodstrm << "I"; 312 | methodstrm << ')' << getTypeDescriptor(f.getReturnType()); 313 | methodstrm.flush(); 314 | 315 | out << method << '\n'; 316 | if (trace) { 317 | printTrc(""); 318 | printTrc(method); 319 | } 320 | 321 | usedRegisters = 1; //First register is a reference to this 322 | if(debug >= 2) 323 | printSimpleInstruction(".var 0 is this L" + classname + ";" 324 | + " from init_method to end_method"); 325 | 326 | for(Function::const_arg_iterator i = f.arg_begin(), e = f.arg_end(); 327 | i != e; i++) { 328 | // getLocalVarNumber must be called at least once in each iteration 329 | unsigned int varNum = getLocalVarNumber(i); 330 | if(debug >= 2) 331 | printSimpleInstruction(".var " + utostr(varNum) + " is " 332 | + getValueName(i) + ' ' + getTypeDescriptor(i->getType()) 333 | + " from init_method to end_method"); 334 | } 335 | if(f.isVarArg()) { 336 | vaArgNum = usedRegisters++; 337 | if(debug >= 2) 338 | printSimpleInstruction(".var " + utostr(vaArgNum) 339 | + " is varargptr I from init_method to end_method"); 340 | } 341 | printLabel("init_method"); 342 | 343 | // TODO: better stack depth analysis 344 | unsigned int stackDepth = 10; 345 | unsigned int numJumps = 0; 346 | for(const_inst_iterator i = inst_begin(&f), e = inst_end(&f); 347 | i != e; i++) { 348 | if(stackDepth < (i->getNumOperands()+2)) 349 | stackDepth = i->getNumOperands()+2; 350 | if(i->getType() != Type::getVoidTy(f.getContext())) 351 | printLocalVariable(f, &*i); 352 | if(const CallInst *inst = dyn_cast(&*i)) 353 | if(!isa(inst) 354 | && getValueName(inst->getOperand(0)) == "setjmp") 355 | numJumps++; 356 | } 357 | 358 | for(unsigned int i = 0; i < numJumps; i++) { 359 | // initialise jump IDs to prevent class verification errors 360 | printSimpleInstruction("iconst_0"); 361 | printSimpleInstruction("istore", utostr(usedRegisters + i)); 362 | } 363 | 364 | printLabel("begin_method"); 365 | printStartInvocationTag(); 366 | printEndInvocationTag("lljvm/runtime/Memory/createStackFrame()V"); 367 | printFunctionBody(f); 368 | if(numJumps) printCatchJump(numJumps); 369 | printSimpleInstruction(".limit stack", utostr(stackDepth * 2)); 370 | printSimpleInstruction(".limit locals", utostr(usedRegisters)); 371 | printLabel("end_method"); 372 | out << ".end method\n"; 373 | } 374 | -------------------------------------------------------------------------------- /backend/loadstore.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | /** 26 | * Load the given value. 27 | * 28 | * @param v the value to load 29 | */ 30 | void JVMWriter::printValueLoad(const Value *v) { 31 | if(const Function *f = dyn_cast(v)) { 32 | std::string sig = getValueName(f) 33 | + getCallSignature(f->getFunctionType()); 34 | printStartInvocationTag(); 35 | if(externRefs.count(v)) 36 | printLoadClassNameForMethod(sig); 37 | else 38 | printSimpleInstruction("ldc", '"' + classname + '"'); 39 | printSimpleInstruction("ldc", '"' + sig + '"'); 40 | printEndInvocationTag( 41 | "lljvm/runtime/Function/getFunctionPointer" 42 | "(Ljava/lang/String;Ljava/lang/String;)I"); 43 | } else if(isa(v)) { 44 | const Type *ty = cast(v->getType())->getElementType(); 45 | if(externRefs.count(v)) 46 | printGetField(getValueName(v)+" I"); 47 | else { 48 | printGetField(classname + "/" + getValueName(v) + " I",true); 49 | } 50 | } else if(isa(v)) { 51 | printPtrLoad(0); 52 | } else if(const ConstantExpr *ce = dyn_cast(v)) { 53 | printConstantExpr(ce); 54 | } else if(const Constant *c = dyn_cast(v)) { 55 | printConstLoad(c); 56 | } else { 57 | if(getLocalVarNumber(v) <= 3) 58 | printSimpleInstruction( 59 | getTypePrefix(v->getType(), true) + "load_" 60 | + utostr(getLocalVarNumber(v)) 61 | + " ; " + getValueName(v)); 62 | else 63 | printSimpleInstruction( 64 | getTypePrefix(v->getType(), true) + "load", 65 | utostr(getLocalVarNumber(v)) 66 | + " ; " + getValueName(v)); 67 | } 68 | } 69 | 70 | /** 71 | * Store the value currently on top of the stack to the given local variable. 72 | * 73 | * @param v the Value representing the local variable 74 | */ 75 | void JVMWriter::printValueStore(const Value *v) { 76 | if(isa(v) || isa(v) || isa(v)) { 77 | errs() << "Value = " << *v << '\n'; 78 | llvm_unreachable("Invalid value"); 79 | } 80 | unsigned int bitWidth = getBitWidth(v->getType()); 81 | // truncate int 82 | if(bitWidth == 16) 83 | printSimpleInstruction("i2s"); 84 | else if(bitWidth == 8) 85 | printSimpleInstruction("i2b"); 86 | else if(bitWidth == 1) { 87 | printSimpleInstruction("iconst_1"); 88 | printSimpleInstruction("iand"); 89 | } 90 | if(getLocalVarNumber(v) <= 3) 91 | printSimpleInstruction( 92 | getTypePrefix(v->getType(), true) + "store_" 93 | + utostr(getLocalVarNumber(v)) 94 | + " ; " + getValueName(v)); 95 | else 96 | printSimpleInstruction( 97 | getTypePrefix(v->getType(), true) + "store", 98 | utostr(getLocalVarNumber(v)) 99 | + " ; " + getValueName(v)); 100 | } 101 | 102 | /** 103 | * Load a value from the given address. 104 | * 105 | * @param v the address 106 | */ 107 | void JVMWriter::printIndirectLoad(const Value *v) { 108 | printValueLoad(v); 109 | const Type *ty = v->getType(); 110 | if(const PointerType *p = dyn_cast(ty)) 111 | ty = p->getElementType(); 112 | printIndirectLoad(ty); 113 | } 114 | 115 | /** 116 | * Load a value of the given type from the address curently on top of the 117 | * stack. 118 | * 119 | * @param ty the type of the value 120 | */ 121 | void JVMWriter::printIndirectLoad(const Type *ty) { 122 | printStartInvocationTag(1); 123 | printEndInvocationTag("lljvm/runtime/Memory/load_" 124 | + getTypePostfix(ty) + "(I)" + getTypeDescriptor(ty)); 125 | } 126 | 127 | /** 128 | * Store a value at the given address. 129 | * 130 | * @param ptr the address at which to store the value 131 | * @param val the value to store 132 | */ 133 | void JVMWriter::printIndirectStore(const Value *ptr, const Value *val) { 134 | printStartInvocationTag(); 135 | printValueLoad(ptr); 136 | printValueLoad(val); 137 | printEndInvocationTag("lljvm/runtime/Memory/store(I" + getTypeDescriptor(val->getType()) + ")V"); 138 | } 139 | 140 | -------------------------------------------------------------------------------- /backend/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | using namespace llvm; 40 | 41 | static cl::opt input( 42 | cl::Positional, cl::desc(""), cl::init("-")); 43 | static cl::opt classname( 44 | "classname", cl::desc("Binary name of the generated class")); 45 | static cl::opt sourcename( 46 | "sourcename", cl::desc("Name of source file to be included in the generated class")); 47 | static cl::opt tracefile( 48 | "tracefile", cl::desc("Name of the trace file to generate (must use -g3)")); 49 | 50 | 51 | enum DebugLevel {g0 = 0, g1 = 1, g2 = 2, g3 = 3}; 52 | cl::opt debugLevel(cl::desc("Debugging level:"), cl::init(g1), 53 | cl::values( 54 | clEnumValN(g2, "g", "Same as -g2"), 55 | clEnumVal(g0, "No debugging information"), 56 | clEnumVal(g1, "Source file and line number information (default)"), 57 | clEnumVal(g2, "-g1 + Local variable information"), 58 | clEnumVal(g3, "-g2 + Commented LLVM assembly"), 59 | clEnumValEnd)); 60 | 61 | int main(int argc, char **argv) { 62 | cl::ParseCommandLineOptions(argc, argv, "LLJVM Backend\n"); 63 | std::string err; 64 | 65 | MemoryBuffer *buf = MemoryBuffer::getFileOrSTDIN(input, &err); 66 | if(!buf) { 67 | std::cerr << "Unable to open bitcode file: " << err << std::endl; 68 | return 1; 69 | } 70 | 71 | Module *mod = ParseBitcodeFile(buf, getGlobalContext(), &err); 72 | if(!mod) { 73 | std::cerr << "Unable to parse bitcode file: " << err << std::endl; 74 | return 1; 75 | } 76 | 77 | llvm::raw_fd_ostream *trace_stream(0); 78 | if (!tracefile.empty()) { 79 | if (debugLevel < 3) { 80 | std::cerr << "May only specify a trace file if generating -g3 debugging information" << std::endl; 81 | return 1; 82 | } 83 | err = ""; 84 | trace_stream = new llvm::raw_fd_ostream(tracefile.c_str(), err); 85 | if (!err.empty()) { 86 | std::cerr << "Unable to open tracefile " << tracefile << " : " << err << std::endl; 87 | return 1; 88 | } 89 | } 90 | 91 | 92 | PassManager pm; 93 | TargetData td("e-p:32:32:32" 94 | "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" 95 | "-f32:32:32-f64:64:64"); 96 | pm.add(new TargetData(td)); 97 | pm.add(createVerifierPass()); 98 | pm.add(createGCLoweringPass()); 99 | // TODO: fix switch generation so the following pass is not needed 100 | pm.add(createLowerSwitchPass()); 101 | pm.add(createIndVarSimplifyPass()); 102 | pm.add(createPromoteMemoryToRegisterPass()); //good 103 | pm.add(createDeadStoreEliminationPass()); 104 | pm.add(createAggressiveDCEPass()); 105 | pm.add(createCFGSimplificationPass()); 106 | pm.add(new JVMWriter(&td, fouts(), classname 107 | , sourcename, debugLevel, trace_stream)); 108 | pm.add(createGCInfoDeleter()); 109 | pm.run(*mod); 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /backend/name.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2010 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | #include 26 | #include 27 | 28 | /** 29 | * Replace any non-alphanumeric characters with underscores. 30 | * 31 | * @param name the name to sanitize 32 | * @return the sanitized name 33 | */ 34 | std::string JVMWriter::sanitizeName(std::string name) { 35 | for(std::string::iterator i = name.begin(), e = name.end(); i != e; i++) 36 | if(!isalnum(*i)) 37 | *i = '_'; 38 | return name; 39 | } 40 | 41 | /** 42 | * Return the name of the given value. 43 | * 44 | * @param v the value 45 | * @return the name of the value 46 | */ 47 | std::string JVMWriter::getValueName(const Value *v) { 48 | if(const GlobalValue *gv = dyn_cast(v)) 49 | return sanitizeName(Mangler(MCAsmInfo()).getNameWithPrefix(gv)); 50 | if(v->hasName()) 51 | return '_' + sanitizeName(v->getName()); 52 | if(localVars.count(v)) { 53 | unsigned int tid; 54 | if (temporaryNames.count(v)) 55 | tid = temporaryNames[v]; 56 | else { 57 | tid = temporaryNames.size(); 58 | temporaryNames[v] = tid; 59 | } 60 | return "$" + utostr(tid); 61 | } 62 | return "_"; 63 | } 64 | /** 65 | * Return the label name of the given block. 66 | * 67 | * @param block the block 68 | * @return the label 69 | */ 70 | std::string JVMWriter::getLabelName(const BasicBlock *block) { 71 | if(!blockIDs.count(block)) 72 | blockIDs[block] = blockIDs.size() + 1; 73 | return sanitizeName("label" + utostr(blockIDs[block])); 74 | } 75 | -------------------------------------------------------------------------------- /backend/printinst.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | namespace { 26 | const char TAG_INVOKE_BEGIN[] = "*LLJVM|INVOKE-BEGIN"; 27 | const char TAG_INVOKE_END[] = "*LLJVM|INVOKE-END"; 28 | const char TAG_GET_FIELD[] = "*LLJVM|GET-FIELD"; 29 | const char TAG_CLASSNAME_FOR_METHOD[] = "*LLJVM|CLASSNAME-FOR-METHOD"; 30 | const char TAG_LINKER_DECLARATIONS[] = "*LLJVM|LINKER-DECLARATIONS"; 31 | const char TAG_LINKER_INITIALIZATIONS[] = "*LLJVM|LINKER-INITIALIZATIONS"; 32 | } 33 | 34 | /** 35 | * Print the given binary instruction. 36 | * 37 | * @param name the name of the instruction 38 | * @param left the first operand 39 | * @param right the second operand 40 | */ 41 | void JVMWriter::printBinaryInstruction(const char *name, 42 | const Value *left, 43 | const Value *right) { 44 | printValueLoad(left); 45 | printValueLoad(right); 46 | out << '\t' << name << '\n'; 47 | } 48 | 49 | /** 50 | * Print the given binary instruction. 51 | * 52 | * @param name the name of the instruction 53 | * @param left the first operand 54 | * @param right the second operand 55 | */ 56 | void JVMWriter::printBinaryInstruction(const std::string &name, 57 | const Value *left, 58 | const Value *right) { 59 | printValueLoad(left); 60 | printValueLoad(right); 61 | out << '\t' << name << '\n'; 62 | } 63 | 64 | /** 65 | * Print the given instruction. 66 | * 67 | * @param inst the instruction 68 | */ 69 | void JVMWriter::printSimpleInstruction(const char *inst) { 70 | out << '\t' << inst << '\n'; 71 | } 72 | 73 | /** 74 | * Print the given instruction. 75 | * 76 | * @param inst the instruction 77 | * @param operand the operand to the instruction 78 | */ 79 | void JVMWriter::printSimpleInstruction(const char *inst, const char *operand) { 80 | out << '\t' << inst << ' ' << operand << '\n'; 81 | } 82 | 83 | /** 84 | * Print the given instruction. 85 | * 86 | * @param inst the instruction 87 | */ 88 | void JVMWriter::printSimpleInstruction(const std::string &inst) { 89 | out << '\t' << inst << '\n'; 90 | } 91 | 92 | /** 93 | * Print the given instruction. 94 | * 95 | * @param inst the instruction 96 | * @param operand the operand to the instruction 97 | */ 98 | void JVMWriter::printSimpleInstruction(const std::string &inst, 99 | const std::string &operand) { 100 | out << '\t' << inst << ' ' << operand << '\n'; 101 | } 102 | 103 | /** 104 | * Print the virtual instruction with the given signature. 105 | * 106 | * @param sig the signature of the instruction 107 | */ 108 | void JVMWriter::printVirtualInstruction(const char *sig) { 109 | out << '\t' << "invokestatic lljvm/runtime/Instruction/" << sig << '\n'; 110 | } 111 | 112 | /** 113 | * Print the virtual instruction with the given signature. 114 | * 115 | * @param sig the signature of the instruction 116 | * @param operand the operand to the instruction 117 | */ 118 | void JVMWriter::printVirtualInstruction(const char *sig, 119 | const Value *operand) { 120 | printValueLoad(operand); 121 | printVirtualInstruction(sig); 122 | } 123 | 124 | /** 125 | * Print the virtual instruction with the given signature. 126 | * 127 | * @param sig the signature of the instruction 128 | * @param left the first operand 129 | * @param right the second operand 130 | */ 131 | void JVMWriter::printVirtualInstruction(const char *sig, 132 | const Value *left, 133 | const Value *right) { 134 | printValueLoad(left); 135 | printValueLoad(right); 136 | printVirtualInstruction(sig); 137 | } 138 | 139 | /** 140 | * Print the virtual instruction with the given signature. 141 | * 142 | * @param sig the signature of the instruction 143 | */ 144 | void JVMWriter::printVirtualInstruction(const std::string &sig) { 145 | printVirtualInstruction(sig.c_str()); 146 | } 147 | 148 | /** 149 | * Print the virtual instruction with the given signature. 150 | * 151 | * @param sig the signature of the instruction 152 | * @param operand the operand to the instruction 153 | */ 154 | void JVMWriter::printVirtualInstruction(const std::string &sig, 155 | const Value *operand) { 156 | printValueLoad(operand); 157 | printVirtualInstruction(sig); 158 | } 159 | 160 | /** 161 | * Print the virtual instruction with the given signature. 162 | * 163 | * @param sig the signature of the instruction 164 | * @param left the first operand 165 | * @param right the second operand 166 | */ 167 | void JVMWriter::printVirtualInstruction(const std::string &sig, 168 | const Value *left, 169 | const Value *right) { 170 | printValueLoad(left); 171 | printValueLoad(right); 172 | printVirtualInstruction(sig); 173 | } 174 | 175 | /** 176 | * Print the given label. 177 | * 178 | * @param label the label 179 | */ 180 | void JVMWriter::printLabel(const char *label) { 181 | out << label << ":\n"; 182 | } 183 | 184 | /** 185 | * Print the given label. 186 | * 187 | * @param label the label 188 | */ 189 | void JVMWriter::printLabel(const std::string &label) { 190 | out << label << ":\n"; 191 | } 192 | 193 | /** 194 | * Print the linker tag indicating the start of a JVM invocation sequence. 195 | * This should be followed by instructions placing the invocation arguments 196 | * on the stack and finally by an end invocation tag. 197 | * 198 | * @param includeStackSize number of existing positions on the stack that should 199 | * be included in the invocation. For non-static invocations, the linker-generated 200 | * code must insert a reference to the target instance below these items. Currently 201 | * only 0 and 1 are supported. 202 | */ 203 | void JVMWriter::printStartInvocationTag(int includeStackSize) { 204 | out << TAG_INVOKE_BEGIN << "|includeStackSize=" << includeStackSize << "\n"; 205 | } 206 | 207 | /** 208 | * Print a linker tag indicating the end of a JVM invocation sequence. 209 | * @param sig a symbolic reference to the method to invoke. The reference may be 210 | * unqualified, in which case the target classname will be resolved by the linker. 211 | * @param local if true, then the call is to this instance rather than an external instance. 212 | */ 213 | void JVMWriter::printEndInvocationTag(const std::string &sig, bool local) { 214 | out << TAG_INVOKE_END << "|sig=" << sig << "|local=" << (local?"true":"false") << "\n"; 215 | } 216 | 217 | /** 218 | * Print a linker tag for generating a field access. 219 | * @param sig a symbolic reference to the field. The reference may be 220 | * unqualified, in which case the target classname will be resolved by the linker. 221 | * @param local if true, then the access is to this instance rather than an external instance. 222 | */ 223 | void JVMWriter::printGetField(const std::string &sig, bool local) { 224 | out << TAG_GET_FIELD << "|sig=" << sig << "|local=" << (local?"true":"false") << "\n"; 225 | } 226 | 227 | /** 228 | * Print a linker tag for loading a resolved class name on the stack. At link time, 229 | * this generates a "ldc" instruction for the resolved class name. 230 | * @param sig a symbolic reference to the method to invoke. The reference may be 231 | * unqualified, in which case the target classname will be resolved by the linker. 232 | */ 233 | void JVMWriter::printLoadClassNameForMethod(const std::string &sig) { 234 | out << TAG_CLASSNAME_FOR_METHOD << "|sig=" << sig << "\n"; 235 | } 236 | 237 | /** 238 | * Print the linker declarations placeholder. The linker will replace this with 239 | * field declarations for the members it creates. 240 | */ 241 | void JVMWriter::printDeclareLinkerFields() { 242 | out << TAG_LINKER_DECLARATIONS << "\n"; 243 | } 244 | 245 | /** 246 | * Print the linker initializations placeholder. The linker will replace this 247 | * with code for initializing the fields it defined. 248 | */ 249 | void JVMWriter::printInitLinkerFields() { 250 | out << TAG_LINKER_INITIALIZATIONS << "\n"; 251 | } 252 | 253 | void JVMWriter::printTrc(const std::string &sig) { 254 | if (!trace) 255 | return; 256 | (*trace) << sig << '\n'; 257 | trcLineNum++; 258 | std::string::size_type pos; 259 | for(pos=0;(pos=sig.find('\n',pos))!=std::string::npos;pos++) 260 | trcLineNum++; 261 | 262 | } 263 | 264 | -------------------------------------------------------------------------------- /backend/sections.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2010 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | /** 26 | * Print the header. 27 | */ 28 | void JVMWriter::printHeader() { 29 | out << ".bytecode 49.0\n"; 30 | if(debug >= 1) 31 | out << ".source " << sourcename << "\n"; 32 | out << ".class public " << classname << "\n" 33 | ".super java/lang/Object\n\n" << "\n" 34 | ".implements lljvm/runtime/Module" << "\n"; 35 | out << "; ;;START LINKER DECLARATIONS;; ;\n"; 36 | printDeclareLinkerFields(); 37 | out << "; ;;END LINKER DECLARATIONS;; ;\n\n"; 38 | } 39 | 40 | /** 41 | * Print the field declarations. 42 | */ 43 | void JVMWriter::printFields() { 44 | out << "; Fields\n"; 45 | 46 | for(Module::global_iterator i = module->global_begin(), 47 | e = module->global_end(); i != e; i++) { 48 | if(i->isDeclaration()) { 49 | out << ";.extern field "; 50 | externRefs.insert(i); 51 | } else 52 | out << ".field " 53 | << (i->hasLocalLinkage() ? "private " : "public ") 54 | << "final "; 55 | out << getValueName(i) << ' ' << getTypeDescriptor(i->getType()); 56 | if(debug >= 3) 57 | out << " ; " << *i; 58 | else 59 | out << '\n'; 60 | } 61 | out << '\n'; 62 | } 63 | 64 | /** 65 | * Print the list of external methods. 66 | */ 67 | void JVMWriter::printExternalMethods() { 68 | out << "; External methods\n"; 69 | for(Module::const_iterator i = module->begin(), 70 | e = module->end(); i != e; i++) { 71 | if(i->isDeclaration() && !i->isIntrinsic()) { 72 | const Function *f = i; 73 | const FunctionType *ty = f->getFunctionType(); 74 | out << ";.extern method " 75 | << getValueName(f) << getCallSignature(ty); 76 | if(debug >= 3) 77 | out << " ; " << *ty; 78 | out << '\n'; 79 | externRefs.insert(f); 80 | } 81 | } 82 | out << '\n'; 83 | } 84 | 85 | /** 86 | * Print the class constructor. 87 | */ 88 | void JVMWriter::printConstructor() { 89 | out << "; Constructor\n" 90 | ".method public ()V\n"; 91 | printSimpleInstruction("aload_0"); 92 | printSimpleInstruction("invokespecial","java/lang/Object/()V"); 93 | printSimpleInstruction("return"); 94 | printSimpleInstruction(".limit stack 1"); 95 | printSimpleInstruction(".limit locals 1"); 96 | out << ".end method\n\n"; 97 | 98 | out << ".method public initialize(Llljvm/runtime/Context;)V\n"; 99 | 100 | printSimpleInstruction(".limit stack 12"); 101 | printSimpleInstruction(".limit locals 2"); 102 | 103 | out << "\n;;;START LINKER INITIALIZATIONS;;;\n"; 104 | printInitLinkerFields(); 105 | out << ";;;END LINKER INITIALIZATIONS;;;\n\n"; 106 | 107 | 108 | out << "\n\t; allocate global variables\n"; 109 | 110 | for(Module::global_iterator i = module->global_begin(), 111 | e = module->global_end(); i != e; i++) { 112 | if(!i->isDeclaration()) { 113 | const GlobalVariable *g = i; 114 | const Constant *c = g->getInitializer(); 115 | printSimpleInstruction("aload_0"); 116 | printStartInvocationTag(); 117 | printConstLoad( 118 | APInt(32, targetData->getTypeAllocSize(c->getType()), false)); 119 | printEndInvocationTag("lljvm/runtime/Memory/allocateData(I)I"); 120 | printSimpleInstruction("putfield", 121 | classname + "/" + getValueName(g) + " I"); 122 | } 123 | } 124 | 125 | out << "\n\t; initialize global variables\n"; 126 | for(Module::global_iterator i = module->global_begin(), 127 | e = module->global_end(); i != e; i++) { 128 | if(!i->isDeclaration()) { 129 | const GlobalVariable *g = i; 130 | const Constant *c = g->getInitializer(); 131 | printSimpleInstruction("aload_0"); 132 | printSimpleInstruction("getfield", 133 | classname + "/" + getValueName(g) + " I"); 134 | printStaticConstant(c); 135 | printSimpleInstruction("pop"); 136 | out << '\n'; 137 | } 138 | } 139 | 140 | out << "\n" 141 | "\treturn\n" 142 | ".end method\n\n"; 143 | 144 | 145 | out << ".method public destroy(Llljvm/runtime/Context;)V\n"; 146 | printSimpleInstruction("return"); 147 | printSimpleInstruction(".limit stack 0"); 148 | printSimpleInstruction(".limit locals 2"); 149 | out << ".end method\n\n"; 150 | 151 | } 152 | 153 | /** 154 | * Print the main method. 155 | */ 156 | void JVMWriter::printMainMethod() { 157 | const Function *f = module->getFunction("main"); 158 | if(!f || f->isDeclaration()) 159 | return; 160 | 161 | out << ".method public static main([Ljava/lang/String;)V\n"; 162 | printSimpleInstruction(".limit stack 6"); 163 | printSimpleInstruction(".limit locals 2"); 164 | printSimpleInstruction("new","lljvm/runtime/DefaultContext"); 165 | printSimpleInstruction("dup"); 166 | printSimpleInstruction("invokespecial","lljvm/runtime/DefaultContext/()V"); 167 | printSimpleInstruction("dup"); 168 | printSimpleInstruction("astore_1"); 169 | printSimpleInstruction("ldc",classname); 170 | printSimpleInstruction("invokeinterface","lljvm/runtime/Context/getModule(Ljava/lang/Class;)Ljava/lang/Object; 2"); 171 | printSimpleInstruction("checkcast",classname); 172 | if(f->arg_size() == 0) { 173 | printSimpleInstruction("invokevirtual",classname + "/main()I"); 174 | } else if(f->arg_size() == 2) { 175 | Function::const_arg_iterator arg1, arg2; 176 | arg1 = arg2 = f->arg_begin(); arg2++; 177 | if(!arg1->getType()->isIntegerTy() 178 | || arg2->getType()->getTypeID() != Type::PointerTyID) 179 | llvm_unreachable("main function has invalid type signature"); 180 | printSimpleInstruction("aload_0"); 181 | printSimpleInstruction("arraylength"); 182 | 183 | printSimpleInstruction("aload_1"); 184 | printSimpleInstruction("ldc","lljvm/runtime/Memory"); 185 | printSimpleInstruction("invokeinterface","lljvm/runtime/Context/getModule(Ljava/lang/Class;)Ljava/lang/Object; 2"); 186 | printSimpleInstruction("checkcast","lljvm/runtime/Memory"); 187 | printSimpleInstruction("aload_0"); 188 | printSimpleInstruction("invokevirtual", 189 | "lljvm/runtime/Memory/storeStack([Ljava/lang/String;)I"); 190 | 191 | printSimpleInstruction("invokevirtual", classname + "/main(" 192 | + getTypeDescriptor(arg1->getType()) 193 | + getTypeDescriptor(arg2->getType()) + ")I"); 194 | } else { 195 | llvm_unreachable("main function has invalid number of arguments"); 196 | } 197 | 198 | printSimpleInstruction("aload_1"); 199 | printSimpleInstruction("ldc","lljvm/lib/c"); 200 | printSimpleInstruction("invokeinterface","lljvm/runtime/Context/getModule(Ljava/lang/Class;)Ljava/lang/Object; 2"); 201 | printSimpleInstruction("checkcast","lljvm/lib/c"); 202 | printSimpleInstruction("swap"); 203 | printSimpleInstruction("invokevirtual", "lljvm/lib/c/exit(I)V"); 204 | printSimpleInstruction("return"); 205 | out << ".end method\n"; 206 | } 207 | 208 | -------------------------------------------------------------------------------- /backend/types.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "backend.h" 24 | 25 | /** 26 | * Return the bit width of the given type. 27 | * 28 | * @param ty the type 29 | * @param expand specifies whether to expand the type to 32 bits 30 | * @return the bit width 31 | */ 32 | unsigned int JVMWriter::getBitWidth(const Type *ty, bool expand) { 33 | if(ty->getTypeID() == Type::ArrayTyID 34 | || ty->getTypeID() == Type::VectorTyID 35 | || ty->getTypeID() == Type::StructTyID 36 | || ty->getTypeID() == Type::PointerTyID) 37 | return 32; 38 | 39 | unsigned int n = ty->getPrimitiveSizeInBits(); 40 | switch(n) { 41 | case 1: 42 | case 8: 43 | case 16: 44 | case 32: if(expand) return 32; 45 | case 64: return n; 46 | default: 47 | errs() << "Bits = " << n << '\n'; 48 | llvm_unreachable("Unsupported integer width"); 49 | } 50 | } 51 | 52 | /** 53 | * Return the ID of the given type. 54 | * 55 | * @param ty the type 56 | * @param expand specifies whether to expand the type to 32 bits 57 | * @return the type ID 58 | */ 59 | char JVMWriter::getTypeID(const Type *ty, bool expand) { 60 | switch(ty->getTypeID()) { 61 | case Type::VoidTyID: 62 | return 'V'; 63 | case Type::IntegerTyID: 64 | switch(getBitWidth(ty, expand)) { 65 | case 1: return 'Z'; 66 | case 8: return 'B'; 67 | case 16: return 'S'; 68 | case 32: return 'I'; 69 | case 64: return 'J'; 70 | } 71 | case Type::FloatTyID: 72 | return 'F'; 73 | case Type::DoubleTyID: 74 | return 'D'; 75 | case Type::PointerTyID: 76 | case Type::StructTyID: 77 | case Type::ArrayTyID: 78 | case Type::VectorTyID: 79 | return 'I'; 80 | default: 81 | errs() << "Type = " << *ty << '\n'; 82 | llvm_unreachable("Invalid type"); 83 | } 84 | } 85 | /** 86 | * Return the name of the given type. 87 | * 88 | * @param ty the type 89 | * @param expand specifies whether to expand the type to 32 bits 90 | * @return the type name 91 | */ 92 | std::string JVMWriter::getTypeName(const Type *ty, bool expand) { 93 | switch(getTypeID(ty, expand)) { 94 | case 'V': return "void"; 95 | case 'Z': return "boolean"; 96 | case 'B': return "byte"; 97 | case 'S': return "short"; 98 | case 'I': return "int"; 99 | case 'J': return "long"; 100 | case 'F': return "float"; 101 | case 'D': return "double"; 102 | } 103 | } 104 | 105 | /** 106 | * Return the type descriptor of the given type. 107 | * 108 | * @param ty the type 109 | * @param expand specifies whether to expand the type to 32 bits 110 | * @return the type descriptor 111 | */ 112 | std::string JVMWriter::getTypeDescriptor(const Type *ty, bool expand) { 113 | return std::string() + getTypeID(ty, expand); 114 | } 115 | 116 | /** 117 | * Return the type postfix of the given type. 118 | * 119 | * @param ty the type 120 | * @param expand specifies whether to expand the type to 32 bits 121 | * @return the type postfix 122 | */ 123 | std::string JVMWriter::getTypePostfix(const Type *ty, bool expand) { 124 | switch(ty->getTypeID()) { 125 | case Type::VoidTyID: 126 | return "void"; 127 | case Type::IntegerTyID: 128 | return "i" + utostr(getBitWidth(ty, expand)); 129 | case Type::FloatTyID: 130 | return "f32"; 131 | case Type::DoubleTyID: 132 | return "f64"; 133 | case Type::PointerTyID: 134 | case Type::StructTyID: 135 | case Type::ArrayTyID: 136 | case Type::VectorTyID: 137 | return "i32"; 138 | default: 139 | errs() << "TypeID = " << ty->getTypeID() << '\n'; 140 | llvm_unreachable("Invalid type"); 141 | } 142 | } 143 | 144 | /** 145 | * Return the type prefix of the given type. 146 | * 147 | * @param ty the type 148 | * @param expand specifies whether to expand the type to 32 bits 149 | * @return the type prefix 150 | */ 151 | std::string JVMWriter::getTypePrefix(const Type *ty, bool expand) { 152 | switch(getTypeID(ty, expand)) { 153 | case 'Z': 154 | case 'B': return "b"; 155 | case 'S': return "s"; 156 | case 'I': return "i"; 157 | case 'J': return "l"; 158 | case 'F': return "f"; 159 | case 'D': return "d"; 160 | case 'V': llvm_unreachable("void has no prefix"); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'eclipse' 3 | apply plugin: 'findbugs' 4 | 5 | //Java 7 6 | sourceCompatibility = 1.7 7 | targetCompatibility = 1.7 8 | 9 | task wrapper(type: Wrapper) { 10 | gradleVersion = '2.13' 11 | } 12 | 13 | 14 | //FindBugs lint tool 15 | findbugs { 16 | ignoreFailures = true 17 | toolVersion = "3.0.1" 18 | sourceSets = [sourceSets.main] 19 | reportsDir = file("$project.buildDir/reports/findbugs") 20 | effort = "max" 21 | } 22 | 23 | tasks.withType(FindBugs) { 24 | reports { 25 | xml.enabled false 26 | html.enabled true 27 | } 28 | } 29 | 30 | repositories { 31 | mavenCentral() 32 | } 33 | 34 | //get more info from tests 35 | test { 36 | testLogging { 37 | exceptionFormat = 'full' 38 | //see https://discuss.gradle.org/t/whats-upcoming-in-gradle-1-1-test-logging/7741 39 | events "passed", "skipped", "failed", "standardError", "standardOut" 40 | } 41 | } 42 | 43 | dependencies { 44 | testCompile 'junit:junit:4.12' 45 | } 46 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjakway/lljvm/18d8d749593bbdc3850d61a3960d0ae3f21a7617/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Apr 29 11:01:09 EDT 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/AbstractFileHandle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.io; 24 | 25 | import java.io.IOException; 26 | 27 | import lljvm.runtime.Error; 28 | import lljvm.runtime.Memory; 29 | 30 | /** 31 | * A minimal implementation of the FileHandle interface. 32 | * 33 | * @author David Roberts 34 | */ 35 | public abstract class AbstractFileHandle implements FileHandle { 36 | /** Specifies whether this file descriptor supports reading */ 37 | protected final boolean read; 38 | /** Specifies whether this file descriptor supports writing */ 39 | protected final boolean write; 40 | /** Specifies whether to enable synchronous I/O */ 41 | protected final boolean synchronous; 42 | 43 | protected final Memory memory; 44 | protected final Error error; 45 | 46 | /** 47 | * Construct a new instance with the given read/write capabilities. 48 | * 49 | * @param read specifies whether this file descriptor supports 50 | * reading 51 | * @param write specifies whether this file descriptor supports 52 | * writing 53 | */ 54 | protected AbstractFileHandle(boolean read, boolean write, 55 | boolean synchronous) { 56 | this.memory = Memory.getMemorySingleton(); 57 | this.error = Error.getErrorSingleton(memory); 58 | this.read = read; 59 | this.write = write; 60 | this.synchronous = synchronous; 61 | } 62 | 63 | /** 64 | * Reads the next byte of data. 65 | * 66 | * @return the next byte of data, or -1 on EOF 67 | * @throws IOException if an I/O error occurs 68 | */ 69 | protected int read() throws IOException { 70 | return -1; 71 | } 72 | 73 | /** 74 | * Returns true if there is at least one byte available for reading. 75 | * 76 | * @return true if there is at least one byte available 77 | * for reading 78 | * @throws IOException if an I/O error occurs 79 | */ 80 | protected boolean available() throws IOException { 81 | return false; 82 | } 83 | 84 | @Override 85 | public int read(int buf, int count) { 86 | if(!read) 87 | return error.errno(Error.EINVAL); 88 | int num_bytes = 0; 89 | try { 90 | while(num_bytes < count) { 91 | int b = read(); 92 | if(b < 0) 93 | break; 94 | memory.store(buf++, (byte) b); 95 | num_bytes++; 96 | if(!available()) 97 | break; 98 | } 99 | } catch(IOException e) { 100 | return error.errno(Error.EIO); 101 | } 102 | return num_bytes; 103 | } 104 | 105 | /** 106 | * Writes the given byte. 107 | * 108 | * @param b the byte to be written 109 | * @throws IOException if an I/O error occurs 110 | */ 111 | protected void write(int b) throws IOException {} 112 | 113 | /** 114 | * Forces any buffered bytes to be written. 115 | * 116 | * @throws IOException if an I/O error occurs 117 | */ 118 | protected void flush() throws IOException {} 119 | 120 | public int write(int buf, int count) { 121 | if(!write) 122 | return error.errno(Error.EINVAL); 123 | int num_bytes = 0; 124 | try { 125 | while(num_bytes < count) { 126 | write(memory.load_i8(buf++)); 127 | num_bytes++; 128 | } 129 | if(synchronous) 130 | flush(); 131 | } catch(IOException e) { 132 | return error.errno(Error.EIO); 133 | } 134 | return num_bytes; 135 | } 136 | 137 | public int seek(int offset, int whence) { 138 | return error.errno(Error.ESPIPE); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/DefaultStandardHandleFactory.java: -------------------------------------------------------------------------------- 1 | package lljvm.io; 2 | 3 | public class DefaultStandardHandleFactory extends StreamStandardHandleFactory { 4 | public DefaultStandardHandleFactory() { 5 | super(System.in,System.out,System.err); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/FileHandle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.io; 24 | 25 | import java.io.Closeable; 26 | 27 | /** 28 | * Interface for performing operations on a file descriptor. 29 | * 30 | * @author David Roberts 31 | */ 32 | public interface FileHandle extends Closeable { 33 | /** 34 | * Read from this file descriptor. 35 | * 36 | * @param buf the buffer to read the bytes into 37 | * @param count the maximum number of bytes to read 38 | * @return the number of bytes read on success, -1 on error 39 | */ 40 | public int read(int buf, int count); 41 | 42 | /** 43 | * Write to this file descriptor. 44 | * 45 | * @param buf the buffer of bytes to be written 46 | * @param count the maximum number of bytes to write 47 | * @return the number of bytes written on success, -1 on error 48 | */ 49 | public int write(int buf, int count); 50 | 51 | /** 52 | * Reposition file descriptor offset. 53 | * 54 | * @param offset where to reposition the offset according to the 55 | * directive whence 56 | * @param whence specifies the reference point to which offset refers 57 | * @return the resulting offset on success, -1 on error 58 | */ 59 | public int seek(int offset, int whence); 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/FileSystem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.io; 24 | 25 | /** 26 | * An interface for interacting with the file system. 27 | * 28 | * @author David Roberts 29 | */ 30 | public interface FileSystem { 31 | /** 32 | * Create and open a file or device. 33 | * 34 | * @param pathname the name of the file 35 | * @param flags the file status flags 36 | * @param mode the permissions for the newly created file 37 | * @return the new file handle 38 | */ 39 | public FileHandle open(String pathname, int flags, int mode); 40 | 41 | /** 42 | * Open a file or device. 43 | * 44 | * @param pathname the name of the file 45 | * @param flags the file status flags 46 | * @return the new file handle 47 | */ 48 | public FileHandle open(String pathname, int flags); 49 | 50 | /** 51 | * Change the name or location of a file. 52 | * 53 | * @param oldpath the current path of the file 54 | * @param newpath the new path of the file 55 | * @return true on success 56 | */ 57 | public boolean rename(String oldpath, String newpath); 58 | 59 | /** 60 | * Create a new (hard) link to an existing file. 61 | * 62 | * @param oldpath the existing file 63 | * @param newpath the link to be created, unless newpath already exists 64 | * @return true on success 65 | */ 66 | public boolean link(String oldpath, String newpath); 67 | 68 | /** 69 | * Delete a name from the file system. 70 | * 71 | * @param pathname the name to delete 72 | * @return true on success 73 | */ 74 | public boolean unlink(String pathname); 75 | 76 | /** 77 | * Change the working directory. 78 | * 79 | * @param path the new working directory 80 | * @return true on success 81 | */ 82 | public boolean chdir(String path); 83 | 84 | /** 85 | * Return the absolute pathname of the current working directory. 86 | * 87 | * @return the current working directory 88 | */ 89 | public String getcwd(); 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/InputStreamFileHandle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.io; 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | 28 | /** 29 | * Implements the FileHandle interface, backed by an InputStream. 30 | * 31 | * @author David Roberts 32 | */ 33 | public class InputStreamFileHandle extends AbstractFileHandle { 34 | /** The input stream */ 35 | private InputStream inputStream; 36 | 37 | /** 38 | * Construct a new instance with the given input stream. 39 | * 40 | * @param inputStream the input stream 41 | */ 42 | public InputStreamFileHandle(InputStream inputStream) { 43 | super(true, false, false); 44 | this.inputStream = inputStream; 45 | } 46 | 47 | protected int read() throws IOException { 48 | return inputStream.read(); 49 | } 50 | 51 | protected boolean available() throws IOException { 52 | return inputStream.available() != 0; 53 | } 54 | 55 | public void close() throws IOException { 56 | inputStream.close(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/NativeFileSystem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.io; 24 | 25 | import java.io.File; 26 | import java.io.IOException; 27 | 28 | import lljvm.runtime.Error; 29 | import lljvm.runtime.Memory; 30 | import lljvm.runtime.IO; 31 | 32 | /** 33 | * Implements the FileSystem interface using the native Java I/O operations. 34 | * 35 | * @author David Roberts 36 | */ 37 | public class NativeFileSystem implements FileSystem { 38 | /** User working directory system property */ 39 | private static final String USER_DIR = System.getProperty("user.dir"); 40 | /** Current working directory */ 41 | private File cwd = (USER_DIR == null ? new File("") : new File(USER_DIR)); 42 | 43 | private Error error = Error.getErrorSingleton(Memory.getMemorySingleton()); 44 | 45 | public NativeFileSystem() { 46 | } 47 | 48 | /** 49 | * Return the File object representing the file with the given name, 50 | * relative to the current working directory if applicable. 51 | * 52 | * @param name the name of the file 53 | * @return the File object representing the file 54 | */ 55 | private File newFile(String name) { 56 | File file = new File(name); 57 | if(!file.isAbsolute()) 58 | file = new File(cwd, name); 59 | return file; 60 | } 61 | 62 | public FileHandle open(String pathname, int flags, int mode) { 63 | File file = newFile(pathname); 64 | try { 65 | if(file.createNewFile()) { 66 | file.setReadable( 67 | (mode & (IO.S_IRUSR|IO.S_IRGRP|IO.S_IROTH)) != 0, 68 | (mode & (IO.S_IRGRP|IO.S_IROTH)) == 0); 69 | file.setWritable( 70 | (mode & (IO.S_IWUSR|IO.S_IWGRP|IO.S_IWOTH)) != 0, 71 | (mode & (IO.S_IWGRP|IO.S_IWOTH)) == 0); 72 | file.setExecutable( 73 | (mode & (IO.S_IXUSR|IO.S_IXGRP|IO.S_IXOTH)) != 0, 74 | (mode & (IO.S_IXGRP|IO.S_IXOTH)) == 0); 75 | } else { // file already exists 76 | if((flags & IO.O_EXCL) != 0) { 77 | error.errno(Error.EEXIST); 78 | return null; 79 | } 80 | } 81 | } catch(IOException e) { 82 | error.errno(Error.EACCES); 83 | return null; 84 | } 85 | return open(file, flags); 86 | } 87 | 88 | public FileHandle open(String pathname, int flags) { 89 | return open(newFile(pathname), flags); 90 | } 91 | 92 | /** 93 | * Open a file handle for the given file. 94 | * 95 | * @param file the File object representing the file 96 | * @param flags the file status flags 97 | * @return the new file handle 98 | */ 99 | private FileHandle open(File file, int flags) { 100 | try { 101 | return new RandomAccessFileHandle(file, flags); 102 | } catch(IOException e) { 103 | error.errno(Error.EACCES); 104 | return null; 105 | } 106 | } 107 | 108 | public boolean rename(String oldpath, String newpath) { 109 | File oldfile = newFile(oldpath); 110 | File newfile = newFile(newpath); 111 | return oldfile.renameTo(newfile); 112 | } 113 | 114 | public boolean link(String oldpath, String newpath) { 115 | // TODO: Java 7: 117 | return false; 118 | } 119 | 120 | public boolean unlink(String pathname) { 121 | return false; 122 | } 123 | 124 | public boolean chdir(String path) { 125 | File newCWD = newFile(path); 126 | if(!newCWD.exists()) 127 | return false; 128 | cwd = newCWD; 129 | return true; 130 | } 131 | 132 | public String getcwd() { 133 | return cwd.getAbsolutePath(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/OutputStreamFileHandle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.io; 24 | 25 | import java.io.IOException; 26 | import java.io.OutputStream; 27 | 28 | /** 29 | * Implements the FileHandle interface, backed by an OutputStream. 30 | * 31 | * @author David Roberts 32 | */ 33 | public class OutputStreamFileHandle extends AbstractFileHandle { 34 | /** The output stream */ 35 | private OutputStream outputStream; 36 | 37 | /** 38 | * Construct a new instance with the given output stream. 39 | * 40 | * @param outputStream the output stream 41 | */ 42 | public OutputStreamFileHandle(OutputStream outputStream) { 43 | super(false, true, false); 44 | this.outputStream = outputStream; 45 | } 46 | 47 | protected void write(int b) throws IOException { 48 | outputStream.write(b); 49 | } 50 | 51 | protected void flush() throws IOException { 52 | outputStream.flush(); 53 | } 54 | 55 | public void close() throws IOException { 56 | outputStream.close(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/RandomAccessFileHandle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.io; 24 | 25 | import java.io.File; 26 | import java.io.IOException; 27 | import java.io.RandomAccessFile; 28 | import java.nio.ByteBuffer; 29 | 30 | import lljvm.runtime.Error; 31 | import lljvm.runtime.IO; 32 | import lljvm.runtime.Memory; 33 | 34 | /** 35 | * Implements the FileHandle interface, backed by a RandomAccessFile. 36 | * 37 | * @author David Roberts 38 | */ 39 | public class RandomAccessFileHandle extends AbstractFileHandle { 40 | /** The file */ 41 | private final RandomAccessFile file; 42 | /** 43 | * Construct a new instance for the given file, with the given flags. 44 | * 45 | * @param file the File object representing the file 46 | * @param flags the file status flags 47 | * @throws IOException if an error occurs while opening the file 48 | */ 49 | public RandomAccessFileHandle(File file, int flags) 50 | throws IOException { 51 | super((flags & IO.O_WRONLY) == 0, 52 | (flags & (IO.O_WRONLY|IO.O_RDWR)) != 0, 53 | (flags & IO.O_SYNC) != 0); 54 | this.file = new RandomAccessFile(file, this.write ? "rw" : "r"); 55 | if(this.write && (flags & IO.O_TRUNC) != 0) 56 | this.file.getChannel().truncate(0); 57 | } 58 | 59 | protected int read() throws IOException { 60 | return file.read(); 61 | } 62 | 63 | protected boolean available() throws IOException { 64 | return file.getFilePointer() < file.length(); 65 | } 66 | 67 | protected void write(int b) throws IOException { 68 | file.write(b); 69 | } 70 | 71 | protected void flush() throws IOException { 72 | file.getFD().sync(); 73 | } 74 | 75 | public void close() throws IOException { 76 | file.close(); 77 | } 78 | 79 | public int seek(int offset, int whence) { 80 | long n = offset; 81 | try { 82 | switch(whence) { 83 | case IO.SEEK_SET: break; 84 | case IO.SEEK_CUR: n += file.getFilePointer(); break; 85 | case IO.SEEK_END: n += file.length(); break; 86 | default: return error.errno(Error.EINVAL); 87 | } 88 | file.seek(n); 89 | } catch(IOException e) { 90 | return error.errno(Error.EINVAL); 91 | } 92 | if(n > Integer.MAX_VALUE) 93 | return error.errno(Error.EOVERFLOW); 94 | return (int) n; 95 | } 96 | 97 | @Override 98 | public int write(int buf, int count) { 99 | if(!write) 100 | return error.errno(Error.EINVAL); 101 | 102 | final int result; 103 | try { 104 | if (count==0) { 105 | result = 0; 106 | } else if (count==1) { 107 | file.writeByte(memory.load_i8(buf)); 108 | result = 1; 109 | } else { 110 | PageWriter writer = new PageWriter(); 111 | memory.getPages(writer, buf, count); 112 | if (writer.ioExc!=null) 113 | throw writer.ioExc; 114 | result = writer.count; 115 | } 116 | if(synchronous) 117 | flush(); 118 | } catch(IOException e) { 119 | return error.errno(Error.EIO); 120 | } 121 | return result; 122 | } 123 | 124 | private class PageWriter implements Memory.PageConsumer { 125 | IOException ioExc; 126 | int count; 127 | PageWriter() {} 128 | @Override 129 | public boolean next(ByteBuffer buf) { 130 | while(buf.hasRemaining()) { 131 | try { 132 | count += file.getChannel().write(buf); 133 | } catch (IOException e) { 134 | ioExc = e; 135 | return false; 136 | } 137 | } 138 | return true; 139 | } 140 | } 141 | 142 | @Override 143 | public int read(int buf, int count) { 144 | if(!read) 145 | return error.errno(Error.EINVAL); 146 | final int result; 147 | try { 148 | if (count==0) { 149 | result = 0; 150 | } else if (count==1) { 151 | int val = file.read(); 152 | if (val>=0) { 153 | memory.store(buf,(byte)val); 154 | result = 1; 155 | } else { 156 | result = 0; 157 | } 158 | } else { 159 | PageReader reader = new PageReader(); 160 | memory.getPages(reader, buf, count); 161 | if (reader.ioExc!=null) 162 | return error.errno(Error.EIO); 163 | result = reader.count; 164 | } 165 | } catch (IOException e) { 166 | return error.errno(Error.EIO); 167 | } 168 | return result; 169 | } 170 | 171 | class PageReader implements Memory.PageConsumer { 172 | IOException ioExc; 173 | int count; 174 | PageReader() {} 175 | @Override 176 | public boolean next(ByteBuffer buf) { 177 | while(buf.hasRemaining()) { 178 | try { 179 | int r = file.getChannel().read(buf); 180 | if (r<0) 181 | return false; 182 | count += r; 183 | } catch (IOException e) { 184 | ioExc = e; 185 | return false; 186 | } 187 | } 188 | return true; 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/StandardHandleFactory.java: -------------------------------------------------------------------------------- 1 | package lljvm.io; 2 | 3 | public interface StandardHandleFactory { 4 | FileHandle createStdin(); 5 | FileHandle createStdout(); 6 | FileHandle createStderr(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/StreamStandardHandleFactory.java: -------------------------------------------------------------------------------- 1 | package lljvm.io; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | 7 | public class StreamStandardHandleFactory implements StandardHandleFactory { 8 | private final InputStream stdin; 9 | private final OutputStream stdout; 10 | private final OutputStream stderr; 11 | 12 | public StreamStandardHandleFactory(InputStream stdin, OutputStream stdout, OutputStream stderr) { 13 | super(); 14 | this.stdin = stdin; 15 | this.stdout = stdout; 16 | this.stderr = stderr; 17 | } 18 | 19 | @Override 20 | public FileHandle createStdin() { 21 | return new InputStreamFileHandle(stdin); 22 | } 23 | 24 | @Override 25 | public FileHandle createStdout() { 26 | return new OutputStreamFileHandle(stdout); 27 | } 28 | 29 | @Override 30 | public FileHandle createStderr() { 31 | return new OutputStreamFileHandle(stderr); 32 | } 33 | 34 | /** 35 | * Decorates an input stream such that {@link InputStream#close()} has no effect. 36 | * @param stream the base stream 37 | * @return the decorated stream 38 | */ 39 | public static InputStream noClose(InputStream stream) { 40 | return new NoCloseInputStream(stream); 41 | } 42 | /** 43 | * Decorates an output stream such that {@link OutputStream#close()} is equivalent to {@link OutputStream#flush()}. 44 | * @param stream the base stream 45 | * @return the decorated stream 46 | */ 47 | public static OutputStream noClose(OutputStream stream) { 48 | return new NoCloseOutputStream(stream); 49 | } 50 | 51 | private static final class NoCloseOutputStream extends OutputStream { 52 | private final OutputStream out; 53 | 54 | public NoCloseOutputStream(OutputStream out) { 55 | super(); 56 | this.out = out; 57 | } 58 | 59 | @Override 60 | public void write(int b) throws IOException { 61 | out.write(b); 62 | } 63 | 64 | @Override 65 | public void write(byte[] b) throws IOException { 66 | out.write(b); 67 | } 68 | 69 | @Override 70 | public void write(byte[] b, int off, int len) throws IOException { 71 | out.write(b, off, len); 72 | } 73 | 74 | @Override 75 | public void flush() throws IOException { 76 | out.flush(); 77 | } 78 | 79 | @Override 80 | public void close() throws IOException { 81 | out.flush(); 82 | } 83 | } 84 | 85 | private static final class NoCloseInputStream extends InputStream { 86 | private final InputStream in; 87 | 88 | NoCloseInputStream(InputStream in) { 89 | super(); 90 | this.in = in; 91 | } 92 | 93 | @Override 94 | public int read() throws IOException { 95 | return in.read(); 96 | } 97 | 98 | @Override 99 | public int read(byte[] b) throws IOException { 100 | return in.read(b); 101 | } 102 | 103 | @Override 104 | public int read(byte[] b, int off, int len) throws IOException { 105 | return in.read(b,off,len); 106 | } 107 | 108 | @Override 109 | public long skip(long n) throws IOException { 110 | return in.skip(n); 111 | } 112 | 113 | @Override 114 | public int available() throws IOException { 115 | return in.available(); 116 | } 117 | 118 | @Override 119 | public void close() {} 120 | 121 | @Override 122 | public synchronized void mark(int readlimit) { 123 | in.mark(readlimit); 124 | } 125 | 126 | @Override 127 | public synchronized void reset() throws IOException { 128 | in.reset(); 129 | } 130 | 131 | @Override 132 | public boolean markSupported() { 133 | return in.markSupported(); 134 | } 135 | 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/lljvm/io/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The LLJVM I/O Support Library. 3 | */ 4 | package lljvm.io; 5 | -------------------------------------------------------------------------------- /src/main/java/lljvm/runtime/Error.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.runtime; 24 | 25 | /** 26 | * Provides errno - the number of the last error, along with its associated 27 | * error value constants. 28 | * 29 | * @author David Roberts 30 | */ 31 | public final class Error { 32 | 33 | private static Error error = null; 34 | public static final Error getErrorSingleton(Memory mem) 35 | { 36 | //if error is null we have to allocate memory for errno in the singleton, which is why we need a Memory parameter 37 | if(error == null) 38 | { 39 | error = new Error(mem); 40 | } 41 | return error; 42 | } 43 | 44 | /** Not super-user */ 45 | public static final int EPERM = 1; 46 | /** No such file or directory */ 47 | public static final int ENOENT = 2; 48 | /** No such process */ 49 | public static final int ESRCH = 3; 50 | /** final interrupted system call */ 51 | public static final int EINTR = 4; 52 | /** I/O error */ 53 | public static final int EIO = 5; 54 | /** No such device or address */ 55 | public static final int ENXIO = 6; 56 | /** Arg list too long */ 57 | public static final int E2BIG = 7; 58 | /** Exec format error */ 59 | public static final int ENOEXEC = 8; 60 | /** Bad file number */ 61 | public static final int EBADF = 9; 62 | /** No children */ 63 | public static final int ECHILD = 10; 64 | /** No more processes */ 65 | public static final int EAGAIN = 11; 66 | /** Not enough core */ 67 | public static final int ENOMEM = 12; 68 | /** Permission denied */ 69 | public static final int EACCES = 13; 70 | /** Bad address */ 71 | public static final int EFAULT = 14; 72 | /** Block device required */ 73 | public static final int ENOTBLK = 15; 74 | /** Mount device busy */ 75 | public static final int EBUSY = 16; 76 | /** File exists */ 77 | public static final int EEXIST = 17; 78 | /** Cross-device link */ 79 | public static final int EXDEV = 18; 80 | /** No such device */ 81 | public static final int ENODEV = 19; 82 | /** Not a directory */ 83 | public static final int ENOTDIR = 20; 84 | /** Is a directory */ 85 | public static final int EISDIR = 21; 86 | /** Invalid argument */ 87 | public static final int EINVAL = 22; 88 | /** Too many open files in system */ 89 | public static final int ENFILE = 23; 90 | /** Too many open files */ 91 | public static final int EMFILE = 24; 92 | /** Not a typewriter */ 93 | public static final int ENOTTY = 25; 94 | /** Text file busy */ 95 | public static final int ETXTBSY = 26; 96 | /** File too large */ 97 | public static final int EFBIG = 27; 98 | /** No space left on device */ 99 | public static final int ENOSPC = 28; 100 | /** Illegal seek */ 101 | public static final int ESPIPE = 29; 102 | /** Read only file system */ 103 | public static final int EROFS = 30; 104 | /** Too many links */ 105 | public static final int EMLINK = 31; 106 | /** Broken pipe */ 107 | public static final int EPIPE = 32; 108 | /** Math arg out of domain of func */ 109 | public static final int EDOM = 33; 110 | /** Math result not representable */ 111 | public static final int ERANGE = 34; 112 | /** No message of desired type */ 113 | public static final int ENOMSG = 35; 114 | /** Identifier removed */ 115 | public static final int EIDRM = 36; 116 | /** Channel number out of range */ 117 | public static final int ECHRNG = 37; 118 | /** Level 2 not synchronized */ 119 | public static final int EL2NSYNC = 38; 120 | /** Level 3 halted */ 121 | public static final int EL3HLT = 39; 122 | /** Level 3 reset */ 123 | public static final int EL3RST = 40; 124 | /** Link number out of range */ 125 | public static final int ELNRNG = 41; 126 | /** Protocol driver not attached */ 127 | public static final int EUNATCH = 42; 128 | /** No CSI structure available */ 129 | public static final int ENOCSI = 43; 130 | /** Level 2 halted */ 131 | public static final int EL2HLT = 44; 132 | /** Deadlock condition */ 133 | public static final int EDEADLK = 45; 134 | /** No record locks available */ 135 | public static final int ENOLCK = 46; 136 | /** Invalid exchange */ 137 | public static final int EBADE = 50; 138 | /** Invalid request descriptor */ 139 | public static final int EBADR = 51; 140 | /** Exchange full */ 141 | public static final int EXFULL = 52; 142 | /** No anode */ 143 | public static final int ENOANO = 53; 144 | /** Invalid request code */ 145 | public static final int EBADRQC = 54; 146 | /** Invalid slot */ 147 | public static final int EBADSLT = 55; 148 | /** File locking deadlock error */ 149 | public static final int EDEADLOCK = 56; 150 | /** Bad font file fmt */ 151 | public static final int EBFONT = 57; 152 | /** Device not a stream */ 153 | public static final int ENOSTR = 60; 154 | /** No data (for no delay io) */ 155 | public static final int ENODATA = 61; 156 | /** Timer expired */ 157 | public static final int ETIME = 62; 158 | /** Out of streams resources */ 159 | public static final int ENOSR = 63; 160 | /** Machine is not on the network */ 161 | public static final int ENONET = 64; 162 | /** Package not installed */ 163 | public static final int ENOPKG = 65; 164 | /** The object is remote */ 165 | public static final int EREMOTE = 66; 166 | /** The link has been severed */ 167 | public static final int ENOLINK = 67; 168 | /** Advertise error */ 169 | public static final int EADV = 68; 170 | /** Srmount error */ 171 | public static final int ESRMNT = 69; 172 | /** Communication error on send */ 173 | public static final int ECOMM = 70; 174 | /** Protocol error */ 175 | public static final int EPROTO = 71; 176 | /** Multihop attempted */ 177 | public static final int EMULTIHOP = 74; 178 | /** Inode is remote (not really error) */ 179 | public static final int ELBIN = 75; 180 | /** Cross mount pofinal int (not really error) */ 181 | public static final int EDOTDOT = 76; 182 | /** Trying to read unreadable message */ 183 | public static final int EBADMSG = 77; 184 | /** Inappropriate file type or format */ 185 | public static final int EFTYPE = 79; 186 | /** Given log. name not unique */ 187 | public static final int ENOTUNIQ = 80; 188 | /** f.d. invalid for this operation */ 189 | public static final int EBADFD = 81; 190 | /** Remote address changed */ 191 | public static final int EREMCHG = 82; 192 | /** Can't access a needed shared lib */ 193 | public static final int ELIBACC = 83; 194 | /** Accessing a corrupted shared lib */ 195 | public static final int ELIBBAD = 84; 196 | /** .lib section in a.out corrupted */ 197 | public static final int ELIBSCN = 85; 198 | /** Attempting to link in too many libs */ 199 | public static final int ELIBMAX = 86; 200 | /** Attempting to exec a shared library */ 201 | public static final int ELIBEXEC = 87; 202 | /** Function not implemented */ 203 | public static final int ENOSYS = 88; 204 | /** No more files */ 205 | public static final int ENMFILE = 89; 206 | /** Directory not empty */ 207 | public static final int ENOTEMPTY = 90; 208 | /** File or path name too long */ 209 | public static final int ENAMETOOLONG = 91; 210 | /** Too many symbolic links */ 211 | public static final int ELOOP = 92; 212 | /** Operation not supported on transport endpofinal int */ 213 | public static final int EOPNOTSUPP = 95; 214 | /** Protocol family not supported */ 215 | public static final int EPFNOSUPPORT = 96; 216 | /** Connection reset by peer */ 217 | public static final int ECONNRESET = 104; 218 | /** No buffer space available */ 219 | public static final int ENOBUFS = 105; 220 | /** Address family not supported by protocol family */ 221 | public static final int EAFNOSUPPORT = 106; 222 | /** Protocol wrong type for socket */ 223 | public static final int EPROTOTYPE = 107; 224 | /** Socket operation on non-socket */ 225 | public static final int ENOTSOCK = 108; 226 | /** Protocol not available */ 227 | public static final int ENOPROTOOPT = 109; 228 | /** Can't send after socket shutdown */ 229 | public static final int ESHUTDOWN = 110; 230 | /** Connection refused */ 231 | public static final int ECONNREFUSED = 111; 232 | /** Address already in use */ 233 | public static final int EADDRINUSE = 112; 234 | /** Connection aborted */ 235 | public static final int ECONNABORTED = 113; 236 | /** Network is unreachable */ 237 | public static final int ENETUNREACH = 114; 238 | /** Network final interface is not configured */ 239 | public static final int ENETDOWN = 115; 240 | /** Connection timed out */ 241 | public static final int ETIMEDOUT = 116; 242 | /** Host is down */ 243 | public static final int EHOSTDOWN = 117; 244 | /** Host is unreachable */ 245 | public static final int EHOSTUNREACH = 118; 246 | /** Connection already in progress */ 247 | public static final int EINPROGRESS = 119; 248 | /** Socket already connected */ 249 | public static final int EALREADY = 120; 250 | /** Destination address required */ 251 | public static final int EDESTADDRREQ = 121; 252 | /** Message too long */ 253 | public static final int EMSGSIZE = 122; 254 | /** Unknown protocol */ 255 | public static final int EPROTONOSUPPORT = 123; 256 | /** Socket type not supported */ 257 | public static final int ESOCKTNOSUPPORT = 124; 258 | /** Address not available */ 259 | public static final int EADDRNOTAVAIL = 125; 260 | /** Connection aborted by network */ 261 | public static final int ENETRESET = 126; 262 | /** Socket is already connected */ 263 | public static final int EISCONN = 127; 264 | /** Socket is not connected */ 265 | public static final int ENOTCONN = 128; 266 | /** Too many references: cannot splice */ 267 | public static final int ETOOMANYREFS = 129; 268 | /** Too many processes */ 269 | public static final int EPROCLIM = 130; 270 | /** Too many users */ 271 | public static final int EUSERS = 131; 272 | /** Disk quota exceeded */ 273 | public static final int EDQUOT = 132; 274 | /** Stale file handle */ 275 | public static final int ESTALE = 133; 276 | /** Not supported */ 277 | public static final int ENOTSUP = 134; 278 | /** No medium (in tape drive) */ 279 | public static final int ENOMEDIUM = 135; 280 | /** No such host or network path */ 281 | public static final int ENOSHARE = 136; 282 | /** Filename exists with different case */ 283 | public static final int ECASECLASH = 137; 284 | /** Illegal byte sequence */ 285 | public static final int EILSEQ = 138; 286 | /** Value too large for defined data type */ 287 | public static final int EOVERFLOW = 139; 288 | /** Operation canceled */ 289 | public static final int ECANCELED = 140; 290 | /** State not recoverable */ 291 | public static final int ENOTRECOVERABLE = 141; 292 | /** Previous owner died */ 293 | public static final int EOWNERDEAD = 142; 294 | 295 | private Memory memory; 296 | 297 | /** Pointer to errno */ 298 | public int errno; 299 | 300 | private Error(Memory memory) 301 | { 302 | this.memory = memory; 303 | errno = memory.allocateData(4); 304 | } 305 | 306 | /** 307 | * Returns the value of errno. 308 | * 309 | * @return the value of errno 310 | */ 311 | public int errno() { 312 | return memory.load_i32(errno); 313 | } 314 | 315 | /** 316 | * Sets the value of errno. 317 | * 318 | * @param value the new value of errno 319 | * @return -1 320 | */ 321 | public int errno(int value) { 322 | memory.store(errno, value); 323 | return -1; 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /src/main/java/lljvm/runtime/IO.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.runtime; 24 | 25 | import java.io.IOException; 26 | 27 | import lljvm.io.FileHandle; 28 | import lljvm.io.FileSystem; 29 | import lljvm.io.NativeFileSystem; 30 | import lljvm.io.StandardHandleFactory; 31 | import lljvm.io.DefaultStandardHandleFactory; 32 | import lljvm.runtime.Error; 33 | import lljvm.runtime.Memory; 34 | 35 | /** 36 | * Provides methods and constants related to I/O. 37 | * 38 | * @author David Roberts 39 | */ 40 | public final class IO { 41 | public static IO ioSingleton = null; 42 | public static final IO getIOSingleton() 43 | { 44 | if(ioSingleton == null) 45 | { 46 | ioSingleton = new IO(); 47 | } 48 | return ioSingleton; 49 | } 50 | 51 | /** Open for reading only */ 52 | public static final int O_RDONLY = 0x0000; 53 | /** Open for writing only */ 54 | public static final int O_WRONLY = 0x0001; 55 | /** Open for reading and writing */ 56 | public static final int O_RDWR = 0x0002; 57 | /** Open in append mode */ 58 | public static final int O_APPEND = 0x0008; 59 | /** Create the file if it does not already exist */ 60 | public static final int O_CREAT = 0x0200; 61 | /** Truncate the file to length 0 if it already exists */ 62 | public static final int O_TRUNC = 0x0400; 63 | /** Ensure that this call creates the file */ 64 | public static final int O_EXCL = 0x0800; 65 | /** Open for synchronous I/O */ 66 | public static final int O_SYNC = 0x2000; 67 | /** Open in non-blocking mode */ 68 | public static final int O_NONBLOCK = 0x4000; 69 | /** Don't assign a tty on this open */ 70 | public static final int O_NOCTTY = 0x8000; 71 | 72 | /** Set file offset to offset */ 73 | public static final int SEEK_SET = 0; 74 | /** Set file offset to current plus offset */ 75 | public static final int SEEK_CUR = 1; 76 | /** Set file offset to EOF plus offset */ 77 | public static final int SEEK_END = 2; 78 | 79 | /** Read permission, owner */ 80 | public static final int S_IRUSR = 0000400; 81 | /** Write permission, owner */ 82 | public static final int S_IWUSR = 0000200; 83 | /** Execute/search permission, owner */ 84 | public static final int S_IXUSR = 0000100; 85 | /** All permissions, owner */ 86 | public static final int S_IRWXU = (S_IRUSR | S_IWUSR | S_IXUSR); 87 | /** Read permission, group */ 88 | public static final int S_IRGRP = 0000040; 89 | /** Write permission, group */ 90 | public static final int S_IWGRP = 0000020; 91 | /** Execute/search permission, group */ 92 | public static final int S_IXGRP = 0000010; 93 | /** All permissions, group */ 94 | public static final int S_IRWXG = (S_IRGRP | S_IWGRP | S_IXGRP); 95 | /** Read permission, others */ 96 | public static final int S_IROTH = 0000004; 97 | /** Write permission, others */ 98 | public static final int S_IWOTH = 0000002; 99 | /** Execute/search permission, others */ 100 | public static final int S_IXOTH = 0000001; 101 | /** All permissions, others */ 102 | public static final int S_IRWXO = (S_IROTH | S_IWOTH | S_IXOTH); 103 | 104 | /** The maximum number of files that a process can open */ 105 | public static final int OPEN_MAX = 1<<10; 106 | 107 | /** File descriptor table */ 108 | private final FileHandle[] fileDescriptors = 109 | new FileHandle[OPEN_MAX]; 110 | /** Number of file descriptors that have been opened */ 111 | private int numFileDescriptors = 0; 112 | 113 | /** The file system interface */ 114 | private FileSystem fileSystem = new NativeFileSystem(); 115 | 116 | private Memory memory = Memory.getMemorySingleton(); 117 | private Error error = Error.getErrorSingleton(Memory.getMemorySingleton()); 118 | 119 | /** 120 | * Prevent this class from being instantiated. 121 | */ 122 | private IO() { 123 | StandardHandleFactory shf = new DefaultStandardHandleFactory(); 124 | putFileHandle(shf.createStdin()); 125 | putFileHandle(shf.createStdout()); 126 | putFileHandle(shf.createStderr()); 127 | } 128 | 129 | /** 130 | * Open and possibly create a file or device. 131 | * 132 | * @param pathname the pathname of the file 133 | * @param flags the file status flags 134 | * @param args a pointer to the packed list of varargs 135 | * i.e. a pointer to the mode argument, the permissions 136 | * for the newly created file (if applicable) 137 | * @return the new file descriptor on success, -1 on error 138 | */ 139 | public int open(int pathname, int flags, int args) { 140 | String name = memory.load_string(pathname); 141 | FileHandle fileHandle = ((flags & O_CREAT) != 0) 142 | ? fileSystem.open(name, flags, memory.load_i32(args)) 143 | : fileSystem.open(name, flags); 144 | if(fileHandle == null) 145 | return -1; 146 | return putFileHandle(fileHandle); 147 | } 148 | 149 | /** 150 | * Add the given FileHandle to the file descriptor table. 151 | * 152 | * @param fileHandle the FileHandle 153 | * @return the new file descriptor on success, -1 on error 154 | */ 155 | private int putFileHandle(FileHandle fileHandle) { 156 | if(numFileDescriptors >= OPEN_MAX) 157 | return error.errno(Error.ENFILE); 158 | int fd = numFileDescriptors++; 159 | fileDescriptors[fd] = fileHandle; 160 | return fd; 161 | } 162 | 163 | /** 164 | * Returns the FileHandle for the given file descriptor. 165 | * 166 | * @param fd the file descriptor 167 | * @return the FileHandle 168 | */ 169 | private FileHandle getFileHandle(int fd) { 170 | return fileDescriptors[fd]; 171 | } 172 | 173 | /** 174 | * Read from a file descriptor. 175 | * 176 | * @param fd the file descriptor to be read 177 | * @param buf the buffer to read the bytes into 178 | * @param count the maximum number of bytes to read 179 | * @return the number of bytes read on success, -1 on error 180 | */ 181 | public int read(int fd, int buf, int count) { 182 | return getFileHandle(fd).read(buf, count); 183 | } 184 | 185 | /** 186 | * Write to a file descriptor. 187 | * 188 | * @param fd the file descriptor to be written to 189 | * @param buf the buffer of bytes to be written 190 | * @param count the maximum number of bytes to write 191 | * @return the number of bytes written on success, -1 on error 192 | */ 193 | public int write(int fd, int buf, int count) { 194 | return getFileHandle(fd).write(buf, count); 195 | } 196 | 197 | /** 198 | * Reposition file offset. 199 | * 200 | * @param fd the file descriptor whose offset to reposition 201 | * @param offset where to reposition the offset according to the directive 202 | * whence 203 | * @param whence specifies the reference point to which offset refers 204 | * @return the resulting offset on success, -1 on error 205 | */ 206 | public int lseek(int fd, int offset, int whence) { 207 | return getFileHandle(fd).seek(offset, whence); 208 | } 209 | 210 | /** 211 | * Close the given file descriptor. 212 | * 213 | * @param fd the file descriptor 214 | * @return 0 on success, -1 on error 215 | */ 216 | public int close(int fd) { 217 | if(fd < 0 || fd >= OPEN_MAX || fileDescriptors[fd] == null) 218 | return error.errno(Error.EBADF); 219 | try { 220 | fileDescriptors[fd].close(); 221 | fileDescriptors[fd] = null; 222 | } catch(IOException e) { 223 | return error.errno(Error.EIO); 224 | } 225 | return 0; 226 | } 227 | 228 | /** 229 | * Close all open file descriptors, including the standard input, standard 230 | * output and standard error streams. This method should only be called 231 | * during an exit. 232 | */ 233 | public void close() { 234 | for(int fd = 0; fd < numFileDescriptors; fd++) 235 | close(fd); 236 | } 237 | 238 | /** 239 | * Test whether the given file descriptor refers to a terminal. 240 | * 241 | * @param fd the file descriptor to test 242 | * @return 1 if fd refers to a terminal, 0 otherwise 243 | */ 244 | public int isatty(int fd) { 245 | if(fd < 0 || fd > 2) 246 | return 0; 247 | //TODO - Can we do better than this? 248 | return java.lang.System.console() != null ? 1 : 0; 249 | } 250 | 251 | /** 252 | * Change the name or location of a file. 253 | * 254 | * @param oldpath the current path of the file 255 | * @param newpath the new path of the file 256 | * @return 0 on success, -1 on error 257 | */ 258 | public int _rename(int oldpath, int newpath) { 259 | if(!fileSystem.rename(memory.load_string(oldpath), 260 | memory.load_string(newpath))) 261 | return error.errno(Error.EACCES); 262 | return 0; 263 | } 264 | 265 | /** 266 | * Create a new (hard) link to an existing file. 267 | * 268 | * @param oldpath the existing file 269 | * @param newpath the link to be created, unless newpath already exists 270 | * @return 0 on success, -1 on error 271 | */ 272 | public int link(int oldpath, int newpath) { 273 | if(!fileSystem.link(memory.load_string(oldpath), 274 | memory.load_string(newpath))) 275 | return error.errno(Error.EMLINK); 276 | return 0; 277 | } 278 | 279 | /** 280 | * Delete a name from the file system. 281 | * 282 | * @param pathname the name to delete 283 | * @return 0 on success, -1 on error 284 | */ 285 | public int unlink(int pathname) { 286 | if(!fileSystem.unlink(memory.load_string(pathname))) 287 | return error.errno(Error.ENOENT); 288 | return 0; 289 | } 290 | 291 | /** 292 | * Stats the file pointed to by path and fills in buf. 293 | * 294 | * @param path the path of the file to be stat-ed 295 | * @param buf a pointer to the stat structure to be filled in 296 | * @return 0 on success, -1 on error 297 | */ 298 | public int stat(int path, int buf) { 299 | // TODO: st->st_mode = S_IFCHR; 300 | return 0; 301 | } 302 | 303 | /** 304 | * Stats the file specified by the given file descriptor and fills in buf. 305 | * 306 | * @param fd the file descriptor to be stat-ed 307 | * @param buf a pointer to the stat structure to be filled in 308 | * @return 0 on success, -1 on error 309 | */ 310 | public int fstat(int fd, int buf) { 311 | // TODO: buf->st_mode = S_IFCHR; 312 | return 0; 313 | } 314 | 315 | /** 316 | * Change the working directory. 317 | * 318 | * @param path the new working directory 319 | * @return 0 on success, -1 on error 320 | */ 321 | public int chdir(int path) { 322 | if(!fileSystem.chdir(memory.load_string(path))) 323 | return error.errno(Error.ENOENT); 324 | return 0; 325 | } 326 | 327 | /** 328 | * Copy the absolute pathname of the current working directory into the 329 | * given buffer. 330 | * 331 | * @param buf the result buffer 332 | * @param size the size of the buffer 333 | * @return buf on success, NULL on error 334 | */ 335 | public int getcwd(int buf, int size) { 336 | return memory.store(buf, fileSystem.getcwd(), size); 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /src/main/java/lljvm/runtime/Jump.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.runtime; 24 | 25 | /** 26 | * Provides support for setjmp/longjmp. 27 | * 28 | * @author David Roberts 29 | */ 30 | @SuppressWarnings("serial") 31 | public class Jump extends RuntimeException { 32 | /** The ID of this Jump */ 33 | public final int id; 34 | /** The return value of this Jump */ 35 | public final int value; 36 | 37 | /** 38 | * Create a new Jump with the given ID and return value. 39 | * 40 | * @param id the ID 41 | * @param value the return value 42 | */ 43 | Jump(int id, int value) { 44 | this.id = id; 45 | this.value = (value == 0 ? 1 : value); 46 | } 47 | 48 | /** 49 | * Disable Throwable.fillInStackTrace as it is costly and unnecessary for 50 | * this purpose. 51 | */ 52 | public Throwable fillInStackTrace() { 53 | return this; 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/lljvm/runtime/JumpFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.runtime; 24 | 25 | /** 26 | * Module containing the {@code setjmp} and {@code longjmp} functions. 27 | * @author David Roberts (wrote the original code contained in the Jump class) 28 | * @author Joshua Arnold (refactored into this class) 29 | * 30 | */ 31 | public class JumpFunctions { 32 | 33 | /** The number of setjmp calls that have been made so far */ 34 | private int numJumps = 0; 35 | 36 | private Memory memory = Memory.getMemorySingleton(); 37 | 38 | /** 39 | * Create a new Jump with the given ID and return value. 40 | * 41 | * @param id the ID 42 | * @param value the return value 43 | */ 44 | public JumpFunctions() { 45 | } 46 | 47 | /** 48 | * Save the stack context in env for later use by longjmp. 49 | * 50 | * @param env where to store the stack context 51 | * @return the unique ID of this jump target 52 | */ 53 | public int setjmp(int env) { 54 | int id = ++numJumps; 55 | int stackDepth = memory.getStackDepth(); 56 | memory.store(env, id); 57 | memory.store(env+4, stackDepth); 58 | return id; 59 | } 60 | 61 | /** 62 | * Jump to the last call of setjmp with the corresponding env argument, 63 | * causing setjmp to return the given value. 64 | * If the return value is 0, 1 will be returned instead. 65 | * 66 | * @param env the stack context stored by setjmp 67 | * @param val the return value 68 | */ 69 | public void longjmp(int env, int val) { 70 | int id = memory.load_i32(env); 71 | int stackDepth = memory.load_i32(env+4); 72 | memory.destroyStackFrames(memory.getStackDepth() - stackDepth); 73 | throw new Jump(id, val); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/lljvm/runtime/Math.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.runtime; 24 | 25 | /** 26 | * Provides common math functions either not provided by Java, or provided 27 | * under a different name to that of libm. 28 | * 29 | * @author David Roberts 30 | */ 31 | public final class Math { 32 | /** Not a Number */ 33 | public static final int FP_NAN = 0; 34 | /** Positive/negative infinity */ 35 | public static final int FP_INFINITE = 1; 36 | /** Zero */ 37 | public static final int FP_ZERO = 2; 38 | /** Too small to be represented in normalised format */ 39 | public static final int FP_SUBNORMAL = 3; 40 | /** Not NaN, infinite, zero, or sub-normal */ 41 | public static final int FP_NORMAL = 4; 42 | 43 | private Memory memory; 44 | 45 | /** 46 | * Prevent this class from being instantiated. 47 | */ 48 | private Math() { 49 | } 50 | 51 | 52 | /** 53 | * Inverse hyperbolic sine function. 54 | * 55 | * @param x the value whose inverse hyperbolic sine is to be returned 56 | * @return the value whose hyperbolic sine is x 57 | */ 58 | public double asinh(double x) { 59 | return java.lang.Math.log(x + java.lang.Math.sqrt(x * x + 1)); 60 | } 61 | 62 | /** 63 | * Inverse hyperbolic cosine function. 64 | * 65 | * @param x the value whose inverse hyperbolic cosine is to be returned 66 | * @return the value whose hyperbolic cosine is x 67 | */ 68 | public double acosh(double x) { 69 | return java.lang.Math.log( 70 | x + java.lang.Math.sqrt(x - 1) * java.lang.Math.sqrt(x + 1)); 71 | } 72 | 73 | /** 74 | * Inverse hyperbolic tangent function. 75 | * 76 | * @param x the value whose inverse hyperbolic tangent is to be returned 77 | * @return the value whose hyperbolic tangent is x 78 | */ 79 | public double atanh(double x) { 80 | return java.lang.Math.log((1 + x) / (1 - x)) / 2; 81 | } 82 | 83 | /** 84 | * Base-2 exponential function. 85 | * 86 | * @param x the exponent 87 | * @return 2 raised to the power of x 88 | */ 89 | public double exp2(double x) { 90 | return java.lang.Math.pow(2, x); 91 | } 92 | 93 | /** 94 | * Return the absolute value of the double value. 95 | * 96 | * @param x the double value 97 | * @return the absolute value of the double value 98 | */ 99 | public double fabs(double x) { 100 | return java.lang.Math.abs(x); 101 | } 102 | 103 | /** 104 | * Return the absolute value of the float value. 105 | * 106 | * @param x the float value 107 | * @return the absolute value of the float value 108 | */ 109 | public float fabsf(float x) { 110 | return java.lang.Math.abs(x); 111 | } 112 | 113 | /** 114 | * Return the floating-point remainder of dividing x by y, rounded 115 | * towards zero to an integer. 116 | * 117 | * @param x the dividend 118 | * @param y the divisor 119 | * @return the remainder of the division 120 | */ 121 | public double fmod(double x, double y) { 122 | return x % y; 123 | } 124 | 125 | /** 126 | * Return the floating-point remainder of dividing x by y, rounded 127 | * towards zero to an integer. 128 | * 129 | * @param x the dividend 130 | * @param y the divisor 131 | * @return the remainder of the division 132 | */ 133 | public float fmodf(float x, float y) { 134 | return x % y; 135 | } 136 | 137 | /** 138 | * Classify the given floating point number. 139 | * 140 | * @param x the floating point number 141 | * @return the integer representing the type of x: 142 | * one of FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL 143 | */ 144 | public int fpclassify(double x) { 145 | if(Double.isNaN(x)) 146 | return FP_NAN; 147 | if(Double.isInfinite(x)) 148 | return FP_INFINITE; 149 | if(x == 0.0) 150 | return FP_ZERO; 151 | if(java.lang.Math.abs(x) < Double.MIN_NORMAL) 152 | return FP_SUBNORMAL; 153 | return FP_NORMAL; 154 | } 155 | 156 | /** 157 | * Split the given number into a normalised fraction and an exponent. 158 | * 159 | * @param x the number to split 160 | * @param exp where to store the exponent 161 | * @return the normalised fraction 162 | */ 163 | public double frexp(double x, int exp) { 164 | if(x == 0.0) 165 | memory.store(exp, 0); 166 | if(Double.isNaN(x) || Double.isInfinite(x) || x == 0.0) 167 | return x; 168 | long bits = Double.doubleToRawLongBits(x); 169 | memory.store(exp, (int) ((bits & 0x7ff0000000000000L) >>> 52) - 1022); 170 | return Double.longBitsToDouble( 171 | (bits & 0x800fffffffffffffL) | 0x3fe0000000000000L); 172 | } 173 | 174 | /** 175 | * Split the given number into a normalised fraction and an exponent. 176 | * 177 | * @param x the number to split 178 | * @param exp where to store the exponent 179 | * @return the normalised fraction 180 | */ 181 | public float frexpf(float x, int exp) { 182 | if(x == 0.0) 183 | memory.store(exp, 0); 184 | if(Float.isNaN(x) || Float.isInfinite(x) || x == 0.0) 185 | return x; 186 | int bits = Float.floatToRawIntBits(x); 187 | memory.store(exp, ((bits & 0x7f800000) >>> 23) - 126); 188 | return Float.intBitsToFloat((bits & 0x7fffff) | 0x3f000000); 189 | } 190 | 191 | /** 192 | * Test whether the given value is infinite. 193 | * 194 | * @param x the value to test 195 | * @return 1 if x is +infinity, -1 if x is -infinity, 0 otherwise 196 | */ 197 | public int isinf(double x) { 198 | if(Double.isInfinite(x)) 199 | return x == Double.POSITIVE_INFINITY ? 1 : -1; 200 | return 0; 201 | } 202 | 203 | /** 204 | * Test whether the given value is Not a Number. 205 | * 206 | * @param x the value to test 207 | * @return 1 if x is NaN, 0 otherwise 208 | */ 209 | public int isnan(double x) { 210 | return Double.isNaN(x) ? 1 : 0; 211 | } 212 | 213 | /** 214 | * Break the given number into an integral part and a fractional part. 215 | * 216 | * @param x the number to break 217 | * @param iptr where to store the integral part 218 | * @return the fractional part 219 | */ 220 | public double modf(double x, int iptr) { 221 | double i = (double) (int) x; 222 | memory.store(iptr, i); 223 | return x - i; 224 | } 225 | 226 | /** 227 | * Break the given number into an integral part and a fractional part. 228 | * 229 | * @param x the number to break 230 | * @param iptr where to store the integral part 231 | * @return the fractional part 232 | */ 233 | public float modff(float x, int iptr) { 234 | float i = (float) (int) x; 235 | memory.store(iptr, i); 236 | return x - i; 237 | } 238 | 239 | /** 240 | * Return the floating-point remainder of dividing x by y, rounded 241 | * towards the nearest integer, ties to even. 242 | * 243 | * @param x the dividend 244 | * @param y the divisor 245 | * @return the remainder of the division 246 | */ 247 | public double remainder(double x, double y) { 248 | return java.lang.Math.IEEEremainder(x, y); 249 | } 250 | 251 | /** 252 | * Return the floating-point remainder of dividing x by y, rounded 253 | * towards the nearest integer, ties to even. 254 | * 255 | * @param x the dividend 256 | * @param y the divisor 257 | * @return the remainder of the division 258 | */ 259 | public float remainderf(float x, float y) { 260 | return (float) remainder(x, y); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /src/main/java/lljvm/runtime/Posix.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.runtime; 24 | 25 | import lljvm.runtime.Error; 26 | import lljvm.runtime.Memory; 27 | 28 | /** 29 | * Provides routines defined by the POSIX API. 30 | * 31 | * @author David Roberts 32 | */ 33 | public final class Posix { 34 | 35 | private Error error = Error.getErrorSingleton(Memory.getMemorySingleton()); 36 | 37 | public Posix() { 38 | } 39 | 40 | /** 41 | * Manipulate the given file descriptor. 42 | * 43 | * @param fd the file descriptor to manipulate 44 | * @param cmd specifies the operation to perform 45 | * @param args a pointer to the packed list of varargs 46 | * i.e. a pointer to the arg argument (if applicable) 47 | * @return the appropriate value on success, -1 on error 48 | */ 49 | public int fcntl(int fd, int cmd, int args) { 50 | // TODO: implement 51 | return error.errno(Error.EACCES); 52 | } 53 | 54 | /** 55 | * Get the time. 56 | * 57 | * @param tv a pointer to the timeval structure to set 58 | * @param tz a pointer to the timezone structure to set 59 | * @return 0 on success, -1 on error 60 | */ 61 | public int gettimeofday(int tv, int tz) { 62 | // TODO: implement 63 | return error.errno(Error.EINVAL); 64 | } 65 | 66 | /** 67 | * Examine and change blocked signals. 68 | * 69 | * @param how specifies the behaviour of the call 70 | * @param set specifies how to change the blocked signals 71 | * @param oldset where to store the previous value of the signal mask 72 | * @return 0 on success, -1 on error 73 | */ 74 | public int sigprocmask(int how, int set, int oldset) { 75 | // TODO: implement 76 | return error.errno(Error.EINVAL); 77 | } 78 | 79 | /** 80 | * Get configuration information. 81 | * 82 | * @param name the name of the variable to retrieve 83 | * @return the value of the system resource on success, -1 on error 84 | */ 85 | public int sysconf(int name) { 86 | // TODO: implement 87 | return error.errno(Error.EINVAL); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/lljvm/runtime/System.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 David Roberts 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | package lljvm.runtime; 24 | 25 | import java.util.concurrent.Callable; 26 | 27 | import lljvm.runtime.IO; 28 | import lljvm.runtime.Error; 29 | import lljvm.runtime.Memory; 30 | 31 | // TODO: proper environ support 32 | 33 | /** 34 | * Provides methods for interfacing with the system. 35 | * 36 | * @author David Roberts 37 | */ 38 | public final class System { 39 | 40 | private Error error = Error.getErrorSingleton(Memory.getMemorySingleton()); 41 | private IO io = IO.getIOSingleton(); 42 | 43 | /** Throw an exception instead of calling System.exit? */ 44 | private boolean throwExit = false; 45 | 46 | 47 | /** 48 | * Thrown to indicate that a call has been made to the _exit syscall. 49 | */ 50 | @SuppressWarnings("serial") 51 | public static class Exit extends java.lang.Error { 52 | /** Exit status code */ 53 | public final int status; 54 | public Exit(int status) { 55 | super(Integer.toString(status)); 56 | this.status = status; 57 | } 58 | } 59 | 60 | 61 | public System() { 62 | } 63 | 64 | 65 | public boolean isThrowExit() { 66 | return throwExit; 67 | } 68 | 69 | 70 | public void setThrowExit(boolean throwExit) { 71 | this.throwExit = throwExit; 72 | } 73 | 74 | 75 | /** 76 | * Performs any necessary cleanup, then terminates with the specified 77 | * status code. 78 | * 79 | * @param status the exit status code 80 | */ 81 | public void _exit(int status) { 82 | if(throwExit) 83 | throw new Exit(status); 84 | io.close(); 85 | java.lang.System.exit(status); 86 | } 87 | 88 | /** 89 | * Execute the program pointed to by filename. 90 | * 91 | * @param filename the name of the executable 92 | * @param argv the argument vector to be passed to the new program 93 | * @param envp an array of environment variables 94 | * @return does not return on success, -1 on error 95 | */ 96 | public int execve(int filename, int argv, int envp) { 97 | // TODO: implement 98 | return error.errno(Error.ENOMEM); 99 | } 100 | 101 | /** 102 | * Duplicate the calling process. 103 | * 104 | * @return the PID of the child process on success, -1 on error 105 | */ 106 | public int fork() { 107 | // TODO: implement 108 | return error.errno(Error.EAGAIN); 109 | } 110 | 111 | /** 112 | * Returns to process ID of the calling process. 113 | * 114 | * @return the PID of the calling process 115 | */ 116 | public int getpid() { 117 | // TODO: implement 118 | return 1; 119 | } 120 | 121 | /** 122 | * Send a signal to a process. 123 | * 124 | * @param pid the PID of the process 125 | * @param sig the signal 126 | * @return 0 on success, -1 on error 127 | */ 128 | public int kill(int pid, int sig) { 129 | // TODO: implement 130 | return error.errno(Error.EINVAL); 131 | } 132 | 133 | /** 134 | * Get process times. 135 | * 136 | * @param buf a pointer to the tms structure the process times are to be 137 | * stored in 138 | * @return the number of clock ticks that have elapsed since an 139 | * arbitrary point in the past on success, -1 on error 140 | */ 141 | public int times(int buf) { 142 | // TODO: implement 143 | return -1; 144 | } 145 | 146 | /** 147 | * Wait for a process to change state. 148 | * 149 | * @param status a pointer to the int in which status information is to be 150 | * stored 151 | * @return the PID of the terminated child on success, -1 on error 152 | */ 153 | public int wait(int status) { 154 | // TODO: implement 155 | return error.errno(Error.ECHILD); 156 | } 157 | 158 | public int catchExits(Callable f) throws Exception { 159 | try { 160 | return f.call(); 161 | } catch (Exit e) { 162 | return e.status; 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/lljvm/util/ClassInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Joshua Arnold 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package lljvm.util; 23 | 24 | 25 | import java.lang.reflect.Modifier; 26 | import java.util.ArrayList; 27 | import java.util.Collection; 28 | import java.util.Collections; 29 | import java.util.HashMap; 30 | import java.util.List; 31 | import java.util.Map; 32 | 33 | import static lljvm.util.ReflectionUtils.modifiersFrom; 34 | 35 | /** 36 | * Contains basic information about a class. 37 | *

38 | * The primary advantage of {@code ClassInfo} over {@link Class} is that the former doesn't 39 | * require the class to actually be loaded. For example, the ASM linker uses {@code ClassInfo} 40 | * to describe classes defined in an ASM source file. 41 | *

42 | * @author Joshua Arnold 43 | */ 44 | public final class ClassInfo { 45 | private final ClassName name; 46 | private final List methods; 47 | private final List fields; 48 | private final int modifiers; 49 | private int hash; 50 | 51 | private final Map methodsBySignature; 52 | private final Map fieldsBySignature; 53 | 54 | 55 | private static Map createMemberMap(Collection items) { 56 | HashMap map = new HashMap(); 57 | for(V item : items) { 58 | String uqr = item.getSignature(); 59 | if (!map.containsKey(uqr)) 60 | map.put(uqr,item); 61 | } 62 | return Collections.unmodifiableMap(map); 63 | } 64 | 65 | public ClassInfo(ClassName name, Collection methods, Collection fields, int modifiers) { 66 | super(); 67 | if (name==null) 68 | throw new IllegalArgumentException(); 69 | this.name = name; 70 | this.methods = copy(methods); 71 | this.fields = copy(fields); 72 | this.modifiers = modifiers; 73 | this.methodsBySignature = createMemberMap(methods); 74 | this.fieldsBySignature = createMemberMap(fields); 75 | } 76 | public ClassInfo(ClassName name, Collection methods, Collection fields, String...modifiers) { 77 | this(name,methods,fields,modifiersFrom(modifiers)); 78 | } 79 | public ClassInfo(ClassName name, Collection methods, Collection fields, Iterable modifiers) { 80 | this(name,methods,fields,modifiersFrom(modifiers)); 81 | } 82 | 83 | 84 | public ClassName getName() { 85 | return name; 86 | } 87 | 88 | public String getBinaryName() { 89 | return name.getBinaryName(); 90 | } 91 | 92 | public String getJavaName() { 93 | return name.getJavaName(); 94 | } 95 | 96 | public List getMethods() { 97 | return methods; 98 | } 99 | public List getFields() { 100 | return fields; 101 | } 102 | public int getModifiers() { 103 | return modifiers; 104 | } 105 | 106 | public boolean isPublic() { 107 | return Modifier.isPublic(modifiers); 108 | } 109 | 110 | public boolean isPrivate() { 111 | return Modifier.isPrivate(modifiers); 112 | } 113 | 114 | public boolean isProtected() { 115 | return Modifier.isProtected(modifiers); 116 | } 117 | 118 | public boolean isStatic() { 119 | return Modifier.isStatic(modifiers); 120 | } 121 | 122 | public boolean isFinal() { 123 | return Modifier.isFinal(modifiers); 124 | } 125 | 126 | public boolean isAbstract() { 127 | return Modifier.isAbstract(modifiers); 128 | } 129 | 130 | public boolean isInterface() { 131 | return Modifier.isInterface(modifiers); 132 | } 133 | 134 | private static List copy(Collection col) { 135 | return col != null ? Collections.unmodifiableList(new ArrayList(col)) : Collections.emptyList(); 136 | } 137 | 138 | public MethodInfo findMethod(String unqualifiedRef) { 139 | return methodsBySignature.get(unqualifiedRef); 140 | } 141 | public FieldInfo findField(String unqualifiedRef) { 142 | return fieldsBySignature.get(unqualifiedRef); 143 | } 144 | 145 | public Map getMethodMap() { 146 | return methodsBySignature; 147 | } 148 | public Map getFieldMap() { 149 | return fieldsBySignature; 150 | } 151 | 152 | @Override 153 | public int hashCode() { 154 | int h = hash; 155 | if (h==0) { 156 | h = modifiers + 757 * ( 157 | name.hashCode() + 757 * ( 158 | methodsBySignature.hashCode() + 757 * fieldsBySignature.hashCode())); 159 | h = h==0 ? -1 : h; 160 | hash = h; 161 | } 162 | return h; 163 | } 164 | 165 | /** 166 | * Defines equality of {@code ClassInfo} instances. 167 | * @return true if {@code obj} is a {@code ClassInfo} and has the same {@linkplain #getName() name}, {@linkplain #getModifiers() modifiers}, 168 | * {@linkplain #getFields() fields}, and {@link #getMethods() methods} as this {@code ClassInfo}. The order of methods and fields in their 169 | * respective lists is not considered relevant. 170 | */ 171 | @Override 172 | public boolean equals(Object obj) { 173 | if (obj==this) 174 | return true; 175 | if (!(obj instanceof ClassInfo)) 176 | return false; 177 | ClassInfo ci = (ClassInfo)obj; 178 | return modifiers==ci.modifiers && name.equals(ci.name) 179 | && methodsBySignature.equals(ci.methodsBySignature) 180 | && fieldsBySignature.equals(ci.fieldsBySignature); 181 | } 182 | 183 | @Override 184 | public String toString() { 185 | return "ClassInfo: "+getName(); 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /src/main/java/lljvm/util/ClassName.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Joshua Arnold 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package lljvm.util; 23 | 24 | 25 | public class ClassName { 26 | private final String binaryName; 27 | private final String javaName; 28 | private final int simplePos; 29 | 30 | 31 | 32 | public ClassName(String name) { 33 | if (name==null || name.isEmpty()) 34 | throw new IllegalArgumentException(); 35 | this.binaryName = name.replace('.', '/'); 36 | this.javaName = name.replace('/', '.'); 37 | int p = javaName.lastIndexOf('.'); 38 | simplePos = p<0 ? 0 : p+1; 39 | } 40 | 41 | public static ClassName from(String name) { 42 | return new ClassName(name); 43 | } 44 | 45 | public static ClassName from(Class cls) { 46 | return from(cls.getName()); 47 | } 48 | 49 | public String getBinaryName() { 50 | return binaryName; 51 | } 52 | 53 | 54 | public String getJavaName() { 55 | return javaName; 56 | } 57 | 58 | public String getSimpleName() { 59 | return javaName.substring(simplePos); 60 | } 61 | 62 | public String getBinaryPackageName() { 63 | return simplePos>0 ? binaryName.substring(0,simplePos-1) : ""; 64 | } 65 | 66 | public String getJavaPackageName() { 67 | return simplePos>0 ? binaryName.substring(0,simplePos-1) : ""; 68 | } 69 | 70 | public boolean hasSamePackageAs(ClassName other) { 71 | return getBinaryPackageName().equals(other.getBinaryPackageName()); 72 | } 73 | 74 | 75 | @Override 76 | public boolean equals(Object o) { 77 | return (o instanceof ClassName) && ((ClassName)o).javaName.equals(javaName); 78 | } 79 | @Override 80 | public int hashCode() { 81 | return javaName.hashCode(); 82 | } 83 | @Override 84 | public String toString() { 85 | return javaName; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/lljvm/util/FieldInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Joshua Arnold 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package lljvm.util; 23 | 24 | import java.lang.reflect.Field; 25 | import java.lang.reflect.Modifier; 26 | 27 | import static lljvm.util.ReflectionUtils.modifiersFrom; 28 | 29 | /** 30 | * Contains basic information about a field. 31 | *

32 | * The primary advantage of {@code FieldInfo} over {@link Field} is that the former doesn't 33 | * require the field's class to be loaded. For example, the ASM linker uses {@code FieldInfo} 34 | * to describe fields defined in an ASM source file. 35 | *

36 | * @author Joshua Arnold 37 | */ 38 | public final class FieldInfo extends MemberInfo { 39 | 40 | private final int fieldDelim; 41 | private final int typeDelim; 42 | 43 | public FieldInfo(String qualifiedSignature, int modifiers) { 44 | super(qualifiedSignature, modifiers); 45 | 46 | typeDelim = qualifiedSignature.indexOf(' '); 47 | if (typeDelim < 0) 48 | throw new IllegalArgumentException(qualifiedSignature); 49 | 50 | fieldDelim = qualifiedSignature.lastIndexOf('/', typeDelim-1); 51 | if (fieldDelim < 0) 52 | throw new IllegalArgumentException(qualifiedSignature); 53 | } 54 | 55 | public FieldInfo(String qualifiedSignature, Iterable modifiers) { 56 | this(qualifiedSignature,modifiersFrom(modifiers)); 57 | } 58 | 59 | public FieldInfo(String qualifiedSignature, String... modifiers) { 60 | this(qualifiedSignature,modifiersFrom(modifiers)); 61 | } 62 | 63 | public static FieldInfo from(Field field) { 64 | return new FieldInfo(ReflectionUtils.getQualifiedSignature(field), field.getModifiers()); 65 | } 66 | 67 | public static FieldInfo from(String className, String fieldName, String typeString, int modifiers) { 68 | return new FieldInfo(className.replace('.', '/') + "/" + fieldName +" "+typeString, modifiers); 69 | } 70 | 71 | public static FieldInfo from(String className, String fieldName, String typeString, Iterable modifiers) { 72 | return from(className, fieldName, typeString, modifiersFrom(modifiers)); 73 | } 74 | 75 | public FieldInfo forClass(String className) { 76 | return new FieldInfo(className+"/"+getSignature(), modifiers); 77 | } 78 | 79 | public String getSignature() { 80 | return qualifiedSignature.substring(fieldDelim+1); 81 | } 82 | 83 | public String getBinaryClassName() { 84 | return qualifiedSignature.substring(0,fieldDelim); 85 | } 86 | 87 | public String getMemberName() { 88 | return qualifiedSignature.substring(fieldDelim+1,typeDelim); 89 | } 90 | 91 | public String getType() { 92 | return qualifiedSignature.substring(typeDelim+1); 93 | } 94 | 95 | public boolean isVolatile() { 96 | return Modifier.isVolatile(modifiers); 97 | } 98 | 99 | public boolean isTransient() { 100 | return Modifier.isTransient(modifiers); 101 | } 102 | 103 | @Override 104 | public int hashCode() { 105 | return sigAndModsHashcode(); 106 | } 107 | 108 | @Override 109 | public boolean equals(Object obj) { 110 | return (obj instanceof FieldInfo) && sigAndModsEquals((FieldInfo)obj); 111 | } 112 | 113 | @Override 114 | public String toString() { 115 | return "FieldInfo: "+getQualifiedSignature(); 116 | } 117 | 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/lljvm/util/MemberInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Joshua Arnold 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package lljvm.util; 23 | 24 | import java.lang.reflect.Modifier; 25 | 26 | /** 27 | * Describes a method or a field. 28 | * @author Joshua Arnold 29 | */ 30 | public abstract class MemberInfo { 31 | protected final String qualifiedSignature; 32 | protected final int modifiers; 33 | MemberInfo(String qualifiedSignature, int modifiers) { 34 | super(); 35 | this.qualifiedSignature = qualifiedSignature; 36 | this.modifiers = modifiers; 37 | if (qualifiedSignature==null || qualifiedSignature.isEmpty() || qualifiedSignature.indexOf('.')>=0) 38 | throw new IllegalArgumentException(qualifiedSignature); 39 | } 40 | 41 | public final String getQualifiedSignature() { 42 | return qualifiedSignature; 43 | } 44 | 45 | public abstract String getSignature(); 46 | 47 | public abstract String getBinaryClassName(); 48 | 49 | public abstract String getMemberName(); 50 | 51 | public abstract String getType(); 52 | 53 | 54 | public final int getModifiers() { 55 | return modifiers; 56 | } 57 | 58 | public final boolean isPublic() { 59 | return Modifier.isPublic(modifiers); 60 | } 61 | 62 | public final boolean isPrivate() { 63 | return Modifier.isPrivate(modifiers); 64 | } 65 | 66 | public final boolean isProtected() { 67 | return Modifier.isProtected(modifiers); 68 | } 69 | 70 | public final boolean isStatic() { 71 | return Modifier.isStatic(modifiers); 72 | } 73 | 74 | public final boolean isFinal() { 75 | return Modifier.isFinal(modifiers); 76 | } 77 | 78 | final boolean sigAndModsEquals(MemberInfo info) { 79 | return qualifiedSignature.equals(info.qualifiedSignature) && modifiers == info.modifiers; 80 | } 81 | 82 | final int sigAndModsHashcode() { 83 | return qualifiedSignature.hashCode() + 127 * modifiers; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/lljvm/util/MethodInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Joshua Arnold 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package lljvm.util; 23 | 24 | import java.lang.reflect.Method; 25 | import java.lang.reflect.Modifier; 26 | 27 | import static lljvm.util.ReflectionUtils.modifiersFrom; 28 | 29 | /** 30 | * Contains basic information about a method. 31 | *

32 | * The primary advantage of {@code MethodInfo} over {@link Method} is that the former doesn't 33 | * require the method's class to be loaded. For example, the ASM linker uses {@code MethodInfo} 34 | * to describe methods defined in an ASM source file. 35 | *

36 | * @author Joshua Arnold 37 | */ 38 | public final class MethodInfo extends MemberInfo { 39 | 40 | private final int methodDelim; 41 | private final int typeDelim; 42 | 43 | public MethodInfo(String qualifiedSignature, int modifiers) { 44 | super(qualifiedSignature,modifiers); 45 | typeDelim = qualifiedSignature.indexOf('('); 46 | if (typeDelim < 0) 47 | throw new IllegalArgumentException(qualifiedSignature); 48 | 49 | methodDelim = qualifiedSignature.lastIndexOf('/', typeDelim-1); 50 | if (methodDelim < 0) 51 | throw new IllegalArgumentException(qualifiedSignature); 52 | } 53 | 54 | public MethodInfo(String qualifiedSignature, Iterable modifiers) { 55 | this(qualifiedSignature,modifiersFrom(modifiers)); 56 | } 57 | public MethodInfo(String qualifiedSignature, String... modifiers) { 58 | this(qualifiedSignature,modifiersFrom(modifiers)); 59 | } 60 | 61 | public static MethodInfo from(Method method) { 62 | return new MethodInfo(ReflectionUtils.getQualifiedSignature(method), method.getModifiers()); 63 | } 64 | 65 | public static MethodInfo from(String className, String methodName, String typeString, int modifiers) { 66 | return new MethodInfo(className.replace('.', '/') + "/" + methodName + typeString, modifiers); 67 | } 68 | 69 | public static MethodInfo from(String className, String methodName, String typeString, Iterable modifiers) { 70 | return from(className, methodName, typeString, modifiersFrom(modifiers)); 71 | } 72 | 73 | public MethodInfo forClass(String className) { 74 | return new MethodInfo(className+"/"+getSignature(), modifiers); 75 | } 76 | 77 | public String getSignature() { 78 | return qualifiedSignature.substring(methodDelim+1); 79 | } 80 | 81 | public String getBinaryClassName() { 82 | return qualifiedSignature.substring(0,methodDelim); 83 | } 84 | 85 | public String getMemberName() { 86 | return qualifiedSignature.substring(methodDelim+1,typeDelim); 87 | } 88 | 89 | public String getType() { 90 | return qualifiedSignature.substring(typeDelim); 91 | } 92 | 93 | public boolean isSynchronized() { 94 | return Modifier.isSynchronized(modifiers); 95 | } 96 | 97 | public boolean isAbstract() { 98 | return Modifier.isAbstract(modifiers); 99 | } 100 | 101 | public boolean isNative() { 102 | return Modifier.isNative(modifiers); 103 | } 104 | 105 | @Override 106 | public int hashCode() { 107 | return sigAndModsHashcode(); 108 | } 109 | 110 | @Override 111 | public boolean equals(Object obj) { 112 | return (obj instanceof MethodInfo) && sigAndModsEquals((MethodInfo)obj); 113 | } 114 | 115 | @Override 116 | public String toString() { 117 | return "MethodInfo: "+getQualifiedSignature(); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/lljvm/util/StreamUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Joshua Arnold 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package lljvm.util; 23 | 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.io.OutputStream; 27 | 28 | /** 29 | * Contains some generically useful utility methods. 30 | * 31 | * 32 | * @author Joshua Arnold 33 | */ 34 | public class StreamUtils { 35 | 36 | 37 | private StreamUtils() {}; 38 | 39 | public static OutputStream noClose(OutputStream out) { 40 | return new NoClose(out); 41 | } 42 | 43 | public static int readFully(InputStream strm, byte[] dest, int off, int len) throws IOException { 44 | if (len<=0) 45 | return strm.read(dest, off, len); 46 | int total = 0; 47 | while(len>0) { 48 | int r = strm.read(dest, off, len); 49 | if (r<0) 50 | return total>0 ? total : -1; 51 | total += r; 52 | off += r; 53 | len -= r; 54 | } 55 | return total; 56 | } 57 | 58 | public static void readFully(InputStream is, OutputStream dest) throws IOException { 59 | byte[] buf = new byte[1<<12]; 60 | for(int len;(len=is.read(buf))>0;) { 61 | dest.write(buf,0,len); 62 | } 63 | } 64 | 65 | 66 | private static final class NoClose extends OutputStream { 67 | private final OutputStream out; 68 | NoClose(OutputStream out) { 69 | this.out=out; 70 | } 71 | @Override 72 | public void close() throws IOException { 73 | flush(); 74 | } 75 | @Override 76 | public void write(int b) throws IOException { 77 | out.write(b); 78 | } 79 | @Override 80 | public void write(byte[] b) throws IOException { 81 | out.write(b); 82 | } 83 | @Override 84 | public void write(byte[] b, int off, int len) throws IOException { 85 | out.write(b, off, len); 86 | } 87 | @Override 88 | public void flush() throws IOException { 89 | out.flush(); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/lljvm/util/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Utility classes. 3 | */ 4 | package lljvm.util; 5 | -------------------------------------------------------------------------------- /src/test/java/ghcjvm/tests/runtime/ErrorTests.java: -------------------------------------------------------------------------------- 1 | package ghcjvm.tests.runtime; 2 | 3 | import org.junit.*; 4 | import static org.junit.Assert.*; 5 | 6 | import lljvm.runtime.Error; 7 | import lljvm.runtime.Memory; 8 | 9 | public class ErrorTests 10 | { 11 | private Error err; 12 | 13 | @Before 14 | public void setUp() 15 | { 16 | err = Error.getErrorSingleton(Memory.getMemorySingleton()); 17 | } 18 | 19 | @After 20 | public void tearDown() 21 | { 22 | 23 | } 24 | 25 | 26 | /** 27 | * sanity check that the singleton method works 28 | */ 29 | @Test 30 | public void testGetSingleton() 31 | { 32 | final Error e = Error.getErrorSingleton(Memory.getMemorySingleton()); 33 | assertNotNull(e); 34 | 35 | assertTrue(e instanceof Error); 36 | } 37 | 38 | @Test 39 | public void testSetErrno() 40 | { 41 | final int prevErrno = err.errno(); 42 | err.errno(Integer.MAX_VALUE); 43 | 44 | //set errno to max value and check 45 | final int maxVal = err.errno(); 46 | assertEquals(Integer.MAX_VALUE, maxVal); 47 | 48 | //set errno to min value and check 49 | err.errno(Integer.MIN_VALUE); 50 | final int minVal = err.errno(); 51 | assertEquals(Integer.MIN_VALUE, minVal); 52 | 53 | //reset and check 54 | err.errno(prevErrno); 55 | assertEquals(err.errno(), prevErrno); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/ghcjvm/tests/runtime/MemoryTests.java: -------------------------------------------------------------------------------- 1 | package ghcjvm.tests.runtime; 2 | 3 | import org.junit.*; 4 | import static org.junit.Assert.*; 5 | 6 | import lljvm.runtime.Memory; 7 | 8 | 9 | public class MemoryTests 10 | { 11 | /** 12 | * emulated type sizes in bytes 13 | */ 14 | private static final int LONG_SIZE = 8, 15 | INT_SIZE = 4, 16 | FLOAT_SIZE = 4, 17 | DOUBLE_SIZE=8; 18 | private Memory mem; 19 | 20 | /** 21 | * whether to store on the stack or heap 22 | */ 23 | enum Loc 24 | { 25 | STACK, HEAP 26 | } 27 | 28 | @Before 29 | public void setUp() 30 | { 31 | mem = Memory.getMemorySingleton(); 32 | } 33 | 34 | @After 35 | public void tearDown() 36 | { 37 | 38 | } 39 | 40 | @Test 41 | public void testStoreMaxLong() 42 | { 43 | assertStoreValue(Long.MAX_VALUE, Loc.STACK); 44 | } 45 | 46 | @Test 47 | public void testStoreMinLong() 48 | { 49 | assertStoreValue(Long.MIN_VALUE, Loc.STACK); 50 | } 51 | 52 | private void assertStoreValue(long value, Loc which) 53 | { 54 | final int arbitrary = 999; 55 | switch(which) 56 | { 57 | case STACK: 58 | //store 8-byte long 59 | int value_ptr = mem.storeStack(value); 60 | //store a 4-byte integer 61 | int next_ptr = mem.storeStack(arbitrary); 62 | //store another long 63 | int following_ptr = mem.storeStack(value / 2); 64 | 65 | //make sure the pointers are in the right order 66 | assertTrue(value_ptr > next_ptr); 67 | assertTrue(next_ptr > following_ptr); 68 | 69 | assertEquals(value, mem.load_i64(value_ptr)); 70 | assertEquals(arbitrary, mem.load_i32(next_ptr)); 71 | assertEquals(value / 2, mem.load_i64(following_ptr)); 72 | 73 | break; 74 | case HEAP: 75 | 76 | break; 77 | default: 78 | fail("invalid enum type for Loc which"); 79 | } 80 | } 81 | 82 | /** 83 | * sanity check that the singleton method works 84 | */ 85 | @Test 86 | public void testGetSingleton() 87 | { 88 | final Memory m = Memory.getMemorySingleton(); 89 | assertNotNull(m); 90 | 91 | assertTrue(m instanceof Memory); 92 | } 93 | } 94 | --------------------------------------------------------------------------------