pax_global_header00006660000000000000000000000064123144024320014505gustar00rootroot0000000000000052 comment=1e1fff58f8c7c21833c53103a822cbeba4ec27db ReadyTalk-avian-1e1fff5/000077500000000000000000000000001231440243200151605ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/.clang-format000066400000000000000000000002371231440243200175350ustar00rootroot00000000000000--- BasedOnStyle: Chromium IndentCaseLabels: false BreakBeforeBraces: Stroustrup AllowShortFunctionsOnASingleLine: false BreakBeforeBinaryOperators: true ... ReadyTalk-avian-1e1fff5/.gitignore000066400000000000000000000001701231440243200171460ustar00rootroot00000000000000.gdb_history build *~ .classpath .project .settings bin /lib /distrib *.pdb *.swp /*.sublime-* workspace/ src/.cproject ReadyTalk-avian-1e1fff5/.mailmap000066400000000000000000000021301231440243200165750ustar00rootroot00000000000000Carsten Elton Sørensen Carsten Elton Sørensen Dain Darnell Dain Darnell Edison Guo Jason Treadwell Jason Treadwell Jason Treadwell Jason Treadwell Jason Treadwell Jason Treadwell Jason Treadwell Jason Treadwell Jason Treadwell Joel Dice Joel Dice Joel Dice Joel Dice Anonymous Joshua Warner Matt Weaver Mike Jensen Mike Jensen Mike Jensen Terek Campbell Thiago Bedin Frustaci Zsombor Gegesy ReadyTalk-avian-1e1fff5/.travis.yml000066400000000000000000000004661231440243200172770ustar00rootroot00000000000000language: cpp env: global: secure: NhmSoQSnkmcj5BgBtVTd1X5KIECmFHwss8hzDdNmEtbGe3sIBjZksx1RSP67y/bAhuG9l8rrc0V/yMvCJY8KnjirZE9bhcY8jY8Tl1nRuUbruT7QEoufhCi79+9U1KA62PdbvHnNmoRjvwPfe3SirNbDNH0Cc3ugJnYew/c1TLQ= script: ./test/ci.sh after_success: - make javadoc - .utility/push-javadoc-to-gh-pages.shReadyTalk-avian-1e1fff5/.utility/000077500000000000000000000000001231440243200167415ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/.utility/push-javadoc-to-gh-pages.sh000077500000000000000000000014601231440243200237760ustar00rootroot00000000000000#!/bin/bash # This script was originally written by maxiaohao in the aws-mock GitHub project. # https://github.com/treelogic-swe/aws-mock/ if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo "Start to publish lastest Javadoc to gh-pages..." cd build/ if test -d gh-pages then cd gh-pages git pull else git clone --quiet --branch=gh-pages https://${GH_TOKEN}@github.com/ReadyTalk/avian gh-pages > /dev/null cd gh-pages git config user.email "travis@travis-ci.org" git config user.name "travis-ci" fi git rm -rf ./javadoc cp -Rf ../javadoc ./javadoc git add -f . git commit -m "Lastest javadoc on successful travis build $TRAVIS_BUILD_NUMBER auto-pushed to gh-pages" git push -fq origin gh-pages > /dev/null echo "Done magic with auto publishment to gh-pages." fi ReadyTalk-avian-1e1fff5/README.md000066400000000000000000000735201231440243200164460ustar00rootroot00000000000000Avian - A lightweight Java Virtual Machine (JVM) ================================================ [![Build Status](https://travis-ci.org/ReadyTalk/avian.png?branch=master)](https://travis-ci.org/ReadyTalk/avian) Quick Start ----------- #### on Linux: $ export JAVA_HOME=/usr/local/java # or wherever you have the JDK installed $ make $ build/linux-i386/avian -cp build/linux-i386/test Hello #### on Mac OS X: $ export JAVA_HOME=/Library/Java/Home $ make $ build/darwin-i386/avian -cp build/darwin-i386/test Hello #### on Windows (MSYS): $ git clone git@github.com:ReadyTalk/win32.git ../win32 $ export JAVA_HOME="C:/Program Files/Java/jdk1.6.0_07" $ make $ build/windows-i386/avian -cp build/windows-i386/test Hello #### on Windows (Cygwin): $ git clone git@github.com:ReadyTalk/win32.git ../win32 $ export JAVA_HOME="/cygdrive/c/Program Files/Java/jdk1.6.0_07" $ make $ build/windows-i386/avian -cp build/windows-i386/test Hello #### on FreeBSD: $ export JAVA_HOME=/usr/local/openjdk7 # or wherever you have the JDK installed $ gmake $ build/freebsd-x86_64/avian -cp build/freebsd-x86_64/test Hello Adjust JAVA_HOME according to your system, but be sure to use forward slashes in the path. Introduction ------------ Avian is a lightweight virtual machine and class library designed to provide a useful subset of Java's features, suitable for building self-contained applications. More information is available at the project [web site](http://oss.readytalk.com/avian). If you have any trouble building, running, or embedding Avian, please post a message to our [discussion group](http://groups.google.com/group/avian). That's also the place for any other questions, comments, or suggestions you might have. Supported Platforms ------------------- Avian can currently target the following platforms: * Linux (i386, x86_64, ARM, and 32-bit PowerPC) * Windows (i386 and x86_64) * Mac OS X (i386 and x86_64) * Apple iOS (i386 and ARM) * FreeBSD (i386, x86_64) Building -------- Build requirements include: * GNU make 3.80 or later * GCC 3.4 or later (4.5.1 or later for Windows/x86_64) or LLVM Clang 3.1 or later (see use-clang option below) * JDK 1.5 or later * MinGW 3.4 or later (only if compiling for Windows) * zlib 1.2.3 or later Earlier versions of some of these packages may also work but have not been tested. The build is directed by a single makefile and may be influenced via certain flags described below, all of which are optional. $ make \ platform={linux,windows,darwin,freebsd} \ arch={i386,x86_64,powerpc,arm} \ process={compile,interpret} \ mode={debug,debug-fast,fast,small} \ lzma= \ ios={true,false} \ bootimage={true,false} \ heapdump={true,false} \ tails={true,false} \ continuations={true,false} \ use-clang={true,false} \ openjdk= \ openjdk-src= \ android= * `platform` - the target platform * _default:_ output of $(uname -s | tr [:upper:] [:lower:]), normalized in some cases (e.g. CYGWIN_NT-5.1 -> windows) * `arch` - the target architecture * _default:_ output of $(uname -m), normalized in some cases (e.g. i686 -> i386) * `process` - choice between pure interpreter or JIT compiler * _default:_ compile * `mode` - which set of compilation flags to use to determine optimization level, debug symbols, and whether to enable assertions * _default:_ fast * `lzma` - if set, support use of LZMA to compress embedded JARs and boot images. The value of this option should be a directory containing a recent LZMA SDK (available [here](http://www.7-zip.org/sdk.html)). Currently, only version 9.20 of the SDK has been tested, but other versions might work. * _default:_ not set * `ios` - if true, cross-compile for iOS on OS X. Note that non-jailbroken iOS devices do not allow JIT compilation, so only process=interpret or bootimage=true builds will run on such devices. See [here](https://github.com/ReadyTalk/hello-ios) for an example of an Xcode project for iOS which uses Avian. * _default:_ false * `armv6` - if true, don't use any instructions newer than armv6. By default, we assume the target is armv7 or later, and thus requires explicit memory barrier instructions to ensure cache coherency * `bootimage` - if true, create a boot image containing the pre-parsed class library and ahead-of-time compiled methods. This option is only valid for process=compile builds. Note that you may need to specify both build-arch=x86_64 and arch=x86_64 on 64-bit systems where "uname -m" prints "i386". * _default:_ false * `heapdump` - if true, implement avian.Machine.dumpHeap(String), which, when called, will generate a snapshot of the heap in a simple, ad-hoc format for memory profiling purposes. See heapdump.cpp for details. * _default:_ false * `tails` - if true, optimize each tail call by replacing the caller's stack frame with the callee's. This convention ensures proper tail recursion, suitable for languages such as Scheme. This option is only valid for process=compile builds. * _default:_ false * `continuations` - if true, support continuations via the avian.Continuations methods callWithCurrentContinuation and dynamicWind. See Continuations.java for details. This option is only valid for process=compile builds. * _default:_ false * `use-clang` - if true, use LLVM's clang instead of GCC to build. Note that this does not currently affect cross compiles, only native builds. * _default:_ false * `openjdk` - if set, use the OpenJDK class library instead of the default Avian class library. See "Building with the OpenJDK Class Library" below for details. * _default:_ not set * `openjdk-src` - if this and the openjdk option above are both set, build an embeddable VM using the OpenJDK class library. The JNI components of the OpenJDK class library will be built from the sources found under the specified directory. See "Building with the OpenJDK Class Library" below for details. * _default:_ not set * `android` - if set, use the Android class library instead of the default Avian class library. See "Building with the Android Class Library" below for details. * _default:_ not set These flags determine the name of the directory used for the build. The name always starts with _${platform}-${arch}_, and each non-default build option is appended to the name. For example, a debug build with bootimage enabled on Linux/i386 would be built in _build/linux-i386-debug-bootimage_. This allows you to build with several different sets of options independently and even simultaneously without doing a clean build each time. If you are compiling for Windows, you may either cross-compile using MinGW or build natively on Windows under MSYS or Cygwin. #### Installing MSYS: __1.__ Download and install the current MinGW and MSYS packages from mingw.org, selecting the C and C++ compilers when prompted. Use the post-install script to create the filesystem link to the compiler. __2.__ Download GNU Make 3.81 from the MSYS download page (make-3.81-MSYS-1.0.11-2.tar.bz2) and extract the tar file into _e.g. c:/msys/1.0_. #### Installing Cygwin: __1.__ Download and run setup.exe from [cygwin's website](http://www.cygwin.com), installing the base system and these packages: make, gcc-mingw-g++, mingw64-i686-gcc-g++, mingw64-x86_64-gcc-g++, and (optionally) git. You may also find our win32 repository useful: (run this from the directory containing the avian directory) $ git clone git@github.com:ReadyTalk/win32.git This gives you the Windows JNI headers, zlib headers and library, and a few other useful libraries like OpenSSL, libjpeg, and libpng. There's also a win64 repository for 64-bit builds: $ git clone git@github.com:ReadyTalk/win64.git Building with the Microsoft Visual C++ Compiler ----------------------------------------------- You can also build using the MSVC compiler, which makes debugging with tools like WinDbg and Visual Studio much easier. Note that you will still need to have GCC installed - MSVC is only used to compile the C++ portions of the VM, while the assembly code and helper tools are built using GCC. The MSVC build has been tested with Visual Studio Express Edition versions 8, 9, and 10. Other versions may also work. To build with MSVC, install Cygwin as described above and set the following environment variables: $ export PATH="/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/Common7/IDE:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC/BIN:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/Common7/Tools:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v3.5:/cygdrive/c/WINDOWS/Microsoft.NET/Framework/v2.0.50727:/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC/VCPackages:/cygdrive/c/Program Files/Microsoft SDKs/Windows/v6.0A/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem" $ export LIBPATH="C:\WINDOWS\Microsoft.NET\Framework\v3.5;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;C:\Program Files\Microsoft Visual Studio 9.0\VC\LIB;" $ export VCINSTALLDIR="C:\Program Files\Microsoft Visual Studio 9.0\VC" $ export LIB="C:\Program Files\Microsoft Visual Studio 9.0\VC\LIB;C:\Program Files\Microsoft SDKs\Windows\v6.0A\lib;" $ export INCLUDE="C:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE;C:\Program Files\Microsoft SDKs\Windows\v6.0A\include;" Adjust these definitions as necessary according to your MSVC installation. Finally, build with the msvc flag set to the MSVC tool directory: $ make msvc="/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC" Building with the OpenJDK Class Library --------------------------------------- By default, Avian uses its own lightweight class library. However, that library only contains a relatively small subset of the classes and methods included in the JRE. If your application requires features beyond that subset, you may want to tell Avian to use OpenJDK's class library instead. To do so, specify the directory where OpenJDK is installed, e.g.: $ make openjdk=/usr/lib/jvm/java-7-openjdk This will build Avian as a conventional JVM (e.g. libjvm.so) which loads its boot class library and native libraries (e.g. libjava.so) from _/usr/lib/jvm/java-7-openjdk/jre_ at runtime. Note that you must use an absolute path here, or else the result will not work when run from other directories. In this configuration, OpenJDK needs to remain installed for Avian to work, and you can run applications like this: $ build/linux-x86_64-openjdk/avian-dynamic -cp /path/to/my/application \ com.example.MyApplication Alternatively, you can enable a stand-alone build using OpenJDK by specifying the location of the OpenJDK source code, e.g.: $ make openjdk=$(pwd)/../jdk7/build/linux-amd64/j2sdk-image \ openjdk-src=$(pwd)/../jdk7/jdk/src You must ensure that the path specified for openjdk-src does not have any spaces in it; make gets confused when dependency paths include spaces, and we haven't found away around that except to avoid paths with spaces entirely. The result of such a build is a self-contained binary which does not depend on external libraries, jars, or other files. In this case, the specified paths are used only at build time; anything needed at runtime is embedded in the binary. Thus, the process of running an application is simplified: $ build/linux-x86_64-openjdk-src/avian -cp /path/to/my/application \ com.example.MyApplication Note that the resulting binary will be very large due to the size of OpenJDK's class library. This can be mitigated using UPX, preferably an LZMA-enabled version: $ upx --lzma --best build/linux-x86_64-openjdk-src/avian You can reduce the size futher for embedded builds by using ProGuard and the supplied openjdk.pro configuration file (see "Embedding with ProGuard and a Boot Image" below). Note that you'll still need to use vm.pro in that case -- openjdk.pro just adds additional constraints specific to the OpenJDK port. Also see app.mk in _git://oss.readytalk.com/avian-swt-examples.git_ for an example of using Avian, OpenJDK, ProGuard, and UPX in concert. Here are some examples of how to install OpenJDK and build Avian with it on various OSes: #### Debian-based Linux: _Conventional build:_ $ apt-get install openjdk-7-jdk $ make openjdk=/usr/lib/jvm/java-7-openjdk test _Stand-alone build:_ $ apt-get install openjdk-7-jdk $ apt-get source openjdk-7-jdk $ apt-get build-dep openjdk-7-jdk $ (cd openjdk-7-7~b147-2.0 && dpkg-buildpackage) $ make openjdk=/usr/lib/jvm/java-7-openjdk \ openjdk-src=$(pwd)/openjdk-7-7~b147-2.0/build/openjdk/jdk/src \ test ####Mac OS X: _Prerequisite:_ Build OpenJDK 7 according to [this site](https://wikis.oracle.com/display/OpenJDK/Mac+OS+X+Port). _Conventional build:_ $ make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image test _Stand-alone build:_ $ make openjdk=$(pwd)/../jdk7u-dev/build/macosx-amd64/j2sdk-image \ openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test ####Windows (Cygwin): _Prerequisite:_ Build OpenJDK 7 according to [this site](http://weblogs.java.net/blog/simonis/archive/2011/10/28/yaojowbi-yet-another-openjdk-windows-build-instruction). Alternatively, use https://github.com/alexkasko/openjdk-unofficial-builds. _Conventional build:_ $ make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image test _Stand-alone build:_ $ make openjdk=$(pwd)/../jdk7u-dev/build/windows-i586/j2sdk-image \ openjdk-src=$(pwd)/../p/jdk7u-dev/jdk/src test Currently, only OpenJDK 7 is supported. Later versions might work, but have not yet been tested. Building with the Android Class Library --------------------------------------- As an alternative to both the Avian and OpenJDK class libaries, you can also build with the Android class library on some platforms (currently Linux works and OS X mostly works). To build this way, do the following, starting from the Avian directory: cd .. mkdir -p android/system android/external cd android git clone https://android.googlesource.com/platform/bionic (cd bionic && \ git checkout 84983592ade3ec7d72d082262fb6646849979bfc) git clone https://android.googlesource.com/platform/system/core \ system/core (cd system/core && \ git checkout fafcabd0dd4432de3c7f5956edec23f6ed241b56) git clone https://android.googlesource.com/platform/external/fdlibm \ external/fdlibm (cd external/fdlibm && \ git checkout 0da5f683c9ddc9442af3b389b4220e91ccffb320) git clone https://android.googlesource.com/platform/external/icu4c \ external/icu4c (cd external/icu4c && \ git checkout 8fd45e08f1054d80a356ef8aa05659a2ba84707c) git clone https://android.googlesource.com/platform/libnativehelper (cd libnativehelper && \ git checkout cf5ac0ec696fce7fac6b324ec7d4d6da217e501c) git clone https://android.googlesource.com/platform/external/openssl \ external/openssl (cd external/openssl && \ git checkout 7b972f1aa23172c4430ada7f3236fa1fd9b31756) git clone https://android.googlesource.com/platform/external/zlib \ external/zlib (cd external/zlib && \ git checkout 15b6223aa57a347ce113729253802cb2fdeb4ad0) git clone git://git.openssl.org/openssl.git openssl-upstream (cd openssl-upstream && \ git checkout OpenSSL_1_0_1e) git clone https://github.com/dicej/android-libcore64 libcore curl -Of http://oss.readytalk.com/avian/expat-2.1.0.tar.gz (cd external && tar xzf ../expat-2.1.0.tar.gz && mv expat-2.1.0 expat) (cd external/expat && CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure \ --enable-static && make) (cd external/fdlibm && (mv makefile.in Makefile.in || true) \ && CFLAGS=-fPIC bash configure && make) (cd external/icu4c && CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure \ --enable-static && make) NB: use 'CC="gcc -fPIC" ./Configure darwin64-x86_64-cc' when building for x86_64 OS X instead of 'CC="gcc -fPIC" ./config': (cd openssl-upstream \ && (for x in \ progs \ handshake_cutthrough \ jsse \ channelid \ eng_dyn_dirs \ fix_clang_build \ tls12_digests \ alpn; \ do patch -p1 < ../external/openssl/patches/$x.patch; done) \ && CC="gcc -fPIC" ./config && make) cd ../avian make android=$(pwd)/../android test Note that we use https://github.com/dicej/android-libcore64 above instead of the upstream https://android.googlesource.com/platform/libcore repository, since the former has patches to provide better support for non-Linux platforms. Also note that we use the upstream OpenSSL repository and apply the Android patches to it. This is because it is not clear how to build the Android fork of OpenSSL directly without checking out and building the entire platform. As of this writing, the patches apply cleanly against OpenSSL 1.0.1e, so that's the tag we check out, but this may change in the future when the Android fork rebases against a new OpenSSL version. Finally, we specify specific commit hashes for each repository which are known to work. Later versions may also work, but have not been tested. Installing ---------- Installing Avian is as simple as copying the executable to the desired directory: $ cp build/${platform}-${arch}/avian ~/bin/ Embedding --------- The following series of commands illustrates how to produce a stand-alone executable out of a Java application using Avian. Note: if you are building on Cygwin, prepend "x86_64-w64-mingw32-" or "i686-w64-mingw32-" to the ar, g++, gcc, strip, and dlltool commands below (e.g. x86_64-w64-mingw32-gcc). __1.__ Build Avian, create a new directory, and populate it with the VM object files and bootstrap classpath jar. $ make $ mkdir hello $ cd hello $ ar x ../build/${platform}-${arch}/libavian.a $ cp ../build/${platform}-${arch}/classpath.jar boot.jar __2.__ Build the Java code and add it to the jar. $ cat >Hello.java <embedded-jar-main.cpp <("-Xbootclasspath:[bootJar]"); JavaVM* vm; void* env; JNI_CreateJavaVM(&vm, &env, &vmArgs); JNIEnv* e = static_cast(env); jclass c = e->FindClass("Hello"); if (not e->ExceptionCheck()) { jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); if (not e->ExceptionCheck()) { jclass stringClass = e->FindClass("java/lang/String"); if (not e->ExceptionCheck()) { jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0); if (not e->ExceptionCheck()) { for (int i = 1; i < ac; ++i) { e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i])); } e->CallStaticVoidMethod(c, m, a); } } } } int exitCode = 0; if (e->ExceptionCheck()) { exitCode = -1; e->ExceptionDescribe(); } vm->DestroyJavaVM(); return exitCode; } EOF __on Linux:__ $ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \ -D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o __on Mac OS X:__ $ g++ -I$JAVA_HOME/include -D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp \ -o main.o __on Windows:__ $ g++ -fno-exceptions -fno-rtti -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/win32" \ -D_JNI_IMPLEMENTATION_ -c embedded-jar-main.cpp -o main.o __5.__ Link the objects produced above to produce the final executable, and optionally strip its symbols. __on Linux:__ $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello $ strip --strip-all hello __on Mac OS X:__ $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello -framework CoreFoundation $ strip -S -x hello __on Windows:__ $ dlltool -z hello.def *.o $ dlltool -d hello.def -e hello.exp $ gcc hello.exp *.o -L../../win32/lib -lmingwthrd -lm -lz -lws2_32 \ -lIphlpapi -mwindows -mconsole -o hello.exe $ strip --strip-all hello.exe Embedding with ProGuard and a Boot Image ---------------------------------------- The following illustrates how to embed an application as above, except this time we preprocess the code using ProGuard and build a boot image from it for quicker startup. The pros and cons of using ProGuard are as follow: * Pros: ProGuard will eliminate unused code, optimize the rest, and obfuscate it as well for maximum space savings * Cons: increased build time, especially for large applications, and extra effort needed to configure it for applications which rely heavily on reflection and/or calls to Java from native code For boot image builds: * Pros: the boot image build pre-parses all the classes and compiles all the methods, obviating the need for JIT compilation at runtime. This also makes garbage collection faster, since the pre-parsed classes are never visited. * Cons: the pre-parsed classes and AOT-compiled methods take up more space in the executable than the equivalent class files. In practice, this can make the executable 30-50% larger. Also, AOT compilation does not yet yield significantly faster or smaller code than JIT compilation. Finally, floating point code may be slower on 32-bit x86 since the compiler cannot assume SSE2 support will be available at runtime, and the x87 FPU is not supported except via out-of-line helper functions. Note you can use ProGuard without using a boot image and vice-versa, as desired. The following instructions assume we are building for Linux/i386. Please refer to the previous example for guidance on other platforms. __1.__ Build Avian, create a new directory, and populate it with the VM object files. $ make bootimage=true $ mkdir hello $ cd hello $ ar x ../build/linux-i386-bootimage/libavian.a __2.__ Create a stage1 directory and extract the contents of the class library jar into it. $ mkdir stage1 $ (cd stage1 && jar xf ../../build/linux-i386-bootimage/classpath.jar) __3.__ Build the Java code and add it to stage1. $ cat >Hello.java <hello.pro <bootimage-main.cpp <("-Davian.bootimage=bootimageBin"); options[1].optionString = const_cast("-Davian.codeimage=codeimageBin"); JavaVM* vm; void* env; JNI_CreateJavaVM(&vm, &env, &vmArgs); JNIEnv* e = static_cast(env); jclass c = e->FindClass("Hello"); if (not e->ExceptionCheck()) { jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); if (not e->ExceptionCheck()) { jclass stringClass = e->FindClass("java/lang/String"); if (not e->ExceptionCheck()) { jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0); if (not e->ExceptionCheck()) { for (int i = 1; i < ac; ++i) { e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i])); } e->CallStaticVoidMethod(c, m, a); } } } } int exitCode = 0; if (e->ExceptionCheck()) { exitCode = -1; e->ExceptionDescribe(); } vm->DestroyJavaVM(); return exitCode; } EOF $ g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \ -D_JNI_IMPLEMENTATION_ -c bootimage-main.cpp -o main.o __8.__ Link the objects produced above to produce the final executable, and optionally strip its symbols. $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello $ strip --strip-all hello Trademarks ---------- Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners. The Avian project is not affiliated with Oracle. ReadyTalk-avian-1e1fff5/android.pro000066400000000000000000000053131231440243200173240ustar00rootroot00000000000000# these are referenced in JniConstants.cpp: -keep class java.text.Bidi$Run -keep class java.math.BigDecimal -keep class java.lang.Boolean -keep class java.lang.Byte -keep class java.nio.charset.CharsetICU { CharsetICU(java.lang.String, java.lang.String, java.lang.String[]); } -keep class java.lang.reflect.Constructor -keep class java.util.zip.Deflater -keep class java.lang.Double -keep class libcore.io.ErrnoException -keep class java.lang.reflect.Field -keep class libcore.icu.NativeDecimalFormat$FieldPositionIterator { void setData(int[]); } -keep class java.io.FileDescriptor -keep class libcore.io.GaiException -keep class java.net.Inet6Address -keep class java.net.InetAddress -keep class java.net.InetSocketAddress -keep class java.net.InetUnixAddress -keep class java.util.zip.Inflater -keep class java.lang.Integer -keep class libcore.icu.LocaleData -keep class java.lang.Long -keep class java.lang.reflect.Method -keep class libcore.util.MutableInt -keep class libcore.util.MutableLong -keep class java.text.ParsePosition -keep class java.util.regex.PatternSyntaxException -keep class java.lang.RealToString -keep class java.net.Socket -keep class java.net.SocketImpl -keep class java.lang.String -keep class libcore.io.StructAddrinfo -keep class libcore.io.StructFlock -keep class libcore.io.StructGroupReq -keep class libcore.io.StructLinger -keep class libcore.io.StructPasswd { StructPasswd(java.lang.String, int, int, java.lang.String, java.lang.String); } -keep class libcore.io.StructPollfd -keep class libcore.io.StructStat { StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long); } -keep class libcore.io.StructStatFs -keep class libcore.io.StructTimeval -keep class libcore.io.StructUtsname { StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String); } -keep class libcore.io.StructUcred # referenced from libcore native code -keep class libcore.icu.LocaleData { ; } -keep class org.conscrypt.OpenSSLBIOInputStream { ; } -keep class java.util.Calendar { void set(int, int, int, int, int, int); } # called from the VM -keep class java.lang.Thread { Thread(java.lang.ThreadGroup, java.lang.String, int, boolean); } -keep class avian.Classes { java.lang.Class forName(java.lang.String, boolean, java.lang.ClassLoader); int findField(avian.VMClass, java.lang.String); int findMethod(avian.VMClass, java.lang.String, java.lang.Class[]); java.lang.annotation.Annotation getAnnotation(java.lang.ClassLoader, java.lang.Object[]); } -keep class java.lang.VMThread { VMThread(java.lang.Thread); } # loaded reflectively to handle embedded resources: -keep class avian.avianvmresource.Handler ReadyTalk-avian-1e1fff5/classpath/000077500000000000000000000000001231440243200171425ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/avian/000077500000000000000000000000001231440243200202405ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/avian/Addendum.java000066400000000000000000000007331231440243200226270ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public class Addendum { public Object pool; public Object annotationTable; public Object signature; } ReadyTalk-avian-1e1fff5/classpath/avian/AnnotationInvocationHandler.java000066400000000000000000000016101231440243200265430ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import java.lang.reflect.Method; import java.lang.reflect.InvocationHandler; public class AnnotationInvocationHandler implements InvocationHandler { private Object[] data; public AnnotationInvocationHandler(Object[] data) { this.data = data; } public Object invoke(Object proxy, Method method, Object[] arguments) { String name = method.getName(); for (int i = 2; i < data.length; i += 2) { if (name.equals(data[i])) { return data[i + 1]; } } return method.getDefaultValue(); } } ReadyTalk-avian-1e1fff5/classpath/avian/Assembler.java000066400000000000000000000067101231440243200230240ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import static avian.Stream.write1; import static avian.Stream.write2; import static avian.Stream.write4; import avian.ConstantPool.PoolEntry; import java.util.List; import java.io.OutputStream; import java.io.IOException; public class Assembler { public static final int ACC_PUBLIC = 1 << 0; public static final int ACC_STATIC = 1 << 3; public static final int aaload = 0x32; public static final int aastore = 0x53; public static final int aload = 0x19; public static final int aload_0 = 0x2a; public static final int aload_1 = 0x2b; public static final int astore_0 = 0x4b; public static final int anewarray = 0xbd; public static final int areturn = 0xb0; public static final int dload = 0x18; public static final int dreturn = 0xaf; public static final int dup = 0x59; public static final int fload = 0x17; public static final int freturn = 0xae; public static final int getfield = 0xb4; public static final int goto_ = 0xa7; public static final int iload = 0x15; public static final int invokeinterface = 0xb9; public static final int invokespecial = 0xb7; public static final int invokestatic = 0xb8; public static final int invokevirtual = 0xb6; public static final int ireturn = 0xac; public static final int jsr = 0xa8; public static final int ldc_w = 0x13; public static final int lload = 0x16; public static final int lreturn = 0xad; public static final int new_ = 0xbb; public static final int pop = 0x57; public static final int putfield = 0xb5; public static final int ret = 0xa9; public static final int return_ = 0xb1; public static void writeClass(OutputStream out, List pool, int name, int super_, int[] interfaces, MethodData[] methods) throws IOException { int codeAttributeName = ConstantPool.addUtf8(pool, "Code"); write4(out, 0xCAFEBABE); write2(out, 0); // minor version write2(out, 50); // major version write2(out, pool.size() + 1); for (PoolEntry e: pool) { e.writeTo(out); } write2(out, ACC_PUBLIC); // flags write2(out, name + 1); write2(out, super_ + 1); write2(out, interfaces.length); for (int i: interfaces) { write2(out, i + 1); } write2(out, 0); // field count write2(out, methods.length); for (MethodData m: methods) { write2(out, m.flags); write2(out, m.nameIndex + 1); write2(out, m.specIndex + 1); write2(out, 1); // attribute count write2(out, codeAttributeName + 1); write4(out, m.code.length); out.write(m.code); } write2(out, 0); // attribute count } public static class MethodData { public final int flags; public final int nameIndex; public final int specIndex; public final byte[] code; public MethodData(int flags, int nameIndex, int specIndex, byte[] code) { this.flags = flags; this.nameIndex = nameIndex; this.specIndex = specIndex; this.code = code; } } } ReadyTalk-avian-1e1fff5/classpath/avian/Atomic.java000066400000000000000000000003501231440243200223150ustar00rootroot00000000000000package avian; import java.lang.reflect.Field; public class Atomic { public static native long getOffset(Field field); public static native boolean compareAndSwapObject (Object o, long offset, Object old, Object new_); } ReadyTalk-avian-1e1fff5/classpath/avian/Callback.java000066400000000000000000000007521231440243200226030ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public interface Callback { public void handleResult(T result); public void handleException(Throwable exception); } ReadyTalk-avian-1e1fff5/classpath/avian/Cell.java000066400000000000000000000023661231440243200217710ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public class Cell { public T value; public Cell next; public Cell(T value, Cell next) { this.value = value; this.next = next; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("("); for (Cell c = this; c != null; c = c.next) { sb.append(value); if (c.next != null) { sb.append(" "); } } sb.append(")"); return sb.toString(); } public static Cell cons(Car car, Cell cdr) { return new Cell(car, cdr); } public static boolean equal(T a, T b) { return (a == null && b == null) || (a != null && a.equals(b)); } public static boolean equal(Cell a, Cell b) { while (a != null) { if (b == null || (! equal(a.value, b.value))) { return false; } a = a.next; b = b.next; } return b == null; } } ReadyTalk-avian-1e1fff5/classpath/avian/ClassAddendum.java000066400000000000000000000016141231440243200236140ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public class ClassAddendum extends Addendum { public Object[] interfaceTable; public InnerClassReference[] innerClassTable; /** * If this value is negative, all the methods in VMClass.methodTable * were declared in that class. Otherwise, only the first * declaredMethodCount methods in that table were declared in that * class, while the rest were declared in interfaces implemented or * extended by that class. */ public int declaredMethodCount; public Object enclosingClass; public Object enclosingMethod; } ReadyTalk-avian-1e1fff5/classpath/avian/Classes.java000066400000000000000000000370221231440243200225040ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import static avian.Stream.read1; import static avian.Stream.read2; import java.net.URL; import java.net.MalformedURLException; import java.security.CodeSource; import java.security.AllPermission; import java.security.Permissions; import java.security.ProtectionDomain; import java.security.cert.Certificate; import java.lang.reflect.Modifier; import java.lang.reflect.Method; import java.lang.reflect.Field; import java.lang.reflect.Proxy; import java.lang.annotation.Annotation; import java.io.InputStream; import java.io.ByteArrayInputStream; import java.io.IOException; public class Classes { private static final int LinkFlag = 1 << 8; public static native VMClass defineVMClass (ClassLoader loader, byte[] b, int offset, int length); public static native VMClass primitiveClass(char name); public static native void initialize(VMClass vmClass); public static native boolean isAssignableFrom(VMClass a, VMClass b); public static native VMClass getVMClass(Object o); private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec) throws ClassNotFoundException; private static VMClass loadVMClass(ClassLoader loader, byte[] nameBytes, int offset, int length) { byte[] spec = new byte[length + 1]; System.arraycopy(nameBytes, offset, spec, 0, length); try { VMClass c = resolveVMClass(loader, spec); if (c == null) { throw new NoClassDefFoundError(); } return c; } catch (ClassNotFoundException e) { NoClassDefFoundError error = new NoClassDefFoundError (new String(nameBytes, offset, length)); error.initCause(e); throw error; } } private static Object parseAnnotationValue(ClassLoader loader, Object pool, InputStream in) throws IOException { switch (read1(in)) { case 'Z': return Boolean.valueOf(Singleton.getInt(pool, read2(in) - 1) != 0); case 'B': return Byte.valueOf((byte) Singleton.getInt(pool, read2(in) - 1)); case 'C': return Character.valueOf((char) Singleton.getInt(pool, read2(in) - 1)); case 'S': return Short.valueOf((short) Singleton.getInt(pool, read2(in) - 1)); case 'I': return Integer.valueOf(Singleton.getInt(pool, read2(in) - 1)); case 'F': return Float.valueOf (Float.intBitsToFloat(Singleton.getInt(pool, read2(in) - 1))); case 'J': { return Long.valueOf(Singleton.getLong(pool, read2(in) - 1)); } case 'D': { return Double.valueOf (Double.longBitsToDouble(Singleton.getLong(pool, read2(in) - 1))); } case 's': { byte[] data = (byte[]) Singleton.getObject(pool, read2(in) - 1); return new String(data, 0, data.length - 1); } case 'e': { byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1); byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); return Enum.valueOf (SystemClassLoader.getClass (loadVMClass(loader, typeName, 1, typeName.length - 3)), new String(name, 0, name.length - 1)); } case 'c':{ byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); return SystemClassLoader.getClass (loadVMClass(loader, name, 1, name.length - 3)); } case '@': return getAnnotation(loader, parseAnnotation(loader, pool, in)); case '[': { Object[] array = new Object[read2(in)]; for (int i = 0; i < array.length; ++i) { array[i] = parseAnnotationValue(loader, pool, in); } return array; } default: throw new AssertionError(); } } private static Object[] parseAnnotation(ClassLoader loader, Object pool, InputStream in) throws IOException { byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1); Object[] annotation = new Object[(read2(in) + 1) * 2]; annotation[1] = SystemClassLoader.getClass (loadVMClass(loader, typeName, 1, typeName.length - 3)); for (int i = 2; i < annotation.length; i += 2) { byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); annotation[i] = new String(name, 0, name.length - 1); annotation[i + 1] = parseAnnotationValue(loader, pool, in); } return annotation; } private static Object[] parseAnnotationTable(ClassLoader loader, Object pool, InputStream in) throws IOException { Object[] table = new Object[read2(in)]; for (int i = 0; i < table.length; ++i) { table[i] = parseAnnotation(loader, pool, in); } return table; } private static void parseAnnotationTable(ClassLoader loader, Addendum addendum) { if (addendum != null && addendum.annotationTable instanceof byte[]) { try { addendum.annotationTable = parseAnnotationTable (loader, addendum.pool, new ByteArrayInputStream ((byte[]) addendum.annotationTable)); } catch (IOException e) { AssertionError error = new AssertionError(); error.initCause(e); throw error; } } } private static int resolveSpec(ClassLoader loader, byte[] spec, int start) { int result; int end; switch (spec[start]) { case 'L': ++ start; end = start; while (spec[end] != ';') ++ end; result = end + 1; break; case '[': end = start + 1; while (spec[end] == '[') ++ end; switch (spec[end]) { case 'L': ++ end; while (spec[end] != ';') ++ end; ++ end; break; default: ++ end; } result = end; break; default: return start + 1; } loadVMClass(loader, spec, start, end - start); return result; } private static int declaredMethodCount(VMClass c) { ClassAddendum a = c.addendum; if (a != null) { int count = a.declaredMethodCount; if (count >= 0) { return count; } } VMMethod[] table = c.methodTable; return table == null ? 0 : table.length; } public static void link(VMClass c, ClassLoader loader) { acquireClassLock(); try { if ((c.vmFlags & LinkFlag) == 0) { if (c.super_ != null) { link(c.super_, loader); } parseAnnotationTable(loader, c.addendum); if (c.interfaceTable != null) { int stride = ((c.flags & Modifier.INTERFACE) != 0 ? 1 : 2); for (int i = 0; i < c.interfaceTable.length; i += stride) { link((VMClass) c.interfaceTable[i], loader); } } VMMethod[] methodTable = c.methodTable; if (methodTable != null) { for (int i = 0; i < methodTable.length; ++i) { VMMethod m = methodTable[i]; for (int j = 1; j < m.spec.length;) { j = resolveSpec(loader, m.spec, j); } parseAnnotationTable(loader, m.addendum); } } if (c.fieldTable != null) { for (int i = 0; i < c.fieldTable.length; ++i) { VMField f = c.fieldTable[i]; resolveSpec(loader, f.spec, 0); parseAnnotationTable(loader, f.addendum); } } c.vmFlags |= LinkFlag; } } finally { releaseClassLock(); } } public static void link(VMClass c) { link(c, c.loader); } public static Class forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException { if (loader == null) { loader = Class.class.getClassLoader(); } Class c = loader.loadClass(name); VMClass vmc = SystemClassLoader.vmClass(c); Classes.link(vmc, loader); if (initialize) { Classes.initialize(vmc); } return c; } public static Class forCanonicalName(String name) { return forCanonicalName(null, name); } public static Class forCanonicalName(ClassLoader loader, String name) { try { if (name.startsWith("[")) { return forName(name, true, loader); } else if (name.startsWith("L")) { return forName(name.substring(1, name.length() - 1), true, loader); } else { if (name.length() == 1) { return SystemClassLoader.getClass (Classes.primitiveClass(name.charAt(0))); } else { throw new ClassNotFoundException(name); } } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } private static int next(char c, String s, int start) { for (int i = start; i < s.length(); ++i) { if (s.charAt(i) == c) return i; } throw new RuntimeException(); } public static Class[] getParameterTypes(VMMethod vmMethod) { int count = vmMethod.parameterCount; Class[] types = new Class[count]; int index = 0; String spec = new String (vmMethod.spec, 1, vmMethod.spec.length - 2); try { for (int i = 0; i < spec.length(); ++i) { char c = spec.charAt(i); if (c == ')') { break; } else if (c == 'L') { int start = i + 1; i = next(';', spec, start); String name = spec.substring(start, i).replace('/', '.'); types[index++] = Class.forName(name, true, vmMethod.class_.loader); } else if (c == '[') { int start = i; while (spec.charAt(i) == '[') ++i; if (spec.charAt(i) == 'L') { i = next(';', spec, i + 1); String name = spec.substring(start, i).replace('/', '.'); types[index++] = Class.forName (name, true, vmMethod.class_.loader); } else { String name = spec.substring(start, i + 1); types[index++] = forCanonicalName(vmMethod.class_.loader, name); } } else { String name = spec.substring(i, i + 1); types[index++] = forCanonicalName(vmMethod.class_.loader, name); } } } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return types; } public static int findField(VMClass vmClass, String name) { if (vmClass.fieldTable != null) { Classes.link(vmClass); for (int i = 0; i < vmClass.fieldTable.length; ++i) { if (toString(vmClass.fieldTable[i].name).equals(name)) { return i; } } } return -1; } public static String toString(byte[] array) { return new String(array, 0, array.length - 1); } public static boolean match(Class[] a, Class[] b) { if (a.length == b.length) { for (int i = 0; i < a.length; ++i) { if (! a[i].isAssignableFrom(b[i])) { return false; } } return true; } else { return false; } } public static int findMethod(VMClass vmClass, String name, Class[] parameterTypes) { VMMethod[] methodTable = vmClass.methodTable; if (methodTable != null) { Classes.link(vmClass); if (parameterTypes == null) { parameterTypes = new Class[0]; } for (int i = 0; i < methodTable.length; ++i) { VMMethod m = methodTable[i]; if (toString(m.name).equals(name) && match(parameterTypes, getParameterTypes(m))) { return i; } } } return -1; } public static int countMethods(VMClass vmClass, boolean publicOnly) { int count = 0; VMMethod[] methodTable = vmClass.methodTable; if (methodTable != null) { for (int i = 0, j = declaredMethodCount(vmClass); i < j; ++i) { VMMethod m = methodTable[i]; if (((! publicOnly) || ((m.flags & Modifier.PUBLIC)) != 0) && (! toString(m.name).startsWith("<"))) { ++ count; } } } return count; } public static Method[] getMethods(VMClass vmClass, boolean publicOnly) { Method[] array = new Method[countMethods(vmClass, publicOnly)]; VMMethod[] methodTable = vmClass.methodTable; if (methodTable != null) { Classes.link(vmClass); int ai = 0; for (int i = 0, j = declaredMethodCount(vmClass); i < j; ++i) { VMMethod m = methodTable[i]; if (((! publicOnly) || ((m.flags & Modifier.PUBLIC) != 0)) && ! toString(m.name).startsWith("<")) { array[ai++] = makeMethod(SystemClassLoader.getClass(vmClass), i); } } } return array; } public static int countFields(VMClass vmClass, boolean publicOnly) { int count = 0; if (vmClass.fieldTable != null) { for (int i = 0; i < vmClass.fieldTable.length; ++i) { if ((! publicOnly) || ((vmClass.fieldTable[i].flags & Modifier.PUBLIC)) != 0) { ++ count; } } } return count; } public static Field[] getFields(VMClass vmClass, boolean publicOnly) { Field[] array = new Field[countFields(vmClass, publicOnly)]; if (vmClass.fieldTable != null) { Classes.link(vmClass); int ai = 0; for (int i = 0; i < vmClass.fieldTable.length; ++i) { if (((vmClass.fieldTable[i].flags & Modifier.PUBLIC) != 0) || (! publicOnly)) { array[ai++] = makeField(SystemClassLoader.getClass(vmClass), i); } } } return array; } public static Annotation getAnnotation(ClassLoader loader, Object[] a) { if (a[0] == null) { a[0] = Proxy.newProxyInstance (loader, new Class[] { (Class) a[1] }, new AnnotationInvocationHandler(a)); } return (Annotation) a[0]; } public static Object getAnnotationDefaultValue(ClassLoader loader, MethodAddendum addendum) { if (addendum == null) { return null; } byte[] annotationDefault = (byte[]) addendum.annotationDefault; if (annotationDefault == null) { return null; } try { return parseAnnotationValue(loader, addendum.pool, new ByteArrayInputStream(annotationDefault)); } catch (IOException e) { AssertionError error = new AssertionError(); error.initCause(e); throw error; } } private static int index(VMMethod m) { VMMethod[] table = m.class_.methodTable; for (int i = 0; i < table.length; ++i) { if (m == table[i]) return i; } throw new AssertionError(); } public static Method makeMethod(VMMethod m) { return makeMethod(SystemClassLoader.getClass(m.class_), index(m)); } public static ProtectionDomain getProtectionDomain(VMClass c) { CodeSource source = null; if (c.source != null) { try { source = new CodeSource (new URL(new String(c.source, 0, c.source.length - 1)), (Certificate[]) null); } catch (MalformedURLException ignored) { } } Permissions p = new Permissions(); p.add(new AllPermission()); return new ProtectionDomain(source, p); } public static native Method makeMethod(Class c, int slot); public static native Field makeField(Class c, int slot); private static native void acquireClassLock(); private static native void releaseClassLock(); } ReadyTalk-avian-1e1fff5/classpath/avian/ConstantPool.java000066400000000000000000000154541231440243200235370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import static avian.Stream.write1; import static avian.Stream.write2; import static avian.Stream.write4; import java.util.List; import java.io.OutputStream; import java.io.IOException; public class ConstantPool { private static final int CONSTANT_Integer = 3; private static final int CONSTANT_Utf8 = 1; private static final int CONSTANT_String = 8; private static final int CONSTANT_Class = 7; private static final int CONSTANT_NameAndType = 12; private static final int CONSTANT_Fieldref = 9; private static final int CONSTANT_Methodref = 10; public static int add(List pool, PoolEntry e) { int i = 0; for (PoolEntry existing: pool) { if (existing.equals(e)) { return i; } else { ++i; } } pool.add(e); return pool.size() - 1; } public static int addInteger(List pool, int value) { return add(pool, new IntegerPoolEntry(value)); } public static int addUtf8(List pool, String value) { return add(pool, new Utf8PoolEntry(value)); } public static int addString(List pool, String value) { return add(pool, new StringPoolEntry(addUtf8(pool, value))); } public static int addClass(List pool, String name) { return add(pool, new ClassPoolEntry(addUtf8(pool, name))); } public static int addNameAndType(List pool, String name, String type) { return add(pool, new NameAndTypePoolEntry (addUtf8(pool, name), addUtf8(pool, type))); } public static int addFieldRef(List pool, String className, String name, String spec) { return add(pool, new FieldRefPoolEntry (addClass(pool, className), addNameAndType(pool, name, spec))); } public static int addMethodRef(List pool, String className, String name, String spec) { return add(pool, new MethodRefPoolEntry (addClass(pool, className), addNameAndType(pool, name, spec))); } public interface PoolEntry { public void writeTo(OutputStream out) throws IOException; } private static class IntegerPoolEntry implements PoolEntry { private final int value; public IntegerPoolEntry(int value) { this.value = value; } public void writeTo(OutputStream out) throws IOException { write1(out, CONSTANT_Integer); write4(out, value); } public boolean equals(Object o) { return o instanceof IntegerPoolEntry && ((IntegerPoolEntry) o).value == value; } } private static class Utf8PoolEntry implements PoolEntry { private final String data; public Utf8PoolEntry(String data) { this.data = data; } public void writeTo(OutputStream out) throws IOException { write1(out, CONSTANT_Utf8); byte[] bytes = data.getBytes(); write2(out, bytes.length); out.write(bytes); } public boolean equals(Object o) { return o instanceof Utf8PoolEntry && ((Utf8PoolEntry) o).data.equals(data); } } private static class StringPoolEntry implements PoolEntry { private final int valueIndex; public StringPoolEntry(int valueIndex) { this.valueIndex = valueIndex; } public void writeTo(OutputStream out) throws IOException { write1(out, CONSTANT_String); write2(out, valueIndex + 1); } public boolean equals(Object o) { return o instanceof StringPoolEntry && ((StringPoolEntry) o).valueIndex == valueIndex; } } private static class ClassPoolEntry implements PoolEntry { private final int nameIndex; public ClassPoolEntry(int nameIndex) { this.nameIndex = nameIndex; } public void writeTo(OutputStream out) throws IOException { write1(out, CONSTANT_Class); write2(out, nameIndex + 1); } public boolean equals(Object o) { return o instanceof ClassPoolEntry && ((ClassPoolEntry) o).nameIndex == nameIndex; } } private static class NameAndTypePoolEntry implements PoolEntry { private final int nameIndex; private final int typeIndex; public NameAndTypePoolEntry(int nameIndex, int typeIndex) { this.nameIndex = nameIndex; this.typeIndex = typeIndex; } public void writeTo(OutputStream out) throws IOException { write1(out, CONSTANT_NameAndType); write2(out, nameIndex + 1); write2(out, typeIndex + 1); } public boolean equals(Object o) { if (o instanceof NameAndTypePoolEntry) { NameAndTypePoolEntry other = (NameAndTypePoolEntry) o; return other.nameIndex == nameIndex && other.typeIndex == typeIndex; } else { return false; } } } private static class FieldRefPoolEntry implements PoolEntry { private final int classIndex; private final int nameAndTypeIndex; public FieldRefPoolEntry(int classIndex, int nameAndTypeIndex) { this.classIndex = classIndex; this.nameAndTypeIndex = nameAndTypeIndex; } public void writeTo(OutputStream out) throws IOException { write1(out, CONSTANT_Fieldref); write2(out, classIndex + 1); write2(out, nameAndTypeIndex + 1); } public boolean equals(Object o) { if (o instanceof FieldRefPoolEntry) { FieldRefPoolEntry other = (FieldRefPoolEntry) o; return other.classIndex == classIndex && other.nameAndTypeIndex == nameAndTypeIndex; } else { return false; } } } private static class MethodRefPoolEntry implements PoolEntry { private final int classIndex; private final int nameAndTypeIndex; public MethodRefPoolEntry(int classIndex, int nameAndTypeIndex) { this.classIndex = classIndex; this.nameAndTypeIndex = nameAndTypeIndex; } public void writeTo(OutputStream out) throws IOException { write1(out, CONSTANT_Methodref); write2(out, classIndex + 1); write2(out, nameAndTypeIndex + 1); } public boolean equals(Object o) { if (o instanceof MethodRefPoolEntry) { MethodRefPoolEntry other = (MethodRefPoolEntry) o; return other.classIndex == classIndex && other.nameAndTypeIndex == nameAndTypeIndex; } else { return false; } } } } ReadyTalk-avian-1e1fff5/classpath/avian/Continuations.java000066400000000000000000000306211231440243200237420ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import java.util.concurrent.Callable; /** * This class provides methods to capture continuations and manage * control flow when calling continuations. * *

A continuation is a snapshot of a thread's call stack which can * be captured via callWithCurrentContinuation and later * restored any number of times. The program may restore this * snapshot by either feeding it a result (to be returned by * callWithCurrentContinuation) or feeding it an * exception (to be thrown by * callWithCurrentContinuation). Continuations may be * used to implement features such as coroutines, generators, and * cooperative multitasking. * *

This class provides two static methods, * callWithCurrentContinuation and * dynamicWind, with similar semantics to the Scheme * functions call-with-current-continuation and * dynamic-wind, respectively. In addition, we define * how continuations work with respect to native code, exceptions, * try/finally blocks, synchronized blocks, and multithreading. * *

Continuations and Continuation Contexts

* *

A continuation can be thought of as a singly-linked list of * stack frames representing the call trace, where the head of the * list is the frame of the method most recently called (i.e. the top * of the stack). However, this trace only extends as far as the most * recent chain of Java frames - it ends just prior to the most recent * native frame in the stack. The reason for this is that the VM * cannot, in general, safely capture and restore native frames. * Therefore, each call from native code to Java (including the * original invocation of main(String[]) or * Thread.run()) represents a new continuation context in * which continuations may be captured, and these will only contain * frames from within that context. * *

Calling a continuation (i.e. feeding it a result or exception) * causes the current continuation to be replaced with the called * continuation. When the last method in this new continuation * returns, it returns to the native frame which created the current * context, which may or may not be the same as the context in which * that continuation was created. * *

We define the return type of a continuation context as the * return type of the first method called in that context. A * continuation may be called from a different context than the one in * which it was created, provided the return type of the latter is * compatible with the current context. * *

Given a thread executing in context "A" which wants to call a * continuation created in context "B", the following rules apply: * *

    * *
  • If the return type of "A" is void, the return * type of "B" may be anything, including void
  • * *
  • If the return type of "A" is a primitive type, the return * type of "B" must match exactly
  • * *
  • If the return type of "A" is an object type, that type must * be assignable from the return type of "B" (i.e. the latter must * either be the same as the former or a superclass or * superinterface of it)
  • * *
* *

A thread may call a continuation created by a different thread * provided the return types are compatible. Multiple threads may * safely call the same continuation simultaneously without * synchronization. Any attempt to call a continuation from a context * with an incompatible return type will throw an {@link * avian.IncompatibleContinuationException}. * *

Winding, Unwinding, and Rewinding

* *

Traditionally, Java provides one way to wind the execution stack * (method calls) and two ways to unwind it (normal returns and * exception unwinding). With continuations, we add a new way to * rewind the stack and a new way to unwind it. * *

The call stack of a continuation may share frames with other * continuations - in which case they share a common history. When * calling a continuation "B" from the current continuation "A", the * VM must unwind past any frames which are in "A" but not in "B" and * rewind past any frames in "B" but not in "A". During this * unwinding and rewinding, control may pass through synchronized and * try/finally blocks while going down the old stack and up the new * stack. * *

However, unlike the traditional processes of winding and * unwinding, the VM will ignore these blocks - monitors will not be * released or acquired and finally blocks will not execute. This is * by design. The purpose of such a block is to acquire a resource, * such as a file handle or monitor, once before executing a task and * release it after the task is finished, regardless of how often the * task might temporarily yield control to other continuations. * *

Alternatively, one might wish to acquire and release a resource * each time control (re)winds to or unwinds from a continuation, * respectively. In this case, one may use dynamicWind * to register functions which will run every time that frame is * passed, regardless of how the stack is wound or unwound. */ public class Continuations { private Continuations() { } private static final ThreadLocal latestReset = new ThreadLocal(); /** * Captures the current continuation, passing a reference to the * specified receiver. * *

This method will either return the result returned by * receiver.call(Callback), propagate the exception * thrown by that method, return the result passed to the * handleResult(T) method of the continuation, or throw the * exception passed to the handleException(Throwable) method of the * continuation. */ public static native T callWithCurrentContinuation (Function,T> receiver) throws Exception; /** * Calls the specified "before" and "after" tasks each time a * continuation containing the call is wound or unwound, * respectively. * *

This method first calls before.run(), then * thunk.call(), and finally after.run(), * returning the result of the second call. If * before.run() does not return normally, the second * and third calls will not happen. If thunk.call() * throws an exception, after.run(), will be called * before the exception is propagated. * *

If thunk.call() calls a continuation (directly or * via a subroutine) which does not include the current call to * dynamicWind, after.run() will be called * before control passes to that continuation. If this call throws * an exception, the exception will propagate to the current caller * of dynamicWind. * *

If thunk.call() creates a continuation which is * later called from a continuation which does not include the * current call to dynamicWind, * before.run() will be called before control passes to * that continuation. As above, if this call throws an exception, * the exception will propagate to the current caller of * dynamicWind. */ public static T dynamicWind(Runnable before, Callable thunk, Runnable after) throws Exception { UnwindResult result = dynamicWind2(before, thunk, after); if (result.continuation != null) { after.run(); if (result.exception != null) { result.continuation.handleException(result.exception); } else { result.continuation.handleResult(result.result); } throw new AssertionError(); } else { return (T) result.result; } } public static C reset(final Callable thunk) throws Exception { final Reset reset = new Reset(latestReset.get()); latestReset.set(reset); try { Object result = callWithCurrentContinuation (new Function,Object>() { public Object call(Callback continuation) throws Exception { reset.continuation = continuation; return thunk.call(); } }); while (true) { Cell shift = reset.shifts; if (shift != null) { reset.shifts = shift.next; result = shift.value.call(result); } else { return (C) result; } } } finally { latestReset.set(reset.next); } } public static A shift (final Function,C> receiver) throws Exception { return (A) callWithCurrentContinuation (new Function,Object>() { public Object call(final Callback continuation) { final Reset reset = latestReset.get(); reset.shifts = new Cell(new Function() { public Object call(Object ignored) throws Exception { return receiver.call (new Function() { public Object call(final Object argument) throws Exception { return callWithCurrentContinuation (new Function,Object>() { public Object call (final Callback shiftContinuation) throws Exception { reset.shifts = new Cell (new Function() { public Object call(Object result) throws Exception { shiftContinuation.handleResult(result); throw new AssertionError(); } }, reset.shifts); continuation.handleResult(argument); throw new AssertionError(); } }); } }); } public void handleException(Throwable exception) { throw new AssertionError(); } }, reset.shifts); reset.continuation.handleResult(null); throw new AssertionError(); } }); } private static native UnwindResult dynamicWind2(Runnable before, Callable thunk, Runnable after) throws Exception; private static UnwindResult wind(Runnable before, Callable thunk, Runnable after) throws Exception { before.run(); try { return new UnwindResult(null, thunk.call(), null); } finally { after.run(); } } private static void rewind(Runnable before, Callback continuation, Object result, Throwable exception) throws Exception { before.run(); if (exception != null) { continuation.handleException(exception); } else { continuation.handleResult(result); } throw new AssertionError(); } private static class Continuation implements Callback { public native void handleResult(T result); public native void handleException(Throwable exception); } private static class UnwindResult { public final Callback continuation; public final Object result; public final Throwable exception; public UnwindResult(Callback continuation, Object result, Throwable exception) { this.continuation = continuation; this.result = result; this.exception = exception; } } private static class Reset { public Callback continuation; public final Reset next; public Cell shifts; public Reset(Reset next) { this.next = next; } } } ReadyTalk-avian-1e1fff5/classpath/avian/Data.java000066400000000000000000000152321231440243200217570ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import java.util.Map; import java.util.Map.Entry; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.Collections; public class Data { public static int nextPowerOfTwo(int n) { int r = 1; while (r < n) r <<= 1; return r; } public static boolean equal(V a, V b) { return a == null ? b == null : a.equals(b); } public static T[] toArray(Collection collection, T[] array) { Class c = array.getClass().getComponentType(); if (array.length < collection.size()) { array = (T[]) java.lang.reflect.Array.newInstance(c, collection.size()); } int i = 0; for (Object o: collection) { if (c.isInstance(o)) { array[i++] = (T) o; } else { throw new ArrayStoreException(); } } return array; } public static String toString(Collection c) { StringBuilder sb = new StringBuilder(); sb.append("["); for (Iterator it = c.iterator(); it.hasNext();) { sb.append(it.next()); if (it.hasNext()) { sb.append(","); } } sb.append("]"); return sb.toString(); } public static String toString(Map m) { StringBuilder sb = new StringBuilder(); sb.append("{"); for (Iterator it = m.entrySet().iterator(); it.hasNext();) { Entry e = it.next(); sb.append(e.getKey()) .append("=") .append(e.getValue()); if (it.hasNext()) { sb.append(","); } } sb.append("}"); return sb.toString(); } public interface EntryMap { public int size(); public Entry find(Object key); public Entry remove(Object key); public void clear(); public Iterator> iterator(); } public static class EntrySet extends AbstractSet> { private final EntryMap map; public EntrySet(EntryMap map) { this.map = map; } public int size() { return map.size(); } public boolean isEmpty() { return map.size() == 0; } public boolean contains(Object o) { return (o instanceof Entry) && map.find(((Entry)o).getKey()) != null; } public boolean add(Entry e) { throw new UnsupportedOperationException(); } public boolean remove(Object o) { return (o instanceof Entry) && map.remove(((Entry) o).getKey()) != null; } public boolean remove(Entry e) { return map.remove(e.getKey()) != null; } public Object[] toArray() { return toArray(new Object[size()]); } public T[] toArray(T[] array) { return Data.toArray(this, array); } public void clear() { map.clear(); } public Iterator> iterator() { return map.iterator(); } } public static class KeySet extends AbstractSet { private final EntryMap map; public KeySet(EntryMap map) { this.map = map; } public int size() { return map.size(); } public boolean isEmpty() { return map.size() == 0; } public boolean contains(Object key) { return map.find(key) != null; } public boolean add(K key) { throw new UnsupportedOperationException(); } public boolean remove(Object key) { return map.remove(key) != null; } public Object[] toArray() { return toArray(new Object[size()]); } public T[] toArray(T[] array) { return Data.toArray(this, array); } public void clear() { map.clear(); } public Iterator iterator() { return new KeyIterator(map.iterator()); } } public static class Values implements Collection { private final EntryMap map; public Values(EntryMap map) { this.map = map; } public int size() { return map.size(); } public boolean isEmpty() { return map.size() == 0; } public boolean contains(Object value) { for (Iterator> it = map.iterator(); it.hasNext();) { if (equal(it.next().getValue(), value)) { return true; } } return false; } public boolean containsAll(Collection c) { if (c == null) { throw new NullPointerException("collection is null"); } for (Iterator it = c.iterator(); it.hasNext();) { if (! contains(it.next())) { return false; } } return true; } public boolean add(V value) { throw new UnsupportedOperationException(); } public boolean addAll(Collection collection) { throw new UnsupportedOperationException(); } public boolean remove(Object value) { for (Iterator> it = map.iterator(); it.hasNext();) { if (equal(it.next().getValue(), value)) { it.remove(); return true; } } return false; } public boolean removeAll(Collection c) { boolean changed = false; for (Iterator> it = map.iterator(); it.hasNext();) { if (c.contains(it.next().getValue())) { it.remove(); changed = true; } } return changed; } public Object[] toArray() { return toArray(new Object[size()]); } public T[] toArray(T[] array) { return Data.toArray(this, array); } public void clear() { map.clear(); } public Iterator iterator() { return new ValueIterator(map.iterator()); } } public static class KeyIterator implements Iterator { private final Iterator> it; public KeyIterator(Iterator> it) { this.it = it; } public K next() { return it.next().getKey(); } public boolean hasNext() { return it.hasNext(); } public void remove() { it.remove(); } } public static class ValueIterator implements Iterator { private final Iterator> it; public ValueIterator(Iterator> it) { this.it = it; } public V next() { return it.next().getValue(); } public boolean hasNext() { return it.hasNext(); } public void remove() { it.remove(); } } } ReadyTalk-avian-1e1fff5/classpath/avian/FieldAddendum.java000066400000000000000000000006371231440243200235760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public class FieldAddendum extends Addendum { } ReadyTalk-avian-1e1fff5/classpath/avian/Function.java000066400000000000000000000007001231440243200226650ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public interface Function { public B call(A argument) throws Exception; } ReadyTalk-avian-1e1fff5/classpath/avian/IncompatibleContinuationException.java000066400000000000000000000011121231440243200277560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public class IncompatibleContinuationException extends Exception { public IncompatibleContinuationException(String message) { super(message); } public IncompatibleContinuationException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/avian/InnerClassReference.java000066400000000000000000000007561231440243200247730ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public class InnerClassReference { public byte[] inner; public byte[] outer; public byte[] name; public short flags; } ReadyTalk-avian-1e1fff5/classpath/avian/Iso88591.java000066400000000000000000000013461231440243200222600ustar00rootroot00000000000000 /* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import java.io.ByteArrayOutputStream; public class Iso88591 { public static byte[] encode(char[] s16, int offset, int length) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); for (int i = offset; i < offset+length; ++i) { // ISO-88591-1/Latin-1 is the same as UTF-16 under 0x100 buf.write(s16[i]); } return buf.toByteArray(); } } ReadyTalk-avian-1e1fff5/classpath/avian/LegacyObjectInputStream.java000066400000000000000000000124561231440243200256420ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; import avian.VMClass; import java.util.HashMap; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; public class LegacyObjectInputStream extends InputStream { private final InputStream in; private final PushbackReader r; public LegacyObjectInputStream(InputStream in) { this.in = in; this.r = new PushbackReader(new InputStreamReader(in)); } public int read() throws IOException { return in.read(); } public int read(byte[] b, int offset, int length) throws IOException { return in.read(b, offset, length); } public void close() throws IOException { in.close(); } public Object readObject() throws IOException, ClassNotFoundException { return readObject(new HashMap()); } public boolean readBoolean() throws IOException { read('z'); return readLongToken() != 0; } public byte readByte() throws IOException { read('b'); return (byte) readLongToken(); } public char readChar() throws IOException { read('c'); return (char) readLongToken(); } public short readShort() throws IOException { read('s'); return (short) readLongToken(); } public int readInt() throws IOException { read('i'); return (int) readLongToken(); } public long readLong() throws IOException { read('j'); return readLongToken(); } public float readFloat() throws IOException { read('f'); return (float) readDoubleToken(); } public double readDouble() throws IOException { read('d'); return readDoubleToken(); } public void defaultReadObject() throws IOException { throw new UnsupportedOperationException(); } private void skipSpace() throws IOException { int c; while ((c = r.read()) != -1 && Character.isWhitespace((char) c)); if (c != -1) { r.unread(c); } } private void read(char v) throws IOException { skipSpace(); int c = r.read(); if (c != v) { if (c == -1) { throw new EOFException(); } else { throw new StreamCorruptedException(); } } } private String readStringToken() throws IOException { skipSpace(); StringBuilder sb = new StringBuilder(); int c; while ((c = r.read()) != -1 && ! Character.isWhitespace((char) c) && c != ')') { sb.append((char) c); } if (c != -1) { r.unread(c); } return sb.toString(); } private long readLongToken() throws IOException { return Long.parseLong(readStringToken()); } private double readDoubleToken() throws IOException { return Double.parseDouble(readStringToken()); } private Object readObject(HashMap map) throws IOException, ClassNotFoundException { skipSpace(); switch (r.read()) { case 'a': return deserializeArray(map); case 'l': return deserializeObject(map); case 'n': return null; case -1: throw new EOFException(); default: throw new StreamCorruptedException(); } } private Object deserialize(HashMap map) throws IOException, ClassNotFoundException { skipSpace(); switch (r.read()) { case 'a': return deserializeArray(map); case 'l': return deserializeObject(map); case 'r': return map.get((int) readLongToken()); case 'n': return null; case 'z': return (readLongToken() != 0); case 'b': return (byte) readLongToken(); case 'c': return (char) readLongToken(); case 's': return (short) readLongToken(); case 'i': return (int) readLongToken(); case 'j': return readLongToken(); case 'f': return (float) readDoubleToken(); case 'd': return readDoubleToken(); case -1: throw new EOFException(); default: throw new StreamCorruptedException(); } } private Object deserializeArray(HashMap map) throws IOException, ClassNotFoundException { read('('); int id = (int) readLongToken(); Class c = Class.forName(readStringToken()); int length = (int) readLongToken(); Class t = c.getComponentType(); Object o = Array.newInstance(t, length); map.put(id, o); for (int i = 0; i < length; ++i) { Array.set(o, i, deserialize(map)); } read(')'); return o; } private static native Object makeInstance(VMClass c); private Object deserializeObject(HashMap map) throws IOException, ClassNotFoundException { read('('); int id = (int) readLongToken(); Class c = Class.forName(readStringToken()); Object o = makeInstance(c.vmClass); map.put(id, o); for (Field f: c.getAllFields()) { int modifiers = f.getModifiers(); if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) { try { f.set(o, deserialize(map)); } catch (Exception e) { throw new RuntimeException(e); } } } read(')'); return o; } } ReadyTalk-avian-1e1fff5/classpath/avian/LegacyObjectOutputStream.java000066400000000000000000000121511231440243200260330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import java.util.IdentityHashMap; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.io.Serializable; import java.io.NotSerializableException; public class LegacyObjectOutputStream extends OutputStream { private final PrintStream out; public LegacyObjectOutputStream(OutputStream out) { this.out = new PrintStream(out); } public void write(int c) throws IOException { out.write(c); } public void write(byte[] b, int offset, int length) throws IOException { out.write(b, offset, length); } public void flush() throws IOException { out.flush(); } public void close() throws IOException { out.close(); } public void writeObject(Object o) throws IOException { writeObject(o, new IdentityHashMap(), new int[] {0}); } public void writeBoolean(boolean v) { out.print("z"); out.print((v ? 1 : 0)); } public void writeByte(byte v) { out.print("b"); out.print((int) v); } public void writeChar(char v) { out.print("c"); out.print((int) v); } public void writeShort(short v) { out.print("s"); out.print((int) v); } public void writeInt(int v) { out.print("i"); out.print(v); } public void writeLong(long v) { out.print("j"); out.print(v); } public void writeFloat(float v) { out.print("f"); out.print(v); } public void writeDouble(double v) { out.print("d"); out.print(v); } public void defaultWriteObject() throws IOException { throw new UnsupportedOperationException(); } private void writeObject(Object o, IdentityHashMap map, int[] nextId) throws IOException { if (o == null) { out.print("n"); } else { Integer id = map.get(o); if (id == null) { map.put(o, nextId[0]); Class c = o.getClass(); if (c.isArray()) { serializeArray(o, map, nextId); } else if (Serializable.class.isAssignableFrom(c)) { serializeObject(o, map, nextId); } else { throw new NotSerializableException(c.getName()); } } else { out.print("r"); out.print(id.intValue()); } } } private void serializeArray(Object o, IdentityHashMap map, int[] nextId) throws IOException { Class c = o.getClass(); Class t = c.getComponentType(); int length = Array.getLength(o); out.print("a("); out.print(nextId[0]++); out.print(" "); out.print(c.getName()); out.print(" "); out.print(length); for (int i = 0; i < length; ++i) { out.print(" "); Object v = Array.get(o, i); if (t.equals(boolean.class)) { writeBoolean((Boolean) v); } else if (t.equals(byte.class)) { writeByte((Byte) v); } else if (t.equals(char.class)) { writeChar((Character) v); } else if (t.equals(short.class)) { writeShort((Short) v); } else if (t.equals(int.class)) { writeInt((Integer) v); } else if (t.equals(long.class)) { writeLong((Long) v); } else if (t.equals(float.class)) { writeFloat((Float) v); } else if (t.equals(double.class)) { writeDouble((Double) v); } else { writeObject(v, map, nextId); } } out.print(")"); } private void serializeObject(Object o, IdentityHashMap map, int[] nextId) throws IOException { Class c = o.getClass(); out.print("l("); out.print(nextId[0]++); out.print(" "); out.print(c.getName()); for (Field f: c.getAllFields()) { int modifiers = f.getModifiers(); if ((modifiers & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) { out.print(" "); Object v; try { v = f.get(o); } catch (Exception e) { throw new RuntimeException(e); } Class t = f.getType(); if (t.equals(boolean.class)) { writeBoolean((Boolean) v); } else if (t.equals(byte.class)) { writeByte((Byte) v); } else if (t.equals(char.class)) { writeChar((Character) v); } else if (t.equals(short.class)) { writeShort((Short) v); } else if (t.equals(int.class)) { writeInt((Integer) v); } else if (t.equals(long.class)) { writeLong((Long) v); } else if (t.equals(float.class)) { writeFloat((Float) v); } else if (t.equals(double.class)) { writeDouble((Double) v); } else { writeObject(v, map, nextId); } } } out.print(")"); } } ReadyTalk-avian-1e1fff5/classpath/avian/Machine.java000066400000000000000000000015131231440243200224470ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import sun.misc.Unsafe; import java.lang.reflect.Field; public abstract class Machine { private static final Unsafe unsafe; static { Unsafe u; try { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); u = (Unsafe)f.get(null); } catch (Exception e) { u = null; } unsafe = u; } public static native void dumpHeap(String outputFile); public static Unsafe getUnsafe() { return unsafe; } } ReadyTalk-avian-1e1fff5/classpath/avian/MethodAddendum.java000066400000000000000000000010151231440243200237620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public class MethodAddendum extends Addendum { public Object exceptionTable; public Object annotationDefault; public Object parameterAnnotationTable; } ReadyTalk-avian-1e1fff5/classpath/avian/PersistentSet.java000066400000000000000000000366641231440243200237360ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import java.util.Comparator; public class PersistentSet implements Iterable { private static final Node NullNode = new Node(null); static { NullNode.left = NullNode; NullNode.right = NullNode; } private final Node root; private final Comparator comparator; private final int size; public PersistentSet() { this(NullNode, new Comparator() { public int compare(T a, T b) { return ((Comparable) a).compareTo(b); } }, 0); } public PersistentSet(Comparator comparator) { this(NullNode, comparator, 0); } private PersistentSet(Node root, Comparator comparator, int size) { this.root = root; this.comparator = comparator; this.size = size; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("{"); for (java.util.Iterator it = iterator(); it.hasNext();) { sb.append(it.next()); if (it.hasNext()) { sb.append(","); } } sb.append("}"); return sb.toString(); } public Comparator comparator() { return comparator; } public PersistentSet add(T value) { return add(value, false); } public int size() { return size; } public PersistentSet add(T value, boolean replaceExisting) { Path p = find(value); if (! p.fresh) { if (replaceExisting) { return p.replaceWith(value); } else { return this; } } return add(p); } private PersistentSet add(Path p) { if (! p.fresh) throw new IllegalArgumentException(); Node new_ = p.node; Node newRoot = p.root.root; Cell> ancestors = p.ancestors; // rebalance new_.red = true; while (ancestors != null && ancestors.value.red) { if (ancestors.value == ancestors.next.value.left) { if (ancestors.next.value.right.red) { ancestors.value.red = false; ancestors.next.value.right = new Node(ancestors.next.value.right); ancestors.next.value.right.red = false; ancestors.next.value.red = true; new_ = ancestors.next.value; ancestors = ancestors.next.next; } else { if (new_ == ancestors.value.right) { new_ = ancestors.value; ancestors = ancestors.next; Node n = leftRotate(new_); if (ancestors.value.right == new_) { ancestors.value.right = n; } else { ancestors.value.left = n; } ancestors = new Cell(n, ancestors); } ancestors.value.red = false; ancestors.next.value.red = true; Node n = rightRotate(ancestors.next.value); if (ancestors.next.next == null) { newRoot = n; } else if (ancestors.next.next.value.right == ancestors.next.value) { ancestors.next.next.value.right = n; } else { ancestors.next.next.value.left = n; } // done } } else { if (ancestors.next.value.left.red) { ancestors.value.red = false; ancestors.next.value.left = new Node(ancestors.next.value.left); ancestors.next.value.left.red = false; ancestors.next.value.red = true; new_ = ancestors.next.value; ancestors = ancestors.next.next; } else { if (new_ == ancestors.value.left) { new_ = ancestors.value; ancestors = ancestors.next; Node n = rightRotate(new_); if (ancestors.value.right == new_) { ancestors.value.right = n; } else { ancestors.value.left = n; } ancestors = new Cell(n, ancestors); } ancestors.value.red = false; ancestors.next.value.red = true; Node n = leftRotate(ancestors.next.value); if (ancestors.next.next == null) { newRoot = n; } else if (ancestors.next.next.value.right == ancestors.next.value) { ancestors.next.next.value.right = n; } else { ancestors.next.next.value.left = n; } // done } } } newRoot.red = false; return new PersistentSet(newRoot, comparator, size + 1); } private static Node leftRotate(Node n) { Node child = new Node(n.right); n.right = child.left; child.left = n; return child; } private static Node rightRotate(Node n) { Node child = new Node(n.left); n.left = child.right; child.right = n; return child; } public PersistentSet remove(T value) { Path p = find(value); if (! p.fresh) { return remove(p); } return this; } private PersistentSet remove(Path p) { if (size == 1) { if (p.node != root) { throw new IllegalArgumentException(); } return new PersistentSet(NullNode, comparator, 0); } Node new_ = p.node; Node newRoot = p.root.root; Cell> ancestors = p.ancestors; Node dead; if (new_.left == NullNode || new_.right == NullNode) { dead = new_; } else { Cell> path = successor(new_, ancestors); dead = path.value; ancestors = path.next; } Node child; if (dead.left != NullNode) { child = new Node(dead.left); } else if (dead.right != NullNode) { child = new Node(dead.right); } else { child = NullNode; } if (ancestors == null) { child.red = false; return new PersistentSet(child, comparator, 1); } else if (dead == ancestors.value.left) { ancestors.value.left = child; } else { ancestors.value.right = child; } if (dead != new_) { new_.value = dead.value; } if (! dead.red) { // rebalance while (ancestors != null && ! child.red) { if (child == ancestors.value.left) { Node sibling = ancestors.value.right = new Node(ancestors.value.right); if (sibling.red) { sibling.red = false; ancestors.value.red = true; Node n = leftRotate(ancestors.value); if (ancestors.next == null) { newRoot = n; } else if (ancestors.next.value.right == ancestors.value) { ancestors.next.value.right = n; } else { ancestors.next.value.left = n; } ancestors.next = new Cell(n, ancestors.next); sibling = ancestors.value.right = new Node(ancestors.value.right); } if (! (sibling.left.red || sibling.right.red)) { sibling.red = true; child = ancestors.value; ancestors = ancestors.next; } else { if (! sibling.right.red) { sibling.left = new Node(sibling.left); sibling.left.red = false; sibling.red = true; sibling = ancestors.value.right = rightRotate(sibling); } sibling.red = ancestors.value.red; ancestors.value.red = false; sibling.right = new Node(sibling.right); sibling.right.red = false; Node n = leftRotate(ancestors.value); if (ancestors.next == null) { newRoot = n; } else if (ancestors.next.value.right == ancestors.value) { ancestors.next.value.right = n; } else { ancestors.next.value.left = n; } child = newRoot; ancestors = null; } } else { Node sibling = ancestors.value.left = new Node(ancestors.value.left); if (sibling.red) { sibling.red = false; ancestors.value.red = true; Node n = rightRotate(ancestors.value); if (ancestors.next == null) { newRoot = n; } else if (ancestors.next.value.left == ancestors.value) { ancestors.next.value.left = n; } else { ancestors.next.value.right = n; } ancestors.next = new Cell(n, ancestors.next); sibling = ancestors.value.left = new Node(ancestors.value.left); } if (! (sibling.right.red || sibling.left.red)) { sibling.red = true; child = ancestors.value; ancestors = ancestors.next; } else { if (! sibling.left.red) { sibling.right = new Node(sibling.right); sibling.right.red = false; sibling.red = true; sibling = ancestors.value.left = leftRotate(sibling); } sibling.red = ancestors.value.red; ancestors.value.red = false; sibling.left = new Node(sibling.left); sibling.left.red = false; Node n = rightRotate(ancestors.value); if (ancestors.next == null) { newRoot = n; } else if (ancestors.next.value.left == ancestors.value) { ancestors.next.value.left = n; } else { ancestors.next.value.right = n; } child = newRoot; ancestors = null; } } } child.red = false; } return new PersistentSet(newRoot, comparator, size - 1); } private static Cell> minimum(Node n, Cell> ancestors) { while (n.left != NullNode) { n.left = new Node(n.left); ancestors = new Cell(n, ancestors); n = n.left; } return new Cell(n, ancestors); } private static Cell> maximum(Node n, Cell> ancestors) { while (n.right != NullNode) { n.right = new Node(n.right); ancestors = new Cell(n, ancestors); n = n.right; } return new Cell(n, ancestors); } private static Cell> successor(Node n, Cell> ancestors) { if (n.right != NullNode) { n.right = new Node(n.right); return minimum(n.right, new Cell(n, ancestors)); } while (ancestors != null && n == ancestors.value.right) { n = ancestors.value; ancestors = ancestors.next; } return ancestors; } private static Cell> predecessor(Node n, Cell> ancestors) { if (n.left != NullNode) { n.left = new Node(n.left); return maximum(n.left, new Cell(n, ancestors)); } while (ancestors != null && n == ancestors.value.left) { n = ancestors.value; ancestors = ancestors.next; } return ancestors; } public Path find(T value) { Node newRoot = new Node(root); Cell> ancestors = null; Node old = root; Node new_ = newRoot; while (old != NullNode) { ancestors = new Cell(new_, ancestors); int difference = comparator.compare(value, old.value); if (difference < 0) { old = old.left; new_ = new_.left = new Node(old); } else if (difference > 0) { old = old.right; new_ = new_.right = new Node(old); } else { return new Path(false, new_, new PersistentSet(newRoot, comparator, size), ancestors.next); } } new_.value = value; return new Path(true, new_, new PersistentSet(newRoot, comparator, size), ancestors); } public Path first() { if (root == NullNode) return null; Node newRoot = new Node(root); Cell> ancestors = null; Node old = root; Node new_ = newRoot; while (old.left != NullNode) { ancestors = new Cell(new_, ancestors); old = old.left; new_ = new_.left = new Node(old); } return new Path(true, new_, new PersistentSet(newRoot, comparator, size), ancestors); } public Path last() { if (root == NullNode) return null; Node newRoot = new Node(root); Cell> ancestors = null; Node old = root; Node new_ = newRoot; while (old.right != NullNode) { ancestors = new Cell(new_, ancestors); old = old.right; new_ = new_.right = new Node(old); } return new Path(true, new_, new PersistentSet(newRoot, comparator, size), ancestors); } public java.util.Iterator iterator() { return new Iterator(first()); } private Path successor(Path p) { Cell> s = successor(p.node, p.ancestors); if (s == null) { return null; } else { return new Path(false, s.value, p.root, s.next); } } private Path predecessor(Path p) { Cell> s = predecessor(p.node, p.ancestors); if (s == null) { return null; } else { return new Path(false, s.value, p.root, s.next); } } private static class Node { public T value; public Node left; public Node right; public boolean red; public Node(Node basis) { if (basis != null) { value = basis.value; left = basis.left; right = basis.right; red = basis.red; } } } public static class Path { private final boolean fresh; private final Node node; private final PersistentSet root; private final Cell> ancestors; public Path(boolean fresh, Node node, PersistentSet root, Cell> ancestors) { this.fresh = fresh; this.node = node; this.root = root; this.ancestors = ancestors; } public T value() { return node.value; } public boolean fresh() { return fresh; } public PersistentSet root() { return root; } public Path successor() { return root.successor(this); } public Path predecessor() { return root.predecessor(this); } public PersistentSet remove() { if (fresh) throw new IllegalStateException(); return root.remove(this); } public PersistentSet add() { if (! fresh) throw new IllegalStateException(); return root.add(this); } public PersistentSet replaceWith(T value) { if (fresh) throw new IllegalStateException(); if (root.comparator.compare(node.value, value) != 0) throw new IllegalArgumentException(); node.value = value; return root; } } public class Iterator implements java.util.Iterator { private PersistentSet.Path path; private Iterator(PersistentSet.Path path) { this.path = path; } private Iterator(Iterator start) { path = start.path; } public boolean hasNext() { return path != null; } public T next() { PersistentSet.Path p = path; path = path.successor(); return p.value(); } public void remove() { throw new UnsupportedOperationException(); } } } ReadyTalk-avian-1e1fff5/classpath/avian/Singleton.java000066400000000000000000000011361231440243200230460ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public abstract class Singleton { public static native int getInt(Object singleton, int offset); public static native long getLong(Object singleton, int offset); public static native Object getObject(Object singleton, int offset); } ReadyTalk-avian-1e1fff5/classpath/avian/Stream.java000066400000000000000000000045571231440243200223510ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; import java.io.EOFException; public abstract class Stream { public static void write1(OutputStream out, int v) throws IOException { out.write(v & 0xFF); } public static int read1(InputStream in) throws IOException { return in.read(); } public static void write2(OutputStream out, int v) throws IOException { out.write((v >>> 8) & 0xFF); out.write((v ) & 0xFF); } public static int read2(InputStream in) throws IOException { int b1 = in.read(); int b2 = in.read(); if (b2 == -1) throw new EOFException(); return ((b1 << 8) | (b2 & 0xFF)); } public static void write4(OutputStream out, int v) throws IOException { out.write((v >>> 24) & 0xFF); out.write((v >>> 16) & 0xFF); out.write((v >>> 8) & 0xFF); out.write((v ) & 0xFF); } public static int read4(InputStream in) throws IOException { int b1 = in.read(); int b2 = in.read(); int b3 = in.read(); int b4 = in.read(); if (b4 == -1) throw new EOFException(); return ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); } public static void write8(OutputStream out, long v) throws IOException { write4(out, (int) (v >>> 32) & 0xFFFFFFFF); write4(out, (int) (v ) & 0xFFFFFFFF); } public static long read8(InputStream in) throws IOException { long b1 = in.read(); long b2 = in.read(); long b3 = in.read(); long b4 = in.read(); long b5 = in.read(); long b6 = in.read(); long b7 = in.read(); long b8 = in.read(); if (b8 == -1) throw new EOFException(); return ((b1 << 56) | (b2 << 48) | (b3 << 40) | (b4 << 32) | (b5 << 24) | (b6 << 16) | (b7 << 8) | (b8)); } public static void set4(byte[] array, int offset, int v) { array[offset ] = (byte) ((v >>> 24) & 0xFF); array[offset + 1] = (byte) ((v >>> 16) & 0xFF); array[offset + 2] = (byte) ((v >>> 8) & 0xFF); array[offset + 3] = (byte) ((v ) & 0xFF); } } ReadyTalk-avian-1e1fff5/classpath/avian/SystemClassLoader.java000066400000000000000000000111741231440243200245100ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import java.net.URL; import java.net.MalformedURLException; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.ArrayList; import java.util.Enumeration; import java.util.NoSuchElementException; public class SystemClassLoader extends ClassLoader { private native VMClass findVMClass(String name) throws ClassNotFoundException; protected Class findClass(String name) throws ClassNotFoundException { return getClass(findVMClass(name)); } public static native Class getClass(VMClass vmClass); public static native VMClass vmClass(Class jClass); private native VMClass findLoadedVMClass(String name); protected Class reallyFindLoadedClass(String name){ VMClass c = findLoadedVMClass(name); return c == null ? null : getClass(c); } protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class c = findLoadedClass(name); if (c == null) { ClassLoader parent = getParent(); if (parent != null) { try { c = parent.loadClass(name); } catch (ClassNotFoundException ok) { } } if (c == null) { c = findClass(name); } } if (resolve) { resolveClass(c); } return c; } private native String resourceURLPrefix(String name); protected URL findResource(String name) { String prefix = resourceURLPrefix(name); if (prefix != null) { try { return new URL(prefix + name); } catch (MalformedURLException ignored) { } } return null; } protected Package getPackage(String name) { Package p = super.getPackage(name); if (p == null) { String source = getPackageSource(name); if (source != null) { // todo: load attributes from JAR manifest definePackage(name, null, null, null, null, null, null, null); } } return super.getPackage(name); } protected static native String getPackageSource(String name); // OpenJDK's java.lang.ClassLoader.getResource makes use of // sun.misc.Launcher to load bootstrap resources, which is not // appropriate for the Avian build, so we override it to ensure we // get the behavior we want. This implementation is the same as // that of Avian's java.lang.ClassLoader.getResource. public URL getResource(String path) { URL url = null; ClassLoader parent = getParent(); if (parent != null) { url = parent.getResource(path); } if (url == null) { url = findResource(path); } return url; } // As above, we override this method to avoid inappropriate behavior // in OpenJDK's java.lang.ClassLoader.getResources. public Enumeration getResources(String name) throws IOException { Collection urls = new ArrayList(5); ClassLoader parent = getParent(); if (parent != null) { for (Enumeration e = parent.getResources(name); e.hasMoreElements();) { urls.add(e.nextElement()); } } Enumeration urls2 = findResources(name); while (urls2.hasMoreElements()) { urls.add(urls2.nextElement()); } return Collections.enumeration(urls); } private class ResourceEnumeration implements Enumeration { private long[] finderElementPtrPtr; private String name, urlPrefix; public ResourceEnumeration(String name) { this.name = name; finderElementPtrPtr = new long[1]; urlPrefix = nextResourceURLPrefix(); } private native String nextResourceURLPrefix(SystemClassLoader loader, String name, long[] finderElementPtrPtr); private String nextResourceURLPrefix() { return nextResourceURLPrefix(SystemClassLoader.this, name, finderElementPtrPtr); } public boolean hasMoreElements() { return urlPrefix != null; } public URL nextElement() { if (urlPrefix == null) throw new NoSuchElementException(); URL result; try { result = new URL(urlPrefix + name); } catch (MalformedURLException ignored) { result = null; } if (finderElementPtrPtr[0] == 0l) urlPrefix = null; else urlPrefix = nextResourceURLPrefix(); return result; } } protected Enumeration findResources(String name) { return new ResourceEnumeration(name); } } ReadyTalk-avian-1e1fff5/classpath/avian/Traces.java000066400000000000000000000032261231440243200223270ustar00rootroot00000000000000package avian; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; public class Traces { private static final String Newline = System.getProperty("line.separator"); private static String traceAllThreads() { StringBuilder buffer = new StringBuilder(); Thread[] threads = new Thread[Thread.activeCount()]; int count = Thread.enumerate(threads); for (int i = 0; i < count; ++i) { traceThread(threads[i], buffer); } return buffer.toString(); } private static String traceThread(Thread thread) { StringBuilder buffer = new StringBuilder(); traceThread(thread, buffer); return buffer.toString(); } private static void traceThread(Thread thread, StringBuilder buffer) { buffer.append(thread).append(Newline); for (StackTraceElement e: thread.getStackTrace()) { buffer.append("\tat ").append(e).append(Newline); } } public static void startTraceListener(final String host, final int port) { Thread t = new Thread(new Runnable() { public void run() { try { ServerSocketChannel server = ServerSocketChannel.open(); server.socket().bind(new InetSocketAddress(host, port)); while (true) { SocketChannel c = server.accept(); try { c.write(ByteBuffer.wrap(traceAllThreads().getBytes())); } finally { c.close(); } } } catch (Exception e) { e.printStackTrace(); } } }); t.setDaemon(true); t.start(); } } ReadyTalk-avian-1e1fff5/classpath/avian/Utf8.java000066400000000000000000000070001231440243200217260ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; import java.io.ByteArrayOutputStream; public class Utf8 { public static boolean test(Object data) { if (!(data instanceof byte[])) return false; byte[] b = (byte[])data; for (int i = 0; i < b.length; ++i) { if (((int)b[i] & 0x080) != 0) return true; } return false; } public static byte[] encode(char[] s16, int offset, int length) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); for (int i = offset; i < offset+length; ++i) { char c = s16[i]; if (c == '\u0000') { // null char buf.write(0); buf.write(0); } else if (c < 0x080) { // 1 byte char buf.write(c); } else if (c < 0x0800) { // 2 byte char buf.write(0x0c0 | (c >>> 6)); buf.write(0x080 | (c & 0x03f)); } else { // 3 byte char buf.write(0x0e0 | ((c >>> 12) & 0x0f)); buf.write(0x080 | ((c >>> 6) & 0x03f)); buf.write(0x080 | (c & 0x03f)); } } return buf.toByteArray(); } public static Object decode(byte[] s8, int offset, int length) { Object buf = new byte[length]; boolean isMultiByte = false; int i=offset, j=0; while (i < offset+length) { int x = s8[i++]; if ((x & 0x080) == 0x0) { // 1 byte char if (x == 0) { // 2 byte null char if (i == offset + length) { return null; } ++ i; } cram(buf, j++, x); } else if ((x & 0x0e0) == 0x0c0) { // 2 byte char if (i == offset + length) { return null; } if (!isMultiByte) { buf = widen(buf, j, length-1); isMultiByte = true; } int y = s8[i++]; cram(buf, j++, ((x & 0x1f) << 6) | (y & 0x3f)); } else if ((x & 0x0f0) == 0x0e0) { // 3 byte char if (i + 1 >= offset + length) { return null; } if (!isMultiByte) { buf = widen(buf, j, length-2); isMultiByte = true; } int y = s8[i++]; int z = s8[i++]; cram(buf, j++, ((x & 0xf) << 12) | ((y & 0x3f) << 6) | (z & 0x3f)); } } return trim(buf, j); } public static char[] decode16(byte[] s8, int offset, int length) { Object decoded = decode(s8, offset, length); if (decoded == null) { return null; } else if (decoded instanceof char[]) { return (char[])decoded; } else { return (char[])widen(decoded, length, length); } } private static void cram(Object data, int index, int val) { if (data instanceof byte[]) ((byte[])data)[index] = (byte)val; else ((char[])data)[index] = (char)val; } private static Object widen(Object data, int length, int capacity) { byte[] src = (byte[])data; char[] result = new char[capacity]; for (int i = 0; i < length; ++i) result[i] = (char)((int)src[i] & 0x0ff); return result; } private static Object trim(Object data, int length) { if (data instanceof byte[]) return data; if (((char[])data).length == length) return data; char[] result = new char[length]; System.arraycopy(data, 0, result, 0, length); return result; } } ReadyTalk-avian-1e1fff5/classpath/avian/VMClass.java000066400000000000000000000025151231440243200224160ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public class VMClass { public short flags; public short vmFlags; public short fixedSize; public byte arrayElementSize; public byte arrayDimensions; public int runtimeDataIndex; public int[] objectMask; public byte[] name; public byte[] sourceFile; public VMClass super_; public Object[] interfaceTable; public VMMethod[] virtualTable; public VMField[] fieldTable; /** * Methods declared in this class, plus any abstract virtual methods * inherited from implemented or extended interfaces. If addendum * is non-null and addendum.declaredMethodCount is non-negative, * then the first addendum.declaredMethodCount methods are declared * methods, while the rest are abstract virtual methods. If * addendum is null or addendum.declaredMethodCount is negative, all * are declared methods. */ public VMMethod[] methodTable; public ClassAddendum addendum; public Object staticTable; public ClassLoader loader; public byte[] source; } ReadyTalk-avian-1e1fff5/classpath/avian/VMField.java000066400000000000000000000011351231440243200223710ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public class VMField { public byte vmFlags; public byte code; public short flags; public short offset; public int nativeID; public byte[] name; public byte[] spec; public FieldAddendum addendum; public VMClass class_; } ReadyTalk-avian-1e1fff5/classpath/avian/VMMethod.java000066400000000000000000000015061231440243200225700ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian; public class VMMethod { public byte vmFlags; public byte returnCode; public byte parameterCount; public byte parameterFootprint; public short flags; public short offset; public int nativeID; public int runtimeDataIndex; public byte[] name; public byte[] spec; public MethodAddendum addendum; public VMClass class_; public Object code; public boolean hasAnnotations() { return addendum != null && addendum.annotationTable != null; } } ReadyTalk-avian-1e1fff5/classpath/avian/avianvmresource/000077500000000000000000000000001231440243200234515ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/avian/avianvmresource/Handler.java000066400000000000000000000054501231440243200256750ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian.avianvmresource; import java.net.URL; import java.net.URLStreamHandler; import java.net.URLConnection; import java.io.IOException; import java.io.FileNotFoundException; import java.io.InputStream; public class Handler extends URLStreamHandler { protected URLConnection openConnection(URL url) { return new ResourceConnection(url); } private static class ResourceConnection extends URLConnection { public ResourceConnection(URL url) { super(url); } public int getContentLength() { return ResourceInputStream.getContentLength(url.getFile()); } public InputStream getInputStream() throws IOException { return new ResourceInputStream(url.getFile()); } public void connect() { // ignore } } private static class ResourceInputStream extends InputStream { private long peer; private int position; public ResourceInputStream(String path) throws IOException { peer = open(path); if (peer == 0) { throw new FileNotFoundException(path); } } private static native int getContentLength(String path); private static native long open(String path) throws IOException; private static native int read(long peer, int position) throws IOException; private static native int read(long peer, int position, byte[] b, int offset, int length) throws IOException; public static native void close(long peer) throws IOException; public static native int available(long peer, int position); public int available() { return available(peer, position); } public int read() throws IOException { if (peer != 0) { int c = read(peer, position); if (c >= 0) { ++ position; } return c; } else { throw new IOException(); } } public int read(byte[] b, int offset, int length) throws IOException { if (peer != 0) { if (b == null) { throw new NullPointerException(); } if (offset < 0 || offset + length > b.length) { throw new ArrayIndexOutOfBoundsException(); } int c = read(peer, position, b, offset, length); if (c >= 0) { position += c; } return c; } else { throw new IOException(); } } public void close() throws IOException { if (peer != 0) { close(peer); peer = 0; } } } } ReadyTalk-avian-1e1fff5/classpath/avian/file/000077500000000000000000000000001231440243200211575ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/avian/file/Handler.java000066400000000000000000000021751231440243200234040ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian.file; import java.net.URL; import java.net.URLStreamHandler; import java.net.URLConnection; import java.io.IOException; import java.io.FileNotFoundException; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class Handler extends URLStreamHandler { protected URLConnection openConnection(URL url) { return new FileURLConnection(url); } private static class FileURLConnection extends URLConnection { public FileURLConnection(URL url) { super(url); } public int getContentLength() { return (int) new File(url.getFile()).length(); } public InputStream getInputStream() throws IOException { return new FileInputStream(url.getFile()); } public void connect() { // ignore } } } ReadyTalk-avian-1e1fff5/classpath/avian/http/000077500000000000000000000000001231440243200212175ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/avian/http/Handler.java000066400000000000000000000013671231440243200234460ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian.http; import java.net.URL; import java.net.URLStreamHandler; import java.net.URLConnection; import java.io.IOException; import java.io.FileNotFoundException; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class Handler extends URLStreamHandler { protected URLConnection openConnection(URL url) { throw new UnsupportedOperationException(); } } ReadyTalk-avian-1e1fff5/classpath/avian/jar/000077500000000000000000000000001231440243200210145ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/avian/jar/Handler.java000066400000000000000000000043021231440243200232330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package avian.jar; import java.net.URL; import java.net.MalformedURLException; import java.net.URLStreamHandler; import java.net.JarURLConnection; import java.net.URLConnection; import java.io.IOException; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.jar.JarFile; import java.util.jar.JarEntry; public class Handler extends URLStreamHandler { protected URLConnection openConnection(URL url) { return new MyJarURLConnection(url); } protected void parseURL(URL url, String s, int start, int end) throws MalformedURLException { // skip "jar:" s = s.toString().substring(4); int index = s.indexOf("!/"); if (index < 0) { throw new MalformedURLException(); } URL file = new URL(s.substring(0, index)); if (! "file".equals(file.getProtocol())) { throw new RuntimeException ("protocol " + file.getProtocol() + " not yet supported"); } url.set("jar", null, -1, s, null); } private static class MyJarURLConnection extends JarURLConnection { private final JarFile file; private final JarEntry entry; public MyJarURLConnection(URL url) { super(url); String s = url.getFile(); int index = s.indexOf("!/"); try { this.file = new JarFile(new URL(s.substring(0, index)).getFile()); this.entry = this.file.getJarEntry(s.substring(index + 2)); } catch (MalformedURLException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } public JarFile getJarFile() throws IOException { return file; } public int getContentLength() { return (int)entry.getSize(); } public InputStream getInputStream() throws IOException { return file.getInputStream(entry); } public void connect() { // ignore } } } ReadyTalk-avian-1e1fff5/classpath/java-io.cpp000066400000000000000000000552631231440243200212070ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include #include #include #include "jni.h" #include "jni-util.h" #ifdef PLATFORM_WINDOWS # define UNICODE # include # include # include # include # define ACCESS _waccess # define CLOSE _close # define READ _read # define WRITE _write # define STAT _wstat # define STRUCT_STAT struct _stat # define MKDIR(path, mode) _wmkdir(path) # define CHMOD(path, mode) _wchmod(path, mode) # define REMOVE _wremove # define RENAME _wrename # define OPEN_MASK O_BINARY # define CHECK_X_OK R_OK # ifdef _MSC_VER # define S_ISREG(x) ((x) & _S_IFREG) # define S_ISDIR(x) ((x) & _S_IFDIR) # define S_IRUSR _S_IREAD # define S_IWUSR _S_IWRITE # define W_OK 2 # define R_OK 4 # else # define OPEN _wopen # endif # define GET_CHARS GetStringChars # define RELEASE_CHARS(path, chars) ReleaseStringChars(path, reinterpret_cast(chars)) typedef wchar_t char_t; #if defined(WINAPI_FAMILY) #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #include "avian-interop.h" #define SKIP_OPERATOR_NEW #endif #endif #else // not PLATFORM_WINDOWS # include # include # include "sys/mman.h" # define ACCESS access # define OPEN open # define CLOSE close # define READ read # define WRITE write # define STAT stat # define STRUCT_STAT struct stat # define MKDIR mkdir # define CHMOD chmod # define REMOVE remove # define RENAME rename # define OPEN_MASK 0 # define CHECK_X_OK X_OK # define GET_CHARS GetStringUTFChars # define RELEASE_CHARS ReleaseStringUTFChars typedef char char_t; #endif // not PLATFORM_WINDOWS #ifndef WINAPI_FAMILY # ifndef WINAPI_PARTITION_DESKTOP # define WINAPI_PARTITION_DESKTOP 1 # endif # ifndef WINAPI_FAMILY_PARTITION # define WINAPI_FAMILY_PARTITION(x) (x) # endif #endif // WINAPI_FAMILY #if !defined(SKIP_OPERATOR_NEW) inline void* operator new(size_t, void* p) throw() { return p; } #endif typedef const char_t* string_t; namespace { #ifdef _MSC_VER inline int OPEN(string_t path, int mask, int mode) { int fd; if (_wsopen_s(&fd, path, mask, _SH_DENYNO, mode) == 0) { return fd; } else { return -1; } } #endif inline bool exists(string_t path) { #ifdef PLATFORM_WINDOWS return GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES; #else STRUCT_STAT s; return STAT(path, &s) == 0; #endif } inline int doOpen(JNIEnv* e, string_t path, int mask) { int fd = OPEN(path, mask | OPEN_MASK, S_IRUSR | S_IWUSR); if (fd == -1) { if (errno == ENOENT) { throwNewErrno(e, "java/io/FileNotFoundException"); } else { throwNewErrno(e, "java/io/IOException"); } } return fd; } inline void doClose(JNIEnv* e, jint fd) { int r = CLOSE(fd); if (r == -1) { throwNewErrno(e, "java/io/IOException"); } } inline int doRead(JNIEnv* e, jint fd, jbyte* data, jint length) { int r = READ(fd, data, length); if (r > 0) { return r; } else if (r == 0) { return -1; } else { throwNewErrno(e, "java/io/IOException"); return 0; } } inline void doWrite(JNIEnv* e, jint fd, const jbyte* data, jint length) { int r = WRITE(fd, data, length); if (r != length) { throwNewErrno(e, "java/io/IOException"); } } #ifdef PLATFORM_WINDOWS class Directory { public: Directory(): handle(0), findNext(false) { } virtual string_t next() { if (handle and handle != INVALID_HANDLE_VALUE) { if (findNext) { if (FindNextFileW(handle, &data)) { return data.cFileName; } } else { findNext = true; return data.cFileName; } } return 0; } virtual void dispose() { if (handle and handle != INVALID_HANDLE_VALUE) { FindClose(handle); } free(this); } HANDLE handle; WIN32_FIND_DATAW data; bool findNext; }; #else // not PLATFORM_WINDOWS #endif // not PLATFORM_WINDOWS } // namespace static inline string_t getChars(JNIEnv* e, jstring path) { return reinterpret_cast(e->GET_CHARS(path, 0)); } static inline void releaseChars(JNIEnv* e, jstring path, string_t chars) { e->RELEASE_CHARS(path, chars); } extern "C" JNIEXPORT jstring JNICALL Java_java_io_File_toCanonicalPath(JNIEnv* /*e*/, jclass, jstring path) { // todo return path; } extern "C" JNIEXPORT jstring JNICALL Java_java_io_File_toAbsolutePath(JNIEnv* e UNUSED, jclass, jstring path) { #ifdef PLATFORM_WINDOWS # if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) string_t chars = getChars(e, path); if (chars) { const unsigned BufferSize = MAX_PATH; char_t buffer[BufferSize]; DWORD success = GetFullPathNameW(chars, BufferSize, buffer, 0); releaseChars(e, path, chars); if (success) { return e->NewString (reinterpret_cast(buffer), wcslen(buffer)); } } return path; # else string_t chars = getChars(e, path); if(chars) { std::wstring partialPath = chars; releaseChars(e, path, chars); std::wstring fullPath = AvianInterop::GetFullPath(partialPath); return e->NewString (reinterpret_cast(fullPath.c_str()), fullPath.length()); } return path; # endif #else jstring result = path; string_t chars = getChars(e, path); if (chars) { if (chars[0] != '/') { char* cwd = getcwd(NULL, 0); if (cwd) { unsigned size = strlen(cwd) + strlen(chars) + 2; RUNTIME_ARRAY(char, buffer, size); snprintf(RUNTIME_ARRAY_BODY(buffer), size, "%s/%s", cwd, chars); result = e->NewStringUTF(RUNTIME_ARRAY_BODY(buffer)); free(cwd); } } releaseChars(e, path, chars); } return result; #endif } extern "C" JNIEXPORT jlong JNICALL Java_java_io_File_length(JNIEnv* e, jclass, jstring path) { #ifdef PLATFORM_WINDOWS // Option: without opening file // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364946(v=vs.85).aspx string_t chars = getChars(e, path); if(chars) { LARGE_INTEGER fileSize; #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) HANDLE file = CreateFileW (chars, FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); #else HANDLE file = CreateFile2 (chars, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr); #endif releaseChars(e, path, chars); if (file == INVALID_HANDLE_VALUE) return 0; #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) if(!GetFileSizeEx(file, &fileSize)) { CloseHandle(file); return 0; } #else FILE_STANDARD_INFO info; if(!GetFileInformationByHandleEx(file, FileStandardInfo, &info, sizeof(info))) { CloseHandle(file); return 0; } fileSize = info.EndOfFile; #endif CloseHandle(file); return static_cast(fileSize.QuadPart); } #else string_t chars = getChars(e, path); if (chars) { STRUCT_STAT s; int r = STAT(chars, &s); releaseChars(e, path, chars); if (r == 0) { return s.st_size; } } #endif return 0; } extern "C" JNIEXPORT void JNICALL Java_java_io_File_mkdir(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { if (not exists(chars)) { int r = ::MKDIR(chars, 0777); if (r != 0) { throwNewErrno(e, "java/io/IOException"); } } releaseChars(e, path, chars); } } extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_createNewFile(JNIEnv* e, jclass, jstring path) { bool result = false; string_t chars = getChars(e, path); if (chars) { if (not exists(chars)) { int fd = OPEN(chars, O_CREAT | O_WRONLY | O_EXCL, 0666); if (fd == -1) { if (errno != EEXIST) { throwNewErrno(e, "java/io/IOException"); } } else { result = true; doClose(e, fd); } } releaseChars(e, path, chars); } return result; } extern "C" JNIEXPORT void JNICALL Java_java_io_File_delete(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { int r = REMOVE(chars); if (r != 0) { throwNewErrno(e, "java/io/IOException"); } releaseChars(e, path, chars); } } extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_canRead(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { int r = ACCESS(chars, R_OK); releaseChars(e, path, chars); return (r == 0); } return false; } extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_canWrite(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { int r = ACCESS(chars, W_OK); releaseChars(e, path, chars); return (r == 0); } return false; } extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_canExecute(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { int r = ACCESS(chars, CHECK_X_OK); releaseChars(e, path, chars); return (r == 0); } return false; } #ifndef PLATFORM_WINDOWS extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_setExecutable(JNIEnv* e, jclass, jstring path, jboolean executable, jboolean ownerOnly) { string_t chars = getChars(e, path); if(chars) { jboolean v; int mask; if(ownerOnly) { mask = S_IXUSR; } else { mask = S_IXUSR | S_IXGRP | S_IXOTH; } STRUCT_STAT s; int r = STAT(chars, &s); if(r == 0) { int mode = s.st_mode; if(executable) { mode |= mask; } else { mode &= ~mask; } if(CHMOD(chars, mode) != 0) { v = false; } else { v = true; } } else { v = false; } releaseChars(e, path, chars); return v; } return false; } #else // ifndef PLATFORM_WINDOWS extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_setExecutable(JNIEnv*, jclass, jstring, jboolean executable, jboolean) { return executable; } #endif extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_rename(JNIEnv* e, jclass, jstring old, jstring new_) { string_t oldChars = getChars(e, old); string_t newChars = getChars(e, new_); if (oldChars) { bool v; if (newChars) { v = RENAME(oldChars, newChars) == 0; releaseChars(e, new_, newChars); } else { v = false; } releaseChars(e, old, oldChars); return v; } else { return false; } } extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_isDirectory(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { STRUCT_STAT s; int r = STAT(chars, &s); bool v = (r == 0 and S_ISDIR(s.st_mode)); releaseChars(e, path, chars); return v; } else { return false; } } extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_isFile(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { STRUCT_STAT s; int r = STAT(chars, &s); bool v = (r == 0 and S_ISREG(s.st_mode)); releaseChars(e, path, chars); return v; } else { return false; } } extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_exists(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { bool v = exists(chars); releaseChars(e, path, chars); return v; } else { return false; } } extern "C" JNIEXPORT jlong JNICALL Java_java_io_File_lastModified(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { #ifdef PLATFORM_WINDOWS // Option: without opening file // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364946(v=vs.85).aspx # if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) HANDLE hFile = CreateFileW (chars, FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); # else HANDLE hFile = CreateFile2 (chars, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr); # endif releaseChars(e, path, chars); if (hFile == INVALID_HANDLE_VALUE) return 0; LARGE_INTEGER fileDate, filetimeToUnixEpochAdjustment; filetimeToUnixEpochAdjustment.QuadPart = 11644473600000L * 10000L; # if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) FILETIME fileLastWriteTime; if (!GetFileTime(hFile, 0, 0, &fileLastWriteTime)) { CloseHandle(hFile); return 0; } fileDate.HighPart = fileLastWriteTime.dwHighDateTime; fileDate.LowPart = fileLastWriteTime.dwLowDateTime; # else FILE_BASIC_INFO fileInfo; if (!GetFileInformationByHandleEx(hFile, FileBasicInfo, &fileInfo, sizeof(fileInfo))) { CloseHandle(hFile); return 0; } fileDate = fileInfo.ChangeTime; # endif CloseHandle(hFile); fileDate.QuadPart -= filetimeToUnixEpochAdjustment.QuadPart; return fileDate.QuadPart / 10000000L; #else struct stat fileStat; int res = stat(chars, &fileStat); releaseChars(e, path, chars); if (res == -1) { return 0; } # ifdef __APPLE__ #define MTIME st_mtimespec # else #define MTIME st_mtim # endif return (static_cast(fileStat.MTIME.tv_sec) * 1000) + (static_cast(fileStat.MTIME.tv_nsec) / (1000*1000)); #endif } return 0; } #ifdef PLATFORM_WINDOWS extern "C" JNIEXPORT jlong JNICALL Java_java_io_File_openDir(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { unsigned length = wcslen(chars); unsigned size = length * sizeof(char_t); RUNTIME_ARRAY(char_t, buffer, length + 3); memcpy(RUNTIME_ARRAY_BODY(buffer), chars, size); memcpy(RUNTIME_ARRAY_BODY(buffer) + length, L"\\*", 6); releaseChars(e, path, chars); Directory* d = new (malloc(sizeof(Directory))) Directory; #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) d->handle = FindFirstFileW(RUNTIME_ARRAY_BODY(buffer), &(d->data)); #else d->handle = FindFirstFileExW(RUNTIME_ARRAY_BODY(buffer), FindExInfoStandard, &(d->data), FindExSearchNameMatch, NULL, 0); #endif if (d->handle == INVALID_HANDLE_VALUE) { d->dispose(); d = 0; } return reinterpret_cast(d); } else { return 0; } } extern "C" JNIEXPORT jstring JNICALL Java_java_io_File_readDir(JNIEnv* e, jclass, jlong handle) { Directory* d = reinterpret_cast(handle); while (true) { string_t s = d->next(); if (s) { if (wcscmp(s, L".") == 0 || wcscmp(s, L"..") == 0) { // skip . or .. and try again } else { return e->NewString(reinterpret_cast(s), wcslen(s)); } } else { return 0; } } } extern "C" JNIEXPORT void JNICALL Java_java_io_File_closeDir(JNIEnv* , jclass, jlong handle) { reinterpret_cast(handle)->dispose(); } #else // not PLATFORM_WINDOWS extern "C" JNIEXPORT jlong JNICALL Java_java_io_File_openDir(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { jlong handle = reinterpret_cast(opendir(chars)); releaseChars(e, path, chars); return handle; } else { return 0; } } extern "C" JNIEXPORT jstring JNICALL Java_java_io_File_readDir(JNIEnv* e, jclass, jlong handle) { struct dirent * directoryEntry; if (handle!=0) { while (true) { directoryEntry = readdir(reinterpret_cast(handle)); if (directoryEntry == NULL) { return NULL; } else if (strcmp(directoryEntry->d_name, ".") == 0 || strcmp(directoryEntry->d_name, "..") == 0) { // skip . or .. and try again } else { return e->NewStringUTF(directoryEntry->d_name); } } } return NULL; } extern "C" JNIEXPORT void JNICALL Java_java_io_File_closeDir(JNIEnv* , jclass, jlong handle) { if (handle!=0) { closedir(reinterpret_cast(handle)); } } #endif // not PLATFORM_WINDOWS extern "C" JNIEXPORT jint JNICALL Java_java_io_FileInputStream_open(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { int fd = doOpen(e, chars, O_RDONLY); releaseChars(e, path, chars); return fd; } else { return -1; } } extern "C" JNIEXPORT jint JNICALL Java_java_io_FileInputStream_read__I(JNIEnv* e, jclass, jint fd) { jbyte data; int r = doRead(e, fd, &data, 1); if (r <= 0) { return -1; } else { return data & 0xff; } } extern "C" JNIEXPORT jint JNICALL Java_java_io_FileInputStream_read__I_3BII (JNIEnv* e, jclass, jint fd, jbyteArray b, jint offset, jint length) { jbyte* data = static_cast(malloc(length)); if (data == 0) { throwNew(e, "java/lang/OutOfMemoryError", 0); return 0; } int r = doRead(e, fd, data, length); e->SetByteArrayRegion(b, offset, length, data); free(data); return r; } extern "C" JNIEXPORT void JNICALL Java_java_io_FileInputStream_close(JNIEnv* e, jclass, jint fd) { doClose(e, fd); } extern "C" JNIEXPORT jint JNICALL Java_java_io_FileOutputStream_open(JNIEnv* e, jclass, jstring path, jboolean append) { string_t chars = getChars(e, path); if (chars) { int fd = doOpen(e, chars, append ? (O_WRONLY | O_CREAT | O_APPEND) : (O_WRONLY | O_CREAT | O_TRUNC)); releaseChars(e, path, chars); return fd; } else { return -1; } } extern "C" JNIEXPORT void JNICALL Java_java_io_FileOutputStream_write__II(JNIEnv* e, jclass, jint fd, jint c) { jbyte data = c; doWrite(e, fd, &data, 1); } extern "C" JNIEXPORT void JNICALL Java_java_io_FileOutputStream_write__I_3BII (JNIEnv* e, jclass, jint fd, jbyteArray b, jint offset, jint length) { jbyte* data = static_cast(malloc(length)); if (data == 0) { throwNew(e, "java/lang/OutOfMemoryError", 0); return; } e->GetByteArrayRegion(b, offset, length, data); if (not e->ExceptionCheck()) { doWrite(e, fd, data, length); } free(data); } extern "C" JNIEXPORT void JNICALL Java_java_io_FileOutputStream_close(JNIEnv* e, jclass, jint fd) { doClose(e, fd); } extern "C" JNIEXPORT void JNICALL Java_java_io_RandomAccessFile_open(JNIEnv* e, jclass, jstring path, jboolean allowWrite, jlongArray result) { string_t chars = getChars(e, path); if (chars) { jlong peer = 0; jlong length = 0; int flags = (allowWrite ? O_RDWR | O_CREAT : O_RDONLY) | OPEN_MASK; #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #if defined(PLATFORM_WINDOWS) int fd = ::_wopen(chars, flags); #else int fd = ::open((const char*)chars, flags, 0666); #endif releaseChars(e, path, chars); if (fd == -1) { throwNewErrno(e, "java/io/IOException"); return; } struct ::stat fileStats; if(::fstat(fd, &fileStats) == -1) { ::close(fd); throwNewErrno(e, "java/io/IOException"); return; } peer = fd; length = fileStats.st_size; #else HANDLE hFile = CreateFile2 (chars, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr); if (hFile == INVALID_HANDLE_VALUE) { throwNewErrno(e, "java/io/IOException"); return; } FILE_STANDARD_INFO info; if(!GetFileInformationByHandleEx(hFile, FileStandardInfo, &info, sizeof(info))) { CloseHandle(hFile); throwNewErrno(e, "java/io/IOException"); return; } peer = (jlong)hFile; length = info.EndOfFile.QuadPart; #endif e->SetLongArrayRegion(result, 0, 1, &peer); e->SetLongArrayRegion(result, 1, 1, &length); } } extern "C" JNIEXPORT jint JNICALL Java_java_io_RandomAccessFile_readBytes(JNIEnv* e, jclass, jlong peer, jlong position, jbyteArray buffer, int offset, int length) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) int fd = (int)peer; if(::lseek(fd, position, SEEK_SET) == -1) { throwNewErrno(e, "java/io/IOException"); return -1; } uint8_t* dst = reinterpret_cast (e->GetPrimitiveArrayCritical(buffer, 0)); int64_t bytesRead = ::read(fd, dst + offset, length); e->ReleasePrimitiveArrayCritical(buffer, dst, 0); if(bytesRead == -1) { throwNewErrno(e, "java/io/IOException"); return -1; } #else HANDLE hFile = (HANDLE)peer; LARGE_INTEGER lPos; lPos.QuadPart = position; if(!SetFilePointerEx(hFile, lPos, nullptr, FILE_BEGIN)) { throwNewErrno(e, "java/io/IOException"); return -1; } uint8_t* dst = reinterpret_cast (e->GetPrimitiveArrayCritical(buffer, 0)); DWORD bytesRead = 0; if(!ReadFile(hFile, dst + offset, length, &bytesRead, nullptr)) { e->ReleasePrimitiveArrayCritical(buffer, dst, 0); throwNewErrno(e, "java/io/IOException"); return -1; } e->ReleasePrimitiveArrayCritical(buffer, dst, 0); #endif return (jint)bytesRead; } extern "C" JNIEXPORT jint JNICALL Java_java_io_RandomAccessFile_writeBytes(JNIEnv* e, jclass, jlong peer, jlong position, jbyteArray buffer, int offset, int length) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) int fd = (int)peer; if(::lseek(fd, position, SEEK_SET) == -1) { throwNewErrno(e, "java/io/IOException"); return -1; } uint8_t* dst = reinterpret_cast (e->GetPrimitiveArrayCritical(buffer, 0)); int64_t bytesWritten = ::write(fd, dst + offset, length); e->ReleasePrimitiveArrayCritical(buffer, dst, 0); if(bytesWritten == -1) { throwNewErrno(e, "java/io/IOException"); return -1; } #else HANDLE hFile = (HANDLE)peer; LARGE_INTEGER lPos; lPos.QuadPart = position; if(!SetFilePointerEx(hFile, lPos, nullptr, FILE_BEGIN)) { throwNewErrno(e, "java/io/IOException"); return -1; } uint8_t* dst = reinterpret_cast (e->GetPrimitiveArrayCritical(buffer, 0)); DWORD bytesWritten = 0; if(!WriteFile(hFile, dst + offset, length, &bytesWritten, nullptr)) { e->ReleasePrimitiveArrayCritical(buffer, dst, 0); throwNewErrno(e, "java/io/IOException"); return -1; } e->ReleasePrimitiveArrayCritical(buffer, dst, 0); #endif return (jint)bytesWritten; } extern "C" JNIEXPORT void JNICALL Java_java_io_RandomAccessFile_close(JNIEnv* /* e*/, jclass, jlong peer) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) int fd = (int)peer; ::close(fd); #else HANDLE hFile = (HANDLE)peer; CloseHandle(hFile); #endif } ReadyTalk-avian-1e1fff5/classpath/java-lang.cpp000066400000000000000000000666071231440243200215250ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "math.h" #include "stdlib.h" #include "time.h" #include "string.h" #include "stdio.h" #include "jni.h" #include "jni-util.h" #include "errno.h" #include "fcntl.h" #include "ctype.h" #ifdef PLATFORM_WINDOWS # include "windows.h" # include "winbase.h" # include "io.h" # include "tchar.h" # include "float.h" # include "sys/types.h" # include "sys/timeb.h" # define SO_PREFIX "" # define SO_SUFFIX ".dll" # ifdef _MSC_VER # define snprintf sprintf_s # define isnan _isnan # define isfinite _finite # define strtof strtod # endif #else // not PLATFORM_WINDOWS # define SO_PREFIX "lib" # ifdef __APPLE__ # define SO_SUFFIX ".jnilib" # include # if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE # include # endif # else # define SO_SUFFIX ".so" # endif # include "unistd.h" # include "limits.h" # include "signal.h" # include "sys/time.h" # include "sys/types.h" # ifndef __ANDROID__ # include "sys/sysctl.h" # endif # include "sys/utsname.h" # include "sys/wait.h" #endif // not PLATFORM_WINDOWS #ifndef WINAPI_FAMILY # ifndef WINAPI_PARTITION_DESKTOP # define WINAPI_PARTITION_DESKTOP 1 # endif # ifndef WINAPI_FAMILY_PARTITION # define WINAPI_FAMILY_PARTITION(x) (x) # endif #else # if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) # include "avian-interop.h" # endif #endif // WINAPI_FAMILY namespace { #ifdef PLATFORM_WINDOWS #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) char* getErrorStr(DWORD err) { LPSTR errorStr = 0; if(!FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, err, LANG_SYSTEM_DEFAULT, (LPSTR)&errorStr, 0, 0)) { char* errStr = (char*) malloc(9 * sizeof(char)); snprintf(errStr, 9, "%d", (int) err); return errStr; } char* errStr = strdup(errorStr); LocalFree(errorStr); return errStr; } #else char* getErrorStr(DWORD err) { LPSTR errorStr = (LPSTR)malloc(4096); //NOTE: something constant if(!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, err, LANG_SYSTEM_DEFAULT, errorStr, 0, 0)) { free(errorStr); char* errStr = (char*) malloc(9 * sizeof(char)); snprintf(errStr, 9, "%d", (int) err); return errStr; } char* errStr = strdup(errorStr); free(errorStr); return errStr; } #endif #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) void makePipe(JNIEnv* e, HANDLE p[2]) { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.bInheritHandle = 1; sa.lpSecurityDescriptor = 0; BOOL success = CreatePipe(p, p + 1, &sa, 0); if (not success) { throwNew(e, "java/io/IOException", getErrorStr(GetLastError())); } } #endif int descriptor(JNIEnv* e, HANDLE h) { int fd = _open_osfhandle(reinterpret_cast(h), 0); if (fd == -1) { throwNewErrno(e, "java/io/IOException"); } return fd; } #else void makePipe(JNIEnv* e, int p[2]) { if(pipe(p) != 0) { throwNewErrno(e, "java/io/IOException"); } } void safeClose(int &fd) { if(fd != -1) close(fd); fd = -1; } void close(int p[2]) { ::close(p[0]); ::close(p[1]); } void clean(JNIEnv* e, jobjectArray command, char** p) { int i = 0; for(char** x = p; *x; ++x, ++i){ jstring element = (jstring) e->GetObjectArrayElement(command, i); e->ReleaseStringUTFChars(element, *x); } free(p); } #endif } class Locale { // represents an ISO two-char language/country pair static const unsigned FIELDLEN = 2; static const unsigned FIELDSIZE = FIELDLEN + 1; static const char* DEFAULT_LANGUAGE; static const char* DEFAULT_REGION; char language[FIELDSIZE]; char region[FIELDSIZE]; bool isLanguage(const char* language) { if (!language) return false; unsigned len = strlen(language); if (len != FIELDLEN) return false; const char* p = language - 1; while (islower(*++p)) ; if (*p != '\0') return false; return true; } bool isRegion(const char* region) { if (!region) return false; unsigned len = strlen(region); if (len != FIELDLEN) return false; const char* p = region - 1; while (isupper(*++p)) ; if (*p != '\0') return false; return true; } public: Locale(const char* language = "") { Locale l(language, ""); *this = l; } Locale(const char* language, const char* region) { language = isLanguage(language) ? language : DEFAULT_LANGUAGE; region = isRegion(region) ? region : DEFAULT_REGION; memcpy(this->language, language, FIELDSIZE); memcpy(this->region, region, FIELDSIZE); } Locale& operator=(const Locale& l) { memcpy(language, l.language, FIELDSIZE); memcpy(region, l.region, FIELDSIZE); return *this; } const char* getLanguage() { return reinterpret_cast(language); } const char* getRegion() { return reinterpret_cast(region); } }; const char* Locale::DEFAULT_LANGUAGE = "en"; const char* Locale::DEFAULT_REGION = ""; #ifdef PLATFORM_WINDOWS void appendN(char** dest, char ch, size_t length) { for(size_t i = 0; i < length; i++) { *((*dest)++) = ch; } } bool needsEscape(const char* src, size_t length) { const char* end = src + length; for(const char* ptr = src; ptr < end; ptr++) { switch(*ptr) { case ' ': case '\t': case '\n': case '\v': case '"': return true; } } return false; } void copyAndEscape(char** dest, const char* src, size_t length) { char* destp = *dest; const char* end = src + length; if(length != 0 && !needsEscape(src, length)) { for(const char* ptr = src; ptr < end; ptr++) { *(destp++) = *ptr; } } else { *(destp++) = '"'; for(const char* ptr = src; ; ptr++) { unsigned numBackslashes = 0; while(ptr < end && *ptr == '\\') { ptr++; numBackslashes++; } if(ptr == end) { appendN(&destp, '\\', 2 * numBackslashes); break; } else if(*ptr == '"') { appendN(&destp, '\\', 2 * numBackslashes + 1); *(destp++) = *ptr; } else { appendN(&destp, '\\', numBackslashes); *(destp++) = *ptr; } } *(destp++) = '"'; } *dest = destp; } extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, jobjectArray command, jlongArray process) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) int size = 0; for (int i = 0; i < e->GetArrayLength(command); ++i){ jstring element = (jstring) e->GetObjectArrayElement(command, i); if(element) { // worst case, assuming every character is '"', and we escape all of them size += 2 * e->GetStringUTFLength(element) + 3; } else { throwNew(e, "java/lang/NullPointerException", strdup("null string array element")); } } RUNTIME_ARRAY(char, line, size); char* linep = RUNTIME_ARRAY_BODY(line); for (int i = 0; i < e->GetArrayLength(command); ++i) { if (i) *(linep++) = _T(' '); jstring element = (jstring) e->GetObjectArrayElement(command, i); const char* s = e->GetStringUTFChars(element, 0); copyAndEscape(&linep, s, e->GetStringUTFLength(element)); e->ReleaseStringUTFChars(element, s); } *(linep++) = _T('\0'); HANDLE in[] = { 0, 0 }; HANDLE out[] = { 0, 0 }; HANDLE err[] = { 0, 0 }; makePipe(e, in); SetHandleInformation(in[0], HANDLE_FLAG_INHERIT, 0); jlong inDescriptor = static_cast(descriptor(e, in[0])); if(e->ExceptionCheck()) return; e->SetLongArrayRegion(process, 2, 1, &inDescriptor); makePipe(e, out); SetHandleInformation(out[1], HANDLE_FLAG_INHERIT, 0); jlong outDescriptor = static_cast(descriptor(e, out[1])); if(e->ExceptionCheck()) return; e->SetLongArrayRegion(process, 3, 1, &outDescriptor); makePipe(e, err); SetHandleInformation(err[0], HANDLE_FLAG_INHERIT, 0); jlong errDescriptor = static_cast(descriptor(e, err[0])); if(e->ExceptionCheck()) return; e->SetLongArrayRegion(process, 4, 1, &errDescriptor); PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; si.hStdOutput = in[1]; si.hStdInput = out[0]; si.hStdError = err[1]; BOOL success = CreateProcess(0, (LPSTR) RUNTIME_ARRAY_BODY(line), 0, 0, 1, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, 0, 0, &si, &pi); CloseHandle(in[1]); CloseHandle(out[0]); CloseHandle(err[1]); if (not success) { throwNew(e, "java/io/IOException", getErrorStr(GetLastError())); return; } jlong pid = reinterpret_cast(pi.hProcess); e->SetLongArrayRegion(process, 0, 1, &pid); jlong tid = reinterpret_cast(pi.hThread); e->SetLongArrayRegion(process, 1, 1, &tid); #else throwNew(e, "java/io/Exception", strdup("Not supported on WinRT/WinPhone8")); #endif } extern "C" JNIEXPORT jint JNICALL Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid, jlong tid) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) DWORD exitCode; WaitForSingleObject(reinterpret_cast(pid), INFINITE); BOOL success = GetExitCodeProcess(reinterpret_cast(pid), &exitCode); if(not success){ throwNew(e, "java/lang/Exception", getErrorStr(GetLastError())); } CloseHandle(reinterpret_cast(pid)); CloseHandle(reinterpret_cast(tid)); return exitCode; #else throwNew(e, "java/io/Exception", strdup("Not supported on WinRT/WinPhone8")); return -1; #endif } extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_kill(JNIEnv* e UNUSED, jclass, jlong pid) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) TerminateProcess(reinterpret_cast(pid), 1); #else throwNew(e, "java/io/Exception", strdup("Not supported on WinRT/WinPhone8")); #endif } Locale getLocale() { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) const char* lang = ""; const char* reg = ""; unsigned langid = GetUserDefaultUILanguage(); unsigned prilang = langid & 0x3ff; unsigned sublang = langid >> 10; switch (prilang) { case 0x004: { lang = "zh"; switch (sublang) { case 0x01: reg = "CN"; break; case 0x02: reg = "TW"; break; case 0x03: reg = "HK"; break; case 0x04: reg = "SG"; break; } } break; case 0x006: lang = "da"; reg = "DK"; break; case 0x007: lang = "de"; reg = "DE"; break; case 0x009: { lang = "en"; switch (sublang) { case 0x01: reg = "US"; break; case 0x02: reg = "GB"; break; case 0x03: reg = "AU"; break; case 0x04: reg = "CA"; break; case 0x05: reg = "NZ"; break; case 0x06: reg = "IE"; break; case 0x07: reg = "ZA"; break; case 0x10: reg = "IN"; break; } } break; case 0x00a: { lang = "es"; switch (sublang) { case 0x01: case 0x03: reg = "ES"; break; case 0x02: reg = "MX"; break; } } break; case 0x00c: { lang = "fr"; switch (sublang) { case 0x01: reg = "FR"; break; case 0x02: reg = "BE"; break; case 0x03: reg = "CA"; break; } } break; case 0x010: lang = "it"; reg = "IT"; break; case 0x011: lang = "ja"; reg = "JP"; break; case 0x012: lang = "ko"; reg = "KR"; break; case 0x013: { lang = "nl"; switch (sublang) { case 0x01: reg = "NL"; break; case 0x02: reg = "BE"; break; } } break; case 0x014: lang = "no"; reg = "NO"; break; case 0x015: lang = "pl"; reg = "PL"; break; case 0x016: { lang = "pt"; switch (sublang) { case 0x01: reg = "BR"; break; case 0x02: reg = "PT"; break; } } break; case 0x018: lang = "ro"; reg = "RO"; break; case 0x019: lang = "ru"; reg = "RU"; break; case 0x01d: lang = "sv"; reg = "SE"; break; default: lang = "en"; } return Locale(lang, reg); #else std::wstring culture = AvianInterop::GetCurrentUICulture(); char* cultureName = strdup(std::string(culture.begin(), culture.end()).c_str()); char* delimiter = strchr(cultureName, '-'); if(!delimiter) { free(cultureName); return Locale("en", "US"); } const char* lang = cultureName; const char* reg = delimiter + 1; *delimiter = 0; Locale locale(lang, reg); free(cultureName); return locale; #endif } #else extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, jobjectArray command, jlongArray process) { char** argv = static_cast (malloc((e->GetArrayLength(command) + 1) * sizeof(char*))); int i; for(i = 0; i < e->GetArrayLength(command); i++){ jstring element = (jstring) e->GetObjectArrayElement(command, i); char* s = const_cast(e->GetStringUTFChars(element, 0)); argv[i] = s; } argv[i] = 0; int in[] = { -1, -1 }; int out[] = { -1, -1 }; int err[] = { -1, -1 }; int msg[] = { -1, -1 }; makePipe(e, in); if(e->ExceptionCheck()) return; jlong inDescriptor = static_cast(in[0]); e->SetLongArrayRegion(process, 2, 1, &inDescriptor); makePipe(e, out); if(e->ExceptionCheck()) return; jlong outDescriptor = static_cast(out[1]); e->SetLongArrayRegion(process, 3, 1, &outDescriptor); makePipe(e, err); if(e->ExceptionCheck()) return; jlong errDescriptor = static_cast(err[0]); e->SetLongArrayRegion(process, 4, 1, &errDescriptor); makePipe(e, msg); if(e->ExceptionCheck()) return; if(fcntl(msg[1], F_SETFD, FD_CLOEXEC) != 0) { throwNewErrno(e, "java/io/IOException"); return; } #ifdef __QNX__ // fork(2) doesn't work in multithreaded QNX programs. See // http://www.qnx.com/developers/docs/6.4.1/neutrino/getting_started/s1_procs.html pid_t pid = vfork(); #else // We might be able to just use vfork on all UNIX-style systems, but // the manual makes it sound dangerous due to the shared // parent/child address space, so we use fork if we can. pid_t pid = fork(); #endif switch(pid){ case -1: // error throwNewErrno(e, "java/io/IOException"); return; case 0: { // child // Setup stdin, stdout and stderr dup2(in[1], 1); close(in); dup2(out[0], 0); close(out); dup2(err[1], 2); close(err); close(msg[0]); execvp(argv[0], argv); // Error if here int val = errno; ssize_t rv UNUSED = write(msg[1], &val, sizeof(val)); exit(127); } break; default: { //parent jlong JNIPid = static_cast(pid); e->SetLongArrayRegion(process, 0, 1, &JNIPid); safeClose(in[1]); safeClose(out[0]); safeClose(err[1]); safeClose(msg[1]); int val; int r = read(msg[0], &val, sizeof(val)); if(r == -1) { throwNewErrno(e, "java/io/IOException"); return; } else if(r) { errno = val; throwNewErrno(e, "java/io/IOException"); return; } } break; } safeClose(msg[0]); clean(e, command, argv); fcntl(in[0], F_SETFD, FD_CLOEXEC); fcntl(out[1], F_SETFD, FD_CLOEXEC); fcntl(err[0], F_SETFD, FD_CLOEXEC); } extern "C" JNIEXPORT jint JNICALL Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid, jlong) { bool finished = false; int status; int exitCode; while(!finished){ waitpid(pid, &status, 0); if(WIFEXITED(status)){ finished = true; exitCode = WEXITSTATUS(status); } else if(WIFSIGNALED(status)){ finished = true; exitCode = -1; } } return exitCode; } extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_kill(JNIEnv*, jclass, jlong pid) { kill((pid_t)pid, SIGTERM); } Locale getLocale() { Locale fallback; const char* LANG = getenv("LANG"); if (!LANG || strcmp(LANG, "C") == 0) return fallback; int len = strlen(LANG); char buf[len + 1]; // + 1 for the '\0' char memcpy(buf, LANG, len + 1); char* tracer = buf; const char* reg; while (*tracer && *tracer != '_') ++tracer; if (!*tracer) return fallback; *tracer = '\0'; reg = ++tracer; while (*tracer && *tracer != '.') ++tracer; if (tracer == reg) return fallback; *tracer = '\0'; Locale locale(buf, reg); return locale; } #endif extern "C" JNIEXPORT jstring JNICALL Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, jbooleanArray found) { jstring r = 0; const char* chars = e->GetStringUTFChars(name, 0); if (chars) { #ifdef PLATFORM_WINDOWS if (strcmp(chars, "line.separator") == 0) { r = e->NewStringUTF("\r\n"); } else if (strcmp(chars, "file.separator") == 0) { r = e->NewStringUTF("\\"); } else if (strcmp(chars, "path.separator") == 0) { r = e->NewStringUTF(";"); } else if (strcmp(chars, "os.name") == 0) { # if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) r = e->NewStringUTF("Windows"); # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE) r = e->NewStringUTF("Windows Phone"); # else r = e->NewStringUTF("Windows RT"); # endif } else if (strcmp(chars, "os.version") == 0) { # if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) unsigned size = 32; RUNTIME_ARRAY(char, buffer, size); OSVERSIONINFO OSversion; OSversion.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); ::GetVersionEx(&OSversion); snprintf(RUNTIME_ARRAY_BODY(buffer), size, "%i.%i", (int)OSversion.dwMajorVersion, (int)OSversion.dwMinorVersion); r = e->NewStringUTF(RUNTIME_ARRAY_BODY(buffer)); # else // Currently there is no alternative on WinRT/WP8 r = e->NewStringUTF("8.0"); # endif } else if (strcmp(chars, "os.arch") == 0) { #ifdef ARCH_x86_32 r = e->NewStringUTF("x86"); #elif defined ARCH_x86_64 r = e->NewStringUTF("x86_64"); #elif defined ARCH_powerpc r = e->NewStringUTF("ppc"); #elif defined ARCH_arm r = e->NewStringUTF("arm"); #endif } else if (strcmp(chars, "java.io.tmpdir") == 0) { # if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) TCHAR buffer[MAX_PATH]; GetTempPath(MAX_PATH, buffer); r = e->NewStringUTF(buffer); # else std::wstring tmpDir = AvianInterop::GetTemporaryFolder(); r = e->NewString((const jchar*)tmpDir.c_str(), tmpDir.length()); # endif } else if (strcmp(chars, "user.dir") == 0) { # if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) TCHAR buffer[MAX_PATH]; GetCurrentDirectory(MAX_PATH, buffer); r = e->NewStringUTF(buffer); # else std::wstring userDir = AvianInterop::GetInstalledLocation(); r = e->NewString((const jchar*)userDir.c_str(), userDir.length()); # endif } else if (strcmp(chars, "user.home") == 0) { # ifdef _MSC_VER # if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) WCHAR buffer[MAX_PATH]; size_t needed; if (_wgetenv_s(&needed, buffer, MAX_PATH, L"USERPROFILE") == 0) { r = e->NewString(reinterpret_cast(buffer), lstrlenW(buffer)); } else { r = 0; } # else std::wstring userHome = AvianInterop::GetDocumentsLibraryLocation(); r = e->NewString((const jchar*)userHome.c_str(), userHome.length()); # endif # else LPWSTR home = _wgetenv(L"USERPROFILE"); r = e->NewString(reinterpret_cast(home), lstrlenW(home)); # endif } #else if (strcmp(chars, "line.separator") == 0) { r = e->NewStringUTF("\n"); } else if (strcmp(chars, "file.separator") == 0) { r = e->NewStringUTF("/"); } else if (strcmp(chars, "path.separator") == 0) { r = e->NewStringUTF(":"); } else if (strcmp(chars, "os.name") == 0) { #ifdef __APPLE__ r = e->NewStringUTF("Mac OS X"); #elif defined __FreeBSD__ r = e->NewStringUTF("FreeBSD"); #else r = e->NewStringUTF("Linux"); #endif } else if (strcmp(chars, "os.version") == 0) { struct utsname system_id; uname(&system_id); r = e->NewStringUTF(system_id.release); } else if (strcmp(chars, "os.arch") == 0) { #ifdef ARCH_x86_32 r = e->NewStringUTF("x86"); #elif defined ARCH_x86_64 r = e->NewStringUTF("x86_64"); #elif defined ARCH_powerpc r = e->NewStringUTF("ppc"); #elif defined ARCH_arm r = e->NewStringUTF("arm"); #endif } else if (strcmp(chars, "java.io.tmpdir") == 0) { r = e->NewStringUTF("/tmp"); } else if (strcmp(chars, "user.dir") == 0) { char buffer[PATH_MAX]; r = e->NewStringUTF(getcwd(buffer, PATH_MAX)); } else if (strcmp(chars, "user.home") == 0) { r = e->NewStringUTF(getenv("HOME")); } #endif else if (strcmp(chars, "user.language") == 0) { Locale locale = getLocale(); if (strlen(locale.getLanguage())) r = e->NewStringUTF(locale.getLanguage()); } else if (strcmp(chars, "user.region") == 0) { Locale locale = getLocale(); if (strlen(locale.getRegion())) r = e->NewStringUTF(locale.getRegion()); } e->ReleaseStringUTFChars(name, chars); } if (r) { jboolean v = true; e->SetBooleanArrayRegion(found, 0, 1, &v); } return r; } // System.getEnvironment() implementation // TODO: For Win32, replace usage of deprecated _environ and add Unicode // support (neither of which is likely to be of great importance). #ifdef AVIAN_IOS namespace { const char* environ[] = { 0 }; } #elif defined __APPLE__ # include # define environ (*_NSGetEnviron()) #elif defined(WINAPI_FAMILY) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) // WinRT/WP8 does not provide alternative for environment variables char* environ[] = { 0 }; #else extern char** environ; #endif extern "C" JNIEXPORT jobjectArray JNICALL Java_java_lang_System_getEnvironment(JNIEnv* env, jclass) { int length; for (length = 0; environ[length] != 0; ++length) ; jobjectArray stringArray = env->NewObjectArray(length, env->FindClass("java/lang/String"), env->NewStringUTF("")); for (int i = 0; i < length; i++) { jobject varString = env->NewStringUTF(environ[i]); env->SetObjectArrayElement(stringArray, i, varString); } return stringArray; } extern "C" JNIEXPORT jlong JNICALL Java_java_lang_System_currentTimeMillis(JNIEnv*, jclass) { #ifdef PLATFORM_WINDOWS // We used to use _ftime here, but that only gives us 1-second // resolution on Windows 7. _ftime_s might work better, but MinGW // doesn't have it as of this writing. So we use this mess instead: FILETIME time; GetSystemTimeAsFileTime(&time); return (((static_cast(time.dwHighDateTime) << 32) | time.dwLowDateTime) / 10000) - 11644473600000LL; #else timeval tv = { 0, 0 }; gettimeofday(&tv, 0); return (static_cast(tv.tv_sec) * 1000) + (static_cast(tv.tv_usec) / 1000); #endif } extern "C" JNIEXPORT jstring JNICALL Java_java_lang_System_doMapLibraryName(JNIEnv* e, jclass, jstring name) { jstring r = 0; const char* chars = e->GetStringUTFChars(name, 0); if (chars) { unsigned nameLength = strlen(chars); unsigned size = sizeof(SO_PREFIX) + nameLength + sizeof(SO_SUFFIX); RUNTIME_ARRAY(char, buffer, size); snprintf (RUNTIME_ARRAY_BODY(buffer), size, SO_PREFIX "%s" SO_SUFFIX, chars); r = e->NewStringUTF(RUNTIME_ARRAY_BODY(buffer)); e->ReleaseStringUTFChars(name, chars); } return r; } extern "C" JNIEXPORT jboolean JNICALL Java_java_lang_Double_isInfinite(JNIEnv*, jclass, jdouble val) { return !isfinite(val); } extern "C" JNIEXPORT jboolean JNICALL Java_java_lang_Double_isNaN(JNIEnv*, jclass, jdouble val) { return isnan(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Double_doubleFromString(JNIEnv*e, jclass, jstring s, jintArray numDoublesRead) { const char* chars = e->GetStringUTFChars(s, 0); double d = 0.0; jint numRead = 0; if (chars) { char* lastRead; d = strtod(chars, &lastRead); if ((lastRead != chars) && ((chars + strlen(chars)) == lastRead)) { numRead = 1; } e->ReleaseStringUTFChars(s, chars); } e->SetIntArrayRegion(numDoublesRead, 0, 1, &numRead); return d; } extern "C" JNIEXPORT jboolean JNICALL Java_java_lang_Float_isInfinite(JNIEnv*, jclass, jfloat val) { return !isfinite(val); } extern "C" JNIEXPORT jboolean JNICALL Java_java_lang_Float_isNaN(JNIEnv*, jclass, jfloat val) { return isnan(val); } extern "C" JNIEXPORT jfloat JNICALL Java_java_lang_Float_floatFromString(JNIEnv*e, jclass, jstring s, jintArray numFloatsRead) { const char* chars = e->GetStringUTFChars(s, 0); float f = 0.0; jint numRead = 0; if (chars) { char* lastRead; f = strtof(chars, &lastRead); if ((lastRead != chars) && ((chars + strlen(chars)) == lastRead)) { numRead = 1; } e->ReleaseStringUTFChars(s, chars); } e->SetIntArrayRegion(numFloatsRead, 0, 1, &numRead); return f; } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_sin(JNIEnv*, jclass, jdouble val) { return sin(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_cos(JNIEnv*, jclass, jdouble val) { return cos(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_tan(JNIEnv*, jclass, jdouble val) { return tan(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_asin(JNIEnv*, jclass, jdouble val) { return asin(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_acos(JNIEnv*, jclass, jdouble val) { return acos(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_atan(JNIEnv*, jclass, jdouble val) { return atan(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_atan2(JNIEnv*, jclass, jdouble y, jdouble x) { return atan2(y, x); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_sinh(JNIEnv*, jclass, jdouble val) { return sinh(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_cosh(JNIEnv*, jclass, jdouble val) { return cosh(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_tanh(JNIEnv*, jclass, jdouble val) { return tanh(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_sqrt(JNIEnv*, jclass, jdouble val) { return sqrt(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_pow(JNIEnv*, jclass, jdouble val, jdouble exp) { return pow(val, exp); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_log(JNIEnv*, jclass, jdouble val) { return log(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_floor(JNIEnv*, jclass, jdouble val) { return floor(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_ceil(JNIEnv*, jclass, jdouble val) { return ceil(val); } extern "C" JNIEXPORT jdouble JNICALL Java_java_lang_Math_exp(JNIEnv*, jclass, jdouble exp) { return pow(M_E, exp); } extern "C" JNIEXPORT jint JNICALL Java_java_lang_Double_fillBufferWithDouble(JNIEnv* e, jclass, jdouble val, jbyteArray buffer, jint bufferSize) { jboolean isCopy; jbyte* buf = e->GetByteArrayElements(buffer, &isCopy); jint count = snprintf(reinterpret_cast(buf), bufferSize, "%g", val); e->ReleaseByteArrayElements(buffer, buf, 0); return count; } ReadyTalk-avian-1e1fff5/classpath/java-net.cpp000066400000000000000000000073571231440243200213670ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "jni.h" #include "avian/machine.h" #include "sockets.h" #include "jni-util.h" using namespace avian::classpath::sockets; extern "C" JNIEXPORT void JNICALL Java_java_net_Socket_init(JNIEnv* e, jclass) { init(e); } extern "C" JNIEXPORT SOCKET JNICALL Java_java_net_Socket_create(JNIEnv* e, jclass) { return create(e); } extern "C" JNIEXPORT void JNICALL Java_java_net_Socket_connect(JNIEnv* e, jclass, SOCKET sock, long addr, short port) { connect(e, sock, addr, port); } extern "C" JNIEXPORT void JNICALL Java_java_net_Socket_bind(JNIEnv* e, jclass, SOCKET sock, long addr, short port) { bind(e, sock, addr, port); } extern "C" JNIEXPORT void JNICALL Java_java_net_Socket_abort(JNIEnv* e, jclass, SOCKET sock) { abort(e, sock); } extern "C" JNIEXPORT void JNICALL Java_java_net_Socket_close(JNIEnv* e, jclass, SOCKET sock) { close(e, sock); } extern "C" JNIEXPORT void JNICALL Java_java_net_Socket_closeOutput(JNIEnv* e, jclass, SOCKET sock) { close_output(e, sock); } extern "C" JNIEXPORT void JNICALL Java_java_net_Socket_closeInput(JNIEnv* e, jclass, SOCKET sock) { close_input(e, sock); } extern "C" JNIEXPORT void JNICALL Avian_java_net_Socket_send(vm::Thread* t, vm::object, uintptr_t* arguments) { /* SOCKET s, object buffer_obj, int start_pos, int count */ SOCKET& s = *(reinterpret_cast(&arguments[0])); vm::object buffer_obj = reinterpret_cast(arguments[2]); int32_t& start_pos = *(reinterpret_cast(&arguments[3])); int32_t& count = *(reinterpret_cast(&arguments[4])); char* buffer = reinterpret_cast(&vm::byteArrayBody(t, buffer_obj, start_pos)); avian::classpath::sockets::send((JNIEnv*)t, s, buffer, count); } extern "C" JNIEXPORT int64_t JNICALL Avian_java_net_Socket_recv(vm::Thread* t, vm::object, uintptr_t* arguments) { /* SOCKET s, object buffer_obj, int start_pos, int count */ SOCKET& s = *(reinterpret_cast(&arguments[0])); vm::object buffer_obj = reinterpret_cast(arguments[2]); int32_t& start_pos = *(reinterpret_cast(&arguments[3])); int32_t& count = *(reinterpret_cast(&arguments[4])); char* buffer = reinterpret_cast(&vm::byteArrayBody(t, buffer_obj, start_pos)); return avian::classpath::sockets::recv((JNIEnv*)t, s, buffer, count); } extern "C" JNIEXPORT jint JNICALL Java_java_net_InetAddress_ipv4AddressForName(JNIEnv* e, jclass, jstring name) { const char* chars = e->GetStringUTFChars(name, 0); if (chars) { #ifdef PLATFORM_WINDOWS hostent* host = gethostbyname(chars); e->ReleaseStringUTFChars(name, chars); if (host) { return ntohl(reinterpret_cast(host->h_addr_list[0])->s_addr); } else { throwNew(e, "java/net/UnknownHostException", 0); return 0; } #else addrinfo hints; memset(&hints, 0, sizeof(addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; addrinfo* result; int r = getaddrinfo(chars, 0, &hints, &result); e->ReleaseStringUTFChars(name, chars); if (r != 0) { throwNew(e, "java/net/UnknownHostException", 0); return 0; } else { int address = ntohl (reinterpret_cast(result->ai_addr)->sin_addr.s_addr); freeaddrinfo(result); return address; } #endif } else { throwNew(e, "java/lang/OutOfMemoryError", 0); return 0; } } ReadyTalk-avian-1e1fff5/classpath/java-nio.cpp000066400000000000000000000600601231440243200213540ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include #include "jni.h" #include "jni-util.h" #ifdef PLATFORM_WINDOWS # include # include # include # ifdef _MSC_VER # define snprintf sprintf_s # else # include # endif #else # include # include # include # include # include # include # include # include # include # include #endif #define java_nio_channels_SelectionKey_OP_READ 1L #define java_nio_channels_SelectionKey_OP_WRITE 4L #define java_nio_channels_SelectionKey_OP_CONNECT 8L #define java_nio_channels_SelectionKey_OP_ACCEPT 16L #ifdef PLATFORM_WINDOWS typedef int socklen_t; #endif inline void* operator new(size_t, void* p) throw() { return p; } namespace { inline jbyteArray charsToArray(JNIEnv* e, const char* s) { unsigned length = strlen(s); jbyteArray a = e->NewByteArray(length + 1); e->SetByteArrayRegion(a, 0, length + 1, reinterpret_cast(s)); return a; } inline void doClose(int socket) { #ifdef PLATFORM_WINDOWS closesocket(socket); #else close(socket); #endif } inline jbyteArray errorString(JNIEnv* e, int n) { #ifdef _MSC_VER const unsigned size = 128; char buffer[size]; strerror_s(buffer, size, n); return charsToArray(e, buffer); #else return charsToArray(e, strerror(n)); #endif } inline jbyteArray socketErrorString(JNIEnv* e, int n) { #ifdef PLATFORM_WINDOWS const unsigned size = 64; char buffer[size]; snprintf(buffer, size, "wsa code: %d", n); return charsToArray(e, buffer); #else return errorString(e, n); #endif } inline jbyteArray errorString(JNIEnv* e) { #ifdef PLATFORM_WINDOWS const unsigned size = 64; char buffer[size]; snprintf(buffer, size, "wsa code: %d", WSAGetLastError()); return charsToArray(e, buffer); #else return errorString(e, errno); #endif } void throwIOException(JNIEnv* e, const char* s) { throwNew(e, "java/io/IOException", s); } void throwIOException(JNIEnv* e, jbyteArray a) { jbyte* s = static_cast(e->GetPrimitiveArrayCritical(a, 0)); throwIOException(e, reinterpret_cast(s)); e->ReleasePrimitiveArrayCritical(a, s, 0); } void throwIOException(JNIEnv* e) { throwIOException(e, errorString(e)); } void throwSocketException(JNIEnv* e, const char* s) { throwNew(e, "java/net/SocketException", s); } void throwSocketException(JNIEnv* e, jbyteArray a) { jbyte* s = static_cast(e->GetPrimitiveArrayCritical(a, 0)); throwSocketException(e, reinterpret_cast(s)); e->ReleasePrimitiveArrayCritical(a, s, 0); } void throwSocketException(JNIEnv* e) { throwSocketException(e, errorString(e)); } void init(JNIEnv* e, sockaddr_in* address, jstring hostString, jint port) { const char* chars = e->GetStringUTFChars(hostString, 0); if (chars) { #ifdef PLATFORM_WINDOWS hostent* host = gethostbyname(chars); e->ReleaseStringUTFChars(hostString, chars); if (host == 0) { throwIOException(e); return; } memset(address, 0, sizeof(sockaddr_in)); address->sin_family = AF_INET; address->sin_port = htons(port); address->sin_addr = *reinterpret_cast(host->h_addr_list[0]); #else addrinfo hints; memset(&hints, 0, sizeof(addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; addrinfo* result; int r = getaddrinfo(chars, 0, &hints, &result); e->ReleaseStringUTFChars(hostString, chars); if (r != 0) { throwIOException(e, gai_strerror(r)); return; } memset(address, 0, sizeof(sockaddr_in)); address->sin_family = AF_INET; address->sin_port = htons(port); address->sin_addr = reinterpret_cast (result->ai_addr)->sin_addr; freeaddrinfo(result); #endif } } inline bool einProgress(int error) { #ifdef PLATFORM_WINDOWS return error == WSAEINPROGRESS or error == WSAEWOULDBLOCK; #else return error == EINPROGRESS; #endif } inline bool einProgress() { #ifdef PLATFORM_WINDOWS return WSAGetLastError() == WSAEINPROGRESS or WSAGetLastError() == WSAEWOULDBLOCK; #else return errno == EINPROGRESS; #endif } inline bool eagain() { #ifdef PLATFORM_WINDOWS return WSAGetLastError() == WSAEINPROGRESS or WSAGetLastError() == WSAEWOULDBLOCK; #else return errno == EAGAIN; #endif } bool setBlocking(JNIEnv* e, int d, bool blocking) { #ifdef PLATFORM_WINDOWS u_long a = (blocking ? 0 : 1); int r = ioctlsocket(d, FIONBIO, &a); if (r != 0) { throwIOException(e); return false; } #else int r = fcntl(d, F_SETFL, (blocking ? (fcntl(d, F_GETFL) & (~O_NONBLOCK)) : (fcntl(d, F_GETFL) | O_NONBLOCK))); if (r < 0) { throwIOException(e); return false; } #endif return true; } bool setTcpNoDelay(JNIEnv* e, int d, bool on) { int flag = on; int r = setsockopt (d, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&flag), sizeof(int)); if (r < 0) { throwSocketException(e); return false; } return true; } void doBind(JNIEnv* e, int s, sockaddr_in* address) { { int opt = 1; int r = ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&opt), sizeof(int)); if (r != 0) { throwIOException(e); return; } } #ifdef SO_NOSIGPIPE { int opt = 1; int r = ::setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast(&opt), sizeof(int)); if (r != 0) { throwIOException(e); return; } } #endif { int r = ::bind (s, reinterpret_cast(address), sizeof(sockaddr_in)); if (r != 0) { throwIOException(e); return; } } } void doListen(JNIEnv* e, int s) { int r = ::listen(s, 100); if (r != 0) { throwIOException(e); } } void doFinishConnect(JNIEnv* e, int socket) { int error; socklen_t size = sizeof(int); int r = getsockopt(socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &size); if (r != 0 or size != sizeof(int)) { throwIOException(e); } else if (error and not einProgress(error)) { throwIOException(e, socketErrorString(e, error)); } } bool doConnect(JNIEnv* e, int s, sockaddr_in* address) { int r = ::connect(s, reinterpret_cast(address), sizeof(sockaddr_in)); if (r == 0) { return true; } else if (not einProgress()) { throwIOException(e); return false; } else { return false; } } int doAccept(JNIEnv* e, int s) { sockaddr address; socklen_t length = sizeof(address); int r = ::accept(s, &address, &length); if (r >= 0) { return r; } else if (errno != EINTR) { throwIOException(e); } return -1; } int doRead(int fd, void* buffer, size_t count) { #ifdef PLATFORM_WINDOWS return recv(fd, static_cast(buffer), count, 0); #else return read(fd, buffer, count); #endif } int doRecv(int fd, void* buffer, size_t count, int32_t* host, int32_t* port) { sockaddr address; socklen_t length = sizeof(address); int r = recvfrom (fd, static_cast(buffer), count, 0, &address, &length); if (r > 0) { sockaddr_in a; memcpy(&a, &address, length); *host = ntohl(a.sin_addr.s_addr); *port = ntohs(a.sin_port); } else { *host = 0; *port = 0; } return r; } int doWrite(int fd, const void* buffer, size_t count) { #ifdef PLATFORM_WINDOWS return send(fd, static_cast(buffer), count, 0); #else return write(fd, buffer, count); #endif } int makeSocket(JNIEnv* e, int type = SOCK_STREAM, int protocol = IPPROTO_TCP) { int s = ::socket(AF_INET, type, protocol); if (s < 0) { throwIOException(e); return s; } return s; } } // namespace extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_ServerSocketChannel_natDoAccept(JNIEnv *e, jclass, jint socket) { return ::doAccept(e, socket); } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv *e, jclass, jstring host, jint port) { int s = makeSocket(e); if (s < 0) return s; if (e->ExceptionCheck()) return 0; sockaddr_in address; init(e, &address, host, port); if (e->ExceptionCheck()) return 0; ::doBind(e, s, &address); if (e->ExceptionCheck()) return 0; ::doListen(e, s); return s; } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_DatagramChannel_bind(JNIEnv *e, jclass, jstring host, jint port) { int s = makeSocket(e, SOCK_DGRAM, IPPROTO_UDP); if (s < 0) return s; if (e->ExceptionCheck()) return 0; sockaddr_in address; init(e, &address, host, port); if (e->ExceptionCheck()) return 0; ::doBind(e, s, &address); return s; } extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_configureBlocking(JNIEnv *e, jclass, jint socket, jboolean blocking) { setBlocking(e, socket, blocking); } extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_DatagramChannel_configureBlocking(JNIEnv* e, jclass c, jint socket, jboolean blocking) { return Java_java_nio_channels_SocketChannel_configureBlocking (e, c, socket, blocking); } extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natSetTcpNoDelay(JNIEnv *e, jclass, jint socket, jboolean on) { setTcpNoDelay(e, socket, on); } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e, jclass, jstring host, jint port, jboolean blocking, jbooleanArray retVal) { int s = makeSocket(e); if (e->ExceptionCheck()) return 0; setBlocking(e, s, blocking); sockaddr_in address; init(e, &address, host, port); if (e->ExceptionCheck()) return 0; jboolean connected = ::doConnect(e, s, &address); e->SetBooleanArrayRegion(retVal, 0, 1, &connected); return s; } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_DatagramChannel_connect(JNIEnv *e, jclass, jstring host, jint port) { int s = makeSocket(e, SOCK_DGRAM, IPPROTO_UDP); if (e->ExceptionCheck()) return 0; sockaddr_in address; init(e, &address, host, port); if (e->ExceptionCheck()) return 0; ::doConnect(e, s, &address); return s; } extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e, jclass, jint socket) { doFinishConnect(e, socket); } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_SocketChannel_natRead(JNIEnv *e, jclass, jint socket, jbyteArray buffer, jint offset, jint length, jboolean blocking) { int r; if (blocking) { uint8_t* buf = static_cast(allocate(e, length)); if (buf) { r = ::doRead(socket, buf, length); if (r > 0) { e->SetByteArrayRegion (buffer, offset, r, reinterpret_cast(buf)); } free(buf); } else { return 0; } } else { jboolean isCopy; uint8_t* buf = static_cast (e->GetPrimitiveArrayCritical(buffer, &isCopy)); r = ::doRead(socket, buf + offset, length); e->ReleasePrimitiveArrayCritical(buffer, buf, 0); } if (r < 0) { if (eagain()) { return 0; } else { throwIOException(e); } } else if (r == 0) { return -1; } return r; } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_DatagramChannel_receive(JNIEnv* e, jclass, jint socket, jbyteArray buffer, jint offset, jint length, jboolean blocking, jintArray address) { int r; int32_t host; int32_t port; if (blocking) { uint8_t* buf = static_cast(allocate(e, length)); if (buf) { r = ::doRecv(socket, buf, length, &host, &port); if (r > 0) { e->SetByteArrayRegion (buffer, offset, r, reinterpret_cast(buf)); } free(buf); } else { return 0; } } else { jboolean isCopy; uint8_t* buf = static_cast (e->GetPrimitiveArrayCritical(buffer, &isCopy)); r = ::doRecv(socket, buf + offset, length, &host, &port); e->ReleasePrimitiveArrayCritical(buffer, buf, 0); } if (r < 0) { if (eagain()) { return 0; } else { throwIOException(e); } } else if (r == 0) { return -1; } else { jint jhost = host; e->SetIntArrayRegion(address, 0, 1, &jhost); jint jport = port; e->SetIntArrayRegion(address, 1, 1, &jport); } return r; } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e, jclass, jint socket, jbyteArray buffer, jint offset, jint length, jboolean blocking) { int r; if (blocking) { uint8_t* buf = static_cast(allocate(e, length)); if (buf) { e->GetByteArrayRegion (buffer, offset, length, reinterpret_cast(buf)); r = ::doWrite(socket, buf, length); free(buf); } else { return 0; } } else { jboolean isCopy; uint8_t* buf = static_cast (e->GetPrimitiveArrayCritical(buffer, &isCopy)); r = ::doWrite(socket, buf + offset, length); e->ReleasePrimitiveArrayCritical(buffer, buf, 0); } if (r < 0) { if (eagain()) { return 0; } else { throwIOException(e); } } return r; } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_DatagramChannel_write(JNIEnv* e, jclass c, jint socket, jbyteArray buffer, jint offset, jint length, jboolean blocking) { return Java_java_nio_channels_SocketChannel_natWrite (e, c, socket, buffer, offset, length, blocking); } extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e, jclass, jint socket) { int error; socklen_t size = sizeof(int); int r = getsockopt(socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &size); if (r != 0 or size != sizeof(int)) { throwIOException(e); } else if (error != 0) { throwIOException(e, socketErrorString(e, error)); } } extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natCloseSocket(JNIEnv *, jclass, jint socket) { doClose(socket); } namespace { class Pipe { public: #ifdef PLATFORM_WINDOWS // The Windows socket API only accepts socket file descriptors, not // pipe descriptors or others. Thus, to implement // Selector.wakeup(), we make a socket connection via the loopback // interface and use it as a pipe. Pipe(JNIEnv* e): connected_(false), listener_(-1), reader_(-1), writer_(-1) { sockaddr_in address; address.sin_family = AF_INET; address.sin_port = 0; address.sin_addr.s_addr = inet_addr("127.0.0.1"); //INADDR_LOOPBACK; listener_ = makeSocket(e); if (e->ExceptionCheck()) return; setBlocking(e, listener_, false); ::doBind(e, listener_, &address); if (e->ExceptionCheck()) return; ::doListen(e, listener_); if (e->ExceptionCheck()) return; socklen_t length = sizeof(sockaddr_in); int r = getsockname(listener_, reinterpret_cast(&address), &length); if (r) { throwIOException(e); return; } writer_ = makeSocket(e); if (e->ExceptionCheck()) return; setBlocking(e, writer_, true); connected_ = ::doConnect(e, writer_, &address); } void dispose() { if (listener_ >= 0) ::doClose(listener_); if (reader_ >= 0) ::doClose(reader_); if (writer_ >= 0) ::doClose(writer_); } bool connected() { return connected_; } void setConnected(bool v) { connected_ = v; } int listener() { return listener_; } void setListener(int v) { listener_ = v; } int reader() { return reader_; } void setReader(int v) { reader_ = v; } int writer() { return writer_; } private: bool connected_; int listener_; int reader_; int writer_; #else Pipe(JNIEnv* e) { if (::pipe(pipe) != 0) { throwIOException(e); return; } if (setBlocking(e, pipe[0], false)) { setBlocking(e, pipe[1], false); } open_ = true; } void dispose() { ::doClose(pipe[0]); ::doClose(pipe[1]); open_ = false; } bool connected() { return open_; } int reader() { return pipe[0]; } int writer() { return pipe[1]; } private: int pipe[2]; bool open_; #endif }; struct SelectorState { fd_set read; fd_set write; fd_set except; Pipe control; SelectorState(JNIEnv* e) : control(e) { } }; } // namespace extern "C" JNIEXPORT jlong JNICALL Java_java_nio_channels_SocketSelector_natInit(JNIEnv* e, jclass) { void *mem = malloc(sizeof(SelectorState)); if (mem) { SelectorState *s = new (mem) SelectorState(e); if (e->ExceptionCheck()) return 0; if (s) { FD_ZERO(&(s->read)); FD_ZERO(&(s->write)); FD_ZERO(&(s->except)); return reinterpret_cast(s); } } throwNew(e, "java/lang/OutOfMemoryError", 0); return 0; } extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketSelector_natWakeup(JNIEnv *e, jclass, jlong state) { SelectorState* s = reinterpret_cast(state); if (s->control.connected()) { const char c = 1; int r = ::doWrite(s->control.writer(), &c, 1); if (r != 1) { throwIOException(e); } } } extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketSelector_natClose(JNIEnv *, jclass, jlong state) { SelectorState* s = reinterpret_cast(state); s->control.dispose(); free(s); } extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketSelector_natSelectClearAll(JNIEnv *, jclass, jint socket, jlong state) { SelectorState* s = reinterpret_cast(state); FD_CLR(static_cast(socket), &(s->read)); FD_CLR(static_cast(socket), &(s->write)); FD_CLR(static_cast(socket), &(s->except)); } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_SocketSelector_natSelectUpdateInterestSet(JNIEnv *, jclass, jint socket, jint interest, jlong state, jint max) { SelectorState* s = reinterpret_cast(state); if (interest & (java_nio_channels_SelectionKey_OP_READ | java_nio_channels_SelectionKey_OP_ACCEPT)) { FD_SET(static_cast(socket), &(s->read)); if (max < socket) max = socket; } else { FD_CLR(static_cast(socket), &(s->read)); } if (interest & (java_nio_channels_SelectionKey_OP_WRITE | java_nio_channels_SelectionKey_OP_CONNECT)) { FD_SET(static_cast(socket), &(s->write)); FD_SET(static_cast(socket), &(s->except)); if (max < socket) max = socket; } else { FD_CLR(static_cast(socket), &(s->write)); } return max; } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_SocketSelector_natDoSocketSelect(JNIEnv *e, jclass, jlong state, jint max, jlong interval) { SelectorState* s = reinterpret_cast(state); if (s->control.reader() >= 0) { int socket = s->control.reader(); FD_SET(static_cast(socket), &(s->read)); if (max < socket) max = socket; } #ifdef PLATFORM_WINDOWS if (s->control.listener() >= 0) { int socket = s->control.listener(); FD_SET(static_cast(socket), &(s->read)); if (max < socket) max = socket; } if (not s->control.connected()) { int socket = s->control.writer(); FD_SET(static_cast(socket), &(s->write)); FD_SET(static_cast(socket), &(s->except)); if (max < socket) max = socket; } #endif timeval time; if (interval > 0) { time.tv_sec = interval / 1000; time.tv_usec = (interval % 1000) * 1000; } else if (interval < 0) { time.tv_sec = 0; time.tv_usec = 0; } else { time.tv_sec = 24 * 60 * 60 * 1000; time.tv_usec = 0; } int r = ::select(max + 1, &(s->read), &(s->write), &(s->except), &time); if (r < 0) { if (errno != EINTR) { throwIOException(e); return 0; } } #ifdef PLATFORM_WINDOWS if (FD_ISSET(s->control.writer(), &(s->write)) or FD_ISSET(s->control.writer(), &(s->except))) { int socket = s->control.writer(); FD_CLR(static_cast(socket), &(s->write)); FD_CLR(static_cast(socket), &(s->except)); int error; socklen_t size = sizeof(int); int r = getsockopt(socket, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &size); if (r != 0 or size != sizeof(int)) { throwIOException(e); } else if (error != 0) { throwIOException(e, socketErrorString(e, error)); } s->control.setConnected(true); } if (s->control.listener() >= 0 and FD_ISSET(s->control.listener(), &(s->read))) { FD_CLR(static_cast(s->control.listener()), &(s->read)); s->control.setReader(::doAccept(e, s->control.listener())); s->control.setListener(-1); } #endif if (s->control.reader() >= 0 and FD_ISSET(s->control.reader(), &(s->read))) { FD_CLR(static_cast(s->control.reader()), &(s->read)); char c; int r = 1; while (r == 1) { r = ::doRead(s->control.reader(), &c, 1); } if (r < 0 and not eagain()) { throwIOException(e); } } return r; } extern "C" JNIEXPORT jint JNICALL Java_java_nio_channels_SocketSelector_natUpdateReadySet(JNIEnv *, jclass, jint socket, jint interest, jlong state) { SelectorState* s = reinterpret_cast(state); jint ready = 0; if (FD_ISSET(socket, &(s->read))) { if (interest & java_nio_channels_SelectionKey_OP_READ) { ready |= java_nio_channels_SelectionKey_OP_READ; } if (interest & java_nio_channels_SelectionKey_OP_ACCEPT) { ready |= java_nio_channels_SelectionKey_OP_ACCEPT; } } if (FD_ISSET(socket, &(s->write)) or FD_ISSET(socket, &(s->except))) { if (interest & java_nio_channels_SelectionKey_OP_WRITE) { ready |= java_nio_channels_SelectionKey_OP_WRITE; } if (interest & java_nio_channels_SelectionKey_OP_CONNECT) { ready |= java_nio_channels_SelectionKey_OP_CONNECT; } } return ready; } extern "C" JNIEXPORT jboolean JNICALL Java_java_nio_ByteOrder_isNativeBigEndian(JNIEnv *, jclass) { union { uint32_t i; char c[4]; } u = {0x01020304}; if (u.c[0] == 1) return JNI_TRUE; return JNI_FALSE; } ReadyTalk-avian-1e1fff5/classpath/java-util-zip.cpp000066400000000000000000000101031231440243200223350ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "stdlib.h" #include "string.h" #include "avian/zlib-custom.h" #include "jni.h" #include "jni-util.h" extern "C" JNIEXPORT jlong JNICALL Java_java_util_zip_Inflater_make (JNIEnv* e, jclass, jboolean nowrap) { z_stream* s = static_cast(malloc(sizeof(z_stream))); if (s == 0) { throwNew(e, "java/lang/OutOfMemoryError", 0); return 0; } memset(s, 0, sizeof(z_stream)); int r = inflateInit2(s, (nowrap ? -15 : 15)); if (r != Z_OK) { free(s); throwNew(e, "java/lang/RuntimeException", zError(r)); return 0; } return reinterpret_cast(s); } extern "C" JNIEXPORT void JNICALL Java_java_util_zip_Inflater_dispose(JNIEnv*, jclass, jlong peer) { z_stream* s = reinterpret_cast(peer); inflateEnd(s); free(s); } extern "C" JNIEXPORT void JNICALL Java_java_util_zip_Inflater_inflate (JNIEnv* e, jclass, jlong peer, jbyteArray input, jint inputOffset, jint inputLength, jbyteArray output, jint outputOffset, jint outputLength, jintArray results) { z_stream* s = reinterpret_cast(peer); jbyte* in = static_cast(malloc(inputLength)); if (in == 0) { throwNew(e, "java/lang/OutOfMemoryError", 0); return; } jbyte* out = static_cast(malloc(outputLength)); if (out == 0) { free(in); throwNew(e, "java/lang/OutOfMemoryError", 0); return; } e->GetByteArrayRegion(input, inputOffset, inputLength, in); s->next_in = reinterpret_cast(in); s->avail_in = inputLength; s->next_out = reinterpret_cast(out); s->avail_out = outputLength; int r = inflate(s, Z_SYNC_FLUSH); jint resultArray[3] = { r, static_cast(inputLength - s->avail_in), static_cast(outputLength - s->avail_out) }; free(in); e->SetByteArrayRegion(output, outputOffset, resultArray[2], out); free(out); e->SetIntArrayRegion(results, 0, 3, resultArray); } extern "C" JNIEXPORT jlong JNICALL Java_java_util_zip_Deflater_make (JNIEnv* e, jclass, jboolean nowrap, jint level) { z_stream* s = static_cast(malloc(sizeof(z_stream))); if (s == 0) { throwNew(e, "java/lang/OutOfMemoryError", 0); return 0; } memset(s, 0, sizeof(z_stream)); int r = deflateInit2(s, level, (nowrap ? -15 : 15)); if (r != Z_OK) { free(s); throwNew(e, "java/lang/RuntimeException", zError(r)); return 0; } return reinterpret_cast(s); } extern "C" JNIEXPORT void JNICALL Java_java_util_zip_Deflater_dispose(JNIEnv*, jclass, jlong peer) { z_stream* s = reinterpret_cast(peer); deflateEnd(s); free(s); } extern "C" JNIEXPORT void JNICALL Java_java_util_zip_Deflater_deflate (JNIEnv* e, jclass, jlong peer, jbyteArray input, jint inputOffset, jint inputLength, jbyteArray output, jint outputOffset, jint outputLength, jboolean finish, jintArray results) { z_stream* s = reinterpret_cast(peer); jbyte* in = static_cast(malloc(inputLength)); if (in == 0) { throwNew(e, "java/lang/OutOfMemoryError", 0); return; } jbyte* out = static_cast(malloc(outputLength)); if (out == 0) { free(in); throwNew(e, "java/lang/OutOfMemoryError", 0); return; } e->GetByteArrayRegion(input, inputOffset, inputLength, in); s->next_in = reinterpret_cast(in); s->avail_in = inputLength; s->next_out = reinterpret_cast(out); s->avail_out = outputLength; int r = deflate(s, finish ? Z_FINISH : Z_NO_FLUSH); jint resultArray[3] = { r, static_cast(inputLength - s->avail_in), static_cast(outputLength - s->avail_out) }; free(in); e->SetByteArrayRegion(output, outputOffset, resultArray[2], out); free(out); e->SetIntArrayRegion(results, 0, 3, resultArray); } ReadyTalk-avian-1e1fff5/classpath/java-util.cpp000066400000000000000000000021521231440243200215420ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "time.h" #include "jni.h" #include "jni-util.h" namespace { void removeNewline(char* s) { for (; s; ++s) { if (*s == '\n') { *s = 0; break; } } } } // namespace extern "C" JNIEXPORT jstring JNICALL Java_java_util_Date_toString(JNIEnv* e, jclass c UNUSED, jlong when) { const unsigned BufferSize UNUSED = 27; time_t time = when / 1000; #ifdef PLATFORM_WINDOWS e->MonitorEnter(c); # ifdef _MSC_VER char buffer[BufferSize]; ctime_s(buffer, BufferSize, &time); removeNewline(buffer); # else char* buffer = ctime(&time); # endif jstring r = e->NewStringUTF(buffer); e->MonitorExit(c); return r; #else char buffer[BufferSize]; ctime_r(&time, buffer); removeNewline(buffer); return e->NewStringUTF(buffer); #endif } ReadyTalk-avian-1e1fff5/classpath/java/000077500000000000000000000000001231440243200200635ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/io/000077500000000000000000000000001231440243200204725ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/io/BufferedInputStream.java000066400000000000000000000035741231440243200252640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class BufferedInputStream extends InputStream { private final InputStream in; private final byte[] buffer; private int position; private int limit; public BufferedInputStream(InputStream in, int size) { this.in = in; this.buffer = new byte[size]; } public BufferedInputStream(InputStream in) { this(in, 4096); } private void fill() throws IOException { position = 0; limit = in.read(buffer); } public int read() throws IOException { if (position >= limit) { fill(); if (limit == -1) { return -1; } } return buffer[position++] & 0xFF; } public int read(byte[] b, int offset, int length) throws IOException { int count = 0; if (position < limit) { int remaining = limit - position; if (remaining > length) { remaining = length; } System.arraycopy(buffer, position, b, offset, remaining); count += remaining; position += remaining; offset += remaining; length -= remaining; } while (length > 0) { int c = in.read(b, offset, length); if (c == -1) { if (count == 0) { count = -1; } break; } else { offset += c; count += c; length -= c; if (in.available() <= 0) { break; } } } return count; } public int available() throws IOException { return in.available() + (limit - position); } public void close() throws IOException { in.close(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/BufferedOutputStream.java000066400000000000000000000026551231440243200254640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class BufferedOutputStream extends OutputStream { private final OutputStream out; private final byte[] buffer; private int position; public BufferedOutputStream(OutputStream out, int size) { this.out = out; this.buffer = new byte[size]; } public BufferedOutputStream(OutputStream out) { this(out, 4096); } private void drain() throws IOException { if (position > 0) { out.write(buffer, 0, position); position = 0; } } public void write(int c) throws IOException { if (position >= buffer.length) { drain(); } buffer[position++] = (byte) (c & 0xFF); } public void write(byte[] b, int offset, int length) throws IOException { if (length > buffer.length - position) { drain(); out.write(b, offset, length); } else { System.arraycopy(b, offset, buffer, position, length); position += length; } } public void flush() throws IOException { drain(); out.flush(); } public void close() throws IOException { flush(); out.close(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/BufferedReader.java000066400000000000000000000044741231440243200242130ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class BufferedReader extends Reader { private final Reader in; private final char[] buffer; private int position; private int limit; public BufferedReader(Reader in, int bufferSize) { this.in = in; this.buffer = new char[bufferSize]; } public BufferedReader(Reader in) { this(in, 32); } private void fill() throws IOException { position = 0; limit = in.read(buffer); } public String readLine() throws IOException { StringBuilder sb = new StringBuilder(); while (true) { if (position >= limit) { fill(); } if (position >= limit) { return sb.length() == 0 ? null : sb.toString(); } for (int i = position; i < limit; ++i) { if(buffer[i] == '\r') { sb.append(buffer, position, i - position); position = i + 1; if(i+1 < limit && buffer[i+1] == '\n') { position = i + 2; } return sb.toString(); } else if (buffer[i] == '\n') { sb.append(buffer, position, i - position); position = i + 1; return sb.toString(); } } sb.append(buffer, position, limit-position); position = limit; } } public int read(char[] b, int offset, int length) throws IOException { int count = 0; if (position >= limit && length < buffer.length) { fill(); } if (position < limit) { int remaining = limit - position; if (remaining > length) { remaining = length; } System.arraycopy(buffer, position, b, offset, remaining); count += remaining; position += remaining; offset += remaining; length -= remaining; } if (length > 0) { int c = in.read(b, offset, length); if (c == -1) { if (count == 0) { count = -1; } } else { count += c; } } return count; } public void close() throws IOException { in.close(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/BufferedWriter.java000066400000000000000000000023471231440243200242620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class BufferedWriter extends Writer { private final Writer out; private final char[] buffer; private int position; public BufferedWriter(Writer out, int size) { this.out = out; this.buffer = new char[size]; } public BufferedWriter(Writer out) { this(out, 4096); } private void drain() throws IOException { if (position > 0) { out.write(buffer, 0, position); position = 0; } } public void write(char[] b, int offset, int length) throws IOException { if (length > buffer.length - position) { drain(); out.write(b, offset, length); } else { System.arraycopy(b, offset, buffer, position, length); position += length; } } public void flush() throws IOException { drain(); out.flush(); } public void close() throws IOException { flush(); out.close(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/ByteArrayInputStream.java000066400000000000000000000025031231440243200254330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class ByteArrayInputStream extends InputStream { private final byte[] array; private int position; private final int limit; public ByteArrayInputStream(byte[] array, int offset, int length) { this.array = array; position = offset; this.limit = offset + length; } public ByteArrayInputStream(byte[] array) { this(array, 0, array.length); } public int read() { if (position < limit) { return array[position++] & 0xff; } else { return -1; } } public int read(byte[] buffer, int offset, int bufferLength) { if (bufferLength == 0) { return 0; } if (position >= limit) { return -1; } int remaining = limit-position; if (remaining < bufferLength) { bufferLength = remaining; } System.arraycopy(array, position, buffer, offset, bufferLength); position += bufferLength; return bufferLength; } public int available() { return limit - position; } } ReadyTalk-avian-1e1fff5/classpath/java/io/ByteArrayOutputStream.java000066400000000000000000000053151231440243200256400ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class ByteArrayOutputStream extends OutputStream { private static final int BufferSize = 32; private Cell chain; private int length; private byte[] buffer; private int position; public ByteArrayOutputStream(int capacity) { } public ByteArrayOutputStream() { this(0); } public void reset() { chain = null; length = 0; buffer = null; position = 0; } public int size() { return length; } public void write(int c) { if (buffer == null) { buffer = new byte[BufferSize]; } else if (position >= buffer.length) { flushBuffer(); buffer = new byte[BufferSize]; } buffer[position++] = (byte) (c & 0xFF); ++ length; } private byte[] copy(byte[] b, int offset, int length) { byte[] array = new byte[length]; System.arraycopy(b, offset, array, 0, length); return array; } public void write(byte[] b, int offset, int length) { if (b == null) { throw new NullPointerException(); } if (offset < 0 || offset + length > b.length) { throw new ArrayIndexOutOfBoundsException(); } if (length == 0) return; if (buffer != null && length <= buffer.length - position) { System.arraycopy(b, offset, buffer, position, length); position += length; } else { flushBuffer(); chain = new Cell(copy(b, offset, length), 0, length, chain); } this.length += length; } private void flushBuffer() { if (position > 0) { byte[] b = buffer; int p = position; buffer = null; position = 0; chain = new Cell(b, 0, p, chain); } } public byte[] toByteArray() { flushBuffer(); byte[] array = new byte[length]; int index = length; for (Cell c = chain; c != null; c = c.next) { int start = index - c.length; System.arraycopy(c.array, c.offset, array, start, c.length); index = start; } return array; } public String toString(String encoding) throws UnsupportedEncodingException { return new String(toByteArray(), encoding); } private static class Cell { public byte[] array; public int offset; public int length; public Cell next; public Cell(byte[] array, int offset, int length, Cell next) { this.array = array; this.offset = offset; this.length = length; this.next = next; } } } ReadyTalk-avian-1e1fff5/classpath/java/io/Closeable.java000066400000000000000000000006671231440243200232370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public interface Closeable { void close() throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/io/DataInput.java000066400000000000000000000020021231440243200232200ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public interface DataInput { boolean readBoolean() throws IOException; byte readByte() throws IOException; char readChar() throws IOException; double readDouble() throws IOException; float readFloat() throws IOException; void readFully(byte[] b) throws IOException; void readFully(byte[] b, int off, int len) throws IOException; int readInt() throws IOException; String readLine() throws IOException; long readLong() throws IOException; short readShort() throws IOException; int readUnsignedByte() throws IOException; int readUnsignedShort() throws IOException; String readUTF() throws IOException; int skipBytes(int n) throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/io/DataInputStream.java000066400000000000000000000060661231440243200244120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class DataInputStream extends InputStream implements DataInput { private InputStream in; public DataInputStream(InputStream in) { this.in = in; } public void close() throws IOException { in.close(); } public int read(byte[] buffer) throws IOException { return in.read(buffer); } public int read(byte[] buffer, int offset, int length) throws IOException { return in.read(buffer, offset, length); } public void readFully(byte[] b) throws IOException { readFully(b, 0, b.length); } public void readFully(byte[] b, int offset, int length) throws IOException { while (length > 0) { int count = read(b, offset, length); if (count < 0) { throw new EOFException("Reached EOF " + length + " bytes too early"); } offset += count; length -= count; } } public int read() throws IOException { return in.read(); } private int read0() throws IOException { int b = in.read(); if (b < 0) { throw new EOFException(); } return b; } public boolean readBoolean() throws IOException { return read0() != 0; } public byte readByte() throws IOException { return (byte)read0(); } public short readShort() throws IOException { return (short)((read0() << 8) | read0()); } public int readInt() throws IOException { return ((read0() << 24) | (read0() << 16) | (read0() << 8) | read0()); } public float readFloat() throws IOException { return Float.floatToIntBits(readInt()); } public double readDouble() throws IOException { return Double.doubleToLongBits(readLong()); } public long readLong() throws IOException { return ((readInt() & 0xffffffffl) << 32) | (readInt() & 0xffffffffl); } public char readChar() throws IOException { return (char)readShort(); } public int readUnsignedByte() throws IOException { return readByte() & 0xff; } public int readUnsignedShort() throws IOException { return readShort() & 0xffff; } public String readUTF() throws IOException { int length = readUnsignedShort(); byte[] bytes = new byte[length]; readFully(bytes); return new String(bytes, "UTF-8"); } @Deprecated public String readLine() throws IOException { int c = read(); if (c < 0) { return null; } else if (c == '\n') { return ""; } StringBuilder builder = new StringBuilder(); for (;;) { builder.append((char)c); c = read(); if (c < 0 || c == '\n') { return builder.toString(); } } } public int skipBytes(int n) throws IOException { for (int count = 0; count < n; ++count) { if (read() < 0) {; return count; } } return n; } } ReadyTalk-avian-1e1fff5/classpath/java/io/DataOutput.java000066400000000000000000000020211231440243200234220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public interface DataOutput { void write(byte[] b) throws IOException; void write(byte[] b, int off, int len) throws IOException; void write(int b) throws IOException; void writeBoolean(boolean v) throws IOException; void writeByte(int v) throws IOException; void writeBytes(String s) throws IOException; void writeChar(int v) throws IOException; void writeChars(String s) throws IOException; void writeDouble(double v) throws IOException; void writeFloat(float v) throws IOException; void writeInt(int v) throws IOException; void writeLong(long v) throws IOException; void writeShort(int v) throws IOException; void writeUTF(String s) throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/io/DataOutputStream.java000066400000000000000000000044561231440243200246140ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class DataOutputStream extends OutputStream implements DataOutput { private OutputStream out; public DataOutputStream(OutputStream out) { this.out = out; } public void close() throws IOException { out.close(); } public void flush() throws IOException { out.flush(); } public void write(byte[] buffer) throws IOException { out.write(buffer); } public void write(byte[] buffer, int offset, int length) throws IOException { out.write(buffer, offset, length); } public void write(int b) throws IOException { out.write(b); } public void writeBoolean(boolean b) throws IOException { writeByte(b ? 1 : 0); } public void writeByte(int b) throws IOException { out.write(b); } public void writeShort(int s) throws IOException { write((byte)(s >> 8)); write((byte)s); } public void writeInt(int i) throws IOException { write((byte)(i >> 24)); write((byte)(i >> 16)); write((byte)(i >> 8)); write((byte)i); } public void writeFloat(float f) throws IOException { writeInt(Float.floatToIntBits(f)); } public void writeDouble(double d) throws IOException { writeLong(Double.doubleToLongBits(d)); } public void writeLong(long l) throws IOException { write((byte)(l >> 56)); write((byte)(l >> 48)); write((byte)(l >> 40)); write((byte)(l >> 32)); write((byte)(l >> 24)); write((byte)(l >> 16)); write((byte)(l >> 8)); write((byte)l); } public void writeChar(int ch) throws IOException { write((byte)(ch >> 8)); write((byte)ch); } public void writeChars(String s) throws IOException { for (char ch : s.toCharArray()) { writeChar(ch & 0xffff); } } public void writeBytes(String s) throws IOException { out.write(s.getBytes()); } public void writeUTF(String s) throws IOException { byte[] bytes = s.getBytes("UTF-8"); writeShort((short)bytes.length); out.write(bytes); } } ReadyTalk-avian-1e1fff5/classpath/java/io/EOFException.java000066400000000000000000000010221231440243200236200ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class EOFException extends IOException { public EOFException(String message) { super(message); } public EOFException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/io/Externalizable.java000066400000000000000000000007611231440243200243120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public interface Externalizable { public void readExternal(ObjectInput in); public void writeExternal(ObjectOutput out); } ReadyTalk-avian-1e1fff5/classpath/java/io/File.java000066400000000000000000000162761231440243200222300ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class File implements Serializable { private static final String FileSeparator = System.getProperty("file.separator"); public static final String separator = FileSeparator; public static final char separatorChar = FileSeparator.charAt(0); private static final String PathSeparator = System.getProperty("path.separator"); public static final String pathSeparator = PathSeparator; public static final char pathSeparatorChar = PathSeparator.charAt(0); // static { // System.loadLibrary("natives"); // } private final String path; public File(String path) { if (path == null) throw new NullPointerException(); this.path = normalize(path); } public File(String parent, String child) { this(parent + FileSeparator + child); } public File(File parent, String child) { this(parent.getPath() + FileSeparator + child); } public static File createTempFile(String prefix, String suffix) throws IOException { return createTempFile(prefix, suffix, null); } public static File createTempFile(String prefix, String suffix, File directory) throws IOException { if(directory == null) { directory = new File(System.getProperty("java.io.tmpdir")); } if(suffix == null) { suffix = ".tmp"; } File ret; long state = System.currentTimeMillis(); do { ret = generateFile(directory, prefix, state, suffix); state *= 7; state += 3; } while(ret == null); ret.createNewFile(); return ret; } private static File generateFile(File directory, String prefix, long state, String suffix) { File ret = new File(directory, prefix + state + suffix); if(ret.exists()) { return null; } else { return ret; } } private static String stripSeparators(String p) { while (p.endsWith(FileSeparator)) { p = p.substring(0, p.length() - 1); } return p; } private static String normalize(String path) { return stripSeparators ("\\".equals(FileSeparator) ? path.replace('/', '\\') : path); } public static native boolean rename(String old, String new_); public boolean renameTo(File newName) { return rename(path, newName.path); } private static native boolean isDirectory(String path); public boolean isDirectory() { return isDirectory(path); } private static native boolean isFile(String path); public boolean isFile() { return isFile(path); } public boolean isAbsolute() { return path.equals(toAbsolutePath(path)); } private static native boolean canRead(String path); public boolean canRead() { return canRead(path); } private static native boolean canWrite(String path); public boolean canWrite() { return canWrite(path); } private static native boolean canExecute(String path); public boolean canExecute() { return canExecute(path); } private static native boolean setExecutable(String path, boolean executable, boolean ownerOnly); public boolean setExecutable(boolean executable) { return setExecutable(executable, true); } public boolean setExecutable(boolean executable, boolean ownerOnly) { return setExecutable(path, executable, ownerOnly); } public String getName() { int index = path.lastIndexOf(FileSeparator); if (index >= 0) { return path.substring(index + 1); } else { return path; } } public String toString() { return getPath(); } public String getPath() { return path; } public String getParent() { int index = path.lastIndexOf(FileSeparator); if (index >= 0) { return normalize(path.substring(0, index)); } else { return null; } } public File getParentFile() { String s = getParent(); return (s == null ? null : new File(s)); } private static native String toCanonicalPath(String path); public String getCanonicalPath() { return toCanonicalPath(path); } public File getCanonicalFile() { return new File(getCanonicalPath()); } private static native String toAbsolutePath(String path); public String getAbsolutePath() { return toAbsolutePath(path); } public File getAbsoluteFile() { return new File(getAbsolutePath()); } private static native long length(String path); public long length() { return length(path); } private static native boolean exists(String path); public boolean exists() { return exists(path); } private static native void mkdir(String path) throws IOException; public boolean mkdir() { try { mkdir(path); return true; } catch (IOException e) { return false; } } private static native boolean createNewFile(String path) throws IOException; public boolean createNewFile() throws IOException { return createNewFile(path); } public static native void delete(String path) throws IOException; public boolean delete() { try { delete(path); return true; } catch (IOException e) { return false; } } public boolean mkdirs() { File parent = getParentFile(); if (parent != null) { if (!parent.exists()) { if (!parent.mkdirs()) { return false; } } } return mkdir(); } public File[] listFiles() { return listFiles(null); } public File[] listFiles(FilenameFilter filter) { String[] list = list(filter); if (list != null) { File[] result = new File[list.length]; for (int i = 0; i < list.length; ++i) { result[i] = new File(this, list[i]); } return result; } else { return null; } } public String[] list() { return list(null); } public String[] list(FilenameFilter filter) { long handle = 0; try { handle = openDir(path); if (handle != 0) { Pair list = null; int count = 0; for (String s = readDir(handle); s != null; s = readDir(handle)) { if (filter == null || filter.accept(this, s)) { list = new Pair(s, list); ++ count; } } String[] result = new String[count]; for (int i = count - 1; i >= 0; --i) { result[i] = list.value; list = list.next; } return result; } else { return null; } } finally { if (handle != 0) { closeDir(handle); } } } public long lastModified() { return lastModified(path); } private static native long openDir(String path); private static native long lastModified(String path); private static native String readDir(long handle); private static native long closeDir(long handle); private static class Pair { public final String value; public final Pair next; public Pair(String value, Pair next) { this.value = value; this.next = next; } } } ReadyTalk-avian-1e1fff5/classpath/java/io/FileDescriptor.java000066400000000000000000000013331231440243200242530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class FileDescriptor { public static final FileDescriptor in = new FileDescriptor(0); public static final FileDescriptor out = new FileDescriptor(1); public static final FileDescriptor err = new FileDescriptor(2); final int value; public FileDescriptor(int value) { this.value = value; } public FileDescriptor() { this(-1); } } ReadyTalk-avian-1e1fff5/classpath/java/io/FileInputStream.java000066400000000000000000000034241231440243200244130ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class FileInputStream extends InputStream { // static { // System.loadLibrary("natives"); // } private int fd; private int remaining; public FileInputStream(FileDescriptor fd) { this.fd = fd.value; } public FileInputStream(String path) throws IOException { fd = open(path); remaining = (int) new File(path).length(); } public FileInputStream(File file) throws IOException { this(file.getPath()); } public int available() throws IOException { return remaining; } private static native int open(String path) throws IOException; private static native int read(int fd) throws IOException; private static native int read(int fd, byte[] b, int offset, int length) throws IOException; public static native void close(int fd) throws IOException; public int read() throws IOException { int c = read(fd); if (c >= 0 && remaining > 0) { -- remaining; } return c; } public int read(byte[] b, int offset, int length) throws IOException { if (b == null) { throw new NullPointerException(); } if (offset < 0 || offset + length > b.length) { throw new ArrayIndexOutOfBoundsException(); } int c = read(fd, b, offset, length); if (c > 0 && remaining > 0) { remaining -= c; } return c; } public void close() throws IOException { if (fd != -1) { close(fd); fd = -1; } } } ReadyTalk-avian-1e1fff5/classpath/java/io/FileNotFoundException.java000066400000000000000000000010551231440243200255510ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class FileNotFoundException extends IOException { public FileNotFoundException(String message) { super(message); } public FileNotFoundException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/io/FileOutputStream.java000066400000000000000000000031761231440243200246200ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class FileOutputStream extends OutputStream { // static { // System.loadLibrary("natives"); // } private int fd; public FileOutputStream(FileDescriptor fd) { this.fd = fd.value; } public FileOutputStream(String path) throws IOException { this(path, false); } public FileOutputStream(String path, boolean append) throws IOException { fd = open(path, append); } public FileOutputStream(File file) throws IOException { this(file.getPath()); } private static native int open(String path, boolean append) throws IOException; private static native void write(int fd, int c) throws IOException; private static native void write(int fd, byte[] b, int offset, int length) throws IOException; private static native void close(int fd) throws IOException; public void write(int c) throws IOException { write(fd, c); } public void write(byte[] b, int offset, int length) throws IOException { if (b == null) { throw new NullPointerException(); } if (offset < 0 || offset + length > b.length) { throw new ArrayIndexOutOfBoundsException(); } write(fd, b, offset, length); } public void close() throws IOException { if (fd != -1) { close(fd); fd = -1; } } } ReadyTalk-avian-1e1fff5/classpath/java/io/FileReader.java000066400000000000000000000017251231440243200233440ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class FileReader extends Reader { private final Reader in; public FileReader(FileInputStream in) { this.in = new InputStreamReader(in); } public FileReader(FileDescriptor fd) { this(new FileInputStream(fd)); } public FileReader(String path) throws IOException { this(new FileInputStream(path)); } public FileReader(File file) throws IOException { this(new FileInputStream(file)); } public int read(char[] b, int offset, int length) throws IOException { return in.read(b, offset, length); } public void close() throws IOException { in.close(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/FileWriter.java000066400000000000000000000020361231440243200234120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class FileWriter extends Writer { private final Writer out; private FileWriter(FileOutputStream out) { this.out = new OutputStreamWriter(out); } public FileWriter(FileDescriptor fd) { this(new FileOutputStream(fd)); } public FileWriter(String path) throws IOException { this(new FileOutputStream(path)); } public FileWriter(File file) throws IOException { this(new FileOutputStream(file)); } public void write(char[] b, int offset, int length) throws IOException { out.write(b, offset, length); } public void flush() throws IOException { out.flush(); } public void close() throws IOException { out.close(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/FilenameFilter.java000066400000000000000000000007001231440243200242200ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public interface FilenameFilter { boolean accept(File dir, String name); } ReadyTalk-avian-1e1fff5/classpath/java/io/FilterInputStream.java000066400000000000000000000015021231440243200247540ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class FilterInputStream extends InputStream { protected InputStream in; public FilterInputStream(InputStream in) { this.in = in; } public void close() throws IOException { in.close(); } public int read(byte[] b) throws IOException { return in.read(b); } public int read(byte[] b, int off, int len) throws IOException { return in.read(b, off, len); } public int read() throws IOException { return in.read(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/FilterOutputStream.java000066400000000000000000000016131231440243200251600ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class FilterOutputStream extends OutputStream { protected OutputStream out; public FilterOutputStream(OutputStream out) { this.out = out; } public void close() throws IOException { out.close(); } public void flush() throws IOException { out.flush(); } public void write(byte[] b) throws IOException { out.write(b); } public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); } public void write(int b) throws IOException { out.write(b); } } ReadyTalk-avian-1e1fff5/classpath/java/io/FilterReader.java000066400000000000000000000022501231440243200237040ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public abstract class FilterReader extends Reader { protected Reader in; protected FilterReader(Reader in) { this.in = in; } public int read() throws IOException { return in.read(); } public int read(char[] buffer, int offset, int length) throws IOException { return in.read(buffer, offset, length); } public boolean ready() throws IOException { throw new UnsupportedOperationException(); } public long skip(long n) throws IOException { throw new UnsupportedOperationException(); } public void close() throws IOException { in.close(); } public boolean markSupported() { return in.markSupported(); } public void mark(int readAheadLimit) throws IOException { in.mark(readAheadLimit); } public void reset() throws IOException { in.reset(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/Flushable.java000066400000000000000000000006661231440243200232520ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public interface Flushable { void flush() throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/io/IOException.java000066400000000000000000000012641231440243200235260ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class IOException extends Exception { public IOException(String message, Throwable cause) { super(message, cause); } public IOException(String message) { this(message, null); } public IOException(Throwable cause) { this(null, cause); } public IOException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/io/InputStream.java000066400000000000000000000031651231440243200236150ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public abstract class InputStream implements Closeable { public abstract int read() throws IOException; public int read(byte[] buffer) throws IOException { return read(buffer, 0, buffer.length); } public int read(byte[] buffer, int offset, int length) throws IOException { for (int i = 0; i < length; ++i) { int c = read(); if (c == -1) { if (i == 0) { return -1; } else { return i; } } else { buffer[offset + i] = (byte) (c & 0xFF); } } return length; } public long skip(long count) throws IOException { final long Max = 8 * 1024; int size = (int) (count < Max ? count : Max); byte[] buffer = new byte[size]; long remaining = count; int c; while ((c = read(buffer, 0, (int) (size < remaining ? size : remaining))) >= 0 && remaining > 0) { remaining -= c; } return count - remaining; } public int available() throws IOException { return 0; } public void mark(int limit) { // ignore } public void reset() throws IOException { throw new IOException("mark/reset not supported"); } public boolean markSupported() { return false; } public void close() throws IOException { } } ReadyTalk-avian-1e1fff5/classpath/java/io/InputStreamReader.java000066400000000000000000000045371231440243200247440ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; import avian.Utf8; public class InputStreamReader extends Reader { private static final int MultibytePadding = 4; private final InputStream in; public InputStreamReader(InputStream in) { this.in = in; } public InputStreamReader(InputStream in, String encoding) throws UnsupportedEncodingException { this(in); if (! encoding.equals("UTF-8")) { throw new UnsupportedEncodingException(encoding); } } public int read(char[] b, int offset, int length) throws IOException { if (length == 0) { return 0; } byte[] buffer = new byte[length + MultibytePadding]; int bufferLength = length; int bufferOffset = 0; while (true) { int c = in.read(buffer, bufferOffset, bufferLength); if (c <= 0) { if (bufferOffset > 0) { // if we've reached the end of the stream while trying to // read a multibyte character, we still need to return any // competely-decoded characters, plus \ufffd to indicate an // unknown character c = 1; while (bufferOffset > 0) { char[] buffer16 = Utf8.decode16(buffer, 0, bufferOffset); if (buffer16 != null) { System.arraycopy(buffer16, 0, b, offset, buffer16.length); c = buffer16.length + 1; break; } else { -- bufferOffset; } } b[offset + c - 1] = '\ufffd'; } return c; } bufferOffset += c; char[] buffer16 = Utf8.decode16(buffer, 0, bufferOffset); if (buffer16 != null) { bufferOffset = 0; System.arraycopy(buffer16, 0, b, offset, buffer16.length); return buffer16.length; } else { // the buffer ended in an incomplete multibyte character, so // we try to read a another byte at a time until it's complete bufferLength = 1; } } } public void close() throws IOException { in.close(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/LineNumberReader.java000066400000000000000000000016411231440243200245220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class LineNumberReader extends BufferedReader { private int line; public LineNumberReader(Reader in, int bufferSize) { super(in, bufferSize); } public LineNumberReader(Reader in) { super(in); } public int getLineNumber() { return line; } public void setLineNumber(int v) { line = v; } public int read(char[] b, int offset, int length) throws IOException { int c = super.read(b, offset, length); for (int i = 0; i < c; ++i) { if (b[i] == '\n') { ++ line; } } return c; } } ReadyTalk-avian-1e1fff5/classpath/java/io/NotSerializableException.java000066400000000000000000000011001231440243200262730ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class NotSerializableException extends ObjectStreamException { public NotSerializableException(String message) { super(message); } public NotSerializableException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/io/ObjectInput.java000066400000000000000000000011411231440243200235600ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public interface ObjectInput { public int available(); public void close(); public void read(); public void read(byte[] b); public void read(byte[] b, int off, int len); public Object readObject(); public long skip(long n); } ReadyTalk-avian-1e1fff5/classpath/java/io/ObjectInputStream.java000066400000000000000000000312221231440243200247370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; import static java.io.ObjectOutputStream.STREAM_MAGIC; import static java.io.ObjectOutputStream.STREAM_VERSION; import static java.io.ObjectOutputStream.TC_NULL; import static java.io.ObjectOutputStream.TC_REFERENCE; import static java.io.ObjectOutputStream.TC_CLASSDESC; import static java.io.ObjectOutputStream.TC_OBJECT; import static java.io.ObjectOutputStream.TC_STRING; import static java.io.ObjectOutputStream.TC_ARRAY; import static java.io.ObjectOutputStream.TC_CLASS; import static java.io.ObjectOutputStream.TC_BLOCKDATA; import static java.io.ObjectOutputStream.TC_ENDBLOCKDATA; import static java.io.ObjectOutputStream.TC_RESET; import static java.io.ObjectOutputStream.TC_BLOCKDATALONG; import static java.io.ObjectOutputStream.TC_EXCEPTION; import static java.io.ObjectOutputStream.TC_LONGSTRING; import static java.io.ObjectOutputStream.TC_PROXYCLASSDESC; import static java.io.ObjectOutputStream.TC_ENUM; import static java.io.ObjectOutputStream.SC_WRITE_METHOD; import static java.io.ObjectOutputStream.SC_BLOCK_DATA; import static java.io.ObjectOutputStream.SC_SERIALIZABLE; import static java.io.ObjectOutputStream.SC_EXTERNALIZABLE; import static java.io.ObjectOutputStream.SC_ENUM; import static java.io.ObjectOutputStream.getReadOrWriteMethod; import avian.VMClass; import java.util.ArrayList; import java.util.HashMap; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class ObjectInputStream extends InputStream implements DataInput { private final static int HANDLE_OFFSET = 0x7e0000; private final InputStream in; private final ArrayList references; public ObjectInputStream(InputStream in) throws IOException { this.in = in; short signature = (short)rawShort(); if (signature != STREAM_MAGIC) { throw new IOException("Unrecognized signature: 0x" + Integer.toHexString(signature)); } int version = rawShort(); if (version != STREAM_VERSION) { throw new IOException("Unsupported version: " + version); } references = new ArrayList(); } public int read() throws IOException { return in.read(); } private int rawByte() throws IOException { int c = read(); if (c < 0) { throw new EOFException(); } return c; } private int rawShort() throws IOException { return (rawByte() << 8) | rawByte(); } private int rawInt() throws IOException { return (rawShort() << 16) | rawShort(); } private long rawLong() throws IOException { return ((rawInt() & 0xffffffffl) << 32) | rawInt(); } private String rawString() throws IOException { int length = rawShort(); byte[] array = new byte[length]; readFully(array); return new String(array); } public int read(byte[] b, int offset, int length) throws IOException { return in.read(b, offset, length); } public void readFully(byte[] b) throws IOException { readFully(b, 0, b.length); } public void readFully(byte[] b, int offset, int length) throws IOException { while (length > 0) { int count = read(b, offset, length); if (count < 0) { throw new EOFException("Reached EOF " + length + " bytes too early"); } offset += count; length -= count; } } public String readLine() throws IOException { int c = read(); if (c < 0) { return null; } else if (c == '\n') { return ""; } StringBuilder builder = new StringBuilder(); for (;;) { builder.append((char)c); c = read(); if (c < 0 || c == '\n') { return builder.toString(); } } } public void close() throws IOException { in.close(); } private int remainingBlockData; private int rawBlockDataByte() throws IOException { while (remainingBlockData <= 0) { int b = rawByte(); if (b == TC_BLOCKDATA) { remainingBlockData = rawByte(); } else { throw new UnsupportedOperationException("Unknown token: 0x" + Integer.toHexString(b)); } } --remainingBlockData; return rawByte(); } private int rawBlockDataShort() throws IOException { return (rawBlockDataByte() << 8) | rawBlockDataByte(); } private int rawBlockDataInt() throws IOException { return (rawBlockDataShort() << 16) | rawBlockDataShort(); } private long rawBlockDataLong() throws IOException { return ((rawBlockDataInt() & 0xffffffffl) << 32) | rawBlockDataInt(); } public boolean readBoolean() throws IOException { return rawBlockDataByte() != 0; } public byte readByte() throws IOException { return (byte)rawBlockDataByte(); } public char readChar() throws IOException { return (char)rawBlockDataShort(); } public short readShort() throws IOException { return (short)rawBlockDataShort(); } public int readInt() throws IOException { return rawBlockDataInt(); } public long readLong() throws IOException { return rawBlockDataLong(); } public float readFloat() throws IOException { return Float.intBitsToFloat(rawBlockDataInt()); } public double readDouble() throws IOException { return Double.longBitsToDouble(rawBlockDataLong()); } public int readUnsignedByte() throws IOException { return rawBlockDataByte(); } public int readUnsignedShort() throws IOException { return rawBlockDataShort(); } public String readUTF() throws IOException { int length = rawBlockDataShort(); if (remainingBlockData < length) { throw new IOException("Short block data: " + remainingBlockData + " < " + length); } byte[] bytes = new byte[length]; readFully(bytes); remainingBlockData -= length; return new String(bytes, "UTF-8"); } public int skipBytes(int count) throws IOException { int i = 0; while (i < count) { if (read() < 0) { return i; } ++i; } return count; } private static Class charToPrimitiveType(int c) { if (c == 'B') { return Byte.TYPE; } else if (c == 'C') { return Character.TYPE; } else if (c == 'D') { return Double.TYPE; } else if (c == 'F') { return Float.TYPE; } else if (c == 'I') { return Integer.TYPE; } else if (c == 'J') { return Long.TYPE; } else if (c == 'S') { return Short.TYPE; } else if (c == 'Z') { return Boolean.TYPE; } throw new RuntimeException("Unhandled char: " + (char)c); } private void expectToken(int token) throws IOException { int c = rawByte(); if (c != token) { throw new UnsupportedOperationException("Unexpected token: 0x" + Integer.toHexString(c)); } } private void field(Field field, Object o) throws IOException, IllegalArgumentException, IllegalAccessException, ClassNotFoundException { Class type = field.getType(); if (!type.isPrimitive()) { field.set(o, readObject()); } else { if (type == Byte.TYPE) { field.setByte(o, (byte)rawByte()); } else if (type == Character.TYPE) { field.setChar(o, (char)rawShort()); } else if (type == Double.TYPE) { field.setDouble(o, Double.longBitsToDouble(rawLong())); } else if (type == Float.TYPE) { field.setFloat(o, Float.intBitsToFloat(rawInt())); } else if (type == Integer.TYPE) { field.setInt(o, rawInt()); } else if (type == Long.TYPE) { field.setLong(o, rawLong()); } else if (type == Short.TYPE) { field.setShort(o, (short)rawShort()); } else if (type == Boolean.TYPE) { field.setBoolean(o, rawByte() != 0); } else { throw new IOException("Unhandled type: " + type); } } } public Object readObject() throws IOException, ClassNotFoundException { int c = rawByte(); if (c == TC_NULL) { return null; } if (c == TC_STRING) { int length = rawShort(); byte[] bytes = new byte[length]; readFully(bytes); String s = new String(bytes, "UTF-8"); references.add(s); return s; } if (c == TC_REFERENCE) { int handle = rawInt(); return references.get(handle - HANDLE_OFFSET); } if (c != TC_OBJECT) { throw new IOException("Unexpected token: 0x" + Integer.toHexString(c)); } // class desc c = rawByte(); ClassDesc classDesc; if (c == TC_REFERENCE) { int handle = rawInt() - HANDLE_OFFSET; classDesc = (ClassDesc)references.get(handle); } else if (c == TC_CLASSDESC) { classDesc = classDesc(); } else { throw new UnsupportedOperationException("Unexpected token: 0x" + Integer.toHexString(c)); } try { Object o = makeInstance(classDesc.clazz.vmClass); references.add(o); do { Object o1 = classDesc.clazz.cast(o); boolean customized = (classDesc.flags & SC_WRITE_METHOD) != 0; Method readMethod = customized ? getReadOrWriteMethod(o, "readObject") : null; if (readMethod == null) { if (customized) { throw new IOException("Could not find required readObject method " + "in " + classDesc.clazz); } defaultReadObject(o, classDesc.fields); } else { current = o1; currentFields = classDesc.fields; readMethod.invoke(o, this); current = null; currentFields = null; expectToken(TC_ENDBLOCKDATA); } } while ((classDesc = classDesc.superClassDesc) != null); return o; } catch (IOException e) { throw e; } catch (Exception e) { throw new IOException(e); } } private static class ClassDesc { Class clazz; int flags; Field[] fields; ClassDesc superClassDesc; } private ClassDesc classDesc() throws ClassNotFoundException, IOException { ClassDesc result = new ClassDesc(); String className = rawString(); ClassLoader loader = Thread.currentThread().getContextClassLoader(); result.clazz = loader.loadClass(className); long serialVersionUID = rawLong(); try { Field field = result.clazz.getField("serialVersionUID"); long expected = field.getLong(null); if (expected != serialVersionUID) { throw new IOException("Incompatible serial version UID: 0x" + Long.toHexString(serialVersionUID) + " != 0x" + Long.toHexString(expected)); } } catch (Exception ignored) { } references.add(result); result.flags = rawByte(); if ((result.flags & ~(SC_SERIALIZABLE | SC_WRITE_METHOD)) != 0) { throw new UnsupportedOperationException("Cannot handle flags: 0x" + Integer.toHexString(result.flags)); } int fieldCount = rawShort(); result.fields = new Field[fieldCount]; for (int i = 0; i < result.fields.length; i++) { int typeChar = rawByte(); String fieldName = rawString(); try { result.fields[i] = result.clazz.getDeclaredField(fieldName); } catch (Exception e) { throw new IOException(e); } Class type; if (typeChar == '[' || typeChar == 'L') { String typeName = (String)readObject(); if (typeName.startsWith("L") && typeName.endsWith(";")) { typeName = typeName.substring(1, typeName.length() - 1) .replace('/', '.'); } type = loader.loadClass(typeName); } else { type = charToPrimitiveType(typeChar); } if (result.fields[i].getType() != type) { throw new IOException("Unexpected type of field " + fieldName + ": expected " + result.fields[i].getType() + " but got " + type); } } expectToken(TC_ENDBLOCKDATA); int c = rawByte(); if (c == TC_CLASSDESC) { result.superClassDesc = classDesc(); } else if (c != TC_NULL) { throw new UnsupportedOperationException("Unexpected token: 0x" + Integer.toHexString(c)); } return result; } private Object current; private Field[] currentFields; public void defaultReadObject() throws IOException { defaultReadObject(current, currentFields); } private void defaultReadObject(Object o, Field[] fields) throws IOException { try { for (Field field : fields) { field(field, o); } } catch (IOException e) { throw e; } catch (Exception e) { throw new IOException(e); } } private static native Object makeInstance(VMClass c); } ReadyTalk-avian-1e1fff5/classpath/java/io/ObjectOutput.java000066400000000000000000000011241231440243200237620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public interface ObjectOutput { public void close(); public void flush(); public void write(byte[] b); public void write(byte[] b, int off, int len); public void write(int b); public void writeObject(Object obj); } ReadyTalk-avian-1e1fff5/classpath/java/io/ObjectOutputStream.java000066400000000000000000000224341231440243200251450ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; import java.util.ArrayList; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class ObjectOutputStream extends OutputStream implements DataOutput { final static short STREAM_MAGIC = (short)0xaced; final static short STREAM_VERSION = 5; final static byte TC_NULL = (byte)0x70; final static byte TC_REFERENCE = (byte)0x71; final static byte TC_CLASSDESC = (byte)0x72; final static byte TC_OBJECT = (byte)0x73; final static byte TC_STRING = (byte)0x74; final static byte TC_ARRAY = (byte)0x75; final static byte TC_CLASS = (byte)0x76; final static byte TC_BLOCKDATA = (byte)0x77; final static byte TC_ENDBLOCKDATA = (byte)0x78; final static byte TC_RESET = (byte)0x79; final static byte TC_BLOCKDATALONG = (byte)0x7a; final static byte TC_EXCEPTION = (byte)0x7b; final static byte TC_LONGSTRING = (byte)0x7c; final static byte TC_PROXYCLASSDESC = (byte)0x7d; final static byte TC_ENUM = (byte)0x7e; final static byte SC_WRITE_METHOD = 0x01; //if SC_SERIALIZABLE final static byte SC_BLOCK_DATA = 0x08; //if SC_EXTERNALIZABLE final static byte SC_SERIALIZABLE = 0x02; final static byte SC_EXTERNALIZABLE = 0x04; final static byte SC_ENUM = 0x10; private final OutputStream out; public ObjectOutputStream(OutputStream out) throws IOException { this.out = out; rawShort(STREAM_MAGIC); rawShort(STREAM_VERSION); } public void write(int c) throws IOException { out.write(c); } public void write(byte[] b, int offset, int length) throws IOException { out.write(b, offset, length); } public void flush() throws IOException { out.flush(); } public void close() throws IOException { out.close(); } private void rawByte(int v) throws IOException { out.write((byte)(v & 0xff)); } private void rawShort(int v) throws IOException { rawByte(v >> 8); rawByte(v); } private void rawInt(int v) throws IOException { rawShort(v >> 16); rawShort(v); } private void rawLong(long v) throws IOException { rawInt((int)(v >> 32)); rawInt((int)(v & 0xffffffffl)); } private void blockData(int... bytes) throws IOException { blockData(bytes, null, null); } private void blockData(int[] bytes, byte[] bytes2, char[] chars) throws IOException { int count = (bytes == null ? 0 : bytes.length) + (bytes2 == null ? 0 : bytes2.length) + (chars == null ? 0 : chars.length * 2); if (count < 0x100) { rawByte(TC_BLOCKDATA); rawByte(count); } else { rawByte(TC_BLOCKDATALONG); rawInt(count); } if (bytes != null) { for (int b : bytes) { rawByte(b); } } if (bytes2 != null) { for (byte b : bytes2) { rawByte(b & 0xff); } } if (chars != null) { for (char c : chars) { rawShort((short)c); } } } public void writeBoolean(boolean v) throws IOException { blockData(v ? 1 : 0); } public void writeByte(int v) throws IOException { blockData(v); } public void writeShort(int v) throws IOException { blockData(v >> 8, v); } public void writeChar(int v) throws IOException { blockData(v >> 8, v); } public void writeInt(int v) throws IOException { blockData(v >> 24, v >> 16, v >> 8, v); } public void writeLong(long v) throws IOException { int u = (int)(v >> 32), l = (int)(v & 0xffffffff); blockData(u >> 24, u >> 16, u >> 8, u, l >> 24, l >> 16, l >> 8, l); } public void writeFloat(float v) throws IOException { writeInt(Float.floatToIntBits(v)); } public void writeDouble(double v) throws IOException { writeLong(Double.doubleToLongBits(v)); } public void writeBytes(String s) throws IOException { blockData(null, s.getBytes(), null); } public void writeChars(String s) throws IOException { blockData(null, null, s.toCharArray()); } public void writeUTF(String s) throws IOException { byte[] bytes = s.getBytes(); int length = bytes.length; blockData(new int[] { length >> 8, length }, bytes, null); } private int classHandle; private void string(String s) throws IOException { int length = s.length(); rawShort(length); for (byte b : s.getBytes()) { rawByte(b); } } private static char primitiveTypeChar(Class type) { if (type == Byte.TYPE) { return 'B'; } else if (type == Character.TYPE) { return 'C'; } else if (type == Double.TYPE) { return 'D'; } else if (type == Float.TYPE) { return 'F'; } else if (type == Integer.TYPE) { return 'I'; } else if (type == Long.TYPE) { return 'J'; } else if (type == Short.TYPE) { return 'S'; } else if (type == Boolean.TYPE) { return 'Z'; } throw new RuntimeException("Unhandled primitive type: " + type); } private void classDesc(Class clazz, int scFlags) throws IOException { rawByte(TC_CLASSDESC); // class name string(clazz.getName()); // serial version UID long serialVersionUID = 1l; try { Field field = clazz.getField("serialVersionUID"); serialVersionUID = field.getLong(null); } catch (Exception ignored) {} rawLong(serialVersionUID); // handle rawByte(SC_SERIALIZABLE | scFlags); Field[] fields = getFields(clazz); rawShort(fields.length); for (Field field : fields) { Class fieldType = field.getType(); if (fieldType.isPrimitive()) { rawByte(primitiveTypeChar(fieldType)); string(field.getName()); } else { rawByte(fieldType.isArray() ? '[' : 'L'); string(field.getName()); rawByte(TC_STRING); string("L" + fieldType.getName().replace('.', '/') + ";"); } } rawByte(TC_ENDBLOCKDATA); // TODO: write annotation rawByte(TC_NULL); // super class desc } private void field(Object o, Field field) throws IOException { try { field.setAccessible(true); Class type = field.getType(); if (!type.isPrimitive()) { writeObject(field.get(o)); } else if (type == Byte.TYPE) { rawByte(field.getByte(o)); } else if (type == Character.TYPE) { char c = field.getChar(o); rawShort((short)c); } else if (type == Double.TYPE) { double d = field.getDouble(o); rawLong(Double.doubleToLongBits(d)); } else if (type == Float.TYPE) { float f = field.getFloat(o); rawInt(Float.floatToIntBits(f)); } else if (type == Integer.TYPE) { int i = field.getInt(o); rawInt(i); } else if (type == Long.TYPE) { long l = field.getLong(o); rawLong(l); } else if (type == Short.TYPE) { short s = field.getShort(o); rawShort(s); } else if (type == Boolean.TYPE) { boolean b = field.getBoolean(o); rawByte(b ? 1 : 0); } else { throw new UnsupportedOperationException("Field '" + field.getName() + "' has unsupported type: " + type); } } catch (IOException e) { throw e; } catch (Exception e) { throw new IOException(e); } } private static Field[] getFields(Class clazz) { ArrayList list = new ArrayList(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (0 == (field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT))) { list.add(field); } } return list.toArray(new Field[list.size()]); } public void writeObject(Object o) throws IOException { if (o == null) { rawByte(TC_NULL); return; } if (o instanceof String) { byte[] bytes = ((String)o).getBytes("UTF-8"); rawByte(TC_STRING); rawShort(bytes.length); write(bytes); return; } rawByte(TC_OBJECT); Method writeObject = getReadOrWriteMethod(o, "writeObject"); if (writeObject == null) { classDesc(o.getClass(), 0); defaultWriteObject(o); } else try { classDesc(o.getClass(), SC_WRITE_METHOD); current = o; writeObject.invoke(o, this); current = null; rawByte(TC_ENDBLOCKDATA); } catch (Exception e) { throw new IOException(e); } } static Method getReadOrWriteMethod(Object o, String methodName) { try { Method method = o.getClass().getDeclaredMethod(methodName, new Class[] { methodName.startsWith("write") ? ObjectOutputStream.class : ObjectInputStream.class }); method.setAccessible(true); int modifiers = method.getModifiers(); if ((modifiers & Modifier.STATIC) == 0 || (modifiers & Modifier.PRIVATE) != 0) { return method; } } catch (NoSuchMethodException ignored) { } return null; } private Object current; public void defaultWriteObject() throws IOException { defaultWriteObject(current); } private void defaultWriteObject(Object o) throws IOException { for (Field field : getFields(o.getClass())) { field(o, field); } } } ReadyTalk-avian-1e1fff5/classpath/java/io/ObjectStreamException.java000066400000000000000000000010551231440243200255770ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class ObjectStreamException extends IOException { public ObjectStreamException(String message) { super(message); } public ObjectStreamException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/io/OutputStream.java000066400000000000000000000015211231440243200240100ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public abstract class OutputStream implements Closeable, Flushable { public abstract void write(int c) throws IOException; public void write(byte[] buffer) throws IOException { write(buffer, 0, buffer.length); } public void write(byte[] buffer, int offset, int length) throws IOException { for (int i = 0; i < length; ++i) { write(buffer[offset + i]); } } public void flush() throws IOException { } public void close() throws IOException { } } ReadyTalk-avian-1e1fff5/classpath/java/io/OutputStreamWriter.java000066400000000000000000000014461231440243200252130ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; import avian.Utf8; public class OutputStreamWriter extends Writer { private final OutputStream out; public OutputStreamWriter(OutputStream out) { this.out = out; } public void write(char[] b, int offset, int length) throws IOException { out.write(Utf8.encode(b, offset, length)); } public void flush() throws IOException { out.flush(); } public void close() throws IOException { out.close(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/PrintStream.java000066400000000000000000000054251231440243200236130ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class PrintStream extends OutputStream { private final OutputStream out; private final boolean autoFlush; private static class Static { private static final byte[] newline = System.getProperty("line.separator").getBytes(); } public PrintStream(OutputStream out, boolean autoFlush) { this.out = out; this.autoFlush = autoFlush; } public PrintStream(OutputStream out) { this(out, false); } public synchronized void print(String s) { try { out.write(s.getBytes()); if (autoFlush) flush(); } catch (IOException e) { } } public void print(Object o) { print(String.valueOf(o)); } public void print(boolean v) { print(String.valueOf(v)); } public void print(char c) { print(String.valueOf(c)); } public void print(int v) { print(String.valueOf(v)); } public void print(long v) { print(String.valueOf(v)); } public void print(float v) { print(String.valueOf(v)); } public void print(double v) { print(String.valueOf(v)); } public void print(char[] s) { print(String.valueOf(s)); } public synchronized void println(String s) { try { out.write(s.getBytes()); out.write(Static.newline); if (autoFlush) flush(); } catch (IOException e) { } } public synchronized void println() { try { out.write(Static.newline); if (autoFlush) flush(); } catch (IOException e) { } } public void println(Object o) { println(String.valueOf(o)); } public void println(boolean v) { println(String.valueOf(v)); } public void println(char c) { println(String.valueOf(c)); } public void println(int v) { println(String.valueOf(v)); } public void println(long v) { println(String.valueOf(v)); } public void println(float v) { println(String.valueOf(v)); } public void println(double v) { println(String.valueOf(v)); } public void println(char[] s) { println(String.valueOf(s)); } public void write(int c) throws IOException { out.write(c); if (autoFlush && c == '\n') flush(); } public void write(byte[] buffer, int offset, int length) throws IOException { out.write(buffer, offset, length); if (autoFlush) flush(); } public void flush() { try { out.flush(); } catch (IOException e) { } } public void close() { try { out.close(); } catch (IOException e) { } } } ReadyTalk-avian-1e1fff5/classpath/java/io/PrintWriter.java000066400000000000000000000036731231440243200236370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class PrintWriter extends Writer { private static final char[] newline = System.getProperty("line.separator").toCharArray(); private final Writer out; private final boolean autoFlush; public PrintWriter(Writer out, boolean autoFlush) { this.out = out; this.autoFlush = autoFlush; } public PrintWriter(Writer out) { this(out, false); } public PrintWriter(OutputStream out, boolean autoFlush) { this(new OutputStreamWriter(out), autoFlush); } public PrintWriter(OutputStream out) { this(out, false); } public synchronized void print(String s) { try { out.write(s.toCharArray()); } catch (IOException e) { } } public void print(Object o) { print(o.toString()); } public void print(char c) { print(String.valueOf(c)); } public synchronized void println(String s) { try { out.write(s.toCharArray()); out.write(newline); if (autoFlush) flush(); } catch (IOException e) { } } public synchronized void println() { try { out.write(newline); if (autoFlush) flush(); } catch (IOException e) { } } public void println(Object o) { println(o.toString()); } public void println(char c) { println(String.valueOf(c)); } public void write(char[] buffer, int offset, int length) throws IOException { out.write(buffer, offset, length); if (autoFlush) flush(); } public void flush() { try { out.flush(); } catch (IOException e) { } } public void close() { try { out.close(); } catch (IOException e) { } } } ReadyTalk-avian-1e1fff5/classpath/java/io/PushbackReader.java000066400000000000000000000033731231440243200242260ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class PushbackReader extends Reader { private final Reader in; private char savedChar; private boolean hasSavedChar; public PushbackReader(Reader in, int bufferSize) { if (bufferSize > 1) { throw new IllegalArgumentException(bufferSize + " > 1"); } this.in = in; this.hasSavedChar = false; } public PushbackReader(Reader in) { this(in, 1); } public int read(char[] b, int offset, int length) throws IOException { int count = 0; if (hasSavedChar && length > 0) { length--; b[offset++] = savedChar; hasSavedChar = false; count = 1; } if (length > 0) { int c = in.read(b, offset, length); if (c == -1) { if (count == 0) { count = -1; } } else { count += c; } } return count; } public void unread(char[] b, int offset, int length) throws IOException { if (length != 1) { throw new IOException("Can only push back 1 char, not " + length); } else if (hasSavedChar) { throw new IOException("Already have a saved char"); } else { hasSavedChar = true; savedChar = b[offset]; } } public void unread(char[] b) throws IOException { unread(b, 0, b.length); } public void unread(int c) throws IOException { unread(new char[] { (char) c }); } public void close() throws IOException { in.close(); } } ReadyTalk-avian-1e1fff5/classpath/java/io/RandomAccessFile.java000066400000000000000000000127701231440243200245060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; import java.lang.IllegalArgumentException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class RandomAccessFile { private long peer; private File file; private long position = 0; private long length; private boolean allowWrite; public RandomAccessFile(String name, String mode) throws FileNotFoundException { this(new File(name), mode); } public RandomAccessFile(File file, String mode) throws FileNotFoundException { if (file == null) throw new NullPointerException(); if (mode.equals("rw")) allowWrite = true; else if (! mode.equals("r")) throw new IllegalArgumentException(); this.file = file; open(); } private void open() throws FileNotFoundException { long[] result = new long[2]; open(file.getPath(), allowWrite, result); peer = result[0]; length = result[1]; } private static native void open(String name, boolean allowWrite, long[] result) throws FileNotFoundException; private void refresh() throws IOException { if (file.length() != length) { close(); open(); } } public long length() throws IOException { refresh(); return length; } public long getFilePointer() throws IOException { return position; } public void seek(long position) throws IOException { if (position < 0 || (!allowWrite && position > length())) throw new IOException(); this.position = position; } public int skipBytes(int count) throws IOException { if (position + count > length()) throw new IOException(); this.position = position + count; return count; } public int read(byte b[], int off, int len) throws IOException { if(b == null) throw new IllegalArgumentException(); if (peer == 0) throw new IOException(); if(len == 0) return 0; if (position + len > this.length) throw new EOFException(); if (off < 0 || off + len > b.length) throw new ArrayIndexOutOfBoundsException(); int bytesRead = readBytes(peer, position, b, off, len); position += bytesRead; return bytesRead; } public int read(byte b[]) throws IOException { if(b == null) throw new IllegalArgumentException(); if (peer == 0) throw new IOException(); if(b.length == 0) return 0; if (position + b.length > this.length) throw new EOFException(); int bytesRead = readBytes(peer, position, b, 0, b.length); position += bytesRead; return bytesRead; } public void readFully(byte b[], int off, int len) throws IOException { if(b == null) throw new IllegalArgumentException(); if (peer == 0) throw new IOException(); if(len == 0) return; if (position + len > this.length) throw new EOFException(); if (off < 0 || off + len > b.length) throw new ArrayIndexOutOfBoundsException(); int n = 0; do { int count = readBytes(peer, position, b, off + n, len - n); position += count; if (count == 0) throw new EOFException(); n += count; } while (n < len); } public void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); } private static native int readBytes(long peer, long position, byte[] buffer, int offset, int length); public void write(int b) throws IOException { int count = writeBytes(peer, position, new byte[] { (byte)b }, 0, 1); if (count > 0) position += count; } private static native int writeBytes(long peer, long position, byte[] buffer, int offset, int length); public void close() throws IOException { if (peer != 0) { close(peer); peer = 0; } } private static native void close(long peer); public FileChannel getChannel() { return new FileChannel() { public void close() { if (peer != 0) RandomAccessFile.close(peer); } public boolean isOpen() { return peer != 0; } public int read(ByteBuffer dst, long position) throws IOException { if (!dst.hasArray()) throw new IOException("Cannot handle " + dst.getClass()); // TODO: this needs to be synchronized on the Buffer, no? byte[] array = dst.array(); return readBytes(peer, position, array, dst.position(), dst.remaining()); } public int read(ByteBuffer dst) throws IOException { int count = read(dst, position); if (count > 0) position += count; return count; } public int write(ByteBuffer src, long position) throws IOException { if (!src.hasArray()) throw new IOException("Cannot handle " + src.getClass()); byte[] array = src.array(); return writeBytes(peer, position, array, src.position(), src.remaining()); } public int write(ByteBuffer src) throws IOException { int count = write(src, position); if (count > 0) position += count; return count; } public long position() throws IOException { return getFilePointer(); } public FileChannel position(long position) throws IOException { seek(position); return this; } public long size() throws IOException { return length(); } }; } } ReadyTalk-avian-1e1fff5/classpath/java/io/Reader.java000066400000000000000000000021521231440243200225370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public abstract class Reader implements Closeable { public int read() throws IOException { char[] buffer = new char[1]; int c = read(buffer); if (c <= 0) { return -1; } else { return (int) buffer[0]; } } public int read(char[] buffer) throws IOException { return read(buffer, 0, buffer.length); } public abstract int read(char[] buffer, int offset, int length) throws IOException; public boolean markSupported() { return false; } public void mark(int readAheadLimit) throws IOException { throw new IOException("mark not supported"); } public void reset() throws IOException { throw new IOException("reset not supported"); } public abstract void close() throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/io/Serializable.java000066400000000000000000000006231231440243200237440ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public interface Serializable { } ReadyTalk-avian-1e1fff5/classpath/java/io/StreamCorruptedException.java000066400000000000000000000010661231440243200263420ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class StreamCorruptedException extends IOException { public StreamCorruptedException(String message) { super(message); } public StreamCorruptedException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/io/StringReader.java000066400000000000000000000015731231440243200237340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class StringReader extends Reader { private final String in; private int position = 0; public StringReader(String in) { this.in = in; } public int read(char[] b, int offset, int length) throws IOException { if (length > in.length() - position) { length = in.length() - position; if (length <= 0) { return -1; } } in.getChars(position, position+length, b, offset); position += length; return length; } public void close() throws IOException { } } ReadyTalk-avian-1e1fff5/classpath/java/io/StringWriter.java000066400000000000000000000013451231440243200240030ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class StringWriter extends Writer { private final StringBuilder out = new StringBuilder(); public void write(char[] b, int offset, int length) throws IOException { out.append(b, offset, length); } public String toString() { return out.toString(); } public void flush() throws IOException { } public void close() throws IOException { } } ReadyTalk-avian-1e1fff5/classpath/java/io/UnsupportedEncodingException.java000066400000000000000000000011021231440243200272050ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public class UnsupportedEncodingException extends IOException { public UnsupportedEncodingException(String message) { super(message); } public UnsupportedEncodingException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/io/Writer.java000066400000000000000000000021171231440243200226120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.io; public abstract class Writer implements Closeable, Flushable { public void write(int c) throws IOException { char[] buffer = new char[] { (char) c }; write(buffer); } public void write(char[] buffer) throws IOException { write(buffer, 0, buffer.length); } public void write(String s) throws IOException { write(s.toCharArray()); } public void write(String s, int offset, int length) throws IOException { char[] b = new char[length]; s.getChars(offset, offset + length, b, 0); write(b); } public abstract void write(char[] buffer, int offset, int length) throws IOException; public abstract void flush() throws IOException; public abstract void close() throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/lang/000077500000000000000000000000001231440243200210045ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/lang/AbstractMethodError.java000066400000000000000000000010671231440243200255710ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class AbstractMethodError extends IncompatibleClassChangeError { public AbstractMethodError() { super(); } public AbstractMethodError(String message) { super(message); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Appendable.java000066400000000000000000000012151231440243200237010ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.io.IOException; public interface Appendable { public Appendable append(char c) throws IOException; public Appendable append(CharSequence sequence) throws IOException; public Appendable append(CharSequence sequence, int start, int end) throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/lang/ArithmeticException.java000066400000000000000000000010561231440243200256210ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class ArithmeticException extends RuntimeException { public ArithmeticException(String message) { super(message); } public ArithmeticException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ArrayIndexOutOfBoundsException.java000066400000000000000000000014451231440243200277300ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException { public ArrayIndexOutOfBoundsException(String message, Throwable cause) { super(message, cause); } public ArrayIndexOutOfBoundsException(String message) { this(message, null); } public ArrayIndexOutOfBoundsException(Throwable cause) { this(null, cause); } public ArrayIndexOutOfBoundsException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ArrayStoreException.java000066400000000000000000000010641231440243200256220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class ArrayStoreException extends RuntimeException { public ArrayStoreException(String message) { super(message, null); } public ArrayStoreException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/AssertionError.java000066400000000000000000000020671231440243200246350ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class AssertionError extends Error { public AssertionError() { super("", null); } public AssertionError(boolean detailMessage) { super(""+detailMessage, null); } public AssertionError(char detailMessage) { super(""+detailMessage, null); } public AssertionError(double detailMessage) { super(""+detailMessage, null); } public AssertionError(float detailMessage) { super(""+detailMessage, null); } public AssertionError(int detailMessage) { super(""+detailMessage, null); } public AssertionError(long detailMessage) { super(""+detailMessage, null); } public AssertionError(Object detailMessage) { super(""+detailMessage, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/AutoCloseable.java000066400000000000000000000006671231440243200244020ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public interface AutoCloseable { void close() throws Exception; } ReadyTalk-avian-1e1fff5/classpath/java/lang/Boolean.java000066400000000000000000000033031231440243200232250ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public final class Boolean implements Comparable { public static final Class TYPE = avian.Classes.forCanonicalName("Z"); public static final Boolean FALSE = new Boolean(false); public static final Boolean TRUE = new Boolean(true); private final boolean value; public Boolean(boolean value) { this.value = value; } public Boolean(String s) { this.value = "true".equals(s); } public static Boolean valueOf(boolean value) { return (value ? Boolean.TRUE : Boolean.FALSE); } public static Boolean valueOf(String s) { Boolean.TRUE.booleanValue(); return ("true".equals(s) ? Boolean.TRUE : Boolean.FALSE); } public int compareTo(Boolean o) { return (value ? (o.value ? 0 : 1) : (o.value ? -1 : 0)); } public boolean equals(Object o) { return o instanceof Boolean && ((Boolean) o).value == value; } public int hashCode() { return (value ? 1 : 0); } public String toString() { return toString(value); } public static String toString(boolean v) { return (v ? "true" : "false"); } public boolean booleanValue() { return value; } public static boolean getBoolean(String name) { return parseBoolean(System.getProperty(name)); } public static boolean parseBoolean(String string) { return string != null && string.equalsIgnoreCase("true"); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Byte.java000066400000000000000000000030021231440243200225450ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public final class Byte extends Number implements Comparable { public static final Class TYPE = avian.Classes.forCanonicalName("B"); private final byte value; public Byte(byte value) { this.value = value; } public static Byte valueOf(byte value) { return new Byte(value); } public boolean equals(Object o) { return o instanceof Byte && ((Byte) o).value == value; } public int hashCode() { return value; } public String toString() { return toString(value); } public int compareTo(Byte o) { return value - o.value; } public static String toString(byte v, int radix) { return Long.toString(v, radix); } public static String toString(byte v) { return toString(v, 10); } public static byte parseByte(String s) { return (byte) Integer.parseInt(s); } public byte byteValue() { return value; } public short shortValue() { return value; } public int intValue() { return value; } public long longValue() { return value; } public float floatValue() { return (float) value; } public double doubleValue() { return (double) value; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/CharSequence.java000066400000000000000000000010461231440243200242160ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public interface CharSequence { public char charAt(int index); int length(); CharSequence subSequence(int start, int end); String toString(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/Character.java000066400000000000000000000133771231440243200235560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public final class Character implements Comparable { public static final int MIN_RADIX = 2; public static final int MAX_RADIX = 36; public static final Class TYPE = avian.Classes.forCanonicalName("C"); private final char value; public Character(char value) { this.value = value; } public static Character valueOf(char value) { return new Character(value); } public int compareTo(Character o) { return value - o.value; } public boolean equals(Object o) { return o instanceof Character && ((Character) o).value == value; } public int hashCode() { return (int) value; } public String toString() { return toString(value); } public static String toString(char v) { return new String(new char[] { v }); } public char charValue() { return value; } public static char toLowerCase(char c) { if (c >= 'A' && c <= 'Z') { return (char) ((c - 'A') + 'a'); } else { return c; } } public static int toLowerCase(int codePoint) { if (isSupplementaryCodePoint(codePoint)) { return codePoint; } else { return toLowerCase((char) codePoint); } } public static char toUpperCase(char c) { if (c >= 'a' && c <= 'z') { return (char) ((c - 'a') + 'A'); } else { return c; } } public static int toUpperCase(int codePoint) { if (isSupplementaryCodePoint(codePoint)) { return codePoint; } else { return toUpperCase((char) codePoint); } } public static boolean isDigit(char c) { return c >= '0' && c <= '9'; } public static boolean isDigit(int c) { return c >= '0' && c <= '9'; } public static int digit(char c, int radix) { int digit = 0; if ((c >= '0') && (c <= '9')) { digit = c - '0'; } else if ((c >= 'a') && (c <= 'z')) { digit = c - 'a' + 10; } else if ((c >= 'A') && (c <= 'Z')) { digit = c - 'A' + 10; } else { return -1; } if (digit < radix) { return digit; } else { return -1; } } public static char forDigit(int digit, int radix) { if (MIN_RADIX <= radix && radix <= MAX_RADIX) { if (0 <= digit && digit < radix) { return (char) (digit < 10 ? digit + '0' : digit + 'a' - 10); } } return 0; } public static boolean isLetter(int c) { return canCastToChar(c) && isLetter((char) c); } public static boolean isLetter(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } public static boolean isLetterOrDigit(char c) { return isDigit(c) || isLetter(c); } public static boolean isLetterOrDigit(int c) { return canCastToChar(c) && (isDigit((char) c) || isLetter((char) c)); } public static boolean isLowerCase(int c) { return canCastToChar(c) && isLowerCase((char) c); } public static boolean isLowerCase(char c) { return (c >= 'a' && c <= 'z'); } public static boolean isUpperCase(char c) { return (c >= 'A' && c <= 'Z'); } public static boolean isUpperCase(int c) { return canCastToChar(c) && isUpperCase((char) c); } public static boolean isWhitespace(int c) { return canCastToChar(c) && isWhitespace((char) c); } public static boolean isWhitespace(char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r'; } public static boolean isSpaceChar(char c) { return isWhitespace(c); } public static boolean isHighSurrogate(char ch) { return ch >= '\uD800' && ch <= '\uDBFF'; } public static boolean isLowSurrogate(char ch) { return ch >= '\uDC00' && ch <= '\uDFFF'; } public static boolean isISOControl(char ch) { return ch <= '\u001F' || (ch >= '\u007F' && ch <= '\u009F'); } public static int toCodePoint(char high, char low) { return (((high & 0x3FF) << 10) | (low & 0x3FF)) + 0x10000; } public static boolean isSupplementaryCodePoint(int codePoint) { return codePoint >= 0x10000 && codePoint <= 0x10FFFF; } private static boolean canCastToChar(int codePoint) { return (codePoint >= 0 && codePoint <= 0xFFFF); } public static char[] toChars(int codePoint) { if (isSupplementaryCodePoint(codePoint)) { int cpPrime = codePoint - 0x10000; int high = 0xD800 | ((cpPrime >> 10) & 0x3FF); int low = 0xDC00 | (cpPrime & 0x3FF); return new char[] { (char) high, (char) low }; } return new char[] { (char) codePoint }; } public static boolean isSurrogatePair(char high, char low) { return isHighSurrogate(high) && isLowSurrogate(low); } public static int codePointAt(CharSequence sequence, int offset) { int length = sequence.length(); if (offset < 0 || offset >= length) { throw new IndexOutOfBoundsException(); } char high = sequence.charAt(offset); if (! isHighSurrogate(high) || offset >= length) { return high; } char low = sequence.charAt(offset + 1); if (! isLowSurrogate(low)) { return high; } return toCodePoint(high, low); } public static int codePointCount(CharSequence sequence, int start, int end) { int length = sequence.length(); if (start < 0 || start > end || end >= length) { throw new IndexOutOfBoundsException(); } int count = 0; for (int i = start; i < end; ++i) { if (isHighSurrogate(sequence.charAt(i)) && (i + 1) < end && isLowSurrogate(sequence.charAt(i + 1))) { ++ i; } ++ count; } return count; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Class.java000066400000000000000000000436721231440243200227300ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import avian.VMClass; import avian.ClassAddendum; import avian.AnnotationInvocationHandler; import avian.SystemClassLoader; import avian.Classes; import avian.InnerClassReference; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.AnnotatedElement; import java.lang.annotation.Annotation; import java.io.InputStream; import java.io.IOException; import java.net.URL; import java.util.Arrays; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.security.ProtectionDomain; import java.security.Permissions; import java.security.AllPermission; public final class Class implements Type, AnnotatedElement { private static final int PrimitiveFlag = 1 << 5; private static final int EnumFlag = 1 << 14; public final VMClass vmClass; public Class(VMClass vmClass) { this.vmClass = vmClass; } public String toString() { return getName(); } private static byte[] replace(int a, int b, byte[] s, int offset, int length) { byte[] array = new byte[length]; for (int i = 0; i < length; ++i) { byte c = s[i]; array[i] = (byte) (c == a ? b : c); } return array; } public String getName() { return getName(vmClass); } public static String getName(VMClass c) { if (c.name == null) { if ((c.vmFlags & PrimitiveFlag) != 0) { if (c == Classes.primitiveClass('V')) { c.name = "void\0".getBytes(); } else if (c == Classes.primitiveClass('Z')) { c.name = "boolean\0".getBytes(); } else if (c == Classes.primitiveClass('B')) { c.name = "byte\0".getBytes(); } else if (c == Classes.primitiveClass('C')) { c.name = "char\0".getBytes(); } else if (c == Classes.primitiveClass('S')) { c.name = "short\0".getBytes(); } else if (c == Classes.primitiveClass('I')) { c.name = "int\0".getBytes(); } else if (c == Classes.primitiveClass('F')) { c.name = "float\0".getBytes(); } else if (c == Classes.primitiveClass('J')) { c.name = "long\0".getBytes(); } else if (c == Classes.primitiveClass('D')) { c.name = "double\0".getBytes(); } else { throw new AssertionError(); } } else { throw new AssertionError(); } } return new String (replace('/', '.', c.name, 0, c.name.length - 1), 0, c.name.length - 1, false); } public String getCanonicalName() { if ((vmClass.vmFlags & PrimitiveFlag) != 0) { return getName(); } else if (isArray()) { return getComponentType().getCanonicalName() + "[]"; } else { return getName().replace('$', '.'); } } public String getSimpleName() { if ((vmClass.vmFlags & PrimitiveFlag) != 0) { return getName(); } else if (isArray()) { return getComponentType().getSimpleName() + "[]"; } else { String name = getCanonicalName(); int index = name.lastIndexOf('.'); if (index >= 0) { return name.substring(index + 1); } else { return name; } } } public T newInstance() throws IllegalAccessException, InstantiationException { try { return (T) getConstructor().newInstance(); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } public static Class forName(String name) throws ClassNotFoundException { return forName(name, true, Method.getCaller().class_.loader); } public static Class forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException { return Classes.forName(name, initialize, loader); } public Class getComponentType() { if (isArray()) { String n = getName(); if ("[Z".equals(n)) { return SystemClassLoader.getClass(Classes.primitiveClass('Z')); } else if ("[B".equals(n)) { return SystemClassLoader.getClass(Classes.primitiveClass('B')); } else if ("[S".equals(n)) { return SystemClassLoader.getClass(Classes.primitiveClass('S')); } else if ("[C".equals(n)) { return SystemClassLoader.getClass(Classes.primitiveClass('C')); } else if ("[I".equals(n)) { return SystemClassLoader.getClass(Classes.primitiveClass('I')); } else if ("[F".equals(n)) { return SystemClassLoader.getClass(Classes.primitiveClass('F')); } else if ("[J".equals(n)) { return SystemClassLoader.getClass(Classes.primitiveClass('J')); } else if ("[D".equals(n)) { return SystemClassLoader.getClass(Classes.primitiveClass('D')); } if (vmClass.staticTable == null) throw new AssertionError(); return SystemClassLoader.getClass((VMClass) vmClass.staticTable); } else { return null; } } public boolean isAssignableFrom(Class c) { return Classes.isAssignableFrom(vmClass, c.vmClass); } public Field getDeclaredField(String name) throws NoSuchFieldException { int index = Classes.findField(vmClass, name); if (index < 0) { throw new NoSuchFieldException(name); } else { return new Field(vmClass.fieldTable[index]); } } public Field getField(String name) throws NoSuchFieldException { for (VMClass c = vmClass; c != null; c = c.super_) { int index = Classes.findField(c, name); if (index >= 0) { return new Field(vmClass.fieldTable[index]); } } throw new NoSuchFieldException(name); } public Method getDeclaredMethod(String name, Class ... parameterTypes) throws NoSuchMethodException { if (name.startsWith("<")) { throw new NoSuchMethodException(name); } int index = Classes.findMethod(vmClass, name, parameterTypes); if (index < 0) { throw new NoSuchMethodException(name); } else { return new Method(vmClass.methodTable[index]); } } public Method getMethod(String name, Class ... parameterTypes) throws NoSuchMethodException { if (name.startsWith("<")) { throw new NoSuchMethodException(name); } for (VMClass c = vmClass; c != null; c = c.super_) { int index = Classes.findMethod(c, name, parameterTypes); if (index >= 0) { return new Method(c.methodTable[index]); } } throw new NoSuchMethodException(name); } public Constructor getConstructor(Class ... parameterTypes) throws NoSuchMethodException { int index = Classes.findMethod(vmClass, "", parameterTypes); if (index < 0) { throw new NoSuchMethodException(); } else { return new Constructor(new Method(vmClass.methodTable[index])); } } public Constructor getDeclaredConstructor(Class ... parameterTypes) throws NoSuchMethodException { Constructor c = null; Constructor[] constructors = getDeclaredConstructors(); for (int i = 0; i < constructors.length; ++i) { if (Classes.match(parameterTypes, constructors[i].getParameterTypes())) { c = constructors[i]; } } if (c == null) { throw new NoSuchMethodException(); } else { return c; } } private int countConstructors(boolean publicOnly) { int count = 0; if (vmClass.methodTable != null) { for (int i = 0; i < vmClass.methodTable.length; ++i) { if (((! publicOnly) || ((vmClass.methodTable[i].flags & Modifier.PUBLIC)) != 0) && Method.getName(vmClass.methodTable[i]).equals("")) { ++ count; } } } return count; } public Constructor[] getDeclaredConstructors() { Constructor[] array = new Constructor[countConstructors(false)]; if (vmClass.methodTable != null) { Classes.link(vmClass); int index = 0; for (int i = 0; i < vmClass.methodTable.length; ++i) { if (Method.getName(vmClass.methodTable[i]).equals("")) { array[index++] = new Constructor(new Method(vmClass.methodTable[i])); } } } return array; } public Constructor[] getConstructors() { Constructor[] array = new Constructor[countConstructors(true)]; if (vmClass.methodTable != null) { Classes.link(vmClass); int index = 0; for (int i = 0; i < vmClass.methodTable.length; ++i) { if (((vmClass.methodTable[i].flags & Modifier.PUBLIC) != 0) && Method.getName(vmClass.methodTable[i]).equals("")) { array[index++] = new Constructor(new Method(vmClass.methodTable[i])); } } } return array; } public Field[] getDeclaredFields() { if (vmClass.fieldTable != null) { Field[] array = new Field[vmClass.fieldTable.length]; for (int i = 0; i < vmClass.fieldTable.length; ++i) { array[i] = new Field(vmClass.fieldTable[i]); } return array; } else { return new Field[0]; } } private int countPublicFields() { int count = 0; if (vmClass.fieldTable != null) { for (int i = 0; i < vmClass.fieldTable.length; ++i) { if (((vmClass.fieldTable[i].flags & Modifier.PUBLIC)) != 0) { ++ count; } } } return count; } public Field[] getFields() { Field[] array = new Field[countPublicFields()]; if (vmClass.fieldTable != null) { Classes.link(vmClass); int ai = 0; for (int i = 0; i < vmClass.fieldTable.length; ++i) { if (((vmClass.fieldTable[i].flags & Modifier.PUBLIC)) != 0) { array[ai++] = new Field(vmClass.fieldTable[i]); } } } return array; } private static void getAllFields(VMClass vmClass, ArrayList fields) { if (vmClass.super_ != null) { getAllFields(vmClass.super_, fields); } if (vmClass.fieldTable != null) { Classes.link(vmClass); for (int i = 0; i < vmClass.fieldTable.length; ++i) { fields.add(new Field(vmClass.fieldTable[i])); } } } public Field[] getAllFields() { ArrayList fields = new ArrayList(); getAllFields(vmClass, fields); return fields.toArray(new Field[fields.size()]); } public Method[] getDeclaredMethods() { return Classes.getMethods(vmClass, false); } public Method[] getMethods() { return Classes.getMethods(vmClass, true); } public Class[] getInterfaces() { if (vmClass.interfaceTable != null) { Classes.link(vmClass); int stride = (isInterface() ? 1 : 2); Class[] array = new Class[vmClass.interfaceTable.length / stride]; for (int i = 0; i < array.length; ++i) { array[i] = SystemClassLoader.getClass ((VMClass) vmClass.interfaceTable[i * stride]); } return array; } else { return new Class[0]; } } public T[] getEnumConstants() { if (Enum.class.isAssignableFrom(this)) { try { return (T[]) getMethod("values").invoke(null); } catch (Exception e) { throw new Error(); } } else { return null; } } public Class[] getDeclaredClasses() { ClassAddendum addendum = vmClass.addendum; if (addendum != null) { InnerClassReference[] table = addendum.innerClassTable; if (table != null) { int count = 0; for (int i = 0; i < table.length; ++i) { InnerClassReference reference = table[i]; if (reference.outer != null && Arrays.equals(vmClass.name, reference.outer)) { ++ count; } } Class[] result = new Class[count]; for (int i = 0; i < table.length; ++i) { InnerClassReference reference = table[i]; if (reference.outer != null && Arrays.equals(vmClass.name, reference.outer)) { try { result[--count] = getClassLoader().loadClass (new String(reference.inner, 0, reference.inner.length - 1)); } catch (ClassNotFoundException e) { throw new Error(e); } } } return result; } } return new Class[0]; } public Class getDeclaringClass() { ClassAddendum addendum = vmClass.addendum; if (addendum != null) { InnerClassReference[] table = addendum.innerClassTable; if (table != null) { for (int i = 0; i < table.length; ++i) { InnerClassReference reference = table[i]; if (Arrays.equals(vmClass.name, reference.inner)) { if (reference.outer != null) { try { return getClassLoader().loadClass (new String(reference.outer, 0, reference.outer.length - 1)); } catch (ClassNotFoundException e) { throw new Error(e); } } else { return null; } } } } } return null; } public ClassLoader getClassLoader() { return vmClass.loader; } public int getModifiers() { ClassAddendum addendum = vmClass.addendum; if (addendum != null) { InnerClassReference[] table = addendum.innerClassTable; if (table != null) { for (int i = 0; i < table.length; ++i) { InnerClassReference reference = table[i]; if (Arrays.equals(vmClass.name, reference.inner)) { return reference.flags; } } } } return vmClass.flags; } public boolean isInterface() { return (vmClass.flags & Modifier.INTERFACE) != 0; } public Class getSuperclass() { return (vmClass.super_ == null ? null : SystemClassLoader.getClass(vmClass.super_)); } public boolean isArray() { return vmClass.arrayDimensions != 0; } public static boolean isInstance(VMClass c, Object o) { return o != null && Classes.isAssignableFrom (c, Classes.getVMClass(o)); } public boolean isInstance(Object o) { return isInstance(vmClass, o); } public boolean isPrimitive() { return (vmClass.vmFlags & PrimitiveFlag) != 0; } public boolean isEnum() { return getSuperclass() == Enum.class && (vmClass.flags & EnumFlag) != 0; } public URL getResource(String path) { if (! path.startsWith("/")) { String name = new String (vmClass.name, 0, vmClass.name.length - 1, false); int index = name.lastIndexOf('/'); if (index >= 0) { path = name.substring(0, index) + "/" + path; } } return getClassLoader().getResource(path); } public InputStream getResourceAsStream(String path) { URL url = getResource(path); try { return (url == null ? null : url.openStream()); } catch (IOException e) { return null; } } public boolean desiredAssertionStatus() { return false; } public Class asSubclass(Class c) { if (! c.isAssignableFrom(this)) { throw new ClassCastException(); } return (Class) this; } public T cast(Object o) { return (T) o; } public Package getPackage() { if ((vmClass.vmFlags & PrimitiveFlag) != 0 || isArray()) { return null; } else { String name = getCanonicalName(); int index = name.lastIndexOf('.'); if (index >= 0) { return getClassLoader().getPackage(name.substring(0, index)); } else { return null; } } } public boolean isAnnotationPresent (Class class_) { return getAnnotation(class_) != null; } private static Annotation getAnnotation(VMClass c, Object[] a) { if (a[0] == null) { a[0] = Proxy.newProxyInstance (c.loader, new Class[] { (Class) a[1] }, new AnnotationInvocationHandler(a)); } return (Annotation) a[0]; } public T getAnnotation(Class class_) { for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { Classes.link(c, c.loader); Object[] table = (Object[]) c.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { return (T) getAnnotation(c, a); } } } } return null; } public Annotation[] getDeclaredAnnotations() { if (vmClass.addendum.annotationTable != null) { Classes.link(vmClass); Object[] table = (Object[]) vmClass.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { array[i] = getAnnotation(vmClass, (Object[]) table[i]); } return array; } else { return new Annotation[0]; } } private int countAnnotations() { int count = 0; for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { count += ((Object[]) c.addendum.annotationTable).length; } } return count; } public Annotation[] getAnnotations() { Annotation[] array = new Annotation[countAnnotations()]; int i = 0; for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { Object[] table = (Object[]) c.addendum.annotationTable; for (int j = 0; j < table.length; ++j) { array[i++] = getAnnotation(vmClass, (Object[]) table[j]); } } } return array; } public ProtectionDomain getProtectionDomain() { return Classes.getProtectionDomain(vmClass); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ClassCastException.java000066400000000000000000000010501231440243200254020ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class ClassCastException extends RuntimeException { public ClassCastException(String message) { super(message); } public ClassCastException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ClassLoader.java000066400000000000000000000117521231440243200240510ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.io.InputStream; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.Map; import java.util.HashMap; public abstract class ClassLoader { private final ClassLoader parent; private Map packages; protected ClassLoader(ClassLoader parent) { if (parent == null) { this.parent = getSystemClassLoader(); } else { this.parent = parent; } } protected ClassLoader() { this(getSystemClassLoader()); } private Map packages() { if (packages == null) { packages = new HashMap(); } return packages; } protected Package getPackage(String name) { synchronized (this) { return packages().get(name); } } protected Package[] getPackages() { synchronized (this) { return packages().values().toArray(new Package[packages().size()]); } } protected Package definePackage(String name, String specificationTitle, String specificationVersion, String specificationVendor, String implementationTitle, String implementationVersion, String implementationVendor, URL sealBase) { Package p = new Package (name, implementationTitle, implementationVersion, implementationVendor, specificationTitle, specificationVersion, specificationVendor, sealBase, this); synchronized (this) { packages().put(name, p); return p; } } public static ClassLoader getSystemClassLoader() { return ClassLoader.class.getClassLoader(); } protected Class defineClass(String name, byte[] b, int offset, int length) { if (b == null) { throw new NullPointerException(); } if (offset < 0 || offset > length || offset + length > b.length) { throw new IndexOutOfBoundsException(); } return avian.SystemClassLoader.getClass (avian.Classes.defineVMClass(this, b, offset, length)); } protected Class findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(); } protected Class reallyFindLoadedClass(String name) { return null; } protected final Class findLoadedClass(String name) { return reallyFindLoadedClass(name); } public Class loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class c = findLoadedClass(name); if (c == null) { if (parent != null) { try { c = parent.loadClass(name); } catch (ClassNotFoundException ok) { } } if (c == null) { c = findClass(name); } } if (resolve) { resolveClass(c); } return c; } protected void resolveClass(Class c) { avian.Classes.link(c.vmClass, this); } public final ClassLoader getParent() { return parent; } protected URL findResource(String path) { return null; } protected Enumeration findResources(String name) throws IOException { return Collections.enumeration(new ArrayList(0)); } public URL getResource(String path) { URL url = null; if (parent != null) { url = parent.getResource(path); } if (url == null) { url = findResource(path); } return url; } public InputStream getResourceAsStream(String path) { URL url = getResource(path); try { return (url == null ? null : url.openStream()); } catch (IOException e) { return null; } } public static URL getSystemResource(String path) { return getSystemClassLoader().getResource(path); } public static InputStream getSystemResourceAsStream(String path) { return getSystemClassLoader().getResourceAsStream(path); } public static Enumeration getSystemResources(String name) throws IOException { return getSystemClassLoader().getResources(name); } public Enumeration getResources(String name) throws IOException { Collection resources = collectResources(name); return Collections.enumeration(resources); } private Collection collectResources(String name) { Collection urls = parent != null ? parent.collectResources(name) : new ArrayList(5); URL url = findResource(name); if (url != null) { urls.add(url); } return urls; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ClassNotFoundException.java000066400000000000000000000013251231440243200262510ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class ClassNotFoundException extends Exception { private final Throwable cause2; public ClassNotFoundException(String message, Throwable cause) { super(message, cause); cause2 = cause; } public ClassNotFoundException(String message) { this(message, null); } public ClassNotFoundException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/CloneNotSupportedException.java000066400000000000000000000010711231440243200271540ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class CloneNotSupportedException extends Exception { public CloneNotSupportedException(String message) { super(message); } public CloneNotSupportedException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Cloneable.java000066400000000000000000000006221231440243200235330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public interface Cloneable { } ReadyTalk-avian-1e1fff5/classpath/java/lang/Comparable.java000066400000000000000000000006631231440243200237210ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public interface Comparable { public int compareTo(T o); } ReadyTalk-avian-1e1fff5/classpath/java/lang/Deprecated.java000066400000000000000000000010151231440243200237040ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface Deprecated { } ReadyTalk-avian-1e1fff5/classpath/java/lang/Double.java000066400000000000000000000053031231440243200230620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public final class Double extends Number { public static final Class TYPE = avian.Classes.forCanonicalName("D"); public static final double NEGATIVE_INFINITY = -1.0 / 0.0; public static final double POSITIVE_INFINITY = 1.0 / 0.0; public static final double NaN = 0.0 / 0.0; private final double value; public Double(String value) { this.value = parseDouble(value); } public Double(double value) { this.value = value; } public static Double valueOf(double value) { return new Double(value); } public static Double valueOf(String s) { return new Double(s); } public boolean equals(Object o) { return o instanceof Double && ((Double) o).value == value; } public int hashCode() { long v = doubleToRawLongBits(value); return (int) ((v >> 32) ^ (v & 0xFF)); } public String toString() { return toString(value); } public static String toString(double v) { byte[] buffer = new byte[20]; int numChars = fillBufferWithDouble(v, buffer, 20); return new String(buffer, 0, numChars, false); } public byte byteValue() { return (byte) value; } public short shortValue() { return (short) value; } public int intValue() { return (int) value; } public long longValue() { return (long) value; } public float floatValue() { return (float) value; } public double doubleValue() { return value; } public boolean isInfinite() { return isInfinite(value); } public boolean isNaN() { return isNaN(value); } public static double parseDouble(String s) { int[] numRead = new int[1]; double d = doubleFromString(s, numRead); if (numRead[0] == 1) { return d; } else { throw new NumberFormatException(s); } } public static long doubleToLongBits(double value) { if (isNaN(value)) return 0x7ff8000000000000L; return doubleToRawLongBits(value); } public static native int fillBufferWithDouble(double value, byte[] buffer, int charCount); public static native long doubleToRawLongBits(double value); public static native double longBitsToDouble(long bits); public static native boolean isInfinite(double value); public static native boolean isNaN(double value); public static native double doubleFromString(String s, int[] numRead); } ReadyTalk-avian-1e1fff5/classpath/java/lang/Enum.java000066400000000000000000000034531231440243200225600ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.lang.reflect.Method; public abstract class Enum> implements Comparable { private final String name; protected final int ordinal; public Enum(String name, int ordinal) { this.name = name; this.ordinal = ordinal; } public int compareTo(E other) { if (getDeclaringClass() != other.getDeclaringClass()) { throw new ClassCastException(); } return ordinal - other.ordinal; } public static > T valueOf(Class enumType, String name) { if (name == null) throw new NullPointerException("name"); if (!enumType.isEnum()) throw new IllegalArgumentException(enumType.getCanonicalName() + " is not an enum."); try { Method method = enumType.getMethod("values"); Enum values[] = (Enum[]) method.invoke(null); for (Enum value: values) { if (name.equals(value.name)) { return (T) value; } } } catch (Exception ex) { // Cannot happen throw new Error(ex); } throw new IllegalArgumentException(enumType.getCanonicalName() + "." + name + " is not an enum constant."); } public int ordinal() { return ordinal; } public final String name() { return name; } public String toString() { return name; } public Class getDeclaringClass() { Class c = getClass(); while (c.getSuperclass() != Enum.class) { c = c.getSuperclass(); } return c; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Error.java000066400000000000000000000012301231440243200227340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class Error extends Throwable { public Error(String message, Throwable cause) { super(message, cause); } public Error(String message) { this(message, null); } public Error(Throwable cause) { this(null, cause); } public Error() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Exception.java000066400000000000000000000012541231440243200236070ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class Exception extends Throwable { public Exception(String message, Throwable cause) { super(message, cause); } public Exception(String message) { this(message, null); } public Exception(Throwable cause) { this(null, cause); } public Exception() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ExceptionInInitializerError.java000066400000000000000000000011671231440243200273170ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class ExceptionInInitializerError extends Error { private final Throwable exception; public ExceptionInInitializerError(String message) { super(message); exception = null; } public ExceptionInInitializerError() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Float.java000066400000000000000000000052671231440243200227260ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public final class Float extends Number { public static final Class TYPE = avian.Classes.forCanonicalName("F"); private static final int EXP_BIT_MASK = 0x7F800000; private static final int SIGNIF_BIT_MASK = 0x007FFFFF; public static final float NEGATIVE_INFINITY = -1.0f / 0.0f; public static final float POSITIVE_INFINITY = 1.0f / 0.0f; public static final float NaN = 0.0f / 0.0f; private final float value; public Float(String value) { this.value = parseFloat(value); } public Float(float value) { this.value = value; } public static Float valueOf(float value) { return new Float(value); } public static Float valueOf(String s) { return new Float(s); } public boolean equals(Object o) { return o instanceof Float && ((Float) o).value == value; } public int hashCode() { return floatToRawIntBits(value); } public String toString() { return toString(value); } public static String toString(float v) { return Double.toString(v); } public byte byteValue() { return (byte) value; } public short shortValue() { return (short) value; } public int intValue() { return (int) value; } public long longValue() { return (long) value; } public float floatValue() { return value; } public double doubleValue() { return (double) value; } public boolean isInfinite() { return isInfinite(value); } public boolean isNaN() { return isNaN(value); } public static float parseFloat(String s) { int[] numRead = new int[1]; float f = floatFromString(s, numRead); if (numRead[0] == 1) { return f; } else { throw new NumberFormatException(s); } } public static int floatToIntBits(float value) { int result = floatToRawIntBits(value); // Check for NaN based on values of bit fields, maximum // exponent and nonzero significand. if (((result & EXP_BIT_MASK) == EXP_BIT_MASK) && (result & SIGNIF_BIT_MASK) != 0) { result = 0x7fc00000; } return result; } public static native int floatToRawIntBits(float value); public static native float intBitsToFloat(int bits); public static native boolean isInfinite(float value); public static native boolean isNaN(float value); public static native float floatFromString(String s, int[] numRead); } ReadyTalk-avian-1e1fff5/classpath/java/lang/IllegalAccessError.java000066400000000000000000000011741231440243200253570ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; /** * TODO : current Avian runtime doesn't check, need to be implemented. * */ public class IllegalAccessError extends IncompatibleClassChangeError { public IllegalAccessError(String message) { super(message); } public IllegalAccessError() { } } ReadyTalk-avian-1e1fff5/classpath/java/lang/IllegalAccessException.java000066400000000000000000000010551231440243200262220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class IllegalAccessException extends Exception { public IllegalAccessException(String message) { super(message); } public IllegalAccessException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/IllegalArgumentException.java000066400000000000000000000013761231440243200266110ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class IllegalArgumentException extends RuntimeException { public IllegalArgumentException(String message, Throwable cause) { super(message, cause); } public IllegalArgumentException(String message) { this(message, null); } public IllegalArgumentException(Throwable cause) { this(null, cause); } public IllegalArgumentException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/IllegalMonitorStateException.java000066400000000000000000000011171231440243200274500ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class IllegalMonitorStateException extends RuntimeException { public IllegalMonitorStateException(String message) { super(message, null); } public IllegalMonitorStateException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/IllegalStateException.java000066400000000000000000000013571231440243200261060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class IllegalStateException extends RuntimeException { public IllegalStateException(String message, Throwable cause) { super(message, cause); } public IllegalStateException(String message) { this(message, null); } public IllegalStateException(Throwable cause) { this(null, cause); } public IllegalStateException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/IllegalThreadStateException.java000066400000000000000000000014261231440243200272330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class IllegalThreadStateException extends IllegalArgumentException { public IllegalThreadStateException(String message, Throwable cause) { super(message, cause); } public IllegalThreadStateException(String message) { this(message, null); } public IllegalThreadStateException(Throwable cause) { this(null, cause); } public IllegalThreadStateException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/IncompatibleClassChangeError.java000066400000000000000000000011021231440243200273550ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class IncompatibleClassChangeError extends LinkageError { public IncompatibleClassChangeError(String message) { super(message); } public IncompatibleClassChangeError() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/IndexOutOfBoundsException.java000066400000000000000000000014031231440243200267230ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class IndexOutOfBoundsException extends RuntimeException { public IndexOutOfBoundsException(String message, Throwable cause) { super(message, cause); } public IndexOutOfBoundsException(String message) { this(message, null); } public IndexOutOfBoundsException(Throwable cause) { this(null, cause); } public IndexOutOfBoundsException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/InheritableThreadLocal.java000066400000000000000000000010221231440243200261730ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.util.Map; public class InheritableThreadLocal extends ThreadLocal { protected T childValue(T parentValue) { return parentValue; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/InstantiationError.java000066400000000000000000000011731231440243200255070ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; /** * TODO : current Avian runtime doesn't check, need to be implemented. * */ public class InstantiationError extends IncompatibleClassChangeError { public InstantiationError(String message) { super(message); } public InstantiationError() { } } ReadyTalk-avian-1e1fff5/classpath/java/lang/InstantiationException.java000066400000000000000000000010551231440243200263530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class InstantiationException extends Exception { public InstantiationException(String message) { super(message); } public InstantiationException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Integer.java000066400000000000000000000066531231440243200232560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public final class Integer extends Number implements Comparable { public static final Class TYPE = avian.Classes.forCanonicalName("I"); public static final int MIN_VALUE = 0x80000000; public static final int MAX_VALUE = 0x7FFFFFFF; private final int value; public Integer(int value) { this.value = value; } public Integer(String s) { this.value = parseInt(s); } public static Integer valueOf(int value) { return new Integer(value); } public static Integer valueOf(String value) { return valueOf(parseInt(value)); } public boolean equals(Object o) { return o instanceof Integer && ((Integer) o).value == value; } public int hashCode() { return value; } public int compareTo(Integer other) { return value - other.value; } public String toString() { return toString(value); } public static String toString(int v, int radix) { return Long.toString(v, radix); } public static String toString(int v) { return toString(v, 10); } public static String toHexString(int v) { return Long.toString(((long) v) & 0xFFFFFFFFL, 16); } public static String toOctalString(int v) { return Long.toString(((long) v) & 0xFFFFFFFFL, 8); } public static String toBinaryString(int v) { return Long.toString(((long) v) & 0xFFFFFFFFL, 2); } public byte byteValue() { return (byte) value; } public short shortValue() { return (short) value; } public int intValue() { return value; } public long longValue() { return value; } public float floatValue() { return (float) value; } public double doubleValue() { return (double) value; } public static int signum(int v) { if (v == 0) return 0; else if (v > 0) return 1; else return -1; } // See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel public static int bitCount(int v) { v = v - ((v >> 1) & 0x55555555); v = (v & 0x33333333) + ((v >> 2) & 0x33333333); return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; } public static int reverseBytes(int v) { int byte3 = v >>> 24; int byte2 = (v >>> 8) & 0xFF00; int byte1 = (v << 8) & 0xFF00; int byte0 = v << 24; return (byte0 | byte1 | byte2 | byte3); } public static int parseInt(String s) { return parseInt(s, 10); } public static int parseInt(String s, int radix) { return (int) Long.parseLong(s, radix); } public static Integer decode(String string) { if (string.startsWith("-")) { if (string.startsWith("-0") || string.startsWith("-#")) { return new Integer(-decode(string.substring(1))); } } else if (string.startsWith("0")) { char c = string.length() < 2 ? (char)-1 : string.charAt(1); if (c == 'x' || c == 'X') { return new Integer(parseInt(string.substring(2), 0x10)); } return new Integer(parseInt(string, 010)); } else if (string.startsWith("#")) { return new Integer(parseInt(string.substring(1), 0x10)); } return new Integer(parseInt(string, 10)); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/InterruptedException.java000066400000000000000000000013431231440243200260340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class InterruptedException extends Exception { public InterruptedException(String message, Throwable cause) { super(message, cause); } public InterruptedException(String message) { this(message, null); } public InterruptedException(Throwable cause) { this(null, cause); } public InterruptedException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Iterable.java000066400000000000000000000007211231440243200233760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.util.Iterator; public interface Iterable { public Iterator iterator(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/LinkageError.java000066400000000000000000000010241231440243200242300ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class LinkageError extends Error { public LinkageError(String message) { super(message, null); } public LinkageError() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Long.java000066400000000000000000000072301231440243200225500ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public final class Long extends Number implements Comparable { public static final long MIN_VALUE = -9223372036854775808l; public static final long MAX_VALUE = 9223372036854775807l; public static final Class TYPE = avian.Classes.forCanonicalName("J"); private final long value; public Long(long value) { this.value = value; } public Long(String s) { this.value = parseLong(s); } public static Long valueOf(String value) { return new Long(value); } public static Long valueOf(long value) { return new Long(value); } public int compareTo(Long o) { return value > o.value ? 1 : (value < o.value ? -1 : 0); } public boolean equals(Object o) { return o instanceof Long && ((Long) o).value == value; } public int hashCode() { return (int) ((value >> 32) ^ (value & 0xFF)); } public String toString() { return String.valueOf(value); } public static String toString(long v, int radix) { if (radix < 1 || radix > 36) { throw new IllegalArgumentException("radix " + radix + " not in [1,36]"); } if (v == 0) { return "0"; } boolean negative = v < 0; int size = (negative ? 1 : 0); for (long n = v; n != 0; n /= radix) ++size; char[] array = new char[size]; int i = size - 1; for (long n = v; n != 0; n /= radix) { long digit = n % radix; if (negative) digit = -digit; if (digit >= 0 && digit <= 9) { array[i] = (char) ('0' + digit); } else { array[i] = (char) ('a' + (digit - 10)); } --i; } if (negative) { array[i] = '-'; } return new String(array, 0, size, false); } public static String toString(long v) { return toString(v, 10); } public static String toHexString(long v) { return toString(v, 16); } public static String toOctalString(long v) { return toString(v, 8); } public static String toBinaryString(long v) { return toString(v, 2); } public byte byteValue() { return (byte) value; } public short shortValue() { return (short) value; } public int intValue() { return (int) value; } public long longValue() { return value; } public float floatValue() { return (float) value; } public double doubleValue() { return (double) value; } public static int signum(long v) { if (v == 0) return 0; else if (v > 0) return 1; else return -1; } private static long pow(long a, long b) { long c = 1; for (int i = 0; i < b; ++i) c *= a; return c; } public static long parseLong(String s) { return parseLong(s, 10); } public static long parseLong(String s, int radix) { int i = 0; long number = 0; boolean negative = s.startsWith("-"); int length = s.length(); if (negative) { i = 1; -- length; } long factor = pow(radix, length - 1); for (; i < s.length(); ++i) { char c = s.charAt(i); int digit = Character.digit(c, radix); if (digit >= 0) { number += digit * factor; factor /= radix; } else { throw new NumberFormatException("invalid character " + c + " code " + (int) c); } } if (negative) { number = -number; } return number; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Math.java000066400000000000000000000051071231440243200225430ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.util.Random; public final class Math { public static final double E = 2.718281828459045; public static final double PI = 3.141592653589793; private static final Random random = new Random(); private Math() { } public static double max(double a, double b) { return (a < b ? b : a); } public static double min(double a, double b) { return (a > b ? b : a); } public static float max(float a, float b) { return (a < b ? b : a); } public static float min(float a, float b) { return (a > b ? b : a); } public static long max(long a, long b) { return (a < b ? b : a); } public static long min(long a, long b) { return (a > b ? b : a); } public static int max(int a, int b) { return (a < b ? b : a); } public static int min(int a, int b) { return (a > b ? b : a); } public static int abs(int v) { return (v < 0 ? -v : v); } public static long abs(long v) { return (v < 0 ? -v : v); } public static float abs(float v) { return (v < 0 ? -v : v); } public static double abs(double v) { return (v < 0 ? -v : v); } public static long round(double v) { return (long) Math.floor(v + 0.5); } public static int round(float v) { return (int) Math.floor(v + 0.5); } public static double signum(double d) { return d > 0 ? +1.0 : d < 0 ? -1.0 : 0; } public static float signum(float f) { return f > 0 ? +1.0f : f < 0 ? -1.0f : 0; } public static double random() { return random.nextDouble(); } public static native double floor(double v); public static native double ceil(double v); public static native double exp(double v); public static native double log(double v); public static native double cos(double v); public static native double sin(double v); public static native double tan(double v); public static native double cosh(double v); public static native double sinh(double v); public static native double tanh(double v); public static native double acos(double v); public static native double asin(double v); public static native double atan(double v); public static native double sqrt(double v); public static native double pow(double v, double e); } ReadyTalk-avian-1e1fff5/classpath/java/lang/NegativeArraySizeException.java000066400000000000000000000011001231440243200271120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class NegativeArraySizeException extends RuntimeException { public NegativeArraySizeException(String message) { super(message); } public NegativeArraySizeException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/NoClassDefFoundError.java000066400000000000000000000010521231440243200256340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class NoClassDefFoundError extends LinkageError { public NoClassDefFoundError(String message) { super(message); } public NoClassDefFoundError() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/NoSuchFieldError.java000066400000000000000000000010561231440243200250260ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class NoSuchFieldError extends IncompatibleClassChangeError { public NoSuchFieldError(String message) { super(message); } public NoSuchFieldError() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/NoSuchFieldException.java000066400000000000000000000010471231440243200256730ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class NoSuchFieldException extends Exception { public NoSuchFieldException(String message) { super(message); } public NoSuchFieldException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/NoSuchMethodError.java000066400000000000000000000010611231440243200252170ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class NoSuchMethodError extends IncompatibleClassChangeError { public NoSuchMethodError(String message) { super(message); } public NoSuchMethodError() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/NoSuchMethodException.java000066400000000000000000000010521231440243200260640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class NoSuchMethodException extends Exception { public NoSuchMethodException(String message) { super(message); } public NoSuchMethodException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/NullPointerException.java000066400000000000000000000013521231440243200260020ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class NullPointerException extends RuntimeException { public NullPointerException(String message, Throwable cause) { super(message, cause); } public NullPointerException(String message) { this(message, null); } public NullPointerException(Throwable cause) { this(null, cause); } public NullPointerException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Number.java000066400000000000000000000012501231440243200230750ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.io.Serializable; public abstract class Number implements Serializable { public abstract byte byteValue(); public abstract short shortValue(); public abstract int intValue(); public abstract long longValue(); public abstract float floatValue(); public abstract double doubleValue(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/NumberFormatException.java000066400000000000000000000010711231440243200261260ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class NumberFormatException extends IllegalArgumentException { public NumberFormatException(String message) { super(message); } public NumberFormatException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Object.java000066400000000000000000000026721231440243200230640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class Object { protected Object clone() throws CloneNotSupportedException { if ((this instanceof Cloneable) || getClass().isArray()) { return clone(this); } else { throw new CloneNotSupportedException(getClass().getName()); } } private static native Object clone(Object o); public boolean equals(Object o) { return this == o; } protected void finalize() throws Throwable { } public final Class getClass() { return avian.SystemClassLoader.getClass(getVMClass(this)); } private static native avian.VMClass getVMClass(Object o); public native int hashCode(); public native final void notify(); public native final void notifyAll(); public native String toString(); public final void wait() throws InterruptedException { wait(0); } public native final void wait(long milliseconds) throws InterruptedException; public final void wait(long milliseconds, int nanoseconds) throws InterruptedException { if (nanoseconds != 0) { ++ milliseconds; } wait(milliseconds); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/OutOfMemoryError.java000066400000000000000000000010501231440243200251020ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class OutOfMemoryError extends VirtualMachineError { public OutOfMemoryError(String message) { super(message); } public OutOfMemoryError() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Override.java000066400000000000000000000006231231440243200234270ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public @interface Override { } ReadyTalk-avian-1e1fff5/classpath/java/lang/Package.java000066400000000000000000000042441231440243200232060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.net.URL; public class Package { private final String name; private final String implementationTitle; private final String implementationVendor; private final String implementationVersion; private final String specificationTitle; private final String specificationVendor; private final String specificationVersion; private final URL sealed; private final ClassLoader loader; Package(String name, String implementationTitle, String implementationVendor, String implementationVersion, String specificationTitle, String specificationVendor, String specificationVersion, URL sealed, ClassLoader loader) { this.name = name; this.implementationTitle = implementationTitle; this.implementationVendor = implementationVendor; this.implementationVersion = implementationVersion; this.specificationTitle = specificationTitle; this.specificationVendor = specificationVendor; this.specificationVersion = specificationVersion; this.sealed = sealed; this.loader = loader; } public String getName() { return name; } public String getImplementationTitle() { return implementationTitle; } public String getImplementationVendor() { return implementationVendor; } public String getImplementationVersion() { return implementationVersion; } public String getSpecificationTitle() { return specificationTitle; } public String getSpecificationVendor() { return specificationVendor; } public String getSpecificationVersion() { return specificationVersion; } public boolean isSealed() { return sealed != null; } public boolean isSealed(URL url) { return sealed.equals(url); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Process.java000066400000000000000000000013501231440243200232640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.io.InputStream; import java.io.OutputStream; public abstract class Process { public abstract void destroy(); public abstract int exitValue(); public abstract InputStream getInputStream(); public abstract OutputStream getOutputStream(); public abstract InputStream getErrorStream(); public abstract int waitFor() throws InterruptedException; } ReadyTalk-avian-1e1fff5/classpath/java/lang/ReflectiveOperationException.java000066400000000000000000000006631231440243200275040ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class ReflectiveOperationException extends Exception { } ReadyTalk-avian-1e1fff5/classpath/java/lang/Runnable.java000066400000000000000000000006461231440243200234230ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public interface Runnable { public void run(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/Runtime.java000066400000000000000000000107651231440243200233030ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.io.IOException; import java.io.InputStream; import java.io.FileInputStream; import java.io.OutputStream; import java.io.FileOutputStream; import java.io.FileDescriptor; import java.util.StringTokenizer; public class Runtime { private static final Runtime instance = new Runtime(); private Runtime() { } public static Runtime getRuntime() { return instance; } public void load(String path) { if (path != null) { load(path, false); } else { throw new NullPointerException(); } } public void loadLibrary(String path) { if (path != null) { load(path, true); } else { throw new NullPointerException(); } } public Process exec(String command) throws IOException { StringTokenizer t = new StringTokenizer(command); String[] cmd = new String[t.countTokens()]; for (int i = 0; i < cmd.length; i++) cmd[i] = t.nextToken(); return exec(cmd); } public Process exec(final String[] command) throws IOException { final MyProcess[] process = new MyProcess[1]; final Throwable[] exception = new Throwable[1]; synchronized (process) { Thread t = new Thread() { public void run() { synchronized (process) { try { long[] info = new long[5]; exec(command, info); process[0] = new MyProcess (info[0], info[1], (int) info[2], (int) info[3], (int) info[4]); } catch (Throwable e) { exception[0] = e; } finally { process.notifyAll(); } } MyProcess p = process[0]; if (p != null) { synchronized (p) { try { if (p.pid != 0) { p.exitCode = Runtime.waitFor(p.pid, p.tid); p.pid = 0; p.tid = 0; } } finally { p.notifyAll(); } } } } }; t.setDaemon(true); t.start(); while (process[0] == null && exception[0] == null) { try { process.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } } if (exception[0] != null) { if (exception[0] instanceof IOException) { String message = "Failed to run \"" + command[0] + "\": " + exception[0].getMessage(); throw new IOException(message); } else { throw new RuntimeException(exception[0]); } } return process[0]; } public native void addShutdownHook(Thread t); private static native void exec(String[] command, long[] process) throws IOException; private static native int waitFor(long pid, long tid); private static native void load(String name, boolean mapName); private static native void kill(long pid); public native void gc(); public native void exit(int code); public native long freeMemory(); public native long totalMemory(); private static class MyProcess extends Process { private long pid; private long tid; private final int in; private final int out; private final int err; private int exitCode; public MyProcess(long pid, long tid, int in, int out, int err) { this.pid = pid; this.tid = tid; this.in = in; this.out = out; this.err = err; } public void destroy() { if (pid != 0) { kill(pid); } } public InputStream getInputStream() { return new FileInputStream(new FileDescriptor(in)); } public OutputStream getOutputStream() { return new FileOutputStream(new FileDescriptor(out)); } public InputStream getErrorStream() { return new FileInputStream(new FileDescriptor(err)); } public synchronized int exitValue() { if (pid != 0) { throw new IllegalThreadStateException(); } return exitCode; } public synchronized int waitFor() throws InterruptedException { while (pid != 0) { wait(); } return exitCode; } } } ReadyTalk-avian-1e1fff5/classpath/java/lang/RuntimeException.java000066400000000000000000000013171231440243200251530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class RuntimeException extends Exception { public RuntimeException(String message, Throwable cause) { super(message, cause); } public RuntimeException(String message) { this(message, null); } public RuntimeException(Throwable cause) { this(null, cause); } public RuntimeException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/RuntimePermission.java000066400000000000000000000010261231440243200253420ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.security.BasicPermission; public class RuntimePermission extends BasicPermission { public RuntimePermission(String name) { super(name); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/SecurityException.java000066400000000000000000000013331231440243200253350ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class SecurityException extends RuntimeException { public SecurityException(String message, Throwable cause) { super(message, cause); } public SecurityException(String message) { this(message, null); } public SecurityException(Throwable cause) { this(null, cause); } public SecurityException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/SecurityManager.java000066400000000000000000000013741231440243200247560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.security.AccessController; import java.security.Permission; import java.security.SecurityPermission; public class SecurityManager { public SecurityManager() { } public void checkPermission(Permission perm) { AccessController.checkPermission(perm); } public void checkSecurityAccess(String target) { checkPermission(new SecurityPermission(target)); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Short.java000066400000000000000000000027561231440243200227600ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public final class Short extends Number implements Comparable { public static final Class TYPE = avian.Classes.forCanonicalName("S"); public static final short MAX_VALUE = 32767; private final short value; public Short(short value) { this.value = value; } public static Short valueOf(short value) { return new Short(value); } public int compareTo(Short o) { return value - o.value; } public boolean equals(Object o) { return o instanceof Short && ((Short) o).value == value; } public int hashCode() { return value; } public String toString() { return toString(value); } public static String toString(short v, int radix) { return Long.toString(v, radix); } public static String toString(short v) { return toString(v, 10); } public byte byteValue() { return (byte) value; } public short shortValue() { return value; } public int intValue() { return value; } public long longValue() { return value; } public float floatValue() { return (float) value; } public double doubleValue() { return (double) value; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/StackOverflowError.java000066400000000000000000000010561231440243200254540ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class StackOverflowError extends VirtualMachineError { public StackOverflowError(String message) { super(message); } public StackOverflowError() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/StackTraceElement.java000066400000000000000000000032531231440243200252100ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class StackTraceElement { private static int NativeLine = -1; private String class_; private String method; private String file; private int line; public StackTraceElement(String class_, String method, String file, int line) { this.class_ = class_; this.method = method; this.file = file; this.line = line; } public int hashCode() { return class_.hashCode() ^ method.hashCode() ^ line; } public boolean equals(Object o) { if (o instanceof StackTraceElement) { StackTraceElement e = (StackTraceElement) o; return class_.equals(e.class_) && method.equals(e.method) && line == e.line; } else { return false; } } public String toString() { StringBuilder sb = new StringBuilder(); sb.append(class_).append(".").append(method); if (line == NativeLine) { sb.append(" (native)"); } else if (line >= 0) { sb.append(" (line ").append(line).append(")"); } return sb.toString(); } public String getClassName() { return class_; } public String getMethodName() { return method; } public String getFileName() { return file; } public int getLineNumber() { return line; } public boolean isNativeMethod() { return line == NativeLine; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/String.java000066400000000000000000000410161231440243200231170ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.util.Comparator; import java.util.Locale; import java.util.regex.Pattern; import avian.Iso88591; import avian.Utf8; public final class String implements Comparable, CharSequence, Serializable { private static final String UTF_8_ENCODING = "UTF-8"; private static final String ISO_8859_1_ENCODING = "ISO-8859-1"; private static final String LATIN_1_ENCODING = "LATIN-1"; private static final String DEFAULT_ENCODING = UTF_8_ENCODING; public static Comparator CASE_INSENSITIVE_ORDER = new Comparator() { @Override public int compare(String a, String b) { return a.compareToIgnoreCase(b); } }; private final Object data; private final int offset; private final int length; private int hashCode; public String() { this(new char[0], 0, 0); } public String(char[] data, int offset, int length, boolean copy) { this((Object) data, offset, length, copy); } public String(char[] data, int offset, int length) { this(data, offset, length, true); } public String(char[] data) { this(data, 0, data.length); } public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException { this(bytes, offset, length); if (! (charsetName.equalsIgnoreCase(UTF_8_ENCODING) || charsetName.equalsIgnoreCase(ISO_8859_1_ENCODING))) { throw new UnsupportedEncodingException(charsetName); } } public String(byte[] data, int offset, int length, boolean copy) { this((Object) data, offset, length, copy); } public String(byte[] data, int offset, int length) { this(data, offset, length, true); } public String(byte[] data) { this(data, 0, data.length); } public String(String s) { this(s.toCharArray()); } public String(byte[] data, String charset) throws UnsupportedEncodingException { this(data, 0, data.length, charset); } public String(byte bytes[], int highByte, int offset, int length) { if (offset < 0 ) throw new StringIndexOutOfBoundsException(offset); else if (offset + length > bytes.length) throw new StringIndexOutOfBoundsException(offset + length); else if (length < 0) throw new StringIndexOutOfBoundsException(length); char[] c = new char[length]; int mask = highByte << 8; for (int i = 0; i < length; ++i) { c[i] = (char) ((bytes[offset + i] & 0xFF) | mask); } this.data = c; this.offset = 0; this.length = length; } private String(Object data, int offset, int length, boolean copy) { int l; if (data instanceof char[]) { l = ((char[]) data).length; } else { l = ((byte[]) data).length; } if (offset < 0 ) throw new StringIndexOutOfBoundsException(offset); else if (offset + length > l) throw new StringIndexOutOfBoundsException(offset + length); else if (length < 0) throw new StringIndexOutOfBoundsException(length); if(!copy && Utf8.test(data)) copy = true; if (copy) { Object c; if (data instanceof char[]) { c = new char[length]; System.arraycopy(data, offset, c, 0, length); } else { c = Utf8.decode((byte[])data, offset, length); if(c instanceof char[]) length = ((char[])c).length; if (c == null) { throw new RuntimeException ("unable to parse \"" + new String(data, offset, length, false) + "\""); } } this.data = c; this.offset = 0; this.length = length; } else { this.data = data; this.offset = offset; this.length = length; } } @Override public String toString() { return this; } @Override public int length() { return length; } @Override public int hashCode() { if (hashCode == 0) { int h = 0; for (int i = 0; i < length; ++i) h = (h * 31) + charAt(i); hashCode = h; } return hashCode; } @Override public boolean equals(Object o) { if (this == o) { return true; } else if (o instanceof String) { String s = (String) o; return s.length == length && compareTo(s) == 0; } else { return false; } } public boolean equalsIgnoreCase(String s) { if (this == s) { return true; } else { return s.length == length && compareToIgnoreCase(s) == 0; } } @Override public int compareTo(String s) { if (this == s) return 0; int idx = 0; int result; int end = (length < s.length ? length : s.length); while (idx < end) { if ((result = charAt(idx) - s.charAt(idx)) != 0) { return result; } idx++; } return length - s.length; } public int compareToIgnoreCase(String s) { if (this == s) return 0; int idx = 0; int result; int end = (length < s.length ? length : s.length); while (idx < end) { if ((result = Character.toLowerCase(charAt(idx)) - Character.toLowerCase(s.charAt(idx))) != 0) { return result; } idx++; } return length - s.length; } public String trim() { int start = -1; for (int i = 0; i < length; ++i) { char c = charAt(i); if (start == -1 && ! Character.isWhitespace(c)) { start = i; break; } } int end = -1; for (int i = length - 1; i >= 0; --i) { char c = charAt(i); if (end == -1 && ! Character.isWhitespace(c)) { end = i + 1; break; } } if (start >= end) { return ""; } else { return substring(start, end); } } public String toLowerCase() { for (int j = 0; j < length; ++j) { char ch = charAt(j); if (Character.toLowerCase(ch) != ch) { char[] b = new char[length]; for (int i = 0; i < length; ++i) { b[i] = Character.toLowerCase(charAt(i)); } return new String(b, 0, length, false); } } return this; } public String toUpperCase() { for (int j = 0; j < length; ++j) { char ch = charAt(j); if (Character.toUpperCase(ch) != ch) { char[] b = new char[length]; for (int i = 0; i < length; ++i) { b[i] = Character.toUpperCase(charAt(i)); } return new String(b, 0, length, false); } } return this; } public int indexOf(int c) { return indexOf(c, 0); } public int indexOf(int c, int start) { for (int i = start; i < length; ++i) { if (charAt(i) == c) { return i; } } return -1; } public int lastIndexOf(int ch) { return lastIndexOf(ch, length-1); } public int indexOf(String s) { return indexOf(s, 0); } public int indexOf(String s, int start) { if (s.length == 0) return start; for (int i = start; i < length - s.length + 1; ++i) { int j = 0; for (; j < s.length; ++j) { if (charAt(i + j) != s.charAt(j)) { break; } } if (j == s.length) { return i; } } return -1; } public int lastIndexOf(String s) { return lastIndexOf(s, length - s.length); } public int lastIndexOf(String s, int lastIndex) { if (s.length == 0) return lastIndex; for (int i = Math.min(length - s.length, lastIndex); i >= 0; --i) { int j = 0; for (; j < s.length && i + j < length; ++j) { if (charAt(i + j) != s.charAt(j)) { break; } } if (j == s.length) { return i; } } return -1; } public String replace(char oldChar, char newChar) { if (data instanceof char[]) { char[] buf = new char[length]; for (int i=0; i < length; i++) { if (charAt(i) == oldChar) { buf[i] = newChar; } else { buf[i] = charAt(i); } } return new String(buf, 0, length, false); } else { byte[] buf = new byte[length]; byte[] orig = (byte[])data; byte oldByte = (byte)oldChar; byte newByte = (byte)newChar; for (int i=0; i < length; i++) { if (orig[i+offset] == oldByte) { buf[i] = newByte; } else { buf[i] = orig[i+offset]; } } return new String(buf, 0, length, false); } } public String substring(int start) { return substring(start, length); } public String substring(int start, int end) { if (start < 0) throw new StringIndexOutOfBoundsException(start); else if (end > length) throw new StringIndexOutOfBoundsException(end); int newLen = end - start; if (newLen < 0) throw new StringIndexOutOfBoundsException(newLen); if (start == 0 && end == length) return this; else if (end - start == 0) return ""; else return new String(data, offset + start, newLen, false); } public boolean startsWith(String s) { if (length >= s.length) { return substring(0, s.length).compareTo(s) == 0; } else { return false; } } public boolean startsWith(String s, int start) { if (length >= s.length + start) { return substring(start, s.length).compareTo(s) == 0; } else { return false; } } public boolean endsWith(String s) { if (length >= s.length) { return substring(length - s.length).compareTo(s) == 0; } else { return false; } } public String concat(String s) { if (s.length() == 0) { return this; } else { return this + s; } } public void getBytes(int srcOffset, int srcLength, byte[] dst, int dstOffset) { if (srcOffset < 0) throw new StringIndexOutOfBoundsException(srcOffset); else if (srcOffset + srcLength > length) throw new StringIndexOutOfBoundsException(srcOffset + srcLength); else if (srcLength < 0) throw new StringIndexOutOfBoundsException(srcLength); if (data instanceof char[]) { char[] src = (char[]) data; for (int i = 0; i < srcLength; ++i) { dst[i + dstOffset] = (byte) src[i + offset + srcOffset]; } } else { byte[] src = (byte[]) data; System.arraycopy(src, offset + srcOffset, dst, dstOffset, srcLength); } } public byte[] getBytes() { try { return getBytes(DEFAULT_ENCODING); } catch (java.io.UnsupportedEncodingException ex) { throw new RuntimeException( "Default '" + DEFAULT_ENCODING + "' encoding not handled", ex); } } public byte[] getBytes(String format) throws java.io.UnsupportedEncodingException { if(data instanceof byte[]) { byte[] b = new byte[length]; getBytes(0, length, b, 0); return b; } String fmt = format.trim().toUpperCase(); if (DEFAULT_ENCODING.equals(fmt)) { return Utf8.encode((char[])data, offset, length); } else if (ISO_8859_1_ENCODING.equals(fmt) || LATIN_1_ENCODING.equals(fmt)) { return Iso88591.encode((char[])data, offset, length); } else { throw new java.io.UnsupportedEncodingException( "Encoding " + format + " not supported"); } } public void getChars(int srcOffset, int srcEnd, char[] dst, int dstOffset) { if (srcOffset < 0) throw new StringIndexOutOfBoundsException(srcOffset); else if (srcEnd > length) throw new StringIndexOutOfBoundsException(srcEnd); int srcLength = srcEnd-srcOffset; if (data instanceof char[]) { char[] src = (char[]) data; System.arraycopy(src, offset + srcOffset, dst, dstOffset, srcLength); } else { byte[] src = (byte[]) data; for (int i = 0; i < srcLength; ++i) { dst[i + dstOffset] = (char) src[i + offset + srcOffset]; } } } public char[] toCharArray() { char[] b = new char[length]; getChars(0, length, b, 0); return b; } @Override public char charAt(int index) { if (index < 0 || index > length) { throw new StringIndexOutOfBoundsException(index); } if (data instanceof char[]) { return ((char[]) data)[index + offset]; } else { return (char) ((byte[]) data)[index + offset]; } } public String[] split(String regex) { return split(regex, 0); } public String[] split(String regex, int limit) { return Pattern.compile(regex).split(this, limit); } @Override public CharSequence subSequence(int start, int end) { return substring(start, end); } public boolean matches(String regex) { return Pattern.matches(regex, this); } public String replaceFirst(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceFirst(replacement); } public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); } public String replace(CharSequence target, CharSequence replace) { if (target.length() == 0) { return this.infuse(replace.toString()); } String targetString = target.toString(); String replaceString = replace.toString(); int targetSize = target.length(); StringBuilder returnValue = new StringBuilder(); String unhandled = this; int index = -1; while ((index = unhandled.indexOf(targetString)) != -1) { returnValue.append(unhandled.substring(0, index)).append(replaceString); unhandled = unhandled.substring(index + targetSize, unhandled.length()); } returnValue.append(unhandled); return returnValue.toString(); } private String infuse(String infuseWith) { StringBuilder retVal = new StringBuilder(); String me = this; for (int i = 0; i < me.length(); i++) { retVal.append(infuseWith).append(me.substring(i, i + 1)); } retVal.append(infuseWith); return retVal.toString(); } public native String intern(); public static String valueOf(Object s) { return s == null ? "null" : s.toString(); } public static String valueOf(boolean v) { return Boolean.toString(v); } public static String valueOf(byte v) { return Byte.toString(v); } public static String valueOf(short v) { return Short.toString(v); } public static String valueOf(char v) { return Character.toString(v); } public static String valueOf(int v) { return Integer.toString(v); } public static String valueOf(long v) { return Long.toString(v); } public static String valueOf(float v) { return Float.toString(v); } public static String valueOf(double v) { return Double.toString(v); } public static String valueOf(char[] data, int offset, int length) { return new String(data, offset, length); } public static String valueOf(char[] data) { return valueOf(data, 0, data.length); } public int lastIndexOf(int ch, int lastIndex) { if (lastIndex >= length) { lastIndex = length - 1; } for (int i = lastIndex ; i >= 0; --i) { if (charAt(i) == ch) { return i; } } return -1; } public boolean regionMatches(int thisOffset, String match, int matchOffset, int length) { return regionMatches(false, thisOffset, match, matchOffset, length); } public boolean regionMatches(boolean ignoreCase, int thisOffset, String match, int matchOffset, int length) { String a = substring(thisOffset, thisOffset + length); String b = match.substring(matchOffset, matchOffset + length); if (ignoreCase) { return a.equalsIgnoreCase(b); } else { return a.equals(b); } } public boolean isEmpty() { return length == 0; } public boolean contains(CharSequence match) { return indexOf(match.toString()) != -1; } public int codePointAt(int offset) { return Character.codePointAt(this, offset); } public int codePointCount(int start, int end) { return Character.codePointCount(this, start, end); } public String toUpperCase(Locale locale) { if (locale == Locale.ENGLISH) { return toUpperCase(); } else { throw new UnsupportedOperationException("toUpperCase("+locale+')'); } } public String toLowerCase(Locale locale) { if (locale == Locale.ENGLISH) { return toLowerCase(); } else { throw new UnsupportedOperationException("toLowerCase("+locale+')'); } } } ReadyTalk-avian-1e1fff5/classpath/java/lang/StringBuffer.java000066400000000000000000000065451231440243200242610ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class StringBuffer implements CharSequence { private final StringBuilder sb; public StringBuffer(String s) { sb = new StringBuilder(s); } public StringBuffer(int capacity) { sb = new StringBuilder(capacity); } public StringBuffer() { this(0); } public synchronized StringBuffer append(String s) { sb.append(s); return this; } public synchronized StringBuffer append(CharSequence s) { sb.append(s); return this; } public synchronized StringBuffer append(StringBuffer s) { sb.append(s); return this; } public synchronized StringBuffer append(Object o) { sb.append(o); return this; } public synchronized StringBuffer append(char v) { sb.append(v); return this; } public synchronized StringBuffer append(boolean v) { sb.append(v); return this; } public synchronized StringBuffer append(int v) { sb.append(v); return this; } public synchronized StringBuffer append(long v) { sb.append(v); return this; } public synchronized StringBuffer append(float v) { sb.append(v); return this; } public synchronized StringBuffer append(double v) { sb.append(v); return this; } public synchronized StringBuffer append(char[] b, int offset, int length) { sb.append(b, offset, length); return this; } public synchronized StringBuffer append(char[] b) { sb.append(b, 0, b.length); return this; } public synchronized int indexOf(String s) { return sb.indexOf(s); } public synchronized int indexOf(String s, int fromIndex) { return sb.indexOf(s, fromIndex); } public synchronized StringBuffer insert(int i, String s) { sb.insert(i, s); return this; } public synchronized StringBuffer insert(int i, char c) { sb.insert(i, c); return this; } public synchronized StringBuffer insert(int i, int v) { sb.insert(i, v); return this; } public synchronized StringBuffer delete(int start, int end) { sb.delete(start, end); return this; } public synchronized StringBuffer deleteCharAt(int i) { sb.deleteCharAt(i); return this; } public synchronized char charAt(int i) { return sb.charAt(i); } public synchronized int length() { return sb.length(); } public synchronized StringBuffer replace(int start, int end, String str) { sb.replace(start, end, str); return this; } public synchronized void setLength(int v) { sb.setLength(v); } public synchronized void setCharAt(int index, char ch) { sb.setCharAt(index, ch); } public synchronized void getChars(int srcStart, int srcEnd, char[] dst, int dstStart) { sb.getChars(srcStart, srcEnd, dst, dstStart); } public synchronized String toString() { return sb.toString(); } public String substring(int start, int end) { return sb.substring(start, end); } public CharSequence subSequence(int start, int end) { return sb.subSequence(start, end); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/StringBuilder.java000066400000000000000000000202161231440243200244250ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class StringBuilder implements CharSequence, Appendable { private static final int BufferSize = 32; private Cell chain; private int length; private char[] buffer; private int position; public StringBuilder(String s) { append(s); } public StringBuilder(int capacity) { } public StringBuilder() { this(0); } private void flush() { if (position > 0) { chain = new Cell(new String(buffer, 0, position, false), chain); buffer = null; position = 0; } } public StringBuilder append(String s) { if (s == null) { return append("null"); } else { if (s.length() > 0) { if (buffer != null && s.length() <= buffer.length - position) { s.getChars(0, s.length(), buffer, position); position += s.length(); } else { flush(); chain = new Cell(s, chain); } length += s.length(); } return this; } } public StringBuilder append(StringBuffer sb) { return append(sb.toString()); } public StringBuilder append(CharSequence sequence) { return append(sequence.toString()); } public Appendable append(CharSequence sequence, int start, int end) { return append(sequence.subSequence(start, end)); } public StringBuilder append(char[] b, int offset, int length) { return append(new String(b, offset, length)); } public StringBuilder append(Object o) { return append(o == null ? "null" : o.toString()); } public StringBuilder append(char v) { if (buffer == null) { buffer = new char[BufferSize]; } else if (position >= buffer.length) { flush(); buffer = new char[BufferSize]; } buffer[position++] = v; ++ length; return this; } public StringBuilder append(boolean v) { return append(String.valueOf(v)); } public StringBuilder append(int v) { return append(String.valueOf(v)); } public StringBuilder append(long v) { return append(String.valueOf(v)); } public StringBuilder append(float v) { return append(String.valueOf(v)); } public StringBuilder append(double v) { return append(String.valueOf(v)); } public char charAt(int i) { if (i < 0 || i >= length) { throw new IndexOutOfBoundsException(); } flush(); int index = length; for (Cell c = chain; c != null; c = c.next) { int start = index - c.value.length(); index = start; if (i >= start) { return c.value.charAt(i - start); } } throw new RuntimeException(); } public StringBuilder insert(int i, String s) { if (i < 0 || i > length) { throw new IndexOutOfBoundsException(); } if (i == length) { append(s); } else { flush(); int index = length; for (Cell c = chain; c != null; c = c.next) { int start = index - c.value.length(); index = start; if (i >= start) { if (i == start) { c.next = new Cell(s, c.next); } else { String v = c.value; c.value = v.substring(i - start, v.length()); c.next = new Cell(s, new Cell(v.substring(0, i - start), c.next)); } break; } } length += s.length(); } return this; } public StringBuilder insert(int i, CharSequence s) { return insert(i, s.toString()); } public StringBuilder insert(int i, char c) { return insert(i, new String(new char[] { c }, 0, 1, false)); } public StringBuilder insert(int i, int v) { return insert(i, String.valueOf(v)); } public StringBuilder delete(int start, int end) { if (start >= end) { return this; } if (start < 0 || end > length) { throw new IndexOutOfBoundsException(); } flush(); int index = length; Cell p = null; for (Cell c = chain; c != null; c = c.next) { int e = index; int s = index - c.value.length(); index = s; if (end >= e) { if (start <= s) { if (p == null) { chain = c.next; } else { p.next = c.next; } } else { c.value = c.value.substring(0, start - s); break; } } else { if (start <= s) { c.value = c.value.substring(end - s, e - s); } else { String v = c.value; c.value = v.substring(end - s, e - s); c.next = new Cell(v.substring(0, start - s), c.next); break; } } } length -= (end - start); return this; } public StringBuilder deleteCharAt(int i) { return delete(i, i + 1); } public StringBuilder replace(int start, int end, String str) { delete(start, end); insert(start, str); return this; } public int indexOf(String s) { return indexOf(s, 0); } public int indexOf(String s, int start) { int slength = s.length(); if (slength == 0) return start; for (int i = start; i < length - slength + 1; ++i) { int j = 0; for (; j < slength; ++j) { if (charAt(i + j) != s.charAt(j)) { break; } } if (j == slength) { return i; } } return -1; } public int lastIndexOf(String s) { return lastIndexOf(s, length - s.length()); } public int lastIndexOf(String s, int lastIndex) { int slength = s.length(); if (slength == 0) return lastIndex; for (int i = Math.min(length - slength, lastIndex); i >= 0; --i) { int j = 0; for (; j < slength && i + j < length; ++j) { if (charAt(i + j) != s.charAt(j)) { break; } } if (j == slength) { return i; } } return -1; } public int length() { return length; } public void setLength(int v) { if (v < 0) { throw new IndexOutOfBoundsException(); } if (v == 0) { length = 0; chain = null; return; } flush(); int index = length; length = v; for (Cell c = chain; c != null; c = c.next) { int start = index - c.value.length(); if (v > start) { if (v < index) { c.value = c.value.substring(0, v - start); } break; } chain = c.next; index = start; } } public void getChars(int srcStart, int srcEnd, char[] dst, int dstStart) { if (srcStart < 0 || srcEnd > length) { throw new IndexOutOfBoundsException(); } flush(); int index = length; for (Cell c = chain; c != null; c = c.next) { int start = index - c.value.length(); int end = index; index = start; if (start < srcStart) { start = srcStart; } if (end > srcEnd) { end = srcEnd; } if (start < end) { c.value.getChars(start - index, end - index, dst, dstStart + (start - srcStart)); } } } public String toString() { char[] array = new char[length]; getChars(0, length, array, 0); return new String(array, 0, length, false); } private static class Cell { public String value; public Cell next; public Cell(String value, Cell next) { this.value = value; this.next = next; } } public String substring(int start) { return substring(start, length); } public String substring(int start, int end) { int len = end-start; char[] buf = new char[len]; getChars(start, end, buf, 0); return new String(buf, 0, len, false); } public CharSequence subSequence(int start, int end) { return substring(start, end); } public void setCharAt(int index, char ch) { if(index < 0 || index >= length) throw new IndexOutOfBoundsException(); deleteCharAt(index); insert(index, ch); } public void ensureCapacity(int capacity) { // ignore } } ReadyTalk-avian-1e1fff5/classpath/java/lang/StringIndexOutOfBoundsException.java000066400000000000000000000010261231440243200301130ustar00rootroot00000000000000package java.lang; /** * Used by String to signal that a given index is either less than * or greater than the allowed range. */ public class StringIndexOutOfBoundsException extends IndexOutOfBoundsException { private static final long serialVersionUID = -6762910422159637258L; public StringIndexOutOfBoundsException(int index) { super("String index out of range: "+index); } public StringIndexOutOfBoundsException(String message) { super(message); } public StringIndexOutOfBoundsException() {} } ReadyTalk-avian-1e1fff5/classpath/java/lang/SuppressWarnings.java000066400000000000000000000006571231440243200252140ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public @interface SuppressWarnings { String[] value(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/System.java000066400000000000000000000121411231440243200231320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.io.PrintStream; import java.io.InputStream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileDescriptor; import java.util.Map; import java.util.Hashtable; import java.util.Properties; public abstract class System { private static final long NanoTimeBaseInMillis = currentTimeMillis(); private static Property properties; private static Map environment; private static SecurityManager securityManager; // static { // loadLibrary("natives"); // } public static final PrintStream out = new PrintStream (new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)), true); public static final PrintStream err = new PrintStream (new BufferedOutputStream(new FileOutputStream(FileDescriptor.err)), true); public static final InputStream in = new BufferedInputStream(new FileInputStream(FileDescriptor.in)); public static native void arraycopy(Object src, int srcOffset, Object dst, int dstOffset, int length); public static String getProperty(String name) { for (Property p = properties; p != null; p = p.next) { if (p.name.equals(name)) { return p.value; } } boolean[] found = new boolean[1]; String value = getProperty(name, found); if (found[0]) return value; value = getVMProperty(name, found); if (found[0]) return value; return null; } public static String getProperty(String name, String defaultValue) { String result = getProperty(name); if (result==null) { return defaultValue; } return result; } public static String setProperty(String name, String value) { for (Property p = properties; p != null; p = p.next) { if (p.name.equals(name)) { String oldValue = p.value; p.value = value; return oldValue; } } properties = new Property(name, value, properties); return null; } public static Properties getProperties () { Properties prop = new Properties(); for (Property p = properties; p != null; p = p.next) { prop.put(p.name, p.value); } return prop; } private static native String getProperty(String name, boolean[] found); private static native String getVMProperty(String name, boolean[] found); public static native long currentTimeMillis(); public static native int identityHashCode(Object o); public static long nanoTime() { return (currentTimeMillis() - NanoTimeBaseInMillis) * 1000000; } public static String mapLibraryName(String name) { if (name != null) { return doMapLibraryName(name); } else { throw new NullPointerException(); } } private static native String doMapLibraryName(String name); public static void load(String path) { Runtime.getRuntime().load(path); } public static void loadLibrary(String name) { Runtime.getRuntime().loadLibrary(name); } public static void gc() { Runtime.getRuntime().gc(); } public static void exit(int code) { Runtime.getRuntime().exit(code); } public static SecurityManager getSecurityManager() { return securityManager; } public static void setSecurityManager(SecurityManager securityManager) { System.securityManager = securityManager; } private static class Property { public final String name; public String value; public final Property next; public Property(String name, String value, Property next) { this.name = name; this.value = value; this.next = next; } } public static String getenv(String name) throws NullPointerException, SecurityException { if (getSecurityManager() != null) { // is this allowed? getSecurityManager(). checkPermission(new RuntimePermission("getenv." + name)); } return getenv().get(name); } public static Map getenv() throws SecurityException { if (getSecurityManager() != null) { // is this allowed? getSecurityManager().checkPermission(new RuntimePermission("getenv.*")); } if (environment == null) { // build environment table String[] vars = getEnvironment(); environment = new Hashtable(vars.length); for (String var : vars) { // parse name-value pairs int equalsIndex = var.indexOf('='); // null names and values are forbidden if (equalsIndex != -1 && equalsIndex < var.length() - 1) { environment.put(var.substring(0, equalsIndex), var.substring(equalsIndex + 1)); } } } return environment; } /** Returns the native process environment. */ private static native String[] getEnvironment(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/Thread.java000066400000000000000000000157151231440243200230670ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.util.Map; import java.util.WeakHashMap; public class Thread implements Runnable { // set and accessed from within LockSupport protected volatile Object parkBlocker; private long peer; private volatile boolean interrupted; private volatile boolean unparked; private boolean daemon; private byte state; private byte priority; private final Runnable task; private Map locals; private Object sleepLock; private ClassLoader classLoader; private UncaughtExceptionHandler exceptionHandler; private String name; private ThreadGroup group; private static UncaughtExceptionHandler defaultExceptionHandler; public static final int MIN_PRIORITY = 1; public static final int NORM_PRIORITY = 5; public static final int MAX_PRIORITY = 10; public Thread(ThreadGroup group, Runnable task, String name, long stackSize) { this.group = (group == null ? Thread.currentThread().group : group); this.task = task; this.name = name; Thread current = currentThread(); Map map = current.locals; if (map != null) { for (Map.Entry e: map.entrySet()) { if (e.getKey() instanceof InheritableThreadLocal) { InheritableThreadLocal itl = (InheritableThreadLocal) e.getKey(); locals().put(itl, itl.childValue(e.getValue())); } } } classLoader = current.classLoader; } public Thread(ThreadGroup group, Runnable task, String name) { this(group, task, name, 0); } public Thread(ThreadGroup group, String name) { this(null, null, name); } public Thread(Runnable task, String name) { this(null, task, name); } public Thread(Runnable task) { this(null, task, "Thread["+task+"]"); } public Thread(String name) { this(null, null, name); } public Thread() { this((Runnable) null); } public synchronized void start() { if (peer != 0) { throw new IllegalStateException("thread already started"); } state = (byte) State.RUNNABLE.ordinal(); peer = doStart(); if (peer == 0) { state = (byte) State.NEW.ordinal(); throw new RuntimeException("unable to start native thread"); } } private native long doStart(); private static void run(Thread t) throws Throwable { try { t.run(); } catch (Throwable e) { UncaughtExceptionHandler eh = t.exceptionHandler; UncaughtExceptionHandler deh = defaultExceptionHandler; if (eh != null) { eh.uncaughtException(t, e); } else if (deh != null) { deh.uncaughtException(t, e); } else { throw e; } } finally { synchronized (t) { t.state = (byte) State.TERMINATED.ordinal(); t.notifyAll(); } } } public void run() { if (task != null) { task.run(); } } public ClassLoader getContextClassLoader() { return classLoader; } public void setContextClassLoader(ClassLoader v) { classLoader = v; } public Map locals() { if (locals == null) { locals = new WeakHashMap(); } return locals; } public static native Thread currentThread(); public void interrupt() { interrupt(peer); } private static native boolean interrupt(long peer); public static boolean interrupted() { return interrupted(currentThread().peer); } private static native boolean interrupted(long peer); public boolean isInterrupted() { return interrupted; } public static void sleep(long milliseconds) throws InterruptedException { if (milliseconds <= 0) { milliseconds = 1; } Thread t = currentThread(); if (t.sleepLock == null) { t.sleepLock = new Object(); } synchronized (t.sleepLock) { t.sleepLock.wait(milliseconds); } } public static void sleep(long milliseconds, int nanoseconds) throws InterruptedException { if (nanoseconds > 0) { ++ milliseconds; } sleep(milliseconds); } public StackTraceElement[] getStackTrace() { long p = peer; if (p == 0) { return new StackTraceElement[0]; } return Throwable.resolveTrace(getStackTrace(p)); } private static native Object getStackTrace(long peer); public static native int activeCount(); public static native int enumerate(Thread[] array); public String getName() { return name; } public void setName(String name) { this.name = name; } public UncaughtExceptionHandler getUncaughtExceptionHandler() { UncaughtExceptionHandler eh = exceptionHandler; return (eh == null ? group : eh); } public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() { return defaultExceptionHandler; } public void setUncaughtExceptionHandler(UncaughtExceptionHandler h) { exceptionHandler = h; } public static void setDefaultUncaughtExceptionHandler (UncaughtExceptionHandler h) { defaultExceptionHandler = h; } public State getState() { return State.values()[state]; } public boolean isAlive() { switch (getState()) { case NEW: case TERMINATED: return false; default: return true; } } public int getPriority() { return priority; } public void setPriority(int priority) { if (priority < MIN_PRIORITY || priority > MAX_PRIORITY) { throw new IllegalArgumentException(); } this.priority = (byte) priority; } public boolean isDaemon() { return daemon; } public synchronized void setDaemon(boolean v) { if (getState() != State.NEW) { throw new IllegalStateException(); } daemon = v; } public static native void yield(); public synchronized void join() throws InterruptedException { while (getState() != State.TERMINATED) { wait(); } } public synchronized void join(long milliseconds) throws InterruptedException { long then = System.currentTimeMillis(); long remaining = milliseconds; while (remaining > 0 && getState() != State.TERMINATED) { wait(remaining); remaining = milliseconds - (System.currentTimeMillis() - then); } } public void join(long milliseconds, int nanoseconds) throws InterruptedException { if (nanoseconds > 0) { ++ milliseconds; } join(milliseconds); } public ThreadGroup getThreadGroup() { return group; } public static native boolean holdsLock(Object o); public long getId() { return peer; } public interface UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e); } public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ThreadDeath.java000066400000000000000000000006711231440243200240300ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class ThreadDeath extends Error { public ThreadDeath() { } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ThreadGroup.java000066400000000000000000000054221231440243200240760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import avian.Cell; public class ThreadGroup implements Thread.UncaughtExceptionHandler { private final ThreadGroup parent; private final String name; private Cell subgroups; public ThreadGroup(ThreadGroup parent, String name) { this.parent = parent; this.name = name; synchronized (parent) { parent.subgroups = new Cell(this, subgroups); } } public ThreadGroup(String name) { this(Thread.currentThread().getThreadGroup(), name); } public void uncaughtException(Thread t, Throwable e) { if (parent != null) { parent.uncaughtException(t, e); } else { Thread.UncaughtExceptionHandler deh = Thread.getDefaultUncaughtExceptionHandler(); if (deh != null) { deh.uncaughtException(t, e); } else if (! (e instanceof ThreadDeath)) { e.printStackTrace(); } } } public ThreadGroup getParent() { return parent; } public String getName() { return name; } public int activeCount() { int allCount = Thread.activeCount(); Thread[] all = new Thread[allCount]; allCount = Thread.enumerate(all); int count = 0; for (int i = 0; i < allCount; ++i) { if (parentOf(all[i].getThreadGroup())) { ++ count; } } return count; } public int enumerate(Thread[] threads) { return enumerate(threads, true); } public int enumerate(Thread[] threads, boolean recurse) { int allCount = Thread.activeCount(); Thread[] all = new Thread[allCount]; allCount = Thread.enumerate(all); int count = 0; for (int i = 0; i < allCount && count < threads.length; ++i) { Thread t = all[i]; ThreadGroup g = t.getThreadGroup(); if (g == this || (recurse && parentOf(g))) { threads[count++] = t; } } return count; } public boolean parentOf(ThreadGroup g) { for (; g != null; g = g.parent) { if (g == this) { return true; } } return false; } public int enumerate(ThreadGroup[] groups, boolean recurse) { return enumerate(groups, recurse, 0); } private int enumerate(ThreadGroup[] groups, boolean recurse, int count) { for (Cell c = subgroups; c != null && count < groups.length; c = c.next) { ThreadGroup g = c.value; groups[count++] = g; if (recurse) { count = g.enumerate(groups, true, count); } } return count; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ThreadLocal.java000066400000000000000000000020041231440243200240250ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.util.Map; public class ThreadLocal { private static final Object Null = new Object(); protected T initialValue() { return null; } public T get() { Map map = Thread.currentThread().locals(); Object o = map.get(this); if (o == null) { o = initialValue(); if (o == null) { o = Null; } map.put(this, o); } if (o == Null) { o = null; } return (T) o; } public void set(T value) { Map map = Thread.currentThread().locals(); Object o = value; if (o == null) { o = Null; } map.put(this, o); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Throwable.java000066400000000000000000000056301231440243200236020ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; import java.io.PrintStream; import java.io.PrintWriter; import java.io.IOException; import java.io.Serializable; public class Throwable implements Serializable { private String message; private Object trace; private Throwable cause; public Throwable(String message, Throwable cause) { this.message = message; this.trace = trace(1); this.cause = cause; } public Throwable(String message) { this(message, null); } public Throwable(Throwable cause) { this(null, cause); } public Throwable() { this(null, null); } public Throwable getCause() { return cause; } public Throwable initCause(Throwable e) { if (cause == null) { cause = e; return this; } else { throw new IllegalStateException(); } } public String getMessage() { return message; } public String getLocalizedMessage() { return getMessage(); } public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getClass().getName()); if (message != null) { sb.append(": ").append(message); } return sb.toString(); } private static native Object trace(int skipCount); static native StackTraceElement[] resolveTrace(Object trace); private StackTraceElement[] resolveTrace() { if (! (trace instanceof StackTraceElement[])) { trace = resolveTrace(trace); } return (StackTraceElement[]) trace; } public StackTraceElement[] getStackTrace() { return resolveTrace(); } public void setStackTrace(StackTraceElement[] trace) { this.trace = trace; } public void printStackTrace(PrintStream out) { StringBuilder sb = new StringBuilder(); printStackTrace(sb, System.getProperty("line.separator")); out.print(sb.toString()); out.flush(); } public void printStackTrace(PrintWriter out) { StringBuilder sb = new StringBuilder(); printStackTrace(sb, System.getProperty("line.separator")); out.print(sb.toString()); out.flush(); } public void printStackTrace() { printStackTrace(System.err); } private void printStackTrace(StringBuilder sb, String nl) { sb.append(toString()).append(nl); StackTraceElement[] trace = resolveTrace(); for (int i = 0; i < trace.length; ++i) { sb.append(" at ").append(trace[i].toString()).append(nl); } if (cause != null) { sb.append("caused by: "); cause.printStackTrace(sb, nl); } } public Throwable fillInStackTrace() { trace = trace(0); return this; } public void addSuppressed(Throwable exception) { } } ReadyTalk-avian-1e1fff5/classpath/java/lang/UnsatisfiedLinkError.java000066400000000000000000000010551231440243200257560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class UnsatisfiedLinkError extends LinkageError { public UnsatisfiedLinkError(String message) { super(message); } public UnsatisfiedLinkError() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/UnsupportedOperationException.java000066400000000000000000000014271231440243200277430ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class UnsupportedOperationException extends RuntimeException { public UnsupportedOperationException(String message, Throwable cause) { super(message, cause); } public UnsupportedOperationException(String message) { this(message, null); } public UnsupportedOperationException(Throwable cause) { this(null, cause); } public UnsupportedOperationException() { this(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/VirtualMachineError.java000066400000000000000000000010431231440243200255720ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public class VirtualMachineError extends Error { public VirtualMachineError(String message) { super(message); } public VirtualMachineError() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/Void.java000066400000000000000000000007551231440243200225570ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang; public final class Void { public static final Class TYPE = avian.Classes.forCanonicalName("V"); private Void() { } } ReadyTalk-avian-1e1fff5/classpath/java/lang/annotation/000077500000000000000000000000001231440243200231565ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/lang/annotation/Annotation.java000066400000000000000000000007161231440243200261370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.annotation; public interface Annotation { Class annotationType(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/annotation/ElementType.java000066400000000000000000000010001231440243200262430ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.annotation; public enum ElementType { ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE } ReadyTalk-avian-1e1fff5/classpath/java/lang/annotation/Retention.java000066400000000000000000000007441231440243200257750ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.annotation; @Retention(RetentionPolicy.RUNTIME) public @interface Retention { public RetentionPolicy value(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/annotation/RetentionPolicy.java000066400000000000000000000006671231440243200271610ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.annotation; public enum RetentionPolicy { CLASS, RUNTIME, SOURCE } ReadyTalk-avian-1e1fff5/classpath/java/lang/annotation/Target.java000066400000000000000000000010201231440243200252400ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.annotation; @Retention(value=RetentionPolicy.RUNTIME) @Target(value=ElementType.ANNOTATION_TYPE) public @interface Target { public ElementType[] value(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/ref/000077500000000000000000000000001231440243200215605ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/lang/ref/PhantomReference.java000066400000000000000000000012061231440243200256470ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.ref; public class PhantomReference extends Reference { public PhantomReference(T target, ReferenceQueue queue) { super(target, queue); } public PhantomReference(T target) { this(target, null); } public T get() { return null; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ref/Reference.java000066400000000000000000000017751231440243200243330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.ref; public abstract class Reference { private Object vmNext; private T target; private ReferenceQueue queue; Reference jNext; protected Reference(T target, ReferenceQueue queue) { this.target = target; this.queue = queue; } protected Reference(T target) { this(target, null); } public T get() { return target; } public void clear() { target = null; } public boolean isEnqueued() { return jNext != null; } public boolean enqueue() { if (queue != null) { queue.add(this); queue = null; return true; } else { return false; } } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ref/ReferenceQueue.java000066400000000000000000000015001231440243200253220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.ref; public class ReferenceQueue { private Reference front; public Reference poll() { Reference r = front; if (front != null) { if (front == front.jNext) { front = null; } else { front = front.jNext; } } return r; } void add(Reference r) { if (front == null) { r.jNext = r; } else { r.jNext = front; } front = r; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ref/SoftReference.java000066400000000000000000000011241231440243200251530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.ref; public class SoftReference extends Reference { public SoftReference(T target, ReferenceQueue queue) { super(target, queue); } public SoftReference(T target) { this(target, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/ref/WeakReference.java000066400000000000000000000011241231440243200251270ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.ref; public class WeakReference extends Reference { public WeakReference(T target, ReferenceQueue queue) { super(target, queue); } public WeakReference(T target) { this(target, null); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/000077500000000000000000000000001231440243200224305ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/AccessibleObject.java000066400000000000000000000016021231440243200264560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; import java.lang.annotation.Annotation; public abstract class AccessibleObject implements AnnotatedElement { protected static final int Accessible = 1 << 0; public boolean isAnnotationPresent (Class class_) { return getAnnotation(class_) != null; } public abstract boolean isAccessible(); public abstract void setAccessible(boolean v); public static void setAccessible(AccessibleObject[] array, boolean v) { for (AccessibleObject o: array) o.setAccessible(v); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/AnnotatedElement.java000066400000000000000000000012611231440243200265220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; import java.lang.annotation.Annotation; public interface AnnotatedElement { public boolean isAnnotationPresent(Class class_); public T getAnnotation(Class class_); public Annotation[] getAnnotations(); public Annotation[] getDeclaredAnnotations(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/Array.java000066400000000000000000000072121231440243200243530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; public final class Array { private Array() { } public static Object get(Object array, int index) { String className = array.getClass().getName(); if (! className.startsWith("[")) { throw new IllegalArgumentException(); } switch (className.charAt(1)) { case 'B': return Byte.valueOf(((byte[]) array)[index]); case 'C': return Character.valueOf(((char[]) array)[index]); case 'D': return Double.valueOf(((double[]) array)[index]); case 'F': return Float.valueOf(((float[]) array)[index]); case 'I': return Integer.valueOf(((int[]) array)[index]); case 'J': return Long.valueOf(((long[]) array)[index]); case 'S': return Short.valueOf(((short[]) array)[index]); case 'Z': return Boolean.valueOf(((boolean[]) array)[index]); case 'L': case '[': return ((Object[]) array)[index]; default: throw new Error(); } } public static void set(Object array, int index, Object value) { String className = array.getClass().getName(); if (! className.startsWith("[")) { throw new IllegalArgumentException(); } switch (className.charAt(1)) { case 'B': ((byte[]) array)[index] = (Byte) value; break; case 'C': ((char[]) array)[index] = (Character) value; break; case 'D': ((double[]) array)[index] = (Double) value; break; case 'F': ((float[]) array)[index] = (Float) value; break; case 'I': ((int[]) array)[index] = (Integer) value; break; case 'J': ((long[]) array)[index] = (Long) value; break; case 'S': ((short[]) array)[index] = (Short) value; break; case 'Z': ((boolean[]) array)[index] = (Boolean) value; break; case 'L': case '[': if (value == null || array.getClass().getComponentType().isInstance(value)) { ((Object[]) array)[index] = value; } else { throw new IllegalArgumentException ("need " + array.getClass().getComponentType() + ", got " + value.getClass().getName()); } break; default: throw new Error(); } } public static native int getLength(Object array); private static native Object makeObjectArray(Class elementType, int length); public static Object newInstance(Class elementType, int length) { if (length < 0) { throw new NegativeArraySizeException(); } if (elementType.isPrimitive()) { if (elementType.equals(boolean.class)) { return new boolean[length]; } else if (elementType.equals(byte.class)) { return new byte[length]; } else if (elementType.equals(char.class)) { return new char[length]; } else if (elementType.equals(short.class)) { return new short[length]; } else if (elementType.equals(int.class)) { return new int[length]; } else if (elementType.equals(long.class)) { return new long[length]; } else if (elementType.equals(float.class)) { return new float[length]; } else if (elementType.equals(double.class)) { return new double[length]; } else { throw new IllegalArgumentException(); } } else { return makeObjectArray(elementType, length); } } } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/Constructor.java000066400000000000000000000033421231440243200256220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; import java.lang.annotation.Annotation; public class Constructor extends AccessibleObject implements Member { private Method method; public Constructor(Method method) { this.method = method; } public boolean equals(Object o) { return o instanceof Constructor && ((Constructor) o).method.equals(method); } public boolean isAccessible() { return method.isAccessible(); } public void setAccessible(boolean v) { method.setAccessible(v); } public Class getDeclaringClass() { return method.getDeclaringClass(); } public Class[] getParameterTypes() { return method.getParameterTypes(); } public int getModifiers() { return method.getModifiers(); } public String getName() { return method.getName(); } public T getAnnotation(Class class_) { return method.getAnnotation(class_); } public Annotation[] getAnnotations() { return method.getAnnotations(); } public Annotation[] getDeclaredAnnotations() { return method.getDeclaredAnnotations(); } private static native Object make(avian.VMClass c); public T newInstance(Object ... arguments) throws InvocationTargetException, InstantiationException, IllegalAccessException { T v = (T) make(method.getDeclaringClass().vmClass); method.invoke(v, arguments); return v; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/Field.java000066400000000000000000000241661231440243200243270ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; import avian.VMField; import avian.AnnotationInvocationHandler; import avian.SystemClassLoader; import avian.Classes; import java.lang.annotation.Annotation; public class Field extends AccessibleObject { private static final int VoidField = 0; private static final int ByteField = 1; private static final int CharField = 2; private static final int DoubleField = 3; private static final int FloatField = 4; private static final int IntField = 5; private static final int LongField = 6; private static final int ShortField = 7; private static final int BooleanField = 8; private static final int ObjectField = 9; private final VMField vmField; private boolean accessible = true; public Field(VMField vmField) { this.vmField = vmField; } public boolean isAccessible() { return accessible; } public void setAccessible(boolean v) { accessible = v; } public Class getDeclaringClass() { return SystemClassLoader.getClass(vmField.class_); } public int getModifiers() { return vmField.flags; } public String getName() { return getName(vmField); } public static String getName(VMField vmField) { return new String(vmField.name, 0, vmField.name.length - 1, false); } public Class getType() { return Classes.forCanonicalName (vmField.class_.loader, new String(vmField.spec, 0, vmField.spec.length - 1, false)); } public Type getGenericType() { if (vmField.addendum == null || vmField.addendum.signature == null) { return getType(); } String signature = Classes.toString((byte[]) vmField.addendum.signature); return SignatureParser.parse(vmField.class_.loader, signature); } public Object get(Object instance) throws IllegalAccessException { Object target; if ((vmField.flags & Modifier.STATIC) != 0) { target = vmField.class_.staticTable; } else if (Class.isInstance(vmField.class_, instance)) { target = instance; } else { throw new IllegalArgumentException(); } Classes.initialize(vmField.class_); switch (vmField.code) { case ByteField: return Byte.valueOf ((byte) getPrimitive(target, vmField.code, vmField.offset)); case BooleanField: return Boolean.valueOf (getPrimitive(target, vmField.code, vmField.offset) != 0); case CharField: return Character.valueOf ((char) getPrimitive(target, vmField.code, vmField.offset)); case ShortField: return Short.valueOf ((short) getPrimitive(target, vmField.code, vmField.offset)); case IntField: return Integer.valueOf ((int) getPrimitive(target, vmField.code, vmField.offset)); case LongField: return Long.valueOf (getPrimitive(target, vmField.code, vmField.offset)); case FloatField: return Float.valueOf (Float.intBitsToFloat ((int) getPrimitive(target, vmField.code, vmField.offset))); case DoubleField: return Double.valueOf (Double.longBitsToDouble (getPrimitive(target, vmField.code, vmField.offset))); case ObjectField: return getObject(target, vmField.offset); default: throw new Error(); } } public boolean getBoolean(Object instance) throws IllegalAccessException { return ((Boolean) get(instance)).booleanValue(); } public byte getByte(Object instance) throws IllegalAccessException { return ((Byte) get(instance)).byteValue(); } public short getShort(Object instance) throws IllegalAccessException { return ((Short) get(instance)).shortValue(); } public char getChar(Object instance) throws IllegalAccessException { return ((Character) get(instance)).charValue(); } public int getInt(Object instance) throws IllegalAccessException { return ((Integer) get(instance)).intValue(); } public float getFloat(Object instance) throws IllegalAccessException { return ((Float) get(instance)).floatValue(); } public long getLong(Object instance) throws IllegalAccessException { return ((Long) get(instance)).longValue(); } public double getDouble(Object instance) throws IllegalAccessException { return ((Double) get(instance)).doubleValue(); } private boolean matchType(Object value) { switch (vmField.code) { case ByteField: return value instanceof Byte; case BooleanField: return value instanceof Boolean; case CharField: return value instanceof Character; case ShortField: return value instanceof Short; case IntField: return value instanceof Integer; case LongField: return value instanceof Long; case FloatField: return value instanceof Float; case DoubleField: return value instanceof Double; case ObjectField: return value == null || getType().isInstance(value); default: throw new Error(); } } public void set(Object instance, Object value) throws IllegalAccessException { Object target; if ((vmField.flags & Modifier.STATIC) != 0) { target = vmField.class_.staticTable; } else if (Class.isInstance(vmField.class_, instance)) { target = instance; } else { throw new IllegalArgumentException(); } if (! matchType(value)) { throw new IllegalArgumentException(); } Classes.initialize(vmField.class_); switch (vmField.code) { case ByteField: setPrimitive(target, vmField.code, vmField.offset, (Byte) value); break; case BooleanField: setPrimitive (target, vmField.code, vmField.offset, ((Boolean) value) ? 1 : 0); break; case CharField: setPrimitive(target, vmField.code, vmField.offset, (Character) value); break; case ShortField: setPrimitive(target, vmField.code, vmField.offset, (Short) value); break; case IntField: setPrimitive(target, vmField.code, vmField.offset, (Integer) value); break; case LongField: setPrimitive(target, vmField.code, vmField.offset, (Long) value); break; case FloatField: setPrimitive(target, vmField.code, vmField.offset, Float.floatToRawIntBits((Float) value)); break; case DoubleField: setPrimitive(target, vmField.code, vmField.offset, Double.doubleToRawLongBits((Double) value)); break; case ObjectField: setObject(target, vmField.offset, value); break; default: throw new Error(); } } private void set(Object instance, long value) throws IllegalAccessException { Object target; if ((vmField.flags & Modifier.STATIC) != 0) { target = vmField.class_.staticTable; } else if (Class.isInstance(vmField.class_, instance)) { target = instance; } else { throw new IllegalArgumentException(); } Classes.initialize(vmField.class_); switch (vmField.code) { case ByteField: case BooleanField: case CharField: case ShortField: case IntField: case LongField: case FloatField: case DoubleField: setPrimitive(target, vmField.code, vmField.offset, value); break; default: throw new IllegalArgumentException ("needed " + getType() + ", got primitive type when setting " + Class.getName(vmField.class_) + "." + getName()); } } public void setByte(Object instance, byte value) throws IllegalAccessException { set(instance, value & 0xff); } public void setBoolean(Object instance, boolean value) throws IllegalAccessException { set(instance, value ? 1 : 0); } public void setChar(Object instance, char value) throws IllegalAccessException { set(instance, value & 0xffff); } public void setShort(Object instance, short value) throws IllegalAccessException { set(instance, value & 0xffff); } public void setInt(Object instance, int value) throws IllegalAccessException { set(instance, value & 0xffffffffl); } public void setLong(Object instance, long value) throws IllegalAccessException { set(instance, value); } public void setFloat(Object instance, float value) throws IllegalAccessException { set(instance, Float.floatToIntBits(value)); } public void setDouble(Object instance, double value) throws IllegalAccessException { set(instance, Double.doubleToLongBits(value)); } private Annotation getAnnotation(Object[] a) { if (a[0] == null) { a[0] = Proxy.newProxyInstance (vmField.class_.loader, new Class[] { (Class) a[1] }, new AnnotationInvocationHandler(a)); } return (Annotation) a[0]; } public T getAnnotation(Class class_) { if (vmField.addendum != null && vmField.addendum.annotationTable != null) { Object[] table = (Object[]) vmField.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { return (T) getAnnotation(a); } } } return null; } public Annotation[] getAnnotations() { if (vmField.addendum.annotationTable != null) { Object[] table = (Object[]) vmField.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { array[i] = getAnnotation((Object[]) table[i]); } return array; } else { return new Annotation[0]; } } public Annotation[] getDeclaredAnnotations() { return getAnnotations(); } private static native long getPrimitive (Object instance, int code, int offset); private static native Object getObject (Object instance, int offset); private static native void setPrimitive (Object instance, int code, int offset, long value); private static native void setObject (Object instance, int offset, Object value); } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/InvocationHandler.java000066400000000000000000000007741231440243200267120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable; } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/InvocationTargetException.java000066400000000000000000000015361231440243200304370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; public class InvocationTargetException extends Exception { private Throwable target; // for compatibility with OpenJDK public InvocationTargetException(Throwable targetException, String message) { super(message, targetException); } public InvocationTargetException(Throwable targetException) { this(targetException, null); } public InvocationTargetException() { this(null, null); } public Throwable getTargetException() { return getCause(); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/Member.java000066400000000000000000000011041231440243200244760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; public interface Member { public static final int PUBLIC = 0; public static final int DECLARED = 1; public Class getDeclaringClass(); public int getModifiers(); public String getName(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/Method.java000066400000000000000000000102671231440243200245210ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; import avian.VMMethod; import avian.AnnotationInvocationHandler; import avian.SystemClassLoader; import avian.Classes; import java.lang.annotation.Annotation; public class Method extends AccessibleObject implements Member { private final VMMethod vmMethod; private boolean accessible; public Method(VMMethod vmMethod) { this.vmMethod = vmMethod; } public boolean isAccessible() { return accessible; } public void setAccessible(boolean v) { accessible = v; } public static native VMMethod getCaller(); public Class getDeclaringClass() { return SystemClassLoader.getClass(vmMethod.class_); } public int getModifiers() { return vmMethod.flags; } public String getName() { return getName(vmMethod); } public static String getName(VMMethod vmMethod) { return new String(vmMethod.name, 0, vmMethod.name.length - 1, false); } private String getSpec() { return getSpec(vmMethod); } public static String getSpec(VMMethod vmMethod) { return new String(vmMethod.spec, 0, vmMethod.spec.length - 1, false); } public Class[] getParameterTypes() { return Classes.getParameterTypes(vmMethod); } public Object invoke(Object instance, Object ... arguments) throws InvocationTargetException, IllegalAccessException { if ((vmMethod.flags & Modifier.STATIC) != 0 || Class.isInstance(vmMethod.class_, instance)) { if ((vmMethod.flags & Modifier.STATIC) != 0) { instance = null; } if (arguments == null) { if (vmMethod.parameterCount > 0) { throw new NullPointerException(); } arguments = new Object[0]; } if (arguments.length == vmMethod.parameterCount) { Classes.initialize(vmMethod.class_); return invoke(vmMethod, instance, arguments); } else { throw new ArrayIndexOutOfBoundsException(); } } else { // System.out.println // (getDeclaringClass() + "." + getName() + " flags: " + vmMethod.flags + " vm flags: " + vmMethod.vmFlags + " return code: " + vmMethod.returnCode); throw new IllegalArgumentException(); } } private static native Object invoke(VMMethod method, Object instance, Object ... arguments) throws InvocationTargetException, IllegalAccessException; public Class getReturnType() { for (int i = 0; i < vmMethod.spec.length - 1; ++i) { if (vmMethod.spec[i] == ')') { return Classes.forCanonicalName (vmMethod.class_.loader, new String (vmMethod.spec, i + 1, vmMethod.spec.length - i - 2, false)); } } throw new RuntimeException(); } public T getAnnotation(Class class_) { if (vmMethod.hasAnnotations()) { Object[] table = (Object[]) vmMethod.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { return (T) Classes.getAnnotation(vmMethod.class_.loader, a); } } } return null; } public Annotation[] getAnnotations() { if (vmMethod.hasAnnotations()) { Object[] table = (Object[]) vmMethod.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { array[i] = Classes.getAnnotation (vmMethod.class_.loader, (Object[]) table[i]); } return array; } else { return new Annotation[0]; } } public Annotation[] getDeclaredAnnotations() { return getAnnotations(); } public boolean isVarArgs() { return (getModifiers() & 0x80) != 0; } public Object getDefaultValue() { ClassLoader loader = getDeclaringClass().getClassLoader(); return Classes.getAnnotationDefaultValue(loader, vmMethod.addendum); } } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/Modifier.java000066400000000000000000000033521231440243200250340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; public final class Modifier { public static final int PUBLIC = 1 << 0; public static final int PRIVATE = 1 << 1; public static final int PROTECTED = 1 << 2; public static final int STATIC = 1 << 3; public static final int FINAL = 1 << 4; public static final int SUPER = 1 << 5; public static final int SYNCHRONIZED = SUPER; public static final int VOLATILE = 1 << 6; public static final int TRANSIENT = 1 << 7; public static final int NATIVE = 1 << 8; public static final int INTERFACE = 1 << 9; public static final int ABSTRACT = 1 << 10; public static final int STRICT = 1 << 11; private Modifier() { } public static boolean isPublic (int v) { return (v & PUBLIC) != 0; } public static boolean isPrivate (int v) { return (v & PRIVATE) != 0; } public static boolean isProtected(int v) { return (v & PROTECTED) != 0; } public static boolean isStatic (int v) { return (v & STATIC) != 0; } public static boolean isFinal (int v) { return (v & FINAL) != 0; } public static boolean isSuper (int v) { return (v & SUPER) != 0; } public static boolean isNative (int v) { return (v & NATIVE) != 0; } public static boolean isAbstract (int v) { return (v & ABSTRACT) != 0; } public static boolean isInterface(int v) { return (v & INTERFACE) != 0; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/ParameterizedType.java000066400000000000000000000007761231440243200267430ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; public interface ParameterizedType extends Type { Type[] getActualTypeArguments(); Type getOwnerType(); Type getRawType(); } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/Proxy.java000066400000000000000000000276541231440243200244320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; import static avian.Stream.write1; import static avian.Stream.write2; import static avian.Stream.write4; import static avian.Stream.set4; import static avian.Assembler.*; import avian.SystemClassLoader; import avian.Classes; import avian.ConstantPool; import avian.ConstantPool.PoolEntry; import avian.Assembler; import avian.Assembler.MethodData; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.HashSet; import java.io.OutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; public class Proxy { private static int nextNumber; protected InvocationHandler h; protected final static Map methodRefsMap = new HashMap(); protected final Method[] methodRefs; public Proxy() { methodRefs = methodRefsMap.get(getClass()); } public static Class getProxyClass(ClassLoader loader, Class ... interfaces) { for (Class c: interfaces) { if (! c.isInterface()) { throw new IllegalArgumentException(); } } int number; synchronized (Proxy.class) { number = nextNumber++; } try { return makeClass(loader, interfaces, "Proxy-" + number); } catch (IOException e) { AssertionError error = new AssertionError(); error.initCause(e); throw error; } } public static boolean isProxyClass(Class c) { return c.getName().startsWith("Proxy-"); } public static InvocationHandler getInvocationHandler(Object proxy) { return ((Proxy) proxy).h; } private static byte[] makeInvokeCode(List pool, String className, byte[] spec, int parameterCount, int parameterFootprint, int index) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); write2(out, 8); // max stack write2(out, parameterFootprint); // max locals write4(out, 0); // length (we'll set the real value later) write1(out, aload_0); write1(out, getfield); write2(out, ConstantPool.addFieldRef (pool, "java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;") + 1); write1(out, aload_0); write1(out, aload_0); write1(out, getfield); write2(out, ConstantPool.addFieldRef (pool, className, "methodRefs", "[Ljava/lang/reflect/Method;") + 1); write1(out, ldc_w); write2(out, ConstantPool.addInteger(pool, index) + 1); write1(out, aaload); write1(out, ldc_w); write2(out, ConstantPool.addInteger(pool, parameterCount) + 1); write1(out, anewarray); write2(out, ConstantPool.addClass(pool, "java/lang/Object") + 1); int ai = 0; int si; for (si = 1; spec[si] != ')'; ++si) { write1(out, dup); write1(out, ldc_w); write2(out, ConstantPool.addInteger(pool, ai) + 1); switch (spec[si]) { case 'L': ++ si; while (spec[si] != ';') ++si; write1(out, aload); write1(out, ai + 1); break; case '[': ++ si; while (spec[si] == '[') ++si; switch (spec[si]) { case 'L': ++ si; while (spec[si] != ';') ++si; break; default: break; } write1(out, aload); write1(out, ai + 1); break; case 'Z': write1(out, iload); write1(out, ai + 1); write1(out, invokestatic); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;") + 1); break; case 'B': write1(out, iload); write1(out, ai + 1); write1(out, invokestatic); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;") + 1); break; case 'S': write1(out, iload); write1(out, ai + 1); write1(out, invokestatic); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;") + 1); break; case 'C': write1(out, iload); write1(out, ai + 1); write1(out, invokestatic); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;") + 1); break; case 'I': write1(out, iload); write1(out, ai + 1); write1(out, invokestatic); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;") + 1); break; case 'F': write1(out, fload); write1(out, ai + 1); write1(out, invokestatic); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;") + 1); break; case 'J': write1(out, lload); write1(out, ai + 1); write1(out, invokestatic); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;") + 1); ++ ai; break; case 'D': write1(out, dload); write1(out, ai + 1); write1(out, invokestatic); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;") + 1); ++ ai; break; default: throw new IllegalArgumentException(); } write1(out, aastore); ++ ai; } write1(out, invokeinterface); write2(out, ConstantPool.addMethodRef (pool, "java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;" + "Ljava/lang/reflect/Method;" + "[Ljava/lang/Object;)" + "Ljava/lang/Object;") + 1); write2(out, 0); // this will be ignored by the VM switch (spec[si + 1]) { case 'L': case '[': write1(out, areturn); break; case 'Z': write1(out, invokevirtual); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Boolean", "booleanValue", "()Z") + 1); write1(out, ireturn); break; case 'B': write1(out, invokevirtual); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Byte", "byteValue", "()B") + 1); write1(out, ireturn); break; case 'C': write1(out, invokevirtual); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Character", "charValue", "()C") + 1); write1(out, ireturn); break; case 'S': write1(out, invokevirtual); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Short", "shortValue", "()S") + 1); write1(out, ireturn); break; case 'I': write1(out, invokevirtual); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Integer", "intValue", "()I") + 1); write1(out, ireturn); break; case 'F': write1(out, invokevirtual); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Float", "floatValue", "()F") + 1); write1(out, freturn); break; case 'J': write1(out, invokevirtual); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Long", "longValue", "()J") + 1); write1(out, lreturn); break; case 'D': write1(out, invokevirtual); write2(out, ConstantPool.addMethodRef (pool, "java/lang/Double", "doubleValue", "()D") + 1); write1(out, dreturn); break; case 'V': write1(out, pop); write1(out, return_); break; default: throw new IllegalArgumentException(); } write2(out, 0); // exception handler table length write2(out, 0); // attribute count byte[] result = out.toByteArray(); set4(result, 4, result.length - 12); return result; } private static byte[] makeConstructorCode(List pool) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); write2(out, 2); // max stack write2(out, 2); // max locals write4(out, 10); // length write1(out, aload_0); write1(out, invokespecial); write2(out, ConstantPool.addMethodRef (pool, "java/lang/reflect/Proxy", "", "()V") + 1); write1(out, aload_0); write1(out, aload_1); write1(out, putfield); write2(out, ConstantPool.addFieldRef (pool, "java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;") + 1); write1(out, return_); write2(out, 0); // exception handler table length write2(out, 0); // attribute count return out.toByteArray(); } private static Class makeClass(ClassLoader loader, Class[] interfaces, String name) throws IOException { List pool = new ArrayList(); int[] interfaceIndexes = new int[interfaces.length]; for (int i = 0; i < interfaces.length; ++i) { interfaceIndexes[i] = ConstantPool.addClass (pool, interfaces[i].getName().replace('.', '/')); } Set specs = new HashSet(); List methodTable = new ArrayList(); List refs = new ArrayList(); for (Class c: interfaces) { avian.VMMethod[] ivtable = SystemClassLoader.vmClass(c).virtualTable; if (ivtable != null) { for (avian.VMMethod m: ivtable) { String spec = Classes.toString(m.name) + Classes.toString(m.spec); if (specs.contains(spec)) { continue; } methodTable.add(new MethodData (Modifier.PUBLIC, ConstantPool.addUtf8(pool, Classes.toString(m.name)), ConstantPool.addUtf8(pool, Classes.toString(m.spec)), makeInvokeCode(pool, name, m.spec, m.parameterCount, m.parameterFootprint, methodTable.size()))); refs.add(Classes.makeMethod(m)); } } } methodTable.add(new MethodData (Modifier.PUBLIC, ConstantPool.addUtf8(pool, ""), ConstantPool.addUtf8 (pool, "(Ljava/lang/reflect/InvocationHandler;)V"), makeConstructorCode(pool))); int nameIndex = ConstantPool.addClass(pool, name); int superIndex = ConstantPool.addClass(pool, "java/lang/reflect/Proxy"); ByteArrayOutputStream out = new ByteArrayOutputStream(); Assembler.writeClass (out, pool, nameIndex, superIndex, interfaceIndexes, methodTable.toArray(new MethodData[methodTable.size()])); byte[] classData = out.toByteArray(); Class result = avian.SystemClassLoader.getClass (avian.Classes.defineVMClass(loader, classData, 0, classData.length)); methodRefsMap.put(result, refs.toArray(new Method[refs.size()])); return result; } public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler handler) { try { return Proxy.getProxyClass(loader, interfaces) .getConstructor(new Class[] { InvocationHandler.class }) .newInstance(new Object[] { handler }); } catch (Exception e) { AssertionError error = new AssertionError(); error.initCause(e); throw error; } } } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/SignatureParser.java000066400000000000000000000070241231440243200264140ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; import java.util.ArrayList; import java.util.List; class SignatureParser { private final ClassLoader loader; private final char[] array; private int offset; private final Type type; static Type parse(ClassLoader loader, String signature) { return new SignatureParser(loader, signature).type; } private SignatureParser(ClassLoader loader, String signature) { this.loader = loader; array = signature.toCharArray(); type = parseType(); if (offset != array.length) { throw new IllegalArgumentException("Extra characters after " + offset + ": " + signature); } } private Type parseType() { char c = array[offset++]; if (c == 'B') { return Byte.TYPE; } else if (c == 'C') { return Character.TYPE; } else if (c == 'D') { return Double.TYPE; } else if (c == 'F') { return Float.TYPE; } else if (c == 'I') { return Integer.TYPE; } else if (c == 'J') { return Long.TYPE; } else if (c == 'S') { return Short.TYPE; } else if (c == 'Z') { return Boolean.TYPE; } else if (c != 'L') { throw new IllegalArgumentException("Unexpected character: " + c); } StringBuilder builder = new StringBuilder(); Type ownerType = null; for (;;) { for (;;) { c = array[offset++]; if (c == ';' || c == '<') { break; } builder.append(c == '/' ? '.' : c); } String rawTypeName = builder.toString(); Class rawType; try { rawType = loader.loadClass(rawTypeName); } catch (ClassNotFoundException e) { throw new RuntimeException("Could not find class " + rawTypeName); } if (c == ';') { return rawType; } List args = new ArrayList(); while (array[offset] != '>') { args.add(parseType()); } ++offset; c = array[offset++]; ParameterizedType type = makeType(args.toArray(new Type[args.size()]), ownerType, rawType); if (c == ';') { return type; } if (c != '.') { throw new RuntimeException("TODO"); } ownerType = type; builder.append("$"); } } private static String typeName(Type type) { if (type instanceof Class) { Class clazz = (Class) type; return clazz.getName(); } return type.toString(); } private static ParameterizedType makeType(final Type[] args, final Type owner, final Type raw) { return new ParameterizedType() { @Override public Type getRawType() { return raw; } @Override public Type getOwnerType() { return owner; } @Override public Type[] getActualTypeArguments() { return args; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append(typeName(raw)); builder.append('<'); String sep = ""; for (Type t : args) { builder.append(sep).append(typeName(t)); sep = ", "; } builder.append('>'); return builder.toString(); } }; } } ReadyTalk-avian-1e1fff5/classpath/java/lang/reflect/Type.java000066400000000000000000000006251231440243200242170ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.lang.reflect; public interface Type { } ReadyTalk-avian-1e1fff5/classpath/java/math/000077500000000000000000000000001231440243200210145ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/math/BigInteger.java000066400000000000000000000023601231440243200236770ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.math; import java.io.Serializable; public class BigInteger implements Serializable { private int sign; private int[] value; private BigInteger(int sign, long value) { this.sign = sign; int upperBits = (int) (value >>> 32); if (upperBits == 0) // Array with one element this.value = new int[] { (int) value }; else // Array with two elements this.value = new int[] { (int) value, upperBits }; } public static final BigInteger ZERO = new BigInteger(0, 0); public static final BigInteger ONE = new BigInteger(1, 1); public static final BigInteger TEN = new BigInteger(1, 10); public static BigInteger valueOf(long num) { int signum = Long.signum(num); if (signum == 0) return BigInteger.ZERO; else if (signum > 0) return new BigInteger(signum, num); else return new BigInteger(signum, -num); } } ReadyTalk-avian-1e1fff5/classpath/java/math/MathContext.java000066400000000000000000000040641231440243200241210ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.math; import java.io.Serializable; public final class MathContext implements Serializable { public static final MathContext DECIMAL32 = new MathContext( 7, RoundingMode.HALF_EVEN); public static final MathContext DECIMAL64 = new MathContext(16, RoundingMode.HALF_EVEN); public static final MathContext DECIMAL128 = new MathContext(34, RoundingMode.HALF_EVEN); public static final MathContext UNLIMITED = new MathContext(0, RoundingMode.HALF_UP); private int precision; private RoundingMode roundingMode; public MathContext(int precision, RoundingMode roundingMode) { if (precision < 0) throw new IllegalArgumentException(); if (roundingMode == null) throw new NullPointerException(); this.precision = precision; this.roundingMode = roundingMode; } public MathContext(int precision) { this(precision, RoundingMode.HALF_UP); } public int getPrecision() { return precision; } public RoundingMode getRoundingMode() { return roundingMode; } @Override public boolean equals(Object that) { return (that instanceof MathContext) && (precision == ((MathContext) that).getPrecision()) && (roundingMode == ((MathContext) that).getRoundingMode()); } @Override public int hashCode() { return roundingMode.ordinal() | (precision << 4); } private final static String precisionString = "precision="; private final static String roundingModeString = " roundingMode="; @Override public String toString() { StringBuilder sb = new StringBuilder(48); sb.append(precisionString).append(precision); sb.append(roundingModeString).append(roundingMode); return sb.toString(); } } ReadyTalk-avian-1e1fff5/classpath/java/math/RoundingMode.java000066400000000000000000000015531231440243200242550ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.math; public enum RoundingMode { UP (0), DOWN (1), CEILING (2), FLOOR (3), HALF_UP (4), HALF_DOWN (5), HALF_EVEN (6), UNNECESSARY(7); RoundingMode(int rm) { roundingMode = rm; } private final int roundingMode; public static RoundingMode valueOf(int roundingMode) { final RoundingMode[] values = values(); if (roundingMode < 0 || roundingMode >= values.length) throw new IllegalArgumentException(); return values[roundingMode]; } } ReadyTalk-avian-1e1fff5/classpath/java/net/000077500000000000000000000000001231440243200206515ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/net/DatagramSocket.java000066400000000000000000000010761231440243200244110ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.IOException; public abstract class DatagramSocket { public abstract SocketAddress getRemoteSocketAddress(); public abstract void bind(SocketAddress address) throws SocketException; } ReadyTalk-avian-1e1fff5/classpath/java/net/InetAddress.java000066400000000000000000000032671231440243200237310ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.IOException; public class InetAddress { private final String name; private final int ip; private InetAddress(String name) throws UnknownHostException { this.name = name; this.ip = ipv4AddressForName(name); } public String getHostName() { return name; } public String getHostAddress() { try { return new InetAddress(name).toString(); } catch (UnknownHostException e) { return null; // Strange case } } public static InetAddress getByName(String name) throws UnknownHostException { try { Socket.init(); return new InetAddress(name); } catch (IOException e) { UnknownHostException uhe = new UnknownHostException(name); uhe.initCause(e); throw uhe; } } public byte[] getAddress() { byte[] res = new byte[4]; res[0] = (byte) ( ip >>> 24); res[1] = (byte) ((ip >>> 16) & 0xFF); res[2] = (byte) ((ip >>> 8 ) & 0xFF); res[3] = (byte) ((ip ) & 0xFF); return res; } @Override public String toString() { byte[] addr = getAddress(); return (int)((addr[0] + 256) % 256) + "." + (int)((addr[1] + 256) % 256) + "." + (int)((addr[2] + 256) % 256) + "." + (int)((addr[3] + 256) % 256); } int getRawAddress() { return ip; } static native int ipv4AddressForName(String name); } ReadyTalk-avian-1e1fff5/classpath/java/net/InetSocketAddress.java000066400000000000000000000016521231440243200250760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; public class InetSocketAddress extends SocketAddress { private final InetAddress address; private final int port; public InetSocketAddress(String host, int port) throws UnknownHostException { this.address = InetAddress.getByName(host); this.port = port; } public InetSocketAddress(InetAddress address, int port) { this.address = address; this.port = port; } public InetAddress getAddress() { return address; } public String getHostName() { return address.getHostName(); } public int getPort() { return port; } } ReadyTalk-avian-1e1fff5/classpath/java/net/JarURLConnection.java000066400000000000000000000011431231440243200246320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.IOException; import java.util.jar.JarFile; public abstract class JarURLConnection extends URLConnection { public JarURLConnection(URL url) { super(url); } public abstract JarFile getJarFile() throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/net/MalformedURLException.java000066400000000000000000000010541231440243200256640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; public class MalformedURLException extends Exception { public MalformedURLException(String message) { super(message); } public MalformedURLException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/net/ProtocolFamily.java000066400000000000000000000006261231440243200244630ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; public interface ProtocolFamily { } ReadyTalk-avian-1e1fff5/classpath/java/net/ServerSocket.java000066400000000000000000000007751231440243200241440ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.IOException; public abstract class ServerSocket { public abstract void bind(SocketAddress address) throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/net/Socket.java000066400000000000000000000116061231440243200227500ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class Socket implements Closeable, AutoCloseable { private static final int SD_RECEIVE = 0x00; private static final int SD_SEND = 0x01; private static final int SD_BOTH = 0x02; private static final int BUFFER_SIZE = 65535; /** * This method is called from all routines that depend on winsock in windows, * so it has public visibility * @throws IOException */ public static native void init() throws IOException; /** * Creates the native socket object * @return Handle to the native object * @throws IOException */ private static native /* SOCKET */long create() throws IOException; /** * Connects the native socket object to an address:port * @param sock Native socket handler * @param addr Address to connect to * @param port Port to connect to * @throws IOException */ private static native void connect(/* SOCKET */long sock, long addr, short port) throws IOException; private static native void bind(/* SOCKET */long sock, long addr, short port) throws IOException; private static native void send(/* SOCKET */long sock, byte[] buffer, int start_pos, int count) throws IOException; private static native int recv(/* SOCKET */long sock, byte[] buffer, int start_pos, int count) throws IOException; private static native void abort(/* SOCKET */long sock); private static native void close(/* SOCKET */long sock); private static native void closeOutput(/* SOCKET */long sock); private static native void closeInput(/* SOCKET */long sock); private class SocketInputStream extends InputStream { private boolean closed = false; @Override public void close() throws IOException { if (!closed) { closeInput(sock); closed = true; } super.close(); } @Override protected void finalize() throws Throwable { close(); super.finalize(); } @Override public int read() throws IOException { byte[] buffer = new byte[1]; int size = recv(sock, buffer, 0, 1); if (size == 0) { return -1; } return buffer[0]; } @Override public int read(byte[] buffer) throws IOException { int fullSize = buffer.length; int index = 0; int size; do { size = recv(sock, buffer, index, Math.min(fullSize, Socket.BUFFER_SIZE)); fullSize -= size; index += size; } while (fullSize != 0 && size != 0); return index; } } private class SocketOutputStream extends OutputStream { private boolean closed = false; @Override public void close() throws IOException { if (!closed) { closeOutput(sock); closed = true; } super.close(); } @Override protected void finalize() throws Throwable { close(); super.finalize(); } @Override public void write(int c) throws IOException { byte[] res = new byte[1]; res[0] = (byte)c; send(sock, res, 0, 1); } @Override public void write(byte[] buffer) throws IOException { int fullSize = buffer.length; int index = 0; int size; do { size = Math.min(fullSize, Socket.BUFFER_SIZE); send(sock, buffer, index, size); fullSize -= size; index += size; } while (fullSize != 0 && size != 0); } } private long sock; private SocketInputStream inputStream; private SocketOutputStream outputStream; public Socket() throws IOException { Socket.init(); sock = create(); inputStream = new SocketInputStream(); outputStream = new SocketOutputStream(); } public SocketInputStream getInputStream() { return inputStream; } public SocketOutputStream getOutputStream() { return outputStream; } public Socket(InetAddress address, int port) throws IOException { this(); connect(sock, address.getRawAddress(), (short)port); } public Socket(String host, int port) throws UnknownHostException, IOException { this(InetAddress.getByName(host), port); } public void bind(SocketAddress bindpoint) throws IOException { if (bindpoint instanceof InetSocketAddress) { InetSocketAddress inetBindpoint = (InetSocketAddress)bindpoint; bind(sock, inetBindpoint.getAddress().getRawAddress(), (short) inetBindpoint.getPort()); } } public void setTcpNoDelay(boolean on) throws SocketException {} @Override public void close() throws IOException { close(sock); } public void shutdownInput() throws IOException { inputStream.close(); } public void shutdownOutput() throws IOException { outputStream.close(); } @Override protected void finalize() throws Throwable { close(); super.finalize(); } } ReadyTalk-avian-1e1fff5/classpath/java/net/SocketAddress.java000066400000000000000000000006321231440243200242530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; public abstract class SocketAddress { } ReadyTalk-avian-1e1fff5/classpath/java/net/SocketException.java000066400000000000000000000010711231440243200246220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.IOException; public class SocketException extends IOException { public SocketException(String message) { super(message); } public SocketException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/net/StandardProtocolFamily.java000066400000000000000000000006731231440243200261460ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; public enum StandardProtocolFamily implements ProtocolFamily { INET; } ReadyTalk-avian-1e1fff5/classpath/java/net/URL.java000066400000000000000000000052151231440243200221610ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.IOException; import java.io.InputStream; public final class URL { private final URLStreamHandler handler; private String protocol; private String host; private int port; private String file; private String path; private String query; private String ref; public URL(String s) throws MalformedURLException { int colon = s.indexOf(':'); int slash = s.indexOf('/'); if (colon > 0 && (slash < 0 || colon < slash)) { handler = findHandler(s.substring(0, colon)); handler.parseURL(this, s, colon + 1, s.length()); } else { throw new MalformedURLException(s); } } public String toString() { return handler.toExternalForm(this); } public String getProtocol() { return protocol; } public String getHost() { return host; } public int getPort() { return port; } public String getFile() { return file; } public String getRef() { return ref; } public String getPath() { return path; } public String getQuery() { return query; } public URLConnection openConnection() throws IOException { return handler.openConnection(this); } public InputStream openStream() throws IOException { return openConnection().getInputStream(); } public Object getContent() throws IOException { return openStream(); } private static URLStreamHandler findHandler(String protocol) throws MalformedURLException { if ("http".equals(protocol) || "https".equals(protocol)) { return new avian.http.Handler(); } else if ("avianvmresource".equals(protocol)) { return new avian.avianvmresource.Handler(); } else if ("file".equals(protocol)) { return new avian.file.Handler(); } else if ("jar".equals(protocol)) { return new avian.jar.Handler(); } else { throw new MalformedURLException("unknown protocol: " + protocol); } } public void set(String protocol, String host, int port, String file, String ref) { this.protocol = protocol; this.host = host; this.port = port; this.file = file; this.ref = ref; int q = file.lastIndexOf('?'); if (q != -1) { this.query = file.substring(q + 1); this.path = file.substring(0, q); } else { this.path = file; } } } ReadyTalk-avian-1e1fff5/classpath/java/net/URLClassLoader.java000066400000000000000000000030051231440243200242710ustar00rootroot00000000000000package java.net; import java.io.File; import java.io.InputStream; import java.io.IOException; import java.io.ByteArrayOutputStream; public class URLClassLoader extends ClassLoader { private final File jarFile; public URLClassLoader(URL[] urls, ClassLoader parent) { super(parent); if(urls.length != 1) { throw new UnsupportedOperationException(); } if(!urls[0].getProtocol().equals("file")) { throw new UnsupportedOperationException(urls[0].getProtocol()); } this.jarFile = new File(urls[0].getFile()); } protected Class findClass(String name) throws ClassNotFoundException { try { InputStream stream = getResourceAsStream(name.replace(".", "/") + ".class"); if(stream == null) { throw new ClassNotFoundException("couldn't find class " + name); } byte[] buf = new byte[2048]; ByteArrayOutputStream mem = new ByteArrayOutputStream(); try { int size; while((size = stream.read(buf, 0, buf.length)) > 0) { mem.write(buf, 0, size); } byte[] data = mem.toByteArray(); return defineClass(name, data, 0, data.length); } finally { stream.close(); } } catch(IOException e) { throw new ClassNotFoundException("couldn't find class " + name, e); } } public URL getResource(String path) { try { return new URL("jar:file:" + jarFile.getAbsolutePath() + "!/" + path); } catch(MalformedURLException e) { throw new RuntimeException(e); } } }ReadyTalk-avian-1e1fff5/classpath/java/net/URLConnection.java000066400000000000000000000025721231440243200242040ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public abstract class URLConnection { protected final URL url; protected boolean doInput = true; protected boolean doOutput = false; protected boolean useCaches = true; protected URLConnection(URL url) { this.url = url; } public Object getContent() throws IOException { return getInputStream(); } public int getContentLength() { return -1; } public abstract void connect() throws IOException; public InputStream getInputStream() throws IOException { throw new UnknownServiceException(); } public OutputStream getOutputStream() throws IOException { throw new UnknownServiceException(); } public boolean getDoInput() { return doInput; } public boolean getDoOutput() { return doOutput; } public void setDoInput(boolean v) { doInput = v; } public void setDoOutput(boolean v) { doInput = v; } public void setUseCaches(boolean v) { useCaches = v; } } ReadyTalk-avian-1e1fff5/classpath/java/net/URLStreamHandler.java000066400000000000000000000042171231440243200246340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.IOException; public abstract class URLStreamHandler { protected void parseURL(URL url, String s, int start, int end) throws MalformedURLException { String protocol = s.substring(0, start - 1); s = s.substring(start, end); String host = null; int port = -1; if (s.startsWith("//")) { s = s.substring(2); int colon = s.indexOf(':'); int slash = s.indexOf('/'); if (slash < 0) { if (colon < 0) { host = s; } else { host = s.substring(0, colon); port = Integer.parseInt(s.substring(colon + 1)); } s = ""; } else { if (colon < 0 || colon > slash) { host = s.substring(0, slash); } else { host = s.substring(0, colon); port = Integer.parseInt(s.substring(colon + 1, slash)); } s = s.substring(slash); } } String file = null; if (s.length() > 0) { file = s; } url.set(protocol, host, port, file, null); } private static boolean equals(String a, String b) { return (a == null && b == null) || (a != null && a.equals(b)); } protected boolean equals(URL a, URL b) { return equals(a.getHost(), b.getHost()) && (a.getPort() == b.getPort()) && equals(a.getFile(), b.getFile()); } protected String toExternalForm(URL url) { StringBuilder sb = new StringBuilder(); sb.append(url.getProtocol()).append(":"); if (url.getHost() != null) { sb.append("//").append(url.getHost()); if (url.getPort() >= 0) { sb.append(":").append(url.getPort()); } } if (url.getFile() != null) { sb.append(url.getFile()); } return sb.toString(); } protected abstract URLConnection openConnection(URL url) throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/net/UnknownHostException.java000066400000000000000000000010601231440243200256650ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.IOException; public class UnknownHostException extends IOException { public UnknownHostException(String host) { super(host); } public UnknownHostException() { } } ReadyTalk-avian-1e1fff5/classpath/java/net/UnknownServiceException.java000066400000000000000000000011211231440243200263460ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.net; import java.io.IOException; public class UnknownServiceException extends IOException { public UnknownServiceException(String message) { super(message); } public UnknownServiceException() { this(null); } } ReadyTalk-avian-1e1fff5/classpath/java/nio/000077500000000000000000000000001231440243200206505ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/nio/ArrayByteBuffer.java000066400000000000000000000042561231440243200245560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio; class ArrayByteBuffer extends ByteBuffer { private final byte[] array; private final int arrayOffset; ArrayByteBuffer(byte[] array, int offset, int length, boolean readOnly) { super(readOnly); this.array = array; this.arrayOffset = offset; this.capacity = length; this.limit = length; this.position = 0; } public ByteBuffer asReadOnlyBuffer() { ByteBuffer b = new ArrayByteBuffer(array, arrayOffset, capacity, true); b.position(position()); b.limit(limit()); return b; } public boolean hasArray() { return true; } public byte[] array() { return array; } public ByteBuffer slice() { return new ArrayByteBuffer (array, arrayOffset + position, remaining(), true); } public int arrayOffset() { return arrayOffset; } protected void doPut(int position, byte val) { array[arrayOffset + position] = val; } public ByteBuffer put(ByteBuffer src) { int length = src.remaining(); checkPut(position, length); src.get(array, arrayOffset + position, length); position += length; return this; } public ByteBuffer put(byte[] src, int offset, int length) { checkPut(position, length); System.arraycopy(src, offset, array, arrayOffset + position, length); position += length; return this; } public ByteBuffer get(byte[] dst, int offset, int length) { checkGet(position, length); System.arraycopy(array, arrayOffset + position, dst, offset, length); position += length; return this; } protected byte doGet(int position) { return array[arrayOffset+position]; } public String toString() { return "(ArrayByteBuffer with array: " + array + " arrayOffset: " + arrayOffset + " position: " + position + " limit: " + limit + " capacity: " + capacity + ")"; } } ReadyTalk-avian-1e1fff5/classpath/java/nio/Buffer.java000066400000000000000000000023201231440243200227210ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio; public abstract class Buffer { protected int capacity; protected int position; protected int limit; public final int limit() { return limit; } public final int remaining() { return limit-position; } public final int position() { return position; } public final int capacity() { return capacity; } public final Buffer limit(int newLimit) { limit = newLimit; return this; } public final Buffer position(int newPosition) { position = newPosition; return this; } public final boolean hasRemaining() { return remaining() > 0; } public final Buffer clear() { position = 0; limit = capacity; return this; } public final Buffer flip() { limit = position; position = 0; return this; } public final Buffer rewind() { position = 0; return this; } } ReadyTalk-avian-1e1fff5/classpath/java/nio/BufferUnderflowException.java000066400000000000000000000006651231440243200265000ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio; public class BufferUnderflowException extends RuntimeException { } ReadyTalk-avian-1e1fff5/classpath/java/nio/ByteBuffer.java000066400000000000000000000144251231440243200235560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio; public abstract class ByteBuffer extends Buffer implements Comparable { private final boolean readOnly; protected ByteBuffer(boolean readOnly) { this.readOnly = readOnly; } public static ByteBuffer allocate(int capacity) { return new ArrayByteBuffer(new byte[capacity], 0, capacity, false); } public static ByteBuffer allocateDirect(int capacity) { return FixedArrayByteBuffer.make(capacity); } public static ByteBuffer wrap(byte[] array) { return wrap(array, 0, array.length); } public static ByteBuffer wrap(byte[] array, int offset, int length) { return new ArrayByteBuffer(array, offset, length, false); } public abstract ByteBuffer asReadOnlyBuffer(); public abstract ByteBuffer slice(); protected abstract void doPut(int offset, byte val); public abstract ByteBuffer put(byte[] arr, int offset, int len); protected abstract byte doGet(int offset); public abstract ByteBuffer get(byte[] dst, int offset, int length); public boolean hasArray() { return false; } public ByteBuffer compact() { int remaining = remaining(); if (position != 0) { ByteBuffer b = slice(); position = 0; put(b); } position = remaining; limit(capacity()); return this; } public ByteBuffer put(ByteBuffer src) { if (src.hasArray()) { checkPut(position, src.remaining()); put(src.array(), src.arrayOffset() + src.position, src.remaining()); src.position(src.position() + src.remaining()); return this; } else { byte[] buffer = new byte[src.remaining()]; src.get(buffer); return put(buffer); } } public int compareTo(ByteBuffer o) { int end = (remaining() < o.remaining() ? remaining() : o.remaining()); for (int i = 0; i < end; ++i) { int d = get(position + i) - o.get(o.position + i); if (d != 0) { return d; } } return remaining() - o.remaining(); } public boolean equals(Object o) { return o instanceof ByteBuffer && compareTo((ByteBuffer) o) == 0; } public byte[] array() { throw new UnsupportedOperationException(); } public int arrayOffset() { throw new UnsupportedOperationException(); } public ByteBuffer put(int offset, byte val) { checkPut(offset, 1); doPut(offset, val); return this; } public ByteBuffer put(byte val) { put(position, val); ++ position; return this; } public ByteBuffer put(byte[] arr) { return put(arr, 0, arr.length); } public ByteBuffer putLong(int position, long val) { checkPut(position, 8); doPut(position , (byte) ((val >> 56) & 0xff)); doPut(position + 1, (byte) ((val >> 48) & 0xff)); doPut(position + 2, (byte) ((val >> 40) & 0xff)); doPut(position + 3, (byte) ((val >> 32) & 0xff)); doPut(position + 4, (byte) ((val >> 24) & 0xff)); doPut(position + 5, (byte) ((val >> 16) & 0xff)); doPut(position + 6, (byte) ((val >> 8) & 0xff)); doPut(position + 7, (byte) ((val ) & 0xff)); return this; } public ByteBuffer putInt(int position, int val) { checkPut(position, 4); doPut(position , (byte) ((val >> 24) & 0xff)); doPut(position + 1, (byte) ((val >> 16) & 0xff)); doPut(position + 2, (byte) ((val >> 8) & 0xff)); doPut(position + 3, (byte) ((val ) & 0xff)); return this; } public ByteBuffer putShort(int position, short val) { checkPut(position, 2); doPut(position , (byte) ((val >> 8) & 0xff)); doPut(position + 1, (byte) ((val ) & 0xff)); return this; } public ByteBuffer putLong(long val) { putLong(position, val); position += 8; return this; } public ByteBuffer putInt(int val) { putInt(position, val); position += 4; return this; } public ByteBuffer putShort(short val) { putShort(position, val); position += 2; return this; } public byte get() { return get(position++); } public byte get(int position) { checkGet(position, 1); return doGet(position); } public ByteBuffer get(byte[] dst) { return get(dst, 0, dst.length); } public long getLong(int position) { checkGet(position, 8); return (((long) (doGet(position ) & 0xFF)) << 56) | (((long) (doGet(position + 1) & 0xFF)) << 48) | (((long) (doGet(position + 2) & 0xFF)) << 40) | (((long) (doGet(position + 3) & 0xFF)) << 32) | (((long) (doGet(position + 4) & 0xFF)) << 24) | (((long) (doGet(position + 5) & 0xFF)) << 16) | (((long) (doGet(position + 6) & 0xFF)) << 8) | (((long) (doGet(position + 7) & 0xFF)) ); } public int getInt(int position) { checkGet(position, 4); return (((int) (doGet(position ) & 0xFF)) << 24) | (((int) (doGet(position + 1) & 0xFF)) << 16) | (((int) (doGet(position + 2) & 0xFF)) << 8) | (((int) (doGet(position + 3) & 0xFF)) ); } public short getShort(int position) { checkGet(position, 2); return (short) (( ((int) (doGet(position ) & 0xFF)) << 8) | (((int) (doGet(position + 1) & 0xFF)) )); } public long getLong() { long r = getLong(position); position += 8; return r; } public int getInt() { int r = getInt(position); position += 4; return r; } public short getShort() { short r = getShort(position); position += 2; return r; } protected void checkPut(int position, int amount) { if (readOnly) throw new ReadOnlyBufferException(); if (position < 0 || position+amount > limit) throw new IndexOutOfBoundsException(); } protected void checkGet(int position, int amount) { if (amount > limit-position) throw new IndexOutOfBoundsException(); } public ByteBuffer order(ByteOrder order) { if (order != ByteOrder.BIG_ENDIAN) throw new UnsupportedOperationException(); return this; } public ByteOrder order() { return ByteOrder.BIG_ENDIAN; } } ReadyTalk-avian-1e1fff5/classpath/java/nio/ByteOrder.java000066400000000000000000000020041231440243200234060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio; public final class ByteOrder { public static final ByteOrder BIG_ENDIAN = new ByteOrder("BIG_ENDIAN"); public static final ByteOrder LITTLE_ENDIAN = new ByteOrder("LITTLE_ENDIAN"); private static final ByteOrder NATIVE; private static native boolean isNativeBigEndian(); static { if (isNativeBigEndian()) NATIVE = BIG_ENDIAN; else NATIVE = LITTLE_ENDIAN; } private String name; private ByteOrder(String name) { this.name = name; } public String toString() { return name; } public static ByteOrder nativeOrder() { return NATIVE; } } ReadyTalk-avian-1e1fff5/classpath/java/nio/DirectByteBuffer.java000066400000000000000000000051511231440243200247050ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio; import sun.misc.Unsafe; class DirectByteBuffer extends ByteBuffer { private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final int baseOffset = unsafe.arrayBaseOffset(byte[].class); protected final long address; protected DirectByteBuffer(long address, int capacity, boolean readOnly) { super(readOnly); this.address = address; this.capacity = capacity; this.limit = capacity; this.position = 0; } protected DirectByteBuffer(long address, int capacity) { this(address, capacity, false); } public ByteBuffer asReadOnlyBuffer() { ByteBuffer b = new DirectByteBuffer(address, capacity, true); b.position(position()); b.limit(limit()); return b; } public ByteBuffer slice() { return new DirectByteBuffer(address + position, remaining(), true); } protected void doPut(int position, byte val) { unsafe.putByte(address + position, val); } public ByteBuffer put(ByteBuffer src) { if (src instanceof DirectByteBuffer) { checkPut(position, src.remaining()); DirectByteBuffer b = (DirectByteBuffer) src; unsafe.copyMemory (b.address + b.position, address + position, b.remaining()); position += b.remaining(); b.position += b.remaining(); return this; } else { return super.put(src); } } public ByteBuffer put(byte[] src, int offset, int length) { if (offset < 0 || offset + length > src.length) { throw new ArrayIndexOutOfBoundsException(); } checkPut(position, length); unsafe.copyMemory (src, baseOffset + offset, null, address + position, length); position += length; return this; } public ByteBuffer get(byte[] dst, int offset, int length) { if (offset < 0 || offset + length > dst.length) { throw new ArrayIndexOutOfBoundsException(); } checkGet(position, length); unsafe.copyMemory (null, address + position, dst, baseOffset + offset, length); return this; } protected byte doGet(int position) { return unsafe.getByte(address + position); } public String toString() { return "(DirectByteBuffer with address: " + address + " position: " + position + " limit: " + limit + " capacity: " + capacity + ")"; } } ReadyTalk-avian-1e1fff5/classpath/java/nio/FixedArrayByteBuffer.java000066400000000000000000000033201231440243200255250ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio; class FixedArrayByteBuffer extends DirectByteBuffer { private final byte[] array; private final int arrayOffset; private FixedArrayByteBuffer(long address, byte[] array, int offset, int capacity, boolean readOnly) { super(address, capacity, readOnly); this.array = array; this.arrayOffset = offset; } public static FixedArrayByteBuffer make(int capacity) { long[] address = new long[1]; byte[] array = allocateFixed(capacity, address); return new FixedArrayByteBuffer(address[0], array, 0, capacity, false); } private static native byte[] allocateFixed(int capacity, long[] address); public ByteBuffer asReadOnlyBuffer() { ByteBuffer b = new FixedArrayByteBuffer (address, array, arrayOffset, capacity, true); b.position(position()); b.limit(limit()); return b; } public ByteBuffer slice() { return new FixedArrayByteBuffer (address + position, array, arrayOffset + position, remaining(), true); } public String toString() { return "(FixedArrayByteBuffer with address: " + address + " array: " + array + " arrayOffset: " + arrayOffset + " position: " + position + " limit: " + limit + " capacity: " + capacity + ")"; } } ReadyTalk-avian-1e1fff5/classpath/java/nio/ReadOnlyBufferException.java000066400000000000000000000007011231440243200262370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio; public class ReadOnlyBufferException extends UnsupportedOperationException { } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/000077500000000000000000000000001231440243200224435ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/Channel.java000066400000000000000000000007721231440243200246640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; public interface Channel { public void close() throws IOException; public boolean isOpen(); } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/Channels.java000066400000000000000000000066361231440243200250540ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; public class Channels { public static InputStream newInputStream(ReadableByteChannel channel) { return new MyInputStream(channel); } public static OutputStream newOutputStream(WritableByteChannel channel) { return new MyOutputStream(channel); } public static ReadableByteChannel newChannel(InputStream stream) { return new InputStreamChannel(stream); } public static WritableByteChannel newChannel(OutputStream stream) { return new OutputStreamChannel(stream); } private static class MyInputStream extends InputStream { private final ReadableByteChannel channel; public MyInputStream(ReadableByteChannel channel) { this.channel = channel; } public int read() throws IOException { byte[] buffer = new byte[1]; int r = read(buffer); if (r == -1) { return -1; } else { return buffer[0] & 0xFF; } } public int read(byte[] buffer, int offset, int length) throws IOException { return channel.read(ByteBuffer.wrap(buffer, offset, length)); } public void close() throws IOException { channel.close(); } } private static class MyOutputStream extends OutputStream { private final WritableByteChannel channel; public MyOutputStream(WritableByteChannel channel) { this.channel = channel; } public void write(int v) throws IOException { byte[] buffer = new byte[] { (byte) (v & 0xFF) }; write(buffer); } public void write(byte[] buffer, int offset, int length) throws IOException { channel.write(ByteBuffer.wrap(buffer, offset, length)); } public void close() throws IOException { channel.close(); } } private static class InputStreamChannel implements ReadableByteChannel { private InputStream stream; public InputStreamChannel(InputStream stream) { this.stream = stream; } public void close() throws IOException { if (stream != null) { stream.close(); stream = null; } } public boolean isOpen() { return stream != null; } public int read(ByteBuffer b) throws IOException { int c = stream.read (b.array(), b.arrayOffset() + b.position(), b.remaining()); if (c > 0) { b.position(b.position() + c); } return c; } } private static class OutputStreamChannel implements WritableByteChannel { private OutputStream stream; public OutputStreamChannel(OutputStream stream) { this.stream = stream; } public void close() throws IOException { if (stream != null) { stream.close(); stream = null; } } public boolean isOpen() { return stream != null; } public int write(ByteBuffer b) throws IOException { stream.write(b.array(), b.arrayOffset() + b.position(), b.remaining()); int c = b.remaining(); b.position(b.limit()); return c; } } } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/ClosedSelectorException.java000066400000000000000000000007021231440243200300760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; public class ClosedSelectorException extends IllegalStateException { } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/DatagramChannel.java000066400000000000000000000123111231440243200263150ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.net.SocketAddress; import java.net.InetSocketAddress; import java.net.ProtocolFamily; import java.net.Socket; import java.net.SocketException; import java.net.DatagramSocket; import java.net.StandardProtocolFamily; // TODO: This class is both divergent from the Java standard and incomplete. public class DatagramChannel extends SelectableChannel implements ReadableByteChannel, WritableByteChannel { public static final int InvalidSocket = -1; private int socket = InvalidSocket; private boolean blocking = true; private boolean connected = false; public SelectableChannel configureBlocking(boolean v) throws IOException { blocking = v; configureBlocking(); return this; } private void configureBlocking() throws IOException { if (socket != InvalidSocket) { configureBlocking(socket, blocking); } } int socketFD() { return socket; } void handleReadyOps(int ops) { // ignore } public static DatagramChannel open(ProtocolFamily family) throws IOException { if (family.equals(StandardProtocolFamily.INET)) { Socket.init(); return new DatagramChannel(); } else { throw new UnsupportedOperationException(); } } public static DatagramChannel open() throws IOException { return open(StandardProtocolFamily.INET); } public DatagramSocket socket() { return new Handle(); } public DatagramChannel bind(SocketAddress address) throws IOException { InetSocketAddress inetAddress; try { inetAddress = (InetSocketAddress) address; } catch (ClassCastException e) { throw new UnsupportedAddressTypeException(); } socket = bind(inetAddress.getHostName(), inetAddress.getPort()); configureBlocking(); return this; } public DatagramChannel connect(SocketAddress address) throws IOException { InetSocketAddress inetAddress; try { inetAddress = (InetSocketAddress) address; } catch (ClassCastException e) { throw new UnsupportedAddressTypeException(); } socket = connect(inetAddress.getHostName(), inetAddress.getPort()); configureBlocking(); if (socket != 0) connected = true; return this; } public int write(ByteBuffer b) throws IOException { if (b.remaining() == 0) return 0; byte[] array = b.array(); if (array == null) throw new NullPointerException(); int c = write (socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking); if (c > 0) { b.position(b.position() + c); } return c; } public int read(ByteBuffer b) throws IOException { int p = b.position(); receive(b); return b.position() - p; } public SocketAddress receive(ByteBuffer b) throws IOException { if (b.remaining() == 0) return null; byte[] array = b.array(); if (array == null) throw new NullPointerException(); int[] address = new int[2]; int c = receive (socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking, address); if (c > 0) { b.position(b.position() + c); return new InetSocketAddress(ipv4ToString(address[0]), address[1]); } else { return null; } } private static String ipv4ToString(int address) { StringBuilder sb = new StringBuilder(); sb.append( address >> 24 ).append('.') .append((address >> 16) & 0xFF).append('.') .append((address >> 8) & 0xFF).append('.') .append( address & 0xFF); return sb.toString(); } public class Handle extends DatagramSocket { public SocketAddress getRemoteSocketAddress() { throw new UnsupportedOperationException(); } public void bind(SocketAddress address) throws SocketException { try { DatagramChannel.this.bind(address); } catch (SocketException e) { throw e; } catch (IOException e) { SocketException se = new SocketException(); se.initCause(e); throw se; } } } public boolean isConnected() { return connected; } /** TODO: This is probably incomplete. */ public DatagramChannel disconnect() throws IOException { close(); connected = false; return this; } private static native void configureBlocking(int socket, boolean blocking) throws IOException; private static native int bind(String hostname, int port) throws IOException; private static native int connect(String hostname, int port) throws IOException; private static native int write(int socket, byte[] array, int offset, int length, boolean blocking) throws IOException; private static native int receive(int socket, byte[] array, int offset, int length, boolean blocking, int[] address) throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/FileChannel.java000066400000000000000000000020121231440243200254510ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.nio.ByteBuffer; public abstract class FileChannel implements Channel { public static enum MapMode { PRIVATE, READ_ONLY, READ_WRITE }; public abstract int read(ByteBuffer dst) throws IOException; public abstract int read(ByteBuffer dst, long position) throws IOException; public abstract int write(ByteBuffer dst) throws IOException; public abstract int write(ByteBuffer dst, long position) throws IOException; public abstract long position() throws IOException; public abstract FileChannel position(long position) throws IOException; public abstract long size() throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/GatheringByteChannel.java000066400000000000000000000012141231440243200273310ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.nio.ByteBuffer; public interface GatheringByteChannel extends WritableByteChannel { public long write(ByteBuffer[] srcs) throws IOException; public long write(ByteBuffer[] srcs, int offset, int length) throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/ReadableByteChannel.java000066400000000000000000000010411231440243200271160ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.nio.ByteBuffer; public interface ReadableByteChannel extends Channel { public int read(ByteBuffer b) throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/SelectableChannel.java000066400000000000000000000020741231440243200266450ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.nio.ByteBuffer; public abstract class SelectableChannel implements Channel { private SelectionKey key; private boolean open = true; abstract int socketFD(); abstract void handleReadyOps(int ops); public abstract SelectableChannel configureBlocking(boolean v) throws IOException; public SelectionKey register(Selector selector, int interestOps, Object attachment) { key = new SelectionKey(this, selector, interestOps, attachment); selector.add(key); return key; } public boolean isOpen() { return open; } public void close() throws IOException { open = false; key = null; } } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/SelectionKey.java000066400000000000000000000035261231440243200257120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; public class SelectionKey { public static final int OP_READ = 1 << 0; public static final int OP_WRITE = 1 << 2; public static final int OP_CONNECT = 1 << 3; public static final int OP_ACCEPT = 1 << 4; private final SelectableChannel channel; private final Selector selector; private int interestOps; private int readyOps; private final Object attachment; public SelectionKey(SelectableChannel channel, Selector selector, int interestOps, Object attachment) { this.channel = channel; this.selector = selector; this.interestOps = interestOps; this.attachment = attachment; this.readyOps = 0; } public int interestOps() { return interestOps; } public SelectionKey interestOps(int v) { this.interestOps = v; return this; } public int readyOps() { return readyOps; } public void readyOps(int v) { this.readyOps = v; } public boolean isReadable() { return (readyOps & OP_READ) != 0; } public boolean isWritable() { return (readyOps & OP_WRITE) != 0; } public boolean isConnectable() { return (readyOps & OP_CONNECT) != 0; } public boolean isAcceptable() { return (readyOps & OP_ACCEPT) != 0; } public boolean isValid() { return channel.isOpen() && selector.isOpen(); } public SelectableChannel channel() { return channel; } public Selector selector() { return selector; } public Object attachment() { return attachment; } } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/Selector.java000066400000000000000000000023421231440243200250670ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.util.Set; import java.util.HashSet; public abstract class Selector { protected final Set keys = new HashSet(); protected final Set selectedKeys = new HashSet(); public static Selector open() throws IOException { return new SocketSelector(); } public void add(SelectionKey key) { keys.add(key); } public void remove(SelectionKey key) { keys.remove(key); } public Set keys() { return keys; } public Set selectedKeys() { return selectedKeys; } public abstract boolean isOpen(); public abstract Selector wakeup(); public abstract int selectNow() throws IOException; public abstract int select(long interval) throws IOException; public abstract int select() throws IOException; public abstract void close(); } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/ServerSocketChannel.java000066400000000000000000000045071231440243200272240ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.ServerSocket; import java.net.Socket; public class ServerSocketChannel extends SelectableChannel { private final SocketChannel channel; private ServerSocketChannel() throws IOException { channel = new SocketChannel(); } public static ServerSocketChannel open() throws IOException { return new ServerSocketChannel(); } public int socketFD() { return channel.socketFD(); } public void handleReadyOps(int ops) { channel.handleReadyOps(ops); } public SelectableChannel configureBlocking(boolean v) throws IOException { return channel.configureBlocking(v); } public void close() throws IOException { channel.close(); } public SocketChannel accept() throws IOException { SocketChannel c = new SocketChannel(); c.socket = doAccept(); c.connected = true; return c; } public ServerSocket socket() { return new Handle(); } private int doAccept() throws IOException { while (true) { int s = natDoAccept(channel.socket); if (s != -1) { return s; } // todo: throw ClosedByInterruptException if this thread was // interrupted during the accept call } } private int doListen(String host, int port) throws IOException { Socket.init(); return natDoListen(host, port); } public class Handle extends ServerSocket { public void bind(SocketAddress address) throws IOException { InetSocketAddress a; try { a = (InetSocketAddress) address; } catch (ClassCastException e) { throw new IllegalArgumentException(); } channel.socket = doListen(a.getHostName(), a.getPort()); channel.configureBlocking(channel.isBlocking()); } } private static native int natDoAccept(int socket) throws IOException; private static native int natDoListen(String host, int port) throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/SocketChannel.java000066400000000000000000000116071231440243200260340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.net.SocketException; import java.net.SocketAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.ByteBuffer; public class SocketChannel extends SelectableChannel implements ReadableByteChannel, GatheringByteChannel { public static final int InvalidSocket = -1; int socket = InvalidSocket; boolean connected = false; boolean readyToConnect = false; boolean blocking = true; public static SocketChannel open() throws IOException { Socket.init(); return new SocketChannel(); } public SelectableChannel configureBlocking(boolean v) throws IOException { blocking = v; if (socket != InvalidSocket) { configureBlocking(socket, v); } return this; } public boolean isBlocking() { return blocking; } public boolean isConnected() { return connected; } public Socket socket() { try { return new Handle(); } catch (IOException e) { return null; } } public boolean connect(SocketAddress address) throws IOException { InetSocketAddress a; try { a = (InetSocketAddress) address; } catch (ClassCastException e) { throw new UnsupportedAddressTypeException(); } socket = doConnect(a.getHostName(), a.getPort()); configureBlocking(blocking); return connected; } public boolean finishConnect() throws IOException { if (! connected) { while (! readyToConnect) { Selector selector = Selector.open(); SelectionKey key = register(selector, SelectionKey.OP_CONNECT, null); if (blocking) { selector.select(); } else { selector.selectNow(); break; } } natFinishConnect(socket); connected = readyToConnect; } return connected; } public void close() throws IOException { if (isOpen()) { super.close(); closeSocket(); } } private int doConnect(String host, int port) throws IOException { if (host == null) throw new NullPointerException(); boolean b[] = new boolean[1]; int s = natDoConnect(host, port, blocking, b); connected = b[0]; return s; } public int read(ByteBuffer b) throws IOException { if (! isOpen()) return -1; if (b.remaining() == 0) return 0; byte[] array = b.array(); if (array == null) throw new NullPointerException(); int r = natRead(socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking); if (r > 0) { b.position(b.position() + r); } return r; } public int write(ByteBuffer b) throws IOException { if (! connected) { natThrowWriteError(socket); } if (b.remaining() == 0) return 0; byte[] array = b.array(); if (array == null) throw new NullPointerException(); int w = natWrite(socket, array, b.arrayOffset() + b.position(), b.remaining(), blocking); if (w > 0) { b.position(b.position() + w); } return w; } public long write(ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); } public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { long total = 0; for (int i = offset; i < offset + length; ++i) { total += write(srcs[i]); if (srcs[i].hasRemaining()) { return total; } } return total; } private void closeSocket() { natCloseSocket(socket); } int socketFD() { return socket; } void handleReadyOps(int ops) { if ((ops & SelectionKey.OP_CONNECT) != 0) { readyToConnect = true; } } public class Handle extends Socket { public Handle() throws IOException { super(); } public void setTcpNoDelay(boolean on) throws SocketException { natSetTcpNoDelay(socket, on); } } private static native void configureBlocking(int socket, boolean blocking) throws IOException; private static native void natSetTcpNoDelay(int socket, boolean on) throws SocketException; private static native int natDoConnect(String host, int port, boolean blocking, boolean[] connected) throws IOException; private static native void natFinishConnect(int socket) throws IOException; private static native int natRead(int socket, byte[] buffer, int offset, int length, boolean blocking) throws IOException; private static native int natWrite(int socket, byte[] buffer, int offset, int length, boolean blocking) throws IOException; private static native void natThrowWriteError(int socket) throws IOException; private static native void natCloseSocket(int socket); } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/SocketSelector.java000066400000000000000000000064731231440243200262510ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.util.Iterator; import java.net.Socket; class SocketSelector extends Selector { protected volatile long state; protected final Object lock = new Object(); protected boolean woken = false; public SocketSelector() throws IOException { Socket.init(); state = natInit(); } public boolean isOpen() { return state != 0; } public Selector wakeup() { synchronized (lock) { if (isOpen() && (! woken)) { woken = true; natWakeup(state); } } return this; } private boolean clearWoken() { synchronized (lock) { if (woken) { woken = false; return true; } else { return false; } } } public synchronized int selectNow() throws IOException { return doSelect(-1); } public synchronized int select() throws IOException { return doSelect(0); } public synchronized int select(long interval) throws IOException { if (interval < 0) throw new IllegalArgumentException(); return doSelect(interval); } public int doSelect(long interval) throws IOException { if (! isOpen()) { throw new ClosedSelectorException(); } selectedKeys.clear(); if (clearWoken()) interval = -1; int max=0; for (Iterator it = keys.iterator(); it.hasNext();) { SelectionKey key = it.next(); SelectableChannel c = key.channel(); int socket = c.socketFD(); if (c.isOpen()) { key.readyOps(0); max = natSelectUpdateInterestSet (socket, key.interestOps(), state, max); } else { natSelectClearAll(socket, state); it.remove(); } } int r = natDoSocketSelect(state, max, interval); if (r > 0) { for (SelectionKey key : keys) { SelectableChannel c = key.channel(); int socket = c.socketFD(); int ready = natUpdateReadySet(socket, key.interestOps(), state); key.readyOps(ready); if (ready != 0) { c.handleReadyOps(ready); selectedKeys.add(key); } } } clearWoken(); return selectedKeys.size(); } public synchronized void close() { synchronized (lock) { if (isOpen()) { natClose(state); state = 0; } } } private static native long natInit(); private static native void natWakeup(long state); private static native void natClose(long state); private static native void natSelectClearAll(int socket, long state); private static native int natSelectUpdateInterestSet(int socket, int interest, long state, int max); private static native int natDoSocketSelect(long state, int max, long interval) throws IOException; private static native int natUpdateReadySet(int socket, int interest, long state); } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/UnsupportedAddressTypeException.java000066400000000000000000000010251231440243200316630ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; public class UnsupportedAddressTypeException extends IllegalArgumentException { public UnsupportedAddressTypeException() { super(null, null); } } ReadyTalk-avian-1e1fff5/classpath/java/nio/channels/WritableByteChannel.java000066400000000000000000000010421231440243200271710ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.nio.channels; import java.io.IOException; import java.nio.ByteBuffer; public interface WritableByteChannel extends Channel { public int write(ByteBuffer b) throws IOException; } ReadyTalk-avian-1e1fff5/classpath/java/security/000077500000000000000000000000001231440243200217325ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/security/AccessControlException.java000066400000000000000000000013661231440243200272240ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; public class AccessControlException extends SecurityException { private final Permission permission; public AccessControlException(String message) { this(message, null); } public AccessControlException(String message, Permission permission) { super(message); this.permission = permission; } public Permission getPermission() { return permission; } } ReadyTalk-avian-1e1fff5/classpath/java/security/AccessController.java000066400000000000000000000012531231440243200260430ustar00rootroot00000000000000/* Copyright (c) 2008, 2010 Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; /** * No real access control is implemented here. * * @author zsombor * */ public class AccessController { public static Object doPrivileged (PrivilegedAction action) { return action.run(); } public static void checkPermission(Permission perm) throws AccessControlException { } } ReadyTalk-avian-1e1fff5/classpath/java/security/AllPermission.java000066400000000000000000000007431231440243200253620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; public class AllPermission extends Permission { public AllPermission() { super(""); } } ReadyTalk-avian-1e1fff5/classpath/java/security/BasicPermission.java000066400000000000000000000007521231440243200256730ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; public class BasicPermission extends Permission { public BasicPermission(String name) { super(name); } } ReadyTalk-avian-1e1fff5/classpath/java/security/CodeSource.java000066400000000000000000000011571231440243200246340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; import java.net.URL; import java.security.cert.Certificate; public class CodeSource { private final URL url; public CodeSource(URL url, Certificate[] certificates) { this.url = url; } public URL getLocation() { return url; } } ReadyTalk-avian-1e1fff5/classpath/java/security/Permission.java000066400000000000000000000013511231440243200247250ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; public abstract class Permission { protected String name; public Permission(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return this.getClass().getSimpleName() + '['+name+']'; } public PermissionCollection newPermissionCollection() { return null; } } ReadyTalk-avian-1e1fff5/classpath/java/security/PermissionCollection.java000066400000000000000000000007211231440243200267410ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; public abstract class PermissionCollection { public abstract void add(Permission p); } ReadyTalk-avian-1e1fff5/classpath/java/security/Permissions.java000066400000000000000000000021461231440243200251130ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.HashSet; public class Permissions extends PermissionCollection { private final Map collections = new HashMap(); public void add(Permission p) { Class c = p.getClass(); PermissionCollection pc = collections.get(c); if (pc == null) { pc = p.newPermissionCollection(); if (pc == null) { pc = new MyPermissionCollection(); } collections.put(c, pc); } pc.add(p); } private static class MyPermissionCollection extends PermissionCollection { private final Set permissions = new HashSet(); public void add(Permission p) { permissions.add(p); } } } ReadyTalk-avian-1e1fff5/classpath/java/security/PrivilegedAction.java000066400000000000000000000006551231440243200260330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; public interface PrivilegedAction { T run(); } ReadyTalk-avian-1e1fff5/classpath/java/security/ProtectionDomain.java000066400000000000000000000013601231440243200260530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; public class ProtectionDomain { private final CodeSource codeSource; private final PermissionCollection permissions; public ProtectionDomain(CodeSource codeSource, PermissionCollection permissions) { this.codeSource = codeSource; this.permissions = permissions; } public CodeSource getCodeSource() { return codeSource; } } ReadyTalk-avian-1e1fff5/classpath/java/security/SecurityPermission.java000066400000000000000000000007651231440243200264650ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security; public class SecurityPermission extends BasicPermission { public SecurityPermission(String name) { super(name); } } ReadyTalk-avian-1e1fff5/classpath/java/security/cert/000077500000000000000000000000001231440243200226675ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/security/cert/Certificate.java000066400000000000000000000006421231440243200257560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.security.cert; public abstract class Certificate { } ReadyTalk-avian-1e1fff5/classpath/java/text/000077500000000000000000000000001231440243200210475ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/text/DateFormatSymbols.java000066400000000000000000000017151231440243200253150ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.text; public class DateFormatSymbols { private String[] ampm = new String[] { "AM", "PM" }; private String[] shortWeekdays = new String[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; private String[] shortMonths = new String[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; public String[] getAmPmStrings() { return ampm; } public void setAmPmStrings(String[] v) { ampm = v; } public String[] getShortWeekdays() { return shortWeekdays; } public String[] getShortMonths() { return shortMonths; } } ReadyTalk-avian-1e1fff5/classpath/java/text/FieldPosition.java000066400000000000000000000006701231440243200244650ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.text; public class FieldPosition { public FieldPosition(int field) { } } ReadyTalk-avian-1e1fff5/classpath/java/text/Format.java000066400000000000000000000012121231440243200231360ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.text; public abstract class Format { public final String format(Object o) { return format(o, new StringBuffer(), new FieldPosition(0)).toString(); } public abstract StringBuffer format(Object o, StringBuffer target, FieldPosition p); } ReadyTalk-avian-1e1fff5/classpath/java/text/MessageFormat.java000066400000000000000000000061311231440243200244500ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.text; import java.util.Locale; /** * A minimalist Java message formatter. * The string is a sequence of letters, copied verbatim unless the letter * is "{" or "'". If the letter is a "{", this begins a parameter, which * is a base-10 number. {0} will be replaced by the first argument to * format, {1} is the second argument, and so on. * If the letter is a single tick ("'"), then all characters * until the mathcing tick are outputted verbatim(this is useful for escaping * the { character). *

Examples

* * * * * * *
formatArgsResult
There are {0} grapessixThere are six grapes
{2} + {1} = {0}5 2 33 + 2 = 5
{0} and {0} and {0}againagain and again and again
Joe''s age is {0}, not '{0}'30Joe's age is 30, not {0}
*/ public class MessageFormat extends Format { private String pattern; private final Locale locale; public MessageFormat(String pattern, Locale locale) { this.pattern = pattern; this.locale = locale; } public MessageFormat(String pattern) { this(pattern, Locale.getDefault()); } public StringBuffer format(Object args[], StringBuffer target, FieldPosition pos) { int i=0; int len=pattern.length(); while (i < len) { char ch = pattern.charAt(i); if (ch == '{') { // Param should be a number int num=0; while (i < (len-1)) { i++; ch = pattern.charAt(i); if ((ch >= '0') && (ch <= '9')) { num = num * 10 + (ch - '0'); } else if (ch == '}') { target.append((args[num] == null) ? "null" : args[num].toString()); break; } else { throw new IllegalArgumentException("Character within {} isn't digit: " + ch); } } } else if (ch == '\'') { // Char is a literal string i++; ch = pattern.charAt(i); if (ch == '\'') { target.append('\''); } else { while (ch != '\'') { target.append(ch); i++; ch = pattern.charAt(i); } } } else { target.append(ch); } i++; } return target; } public static String format(String message, Object... args) { return new MessageFormat(message).format(args, new StringBuffer(), new FieldPosition(0)).toString(); } public StringBuffer format(Object args, StringBuffer target, FieldPosition p) { return format((Object[]) args, target, p); } public void applyPattern(String pattern) { this.pattern = pattern; } public String toPattern() { return pattern; } } ReadyTalk-avian-1e1fff5/classpath/java/text/ParseException.java000066400000000000000000000011651231440243200246460ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.text; public class ParseException extends Exception { private int errorOffset; public ParseException(String message, int errorOffset) { super(message); this.errorOffset = errorOffset; } public int getErrorOffset() { return errorOffset; } } ReadyTalk-avian-1e1fff5/classpath/java/text/ParsePosition.java000066400000000000000000000014751231440243200245200ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.text; public class ParsePosition { private int index, errorIndex = -1; public ParsePosition(int index) { this.index = index; } public int getErrorIndex() { return errorIndex; } public int getIndex() { return index; } public void setErrorIndex(int i) { errorIndex = i; } public void setIndex(int i) { index = i; } public String toString() { return "index: " + index + "(error index: " + errorIndex + ")"; } } ReadyTalk-avian-1e1fff5/classpath/java/text/SimpleDateFormat.java000066400000000000000000000071531231440243200251200ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.text; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; public class SimpleDateFormat { private String pattern; public SimpleDateFormat(String pattern) { this.pattern = pattern; if (! "yyyy-MM-dd'T'HH:mm:ss".equals(pattern)) { throw new UnsupportedOperationException("Unsupported pattern: " + pattern); } } public void setTimeZone(TimeZone tz) { if(!tz.getDisplayName().equals("GMT")) { throw new UnsupportedOperationException(); } } public StringBuffer format(Date date, StringBuffer buffer, FieldPosition position) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); pad(buffer, calendar.get(Calendar.YEAR), 4); buffer.append('-'); pad(buffer, calendar.get(Calendar.MONTH) + 1, 2); buffer.append('-'); pad(buffer, calendar.get(Calendar.DAY_OF_MONTH), 2); buffer.append("T"); pad(buffer, calendar.get(Calendar.HOUR_OF_DAY), 2); buffer.append(':'); pad(buffer, calendar.get(Calendar.MINUTE), 2); buffer.append(':'); pad(buffer, calendar.get(Calendar.SECOND), 2); return buffer; } public Date parse(String text) { return parse(text, new ParsePosition(0)); } public Date parse(String text, ParsePosition position) { int index = position.getIndex(); try { Calendar calendar = Calendar.getInstance(); index = parseField(text, index, 4, calendar, Calendar.YEAR, 0); index = expectPrefix(text, index, "-"); index = parseField(text, index, 2, calendar, Calendar.MONTH, -1); index = expectPrefix(text, index, "-"); index = parseField(text, index, 2, calendar, Calendar.DAY_OF_MONTH, 0); index = expectPrefix(text, index, "T"); index = parseField(text, index, 2, calendar, Calendar.HOUR_OF_DAY, 0); index = expectPrefix(text, index, ":"); index = parseField(text, index, 2, calendar, Calendar.MINUTE, 0); index = expectPrefix(text, index, ":"); index = parseField(text, index, 2, calendar, Calendar.SECOND, 0); position.setIndex(index); return calendar.getTime(); } catch (ParseException e) { position.setErrorIndex(index); return null; } } private static void pad(StringBuffer buffer, int value, int digits) { int i = value == 0 ? 1 : value; while (i > 0) { i /= 10; --digits; } while (digits-- > 0) { buffer.append('0'); } buffer.append(value); } private static int parseField(String text, int offset, int length, Calendar calendar, int field, int adjustment) throws ParseException { if (text.length() < offset + length) throw new ParseException("Short date: " + text, offset); try { int value = Integer.parseInt(text.substring(offset, offset + length), 10); calendar.set(field, value + adjustment); } catch (NumberFormatException e) { throw new ParseException("Not a number: " + text, offset); } return offset + length; } private static int expectPrefix(String text, int offset, String prefix) throws ParseException { if (text.length() <= offset) throw new ParseException("Short date: " + text, offset); if (! text.substring(offset).startsWith(prefix)) throw new ParseException("Parse error: " + text, offset); return offset + prefix.length(); } } ReadyTalk-avian-1e1fff5/classpath/java/util/000077500000000000000000000000001231440243200210405ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/util/AbstractCollection.java000066400000000000000000000047651231440243200254760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; /** * @author zsombor * */ public abstract class AbstractCollection implements Collection { public boolean add(T element) { throw new UnsupportedOperationException("adding to " + this.getClass().getName()); } public boolean addAll(Collection collection) { boolean result = false; for (T obj : collection) { result |= add(obj); } return result; } public void clear() { throw new UnsupportedOperationException("clear() in " + this.getClass().getName()); } public boolean contains(Object element) { if (element != null) { for (Iterator iter = iterator(); iter.hasNext();) { if (element.equals(iter.next())) { return true; } } } else { for (Iterator iter = iterator(); iter.hasNext();) { if (iter.next()==null) { return true; } } } return false; } public boolean containsAll(Collection c) { if (c == null) { throw new NullPointerException("Collection is null"); } Iterator it = c.iterator(); while (it.hasNext()) { if (! contains(it.next())) { return false; } } return true; } public boolean isEmpty() { return size() == 0; } public boolean remove(Object element) { throw new UnsupportedOperationException("remove(T) in " + this.getClass().getName()); } public boolean removeAll(Collection c) { if (c == null) { throw new NullPointerException("Collection is null"); } boolean changed = false; Iterator it = c.iterator(); while (it.hasNext()) { changed = remove(it.next()) || changed; } return changed; } public abstract int size(); public Object[] toArray() { return toArray(new Object[size()]); } public S[] toArray(S[] array) { return avian.Data.toArray(this, array); } public abstract Iterator iterator(); public String toString() { return avian.Data.toString(this); } } ReadyTalk-avian-1e1fff5/classpath/java/util/AbstractDeque.java000066400000000000000000000032071231440243200244340ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public abstract class AbstractDeque extends AbstractQueue implements Deque { @Override public void push(T e) { addFirst(e); } @Override public void addLast(T element) { if (! offerLast(element)) { throw new IllegalStateException(); } } @Override public void addFirst(T element) { if (! offerFirst(element)) { throw new IllegalStateException(); } } @Override public boolean offer(T element) { return offerLast(element); } @Override public T poll() { return pollFirst(); } @Override public T pop() { return removeFirst(); } @Override public T removeFirst() { return remove(); } @Override public boolean remove(Object element) { return removeFirstOccurrence(element); } @Override public T removeLast() { T result = pollLast(); if (result == null) { throw new NoSuchElementException(); } else { return result; } } @Override public T getFirst() { return element(); } @Override public T getLast() { T result = peekLast(); if (result == null) { throw new NoSuchElementException(); } return result; } @Override public T peek() { return peekFirst(); } } ReadyTalk-avian-1e1fff5/classpath/java/util/AbstractList.java000066400000000000000000000026261231440243200243100ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public abstract class AbstractList extends AbstractCollection implements List { protected int modCount; public boolean add(T o) { add(size(), o); return true; } public boolean addAll(Collection c) { return addAll(size(), c); } public boolean addAll(int startIndex, Collection c) { if (c == null) { throw new NullPointerException("Collection is null"); } int index = startIndex; boolean changed = false; Iterator it = c.iterator(); while (it.hasNext()) { add(index++, it.next()); changed = true; } return changed; } public Iterator iterator() { return listIterator(); } public ListIterator listIterator() { return new Collections.ArrayListIterator(this); } public int indexOf(Object o) { int i = 0; for (T v: this) { if (o == null) { if (v == null) { return i; } } else if (o.equals(v)) { return i; } ++ i; } return -1; } } ReadyTalk-avian-1e1fff5/classpath/java/util/AbstractMap.java000066400000000000000000000007011231440243200241020ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public abstract class AbstractMap extends Object implements Map { } ReadyTalk-avian-1e1fff5/classpath/java/util/AbstractQueue.java000066400000000000000000000024671231440243200244640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public abstract class AbstractQueue extends AbstractCollection implements Queue { protected AbstractQueue() { super(); } @Override public boolean add(T element) { if (offer(element)) { return true; } else { throw new IllegalStateException(); } } @Override public boolean addAll(Collection collection) { if (collection == null) { throw new NullPointerException(); } for (T element : collection) { add(element); } return true; } @Override public void clear() { while (size() > 0) { poll(); } } @Override public T element() { T result = peek(); if (result == null) { throw new NoSuchElementException(); } else { return result; } } @Override public T remove() { T result = poll(); if (result == null) { throw new NoSuchElementException(); } else { return result; } } } ReadyTalk-avian-1e1fff5/classpath/java/util/AbstractSequentialList.java000066400000000000000000000007241231440243200263400ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public abstract class AbstractSequentialList extends AbstractList implements List { } ReadyTalk-avian-1e1fff5/classpath/java/util/AbstractSet.java000066400000000000000000000007141231440243200241240ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public abstract class AbstractSet extends AbstractCollection implements Set { } ReadyTalk-avian-1e1fff5/classpath/java/util/ArrayDeque.java000066400000000000000000000205461231440243200237540ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class ArrayDeque extends AbstractDeque implements Deque { private Object[] dataArray; // both indexes are inclusive, except when size == 0 private int startIndex; private int endIndex; private int size; private int modCount; public ArrayDeque() { this(16); } public ArrayDeque(int intialSize) { dataArray = new Object[intialSize]; modCount = 0; clear(); } public ArrayDeque(Collection c) { this(c.size()); addAll(c); } private void copyInto(Object[] array) { if (startIndex <= endIndex) { // only one copy needed System.arraycopy(dataArray, startIndex, array, 0, size); } else { int firstCopyCount = dataArray.length - startIndex; System.arraycopy(dataArray, startIndex, array, 0, firstCopyCount); System.arraycopy(dataArray, 0, array, firstCopyCount, endIndex + 1); } } private void ensureCapacity(int newSize) { if (dataArray.length < newSize) { Object[] newArray = new Object[dataArray.length * 2]; copyInto(newArray); dataArray = newArray; startIndex = 0; endIndex = size - 1; } } @Override public boolean offerFirst(T e) { ensureCapacity(size() + 1); modCount++; if (size > 0) { // we don't need to move the head index for the first one startIndex--; if (startIndex < 0) { // wrapping to the end of the array startIndex = dataArray.length - 1; } } size++; dataArray[startIndex] = e; return true; } @Override public boolean offerLast(T e) { ensureCapacity(size() + 1); modCount++; if (size > 0) { // we don't need to move the tail index for the first one endIndex = (endIndex + 1) % dataArray.length; } size++; dataArray[endIndex] = e; return true; } @Override public T pollFirst() { modCount++; if (size == 0) { return null; } @SuppressWarnings("unchecked") T result = (T)dataArray[startIndex]; size--; if (size == 0) { startIndex = endIndex = 0; } else { startIndex = (startIndex + 1) % dataArray.length; } return result; } @Override public T pollLast() { modCount++; if (size == 0) { return null; } @SuppressWarnings("unchecked") T result = (T)dataArray[endIndex]; size--; if (size == 0) { startIndex = endIndex = 0; } else { endIndex--; if (endIndex < 0) { endIndex = dataArray.length - 1; } } return result; } @Override public T peekFirst() { if (size == 0) { return null; } else { @SuppressWarnings("unchecked") T result = (T)dataArray[startIndex]; return result; } } @Override public T peekLast() { if (size == 0) { return null; } else { @SuppressWarnings("unchecked") T result = (T)dataArray[endIndex]; return result; } } @Override public boolean addAll(Collection c) { if (c == null || c.isEmpty()) { return false; } ensureCapacity(size() + c.size()); Iterator it = c.iterator(); while (it.hasNext()) { add(it.next()); } return true; } @Override public boolean removeAll(Collection c) { boolean removed = false; Iterator it = c.iterator(); while (it.hasNext()) { removed = remove(it.next()) || removed; } return removed; } private boolean remove(Object o, boolean first) { modCount++; Iterator it; if (first) { it = iterator(); } else { it = descendingIterator(); } while (it.hasNext()) { T next = it.next(); if (next == null) { if (o == null) { it.remove(); return true; } } else if (next.equals(o)) { it.remove(); return true; } } return false; } @Override public boolean removeFirstOccurrence(Object o) { return remove(o, true); } @Override public boolean removeLastOccurrence(Object o) { return remove(o, false); } @Override public void clear() { size = 0; startIndex = endIndex = 0; modCount++; } @Override public int size() { return size; } @Override public boolean contains(Object element) { Iterator it = iterator(); while (it.hasNext()) { T next = it.next(); if (next == null) { if (element == null) { return true; } } else if (next.equals(element)) { return true; } } return false; } @Override public boolean containsAll(Collection c) { Iterator it = c.iterator(); while (it.hasNext()) { if (! contains(it.next())) { return false; } } return true; } @Override public Object[] toArray() { Object[] result = new Object[size]; copyInto(result); return result; } @Override public S[] toArray(S[] array) { return avian.Data.toArray(this, array); } public Iterator iterator() { return new GenericIterator() { @Override protected int getArrayIndex() { int result = (currentIndex + startIndex) % dataArray.length; return result; } }; } public Iterator descendingIterator() { return new GenericIterator() { @Override protected int getArrayIndex() { int result = (endIndex - currentIndex) % dataArray.length; return result; } }; } private abstract class GenericIterator implements Iterator { protected int expectedModCount = modCount; protected int currentIndex = 0; protected abstract int getArrayIndex(); @Override public T next() { if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } else if (currentIndex == size) { throw new NoSuchElementException(); } @SuppressWarnings("unchecked") T result = (T)dataArray[getArrayIndex()]; currentIndex++; return result; } @Override public boolean hasNext() { return currentIndex < size; } @Override public void remove() { currentIndex--; int removalIndex = getArrayIndex(); if (removalIndex == startIndex) { // avoid array copy pollFirst(); expectedModCount = modCount; } else if (removalIndex == endIndex) { // avoid array copy pollLast(); expectedModCount = modCount; } else { // array must be copied Object[] newArray = new Object[dataArray.length]; if (startIndex <= endIndex) { int firstCopyCount = removalIndex - startIndex; System.arraycopy(dataArray, startIndex, newArray, 0, firstCopyCount); System.arraycopy(dataArray, removalIndex + 1, newArray, firstCopyCount, size - firstCopyCount); } else if (removalIndex > startIndex) { int firstCopyCount = removalIndex - startIndex; System.arraycopy(dataArray, startIndex, newArray, 0, firstCopyCount); System.arraycopy(dataArray, startIndex + firstCopyCount + 1, newArray, firstCopyCount, dataArray.length - removalIndex - 1); System.arraycopy(dataArray, 0, newArray, size - removalIndex, endIndex + 1); } else { int firstCopyCount = dataArray.length - startIndex; System.arraycopy(dataArray, startIndex, newArray, 0, firstCopyCount); System.arraycopy(dataArray, 0, newArray, firstCopyCount, removalIndex); System.arraycopy(dataArray, removalIndex + 1, newArray, firstCopyCount + removalIndex, endIndex - removalIndex); } dataArray = newArray; startIndex = 0; endIndex = --size - 1; } } } } ReadyTalk-avian-1e1fff5/classpath/java/util/ArrayList.java000066400000000000000000000107761231440243200236300ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class ArrayList extends AbstractList implements java.io.Serializable { private static final int MinimumCapacity = 16; private Object[] array; private int size; public ArrayList(int capacity) { resize(capacity); } public ArrayList() { this(0); } public ArrayList(Collection source) { this(source.size()); addAll(source); } private void grow(int newSize) { if (array == null || newSize > array.length) { resize(Math.max(newSize, array == null ? MinimumCapacity : array.length * 2)); } } private void shrink(int newSize) { if (array.length / 2 >= MinimumCapacity && newSize <= array.length / 3) { resize(array.length / 2); } } private void resize(int capacity) { Object[] newArray = null; if (capacity != 0) { if (array != null && array.length == capacity) { return; } newArray = new Object[capacity]; if (array != null) { System.arraycopy(array, 0, newArray, 0, size); } } array = newArray; } private static boolean equal(Object a, Object b) { return (a == null && b == null) || (a != null && a.equals(b)); } public int size() { return size; } public void ensureCapacity(int capacity) { grow(capacity); } public boolean contains(Object element) { for (int i = 0; i < size; ++i) { if (equal(element, array[i])) { return true; } } return false; } public void add(int index, T element) { int newSize = Math.max(size+1, index+1); grow(newSize); size = newSize; System.arraycopy(array, index, array, index+1, size-index-1); array[index] = element; } public boolean add(T element) { add(size, element); return true; } public boolean addAll(Collection collection) { for (T t: collection) add(t); return true; } public int indexOf(Object element) { for (int i = 0; i < size; ++i) { if (equal(element, array[i])) { return i; } } return -1; } public int lastIndexOf(Object element) { for (int i = size - 1; i >= 0; --i) { if (equal(element, array[i])) { return i; } } return -1; } public T get(int index) { if (index >= 0 && index < size) { return (T) array[index]; } else { throw new IndexOutOfBoundsException(index + " not in [0, " + size + ")"); } } public T set(int index, T element) { if (index >= 0 && index < size) { Object oldValue = array[index]; array[index] = element; return (T) oldValue; } else { throw new IndexOutOfBoundsException(index + " not in [0, " + size + ")"); } } public T remove(int index) { T v = get(index); int newSize = size - 1; if (index == newSize) { array[index] = null; } else { System.arraycopy(array, index + 1, array, index, newSize - index); } shrink(newSize); size = newSize; return v; } public boolean remove(Object element) { for (int i = 0; i < size; ++i) { if (equal(element, array[i])) { remove(i); return true; } } return false; } public boolean isEmpty() { return size() == 0; } public void clear() { array = null; size = 0; } public Iterator iterator() { return listIterator(); } public ListIterator listIterator(int index) { return new Collections.ArrayListIterator(this, index); } public ListIterator listIterator() { return listIterator(0); } public String toString() { return avian.Data.toString(this); } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(array.length); for (T o : this) { out.writeObject(o); } } private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { in.defaultReadObject(); int capacity = in.readInt(); grow(capacity); for (int i = 0; i < size; i++) { array[i] = in.readObject(); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/Arrays.java000066400000000000000000000345611231440243200231550ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import java.lang.reflect.Array; public class Arrays { private Arrays() { } public static String toString(Object[] a) { return asList(a).toString(); } public static String toString(boolean[] a) { if (a == null) { return "null"; } else { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < a.length; ++i) { sb.append(String.valueOf(a[i])); if (i + 1 != a.length) { sb.append(", "); } } sb.append("]"); return sb.toString(); } } public static String toString(byte[] a) { if (a == null) { return "null"; } else { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < a.length; ++i) { sb.append(String.valueOf(a[i])); if (i + 1 != a.length) { sb.append(", "); } } sb.append("]"); return sb.toString(); } } public static String toString(short[] a) { if (a == null) { return "null"; } else { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < a.length; ++i) { sb.append(String.valueOf(a[i])); if (i + 1 != a.length) { sb.append(", "); } } sb.append("]"); return sb.toString(); } } public static String toString(int[] a) { if (a == null) { return "null"; } else { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < a.length; ++i) { sb.append(String.valueOf(a[i])); if (i + 1 != a.length) { sb.append(", "); } } sb.append("]"); return sb.toString(); } } public static String toString(long[] a) { if (a == null) { return "null"; } else { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < a.length; ++i) { sb.append(String.valueOf(a[i])); if (i + 1 != a.length) { sb.append(", "); } } sb.append("]"); return sb.toString(); } } public static String toString(float[] a) { if (a == null) { return "null"; } else { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < a.length; ++i) { sb.append(String.valueOf(a[i])); if (i + 1 != a.length) { sb.append(", "); } } sb.append("]"); return sb.toString(); } } public static String toString(double[] a) { if (a == null) { return "null"; } else { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < a.length; ++i) { sb.append(String.valueOf(a[i])); if (i + 1 != a.length) { sb.append(", "); } } sb.append("]"); return sb.toString(); } } private static boolean equal(Object a, Object b) { return (a == null && b == null) || (a != null && a.equals(b)); } public static void sort(Object[] array) { sort(array, new Comparator() { @Override public int compare(Object a, Object b) { return ((Comparable) a).compareTo(b); } }); } private final static int SORT_SIZE_THRESHOLD = 16; public static void sort(T[] array, Comparator comparator) { introSort(array, comparator, 0, array.length, array.length); insertionSort(array, comparator); } private static void introSort(T[] array, Comparator comparator, int begin, int end, int limit) { while (end - begin > SORT_SIZE_THRESHOLD) { if (limit == 0) { heapSort(array, comparator, begin, end); return; } limit >>= 1; // median of three T a = array[begin]; T b = array[begin + (end - begin) / 2 + 1]; T c = array[end - 1]; T median; if (comparator.compare(a, b) < 0) { median = comparator.compare(b, c) < 0 ? b : (comparator.compare(a, c) < 0 ? c : a); } else { median = comparator.compare(b, c) > 0 ? b : (comparator.compare(a, c) > 0 ? c : a); } // partition int pivot, i = begin, j = end; for (;;) { while (comparator.compare(array[i], median) < 0) { ++i; } --j; while (comparator.compare(median, array[j]) < 0) { --j; } if (i >= j) { pivot = i; break; } T swap = array[i]; array[i] = array[j]; array[j] = swap; ++i; } introSort(array, comparator, pivot, end, limit); end = pivot; } } private static void heapSort(T[] array, Comparator comparator, int begin, int end) { int count = end - begin; for (int i = count / 2 - 1; i >= 0; --i) { siftDown(array, comparator, i, count, begin); } for (int i = count - 1; i > 0; --i) { // swap begin and begin + i T swap = array[begin + i]; array[begin + i] = array[begin]; array[begin] = swap; siftDown(array, comparator, 0, i, begin); } } private static void siftDown(T[] array, Comparator comparator, int i, int count, int offset) { T value = array[offset + i]; while (i < count / 2) { int child = 2 * i + 1; if (child + 1 < count && comparator.compare(array[child], array[child + 1]) < 0) { ++child; } if (comparator.compare(value, array[child]) >= 0) { break; } array[offset + i] = array[offset + child]; i = child; } array[offset + i] = value; } private static void insertionSort(T[] array, Comparator comparator) { for (int j = 1; j < array.length; ++j) { T t = array[j]; int i = j - 1; while (i >= 0 && comparator.compare(array[i], t) > 0) { array[i + 1] = array[i]; i = i - 1; } array[i + 1] = t; } } public static int hashCode(Object[] array) { if(array == null) { return 9023; } int hc = 823347; for(Object o : array) { hc += o != null ? o.hashCode() : 54267; hc *= 3; } return hc; } public static boolean equals(Object[] a, Object[] b) { if(a == b) { return true; } if(a == null || b == null) { return false; } if(a.length != b.length) { return false; } for(int i = 0; i < a.length; i++) { if(!equal(a[i], b[i])) { return false; } } return true; } public static boolean equals(byte[] a, byte[] b) { if(a == b) { return true; } if(a == null || b == null) { return false; } if(a.length != b.length) { return false; } for(int i = 0; i < a.length; i++) { if(a[i] != b[i]) { return false; } } return true; } public static boolean equals(int[] a, int[] b) { if(a == b) { return true; } if(a == null || b == null) { return false; } if(a.length != b.length) { return false; } for(int i = 0; i < a.length; i++) { if(a[i] != b[i]) { return false; } } return true; } public static boolean equals(long[] a, long[] b) { if(a == b) { return true; } if(a == null || b == null) { return false; } if(a.length != b.length) { return false; } for(int i = 0; i < a.length; i++) { if(a[i] != b[i]) { return false; } } return true; } public static boolean equals(short[] a, short[] b) { if(a == b) { return true; } if(a == null || b == null) { return false; } if(a.length != b.length) { return false; } for(int i = 0; i < a.length; i++) { if(a[i] != b[i]) { return false; } } return true; } public static boolean equals(char[] a, char[] b) { if(a == b) { return true; } if(a == null || b == null) { return false; } if(a.length != b.length) { return false; } for(int i = 0; i < a.length; i++) { if(a[i] != b[i]) { return false; } } return true; } public static boolean equals(float[] a, float[] b) { if(a == b) { return true; } if(a == null || b == null) { return false; } if(a.length != b.length) { return false; } for(int i = 0; i < a.length; i++) { if(a[i] != b[i]) { return false; } } return true; } public static boolean equals(double[] a, double[] b) { if(a == b) { return true; } if(a == null || b == null) { return false; } if(a.length != b.length) { return false; } for(int i = 0; i < a.length; i++) { if(a[i] != b[i]) { return false; } } return true; } public static boolean deepEquals(Object[] a, Object[] b) { if(a == b) { return true; } if(a == null || b == null) { return false; } if(a.length != b.length) { return false; } for(int i = 0; i < a.length; i++) { if(!Objects.deepEquals(a[i], b[i])) { return false; } } return true; } public static List asList(final T ... array) { return new AbstractList() { @Override public int size() { return array.length; } @Override public void add(int index, T element) { throw new UnsupportedOperationException(); } @Override public int indexOf(Object element) { for (int i = 0; i < array.length; ++i) { if (equal(element, array[i])) { return i; } } return -1; } @Override public int lastIndexOf(Object element) { for (int i = array.length - 1; i >= 0; --i) { if (equal(element, array[i])) { return i; } } return -1; } @Override public T get(int index) { return array[index]; } @Override public T set(int index, T value) { throw new UnsupportedOperationException(); } @Override public T remove(int index) { throw new UnsupportedOperationException(); } @Override public ListIterator listIterator(int index) { return new Collections.ArrayListIterator(this, index); } }; } public static void fill(int[] array, int value) { for (int i=0;i void fill(T[] array, T value) { for (int i=0;i newLength ? newLength : array.length; System.arraycopy(array, 0, result, 0, length); return result; } public static byte[] copyOf(byte[] array, int newLength) { byte[] result = new byte[newLength]; int length = array.length > newLength ? newLength : array.length; System.arraycopy(array, 0, result, 0, length); return result; } public static char[] copyOf(char[] array, int newLength) { char[] result = new char[newLength]; int length = array.length > newLength ? newLength : array.length; System.arraycopy(array, 0, result, 0, length); return result; } public static double[] copyOf(double[] array, int newLength) { double[] result = new double[newLength]; int length = array.length > newLength ? newLength : array.length; System.arraycopy(array, 0, result, 0, length); return result; } public static float[] copyOf(float[] array, int newLength) { float[] result = new float[newLength]; int length = array.length > newLength ? newLength : array.length; System.arraycopy(array, 0, result, 0, length); return result; } public static int[] copyOf(int[] array, int newLength) { int[] result = new int[newLength]; int length = array.length > newLength ? newLength : array.length; System.arraycopy(array, 0, result, 0, length); return result; } public static long[] copyOf(long[] array, int newLength) { long[] result = new long[newLength]; int length = array.length > newLength ? newLength : array.length; System.arraycopy(array, 0, result, 0, length); return result; } public static short[] copyOf(short[] array, int newLength) { short[] result = new short[newLength]; int length = array.length > newLength ? newLength : array.length; System.arraycopy(array, 0, result, 0, length); return result; } public static T[] copyOf(T[] array, int newLength) { Class clazz = array.getClass().getComponentType(); T[] result = (T[])Array.newInstance(clazz, newLength); int length = array.length > newLength ? newLength : array.length; System.arraycopy(array, 0, result, 0, length); return result; } public static T[] copyOf(U[] array, int newLength, Class newType) { T[] result = (T[])Array.newInstance(newType.getComponentType(), newLength); int length = array.length > newLength ? newLength : array.length; System.arraycopy(array, 0, result, 0, length); return result; } } ReadyTalk-avian-1e1fff5/classpath/java/util/BitSet.java000066400000000000000000000155051231440243200231030ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import java.io.Serializable; /** * @author zsombor * */ public class BitSet implements Serializable, Cloneable { final static int BITS_PER_LONG = 64; final static int BITS_PER_LONG_SHIFT = 6; final static long MASK = 0xFFFFFFFFFFFFFFFFL; private long[] bits; private static int longPosition(int index) { return index >> BITS_PER_LONG_SHIFT; } private static long bitPosition(int index) { return 1L << (index % BITS_PER_LONG); } private static long getTrueMask(int fromIndex, int toIndex) { int currentRange = toIndex - fromIndex; return (MASK >>> (BITS_PER_LONG - currentRange)) << (fromIndex % BITS_PER_LONG); } public BitSet(int bitLength) { if (bitLength % BITS_PER_LONG == 0) { enlarge(longPosition(bitLength)); } else { enlarge(longPosition(bitLength) + 1); } } public BitSet() { enlarge(1); } public void and(BitSet otherBits) { int min = Math.min(bits.length, otherBits.bits.length); for (int i = 0; i < min; i++) { bits[i] &= otherBits.bits[i]; } for (int i = min; i < bits.length; i++) { bits[i] = 0; } } public void andNot(BitSet otherBits) { int max = Math.max(bits.length, otherBits.bits.length); enlarge(max); int min = Math.min(bits.length, otherBits.bits.length); for (int i = 0; i < min; i++) { bits[i] &= ~otherBits.bits[i]; } } public void or(BitSet otherBits) { int max = Math.max(bits.length, otherBits.bits.length); enlarge(max); int min = Math.min(bits.length, otherBits.bits.length); for (int i = 0; i < min; i++) { bits[i] |= otherBits.bits[i]; } } public void xor(BitSet otherBits) { int max = Math.max(bits.length, otherBits.bits.length); enlarge(max); int min = Math.min(bits.length, otherBits.bits.length); for (int i = 0; i < min; i++) { bits[i] ^= otherBits.bits[i]; } } private void enlarge(int newPartition) { if (bits == null || bits.length < (newPartition + 1)) { long[] newBits = new long[newPartition + 1]; if (bits != null) { System.arraycopy(bits, 0, newBits, 0, bits.length); } bits = newBits; } } public boolean get(int index) { int pos = longPosition(index); if (pos < bits.length) { return (bits[pos] & bitPosition(index)) != 0; } return false; } public void flip(int index) { flip(index, index+1); } public void flip(int fromIndex, int toIndex) { if (fromIndex > toIndex || fromIndex < 0 || toIndex < 0) { throw new IndexOutOfBoundsException(); } else if (fromIndex != toIndex) { MaskInfoIterator iter = new MaskInfoIterator(fromIndex, toIndex); enlarge(iter.getLastPartition()); while (iter.hasNext()) { MaskInfo info = iter.next(); bits[info.partitionIndex] ^= info.mask; } } } public void set(int index) { int pos = longPosition(index); enlarge(pos); bits[pos] |= bitPosition(index); } public void set(int start, int end) { MaskInfoIterator iter = new MaskInfoIterator(start, end); enlarge(iter.getLastPartition()); while (iter.hasNext()) { MaskInfo info = iter.next(); bits[info.partitionIndex] |= info.mask; } } public void clear(int index) { int pos = longPosition(index); if (pos < bits.length) { bits[pos] &= (MASK ^ bitPosition(index)); } } public void clear(int start, int end) { MaskInfoIterator iter = new MaskInfoIterator(start, end); while (iter.hasNext()) { MaskInfo info = iter.next(); bits[info.partitionIndex] &= (MASK ^ info.mask); } } public boolean isEmpty() { for (int i = 0; i < bits.length; i++) { if (bits[i] != 0) { return false; } } return true; } public boolean intersects(BitSet otherBits) { int max = Math.max(bits.length, otherBits.bits.length); for (int i = 0; i < max; i++) { if ((bits[i] & otherBits.bits[i]) != 0) { return true; } } return false; } public int length() { return bits.length << BITS_PER_LONG_SHIFT; } public int nextSetBit(int fromIndex) { return nextBit(fromIndex, false); } private int nextBit(int fromIndex, boolean bitClear) { int pos = longPosition(fromIndex); if (pos >= bits.length) { return -1; } int current = fromIndex; do { long currValue = bits[pos]; if (currValue == 0) { pos++; current = pos << BITS_PER_LONG_SHIFT; } else { do { long bitPos = bitPosition(current); if (((currValue & bitPos) != 0) ^ bitClear) { return current; } else { current++; } } while (current % BITS_PER_LONG != 0); } pos++; } while (pos < bits.length); return -1; } public int nextClearBit(int fromIndex) { return nextBit(fromIndex, true); } public int cardinality() { int numSetBits = 0; for (int i = nextSetBit(0); i >= 0; i = nextSetBit(i+1)) { ++numSetBits; } return numSetBits; } private static class MaskInfoIterator implements Iterator { private int basePartition; private int numPartitionsToTraverse; private int currentPartitionOffset; private int toIndex; private int currentFirstIndex; public MaskInfoIterator(int fromIndex, int toIndex) { this.basePartition = longPosition(fromIndex); this.numPartitionsToTraverse = longPosition(toIndex - 1) - basePartition + 1; this.currentPartitionOffset = 0; this.toIndex = toIndex; this.currentFirstIndex = fromIndex; } public MaskInfo next() { int currentToIndex = Math.min(toIndex, (basePartition + currentPartitionOffset + 1) * BITS_PER_LONG); long mask = getTrueMask(currentFirstIndex, currentToIndex); MaskInfo info = new MaskInfo(mask, basePartition + currentPartitionOffset); currentFirstIndex = currentToIndex; currentPartitionOffset++; return info; } public boolean hasNext() { return currentPartitionOffset < numPartitionsToTraverse; } public void remove() { throw new UnsupportedOperationException(); } public int getLastPartition() { return basePartition + numPartitionsToTraverse - 1; } } private static class MaskInfo { public long mask; public int partitionIndex; public MaskInfo(long mask, int partitionIndex) { this.mask = mask; this.partitionIndex = partitionIndex; } } } ReadyTalk-avian-1e1fff5/classpath/java/util/Calendar.java000066400000000000000000000121271231440243200234170ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public abstract class Calendar { public static final int AM = 0; public static final int AM_PM = 9; public static final int DAY_OF_MONTH = 5; public static final int DAY_OF_WEEK = 7; public static final int HOUR = 10; public static final int HOUR_OF_DAY = 11; public static final int MINUTE = 12; public static final int MONTH = 2; public static final int PM = 1; public static final int SECOND = 13; public static final int YEAR = 1; public static final int FIELD_COUNT = 17; protected long time; protected boolean isTimeSet; protected int[] fields = new int[FIELD_COUNT]; protected boolean areFieldsSet; protected boolean[] isSet = new boolean[FIELD_COUNT]; protected Calendar() { } public static Calendar getInstance() { return new MyCalendar(System.currentTimeMillis()); } public int get(int field) { return fields[field]; } public void set(int field, int value) { fields[field] = value; } public void set(int year, int month, int date) { set(YEAR, year); set(MONTH, month); set(DAY_OF_MONTH, date); } public void setTime(Date date) { time = date.getTime(); } public Date getTime() { return new Date(time); } public abstract void roll(int field, boolean up); public abstract void add(int field, int amount); public void roll(int field, int amount) { boolean up = amount >= 0; if (! up) { amount = - amount; } for (int i = 0; i < amount; ++i) { roll(field, up); } } public abstract int getMinimum(int field); public abstract int getMaximum(int field); public abstract int getActualMinimum(int field); public abstract int getActualMaximum(int field); private static class MyCalendar extends Calendar { private static final long MILLIS_PER_DAY = 86400000; private static final int MILLIS_PER_HOUR = 3600000; private static final int MILLIS_PER_MINUTE = 60000; private static final int MILLIS_PER_SECOND = 1000; private static final int EPOCH_YEAR = 1970; private static final int EPOCH_LEAP_YEAR = 1968; private static final int DAYS_TO_EPOCH = 731; private static final int[][] DAYS_IN_MONTH = new int[][] { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; public MyCalendar(long time) { this.time = time; this.isTimeSet = true; parseIntoFields(time); } public void setTime(Date date) { super.setTime(date); parseIntoFields(this.time); } public Date getTime() { long days = fields[DAY_OF_MONTH] - 1; long years = fields[YEAR] - EPOCH_LEAP_YEAR; days += years * 365 + years / 4 + 1 - DAYS_TO_EPOCH; for (int month = 0; month < fields[MONTH]; month++) { days += DAYS_IN_MONTH[0][month]; } if (fields[MONTH] < 2 && isLeapYear(fields[YEAR])) { days--; } long time = MILLIS_PER_DAY * days + MILLIS_PER_HOUR * fields[HOUR_OF_DAY] + MILLIS_PER_MINUTE * fields[MINUTE] + MILLIS_PER_SECOND * fields[SECOND]; return new Date(time); } private static boolean isLeapYear(int year) { return (year%4 == 0) && (year%100 != 0) || (year%400 == 0); } private void parseIntoFields(long timeInMillis) { long days = timeInMillis / MILLIS_PER_DAY; /* convert days since Jan 1, 1970 to days since Jan 1, 1968 */ days += DAYS_TO_EPOCH; long years = 4 * days / 1461; /* days/365.25 = 4*days/(4*365.25) */ int year = (int)(EPOCH_LEAP_YEAR + years); days -= 365 * years + years / 4; if (!isLeapYear(year)) days--; int month=0; int leapIndex = isLeapYear(year) ? 1 : 0; while (days >= DAYS_IN_MONTH[leapIndex][month]) { days -= DAYS_IN_MONTH[leapIndex][month++]; } days++; int remainder = (int)(timeInMillis % MILLIS_PER_DAY); int hour = remainder / MILLIS_PER_HOUR; remainder = remainder % MILLIS_PER_HOUR; int minute = remainder / MILLIS_PER_MINUTE; remainder = remainder % MILLIS_PER_MINUTE; int second = remainder / MILLIS_PER_SECOND; fields[YEAR] = year; fields[MONTH] = month; fields[DAY_OF_MONTH] = (int)days; fields[HOUR_OF_DAY] = hour; fields[MINUTE] = minute; fields[SECOND] = second; } public void roll(int field, boolean up) { // todo } public void add(int fild, int amount) { // todo } public int getMinimum(int field) { // todo return 0; } public int getMaximum(int field) { // todo return 0; } public int getActualMinimum(int field) { // todo return 0; } public int getActualMaximum(int field) { // todo return 0; } } } ReadyTalk-avian-1e1fff5/classpath/java/util/Collection.java000066400000000000000000000015141231440243200237770ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface Collection extends Iterable { public int size(); public boolean isEmpty(); public boolean contains(Object element); public boolean containsAll(Collection c); public boolean add(T element); public boolean addAll(Collection collection); public boolean remove(Object element); public boolean removeAll(Collection c); public Object[] toArray(); public S[] toArray(S[] array); public void clear(); } ReadyTalk-avian-1e1fff5/classpath/java/util/Collections.java000066400000000000000000000424171231440243200241710ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import avian.Data; public class Collections { private Collections() { } public static void shuffle(List list, Random random) { Object[] array = Data.toArray(list, new Object[list.size()]); for (int i = 0; i < array.length; ++i) { int j = random.nextInt(array.length); Object tmp = array[i]; array[i] = array[j]; array[j] = tmp; } list.clear(); for (int i = 0; i < array.length; ++i) { list.add(array[i]); } } public static void shuffle(List list) { shuffle(list, new Random()); } public static void sort(List list) { sort(list, new Comparator() { public int compare(Object a, Object b) { return ((Comparable) a).compareTo(b); } }); } private final static int SORT_SIZE_THRESHOLD = 16; public static void sort(List list, Comparator comparator) { int size = list.size(); introSort(list, comparator, 0, size, size); insertionSort(list, comparator); } private static void introSort(List list, Comparator comparator, int begin, int end, int limit) { while (end - begin > SORT_SIZE_THRESHOLD) { if (limit == 0) { heapSort(list, comparator, begin, end); return; } limit >>= 1; // median of three T a = list.get(begin); T b = list.get(begin + (end - begin) / 2 + 1); T c = list.get(end - 1); T median; if (comparator.compare(a, b) < 0) { median = comparator.compare(b, c) < 0 ? b : (comparator.compare(a, c) < 0 ? c : a); } else { median = comparator.compare(b, c) > 0 ? b : (comparator.compare(a, c) > 0 ? c : a); } // partition int pivot, i = begin, j = end; for (;;) { while (comparator.compare(list.get(i), median) < 0) { ++i; } --j; while (comparator.compare(median, list.get(j)) < 0) { --j; } if (i >= j) { pivot = i; break; } T swap = list.get(i); list.set(i, list.get(j)); list.set(j, swap); ++i; } introSort(list, comparator, pivot, end, limit); end = pivot; } } private static void heapSort(List list, Comparator comparator, int begin, int end) { int count = end - begin; for (int i = count / 2 - 1; i >= 0; --i) { siftDown(list, comparator, i, count, begin); } for (int i = count - 1; i > 0; --i) { // swap begin and begin + i T swap = list.get(begin + i); list.set(begin + i, list.get(begin)); list.set(begin, swap); siftDown(list, comparator, 0, i, begin); } } private static void siftDown(List list, Comparator comparator, int i, int count, int offset) { T value = list.get(offset + i); while (i < count / 2) { int child = 2 * i + 1; if (child + 1 < count && comparator.compare(list.get(child), list.get(child + 1)) < 0) { ++child; } if (comparator.compare(value, list.get(child)) >= 0) { break; } list.set(offset + i, list.get(offset + child)); i = child; } list.set(offset + i, value); } private static void insertionSort(List list, Comparator comparator) { int size = list.size(); for (int j = 1; j < size; ++j) { T t = list.get(j); int i = j - 1; while (i >= 0 && comparator.compare(list.get(i), t) > 0) { list.set(i + 1, list.get(i)); --i; } list.set(i + 1, t); } } public static int binarySearch(List list, T needle) { int left = -1, right = list.size(); while (left + 1 < right) { int middle = (left + right) >> 1; int result = ((Comparable)needle).compareTo(list.get(middle)); if (result < 0) { right = middle; } else if (result > 0) { left = middle; } else { return middle; } } return -1 - right; } public static void reverse(List list) { int ascending = 0, descending = list.size() - 1; while (ascending < descending) { T tmp = list.get(ascending); list.set(ascending++, list.get(descending)); list.set(descending--, tmp); } } public static final List EMPTY_LIST = new UnmodifiableList(new ArrayList(0)); public static final List emptyList() { return EMPTY_LIST; } public static final Map emptyMap() { return (Map) new UnmodifiableMap( new HashMap(0)); } public static final Set emptySet() { return (Set) new UnmodifiableSet( new HashSet(0)); } public static Enumeration enumeration(Collection c) { return new IteratorEnumeration (c.iterator()); } public static Comparator reverseOrder(Comparator cmp) { return new ReverseComparator(cmp); } static class IteratorEnumeration implements Enumeration { private final Iterator it; public IteratorEnumeration(Iterator it) { this.it = it; } public T nextElement() { return it.next(); } public boolean hasMoreElements() { return it.hasNext(); } } static class SynchronizedCollection implements Collection { protected final Object lock; protected final Collection collection; public SynchronizedCollection(Object lock, Collection collection) { this.lock = lock; this.collection = collection; } public int size() { synchronized (lock) { return collection.size(); } } public boolean isEmpty() { return size() == 0; } public boolean contains(Object e) { synchronized (lock) { return collection.contains(e); } } public boolean add(T e) { synchronized (lock) { return collection.add(e); } } public boolean addAll(Collection collection) { synchronized (lock) { return this.collection.addAll(collection); } } public boolean remove(Object e) { synchronized (lock) { return collection.remove((T)e); } } public Object[] toArray() { return toArray(new Object[size()]); } public T[] toArray(T[] array) { synchronized (lock) { return collection.toArray(array); } } public void clear() { synchronized (lock) { collection.clear(); } } public Iterator iterator() { return new SynchronizedIterator(lock, collection.iterator()); } public boolean containsAll(Collection c) { synchronized (lock) { return collection.containsAll(c); } } public boolean removeAll(Collection c) { synchronized (lock) { return collection.removeAll(c); } } } static class SynchronizedMap implements Map { protected final Object lock; protected final Map map; SynchronizedMap(Map map) { this.map = map; this.lock = this; } SynchronizedMap(Object lock, Map map) { this.lock = lock; this.map = map; } public void clear() { synchronized (lock) { map.clear(); } } public boolean containsKey(Object key) { synchronized (lock) { return map.containsKey(key); } } public boolean containsValue(Object value) { synchronized (lock) { return map.containsValue(value); } } public Set> entrySet() { synchronized (lock) { return new SynchronizedSet>(lock, map.entrySet()); } } public V get(Object key) { synchronized (lock) { return map.get(key); } } public boolean isEmpty() { synchronized (lock) { return map.isEmpty(); } } public Set keySet() { synchronized (lock) { return new SynchronizedSet(lock, map.keySet()); } } public V put(K key, V value) { synchronized (lock) { return map.put(key, value); } } public void putAll(Map elts) { synchronized (lock) { map.putAll(elts); } } public V remove(Object key) { synchronized (lock) { return map.remove(key); } } public int size() { synchronized (lock) { return map.size(); } } public Collection values() { synchronized (lock) { return new SynchronizedCollection(lock, map.values()); } } } public static Map synchronizedMap(Map map) { return new SynchronizedMap (map); } static class SynchronizedSet extends SynchronizedCollection implements Set { public SynchronizedSet(Object lock, Set set) { super(lock, set); } } public static Set synchronizedSet(Set set) { return new SynchronizedSet (new Object(), set); } static class SynchronizedIterator implements Iterator { private final Object lock; private final Iterator it; public SynchronizedIterator(Object lock, Iterator it) { this.lock = lock; this.it = it; } public T next() { synchronized (lock) { return it.next(); } } public boolean hasNext() { synchronized (lock) { return it.hasNext(); } } public void remove() { synchronized (lock) { it.remove(); } } } static class ArrayListIterator implements ListIterator { private final List list; private int toRemove = -1; private int index; public ArrayListIterator(List list) { this(list, 0); } public ArrayListIterator(List list, int index) { this.list = list; this.index = index - 1; } public boolean hasPrevious() { return index >= 0; } public T previous() { if (hasPrevious()) { toRemove = index; return list.get(index--); } else { throw new NoSuchElementException(); } } public T next() { if (hasNext()) { toRemove = ++index; return list.get(index); } else { throw new NoSuchElementException(); } } public boolean hasNext() { return index + 1 < list.size(); } public void remove() { if (toRemove != -1) { list.remove(toRemove); index = toRemove - 1; toRemove = -1; } else { throw new IllegalStateException(); } } } public static List unmodifiableList(List list) { return new UnmodifiableList(list); } static class UnmodifiableList implements List { private List inner; UnmodifiableList(List l) { this.inner = l; } public T get(int index) { return inner.get(index); } public T set(int index, T value) { throw new UnsupportedOperationException(); } public T remove(int index) { throw new UnsupportedOperationException(); } public boolean remove(Object o) { throw new UnsupportedOperationException(); } public boolean add(T element) { throw new UnsupportedOperationException(); } public void add(int index, T element) { throw new UnsupportedOperationException(); } public Iterator iterator() { return new UnmodifiableIterator(inner.iterator()); } public int indexOf(Object value) { return inner.indexOf(value); } public int lastIndexOf(Object value) { return inner.lastIndexOf(value); } public boolean isEmpty() { return inner.isEmpty(); } public ListIterator listIterator(int index) { return new UnmodifiableListIterator(inner.listIterator(index)); } public ListIterator listIterator() { return new UnmodifiableListIterator(inner.listIterator()); } public int size() { return inner.size(); } public boolean contains(Object element) { return inner.contains(element); } public boolean addAll(Collection collection) { throw new UnsupportedOperationException(); } public Object[] toArray() { return inner.toArray(); } public S[] toArray(S[] array) { return inner.toArray(array); } public void clear() { throw new UnsupportedOperationException(); } public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } public boolean addAll(int startIndex, Collection c) { throw new UnsupportedOperationException(); } public boolean containsAll(Collection c) { return inner.containsAll(c); } } public static Map unmodifiableMap(Map m) { return new UnmodifiableMap(m); } static class UnmodifiableMap implements Map { private Map inner; UnmodifiableMap(Map m) { this.inner = m; } public void clear() { throw new UnsupportedOperationException(); } public boolean containsKey(Object key) { return inner.containsKey(key); } public boolean containsValue(Object value) { return inner.containsValue(value); } public Set> entrySet() { return unmodifiableSet(inner.entrySet()); } public V get(Object key) { return inner.get(key); } public boolean isEmpty() { return inner.isEmpty(); } public Set keySet() { return unmodifiableSet(inner.keySet()); } public V put(K key, V value) { throw new UnsupportedOperationException(); } public void putAll(Map t) { throw new UnsupportedOperationException(); } public V remove(Object key) { throw new UnsupportedOperationException(); } public int size() { return inner.size(); } public Collection values() { return unmodifiableCollection(inner.values()); } } static class UnmodifiableIterator implements Iterator { private final Iterator inner; UnmodifiableIterator(Iterator inner) { this.inner = inner; } @Override public T next() { return inner.next(); } @Override public boolean hasNext() { return inner.hasNext(); } @Override public void remove() { throw new UnsupportedOperationException(); } } static class UnmodifiableListIterator extends UnmodifiableIterator implements ListIterator { private final ListIterator innerListIterator; UnmodifiableListIterator(ListIterator listIterator) { super(listIterator); this.innerListIterator = listIterator; } @Override public boolean hasPrevious() { return innerListIterator.hasPrevious(); } @Override public T previous() { return innerListIterator.previous(); } } static class UnmodifiableCollection implements Collection { private final Collection inner; UnmodifiableCollection(Collection inner) { this.inner = inner; } @Override public Iterator iterator() { return new UnmodifiableIterator(inner.iterator()); } @Override public int size() { return inner.size(); } @Override public boolean isEmpty() { return inner.isEmpty(); } @Override public boolean contains(Object element) { return inner.contains(element); } @Override public boolean containsAll(Collection c) { return inner.containsAll(c); } @Override public boolean add(T element) { throw new UnsupportedOperationException(); } @Override public boolean addAll(Collection collection) { throw new UnsupportedOperationException(); } @Override public boolean remove(Object element) { throw new UnsupportedOperationException(); } @Override public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } @Override public Object[] toArray() { return inner.toArray(); } @Override public S[] toArray(S[] array) { return inner.toArray(array); } @Override public void clear() { throw new UnsupportedOperationException(); } } public static UnmodifiableCollection unmodifiableCollection(Collection collection) { return new UnmodifiableCollection(collection); } static class UnmodifiableSet extends UnmodifiableCollection implements Set { UnmodifiableSet(Set inner) { super(inner); } } public static Set unmodifiableSet(Set hs) { return new UnmodifiableSet(hs); } private static final class ReverseComparator implements Comparator { Comparator cmp; public ReverseComparator(Comparator cmp) { this.cmp = cmp; } public int compare(T o1, T o2) { return - cmp.compare(o1, o2); } } public static List singletonList(T o) { ArrayList list = new ArrayList(1); list.add(o); return new UnmodifiableList(list); } } ReadyTalk-avian-1e1fff5/classpath/java/util/Comparator.java000066400000000000000000000006701231440243200240150ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface Comparator { public int compare(T o1, T o2); } ReadyTalk-avian-1e1fff5/classpath/java/util/ConcurrentModificationException.java000066400000000000000000000016431231440243200302360ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; /** * @author zsombor * */ public class ConcurrentModificationException extends RuntimeException { /** * @param message * @param cause */ public ConcurrentModificationException(String message, Throwable cause) { super(message, cause); } /** * @param message */ public ConcurrentModificationException(String message) { super(message); } /** * @param cause */ public ConcurrentModificationException(Throwable cause) { super(cause); } /** * */ public ConcurrentModificationException() { } } ReadyTalk-avian-1e1fff5/classpath/java/util/Date.java000066400000000000000000000012711231440243200225610ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class Date { public final long when; public Date() { when = System.currentTimeMillis(); } public Date(long when) { this.when = when; } public long getTime() { return when; } public String toString() { return toString(when); } private static native String toString(long when); } ReadyTalk-avian-1e1fff5/classpath/java/util/Deque.java000066400000000000000000000016411231440243200227500ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface Deque extends Queue { public boolean offerFirst(T e); public void push(T e); public void addFirst(T element); public boolean offerLast(T e); public void addLast(T element); public T peekFirst(); public T getFirst(); public T peekLast(); public T getLast(); public T pollFirst(); public T removeFirst(); public T pop(); public T pollLast(); public T removeLast(); public Iterator descendingIterator(); public boolean removeLastOccurrence(Object o); public boolean removeFirstOccurrence(Object o); } ReadyTalk-avian-1e1fff5/classpath/java/util/EmptyStackException.java000066400000000000000000000006601231440243200256500ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class EmptyStackException extends RuntimeException {} ReadyTalk-avian-1e1fff5/classpath/java/util/EnumSet.java000066400000000000000000000071371231440243200232730ustar00rootroot00000000000000package java.util; public class EnumSet> extends AbstractSet { private BitSet bitset; private Class elementType; private EnumSet(int size, Class type) { bitset = new BitSet(size); elementType = type; } @Override public boolean add(T element) { int index = element.ordinal(); boolean contains = bitset.get(index); if (!contains) { bitset.set(index); } return !contains; } @Override public boolean remove(Object toRemove) { T element = tryToCast(toRemove); int index = element.ordinal(); boolean contains = bitset.get(index); if (contains) { bitset.clear(index); } return contains; } @Override public boolean contains(Object toCheck) { T element = tryToCast(toCheck); int index = element.ordinal(); return bitset.get(index); } @Override public int size() { return bitset.cardinality(); } @Override public Iterator iterator() { return new EnumSetIterator(); } public static >EnumSet allOf(Class elementType) { EnumSet enumSet = createEmptyEnumSet(elementType); enumSet.bitset.set(0, elementType.getEnumConstants().length); return enumSet; } public static >EnumSet noneOf(Class elementType) { return createEmptyEnumSet(elementType); } public static >EnumSet of(T first, T ... rest) { EnumSet enumSet = createEmptyEnumSet(first.getDeclaringClass()); enumSet.add(first); addAllElementsToSet(Arrays.asList(rest), enumSet); return enumSet; } public static >EnumSet complementOf(EnumSet s) { EnumSet enumSet = copyOf(s); enumSet.bitset.flip(0, s.elementType.getEnumConstants().length); return enumSet; } public static >EnumSet copyOf(EnumSet s) { EnumSet enumSet = createEmptyEnumSet(s.elementType); enumSet.bitset.or(s.bitset); return enumSet; } private static >EnumSet createEmptyEnumSet(Class elementType) { T[] constants = elementType.getEnumConstants(); EnumSet enumSet = new EnumSet(constants.length, elementType); return enumSet; } private static > void addAllElementsToSet(Iterable elements, EnumSet enumSet) { for (T element : elements) { enumSet.add(element); } } @SuppressWarnings("unchecked") private T tryToCast(Object object) throws ClassCastException { //We want the class cast exception if we can't convert. return (T) object; } private class EnumSetIterator implements Iterator { private int currentIndex = 0; private boolean removeAllowed = false; public T next() { if (!hasNext()) { throw new NoSuchElementException("EnumSet has no more elements"); } int indexOfNextValue = nextIndex(); T element = elementType.getEnumConstants()[indexOfNextValue]; currentIndex = indexOfNextValue + 1; removeAllowed = true; return element; } public boolean hasNext() { int indexOfNextValue = nextIndex(); if (indexOfNextValue >= 0) { return true; } else { return false; } } public void remove() { if (!removeAllowed) { throw new IllegalStateException("Cannot remove from this iterator in this state"); } bitset.clear(currentIndex - 1); removeAllowed = false; } private int nextIndex() { return bitset.nextSetBit(currentIndex); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/Enumeration.java000066400000000000000000000007261231440243200241760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface Enumeration { public T nextElement(); public boolean hasMoreElements(); } ReadyTalk-avian-1e1fff5/classpath/java/util/EventListener.java000066400000000000000000000006271231440243200244770ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface EventListener { } ReadyTalk-avian-1e1fff5/classpath/java/util/EventObject.java000066400000000000000000000010461231440243200241140ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class EventObject { protected Object source; public EventObject(Object source) { this.source = source; } public Object getSource() { return source; } } ReadyTalk-avian-1e1fff5/classpath/java/util/HashMap.java000066400000000000000000000206031231440243200232250ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import avian.Data; public class HashMap implements Map { private static final int MinimumCapacity = 16; private int size; private Cell[] array; private final Helper helper; public HashMap(int capacity, Helper helper) { if (capacity > 0) { array = new Cell[Data.nextPowerOfTwo(capacity)]; } this.helper = helper; } public HashMap(int capacity) { this(capacity, new MyHelper()); } public HashMap() { this(0); } public HashMap(Map map) { this(map.size()); for (Map.Entry entry : map.entrySet()) { put(entry.getKey(), entry.getValue()); } } public String toString() { return avian.Data.toString(this); } public boolean isEmpty() { return size() == 0; } public int size() { return size; } private void grow() { if (array == null || size >= array.length * 2) { resize(array == null ? MinimumCapacity : array.length * 2); } } private void shrink() { if (array.length / 2 >= MinimumCapacity && size <= array.length / 3) { resize(array.length / 2); } } private void resize(int capacity) { Cell[] newArray = null; if (capacity != 0) { capacity = Data.nextPowerOfTwo(capacity); if (array != null && array.length == capacity) { return; } newArray = new Cell[capacity]; if (array != null) { for (int i = 0; i < array.length; ++i) { Cell next; for (Cell c = array[i]; c != null; c = next) { next = c.next(); int index = c.hashCode() & (capacity - 1); c.setNext(newArray[index]); newArray[index] = c; } } } } array = newArray; } protected Cell find(Object key) { if (array != null) { int index = helper.hash(key) & (array.length - 1); for (Cell c = array[index]; c != null; c = c.next()) { if (helper.equal(key, c.getKey())) { return c; } } } return null; } private void insert(Cell cell) { ++ size; grow(); int index = cell.hashCode() & (array.length - 1); cell.setNext(array[index]); array[index] = cell; } public void remove(Cell cell) { int index = cell.hashCode() & (array.length - 1); Cell p = null; for (Cell c = array[index]; c != null; c = c.next()) { if (c == cell) { if (p == null) { array[index] = c.next(); } else { p.setNext(c.next()); } -- size; break; } } shrink(); } private Cell putCell(K key, V value) { Cell c = find(key); if (c == null) { insert(helper.make(key, value, null)); } else { c.setValue(value); } return c; } public boolean containsKey(Object key) { return find(key) != null; } public boolean containsValue(Object value) { if (array != null) { for (int i = 0; i < array.length; ++i) { for (Cell c = array[i]; c != null; c = c.next()) { if (helper.equal(value, c.getValue())) { return true; } } } } return false; } public V get(Object key) { Cell c = find(key); return (c == null ? null : c.getValue()); } public Cell removeCell(Object key) { Cell old = null; if (array != null) { int index = helper.hash(key) & (array.length - 1); Cell p = null; for (Cell c = array[index]; c != null; c = c.next()) { if (helper.equal(key, c.getKey())) { old = c; if (p == null) { array[index] = c.next(); } else { p.setNext(c.next()); } -- size; break; } p = c; } shrink(); } return old; } public V put(K key, V value) { Cell c = find(key); if (c == null) { insert(helper.make(key, value, null)); return null; } else { V old = c.getValue(); c.setValue(value); return old; } } public void putAll(Map elts) { for (Map.Entry entry : elts.entrySet()) { put(entry.getKey(), entry.getValue()); } } public V remove(Object key) { Cell c = removeCell((K)key); return (c == null ? null : c.getValue()); } public void clear() { array = null; size = 0; } public Set> entrySet() { return new Data.EntrySet(new MyEntryMap()); } public Set keySet() { return new Data.KeySet(new MyEntryMap()); } public Collection values() { return new Data.Values(new MyEntryMap()); } Iterator> iterator() { return new MyIterator(); } private class MyEntryMap implements Data.EntryMap { public int size() { return HashMap.this.size(); } public Entry find(Object key) { return HashMap.this.find(key); } public Entry remove(Object key) { return removeCell(key); } public void clear() { HashMap.this.clear(); } public Iterator> iterator() { return HashMap.this.iterator(); } } interface Cell extends Entry { public HashMap.Cell next(); public void setNext(HashMap.Cell next); } interface Helper { public Cell make(K key, V value, Cell next); public int hash(K key); public boolean equal(K a, K b); } private static class MyCell implements Cell { public final K key; public V value; public Cell next; public int hashCode; public MyCell(K key, V value, Cell next, int hashCode) { this.key = key; this.value = value; this.next = next; this.hashCode = hashCode; } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V old = this.value; this.value = value; return old; } public HashMap.Cell next() { return next; } public void setNext(HashMap.Cell next) { this.next = next; } public int hashCode() { return hashCode; } } static class MyHelper implements Helper { public Cell make(K key, V value, Cell next) { return new MyCell(key, value, next, hash(key)); } public int hash(K a) { return (a == null ? 0 : a.hashCode()); } public boolean equal(K a, K b) { return (a == null && b == null) || (a != null && a.equals(b)); } } private class MyIterator implements Iterator> { private int currentIndex = -1; private int nextIndex = -1; private Cell previousCell; private Cell currentCell; private Cell nextCell; public MyIterator() { hasNext(); } public Entry next() { if (hasNext()) { if (currentCell != null) { if (currentCell.next() != null) { previousCell = currentCell; } else { previousCell = null; } } currentCell = nextCell; currentIndex = nextIndex; nextCell = nextCell.next(); return currentCell; } else { throw new NoSuchElementException(); } } public boolean hasNext() { if (array != null) { while (nextCell == null && ++ nextIndex < array.length) { if (array[nextIndex] != null) { nextCell = array[nextIndex]; return true; } } } return nextCell != null; } public void remove() { if (currentCell != null) { if (previousCell == null) { array[currentIndex] = currentCell.next(); } else { previousCell.setNext(currentCell.next()); if (previousCell.next() == null) { previousCell = null; } } currentCell = null; -- size; } else { throw new IllegalStateException(); } } } } ReadyTalk-avian-1e1fff5/classpath/java/util/HashSet.java000066400000000000000000000035071231440243200232470ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class HashSet extends AbstractSet implements Set { private static final Object Value = new Object(); private final HashMap map; public HashSet(Collection c) { map = new HashMap(c.size()); addAll(c); } public HashSet(int capacity) { map = new HashMap(capacity); } public HashSet() { this(0); } public int size() { return map.size(); } public boolean isEmpty() { return map.isEmpty(); } public boolean contains(Object element) { return map.containsKey(element); } public boolean add(T element) { return map.put(element, Value) != Value; } public boolean addAll(Collection collection) { boolean change = false; for (T t: collection) if (add(t)) change = true; return change; } public boolean remove(Object element) { return map.remove(element) != Value; } public void clear() { map.clear(); } public Iterator iterator() { return new MyIterator(map.iterator()); } public String toString() { return avian.Data.toString(this); } private static class MyIterator implements Iterator { private final Iterator> it; public MyIterator(Iterator> it) { this.it = it; } public T next() { return it.next().getKey(); } public boolean hasNext() { return it.hasNext(); } public void remove() { it.remove(); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/Hashtable.java000066400000000000000000000040631231440243200236010ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class Hashtable implements Map { private final HashMap map; public Hashtable(int capacity) { map = new HashMap(capacity); } public Hashtable() { this(0); } public Hashtable(Map m) { this(m.size()); for (Entry entry : m.entrySet()) { put(entry.getKey(), entry.getValue()); } } public synchronized String toString() { return map.toString(); } public synchronized boolean isEmpty() { return map.isEmpty(); } public synchronized int size() { return map.size(); } public synchronized boolean containsKey(Object key) { return map.containsKey(key); } public synchronized boolean containsValue(Object value) { return map.containsValue(value); } public synchronized V get(Object key) { return map.get(key); } public synchronized V put(K key, V value) { return map.put(key, value); } public synchronized void putAll(Map elts) { map.putAll(elts); } public synchronized V remove(Object key) { return map.remove(key); } public synchronized void clear() { map.clear(); } public Enumeration keys() { return new Collections.IteratorEnumeration(keySet().iterator()); } public Enumeration elements() { return new Collections.IteratorEnumeration(values().iterator()); } public Set> entrySet() { return new Collections.SynchronizedSet(this, map.entrySet()); } public Set keySet() { return new Collections.SynchronizedSet(this, map.keySet()); } public Collection values() { return new Collections.SynchronizedCollection(this, map.values()); } } ReadyTalk-avian-1e1fff5/classpath/java/util/IdentityHashMap.java000066400000000000000000000031601231440243200247360ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class IdentityHashMap implements Map { private final HashMap map; public IdentityHashMap(int capacity) { map = new HashMap(capacity, new MyHelper()); } public IdentityHashMap() { this(0); } public boolean isEmpty() { return map.isEmpty(); } public int size() { return map.size(); } public boolean containsKey(Object key) { return map.containsKey(key); } public boolean containsValue(Object value) { return map.containsValue(value); } public V get(Object key) { return map.get(key); } public V put(K key, V value) { return map.put(key, value); } public void putAll(Map elts) { map.putAll(elts); } public V remove(Object key) { return map.remove(key); } public void clear() { map.clear(); } public Set> entrySet() { return map.entrySet(); } public Set keySet() { return map.keySet(); } public Collection values() { return map.values(); } private static class MyHelper extends HashMap.MyHelper { public int hash(K a) { return (a == null ? 0 : System.identityHashCode(a)); } public boolean equal(K a, K b) { return a == b; } } } ReadyTalk-avian-1e1fff5/classpath/java/util/Iterator.java000066400000000000000000000007351231440243200235010ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface Iterator { public T next(); public boolean hasNext(); public void remove(); } ReadyTalk-avian-1e1fff5/classpath/java/util/LinkedHashMap.java000066400000000000000000000133301231440243200243530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class LinkedHashMap extends HashMap { private static class LinkedKey { private final K key; private LinkedKey previous, next; public LinkedKey(K key) { this.key = key; } public boolean equals(Object other) { LinkedKey o = (LinkedKey) other; return key.equals(o.key); } public int hashCode() { return key.hashCode(); } } private LinkedKey first, last; private HashMap> lookup; public LinkedHashMap(int capacity) { super(capacity); lookup = new HashMap>(); } public LinkedHashMap() { this(0); } public LinkedHashMap(Map map) { this(map.size()); putAll(map); } public V put(K key, V value) { if (!super.containsKey(key)) { LinkedKey k = new LinkedKey(key); if (first == null) { first = k; } else { last.next = k; k.previous = last; } last = k; lookup.put(key, k); } return super.put(key, value); } public V remove(Object key) { LinkedKey linked = lookup.get(key); if (linked == null) { return null; } if (linked.previous == null) { first = linked.next; } else { linked.previous.next = linked.next; } if (linked.next == null) { last = linked.previous; } else { linked.next.previous = linked.previous; } return super.remove(key); } public void clear() { first = last = null; super.clear(); } public Set> entrySet() { return new EntrySet(); } public Set keySet() { return new KeySet(); } public Collection values() { return new Values(); } Iterator> iterator() { return new MyIterator(); } private class EntrySet extends AbstractSet> { public int size() { return LinkedHashMap.this.size(); } public boolean isEmpty() { return LinkedHashMap.this.isEmpty(); } public boolean contains(Object o) { return (o instanceof Entry) && containsKey(((Entry)o).getKey()); } public boolean add(Entry e) { return put(e.getKey(), e.getValue()) != null; } public boolean remove(Object o) { return (o instanceof Entry) && remove((Entry)o); } public boolean remove(Entry e) { return LinkedHashMap.this.remove(e.getKey()) != null; } public Object[] toArray() { return toArray(new Object[size()]); } public T[] toArray(T[] array) { return avian.Data.toArray(this, array); } public void clear() { LinkedHashMap.this.clear(); } public Iterator> iterator() { return new MyIterator(); } } private class KeySet extends AbstractSet { public int size() { return LinkedHashMap.this.size(); } public boolean isEmpty() { return LinkedHashMap.this.isEmpty(); } public boolean contains(Object key) { return containsKey(key); } public boolean add(K key) { return put(key, null) != null; } public boolean remove(Object key) { return LinkedHashMap.this.remove(key) != null; } public Object[] toArray() { return toArray(new Object[size()]); } public T[] toArray(T[] array) { return avian.Data.toArray(this, array); } public void clear() { LinkedHashMap.this.clear(); } public Iterator iterator() { return new avian.Data.KeyIterator(new MyIterator()); } } private class Values implements Collection { public int size() { return LinkedHashMap.this.size(); } public boolean isEmpty() { return LinkedHashMap.this.isEmpty(); } public boolean contains(Object value) { return containsValue(value); } public boolean containsAll(Collection c) { if (c == null) { throw new NullPointerException("collection is null"); } Iterator it = c.iterator(); while (it.hasNext()) { if (! contains(it.next())) { return false; } } return true; } public boolean add(V value) { throw new UnsupportedOperationException(); } public boolean addAll(Collection collection) { throw new UnsupportedOperationException(); } public boolean remove(Object value) { throw new UnsupportedOperationException(); } public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } public Object[] toArray() { return toArray(new Object[size()]); } public T[] toArray(T[] array) { return avian.Data.toArray(this, array); } public void clear() { LinkedHashMap.this.clear(); } public Iterator iterator() { return new avian.Data.ValueIterator(new MyIterator()); } } private class MyIterator implements Iterator> { private LinkedKey current = first; public Entry next() { if (!hasNext()) { throw new NoSuchElementException(); } Entry result = find(current.key); current = current.next; return result; } public boolean hasNext() { return current != null; } public void remove() { LinkedHashMap.this.remove(current == null ? last.key : current.previous.key); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/LinkedHashSet.java000066400000000000000000000035621231440243200243770ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class LinkedHashSet extends AbstractSet implements Set { private static final Object Value = new Object(); private final LinkedHashMap map; public LinkedHashSet(Collection c) { map = new LinkedHashMap(c.size()); addAll(c); } public LinkedHashSet(int capacity) { map = new LinkedHashMap(capacity); } public LinkedHashSet() { this(0); } public int size() { return map.size(); } public boolean isEmpty() { return map.isEmpty(); } public boolean contains(Object element) { return map.containsKey(element); } public boolean add(T element) { return map.put(element, Value) != Value; } public boolean addAll(Collection collection) { boolean change = false; for (T t: collection) if (add(t)) change = true; return change; } public boolean remove(Object element) { return map.remove(element) != Value; } public void clear() { map.clear(); } public Iterator iterator() { return new MyIterator(map.iterator()); } public String toString() { return avian.Data.toString(this); } private static class MyIterator implements Iterator { private final Iterator> it; public MyIterator(Iterator> it) { this.it = it; } public T next() { return it.next().getKey(); } public boolean hasNext() { return it.hasNext(); } public void remove() { it.remove(); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/LinkedList.java000066400000000000000000000202331231440243200237450ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class LinkedList extends AbstractSequentialList implements Deque { private Cell front; private Cell rear; private int size; public LinkedList(Collection c) { addAll(c); } public LinkedList() { } private Cell find(int index) { int i = 0; for (Cell c = front; c != null; c = c.next) { if (i == index) { return c; } ++ i; } throw new IndexOutOfBoundsException(index + " not in [0, " + size + ")"); } private static boolean equal(Object a, Object b) { return (a == null && b == null) || (a != null && a.equals(b)); } private void addFirst(Cell c) { ++ size; if (front == null) { front = rear = c; } else { c.next = front; front.prev = c; front = c; } } private void addLast(Cell c) { ++ size; if (front == null) { front = rear = c; } else { c.prev = rear; rear.next = c; rear = c; } } private Cell find(Object element) { for (Cell c = front; c != null; c = c.next) { if (equal(c.value, element)) { return c; } } return null; } private void remove(Cell c) { -- size; if (c.prev == null) { front = c.next; } else { c.prev.next = c.next; } if (c.next == null) { rear = c.prev; } else { c.next.prev = c.prev; } } @Override public int size() { return size; } @Override public boolean contains(Object element) { return find(element) != null; } @Override public int indexOf(Object element) { int i = 0; for (Cell c = front; c != null; c = c.next) { if (equal(c.value, element)) { return i; } ++ i; } return -1; } @Override public int lastIndexOf(Object element) { int i = size; for (Cell c = rear; c != null; c = c.prev) { -- i; if (equal(c.value, element)) { return i; } } return -1; } @Override public boolean offer(T element) { return add(element); } @Override public boolean add(T element) { addLast(element); return true; } @Override public boolean addAll(Collection collection) { for (T t: collection) add(t); return true; } @Override public void add(int index, T element) { if (index == 0) { addFirst(element); } else { Cell cell = find(index); Cell newCell = new Cell(element, cell.prev, cell); cell.prev.next = newCell; } } @Override public boolean offerFirst(T e) { addFirst(e); return true; } @Override public void push(T e) { addFirst(e); } @Override public void addFirst(T element) { addFirst(new Cell(element, null, null)); } @Override public boolean offerLast(T e) { addLast(e); return true; } @Override public void addLast(T element) { addLast(new Cell(element, null, null)); } public T get(int index) { return find(index).value; } @Override public T set(int index, T value) { Cell c = find(index); T old = c.value; c.value = value; return old; } @Override public T peek() { return peekFirst(); } @Override public T peekFirst() { if (front != null) { return front.value; } else { return null; } } @Override public T getFirst() { if (front != null) { return front.value; } else { throw new NoSuchElementException(); } } @Override public T peekLast() { if (rear != null) { return rear.value; } else { return null; } } @Override public T getLast() { if (rear != null) { return rear.value; } else { throw new NoSuchElementException(); } } @Override public T remove(int index) { Cell c = find(index); remove(c); return c.value; } @Override public boolean isEmpty() { return size() == 0; } @Override public T poll() { return pollFirst(); } @Override public T pollFirst() { if (front != null) { T v = front.value; remove(front); return v; } else { return null; } } @Override public T removeFirst() { T result = pollFirst(); if (result == null) { throw new NoSuchElementException(); } else { return result; } } @Override public T pop() { return removeFirst(); } @Override public T remove() { return removeFirst(); } @Override public T pollLast() { if (rear != null) { T v = rear.value; remove(rear); return v; } else { throw new NoSuchElementException(); } } @Override public T removeLast() { T result = pollLast(); if (result == null) { throw new NoSuchElementException(); } else { return result; } } @Override public boolean remove(Object element) { Cell c = find(element); if (c == null) { return false; } else { remove(c); return true; } } @Override public void clear() { front = rear = null; size = 0; } @Override public Iterator iterator() { return listIterator(); } @Override public ListIterator listIterator() { return listIterator(0); } @Override public ListIterator listIterator(int index) { MyIterator it = new MyIterator(); for (int i = 0; i < index; ++i) { it.next(); } return it; } @Override public Iterator descendingIterator() { final ListIterator li = listIterator(size()); return new Iterator() { @Override public T next() { return li.previous(); } @Override public boolean hasNext() { return li.hasPrevious(); } @Override public void remove() { li.remove(); } }; } @Override public String toString() { return avian.Data.toString(this); } @Override public T element() { T result = peek(); if (result == null) { throw new NoSuchElementException(); } else { return result; } } @Override public boolean removeFirstOccurrence(Object o) { int index = indexOf(o); if (index > 0) { remove(index); return true; } else { return false; } } @Override public boolean removeLastOccurrence(Object o) { int lastIndex = lastIndexOf(o); if (lastIndex > 0) { remove(lastIndex); return true; } else { return false; } } private static class Cell { public T value; public Cell prev; public Cell next; public Cell(T value, Cell prev, Cell next) { this.value = value; this.prev = prev; this.next = next; } } private class MyIterator implements ListIterator { private Cell toRemove; private Cell current; public T previous() { if (hasPrevious()) { T v = current.value; toRemove = current; current = current.prev; return v; } else { throw new NoSuchElementException(); } } public T next() { if (hasNext()) { if (current == null) { current = front; } else { current = current.next; } toRemove = current; return current.value; } else { throw new NoSuchElementException(); } } public boolean hasNext() { if (current == null) { return front != null; } else { return current.next != null; } } public boolean hasPrevious() { return current != null; } public void remove() { if (toRemove != null) { current = toRemove.prev; LinkedList.this.remove(toRemove); toRemove = null; } else { throw new IllegalStateException(); } } } } ReadyTalk-avian-1e1fff5/classpath/java/util/List.java000066400000000000000000000015361231440243200226230ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface List extends Collection { public T get(int index); public T set(int index, T value); public T remove(int index); public boolean add(T element); public void add(int index, T element); public boolean addAll(int startIndex, Collection c); public int indexOf(Object value); public int lastIndexOf(Object value); public boolean isEmpty(); public ListIterator listIterator(int index); public ListIterator listIterator(); } ReadyTalk-avian-1e1fff5/classpath/java/util/ListIterator.java000066400000000000000000000007431231440243200243340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface ListIterator extends Iterator { public boolean hasPrevious(); public E previous(); } ReadyTalk-avian-1e1fff5/classpath/java/util/Locale.java000066400000000000000000000030761231440243200231100ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class Locale { private static final Locale DEFAULT; public static final Locale ENGLISH = new Locale("en", ""); private final String language; private final String country; private final String variant; static { DEFAULT = new Locale(System.getProperty("user.language"), System.getProperty("user.region")); } public Locale(String language, String country, String variant) { this.language = language; this.country = country; this.variant = variant; } public Locale(String language, String country) { this(language, country, ""); } public Locale(String language) { this(language, ""); } public String getLanguage() { return language; } public String getCountry() { return country; } public String getVariant() { return variant; } public static Locale getDefault() { return DEFAULT; } public final String toString() { boolean hasLanguage = language != ""; boolean hasCountry = country != ""; boolean hasVariant = variant != ""; if (!hasLanguage && !hasCountry) return ""; return language + (hasCountry || hasVariant ? '_' + country : "") + (hasVariant ? '_' + variant : ""); } } ReadyTalk-avian-1e1fff5/classpath/java/util/Map.java000066400000000000000000000016501231440243200224220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface Map { public boolean isEmpty(); public int size(); public boolean containsKey(Object obj); public boolean containsValue(Object obj); public V get(Object key); public V put(K key, V value); public void putAll(Map elts); public V remove(Object key); public void clear(); public Set> entrySet(); public Set keySet(); public Collection values(); public interface Entry { public K getKey(); public V getValue(); public V setValue(V value); } } ReadyTalk-avian-1e1fff5/classpath/java/util/MissingResourceException.java000066400000000000000000000013601231440243200267030ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class MissingResourceException extends RuntimeException { private final String class_; private final String key; public MissingResourceException(String message, String class_, String key) { super(message); this.class_ = class_; this.key = key; } public String getClassName() { return class_; } public String getKey() { return key; } } ReadyTalk-avian-1e1fff5/classpath/java/util/NoSuchElementException.java000066400000000000000000000010641231440243200262740ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class NoSuchElementException extends RuntimeException { public NoSuchElementException(String message) { super(message); } public NoSuchElementException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/util/Objects.java000066400000000000000000000045511231440243200233010ustar00rootroot00000000000000package java.util; public final class Objects { private Objects() { throw new AssertionError("Instantiating java.long.Objetcs is not allowed!"); } public static int compare(final T x, final T y, final Comparator comparator) { if (x == y) return 0; else return comparator.compare(x, y); } public static boolean deepEquals(final Object x, final Object y) { if (x == y) return true; if (x == null || y == null) return false; if (x.getClass().isArray()) { if(x instanceof Object[] && y instanceof Object[]) return Arrays.deepEquals((Object[])x, (Object[])y); if(x instanceof byte[] && y instanceof byte[]) return Arrays.equals((byte[]) x, (byte[]) y); if(x instanceof int[] && y instanceof int[]) return Arrays.equals((int[]) x, (int[]) y); if(x instanceof long[] && y instanceof long[]) return Arrays.equals((long[]) x, (long[]) y); if(x instanceof short[] && y instanceof short[]) return Arrays.equals((short[]) x, (short[]) y); if(x instanceof char[] && y instanceof char[]) return Arrays.equals((char[]) x, (char[]) y); if(x instanceof float[] && y instanceof float[]) return Arrays.equals((float[]) x, (float[]) y); if(x instanceof double[] && y instanceof double[]) return Arrays.equals((double[]) x, (double[]) y); } return x.equals(y); } public static boolean equals(final Object x, final Object y) { if (x == y) return true; if (x != null) return x.equals(y); return false; } public static int hash(final Object... values) { return Arrays.hashCode(values); } public static int hashCode(final Object value) { if (value == null) return 0; return value.hashCode(); } public static T requireNonNull(final T value) { if (value == null) throw new NullPointerException(); else return value; } public static T requireNonNull(final T value, String message) { if (value == null) throw new NullPointerException(message); else return value; } public static String toString(final Object value) { return String.valueOf(value); } public static String toString(final Object value, final String defaultValue) { if (value == null) return defaultValue; return value.toString(); } } ReadyTalk-avian-1e1fff5/classpath/java/util/Observable.java000066400000000000000000000030361231440243200237710ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class Observable { private List observers = new ArrayList(); private boolean changed = false; public void addObserver(Observer o) { if(o == null) { throw new NullPointerException(); } synchronized(this) { if(!observers.contains(o)) { observers.add(o); } } } public synchronized int countObservers() { return observers.size(); } public void deleteObserver(Observer o) { if(o == null) { throw new NullPointerException(); } synchronized(this) { observers.remove(o); } } public void notifyObservers() { notifyObservers(null); } public synchronized void notifyObservers(Object value) { Observer[] obsArray = null; synchronized(this) { if(hasChanged()) { clearChanged(); obsArray = observers.toArray(new Observer[observers.size()]); } } if(obsArray != null) { for(Observer obs : obsArray) { obs.update(this, value); } } } public boolean hasChanged() { return changed; } protected void setChanged() { changed = true; } protected void clearChanged() { changed = false; } }ReadyTalk-avian-1e1fff5/classpath/java/util/Observer.java000066400000000000000000000007001231440243200234670ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface Observer { public void update(Observable o, Object arg); }ReadyTalk-avian-1e1fff5/classpath/java/util/Properties.java000066400000000000000000000113261231440243200240420ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.IOException; import java.io.Reader; public class Properties extends Hashtable { public void load(InputStream in) throws IOException { new InputStreamParser(in).parse(this); } public void load(Reader reader) throws IOException { new ReaderParser(reader).parse(this); } public void store(OutputStream out, String comment) throws IOException { PrintStream os = new PrintStream(out); os.println("# " + comment); for (Iterator it = entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry)it.next(); os.print(entry.getKey()); os.print('='); os.println(entry.getValue()); } os.flush(); } public String getProperty(String key) { return (String)get(key); } public String getProperty(String key, String defaultValue) { String value = (String) get(key); if (value == null) { return defaultValue; } return value; } public Object setProperty(String key, String value) { return put(key, value); } public Enumeration propertyNames() { return keys(); } private abstract static class Parser { private StringBuilder key = null; private StringBuilder value = null; private StringBuilder current = null; private void append(int c) { if (current == null) { if (key == null) { current = key = new StringBuilder(); } else { current = value = new StringBuilder(); } } current.append((char) c); } private void finishLine(Map map) { if (key != null) { map.put(key.toString(), (value == null ? "" : value.toString().trim())); } key = value = current = null; } abstract int readCharacter() throws IOException; char readUtf16() throws IOException { char c = 0; for (int i = 0; i < 4; ++i) { int digit = Character.digit((char)readCharacter(), 16); if (digit == -1) throw new IOException("Invalid Unicode escape encountered."); c <<= 4; c |= digit; } return c; } void parse(Map map) throws IOException { boolean escaped = false; int c; while ((c = readCharacter()) != -1) { if (c == '\\') { if (escaped) { escaped = false; append(c); } else { escaped = true; } } else { switch (c) { case '#': case '!': if (key == null) { while ((c = readCharacter()) != -1 && c != '\n'); } else { append(c); } break; case ' ': case '\r': case '\t': if (escaped || (current != null && value == current)) { append(c); } else if (key == current) { current = null; } break; case ':': case '=': if (escaped || (current != null && value == current)) { append(c); } else { if (key == null) { key = new StringBuilder(); } current = null; } break; case '\n': if (escaped) { append(c); } else { finishLine(map); } break; case 'n': if (escaped) { append('\n'); } else { append(c); } break; case 'u': if (escaped) { append(readUtf16()); } else { append(c); } break; default: append(c); break; } escaped = false; } } finishLine(map); } } static class InputStreamParser extends Parser { InputStream in; public InputStreamParser(InputStream in) { this.in = in; } @Override int readCharacter() throws IOException { return in.read(); } } static class ReaderParser extends Parser { Reader in; public ReaderParser(Reader in) { this.in = in; } @Override int readCharacter() throws IOException { return in.read(); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/PropertyResourceBundle.java000066400000000000000000000014131231440243200263700ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import java.io.InputStream; import java.io.IOException; public class PropertyResourceBundle extends ResourceBundle { private final Properties map = new Properties(); public PropertyResourceBundle(InputStream in) throws IOException { map.load(in); } public Object handleGetObject(String key) { return map.get(key); } public Enumeration getKeys() { return map.keys(); } } ReadyTalk-avian-1e1fff5/classpath/java/util/Queue.java000066400000000000000000000011111231440243200227610ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface Queue extends Collection, Iterable { public boolean add(T element); public T element(); public boolean offer(T element); public T peek(); public T poll(); public T remove(); } ReadyTalk-avian-1e1fff5/classpath/java/util/Random.java000066400000000000000000000036761231440243200231370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class Random { private static final long Mask = 0x5DEECE66DL; private static final long InitialSeed = 123456789987654321L; private static long nextSeed = InitialSeed; private long seed; public Random(long seed) { setSeed(seed); } public Random() { synchronized (Random.class) { setSeed(nextSeed ^ System.currentTimeMillis()); nextSeed *= 123456789987654321L; if (nextSeed == 0) { nextSeed = InitialSeed; } } } public void setSeed(long seed) { this.seed = (seed ^ Mask) & ((1L << 48) - 1); } protected int next(int bits) { seed = ((seed * Mask) + 0xBL) & ((1L << 48) - 1); return (int) (seed >>> (48 - bits)); } public int nextInt(int limit) { if (limit <= 0) { throw new IllegalArgumentException(); } if ((limit & -limit) == limit) { // limit is a power of two return (int) ((limit * (long) next(31)) >> 31); } int bits; int value; do { bits = next(31); value = bits % limit; } while (bits - value + (limit - 1) < 0); return value; } public int nextInt() { return next(32); } public void nextBytes(byte[] bytes) { final int length = bytes.length; for (int i = 0; i < length;) { int r = nextInt(); for (int j = Math.min(length - i, 4); j > 0; --j) { bytes[i++] = (byte) r; r >>= 8; } } } public long nextLong() { return ((long) next(32) << 32) + next(32); } public double nextDouble() { return (((long) next(26) << 27) + next(27)) / (double) (1L << 53); } } ReadyTalk-avian-1e1fff5/classpath/java/util/RandomAccess.java000066400000000000000000000006251231440243200242500ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface RandomAccess { } ReadyTalk-avian-1e1fff5/classpath/java/util/ResourceBundle.java000066400000000000000000000066711231440243200246360ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import java.lang.reflect.Method; import java.io.InputStream; import java.io.IOException; public abstract class ResourceBundle { protected String name; protected ResourceBundle parent; private static String replace(char a, char b, String s) { char[] array = new char[s.length()]; for (int i = 0; i < array.length; ++i) { char c = s.charAt(i); array[i] = (c == a ? b : c); } return new String(array, 0, array.length, false); } private static ResourceBundle findProperties(String name, ClassLoader loader, ResourceBundle parent) throws IOException { InputStream in = loader.getResourceAsStream (replace('.', '/', name) + ".properties"); if (in != null) { try { ResourceBundle r = new PropertyResourceBundle(in); r.name = name; r.parent = parent; return r; } finally { in.close(); } } else { return null; } } private static ResourceBundle find(String name, ClassLoader loader, ResourceBundle parent) throws Exception { try { Class c = Class.forName(name, true, loader); if (c.isAssignableFrom(ResourceBundle.class)) { return (ResourceBundle) c.getConstructor().newInstance(); } } catch (ClassNotFoundException ok) { } catch (NoSuchMethodException ok) { } return findProperties(name, loader, parent); } public static ResourceBundle getBundle(String name, Locale locale, ClassLoader loader) { try { ResourceBundle b = find(name, loader, null); if (locale.getLanguage() != null) { name = name + "_" + locale.getLanguage(); ResourceBundle b2 = find(name, loader, b); if (b2 != null) b = b2; if (locale.getCountry() != null) { name = name + "_" + locale.getCountry(); b2 = find(name, loader, b); if (b2 != null) b = b2; if (locale.getVariant() != null) { name = name + "_" + locale.getVariant(); b2 = find(name, loader, b); if (b2 != null) b = b2; } } } return b; } catch (Exception e) { RuntimeException re = new MissingResourceException(name, name, null); re.initCause(e); throw re; } } public static ResourceBundle getBundle(String name, Locale locale) { return getBundle(name, locale, Method.getCaller().class_.loader); } public static ResourceBundle getBundle(String name) { return getBundle (name, Locale.getDefault(), Method.getCaller().class_.loader); } public Object getObject(String key) { for (ResourceBundle b = this; b != null; b = b.parent) { Object value = b.handleGetObject(key); if (value != null) { return value; } } throw new MissingResourceException(key, name, key); } public String getString(String key) { return (String) getObject(key); } protected abstract Object handleGetObject(String key); public abstract Enumeration getKeys(); } ReadyTalk-avian-1e1fff5/classpath/java/util/Set.java000066400000000000000000000006451231440243200224430ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface Set extends Collection { } ReadyTalk-avian-1e1fff5/classpath/java/util/SortedSet.java000066400000000000000000000012501231440243200236150ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public interface SortedSet extends Collection, Iterable, Set { public Comparator comparator(); public T first(); public SortedSet headSet(T toElement); public T last(); public SortedSet subSet(T fromElement, T toElement); public SortedSet tailSet(T fromElement); } ReadyTalk-avian-1e1fff5/classpath/java/util/Stack.java000066400000000000000000000012121231440243200227440ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class Stack extends Vector { public boolean empty() { return size() == 0; } public T peek() { return get(size() - 1); } public T pop() { return remove(size() - 1); } public T push(T element) { add(element); return element; } } ReadyTalk-avian-1e1fff5/classpath/java/util/StringTokenizer.java000066400000000000000000000046431231440243200250530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class StringTokenizer implements Enumeration { private final String in; private String delimiters; private final boolean includeDelimiters; private int position; public StringTokenizer(String in, String delimiters, boolean includeDelimiters) { this.in = in; this.delimiters = delimiters; this.includeDelimiters = includeDelimiters; } public StringTokenizer(String in, String delimiters) { this(in, delimiters, false); } public StringTokenizer(String in) { this(in, " \t\r\n\f"); } private boolean isDelimiter(char c) { return delimiters.indexOf(c) >= 0; } public int countTokens() { int count = 0; boolean sawNonDelimiter = false; for (int i = position; i < in.length(); ++i) { if (isDelimiter(in.charAt(i))) { if (sawNonDelimiter) { sawNonDelimiter = false; ++ count; } if (includeDelimiters) { ++ count; } } else { sawNonDelimiter = true; } } if (sawNonDelimiter) { ++ count; } return count; } public boolean hasMoreTokens() { for (int i = position; i < in.length(); ++i) { if (isDelimiter(in.charAt(i))) { if (includeDelimiters) { return true; } } else { position = i; return true; } } return false; } public String nextToken() { for (int i = position; i < in.length(); ++i) { if (isDelimiter(in.charAt(i))) { if (includeDelimiters) { return in.substring(i, i + 1); } } else { position = i; while (position < in.length() && ! isDelimiter(in.charAt(position))) { ++ position; } return in.substring(i, position); } } throw new NoSuchElementException(); } public String nextToken(String delimiters) { this.delimiters = delimiters; return nextToken(); } public boolean hasMoreElements() { return hasMoreTokens(); } public Object nextElement() { return nextToken(); } } ReadyTalk-avian-1e1fff5/classpath/java/util/TimeZone.java000066400000000000000000000015101231440243200234320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class TimeZone { // for now, we only support GMT private static final TimeZone GMT = new TimeZone("GMT"); private final String name; private TimeZone(String name) { this.name = name; } public static TimeZone getTimeZone(String id) { // technically the Java spec says that this method // returns GMT if it can't understand the "id" parameter // sigh. return GMT; } public String getDisplayName() { return name; } } ReadyTalk-avian-1e1fff5/classpath/java/util/TreeMap.java000066400000000000000000000136251231440243200232470ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class TreeMap implements Map { private final Comparator comparator; private transient TreeSet> set; public TreeMap(Comparator comparator) { this.comparator = comparator; initializeSet(); } private void initializeSet() { final Comparator comparator = this.comparator != null ? this.comparator : new Comparator() { public int compare(K a, K b) { return ((Comparable) a).compareTo(b); } }; set = new TreeSet(new Comparator>() { public int compare(MyEntry a, MyEntry b) { return comparator.compare(a.key, b.key); } }); } public TreeMap() { this(null); } public String toString() { return avian.Data.toString(this); } public V get(Object key) { MyEntry e = set.find(new MyEntry(key, null)); return e == null ? null : e.value; } public V put(K key, V value) { MyEntry e = set.addAndReplace(new MyEntry(key, value)); return e == null ? null : e.value; } public void putAll(Map elts) { for (Map.Entry entry : elts.entrySet()) { put(entry.getKey(), entry.getValue()); } } public V remove(Object key) { MyEntry e = set.removeAndReturn(new MyEntry(key, null)); return e == null ? null : e.value; } public void clear() { set.clear(); } public int size() { return set.size(); } public boolean isEmpty() { return size() == 0; } public boolean containsKey(Object key) { return set.contains(new MyEntry(key, null)); } private boolean equal(Object a, Object b) { return a == null ? b == null : a.equals(b); } public boolean containsValue(Object value) { for (V v: values()) { if (equal(v, value)) { return true; } } return false; } public Set> entrySet() { return (Set>) (Set) set; } public Set keySet() { return new KeySet(); } public Collection values() { return new Values(); } private static class MyEntry implements Entry { public final K key; public V value; public MyEntry(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V old = this.value; this.value = value; return old; } } private class KeySet extends AbstractSet { public int size() { return TreeMap.this.size(); } public boolean isEmpty() { return TreeMap.this.isEmpty(); } public boolean contains(Object key) { return containsKey(key); } public boolean add(K key) { return set.addAndReplace(new MyEntry(key, null)) != null; } public boolean addAll(Collection collection) { boolean change = false; for (K k: collection) if (add(k)) change = true; return change; } public boolean remove(Object key) { return set.removeAndReturn(new MyEntry(key, null)) != null; } public Object[] toArray() { return toArray(new Object[size()]); } public T[] toArray(T[] array) { return avian.Data.toArray(this, array); } public void clear() { TreeMap.this.clear(); } public Iterator iterator() { return new avian.Data.KeyIterator(set.iterator()); } } private class Values implements Collection { public int size() { return TreeMap.this.size(); } public boolean isEmpty() { return TreeMap.this.isEmpty(); } public boolean contains(Object value) { return containsValue(value); } public boolean containsAll(Collection c) { if (c == null) { throw new NullPointerException("collection is null"); } Iterator it = c.iterator(); while (it.hasNext()) { if (! contains(it.next())) { return false; } } return true; } public boolean add(V value) { throw new UnsupportedOperationException(); } public boolean addAll(Collection collection) { throw new UnsupportedOperationException(); } public boolean remove(Object value) { throw new UnsupportedOperationException(); } public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } public Object[] toArray() { return toArray(new Object[size()]); } public T[] toArray(T[] array) { return avian.Data.toArray(this, array); } public void clear() { TreeMap.this.clear(); } public Iterator iterator() { return new avian.Data.ValueIterator(set.iterator()); } } public final static long serialVersionUID = 0x0cc1f63e2d256ae6l; private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(size()); for (Entry entry : entrySet()) { out.writeObject(entry.getKey()); out.writeObject(entry.getValue()); } } private void readObject(ObjectInputStream in) throws IOException { in.defaultReadObject(); initializeSet(); int size = in.readInt(); for (int i = 0; i < size; i++) try { put((K) in.readObject(), (V) in.readObject()); } catch (ClassNotFoundException e) { throw new IOException(e); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/TreeSet.java000066400000000000000000000122301231440243200232540ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import avian.PersistentSet; import avian.Cell; public class TreeSet extends AbstractSet implements Collection { private PersistentSet> set; public TreeSet(final Comparator comparator) { set = new PersistentSet(new Comparator>() { public int compare(Cell a, Cell b) { return comparator.compare(a.value, b.value); } }); } public TreeSet() { this(new Comparator() { public int compare(T a, T b) { return ((Comparable) a).compareTo(b); } }); } public TreeSet(Collection collection) { this(); for (T item: collection) { add(item); } } public T first() { if (isEmpty()) throw new NoSuchElementException(); return set.first().value().value; } public T last() { if (isEmpty()) throw new NoSuchElementException(); return set.last().value().value; } public Iterator iterator() { return new MyIterator(set.first()); } public Iterator descendingIterator() { return new MyIterator(set.last(), true); } public String toString() { return avian.Data.toString(this); } public boolean add(T value) { PersistentSet.Path> p = set.find(new Cell(value, null)); if (p.fresh()) { set = p.add(); return true; } return false; } T addAndReplace(T value) { PersistentSet.Path> p = set.find(new Cell(value, null)); if (p.fresh()) { set = p.add(); return null; } else { T old = p.value().value; set = p.replaceWith(new Cell(value, null)); return old; } } T find(T value) { PersistentSet.Path> p = set.find(new Cell(value, null)); return p.fresh() ? null : p.value().value; } T removeAndReturn(T value) { Cell cell = removeCell(value); return cell == null ? null : cell.value; } private Cell removeCell(Object value) { PersistentSet.Path> p = set.find(new Cell(value, null)); if (p.fresh()) { return null; } else { Cell old = p.value(); if (p.value().next != null) { set = p.replaceWith(p.value().next); } else { set = p.remove(); } return old; } } public boolean remove(Object value) { return removeCell(value) != null; } public int size() { return set.size(); } public boolean isEmpty() { return set.size() == 0; } public boolean contains(Object value) { return !set.find(new Cell(value, null)).fresh(); } public void clear() { set = new PersistentSet(set.comparator()); } private class MyIterator implements java.util.Iterator { private PersistentSet.Path> path; private PersistentSet.Path> nextPath; private Cell cell; private Cell prevCell; private Cell prevPrevCell; private boolean canRemove = false; private final boolean reversed; private MyIterator(PersistentSet.Path> path) { this(path, false); } private MyIterator(PersistentSet.Path> path, boolean reversed) { this.path = path; this.reversed = reversed; if (path != null) { cell = path.value(); nextPath = nextPath(); } } private MyIterator(MyIterator start) { path = start.path; nextPath = start.nextPath; cell = start.cell; prevCell = start.prevCell; prevPrevCell = start.prevPrevCell; canRemove = start.canRemove; reversed = start.reversed; } public boolean hasNext() { return cell != null || nextPath != null; } public T next() { if (cell == null) { path = nextPath; nextPath = nextPath(); cell = path.value(); } prevPrevCell = prevCell; prevCell = cell; cell = cell.next; canRemove = true; return prevCell.value; } private PersistentSet.Path nextPath() { return reversed ? path.predecessor() : path.successor(); } public void remove() { if (! canRemove) throw new IllegalStateException(); if (prevPrevCell != null && prevPrevCell.next == prevCell) { // cell to remove is not the first in the list. prevPrevCell.next = prevCell.next; prevCell = prevPrevCell; } else if (prevCell.next == cell && cell != null) { // cell to remove is the first in the list, but not the last. set = (PersistentSet) path.replaceWith(cell); prevCell = null; } else { // cell is alone in the list. set = (PersistentSet) path.remove(); path = nextPath; if (path != null) { prevCell = null; cell = path.value(); path = (PersistentSet.Path) set.find((Cell) cell); nextPath = nextPath(); } } canRemove = false; } } } ReadyTalk-avian-1e1fff5/classpath/java/util/UUID.java000066400000000000000000000020071231440243200224500ustar00rootroot00000000000000package java.util; public class UUID { private final byte[] data; private UUID(byte[] data) { this.data = data; } public static UUID randomUUID() { byte[] array = new byte[16]; new Random().nextBytes(array); array[6] &= 0x0f; array[6] |= 0x40; array[8] &= 0x3f; array[8] |= 0x80; return new UUID(array); } public String toString() { StringBuilder sb = new StringBuilder(); toHex(sb, data, 0, 4); sb.append('-'); toHex(sb, data, 4, 2); sb.append('-'); toHex(sb, data, 6, 2); sb.append('-'); toHex(sb, data, 8, 2); sb.append('-'); toHex(sb, data, 10, 6); return sb.toString(); } private static char toHex(int i) { return (char) (i < 10 ? i + '0' : (i - 10) + 'A'); } private static void toHex(StringBuilder sb, byte[] array, int offset, int length) { for (int i = offset; i < offset + length; ++i) { sb.append(toHex((array[i] >> 4) & 0xf)); sb.append(toHex((array[i] ) & 0xf)); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/Vector.java000066400000000000000000000056071231440243200231550ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class Vector extends AbstractList implements java.io.Serializable, Cloneable { private final ArrayList list; public Vector(int capacity) { list = new ArrayList(capacity); } public Vector() { this(0); } public Vector(Collection source) { list = new ArrayList(source); } public synchronized int size() { return list.size(); } public synchronized boolean contains(Object element) { return list.contains(element); } public synchronized void add(int index, T element) { list.add(index, element); } public void insertElementAt(T element, int index) { add(index, element); } public synchronized boolean add(T element) { return list.add(element); } public synchronized boolean addAll(Collection collection) { return list.addAll(collection); } public void addElement(T element) { add(element); } public synchronized T get(int index) { return list.get(index); } public synchronized T set(int index, T value) { return list.set(index, value); } public void setElementAt(T value, int index) { set(index, value); } public T elementAt(int index) { return get(index); } public synchronized T remove(int index) { return list.remove(index); } public synchronized boolean isEmpty() { return list.isEmpty(); } public void removeElementAt(int index) { remove(index); } public synchronized void removeAllElements() { list.clear(); } public synchronized boolean remove(Object element) { return list.remove(element); } public boolean removeElement(T element) { return remove(element); } public synchronized void clear() { list.clear(); } public synchronized int indexOf(Object element) { return list.indexOf(element); } public synchronized int lastIndexOf(Object element) { return list.lastIndexOf(element); } public synchronized void copyInto(Object[] array) { for (int i = 0; i < size(); ++i) { array[i] = list.get(i); } } public Iterator iterator() { return listIterator(); } public ListIterator listIterator(int index) { return new Collections.ArrayListIterator(this, index); } public ListIterator listIterator() { return listIterator(0); } public Enumeration elements() { return new Collections.IteratorEnumeration(iterator()); } public synchronized Object clone() { Vector copy = new Vector(size()); for (T t : this) { copy.add(t); } return copy; } } ReadyTalk-avian-1e1fff5/classpath/java/util/WeakHashMap.java000066400000000000000000000054701231440243200240420ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; import java.lang.ref.ReferenceQueue; import java.lang.ref.Reference; import java.lang.ref.WeakReference; public class WeakHashMap implements Map { private final HashMap map; private final ReferenceQueue queue; public WeakHashMap(int capacity) { map = new HashMap(capacity, new MyHelper()); queue = new ReferenceQueue(); } public WeakHashMap() { this(0); } private void poll() { for (MyCell c = (MyCell) queue.poll(); c != null; c = (MyCell) queue.poll()) { map.remove(c); } } public boolean isEmpty() { return map.isEmpty(); } public int size() { return map.size(); } public boolean containsKey(Object key) { poll(); return map.containsKey(key); } public boolean containsValue(Object value) { poll(); return map.containsValue(value); } public V get(Object key) { poll(); return map.get(key); } public V put(K key, V value) { poll(); return map.put(key, value); } public void putAll(Map elts) { map.putAll(elts); } public V remove(Object key) { poll(); return map.remove(key); } public void clear() { map.clear(); } public Set> entrySet() { return map.entrySet(); } public Set keySet() { return map.keySet(); } public Collection values() { return map.values(); } private static class MyCell extends WeakReference implements HashMap.Cell { public V value; public HashMap.Cell next; public int hashCode; public MyCell(K key, ReferenceQueue queue, V value, HashMap.Cell next, int hashCode) { super(key, queue); this.value = value; this.next = next; this.hashCode = hashCode; } public K getKey() { return get(); } public V getValue() { return value; } public V setValue(V value) { V old = this.value; this.value = value; return old; } public HashMap.Cell next() { return next; } public void setNext(HashMap.Cell next) { this.next = next; } public int hashCode() { return hashCode; } } private class MyHelper extends HashMap.MyHelper { public HashMap.Cell make(K key, V value, HashMap.Cell next) { return new MyCell(key, queue, value, next, hash(key)); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/000077500000000000000000000000001231440243200232225ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/BlockingDeque.java000066400000000000000000000006161231440243200266040ustar00rootroot00000000000000package java.util.concurrent; import java.util.Deque; public interface BlockingDeque extends Deque, BlockingQueue { public T takeFirst() throws InterruptedException; public T takeLast() throws InterruptedException; public T pollFirst(long timeout, TimeUnit unit) throws InterruptedException; public T pollLast(long timeout, TimeUnit unit) throws InterruptedException; } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/BlockingQueue.java000066400000000000000000000010621231440243200266210ustar00rootroot00000000000000package java.util.concurrent; import java.util.Collection; import java.util.Queue; public interface BlockingQueue extends Queue { public void put(T e) throws InterruptedException; public boolean offer(T e, long timeout, TimeUnit unit) throws InterruptedException; public T take() throws InterruptedException; public T poll(long timeout, TimeUnit unit) throws InterruptedException; public int remainingCapacity(); public int drainTo(Collection c); public int drainTo(Collection c, int maxElements); } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/Callable.java000066400000000000000000000007031231440243200255640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; public interface Callable { public T call() throws Exception; } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/CancellationException.java000066400000000000000000000012141231440243200303360ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; public class CancellationException extends IllegalStateException { private static final long serialVersionUID = -9202173006928992231L; public CancellationException() { super(); } public CancellationException(String message) { super(message); } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/CompletionService.java000066400000000000000000000005321231440243200275170ustar00rootroot00000000000000package java.util.concurrent; public interface CompletionService { public Future submit(Callable task); public Future submit(Runnable task, T result); public Future take() throws InterruptedException; public Future poll(); public Future poll(long timeout, TimeUnit unit) throws InterruptedException; } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/ConcurrentHashMap.java000066400000000000000000000250331231440243200274540ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; import avian.Data; import avian.PersistentSet; import avian.PersistentSet.Path; import sun.misc.Unsafe; import java.util.AbstractMap; import java.util.Map; import java.util.Set; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; public class ConcurrentHashMap extends AbstractMap implements ConcurrentMap { private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long Content; private static final Content Empty = new Content(new PersistentSet(), 0); static { try { Content = unsafe.objectFieldOffset (ConcurrentHashMap.class.getDeclaredField("content")); } catch (NoSuchFieldException e) { throw new Error(e); } } private volatile Content content; public ConcurrentHashMap() { content = Empty; } public ConcurrentHashMap(int initialCapacity) { this(); } public boolean isEmpty() { return content.size == 0; } public int size() { return content.size; } public boolean containsKey(Object key) { return find(key) != null; } public boolean containsValue(Object value) { for (V v: values()) { if (value.equals(v)) { return true; } } return false; } public V get(Object key) { Cell cell = find(key); return cell == null ? null : cell.value; } private Cell find(Object key) { Content c = content; Path>> path = c.set.find(new Node(key.hashCode())); for (Cell cell = path.value().value; cell != null; cell = cell.next) { if (key.equals(cell.key)) { return cell; } } return null; } public V putIfAbsent(K key, V value) { Cell cell = put(key, value, PutCondition.IfAbsent, null); return cell == null ? null : cell.value; } public boolean remove(K key, V value) { Cell cell = remove(key, RemoveCondition.IfEqual, value); return cell != null && cell.value.equals(value); } public V replace(K key, V value) { Cell cell = put(key, value, PutCondition.IfPresent, null); return cell == null ? null : cell.value; } public boolean replace(K key, V oldValue, V newValue) { Cell cell = put(key, newValue, PutCondition.IfEqual, oldValue); return cell != null && cell.value.equals(oldValue); } public V put(K key, V value) { Cell cell = put(key, value, PutCondition.Always, null); return cell == null ? null : cell.value; } public V remove(Object key) { Cell cell = remove(key, RemoveCondition.Always, null); return cell == null ? null : cell.value; } private enum PutCondition { Always() { public boolean addIfAbsent() { return true; } public boolean addIfPresent(V a, V b) { return true; } }, IfAbsent() { public boolean addIfAbsent() { return true; } public boolean addIfPresent(V a, V b) { return false; } }, IfPresent() { public boolean addIfAbsent() { return false; } public boolean addIfPresent(V a, V b) { return true; } }, IfEqual() { public boolean addIfAbsent() { return false; } public boolean addIfPresent(V a, V b) { return a.equals(b); } }; public boolean addIfAbsent() { throw new AssertionError(); } public boolean addIfPresent(V a, V b) { throw new AssertionError(); } } private enum RemoveCondition { Always() { public boolean remove(V a, V b) { return true; } }, IfEqual() { public boolean remove(V a, V b) { return a.equals(b); } }; public boolean remove(V a, V b) { throw new AssertionError(); } } private Cell put(K key, V value, PutCondition condition, V oldValue) { Node> node = new Node(key.hashCode()); loop: while (true) { node.value = null; Content content = this.content; Path>> path = content.set.find(node); for (Cell cell = path.value().value; cell != null; cell = cell.next) { if (key.equals(cell.key)) { if (! condition.addIfPresent(cell.value, oldValue)) { return cell; } Cell start = null; Cell last = null; for (Cell cell2 = path.value().value; true; cell2 = cell2.next) { Cell c; c = cell2.clone(); if (last == null) { last = start = c; } else { last.next = c; last = c; } if (cell2 == cell) { c.value = value; break; } } node.value = start; if (unsafe.compareAndSwapObject (this, Content, content, new Content (path.replaceWith(node), content.size))) { return cell; } else { continue loop; } } } // no mapping found -- add a new one if appropriate if (! condition.addIfAbsent()) { return null; } node.value = new Cell(key, value, null); if (unsafe.compareAndSwapObject (this, Content, content, new Content (path.fresh() ? path.add() : path.replaceWith(node), content.size + 1))) { return null; } } } public void putAll(Map map) { for (Map.Entry e: map.entrySet()) { put(e.getKey(), e.getValue()); } } private Cell remove(Object key, RemoveCondition condition, V oldValue) { Node> node = new Node(key.hashCode()); loop: while (true) { node.value = null; Content content = this.content; Path>> path = content.set.find(node); for (Cell cell = path.value().value; cell != null; cell = cell.next) { if (key.equals(cell.key)) { if (! condition.remove(cell.value, oldValue)) { return cell; } Cell start = null; Cell last = null; for (Cell cell2 = path.value().value; cell2 != cell; cell2 = cell2.next) { Cell c = cell2.clone(); if (last == null) { last = start = c; } else { last.next = c; last = c; } } if (last == null) { start = last = cell.next; } else { last.next = cell.next; } node.value = start; if (unsafe.compareAndSwapObject (this, Content, content, new Content (start == null ? path.remove() : path.replaceWith(node), content.size - 1))) { return cell; } else { continue loop; } } } return null; } } public void clear() { content = Empty; } public Set> entrySet() { return new Data.EntrySet(new MyEntryMap()); } public Set keySet() { return new Data.KeySet(new MyEntryMap()); } public Collection values() { return new Data.Values(new MyEntryMap()); } private class MyEntryMap implements Data.EntryMap { public int size() { return ConcurrentHashMap.this.size(); } public Map.Entry find(Object key) { return new MyEntry(ConcurrentHashMap.this.find(key)); } public Map.Entry remove(Object key) { return new MyEntry (ConcurrentHashMap.this.remove(key, RemoveCondition.Always, null)); } public void clear() { ConcurrentHashMap.this.clear(); } public Iterator> iterator() { return new MyIterator(content); } } private static class Content { private final PersistentSet>> set; private final int size; public Content(PersistentSet>> set, int size) { this.set = set; this.size = size; } } private static class Cell implements Cloneable { public final K key; public V value; public Cell next; public Cell(K key, V value, Cell next) { this.key = key; this.value = value; this.next = next; } public Cell clone() { try { return (Cell) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(); } } } private static class Node implements Comparable> { public final int key; public T value; public Node(int key) { this.key = key; } public int compareTo(Node n) { return key - n.key; } } private class MyEntry implements Map.Entry { private final K key; private V value; public MyEntry(Cell cell) { key = cell.key; value = cell.value; } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { V v = value; this.value = value; put(key, value); return v; } } private class MyIterator implements Iterator> { private final Content content; private final Iterator>> iterator; private Cell currentCell; private Cell nextCell; public MyIterator(Content content) { this.content = content; this.iterator = content.set.iterator(); hasNext(); } public Map.Entry next() { if (hasNext()) { currentCell = nextCell; nextCell = nextCell.next; return new MyEntry(currentCell); } else { throw new NoSuchElementException(); } } public boolean hasNext() { if (nextCell == null && iterator.hasNext()) { nextCell = iterator.next().value; } return nextCell != null; } public void remove() { if (currentCell != null) { ConcurrentHashMap.this.remove (currentCell.key, RemoveCondition.Always, null); currentCell = null; } else { throw new IllegalStateException(); } } } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/ConcurrentLinkedQueue.java000066400000000000000000000065511231440243200303520ustar00rootroot00000000000000package java.util.concurrent; import java.util.AbstractQueue; import java.util.Collection; import java.util.Iterator; import avian.Atomic; public class ConcurrentLinkedQueue extends AbstractQueue { private static final long QueueHead; private static final long QueueTail; private static final long NodeNext; static { try { QueueHead = Atomic.getOffset (ConcurrentLinkedQueue.class.getField("head")); QueueTail = Atomic.getOffset (ConcurrentLinkedQueue.class.getField("tail")); NodeNext = Atomic.getOffset (Node.class.getField("next")); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } } private volatile Node head = new Node(null, null); private volatile Node tail = head; @Override public void clear() { // TODO - can we safely make this O(1)? while (poll() != null) { } } @Override public boolean offer(T element) { add(element); return true; } @Override public boolean add(T value) { Node n = new Node(value, null); while (true) { Node t = tail; Node next = tail.next; if (t == tail) { if (next != null) { Atomic.compareAndSwapObject(this, QueueTail, t, next); } else if (Atomic.compareAndSwapObject(tail, NodeNext, null, n)) { Atomic.compareAndSwapObject(this, QueueTail, t, n); break; } } } return true; } @Override public T peek() { return poll(false); } @Override public T poll() { return poll(true); } private T poll(boolean remove) { while (true) { Node h = head; Node t = tail; Node next = head.next; if (h == head) { if (h == t) { if (next != null) { Atomic.compareAndSwapObject(this, QueueTail, t, next); } else { return null; } } else { T value = next.value; if ((! remove) || Atomic.compareAndSwapObject(this, QueueHead, h, next)) { return value; } } } } } private static class Node { public volatile T value; public volatile Node next; public Node(T value, Node next) { this.value = value; this.next = next; } } @Override public int size() { // TODO - implement throw new UnsupportedOperationException(); } @Override public boolean isEmpty() { return size() == 0; } @Override public boolean contains(Object element) { // TODO - implement throw new UnsupportedOperationException(); } @Override public boolean containsAll(Collection c) { // TODO - implement throw new UnsupportedOperationException(); } @Override public boolean remove(Object element) { // TODO - implement throw new UnsupportedOperationException(); } @Override public boolean removeAll(Collection c) { // TODO - implement throw new UnsupportedOperationException(); } @Override public Object[] toArray() { // TODO - implement throw new UnsupportedOperationException(); } @Override public S[] toArray(S[] array) { // TODO - implement throw new UnsupportedOperationException(); } @Override public Iterator iterator() { // TODO - implement throw new UnsupportedOperationException(); } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/ConcurrentMap.java000066400000000000000000000011771231440243200266530ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; import java.util.Map; public interface ConcurrentMap extends Map { public V putIfAbsent(K key, V value); public boolean remove(K key, V value); public V replace(K key, V value); public boolean replace(K key, V oldValue, V newValue); } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/Delayed.java000066400000000000000000000007021231440243200254330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; public interface Delayed { public long getDelay(TimeUnit unit); } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/ExecutionException.java000066400000000000000000000014451231440243200277130ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; public class ExecutionException extends Exception { private static final long serialVersionUID = 7830266012832686185L; protected ExecutionException() { super(); } protected ExecutionException(String message) { super(message); } public ExecutionException(String message, Throwable cause) { super(message, cause); } public ExecutionException(Throwable cause) { super(cause); } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/Executor.java000066400000000000000000000007021231440243200256620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; public interface Executor { public void execute(Runnable task); } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/ExecutorCompletionService.java000066400000000000000000000027051231440243200312420ustar00rootroot00000000000000package java.util.concurrent; public class ExecutorCompletionService implements CompletionService { private final Executor executor; private final BlockingQueue> completionQueue; public ExecutorCompletionService(Executor executor) { this(executor, new LinkedBlockingQueue>()); } public ExecutorCompletionService(Executor executor, BlockingQueue> completionQueue) { this.executor = executor; this.completionQueue = completionQueue; } @Override public Future submit(Callable task) { ECSFuture f = new ECSFuture(task); executor.execute(f); return f; } @Override public Future submit(Runnable task, T result) { ECSFuture f = new ECSFuture(task, result); executor.execute(f); return f; } @Override public Future take() throws InterruptedException { return completionQueue.take(); } @Override public Future poll() { return completionQueue.poll(); } @Override public Future poll(long timeout, TimeUnit unit) throws InterruptedException { return completionQueue.poll(timeout, unit); } private class ECSFuture extends FutureTask implements Future { private ECSFuture(Runnable r, T result) { super(r, result); } private ECSFuture(Callable callable) { super(callable); } @Override protected void done() { completionQueue.add(this); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/ExecutorService.java000066400000000000000000000026411231440243200272070ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; import java.util.List; import java.util.Collection; public interface ExecutorService extends Executor { public void shutdown(); public boolean isShutdown(); public boolean isTerminated(); public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; public Future submit(Callable task); public Future submit(Runnable task, T result); public Future submit(Runnable task); public List> invokeAll(Collection> tasks) throws InterruptedException; public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException; public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException; public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/Future.java000066400000000000000000000014651231440243200253450ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; public interface Future { public boolean cancel(boolean mayInterruptIfRunning); public boolean isCancelled(); public boolean isDone(); public V get() throws InterruptedException, ExecutionException; public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/FutureTask.java000066400000000000000000000107671231440243200261750ustar00rootroot00000000000000package java.util.concurrent; import java.util.concurrent.atomic.AtomicReference; public class FutureTask implements RunnableFuture { private enum State { New, Canceling, Canceled, Running, Done }; private final AtomicReference currentState; private final Callable callable; private final Object notifyLock; private volatile Thread runningThread; private volatile T result; private volatile Throwable failure; public FutureTask(final Runnable r, final T result) { this(new Callable() { @Override public T call() { r.run(); return result; } }); } public FutureTask(Callable callable) { currentState = new AtomicReference(State.New); this.callable = callable; notifyLock = new Object(); runningThread = null; result = null; failure = null; } @Override public void run() { if (currentState.compareAndSet(State.New, State.Running)) { runningThread = Thread.currentThread(); try { result = callable.call(); } catch (Throwable t) { failure = t; } finally { if (currentState.compareAndSet(State.Running, State.Done) || currentState.get() == State.Canceled) { /* in either of these conditions we either were not canceled * or we already were interrupted. The thread may or MAY NOT * be in an interrupted status depending on when it was * interrupted and what the callable did with the state. */ } else { /* Should be in canceling state, so block forever till we are * interrupted. If state already transitioned into canceled * and thus thread is in interrupted status, the exception should * throw immediately on the sleep call. */ try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException e) { // expected } } Thread.interrupted(); // reset interrupted status if set handleDone(); runningThread = null; // must be last operation } } } private void handleDone() { done(); synchronized (notifyLock) { notifyLock.notifyAll(); } } protected void done() { // default implementation does nothing, designed to be overridden } @Override public boolean cancel(boolean mayInterruptIfRunning) { if (currentState.compareAndSet(State.New, State.Canceled)) { handleDone(); return true; } else if (mayInterruptIfRunning && currentState.compareAndSet(State.Running, State.Canceling)) { // handleDone will be called from running thread try { Thread runningThread = this.runningThread; if (runningThread != null) { runningThread.interrupt(); return true; } } finally { // we can not set to canceled until interrupt status has been set currentState.set(State.Canceled); } } return false; } @Override public boolean isCancelled() { return currentState.get() == State.Canceled; } @Override public boolean isDone() { return currentState.get() == State.Done || isCancelled(); } @Override public T get() throws InterruptedException, ExecutionException { try { return get(Long.MAX_VALUE, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { // not possible throw new RuntimeException(e); } } @Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { long timeoutInMillis = unit.toMillis(timeout); long startTime = 0; if (timeoutInMillis < Long.MAX_VALUE) { startTime = System.currentTimeMillis(); } long remainingTime; synchronized (notifyLock) { remainingTime = timeoutInMillis; while (! isDone() && remainingTime > 0) { notifyLock.wait(remainingTime); if (timeoutInMillis < Long.MAX_VALUE) { remainingTime = timeoutInMillis - (System.currentTimeMillis() - startTime); } } } if (remainingTime <= 0) { throw new TimeoutException(); } else if (currentState.get() == State.Canceled) { throw new CancellationException(); } else if (failure != null) { throw new ExecutionException(failure); } else { return result; } } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/LinkedBlockingQueue.java000066400000000000000000000157161231440243200277630ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; import java.util.AbstractQueue; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; public class LinkedBlockingQueue extends AbstractQueue implements BlockingQueue { private final Object collectionLock; private final LinkedList storage; private final int capacity; public LinkedBlockingQueue() { this(Integer.MAX_VALUE); } public LinkedBlockingQueue(int capacity) { collectionLock = new Object(); this.capacity = capacity; storage = new LinkedList(); } // should be synchronized on collectionLock before calling private void handleRemove() { collectionLock.notifyAll(); } // should be synchronized on collectionLock before calling private void handleAdd() { collectionLock.notifyAll(); } // should be synchronized on collectionLock before calling private void blockTillNotFull() throws InterruptedException { blockTillNotFull(Long.MAX_VALUE); } // should be synchronized on collectionLock before calling private void blockTillNotFull(long maxWaitInMillis) throws InterruptedException { if (capacity > storage.size()) { return; } long startTime = 0; if (maxWaitInMillis != Long.MAX_VALUE) { startTime = System.currentTimeMillis(); } long remainingWait = maxWaitInMillis; while (remainingWait > 0) { collectionLock.wait(remainingWait); if (capacity > storage.size()) { return; } else if (maxWaitInMillis != Long.MAX_VALUE) { remainingWait = maxWaitInMillis - (System.currentTimeMillis() - startTime); } } } // should be synchronized on collectionLock before calling private void blockTillNotEmpty() throws InterruptedException { blockTillNotEmpty(Long.MAX_VALUE); } // should be synchronized on collectionLock before calling private void blockTillNotEmpty(long maxWaitInMillis) throws InterruptedException { if (! storage.isEmpty()) { return; } long startTime = 0; if (maxWaitInMillis != Long.MAX_VALUE) { startTime = System.currentTimeMillis(); } long remainingWait = maxWaitInMillis; while (remainingWait > 0) { collectionLock.wait(remainingWait); if (! storage.isEmpty()) { return; } else if (maxWaitInMillis != Long.MAX_VALUE) { remainingWait = maxWaitInMillis - (System.currentTimeMillis() - startTime); } } } @Override public boolean offer(T element) { synchronized (collectionLock) { if (capacity > storage.size()) { storage.addLast(element); handleAdd(); return true; } else { return false; } } } @Override public boolean offer(T e, long timeout, TimeUnit unit) throws InterruptedException { long timeoutInMillis = unit.toMillis(timeout); synchronized (collectionLock) { // block till we can add or have reached timeout blockTillNotFull(timeoutInMillis); return offer(e); } } @Override public void put(T e) throws InterruptedException { synchronized (collectionLock) { // block till we have space blockTillNotFull(); storage.add(e); handleAdd(); } } @Override public boolean addAll(Collection c) { synchronized (collectionLock) { if (storage.size() + c.size() > capacity) { throw new IllegalStateException("Not enough space"); } if (c.isEmpty()) { return false; } else { storage.addAll(c); return true; } } } @Override public T peek() { synchronized (collectionLock) { if (storage.isEmpty()) { return null; } else { return storage.getFirst(); } } } // should be synchronized on collectionLock before calling private T removeFirst() { T result = storage.removeFirst(); handleRemove(); return result; } @Override public T poll() { synchronized (collectionLock) { if (storage.isEmpty()) { return null; } else { return removeFirst(); } } } @Override public T poll(long timeout, TimeUnit unit) throws InterruptedException { long timeoutInMillis = unit.toMillis(timeout); synchronized (collectionLock) { // block till we available or timeout blockTillNotEmpty(timeoutInMillis); return poll(); } } @Override public T take() throws InterruptedException { synchronized (collectionLock) { // block till we available blockTillNotEmpty(); return removeFirst(); } } @Override public int drainTo(Collection c) { return drainTo(c, Integer.MAX_VALUE); } @Override public int drainTo(Collection c, int maxElements) { int remainingElements = maxElements; synchronized (collectionLock) { while (remainingElements > 0 && ! storage.isEmpty()) { c.add(storage.removeFirst()); remainingElements--; } if (remainingElements != maxElements) { handleRemove(); } return maxElements - remainingElements; } } @Override public int remainingCapacity() { synchronized (collectionLock) { return capacity - storage.size(); } } @Override public int size() { synchronized (collectionLock) { return storage.size(); } } @Override public boolean contains(Object element) { synchronized (collectionLock) { return storage.contains(element); } } @Override public boolean containsAll(Collection c) { synchronized (collectionLock) { return storage.containsAll(c); } } @Override public boolean remove(Object element) { synchronized (collectionLock) { if (storage.remove(element)) { handleRemove(); return true; } else { return false; } } } @Override public boolean removeAll(Collection c) { synchronized (collectionLock) { if (storage.removeAll(c)) { handleRemove(); return true; } else { return false; } } } @Override public void clear() { synchronized (collectionLock) { storage.clear(); } } @Override public Object[] toArray() { synchronized (collectionLock) { return storage.toArray(); } } @Override public S[] toArray(S[] array) { synchronized (collectionLock) { return storage.toArray(array); } } @Override public Iterator iterator() { throw new UnsupportedOperationException("Not implemented yet"); } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/RejectedExecutionException.java000066400000000000000000000015161231440243200313600ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; public class RejectedExecutionException extends RuntimeException { private static final long serialVersionUID = -375805702767069545L; public RejectedExecutionException() { super(); } public RejectedExecutionException(String message) { super(message); } public RejectedExecutionException(String message, Throwable cause) { super(message, cause); } public RejectedExecutionException(Throwable cause) { super(cause); } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/RunnableFuture.java000066400000000000000000000002021231440243200270200ustar00rootroot00000000000000package java.util.concurrent; public interface RunnableFuture extends Runnable, Future { // nothing added to interface } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/ScheduledExecutorService.java000066400000000000000000000015711231440243200310310ustar00rootroot00000000000000package java.util.concurrent; public interface ScheduledExecutorService extends ExecutorService { public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit); public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit); public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/ScheduledFuture.java000066400000000000000000000007041231440243200271610ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; public interface ScheduledFuture extends Delayed, Future { } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/ThreadFactory.java000066400000000000000000000001511231440243200266210ustar00rootroot00000000000000package java.util.concurrent; public interface ThreadFactory { public Thread newThread(Runnable r); } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/TimeUnit.java000066400000000000000000000232471231440243200256330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; public enum TimeUnit { NANOSECONDS { @Override public long toNanos(long d) { return d; } @Override public long toMicros(long d) { return d / NANOSECONDS_PER_MICROSECOND; } @Override public long toMillis(long d) { return d / NANOSECONDS_PER_MILLISECOND; } @Override public long toSeconds(long d) { return d / NANOSECONDS_PER_SECOND; } @Override public long toMinutes(long d) { return d / NANOSECONDS_PER_MINUTE; } @Override public long toHours(long d) { return d / NANOSECONDS_PER_HOUR; } @Override public long toDays(long d) { return d / NANOSECONDS_PER_DAY; } @Override public long convert(long d, TimeUnit u) { return u.toNanos(d); } @Override int excessNanos(long d, long m) { return (int) (d - (m * NANOSECONDS_PER_MILLISECOND)); } }, MICROSECONDS { @Override public long toNanos(long d) { return scale(d, NANOSECONDS_PER_MICROSECOND); } @Override public long toMicros(long d) { return d; } @Override public long toMillis(long d) { return d / MICROSECONDS_PER_MILLISECOND; } @Override public long toSeconds(long d) { return d / MICROSECONDS_PER_SECOND; } @Override public long toMinutes(long d) { return d / MICROSECONDS_PER_MINUTE; } @Override public long toHours(long d) { return d / MICROSECONDS_PER_HOUR; } @Override public long toDays(long d) { return d / MICROSECONDS_PER_DAY; } @Override public long convert(long d, TimeUnit u) { return u.toMicros(d); } @Override int excessNanos(long d, long m) { return (int) ((d * NANOSECONDS_PER_MICROSECOND) - (m * NANOSECONDS_PER_MILLISECOND)); } }, MILLISECONDS { @Override public long toNanos(long d) { return scale(d, NANOSECONDS_PER_MILLISECOND); } @Override public long toMicros(long d) { return scale(d, MICROSECONDS_PER_MILLISECOND); } @Override public long toMillis(long d) { return d; } @Override public long toSeconds(long d) { return d / MILLISECONDS_PER_SECOND; } @Override public long toMinutes(long d) { return d / MILLISECONDS_PER_MINUTE; } @Override public long toHours(long d) { return d / MILLISECONDS_PER_HOUR; } @Override public long toDays(long d) { return d / MILLISECONDS_PER_DAY; } @Override public long convert(long d, TimeUnit u) { return u.toMillis(d); } @Override int excessNanos(long d, long m) { return 0; } }, SECONDS { @Override public long toNanos(long d) { return scale(d, NANOSECONDS_PER_SECOND); } @Override public long toMicros(long d) { return scale(d, MICROSECONDS_PER_SECOND); } @Override public long toMillis(long d) { return scale(d, MILLISECONDS_PER_SECOND); } @Override public long toSeconds(long d) { return d; } @Override public long toMinutes(long d) { return d / SECONDS_PER_MINUTE; } @Override public long toHours(long d) { return d / SECONDS_PER_HOUR; } @Override public long toDays(long d) { return d / SECONDS_PER_DAY; } @Override public long convert(long d, TimeUnit u) { return u.toSeconds(d); } @Override int excessNanos(long d, long m) { return 0; } }, MINUTES { @Override public long toNanos(long d) { return scale(d, NANOSECONDS_PER_MINUTE); } @Override public long toMicros(long d) { return scale(d, MICROSECONDS_PER_MINUTE); } @Override public long toMillis(long d) { return scale(d, MILLISECONDS_PER_MINUTE); } @Override public long toSeconds(long d) { return scale(d, SECONDS_PER_MINUTE); } @Override public long toMinutes(long d) { return d; } @Override public long toHours(long d) { return d / MINUETS_PER_HOUR; } @Override public long toDays(long d) { return d / MINUETS_PER_DAY; } @Override public long convert(long d, TimeUnit u) { return u.toMinutes(d); } @Override int excessNanos(long d, long m) { return 0; } }, HOURS { @Override public long toNanos(long d) { return scale(d, NANOSECONDS_PER_HOUR); } @Override public long toMicros(long d) { return scale(d, MICROSECONDS_PER_HOUR); } @Override public long toMillis(long d) { return scale(d, MILLISECONDS_PER_HOUR); } @Override public long toSeconds(long d) { return scale(d, SECONDS_PER_HOUR); } @Override public long toMinutes(long d) { return scale(d, MINUETS_PER_HOUR); } @Override public long toHours(long d) { return d; } @Override public long toDays(long d) { return d / HOURS_PER_DAY; } @Override public long convert(long d, TimeUnit u) { return u.toHours(d); } @Override int excessNanos(long d, long m) { return 0; } }, DAYS { @Override public long toNanos(long d) { return scale(d, NANOSECONDS_PER_DAY); } @Override public long toMicros(long d) { return scale(d, MICROSECONDS_PER_DAY); } @Override public long toMillis(long d) { return scale(d, MILLISECONDS_PER_DAY); } @Override public long toSeconds(long d) { return scale(d, SECONDS_PER_DAY); } @Override public long toMinutes(long d) { return scale(d, MINUETS_PER_DAY); } @Override public long toHours(long d) { return scale(d, HOURS_PER_DAY); } @Override public long toDays(long d) { return d; } @Override public long convert(long d, TimeUnit u) { return u.toDays(d); } @Override int excessNanos(long d, long m) { return 0; } }; private static final long NANOSECONDS_PER_MICROSECOND = 1000L; private static final long MICROSECONDS_PER_MILLISECOND = 1000L; private static final long MILLISECONDS_PER_SECOND = 1000L; private static final long SECONDS_PER_MINUTE = 60; private static final long MINUETS_PER_HOUR = 60; private static final long HOURS_PER_DAY = 24; private static final long NANOSECONDS_PER_MILLISECOND = NANOSECONDS_PER_MICROSECOND * MICROSECONDS_PER_MILLISECOND; private static final long NANOSECONDS_PER_SECOND = NANOSECONDS_PER_MILLISECOND * MILLISECONDS_PER_SECOND; private static final long NANOSECONDS_PER_MINUTE = NANOSECONDS_PER_SECOND * SECONDS_PER_MINUTE; private static final long NANOSECONDS_PER_HOUR = NANOSECONDS_PER_MINUTE * MINUETS_PER_HOUR; private static final long NANOSECONDS_PER_DAY = NANOSECONDS_PER_HOUR * HOURS_PER_DAY; private static final long MICROSECONDS_PER_SECOND = MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_SECOND; private static final long MICROSECONDS_PER_MINUTE = MICROSECONDS_PER_SECOND * SECONDS_PER_MINUTE; private static final long MICROSECONDS_PER_HOUR = MICROSECONDS_PER_MINUTE * MINUETS_PER_HOUR; private static final long MICROSECONDS_PER_DAY = MICROSECONDS_PER_HOUR * HOURS_PER_DAY; private static final long MILLISECONDS_PER_MINUTE = MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE; private static final long MILLISECONDS_PER_HOUR = MILLISECONDS_PER_MINUTE * MINUETS_PER_HOUR; private static final long MILLISECONDS_PER_DAY = MILLISECONDS_PER_HOUR * HOURS_PER_DAY; private static final long SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUETS_PER_HOUR; private static final long SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; private static final long MINUETS_PER_DAY = MINUETS_PER_HOUR * HOURS_PER_DAY; private static long scale(long value, long conversion) { long result = value * conversion; if (value > 0 && result < value) { return Long.MAX_VALUE; } else if (value < 0 && result > value) { return Long.MIN_VALUE; } else { return result; } } public abstract long convert(long sourceDuration, TimeUnit sourceUnit); public abstract long toNanos(long duration); public abstract long toMicros(long duration); public abstract long toMillis(long duration); public abstract long toSeconds(long duration); public abstract long toMinutes(long duration); public abstract long toHours(long duration); public abstract long toDays(long duration); abstract int excessNanos(long d, long m); public void timedWait(Object obj, long timeout) throws InterruptedException { if (timeout > 0) { long ms = toMillis(timeout); int ns = excessNanos(timeout, ms); obj.wait(ms, ns); } } public void timedJoin(Thread thread, long timeout) throws InterruptedException { if (timeout > 0) { long ms = toMillis(timeout); int ns = excessNanos(timeout, ms); thread.join(ms, ns); } } public void sleep(long timeout) throws InterruptedException { if (timeout > 0) { long ms = toMillis(timeout); int ns = excessNanos(timeout, ms); Thread.sleep(ms, ns); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/TimeoutException.java000066400000000000000000000011601231440243200273700ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent; public class TimeoutException extends Exception { private static final long serialVersionUID = 1900926677490660714L; public TimeoutException() { super(); } public TimeoutException(String message) { super(message); } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/atomic/000077500000000000000000000000001231440243200244765ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/atomic/AtomicBoolean.java000066400000000000000000000026031231440243200300560ustar00rootroot00000000000000package java.util.concurrent.atomic; public class AtomicBoolean implements java.io.Serializable { private static final long serialVersionUID = 4654671469794556979L; private static final int FALSE_VALUE = 0; private static final int TRUE_VALUE = 1; private final AtomicInteger value; public AtomicBoolean() { this(false); } public AtomicBoolean(boolean initialValue) { value = new AtomicInteger(intValue(initialValue)); } private static int intValue(boolean value) { return value ? TRUE_VALUE : FALSE_VALUE; } private static boolean booleanValue(int value) { return value == TRUE_VALUE; } public boolean get() { return booleanValue(value.get()); } public boolean compareAndSet(boolean expect, boolean update) { return value.compareAndSet(intValue(expect), intValue(update)); } public boolean weakCompareAndSet(boolean expect, boolean update) { return value.weakCompareAndSet(intValue(expect), intValue(update)); } public void set(boolean newValue) { value.set(intValue(newValue)); } public void lazySet(boolean newValue) { value.lazySet(intValue(newValue)); } public boolean getAndSet(boolean newValue) { int intResult = value.getAndSet(intValue(newValue)); return booleanValue(intResult); } @Override public String toString() { return Boolean.toString(get()); } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/atomic/AtomicInteger.java000066400000000000000000000046231231440243200301000ustar00rootroot00000000000000package java.util.concurrent.atomic; import java.lang.reflect.Field; import sun.misc.Unsafe; public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { Field f = AtomicInteger.class.getDeclaredField("value"); valueOffset = unsafe.objectFieldOffset(f); } catch (NoSuchFieldException e) { throw new Error(e); } } private volatile int value; public AtomicInteger() { this(0); } public AtomicInteger(int initialValue) { this.value = initialValue; } public int get() { return value; } public void set(int newValue) { this.value = newValue; } public void lazySet(int newValue) { unsafe.putOrderedInt(this, valueOffset, newValue); } public boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } public boolean weakCompareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } public int getAndSet(int newValue) { while (true) { int current = value; if (compareAndSet(current, newValue)) { return current; } } } public int getAndAdd(int delta) { while (true) { int current = value; int next = current + delta; if (compareAndSet(current, next)) { return current; } } } public int getAndIncrement() { return getAndAdd(1); } public int getAndDecrement() { return getAndAdd(-1); } public int addAndGet(int delta) { while (true) { int current = value; int next = current + delta; if (compareAndSet(current, next)) { return next; } } } public int incrementAndGet() { return addAndGet(1); } public int decrementAndGet() { return addAndGet(-1); } @Override public byte byteValue() { return (byte)value; } @Override public short shortValue() { return (short)value; } @Override public int intValue() { return value; } @Override public long longValue() { return value; } @Override public float floatValue() { return value; } @Override public double doubleValue() { return value; } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/atomic/AtomicLong.java000066400000000000000000000046471231440243200274100ustar00rootroot00000000000000package java.util.concurrent.atomic; import java.lang.reflect.Field; import sun.misc.Unsafe; public class AtomicLong extends Number implements java.io.Serializable { private static final long serialVersionUID = 1927816293512124184L; private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { Field f = AtomicLong.class.getDeclaredField("value"); valueOffset = unsafe.objectFieldOffset(f); } catch (NoSuchFieldException e) { throw new Error(e); } } private volatile long value; public AtomicLong() { this(0); } public AtomicLong(long initialValue) { this.value = initialValue; } public long get() { return value; } public void set(long newValue) { this.value = newValue; } public void lazySet(long newValue) { unsafe.putOrderedLong(this, valueOffset, newValue); } public boolean compareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update); } public boolean weakCompareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update); } public long getAndSet(long newValue) { while (true) { long current = value; if (compareAndSet(current, newValue)) { return current; } } } public long getAndAdd(long delta) { while (true) { long current = value; long next = current + delta; if (compareAndSet(current, next)) { return current; } } } public long getAndIncrement() { return getAndAdd(1); } public long getAndDecrement() { return getAndAdd(-1); } public long addAndGet(long delta) { while (true) { long current = value; long next = current + delta; if (compareAndSet(current, next)) { return next; } } } public long incrementAndGet() { return addAndGet(1); } public long decrementAndGet() { return addAndGet(-1); } @Override public byte byteValue() { return (byte)value; } @Override public short shortValue() { return (short)value; } @Override public int intValue() { return (int)value; } @Override public long longValue() { return value; } @Override public float floatValue() { return value; } @Override public double doubleValue() { return value; } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/atomic/AtomicReference.java000066400000000000000000000026571231440243200304060ustar00rootroot00000000000000package java.util.concurrent.atomic; import java.lang.reflect.Field; import sun.misc.Unsafe; public class AtomicReference implements java.io.Serializable { private static final long serialVersionUID = -1848883965231344442L; private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { Field f = AtomicReference.class.getDeclaredField("value"); valueOffset = unsafe.objectFieldOffset(f); } catch (NoSuchFieldException e) { throw new Error(e); } } private volatile T value; public AtomicReference() { this(null); } public AtomicReference(T initialValue) { this.value = initialValue; } public T get() { return value; } public void set(T newValue) { value = newValue; } public void lazySet(T newValue) { unsafe.putOrderedObject(this, valueOffset, newValue); } public boolean compareAndSet(T expect, T update) { return unsafe.compareAndSwapObject(this, valueOffset, expect, update); } public boolean weakCompareAndSet(T expect, T update) { return unsafe.compareAndSwapObject(this, valueOffset, expect, update); } public final T getAndSet(T newValue) { while (true) { T current = value; if (compareAndSet(current, newValue)) { return current; } } } @Override public String toString() { return String.valueOf(value); } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/atomic/AtomicReferenceArray.java000066400000000000000000000035051231440243200313760ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent.atomic; import java.util.Arrays; import sun.misc.Unsafe; public class AtomicReferenceArray { private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long arrayOffset = unsafe.arrayBaseOffset(Object.class); private static final long arrayScale = unsafe.arrayIndexScale(Object.class); private final Object[] array; public AtomicReferenceArray(int length) { array = new Object[length]; } public T get(int index) { return (T) unsafe.getObjectVolatile (array, arrayOffset + (index * arrayScale)); } public void set(int index, T newValue) { unsafe.putObjectVolatile (array, arrayOffset + (index * arrayScale), newValue); } public void lazySet(int index, T newValue) { unsafe.putOrderedObject (array, arrayOffset + (index * arrayScale), newValue); } public boolean compareAndSet(int index, T expect, T update) { return unsafe.compareAndSwapObject (array, arrayOffset + (index * arrayScale), expect, update); } public boolean weakCompareAndSet(int index, T expect, T update) { return compareAndSet(index, expect, update); } public final T getAndSet(int index, T newValue) { while (true) { T current = get(index); if (compareAndSet(index, current, newValue)) { return current; } } } public int length() { return array.length; } @Override public String toString() { return Arrays.toString(array); } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/locks/000077500000000000000000000000001231440243200243355ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/locks/Condition.java000066400000000000000000000013341231440243200271270ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent.locks; import java.util.Date; import java.util.concurrent.TimeUnit; public interface Condition { public void await(); public boolean await(long time, TimeUnit unit); public long awaitNanos(long nanosTimeout); public void awaitUninterruptibly(); public boolean awaitUntil(Date deadline); public void signal(); public void signalAll(); } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/locks/Lock.java000066400000000000000000000013011231440243200260630ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent.locks; import java.util.concurrent.TimeUnit; public interface Lock { public void lock(); public void lockInterruptibly() throws InterruptedException; public Condition newCondition(); public boolean tryLock(); public boolean tryLock(long time, TimeUnit unit) throws InterruptedException; public void unlock(); } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/locks/LockSupport.java000066400000000000000000000040461231440243200274710ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent.locks; import sun.misc.Unsafe; public class LockSupport { private LockSupport() { // can't construct } private static final Unsafe unsafe; private static final long parkBlockerOffset; static { unsafe = Unsafe.getUnsafe(); try { parkBlockerOffset = unsafe.objectFieldOffset(Thread.class.getDeclaredField("parkBlocker")); } catch (Exception ex) { throw new Error(ex); } } public static void unpark(Thread thread) { if (thread != null) { unsafe.unpark(thread); } } public static void park(Object blocker) { doParkNanos(blocker, 0L); } public static void parkNanos(Object blocker, long nanos) { if (nanos <= 0) { return; } doParkNanos(blocker, nanos); } private static void doParkNanos(Object blocker, long nanos) { Thread t = Thread.currentThread(); unsafe.putObject(t, parkBlockerOffset, blocker); unsafe.park(false, nanos); unsafe.putObject(t, parkBlockerOffset, null); } public static void parkUntil(Object blocker, long deadline) { Thread t = Thread.currentThread(); unsafe.putObject(t, parkBlockerOffset, blocker); unsafe.park(true, deadline); unsafe.putObject(t, parkBlockerOffset, null); } public static Object getBlocker(Thread t) { if (t == null) { throw new NullPointerException(); } return unsafe.getObjectVolatile(t, parkBlockerOffset); } public static void park() { unsafe.park(false, 0L); } public static void parkNanos(long nanos) { if (nanos > 0) { unsafe.park(false, nanos); } } public static void parkUntil(long deadline) { unsafe.park(true, deadline); } } ReadyTalk-avian-1e1fff5/classpath/java/util/concurrent/locks/ReadWriteLock.java000066400000000000000000000007341231440243200277030ustar00rootroot00000000000000/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.concurrent.locks; public interface ReadWriteLock { public Lock readLock(); public Lock writeLock(); } ReadyTalk-avian-1e1fff5/classpath/java/util/jar/000077500000000000000000000000001231440243200216145ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/util/jar/Attributes.java000066400000000000000000000012621231440243200246060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.jar; public class Attributes { public static class Name { private final String name; private static final int MAX_NAME_LENGTH = 70; public Name(String s) { int len = s.length(); if (len == 0 || len > MAX_NAME_LENGTH) throw new IllegalArgumentException(); name = s; } } } ReadyTalk-avian-1e1fff5/classpath/java/util/jar/JarEntry.java000066400000000000000000000007751231440243200242260ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.jar; import java.util.zip.ZipEntry; public abstract class JarEntry extends ZipEntry { public JarEntry(){ super(null); } } ReadyTalk-avian-1e1fff5/classpath/java/util/jar/JarFile.java000066400000000000000000000036741231440243200240050ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.jar; import java.io.File; import java.io.IOException; import java.util.Enumeration; import java.util.zip.ZipFile; import java.util.zip.ZipEntry; public class JarFile extends ZipFile { public JarFile(String name) throws IOException { super(name); } public JarFile(File file) throws IOException { super(file); } public Enumeration entries() { return (Enumeration) makeEnumeration(JarEntryFactory.Instance); } public JarEntry getJarEntry(String name) { return (JarEntry) getEntry(JarEntryFactory.Instance, name); } private static class MyJarEntry extends JarEntry implements MyEntry { public final Window window; public final int pointer; public MyJarEntry(Window window, int pointer) { this.window = window; this.pointer = pointer; } public String getName() { try { return entryName(window, pointer); } catch (IOException e) { return null; } } public long getCompressedSize() { try { return compressedSize(window, pointer); } catch (IOException e) { return 0; } } public long getSize() { try { return uncompressedSize(window, pointer); } catch (IOException e) { return 0; } } public int pointer() { return pointer; } } private static class JarEntryFactory implements EntryFactory { public static final JarEntryFactory Instance = new JarEntryFactory(); public ZipEntry makeEntry(Window window, int pointer) { return new MyJarEntry(window, pointer); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/logging/000077500000000000000000000000001231440243200224665ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/util/logging/Handler.java000066400000000000000000000006751231440243200247160ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.logging; public class Handler { public void publish(LogRecord r) { } } ReadyTalk-avian-1e1fff5/classpath/java/util/logging/Level.java000066400000000000000000000020611231440243200243770ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.logging; public class Level { public static final Level FINEST = new Level("FINEST", 300); public static final Level FINER = new Level("FINER", 400); public static final Level FINE = new Level("FINE", 500); public static final Level INFO = new Level("INFO", 800); public static final Level WARNING = new Level("WARNING", 900); public static final Level SEVERE = new Level("SEVERE", 1000); private final int value; private final String name; private Level(String name, int value) { this.name = name; this.value = value; } public int intValue() { return value; } public String getName() { return name; } public String toString() { return name; } } ReadyTalk-avian-1e1fff5/classpath/java/util/logging/LogRecord.java000066400000000000000000000021471231440243200252150ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.logging; public class LogRecord { private final String loggerName; private final String message; private final Throwable thrown; private final Level level; private final String methodName; LogRecord(String loggerName, String methodName, Level level, String message, Throwable thrown) { this.loggerName = loggerName; this.message = message; this.thrown = thrown; this.level = level; this.methodName = methodName; } public String getLoggerName() { return loggerName; } public String getMessage() { return message; } public Throwable getThrown() { return thrown; } public Level getLevel() { return level; } public String getSourceMethodName() { return methodName; } } ReadyTalk-avian-1e1fff5/classpath/java/util/logging/Logger.java000066400000000000000000000135511231440243200245550ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.logging; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; public class Logger { private final String name; private Level levelValue = null; private static final ArrayList handlers; private static Logger rootLogger; private Logger parent; static { rootLogger = new Logger(""); rootLogger.setLevel(Level.INFO); handlers = new ArrayList(); handlers.add(new DefaultHandler()); } public static Logger getLogger(String name) { if (name.equals("")) return rootLogger; Logger logger = new Logger(name); logger.parent = rootLogger; logger.setLevel(Level.INFO); return logger; } private Logger(String name) { this.name = name; } public Handler[] getHandlers() { return handlers.toArray(new Handler[handlers.size()]); } public void addHandler(Handler handler) { handlers.add(handler); } public void removeHandler(Handler handler) { handlers.remove(handler); } public Logger getParent() { return parent; } public void fine(String message) { log(Level.FINE, Method.getCaller(), message, null); } public void info(String message) { log(Level.INFO, Method.getCaller(), message, null); } public void warning(String message) { log(Level.WARNING, Method.getCaller(), message, null); } public void severe(String message) { log(Level.SEVERE, Method.getCaller(), message, null); } public void log(Level level, String message) { log(level, Method.getCaller(), message, null); } public void log(Level level, String message, Throwable exception) { log(level, Method.getCaller(), message, exception); } public void log(Level level, String message, Object param) { log(level, Method.getCaller(), replaceParameters(message, param), null); } private static String replaceParameters(String message, Object... params) { StringBuilder builder = new StringBuilder(); int offset = 0; for (int i = 0; i < params.length; ++i) { int curly = message.indexOf("{}", offset); if (curly < 0) { break; } if (curly > offset) { builder.append(message, offset, curly); } offset = curly + 2; builder.append(params[i]); } if (message.length() > offset) { builder.append(message, offset, message.length()); } return builder.toString(); } public void logp(Level level, String sourceClass, String sourceMethod, String msg) { if (!isLoggable(level)) { return; } publish(new LogRecord(name, sourceMethod, level, msg, null)); } public void logp(Level level, String sourceClass, String sourceMethod, String msg, Throwable thrown) { if (!isLoggable(level)) { return; } publish(new LogRecord(name, sourceMethod, level, msg, thrown)); } public Level getLevel() { return levelValue; } private Level getEffectiveLevel() { Logger logger = this; while (logger.levelValue == null) { logger = logger.getParent(); } return logger.getLevel(); } private void log(Level level, avian.VMMethod caller, String message, Throwable exception) { if (level.intValue() < getEffectiveLevel().intValue()) { return; } LogRecord r = new LogRecord (name, caller == null ? "" : Method.getName(caller), level, message, exception); publish(r); } private void publish(LogRecord logRecord) { for (Handler h : handlers) { h.publish(logRecord); } } public void setLevel(Level level) { levelValue = level; } public boolean isLoggable(Level level) { return level.intValue() >= levelValue.intValue(); } private static class DefaultHandler extends Handler { private static final int NAME_WIDTH = 14; private static final int METHOD_WIDTH = 15; private static final int LEVEL_WIDTH = 8; private final String newline; public DefaultHandler() { newline = System.getProperty("line.separator"); } public Object clone() { return this; } public void close() { } public void flush() { } private void maybeLogThrown(StringBuilder sb, Throwable t) { if (t != null) { sb.append("\nCaused by: "); sb.append(t.getClass().getName()); sb.append(": "); sb.append(t.getMessage()); sb.append(newline); for (StackTraceElement elt : t.getStackTrace()) { sb.append('\t'); sb.append(elt.getClassName()); sb.append('.'); sb.append(elt.getMethodName()); sb.append("(line"); sb.append(':'); int lineNumber = elt.getLineNumber(); if (lineNumber == -2) { sb.append("unknown"); } else if (lineNumber == -1) { sb.append("native"); } else { sb.append(lineNumber); } sb.append(')'); sb.append(newline); } maybeLogThrown(sb, t.getCause()); } } private void indent(StringBuilder sb, int amount) { do { sb.append(' '); } while (--amount > 0); } public void publish(LogRecord r) { StringBuilder sb = new StringBuilder(); sb.append(r.getLoggerName()); indent(sb, NAME_WIDTH - r.getLoggerName().length()); sb.append(r.getSourceMethodName()); indent(sb, METHOD_WIDTH - r.getSourceMethodName().length()); sb.append(r.getLevel().getName()); indent(sb, LEVEL_WIDTH - r.getLevel().getName().length()); sb.append(r.getMessage()); maybeLogThrown(sb, r.getThrown()); System.out.println(sb.toString()); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/regex/000077500000000000000000000000001231440243200221525ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/util/regex/CharacterMatcher.java000066400000000000000000000215531231440243200262230ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.regex; /** * A class to match classes of characters. *

* This class is intended to be the working horse behind character classes * such as {@code [a-z]}. *

* @author Johannes Schindelin */ class CharacterMatcher { private boolean[] map; private boolean inversePattern; public static CharacterMatcher parse(String description) { return parse(description.toCharArray()); } public static CharacterMatcher parse(char[] description) { Parser parser = new Parser(description); CharacterMatcher result = parser.parseClass(); if (parser.getEndOffset() != description.length) { throw new RuntimeException("Short character class @" + parser.getEndOffset() + ": " + new String(description)); } return result; } public boolean matches(char c) { int index = c; return (map.length > index && map[index]) ^ inversePattern; } public String toString() { StringBuilder builder = new StringBuilder(); builder.append("["); if (inversePattern) { builder.append("^"); } for (int i = 0; i < map.length; ++ i) { if (!map[i]) { continue; } builder.append(i >= ' ' && i <= 0x7f ? "" + (char)i : ("\\x" + Integer.toHexString(i))); int j = i + 1; while (j < map.length && map[j]) { ++ j; } -- j; if (j > i) { if (j > i + 1) { builder.append('-'); } builder.append(j >= ' ' && j <= 0x7f ? "" + (char)j : ("\\x" + Integer.toHexString(j))); i = j; } } builder.append("]"); return builder.toString(); } private static String specialClass(int c) { if ('d' == c) { return "[0-9]"; } if ('D' == c) { return "[^0-9]"; } if ('s' == c) { return "[ \\t\\n\\x0B\\f\\r]"; } if ('S' == c) { return "[^ \\t\\n\\x0B\\f\\r]"; } if ('w' == c) { return "[a-zA-Z_0-9]"; } if ('W' == c) { return "[^a-zA-Z_0-9]"; } return null; } private CharacterMatcher(boolean[] map, boolean inversePattern) { this.map = map; this.inversePattern = inversePattern; } private void setMatch(int c) { ensureCapacity(c + 1); map[c] = true; } private void ensureCapacity(int length) { if (map.length >= length) { return; } int size = map.length; if (size < 32) { size = 32; } while (size < length) { size <<= 1; } map = java.util.Arrays.copyOf(map, size); } private void merge(CharacterMatcher other) { boolean inversePattern = this.inversePattern || other.inversePattern; if ((map.length < other.map.length) ^ inversePattern) { map = java.util.Arrays.copyOf(map, other.map.length); } for (int i = 0; i < map.length; ++ i) { map[i] = (matches((char)i) || other.matches((char)i)) ^ inversePattern; } this.inversePattern = inversePattern; } private void intersect(CharacterMatcher other) { boolean inversePattern = this.inversePattern && other.inversePattern; if ((map.length > other.map.length) ^ inversePattern) { map = java.util.Arrays.copyOf(map, other.map.length); } for (int i = 0; i < map.length; ++ i) { map[i] = (matches((char)i) && other.matches((char)i)) ^ inversePattern; } this.inversePattern = inversePattern; } static class Parser { private final char[] description; private int offset; public Parser(char[] description) { this.description = description; } public int getEndOffset() { return offset; } /** * Parses an escaped character. * * @param start the offset after the backslash * @return the escaped character, or -1 if no character was recognized */ public int parseEscapedCharacter(int start) { offset = start; return parseEscapedCharacter(); } private int parseEscapedCharacter() { if (offset == description.length) { throw new IllegalArgumentException("Short escaped character"); } char c = description[offset++]; if (c == '0') { int len = digits(offset, 3, 8); if (len == 3 && description[offset] > '3') { --len; } c = (char)Integer.parseInt(new String(description, offset, len), 8); offset += len; return c; } if (c == 'x' || c == 'u') { int len = digits(offset, 4, 16); c = (char)Integer.parseInt(new String(description, offset, len), 16); offset += len; return c; } switch (c) { case 'a': return 0x0007; case 'e': return 0x001B; case 'f': return 0x000C; case 'n': return 0x000A; case 'r': return 0x000D; case 't': return 0x0009; case '\\': case '.': case '*': case '+': case '?': case '|': case '[': case ']': case '{': case '}': case '(': case ')': case '^': case '$': return c; } return -1; } public int digits(int offset, int maxLength, int base) { for (int i = 0; ; ++i) { if (i == maxLength || offset + i >= description.length) { return i; } int value = description[offset + i] - '0'; if (value < 0) { return i; } if (base > 10 && value >= 10) { value += 10 - (value >= 'a' - '0' ? 'a' - '0' : 'A' - '0'); } if (value >= base) { return i; } } } public CharacterMatcher parseClass(int start) { offset = start; return parseClass(); } public CharacterMatcher parseClass() { if (description[offset] != '[') { if (description[offset] == '\\') { String range = specialClass(description[++ offset]); if (range != null) { ++ offset; return CharacterMatcher.parse(range); } } return null; } CharacterMatcher matcher = new CharacterMatcher(new boolean[0], description[++ offset] == '^'); if (matcher.inversePattern) { ++ offset; } int previous = -1; boolean firstCharacter = true; for (;;) { if (offset >= description.length) { unsupported("short regex"); } char c = description[offset++]; if (c == '-' && !firstCharacter && description[offset] != ']') { if (previous < 0) { unsupported("invalid range"); } int rangeEnd = description[offset]; if ('\\' == rangeEnd) { rangeEnd = parseEscapedCharacter(); if (rangeEnd < 0) { unsupported("invalid range"); } } matcher.ensureCapacity(rangeEnd + 1); for (int j = previous + 1; j <= rangeEnd; j++) { matcher.map[j] = true; } } else if (c == '\\') { int saved = offset; previous = parseEscapedCharacter(); if (previous < 0) { offset = saved - 1; CharacterMatcher clazz = parseClass(); if (clazz == null) { unsupported("escape"); } matcher.merge(clazz); } else { matcher.setMatch(previous); } } else if (c == '[') { Parser parser = new Parser(description); CharacterMatcher other = parser.parseClass(offset - 1); if (other == null) { unsupported("invalid merge"); } matcher.merge(other); offset = parser.getEndOffset(); previous = -1; } else if (c == '&') { if (offset + 2 > description.length || description[offset] != '&' || description[offset + 1] != '[') { unsupported("operation"); } Parser parser = new Parser(description); CharacterMatcher other = parser.parseClass(offset + 1); if (other == null) { unsupported("invalid intersection"); } matcher.intersect(other); offset = parser.getEndOffset(); previous = -1; } else if (c == ']') { break; } else { previous = c; matcher.setMatch(previous); } firstCharacter = false; } return matcher; } private void unsupported(String msg) throws UnsupportedOperationException { throw new UnsupportedOperationException("Unsupported " + msg + " @" + offset + ": " + new String(description, 0, description.length)); } } } ReadyTalk-avian-1e1fff5/classpath/java/util/regex/Compiler.java000066400000000000000000000354121231440243200245740ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.regex; import java.util.ArrayList; import java.util.Stack; /** * Compiles regular expressions into {@link PikeVM}s. * * @author Johannes Schindelin */ class Compiler implements PikeVMOpcodes { private final static CharacterMatcher regularCharacter = CharacterMatcher.parse("[^\\\\.*+?|\\[\\]{}()^$]"); private static class Output { private int[] program; private int offset; private int groupCount = -1; private int findPreambleSize; private ArrayList classes; private ArrayList lookarounds; public Output(Expression expr) { // try-run to determine the code size expr.writeCode(this); program = new int[offset]; offset = 0; groupCount = -1; classes = new ArrayList(); lookarounds = new ArrayList(); // write it out! expr.writeCode(this); } public void add(int opcode) { if (program != null) { program[offset] = opcode; } offset++; } public int markJump() { return offset++; } public void setJump(int mark) { if (program != null) { program[mark] = offset; } } public void markFindPreambleEnd() { findPreambleSize = offset; } public PikeVM toVM() { CharacterMatcher[] classes = new CharacterMatcher[this.classes.size()]; this.classes.toArray(classes); PikeVM[] lookarounds = new PikeVM[this.lookarounds.size()]; this.lookarounds.toArray(lookarounds); return new PikeVM(program, findPreambleSize, groupCount, classes, lookarounds); } public int addClass(CharacterMatcher characterClass) { if (program == null) { return -1; } int result = classes.size(); classes.add(characterClass); return result; } public int addLookaround(PikeVM lookaround) { if (program == null) { return -1; } int result = lookarounds.size(); lookarounds.add(lookaround); return result; } } private abstract class Expression { protected abstract void writeCode(Output output); } private class CharacterRange extends Expression { private final CharacterMatcher characterClass; public CharacterRange(CharacterMatcher characterClass) { this.characterClass = characterClass; } protected void writeCode(Output output) { output.add(CHARACTER_CLASS); output.add(output.addClass(characterClass)); } public String toString() { return characterClass.toString(); } } private class Repeat extends Expression { private Expression expr; private int minCount, maxCount; private boolean greedy; public Repeat(Expression expr, int minCount, int maxCount, boolean greedy) { if (minCount < 0) { throw new RuntimeException("Unexpected min count: " + minCount); } if (maxCount != -1) { if (maxCount == 0) { throw new RuntimeException("Unexpected max count: " + maxCount); } if (minCount > maxCount) { throw new RuntimeException("Unexpected range: " + minCount + ", " + maxCount); } } this.expr = expr; this.minCount = minCount; this.maxCount = maxCount; this.greedy = greedy; } protected void writeCode(Output output) { int start = output.offset; int splitJmp = greedy ? SPLIT_JMP : SPLIT; int split = greedy ? SPLIT : SPLIT_JMP; for (int i = 1; i < minCount; ++ i) { expr.writeCode(output); } if (maxCount == -1) { if (minCount > 0) { int jump = output.offset; expr.writeCode(output); output.add(splitJmp); output.add(jump); } else { output.add(split); int jump = output.markJump(); expr.writeCode(output); output.add(splitJmp); output.add(start + 2); output.setJump(jump); } } else { if (minCount > 0) { expr.writeCode(output); } if (maxCount > minCount) { int[] jumps = new int[maxCount - minCount]; for (int i = 0; i < jumps.length; ++ i) { output.add(split); jumps[i] = output.markJump(); expr.writeCode(output); } for (int jump : jumps) { output.setJump(jump); } } } } public String toString() { String qualifier = greedy ? "" : "?"; if (minCount == 0 && maxCount < 2) { return expr.toString() + (minCount < 0 ? "*" : "?") + qualifier; } if (minCount == 1 && maxCount < 0) { return expr.toString() + "+" + qualifier; } return expr.toString() + "{" + minCount + "," + (maxCount < 0 ? "" : "" + maxCount) + "}" + qualifier; } } private class Group extends Expression { private final boolean capturing; private ArrayList list = new ArrayList(); private ArrayList alternatives; public Group(boolean capturing, ArrayList initialList) { this.capturing = capturing; if (initialList != null) { list.addAll(initialList); } } public void push(Expression expr) { list.add(expr); } public void push(final int c) { push(new Expression() { public void writeCode(Output output) { output.add(c); } public String toString() { if (c >= 0) { return "" + (char)c; } switch (c) { case DOT: return "."; case WORD_BOUNDARY: return "\\b"; case NON_WORD_BOUNDARY: return "\\B"; case LINE_START: return "^"; case LINE_END: return "$"; default: throw new RuntimeException("Unhandled opcode: " + c); } } }); } public void startAlternative() { if (alternatives == null) { alternatives = new ArrayList(); } alternatives.add(new Group(false, list)); list.clear(); } public Expression pop() { Expression result = list.remove(list.size() - 1); return result; } protected void writeCode(Output output) { int groupIndex = -1; if (capturing) { groupIndex = ++ output.groupCount; output.add(SAVE_OFFSET); output.add(2 * groupIndex); } int[] jumps = null; if (alternatives != null) { jumps = new int[alternatives.size()]; int i = 0; for (Group alternative : alternatives) { output.add(SPLIT); int jump = output.markJump(); alternative.writeCode(output); output.add(JMP); jumps[i++] = output.markJump(); output.setJump(jump); } } for (Expression expr : list) { expr.writeCode(output); } if (jumps != null) { for (int jump : jumps) { output.setJump(jump); } } if (capturing) { output.add(SAVE_OFFSET); output.add(2 * groupIndex + 1); } } public String toString() { StringBuilder builder = new StringBuilder(); if (alternatives != null || list.size() > 1) { builder.append('('); if (!capturing) { builder.append("?:"); } } if (alternatives != null) { for (Group alternative : alternatives) { builder.append(alternative).append('|'); } } for (Expression expr : list) { builder.append(expr); } if (alternatives != null || list.size() > 1) { builder.append(')'); } return builder.toString(); } } private class Lookaround extends Expression { private final Group group = new Group(false, null); private final boolean forward, negative; public Lookaround(boolean forward, boolean negative) { this.forward = forward; this.negative = negative; } @Override protected void writeCode(Output output) { PikeVM vm = new Output(group).toVM(); if (!forward) { vm.reverse(); } output.add(forward ? (negative ? NEGATIVE_LOOKAHEAD : LOOKAHEAD) : (negative ? NEGATIVE_LOOKAHEAD : LOOKBEHIND)); output.add(output.addLookaround(vm)); } public String toString() { String inner = group.toString(); if (inner.startsWith("(?:")) { inner = inner.substring(3); } else { inner += ")"; } return "(?=" + inner; } } private class Group0 extends Expression { private final Group group; public Group0() { group = new Group(true, null); } public void writeCode(Output output) { // find() preamble int start = output.offset; output.add(SPLIT_JMP); output.add(start + 5); output.add(DOTALL); output.add(SPLIT); output.add(start + 2); output.markFindPreambleEnd(); group.writeCode(output); } public String toString() { String inner = group.toString(); return inner.startsWith("(?:") && inner.endsWith(")") ? inner.substring(1, inner.length() - 1) : inner; } } private Group0 root; private Stack groups; public Compiler() { root = new Group0(); groups = new Stack(); groups.add(root.group); } public Pattern compile(String regex) { char[] array = regex.toCharArray(); CharacterMatcher.Parser characterClassParser = new CharacterMatcher.Parser(array); for (int index = 0; index < array.length; ++ index) { char c = array[index]; Group current = groups.peek(); if (regularCharacter.matches(c)) { current.push(c); continue; } switch (c) { case '.': current.push(DOT); continue; case '\\': int unescaped = characterClassParser.parseEscapedCharacter(index + 1); if (unescaped >= 0) { index = characterClassParser.getEndOffset() - 1; current.push((char)unescaped); continue; } CharacterMatcher characterClass = characterClassParser.parseClass(index); if (characterClass != null) { index = characterClassParser.getEndOffset() - 1; current.push(new CharacterRange(characterClass)); continue; } switch (array[index + 1]) { case 'b': index++; current.push(WORD_BOUNDARY); continue; case 'B': index++; current.push(NON_WORD_BOUNDARY); continue; } throw new RuntimeException("Parse error @" + index + ": " + regex); case '?': case '*': case '+': { boolean greedy = true; if (index + 1 < array.length && array[index + 1] == '?') { greedy = false; ++ index; } current.push(new Repeat(current.pop(), c == '+' ? 1 : 0, c == '?' ? 1 : -1, greedy)); continue; } case '{': { ++ index; int length = characterClassParser.digits(index, 8, 10); int min = Integer.parseInt(regex.substring(index, index + length)); int max = min; index += length - 1; c = index + 1 < array.length ? array[index + 1] : 0; if (c == ',') { ++ index; length = characterClassParser.digits(index + 1, 8, 10); max = length == 0 ? -1 : Integer.parseInt(regex.substring(index + 1, index + 1 + length)); index += length; c = index + 1< array.length ? array[index + 1] : 0; } if (c != '}') { throw new RuntimeException("Invalid quantifier @" + index + ": " + regex); } ++ index; boolean greedy = true; if (index + 1 < array.length && array[index + 1] == '?') { ++ index; greedy = false; } current.push(new Repeat(current.pop(), min, max, greedy)); continue; } case '(': { boolean capturing = true; if (index + 1 < array.length && array[index + 1] == '?') { index += 2; if (index >= array.length) { throw new RuntimeException("Short pattern @" + index + ": " + regex); } c = array[index]; boolean lookAhead = true; if (c == '<') { if (++ index >= array.length) { throw new RuntimeException("Short pattern @" + index + ": " + regex); } lookAhead = false; c = array[index]; if (c != '=' && c != '!') { throw new IllegalArgumentException("Named groups not supported @" + index + ": " + regex); } } switch (c) { case ':': capturing = false; break; case '!': case '=': { capturing = false; Lookaround lookaround = new Lookaround(lookAhead, c == '!'); current.push(lookaround); groups.push(lookaround.group); continue; } default: throw new UnsupportedOperationException("Not yet supported: " + regex.substring(index)); } } current.push(groups.push(new Group(capturing, null))); continue; } case ')': if (groups.size() < 2) { throw new RuntimeException("Invalid group close @" + index + ": " + regex); } groups.pop(); continue; case '[': { CharacterMatcher matcher = characterClassParser.parseClass(index); if (matcher == null) { throw new RuntimeException("Invalid range @" + index + ": " + regex); } current.push(new CharacterRange(matcher)); index = characterClassParser.getEndOffset() - 1; continue; } case '|': current.startAlternative(); continue; case '^': current.push(LINE_START); continue; case '$': current.push(LINE_END); continue; default: throw new RuntimeException("Parse error @" + index + ": " + regex); } } if (groups.size() != 1) { throw new IllegalArgumentException("Unclosed groups: (" + (groups.size() - 1) + "): " + regex); } PikeVM vm = new Output(root).toVM(); String plain = vm.isPlainString(); if (plain != null) { return new TrivialPattern(regex, plain, 0); } return new RegexPattern(regex, 0, vm); } } ReadyTalk-avian-1e1fff5/classpath/java/util/regex/Matcher.java000066400000000000000000000046151231440243200244060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.regex; /** * This is a work in progress. * * @author zsombor and others */ public abstract class Matcher { protected CharSequence input; protected int start; protected int end; public Matcher(CharSequence input) { reset(input); } public abstract boolean matches(); public boolean find() { return find(end); } public abstract boolean find(int start); public Matcher reset() { return reset(input); } public Matcher reset(CharSequence input) { this.input = input; start = 0; end = 0; return this; } public String replaceAll(String replacement) { return replace(replacement, Integer.MAX_VALUE); } public String replaceFirst(String replacement) { return replace(replacement, 1); } protected String replace(String replacement, int limit) { reset(); StringBuilder sb = null; int index = 0; int count = 0; while (count < limit && index < input.length()) { if (find(index)) { if (sb == null) { sb = new StringBuilder(); } if (start > index) { sb.append(input.subSequence(index, start)); } sb.append(replacement); index = end; ++ count; } else if (index == 0) { return input.toString(); } else { break; } } if (index < input.length()) { sb.append(input.subSequence(index, input.length())); } return sb.toString(); } public int start() { return start; } public int end() { return end; } public String group() { return input.subSequence(start, end).toString(); } public int start(int group) { if (group == 0) { return start(); } throw new UnsupportedOperationException(); } public int end(int group) { if (group == 0) { return end(); } throw new UnsupportedOperationException(); } public String group(int group) { if (group == 0) { return group(); } throw new UnsupportedOperationException(); } public int groupCount() { return 0; } } ReadyTalk-avian-1e1fff5/classpath/java/util/regex/Pattern.java000066400000000000000000000045351231440243200244410ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.regex; import java.util.ArrayList; import java.util.List; /** * This is a work in progress. * * @author zsombor and others * */ public abstract class Pattern implements PikeVMOpcodes { public static final int UNIX_LINES = 1; public static final int CASE_INSENSITIVE = 2; public static final int COMMENTS = 4; public static final int MULTILINE = 8; public static final int LITERAL = 16; public static final int DOTALL = 32; public static final int UNICODE_CASE = 64; public static final int CANON_EQ = 128; private final int patternFlags; private final String pattern; protected Pattern(String pattern, int flags) { this.pattern = pattern; this.patternFlags = flags; } public static Pattern compile(String regex) { return compile(regex, 0); } public static Pattern compile(String regex, int flags) { if (flags != 0) { throw new UnsupportedOperationException("TODO"); } return new Compiler().compile(regex); } public int flags() { return patternFlags; } public abstract Matcher matcher(CharSequence input); public static boolean matches(String regex, CharSequence input) { return Pattern.compile(regex).matcher(input).matches(); } public String pattern() { return pattern; } public String[] split(CharSequence input) { return split(input, 0); } public String[] split(CharSequence input, int limit) { if (limit <= 0) { limit = Integer.MAX_VALUE; } Matcher matcher = matcher(input); List result = new ArrayList(); int offset = 0; for (;;) { if (result.size() >= limit || !matcher.find()) { break; } result.add(input.subSequence(offset, matcher.start()).toString()); offset = matcher.end(); } if (offset == 0 || offset < input.length()) { result.add(input.subSequence(offset, input.length()).toString()); } return result.toArray(new String[result.size()]); } } ReadyTalk-avian-1e1fff5/classpath/java/util/regex/PikeVM.java000066400000000000000000000502641231440243200241570ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.regex; /** * A minimal implementation of a regular expression engine. * * @author Johannes Schindelin */ class PikeVM implements PikeVMOpcodes { private final int[] program; private final int groupCount; private final int offsetsCount; /* * For find(), we do not want to anchor the match at the start offset. Our * compiler allows this by prefixing the code with an implicit '(?:.*?)'. For * regular matches() calls, we want to skip that code and start at {@code * findPrefixLength} instead. */ private final int findPrefixLength; private final CharacterMatcher[] classes; private final PikeVM[] lookarounds; private final static CharacterMatcher wordCharacter = CharacterMatcher.parse("\\w"); private final static CharacterMatcher lineTerminator = CharacterMatcher.parse("[\n\r\u0085\u2028\u2029]"); private boolean multiLine; public interface Result { void set(int[] start, int[] end); } protected PikeVM(int[] program, int findPrefixLength, int groupCount, CharacterMatcher[] classes, PikeVM[] lookarounds) { this.program = program; this.findPrefixLength = findPrefixLength; this.groupCount = groupCount; offsetsCount = 2 * groupCount + 2; this.classes = classes; this.lookarounds = lookarounds; } /** * The current thread states. *

* The threads are identified by their program counter. The rationale: as all * threads are executed in lock-step, i.e. for the same character in the * string to be matched, it does not make sense for two threads to be at the * same program counter -- they would both do exactly the same for the rest of * the execution. *

*

* For efficiency, the threads are kept in a linked list that actually lives * in an array indexed by the program counter, pointing to the next thread's * program counter, in the order of high to low priority. *

*

* Program counters which have no thread associated thread are marked as -1. * The program counter associated with the least-priority thread (the last one * in the linked list) is marked as -2 to be able to tell it apart from * unscheduled threads. *

*

* We actually never need to have an explicit value for the priority, the * ordering is sufficient: whenever a new thread is to be scheduled and it is * found to be scheduled already, it was already scheduled by a * higher-priority thread. *

*/ private class ThreadQueue { private int head, tail; // next[pc] is 1 + the next thread's pc private int[] next; // offsets[pc][2 * group] is 1 + start offset private int[][] offsets; public ThreadQueue() { head = tail = -1; next = new int[program.length + 1]; offsets = new int[program.length + 1][]; } public ThreadQueue(int startPC) { head = tail = startPC; next = new int[program.length + 1]; offsets = new int[program.length + 1][]; offsets[head] = new int[offsetsCount]; } public int queueOneImmediately(ThreadQueue into) { for (;;) { if (head < 0) { return -1; } boolean wasQueued = queueNext(head, head, into); int pc = head; if (head == tail) { head = tail = -1; } else { head = next[pc] - 1; next[pc] = 0; } offsets[pc] = null; if (wasQueued) { into.tail = pc; return pc; } } } /** * Schedules the instruction at {@code nextPC} to be executed immediately. *

* For non-matching steps (SPLIT, SAVE_STATE, etc) we need to schedule the * corresponding program counter(s) to be handled right after this opcode, * before advancing to the next character. *

*

* To achieve this, we insert the program counter to-be-scheduled in the * linked thread list at the current position, but only if it has not been * scheduled yet: if it has, a higher-priority thread already reached that * state. *

*

* In contrast to {@link #queueNext(int, int, ThreadQueue)}, this method * works on the current step's thread list. *

* * @param currentPC * the current program counter * @param nextPC * the program counter to schedule * @param copyThreadState * whether to spawn off a new thread * @return whether the step was queued (i.e. no thread was queued for the * same {@code nextPC} already) */ public boolean queueImmediately(int currentPC, int nextPC, boolean copyThreadState) { if (isScheduled(nextPC)) { return false; } int[] offsets = this.offsets[currentPC]; if (copyThreadState) { offsets = java.util.Arrays.copyOf(offsets, offsetsCount); } if (currentPC == tail) { tail = nextPC; } else { next[nextPC] = next[currentPC]; } this.offsets[nextPC] = offsets; next[currentPC] = nextPC + 1; return true; } /** * Schedules the instruction at {@code nextPC} to be executed in the next * step. *

* This method advances the current thread to the next program counter, to * be executed after reading the next character. *

* * @param currentPC * the current program counter * @param nextPC * the program counter to schedule * @param next * the thread state of the next step * @return whether the step was queued (i.e. no thread was queued for the * same {@code nextPC} already) */ private boolean queueNext(int currentPC, int nextPC, ThreadQueue next) { if (next.tail < 0) { next.head = nextPC; } else if (next.isScheduled(nextPC)) { return false; } else { next.next[next.tail] = nextPC + 1; } next.offsets[nextPC] = offsets[currentPC]; next.tail = nextPC; return true; } public void saveOffset(int pc, int index, int offset) { offsets[pc][index] = offset + 1; } public void setResult(Result result) { // copy offsets int[] offsets = this.offsets[program.length]; int[] groupStart = new int[groupCount + 1]; int[] groupEnd = new int[groupCount + 1]; for (int j = 0; j <= groupCount; ++j) { groupStart[j] = offsets[2 * j] - 1; groupEnd[j] = offsets[2 * j + 1] - 1; } result.set(groupStart, groupEnd); } private void mustStartMatchAt(int start) { int previous = -1; for (int pc = head; pc >= 0; ) { int nextPC = next[pc] - 1; if (start + 1 == offsets[pc][0]) { previous = pc; } else { next[pc] = 0; offsets[pc] = null; if (pc == tail) { head = tail = -1; } else if (previous < 0) { head = nextPC; } else { next[previous] = 1 + nextPC; } } pc = nextPC; } } private int startOffset(int pc) { return offsets[pc][0] - 1; } public boolean isEmpty() { return head < 0; } public boolean isScheduled(int pc) { return pc == tail || next[pc] > 0; } public int next(int pc) { return pc < 0 ? head : next[pc] - 1; } public void clean() { for (int pc = head; pc >= 0; ) { int nextPC = next[pc] - 1; next[pc] = 0; offsets[pc] = null; pc = nextPC; } head = tail = -1; } } /** * Executes the Pike VM defined by the program. *

* The idea is to execute threads in parallel, at each step executing them * from the highest priority thread to the lowest one. In contrast to most * regular expression engines, the Thompson/Pike one gets away with linear * complexity because the string is matched from left to right, at each step * executing a number of threads bounded by the length of the program: if two * threads would execute at the same instruction pointer of the program, we * need only consider the higher-priority one. *

*

* This implementation is based on the description of Russ Cox. *

* * @param characters * the {@link String} to match * @param start * the start offset where to match * @param length * the end offset * @param anchorStart * whether the match must start at {@code start} * @param anchorEnd * whether the match must start at {@code end} * @param result * the {@link Matcher} to store the groups' offsets in, if successful * @return whether a match was found */ public boolean matches(char[] characters, int start, int end, boolean anchorStart, boolean anchorEnd, Result result) { ThreadQueue current = new ThreadQueue(); ThreadQueue next = new ThreadQueue(); // initialize the first thread int startPC = anchorStart ? findPrefixLength : 0; ThreadQueue queued = new ThreadQueue(startPC); boolean foundMatch = false; int step = end > start ? +1 : -1; for (int i = start; i != end + step; i += step) { if (queued.isEmpty()) { // no threads left return foundMatch; } char c = i != end ? characters[i] : 0; int pc = -1; for (;;) { pc = current.next(pc); if (pc < 0) { pc = queued.queueOneImmediately(current); } if (pc < 0) { break; } // pc == program.length is a match! if (pc == program.length) { if (anchorEnd && i != end) { continue; } if (result == null) { // only interested in a match, no need to go on return true; } current.setResult(result); // now that we found a match, even higher-priority matches must match // at the same start offset if (!anchorStart) { next.mustStartMatchAt(current.startOffset(pc)); } foundMatch = true; break; } int opcode = program[pc]; switch (opcode) { case DOT: if (c != '\0' && c != '\r' && c != '\n') { current.queueNext(pc, pc + 1, next); } break; case DOTALL: current.queueNext(pc, pc + 1, next); break; case WORD_BOUNDARY: case NON_WORD_BOUNDARY: { int i2 = i - step; int c2 = i2 < 0 || i2 >= characters.length ? -1 : characters[i2]; switch (opcode) { case WORD_BOUNDARY: if ((c2 < 0 || !wordCharacter.matches((char)c2))) { if (wordCharacter.matches(c)) { current.queueImmediately(pc, pc + 1, false); } } else if (i >= 0 && i < characters.length && !wordCharacter.matches(c)) { current.queueImmediately(pc, pc + 1, false); } break; case NON_WORD_BOUNDARY: if ((c2 < 0 || !wordCharacter.matches((char)c2))) { if (i >= 0 && i < characters.length && !wordCharacter.matches(c)) { current.queueImmediately(pc, pc + 1, false); } } else if (wordCharacter.matches(c)) { current.queueImmediately(pc, pc + 1, false); } break; } break; } case LINE_START: if (i == 0 || (multiLine && lineTerminator.matches(characters[i - 1]))) { current.queueImmediately(pc, pc + 1, false); } break; case LINE_END: if (i == characters.length || (multiLine && lineTerminator.matches(c))) { current.queueImmediately(pc, pc + 1, false); } break; case CHARACTER_CLASS: if (classes[program[pc + 1]].matches(c)) { current.queueNext(pc, pc + 2, next); } break; case LOOKAHEAD: if (lookarounds[program[pc + 1]].matches(characters, i, characters.length, true, false, null)) { current.queueImmediately(pc, pc + 2, false); } break; case LOOKBEHIND: if (lookarounds[program[pc + 1]].matches(characters, i - 1, -1, true, false, null)) { current.queueImmediately(pc, pc + 2, false); } break; case NEGATIVE_LOOKAHEAD: if (!lookarounds[program[pc + 1]].matches(characters, i, characters.length, true, false, null)) { current.queueImmediately(pc, pc + 2, false); } break; case NEGATIVE_LOOKBEHIND: if (!lookarounds[program[pc + 1]].matches(characters, i - 1, -1, true, false, null)) { current.queueImmediately(pc, pc + 2, false); } break; /* immediate opcodes, i.e. thread continues within the same step */ case SAVE_OFFSET: if (result != null) { int index = program[pc + 1]; current.saveOffset(pc, index, i); } current.queueImmediately(pc, pc + 2, false); break; case SPLIT: current.queueImmediately(pc, program[pc + 1], true); current.queueImmediately(pc, pc + 2, false); break; case SPLIT_JMP: current.queueImmediately(pc, pc + 2, true); current.queueImmediately(pc, program[pc + 1], false); break; case JMP: current.queueImmediately(pc, program[pc + 1], false); break; default: if (program[pc] >= 0 && program[pc] <= 0xffff) { if (c == (char)program[pc]) { current.queueNext(pc, pc + 1, next); } break; } throw new RuntimeException("Invalid opcode: " + opcode + " at pc " + pc); } } // clean linked thread list (and states) current.clean(); // prepare for next step ThreadQueue swap = queued; queued = next; next = swap; } return foundMatch; } /** * Determines whether this machine recognizes a pattern without special * operators. *

* In case that the regular expression is actually a plain string without any * special operators, we can avoid using a full-blown Pike VM and instead fall * back to using the much faster {@link TrivialPattern}. *

* * @return the string to match, or null if the machine recognizes a * non-trivial pattern */ public String isPlainString() { // we expect the machine to start with the find preamble and SAVE_OFFSET 0 // end with SAVE_OFFSET 1 int start = findPrefixLength; if (start + 1 < program.length && program[start] == SAVE_OFFSET && program[start + 1] == 0) { start += 2; } int end = program.length; if (end > start + 1 && program[end - 2] == SAVE_OFFSET && program[end - 1] == 1) { end -= 2; } for (int i = start; i < end; ++ i) { if (program[i] < 0) { return null; } } char[] array = new char[end - start]; for (int i = start; i < end; ++ i) { array[i - start] = (char)program[i]; } return new String(array); } private static int length(int opcode) { return opcode <= SINGLE_ARG_START && opcode >= SINGLE_ARG_END ? 2 : 1; } private static boolean isJump(int opcode) { return opcode <= SPLIT && opcode >= JMP; } /** * Reverses the program (effectively matching the reverse pattern). *

* It is a well-known fact that any regular expression can be reordered * trivially into an equivalent regular expression to be applied in backward * direction (coming in real handy for look-behind expressions). *

*

* Example: instead of matching the sequence "aaaabb" with the pattern "a+b+", * we can match the reverse sequence "bbaaaa" with the pattern "b+a+". *

*

* One caveat: while the reverse pattern is equivalent in the sense that it * matches if, and only if, the original pattern matches the forward * direction, the same is not true for submatches. Consider the input "a" and * the pattern "(a?)a?": when matching in forward direction the captured group * is "a", while the backward direction will yield the empty string. For that * reason, Java dictates that capturing groups in look-behind patterns are * ignored. *

*/ public void reverse() { reverse(findPrefixLength, program.length); } /** * Reverses a specific part of the program (to match in reverse direction). *

* This is the work-horse of {@link #reverse()}. *

*

* To visualize the process of reversing a program, let's look at it as a * directed graph (each jump is represented by an "X * ", non-jumping steps are represented by a "o"s, arrows show the * direction of the flow, SPLITs spawn two arrows): * *

   * o -> X -> X -> o -> X    o -> o
   * ^    |     \         \___^____^
   *  \__/       \____________|
   * 
* * The concept of reversing the program is easiest explained as following: if * we insert auxiliary nodes "Y" for jump targets, the graph looks * like this instead: * *
   * Y -> o -> X -> X -> o -> X    Y -> o -> Y -> o
   * ^         |     \         \___^_________^
   *  \_______/       \____________|
   * 
* * It is now obvious that reversing the program is equivalent to reversing all * arrows, simply deleting all Xs and substituting each Y * with a jump. Note that the reverse program will have the same number of * JMP, but they will not be associated with the same arrows!: * *
   * X <- o <- o    X <- o <- X <- o
   * |    ^    ^____|________/
   *  \__/ \_______/
   * 
* *

* @param start * start reversing the program with this instruction * @param end * stop reversing at this instruction (this must be either an index * aligned exactly with an instruction, or exactly * {@code program.length}. */ private void reverse(int start, int end) { // Pass 1: build the list of jump targets int[] newJumps = new int[end + 1]; boolean[] brokenArrows = new boolean[end + 1]; for (int pc = start; pc < end; pc += length(program[pc])) { if (isJump(program[pc])) { int target = program[pc + 1]; newJumps[pc + 1] = newJumps[target]; newJumps[target] = pc + 1; if (program[pc] == JMP) { brokenArrows[pc + 2] = true; } } } // Pass 2: determine mapped program counters int[] mapping = new int[end]; for (int pc = start, mappedPC = end; mappedPC > 0 && pc < end; pc += length(program[pc])) { for (int jump = newJumps[pc]; jump > 0; jump = newJumps[jump]) { mappedPC -= 2; } if (!isJump(program[pc])) { mappedPC -= length(program[pc]); } mapping[pc] = mappedPC; } // Pass 3: write the new program int[] reverse = new int[end]; for (int pc = start, mappedPC = end; mappedPC > 0; pc += length(program[pc])) { boolean brokenArrow = brokenArrows[pc]; for (int jump = newJumps[pc]; jump > 0; jump = newJumps[jump]) { reverse[--mappedPC] = mapping[jump - 1]; if (brokenArrow) { reverse[--mappedPC] = JMP; brokenArrow = false; } else { reverse[--mappedPC] = program[jump - 1] == SPLIT_JMP ? SPLIT_JMP : SPLIT; } } if (pc == end) { break; } if (!isJump(program[pc])) { for (int i = length(program[pc]); i-- > 0; ) { reverse[--mappedPC] = program[pc + i]; } } } System.arraycopy(reverse, start, program, start, end - start); } } ReadyTalk-avian-1e1fff5/classpath/java/util/regex/PikeVMOpcodes.java000066400000000000000000000022651231440243200254720ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.regex; /** * Opcodes for the Pike VM. *

* See {@link PikeVM}. *

* * @author Johannes Schindelin */ interface PikeVMOpcodes { final static int DOT = -1; final static int DOTALL = -2; final static int WORD_BOUNDARY = -10; final static int NON_WORD_BOUNDARY = -11; final static int LINE_START = -12; final static int LINE_END = -13; final static int CHARACTER_CLASS = -20; final static int LOOKAHEAD = -30; final static int LOOKBEHIND = -31; final static int NEGATIVE_LOOKAHEAD = -32; final static int NEGATIVE_LOOKBEHIND = -33; final static int SAVE_OFFSET = -40; final static int SPLIT = -50; final static int SPLIT_JMP = -51; // this split prefers to jump final static int JMP = -52; final static int SINGLE_ARG_START = CHARACTER_CLASS; final static int SINGLE_ARG_END = JMP; } ReadyTalk-avian-1e1fff5/classpath/java/util/regex/RegexMatcher.java000066400000000000000000000035371231440243200254030ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.regex; /** * A minimal implementation of a regular expression matcher. * * @author Johannes Schindelin */ public class RegexMatcher extends Matcher { private final PikeVM vm; private char[] array; int[] groupStart, groupEnd; RegexMatcher(PikeVM vm, CharSequence string) { super(string); this.vm = vm; } private final PikeVM.Result adapter = new PikeVM.Result() { public void set(int[] start, int[] end) { RegexMatcher.this.start = start[0]; RegexMatcher.this.end = end[0]; RegexMatcher.this.groupStart = start; RegexMatcher.this.groupEnd = end; } }; public Matcher reset() { start = end = -1; return this; } public Matcher reset(CharSequence input) { this.input = input; array = input.toString().toCharArray(); return reset(); } public boolean matches() { return vm.matches(array, 0, array.length, true, true, adapter); } public boolean find() { return find(end + (start == end ? 1 : 0)); } public boolean find(int offset) { return vm.matches(array, offset, array.length, false, false, adapter); } public int start(int group) { return groupStart[group]; } public int end(int group) { return groupEnd[group]; } public String group(int group) { int offset = start(group); if (offset < 0) { return null; } int length = end(group) - offset; return new String(array, offset, length); } public int groupCount() { return groupStart.length - 1; } } ReadyTalk-avian-1e1fff5/classpath/java/util/regex/RegexPattern.java000066400000000000000000000036121231440243200254270ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.regex; /** * A minimal implementation of a regular expression engine. *

* Intended as a permissively-licensed drop-in replacement for Oracle JDK's * regular expression engine, this class uses the Pike VM implemented in * {@link PikeVM} to match regular expressions. *

*

* The Pike VM not only has a nicer runtime performance than Oracle JDK's * backtracking approach -- O(n*m) instead of O(2^m) where * n is the length of the regular expression pattern (after normalizing * {<n>} quantifiers) and m the length of the text to match against * the pattern -- but also supports arbitrary-sized look-behinds. *

*

* The current implementation supports all regular expression constructs * supported by Oracle JDK's regular expression engine except for the following * ones: *

    *
  • control characters: \cX
  • *
  • extended character classes: \p{...}
  • *
  • extended boundary matchers: \A,\G,\Z,\z
  • *
  • possessive quantifiers: X?+
  • *
  • back references: \<n>, \k<name>
  • *
  • long escape: \Q, \E
  • *
  • named groups: (?<name>X)
  • *
  • flags: (?idmsuxU)
  • *
  • independent, non-capturing group: (?>X)
  • *
*

* * @author Johannes Schindelin */ public class RegexPattern extends Pattern { private PikeVM vm; public RegexMatcher matcher(CharSequence string) { return new RegexMatcher(vm, string); } RegexPattern(String regex, int flags, PikeVM vm) { super(regex, flags); this.vm = vm; } } ReadyTalk-avian-1e1fff5/classpath/java/util/regex/TrivialMatcher.java000066400000000000000000000020431231440243200257320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.regex; /** * This is a work in progress. * * @author zsombor and others */ class TrivialMatcher extends Matcher { private final String pattern; TrivialMatcher(String pattern, CharSequence input) { super(input); this.pattern = pattern; } public boolean matches() { if (pattern.equals(input.toString())) { start = 0; end = input.length(); return true; } else { return false; } } public boolean find(int start) { String p = pattern; int i = TrivialPattern.indexOf(input, p, start); if (i >= 0) { this.start = i; this.end = i + p.length(); return true; } else { return false; } } } ReadyTalk-avian-1e1fff5/classpath/java/util/regex/TrivialPattern.java000066400000000000000000000051671231440243200257760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.regex; import java.util.Iterator; import java.util.List; import java.util.LinkedList; /** * This is a work in progress. * * @author zsombor and others * */ public class TrivialPattern extends Pattern { private final String unescaped; TrivialPattern(String pattern, String unescaped, int flags) { super(pattern, flags); this.unescaped = unescaped; } public Matcher matcher(CharSequence input) { return new TrivialMatcher(unescaped, input); } public String[] split(CharSequence input, int limit) { boolean strip; if (limit < 0) { strip = false; limit = Integer.MAX_VALUE; } else if (limit == 0) { strip = true; limit = Integer.MAX_VALUE; } else { strip = false; } List list = new LinkedList(); int index = 0; int trailing = 0; int patternLength = unescaped.length(); while (index < input.length() && list.size() < limit - 1) { int i; if (patternLength == 0) { if (list.size() == 0) { i = 0; } else { i = index + 1; } } else { i = indexOf(input, unescaped, index); } if (i >= 0) { if (patternLength != 0 && i == index) { ++ trailing; } else { trailing = 0; } list.add(input.subSequence(index, i)); index = i + patternLength; } else { break; } } if (strip && index > 0 && index == input.length()) { ++ trailing; } else { trailing = 0; } list.add(input.subSequence(index, input.length())); String[] result = new String[list.size() - trailing]; int i = 0; for (Iterator it = list.iterator(); it.hasNext() && i < result.length; ++ i) { result[i] = it.next().toString(); } return result; } static int indexOf(CharSequence haystack, CharSequence needle, int start) { if (needle.length() == 0) return start; for (int i = start; i < haystack.length() - needle.length() + 1; ++i) { int j = 0; for (; j < needle.length(); ++j) { if (haystack.charAt(i + j) != needle.charAt(j)) { break; } } if (j == needle.length()) { return i; } } return -1; } } ReadyTalk-avian-1e1fff5/classpath/java/util/zip/000077500000000000000000000000001231440243200216425ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/java/util/zip/CRC32.java000066400000000000000000000034471231440243200232710ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.zip; public class CRC32 { private static final int Polynomial = 0x04C11DB7; private static final int Width = 32; private static final int Top = 1 << (Width - 1); private static final int InitialRemainder = 0xFFFFFFFF; private static final long ResultXor = 0xFFFFFFFFL; private static final int[] table = new int[256]; static { for (int dividend = 0; dividend < 256; ++ dividend) { int remainder = dividend << (Width - 8); for (int bit = 8; bit > 0; --bit) { remainder = ((remainder & Top) != 0) ? (remainder << 1) ^ Polynomial : (remainder << 1); } table[dividend] = remainder; } } private int remainder = InitialRemainder; public void reset() { remainder = InitialRemainder; } public void update(int b) { remainder = table[reflect(b, 8) ^ (remainder >>> (Width - 8))] ^ (remainder << 8); } public void update(byte[] array, int offset, int length) { for (int i = 0; i < length; ++i) { update(array[offset + i] & 0xFF); } } public void update(byte[] array) { update(array, 0, array.length); } public long getValue() { return (reflect(remainder, Width) ^ ResultXor) & 0xFFFFFFFFL; } private static int reflect(int x, int n) { int reflection = 0; for (int i = 0; i < n; ++i) { if ((x & 1) != 0) { reflection |= (1 << ((n - 1) - i)); } x = (x >>> 1); } return reflection; } } ReadyTalk-avian-1e1fff5/classpath/java/util/zip/DataFormatException.java000066400000000000000000000010341231440243200264040ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.zip; public class DataFormatException extends Exception { public DataFormatException(String s) { super(s); } public DataFormatException() { super(); } } ReadyTalk-avian-1e1fff5/classpath/java/util/zip/Deflater.java000066400000000000000000000067451231440243200242470ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.zip; public class Deflater { private static final int DEFAULT_LEVEL = 6; // default compression level (6 is default for gzip) private static final int Z_OK = 0; private static final int Z_STREAM_END = 1; private static final int Z_NEED_DICT = 2; // static { // System.loadLibrary("natives"); // } private long peer; private byte[] input; private int offset; private int length; private boolean needDictionary; private boolean finished; private final boolean nowrap; private boolean finish; public Deflater(int level, boolean nowrap) { this.nowrap = nowrap; peer = make(nowrap, level); } public Deflater(int level) { this(level, false); } public Deflater() { this(DEFAULT_LEVEL); } private void check() { if (peer == 0) { throw new IllegalStateException(); } } private static native long make(boolean nowrap, int level); public boolean finished() { return finished; } public boolean needsDictionary() { return needDictionary; } public boolean needsInput() { return getRemaining() == 0; } public int getRemaining() { return length; } public void setLevel(int level) throws IllegalArgumentException { if (level < 0 || level > 9) { throw new IllegalArgumentException("Valid compression levels are 0-9"); } dispose(peer); peer = make(nowrap, level); } public void setInput(byte[] input) { setInput(input, 0, input.length); } public void setInput(byte[] input, int offset, int length) { this.input = input; this.offset = offset; this.length = length; } public void reset() { dispose(); peer = make(nowrap, DEFAULT_LEVEL); input = null; offset = length = 0; finish = false; needDictionary = finished = false; } public int deflate(byte[] output) { return deflate(output, 0, output.length); } public int deflate(byte[] output, int offset, int length) { final int zlibResult = 0; final int inputCount = 1; final int outputCount = 2; if (peer == 0) { throw new IllegalStateException(); } if (input == null || output == null) { throw new NullPointerException(); } int[] results = new int[3]; deflate(peer, input, this.offset, this.length, output, offset, length, finish, results); if (results[zlibResult] < 0) { throw new AssertionError(); } switch (results[zlibResult]) { case Z_NEED_DICT: needDictionary = true; break; case Z_STREAM_END: finished = true; break; } this.offset += results[inputCount]; this.length -= results[inputCount]; return results[outputCount]; } public void finish() { finish = true; } private static native void deflate (long peer, byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength, boolean finish, int[] results); public void end() { dispose(); } public void dispose() { if (peer != 0) { dispose(peer); peer = 0; } } private static native void dispose(long peer); } ReadyTalk-avian-1e1fff5/classpath/java/util/zip/DeflaterOutputStream.java000066400000000000000000000042021231440243200266260ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.zip; import java.io.OutputStream; import java.io.FilterOutputStream; import java.io.IOException; public class DeflaterOutputStream extends FilterOutputStream { protected final Deflater deflater; protected final byte[] buffer; public DeflaterOutputStream(OutputStream out, Deflater deflater, int bufferSize) { super(out); this.deflater = deflater; this.buffer = new byte[bufferSize]; } public DeflaterOutputStream(OutputStream out, Deflater deflater) { this(out, deflater, 4 * 1024); } public DeflaterOutputStream(OutputStream out) { this(out, new Deflater()); } public void write(int b) throws IOException { byte[] buffer = new byte[1]; buffer[0] = (byte)(b & 0xff); write(buffer, 0, 1); } public void write(byte[] b, int offset, int length) throws IOException { // error condition checking if (deflater.finished()) { throw new IOException("Already at end of stream"); } else if (offset < 0) { throw new IndexOutOfBoundsException("Offset can't be less than zero"); } else if (length < 0) { throw new IndexOutOfBoundsException("Length can't be less than zero"); } else if (b.length - (offset + length) < 0) { throw new IndexOutOfBoundsException("Offset + Length is larger than the input byte array"); } else if (length == 0) { return; } deflater.setInput(b, offset, length); while (deflater.getRemaining() > 0) { deflate(); } } private void deflate() throws IOException { int len = deflater.deflate(buffer, 0, buffer.length); if (len > 0) { out.write(buffer, 0, len); } } public void close() throws IOException { deflater.finish(); while (! deflater.finished()) { deflate(); } out.close(); deflater.dispose(); } } ReadyTalk-avian-1e1fff5/classpath/java/util/zip/Inflater.java000066400000000000000000000057251231440243200242620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.zip; public class Inflater { private static final int Z_OK = 0; private static final int Z_STREAM_END = 1; private static final int Z_NEED_DICT = 2; // static { // System.loadLibrary("natives"); // } private long peer; private byte[] input; private int offset; private int length; private boolean needDictionary; private boolean finished; private final boolean nowrap; public Inflater(boolean nowrap) { this.nowrap = nowrap; peer = make(nowrap); } public Inflater() { this(false); } private void check() { if (peer == 0) { throw new IllegalStateException(); } } private static native long make(boolean nowrap); public boolean finished() { return finished; } public boolean needsDictionary() { return needDictionary; } public boolean needsInput() { return getRemaining() == 0; } public int getRemaining() { return length; } public void setInput(byte[] input) { setInput(input, 0, input.length); } public void setInput(byte[] input, int offset, int length) { this.input = input; this.offset = offset; this.length = length; } public void reset() { dispose(); peer = make(nowrap); input = null; offset = length = 0; needDictionary = finished = false; } public int inflate(byte[] output) throws DataFormatException { return inflate(output, 0, output.length); } public int inflate(byte[] output, int offset, int length) throws DataFormatException { final int zlibResult = 0; final int inputCount = 1; final int outputCount = 2; if (peer == 0) { throw new IllegalStateException(); } if (input == null || output == null) { throw new NullPointerException(); } int[] results = new int[3]; inflate(peer, input, this.offset, this.length, output, offset, length, results); if (results[zlibResult] < 0) { throw new DataFormatException(); } switch (results[zlibResult]) { case Z_NEED_DICT: needDictionary = true; break; case Z_STREAM_END: finished = true; break; } this.offset += results[inputCount]; this.length -= results[inputCount]; return results[outputCount]; } private static native void inflate (long peer, byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength, int[] results); public void end() { dispose(); } public void dispose() { if (peer != 0) { dispose(peer); peer = 0; } } private static native void dispose(long peer); } ReadyTalk-avian-1e1fff5/classpath/java/util/zip/InflaterInputStream.java000066400000000000000000000040141231440243200264440ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.zip; import java.io.InputStream; import java.io.IOException; import java.io.EOFException; public class InflaterInputStream extends InputStream { private final InputStream in; private final Inflater inflater; private final byte[] buffer; public InflaterInputStream(InputStream in, Inflater inflater, int bufferSize) { this.in = in; this.inflater = inflater; this.buffer = new byte[bufferSize]; } public InflaterInputStream(InputStream in, Inflater inflater) { this(in, inflater, 4 * 1024); } public InflaterInputStream(InputStream in) { this(in, new Inflater()); } public int read() throws IOException { byte[] buffer = new byte[1]; int c = read(buffer); return (c < 0 ? c : (buffer[0] & 0xFF)); } public int read(byte[] b, int offset, int length) throws IOException { if (inflater.finished()) { return -1; } while (true) { if (inflater.needsInput()) { int count = in.read(buffer); if (count > 0) { inflater.setInput(buffer, 0, count); } else { throw new EOFException(); } } try { int count = inflater.inflate(b, offset, length); if (count > 0) { return count; } else if (inflater.needsDictionary()) { throw new IOException("missing dictionary"); } else if (inflater.finished()) { return -1; } } catch (DataFormatException e) { throw new IOException(e); } } } public int available() throws IOException { return inflater.finished() ? 0 : 1; } public void close() throws IOException { in.close(); inflater.dispose(); } } ReadyTalk-avian-1e1fff5/classpath/java/util/zip/ZipEntry.java000066400000000000000000000127001231440243200242710ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.zip; /** * Class ZipEntry: * * Class to store and retrieve information for entries in a zip file * Contains variables for all standard zip format field as well as * setter and accessor methods * * "name" is used to store the string name of the entrys * "reqVersion" stores a byte encoded minimum required version to open the zip * "compressionMethod" stores the method used to compress the zip * "modTimeDate" stores an MSDOS time field "millisTime" stores time in long format * "crc" stores crc data for the zip entry * "compSize" and "uncompSize" store compressed and uncompressed sizes * "offset" stores data regarding the offset from the start of the zip file * * @author Christopher Jordan * @author David Chau * @author Aaron Davis * @author Riley Moses */ import java.util.Calendar; import java.util.Date; public class ZipEntry { String name; short reqVersion = -1; short compressionMethod = -1; int modTimeDate = -1; long millisTime = -1; int crc = -1; long compSize = 0; long uncompSize = 0; int offset = -1; public ZipEntry(String name) { this.name = name; setTime(System.currentTimeMillis()); } //Method to return name of the file public String getName() { return name; } //Method to check if file is a directory public boolean isDirectory() { return getName().endsWith("/"); } /** * Method setRequiredVersion: * * Method to set the minimum version required to open the zip file * Valid values for the compression method are the numbers 1.0 to 10.0 * * @author Christopher Jordan */ private boolean setRequiredVersion(float versionFloat){ //Check for valid version numbers if (versionFloat < 1 || versionFloat > 100){ return false; } //Convert to short value for storage versionFloat = versionFloat * 10; short versionShort = (short)versionFloat; //Set value of version reqVersion = versionShort; return true; } //Method to set the compression method for the file //Valid methods are "stored" = 0 or "deflated" = 8 public void setMethod(short compMethod){ if (compMethod == 0 || compMethod == 8){ this.compressionMethod = compMethod; } } public int getMethod(){ return this.compressionMethod; } //Methods to set and get the crc for the entry public void setCrc(int crc){ if (crc < 0 || crc > 0xffffffff){ return; } else this.crc = crc; } public int getCrc(){ return this.crc; } //Methods to set and get the time and date public void setTime(long currentTime){ modTimeDate = computeDOSDateTime(currentTime); millisTime = currentTime; } public long getTime(){ return millisTime; } /** * Method computeDOSDateTime(): * * Takes the time from a long and converts to a Calendar object * * Time is stored in the MSDOS format 5 bits for hour, 6 bits for min, 5 bits for seconds * Hours are in military time and must be adjusted to time zone * Seconds are divided by two before storing and must be multiplied by two to retrieve * * Date is stored in the MSDOS format 7 bit for year, 4 bit for month, 5 bits for day of month * Year is the number of years since 1980 per, the month is stored starting at 0 * for January. Day of month is stored with nature numbering * * Bit masks and shifting are used to build the time and date bytes * * @author Christopher Jordan * @author Aaron Davis **/ private static int computeDOSDateTime(long currentTime){ final int DAY_OF_MONTH = 5; final int HOUR_OF_DAY = 11; final int MINUTE = 12; final int MONTH = 2; final int SECOND = 13; final int YEAR = 1; //Create calendar object, then set time to value passed in Calendar modCalendar = Calendar.getInstance(); modCalendar.setTime(new Date(currentTime)); //Hour int timeBits = modCalendar.get(HOUR_OF_DAY); timeBits = timeBits - 6; timeBits = timeBits << 6; //Minutes int minBits = 0x3f & (modCalendar.get(MINUTE));; timeBits = timeBits ^ minBits; timeBits = timeBits << 5; //Seconds int secBits = 0x1f & (modCalendar.get(SECOND)); secBits = secBits >> 1; //Divide by 2 timeBits = timeBits ^ secBits; //Year int dateBits = (modCalendar.get(YEAR) -1980); dateBits = dateBits << 4; //Month int month = 0xf & ((modCalendar.get(MONTH)) + 1); dateBits = dateBits ^ month; dateBits = dateBits << 5; //Day of month int dayBits = 0x1f & modCalendar.get(DAY_OF_MONTH); dateBits = dateBits ^ dayBits; //Store Date int storeDate = ((dateBits << 16) ^ (timeBits)); return storeDate; } //Methods to set and get the uncompressed size of the entry public void setSize(int size){ if (size < 0){ return; } else uncompSize = size; } public long getSize() { return uncompSize; } //Methods to set and get the compressed size of the entry public void setCompressedSize(long size){ if (size < 0){ return; } else compSize = size; } public long getCompressedSize() { return compSize; } } ReadyTalk-avian-1e1fff5/classpath/java/util/zip/ZipFile.java000066400000000000000000000242541231440243200240560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.zip; import java.io.File; import java.io.RandomAccessFile; import java.io.InputStream; import java.io.IOException; import java.util.Enumeration; import java.util.Iterator; import java.util.Map; import java.util.HashMap; public class ZipFile { private final RandomAccessFile file; private final Window window; private final Map index = new HashMap(); public ZipFile(String name) throws IOException { file = new RandomAccessFile(name, "r"); window = new Window(file, 4096); int fileLength = (int) file.length(); int pointer = fileLength - 22; byte[] magic = new byte[] { 0x50, 0x4B, 0x05, 0x06 }; while (pointer > 0) { if (equal(window.data, window.seek(pointer, magic.length), magic, 0, magic.length)) { pointer = directoryOffset(window, pointer); magic = new byte[] { 0x50, 0x4B, 0x01, 0x02 }; while (pointer < fileLength) { if (equal(window.data, window.seek(pointer, magic.length), magic, 0, magic.length)) { index.put(entryName(window, pointer), pointer); pointer = entryEnd(window, pointer); } else { pointer = fileLength; } } pointer = 0; } else { -- pointer; } } } public ZipFile(File file) throws IOException { this(file.getAbsolutePath()); } public int size() { return index.size(); } protected Enumeration makeEnumeration (EntryFactory factory) { return new MyEnumeration(factory, window, index.values().iterator()); } public Enumeration entries() { return makeEnumeration(ZipEntryFactory.Instance); } protected ZipEntry getEntry(EntryFactory factory, String name) { while (name.startsWith("/")) { name = name.substring(1); } Integer pointer = index.get(name); return (pointer == null ? null : factory.makeEntry(window, pointer)); } public ZipEntry getEntry(String name) { return getEntry(ZipEntryFactory.Instance, name); } public InputStream getInputStream(ZipEntry entry) throws IOException { final int pointer = ((MyEntry) entry).pointer(); int method = compressionMethod(window, pointer); int size = compressedSize(window, pointer); InputStream in = new MyInputStream(file, fileData(window, pointer), size); final int Stored = 0; final int Deflated = 8; switch (method) { case Stored: return in; case Deflated: return new InflaterInputStream(in, new Inflater(true)) { int remaining = uncompressedSize(window, pointer); public int read() throws IOException { byte[] buffer = new byte[1]; int c = read(buffer); return (c < 0 ? c : (buffer[0] & 0xFF)); } public int read(byte[] buffer) throws IOException { return read(buffer, 0, buffer.length); } public int read(byte[] buffer, int offset, int length) throws IOException { int c = super.read(buffer, offset, length); if (c > 0) { remaining -= c; } return c; } public int available() { return remaining; } }; default: throw new IOException(); } } private static boolean equal(byte[] a, int aOffset, byte[] b, int bOffset, int size) { for (int i = 0; i < size; ++i) { if (a[aOffset + i] != b[bOffset + i]) return false; } return true; } private static int get2(Window w, int p) throws IOException { int offset = w.seek(p, 2); return ((w.data[offset + 1] & 0xFF) << 8) | ((w.data[offset ] & 0xFF) ); } private static int get4(Window w, int p) throws IOException { int offset = w.seek(p, 4); return ((w.data[offset + 3] & 0xFF) << 24) | ((w.data[offset + 2] & 0xFF) << 16) | ((w.data[offset + 1] & 0xFF) << 8) | ((w.data[offset ] & 0xFF) ); } private static int directoryOffset(Window w, int p) throws IOException { return get4(w, p + 16); } private static int entryNameLength(Window w, int p) throws IOException { return get2(w, p + 28); } protected static String entryName(Window w, int p) throws IOException { int length = entryNameLength(w, p); return new String(w.data, w.seek(p + 46, length), length); } private static int compressionMethod(Window w, int p) throws IOException { return get2(w, p + 10); } protected static int compressedSize(Window w, int p) throws IOException { return get4(w, p + 20); } protected static int uncompressedSize(Window w, int p) throws IOException { return get4(w, p + 24); } private static int fileNameLength(Window w, int p) throws IOException { return get2(w, p + 28); } private static int extraFieldLength(Window w, int p) throws IOException { return get2(w, p + 30); } private static int commentFieldLength(Window w, int p) throws IOException { return get2(w, p + 32); } private static int entryEnd(Window w, int p) throws IOException { final int HeaderSize = 46; return p + HeaderSize + fileNameLength(w, p) + extraFieldLength(w, p) + commentFieldLength(w, p); } private static int fileData(Window w, int p) throws IOException { int localHeader = localHeader(w, p); final int LocalHeaderSize = 30; return localHeader + LocalHeaderSize + localFileNameLength(w, localHeader) + localExtraFieldLength(w, localHeader); } private static int localHeader(Window w, int p) throws IOException { return get4(w, p + 42); } private static int localFileNameLength(Window w, int p) throws IOException { return get2(w, p + 26); } private static int localExtraFieldLength(Window w, int p) throws IOException { return get2(w, p + 28); } public void close() throws IOException { file.close(); } protected static class Window { private final RandomAccessFile file; public final byte[] data; public int start; public int length; public Window(RandomAccessFile file, int size) { this.file = file; data = new byte[size]; } public int seek(int start, int length) throws IOException { int fileLength = (int) file.length(); if (length > data.length) { throw new IllegalArgumentException ("length " + length + " greater than buffer length " + data.length); } if (start < 0) { throw new IllegalArgumentException("negative start " + start); } if (start + length > fileLength) { throw new IllegalArgumentException ("end " + (start + length) + " greater than file length " + fileLength); } if (start < this.start || start + length > this.start + this.length) { this.length = Math.min(data.length, fileLength); this.start = start - ((this.length - length) / 2); if (this.start < 0) { this.start = 0; } else if (this.start + this.length > fileLength) { this.start = fileLength - this.length; } file.seek(this.start); file.readFully(data, 0, this.length); } return start - this.start; } } protected interface MyEntry { public int pointer(); } private static class MyZipEntry extends ZipEntry implements MyEntry { public final Window window; public final int pointer; public MyZipEntry(Window window, int pointer) { super(null); this.window = window; this.pointer = pointer; } public String getName() { try { return entryName(window, pointer); } catch (IOException e) { return null; } } public long getCompressedSize() { try { return compressedSize(window, pointer); } catch (IOException e) { return 0; } } public long getSize() { try { return uncompressedSize(window, pointer); } catch (IOException e) { return 0; } } public int pointer() { return pointer; } } protected interface EntryFactory { public ZipEntry makeEntry(Window window, int pointer); } private static class ZipEntryFactory implements EntryFactory { public static final ZipEntryFactory Instance = new ZipEntryFactory(); public ZipEntry makeEntry(Window window, int pointer) { return new MyZipEntry(window, pointer); } } private static class MyEnumeration implements Enumeration { private final EntryFactory factory; private final Window window; private final Iterator iterator; public MyEnumeration(EntryFactory factory, Window window, Iterator iterator) { this.factory = factory; this.window = window; this.iterator = iterator; } public boolean hasMoreElements() { return iterator.hasNext(); } public ZipEntry nextElement() { return factory.makeEntry(window, iterator.next()); } } private static class MyInputStream extends InputStream { private RandomAccessFile file; private int offset; private int length; public MyInputStream(RandomAccessFile file, int start, int length) { this.file = file; this.offset = start; this.length = length; } public int read() throws IOException { byte[] b = new byte[1]; int c = read(b); return (c == -1 ? -1 : b[0] & 0xFF); } public int read(byte[] b, int offset, int length) throws IOException { if (this.length == 0) return -1; if (length > this.length) length = this.length; file.seek(this.offset); file.readFully(b, offset, length); this.offset += length; this.length -= length; return length; } public void close() throws IOException { file = null; } } } ReadyTalk-avian-1e1fff5/classpath/java/util/zip/ZipOutputStream.java000066400000000000000000000217441231440243200256540ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util.zip; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.zip.CRC32; import java.util.zip.DeflaterOutputStream; import java.util.zip.Deflater; /** * An as simple as possible implementation of ZipOutputStream * Compression method defaults to DEFLATE * All hardcoded defaults match the defaults for openJDK, * including PKZip version, bit flags set, compression level, etc * * @author David Chau * @author Aaron Davis * @author Christopher Jordan * @author Riley Moses * */ public class ZipOutputStream extends DeflaterOutputStream { private static final int SIGNATURE = 0x04034b50; private static final short VERSION = 0x0014; private static final short BITFLAG = 0x0008; private static final short METHOD = 0x0008; private static final int CENTRAL_FILE_HEADER = 0x02014b50; private static final int DATA_DESCRIPTER_HEADER = 0x08074b50; private static final int END_OF_CENTRAL_DIRECTORY_SIG = 0x06054b50; private static final int DEFAULT_LEVEL = 6; private static final int INPUT_BUFFER_SIZE = 1024; private List entries; private CRC32 crc = new CRC32(); private ZipEntry currentEntry; // holder for current entry private int bytesWritten; // a counter for total bytes written private int sizeOfCentralDirectory; // a counter for central dir size // these are used for the function write(int b) to provide a speed increase private byte[] inputBuffer = new byte[INPUT_BUFFER_SIZE]; private int bufferIndex; public ZipOutputStream(OutputStream outStream) { super(outStream, new Deflater(DEFAULT_LEVEL, true)); bytesWritten = 0; sizeOfCentralDirectory = 0; entries = new ArrayList(); } public void putNextEntry(ZipEntry e) throws IOException { e.offset = bytesWritten; currentEntry = e; entries.add(e); writeLocalHeader(e); } public void closeEntry() throws IOException { // write remainder of buffer if partially full if (bufferIndex != 0) { write(inputBuffer, 0, bufferIndex); bufferIndex = 0; } finish(); currentEntry.crc = (int) crc.getValue(); crc.reset(); writeDataDescriptor(currentEntry); } @Override public void write(byte[] b, int offset, int length) throws IOException { if (offset < 0 || length < 0 || b.length - (offset + length) < 0) throw new IndexOutOfBoundsException(); currentEntry.uncompSize += length; crc.update(b, offset, length); currentEntry.crc = (int) crc.getValue(); deflater.setInput(b, offset, length); while (deflater.getRemaining() > 0) deflate(); } @Override public void write(int b) throws IOException { inputBuffer[bufferIndex] = (byte)(b & 0xff); bufferIndex += 1; if (bufferIndex == 1024) { write(inputBuffer, 0, bufferIndex); bufferIndex = 0; } } private void deflate() throws IOException { int len = deflater.deflate(buffer, 0, buffer.length); currentEntry.compSize += len; bytesWritten += len; if (len > 0) out.write(buffer, 0, len); } private void writeLocalHeader(ZipEntry e) throws IOException { byte[] tmpBuffer = new byte[30]; addFourBytes(SIGNATURE, 0, tmpBuffer); // local header signature addTwoBytes(VERSION, 4, tmpBuffer); // version used addTwoBytes(BITFLAG, 6, tmpBuffer); // flags addTwoBytes(METHOD, 8, tmpBuffer); // compression method addFourBytes(e.modTimeDate, 10, tmpBuffer); // last mod date and time addFourBytes(0, 14, tmpBuffer); // CRC is 0 for local header // with default flag settings (bit 3 set) the compressed and uncompressed size // is written here as 0 and written correctly in the data descripter addFourBytes(0, 18, tmpBuffer); // compressed size addFourBytes(0, 22, tmpBuffer); // uncompressed size addTwoBytes(e.name.length(), 26, tmpBuffer); // length of file name // extra field length, in this implementation extra field in not used addTwoBytes(0, 28, tmpBuffer); out.write(tmpBuffer, 0, 30); // write file name, return the number of bytes written int len = writeUTF8(e.getName()); bytesWritten += 30 + len; } private void writeDataDescriptor(ZipEntry currentEntry) throws IOException { byte[] tmpBuffer = new byte[16]; addFourBytes(DATA_DESCRIPTER_HEADER, 0, tmpBuffer); // data descripter header addFourBytes(currentEntry.crc, 4, tmpBuffer); // crc value addFourBytes((int)currentEntry.compSize, 8, tmpBuffer); // compressed size addFourBytes((int)currentEntry.uncompSize, 12, tmpBuffer);// uncompressed size out.write(tmpBuffer, 0, 16); bytesWritten += 16; } private void writeCentralDirectoryHeader(ZipEntry e) throws IOException { byte[] tmpBuffer = new byte[46]; addFourBytes(CENTRAL_FILE_HEADER, 0, tmpBuffer); // central directory header signature addTwoBytes(VERSION, 4, tmpBuffer); // version made by addTwoBytes(VERSION, 6, tmpBuffer); // version needed addTwoBytes(BITFLAG, 8, tmpBuffer); // flags addTwoBytes(METHOD, 10, tmpBuffer); // compression method addFourBytes(e.modTimeDate, 12, tmpBuffer); // last mod date and time addFourBytes(e.crc, 16, tmpBuffer); // crc addFourBytes((int)e.compSize, 20, tmpBuffer); // compressed size addFourBytes((int)e.uncompSize, 24, tmpBuffer); // uncompressed size addTwoBytes(e.getName().length(), 28, tmpBuffer); // file name length // the following 5 fields are all 0 for a simple default compression addTwoBytes(0, 30, tmpBuffer); // extra field length (not used) addTwoBytes(0, 32, tmpBuffer); // comment length (not used) addTwoBytes(0, 34, tmpBuffer); // disk number start addTwoBytes(0, 36, tmpBuffer); // internal file attribute addFourBytes(0, 38, tmpBuffer); // external file attribute addFourBytes((int) e.offset, 42, tmpBuffer); // relative offset of local header out.write(tmpBuffer, 0, 46); int len = writeUTF8(e.getName()); bytesWritten += 46 + len; sizeOfCentralDirectory += 46 + len; } private void writeEndofCentralDirectory(int offset) throws IOException { byte[] tmpBuffer = new byte[22]; short numEntries = (short) entries.size(); addFourBytes(END_OF_CENTRAL_DIRECTORY_SIG, 0, tmpBuffer); // end of central directory signature addTwoBytes(0, 4, tmpBuffer); // disk number addTwoBytes(0, 6, tmpBuffer); // disk number where central dir starts addTwoBytes(numEntries, 8, tmpBuffer); // number of entries on this disk addTwoBytes(numEntries, 10, tmpBuffer); // number of entries in central dir addFourBytes(sizeOfCentralDirectory, 12, tmpBuffer); // length of central directory addFourBytes(offset, 16, tmpBuffer); // offset of central directory addTwoBytes(0, 20, tmpBuffer); // length of added comments (not used) out.write(tmpBuffer, 0, 22); bytesWritten += 22; } @Override public void close() throws IOException { int centralDirOffset = bytesWritten; for (ZipEntry e : entries) writeCentralDirectoryHeader(e); writeEndofCentralDirectory(centralDirOffset); deflater.dispose(); out.close(); } @Override public void flush() throws IOException { out.write(inputBuffer, 0, inputBuffer.length); inputBuffer = new byte[INPUT_BUFFER_SIZE]; } private void finish() throws IOException { deflater.finish(); while (!deflater.finished()) { deflate(); } deflater.reset(); } private void addTwoBytes(int bytes, int offset, byte[] buffer) throws IOException { buffer[offset] = (byte) (bytes & 0xff); buffer[offset + 1] = (byte) ((bytes >> 8) & 0xff); } private void addFourBytes(int bytes, int offset, byte[] buffer) throws IOException { buffer[offset] = (byte) (bytes & 0xff); buffer[offset + 1] = (byte) ((bytes >> 8) & 0xff); buffer[offset + 2] = (byte) ((bytes >> 16) & 0xff); buffer[offset + 3] = (byte) ((bytes >> 24) & 0xff); } private int writeUTF8(String text) throws IOException { byte[] bytes = text.getBytes("UTF-8"); out.write(bytes, 0, bytes.length); return bytes.length; } }ReadyTalk-avian-1e1fff5/classpath/jni-util.h000066400000000000000000000052221231440243200210470ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef JNI_UTIL #define JNI_UTIL #include "stdio.h" #include "stdlib.h" #include "string.h" #include #undef JNIEXPORT #if (defined __MINGW32__) || (defined _MSC_VER) # define PLATFORM_WINDOWS # define PATH_SEPARATOR ';' # define JNIEXPORT __declspec(dllexport) #else // not (defined __MINGW32__) || (defined _MSC_VER) # define PLATFORM_POSIX # define PATH_SEPARATOR ':' # define JNIEXPORT __attribute__ ((visibility("default"))) \ __attribute__ ((used)) #endif // not (defined __MINGW32__) || (defined _MSC_VER) #ifdef _MSC_VER # define UNUSED typedef char int8_t; typedef unsigned char uint8_t; typedef short int16_t; typedef unsigned short uint16_t; typedef int int32_t; typedef unsigned int uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; # define INT32_MAX 2147483647 # define not ! # define or || # define and && # define xor ^ # ifdef _M_IX86 # define ARCH_x86_32 # elif defined _M_X64 # define ARCH_x86_64 # endif #else // not _MSC_VER # define UNUSED __attribute__((unused)) # include "stdint.h" # include "errno.h" # ifdef __i386__ # define ARCH_x86_32 # elif defined __x86_64__ # define ARCH_x86_64 # elif (defined __POWERPC__) || (defined __powerpc__) # define ARCH_powerpc # elif defined __arm__ # define ARCH_arm # endif #endif // not _MSC_VER inline void throwNew(JNIEnv* e, const char* class_, const char* message, ...) { jclass c = e->FindClass(class_); if (c) { if (message) { static const unsigned BufferSize = 256; char buffer[BufferSize]; va_list list; va_start(list, message); #ifdef _MSC_VER vsnprintf_s(buffer, BufferSize - 1, _TRUNCATE, message, list); #else vsnprintf(buffer, BufferSize - 1, message, list); #endif va_end(list); e->ThrowNew(c, buffer); } else { e->ThrowNew(c, 0); } e->DeleteLocalRef(c); } } inline void throwNewErrno(JNIEnv* e, const char* class_) { #ifdef _MSC_VER const unsigned size = 128; char buffer[size]; strerror_s(buffer, size, errno); throwNew(e, class_, buffer); #else throwNew(e, class_, strerror(errno)); #endif } inline void* allocate(JNIEnv* e, unsigned size) { void* p = malloc(size); if (p == 0) { throwNew(e, "java/lang/OutOfMemoryError", 0); } return p; } #endif//JNI_UTIL ReadyTalk-avian-1e1fff5/classpath/sockets.cpp000066400000000000000000000114111231440243200213170ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ /* * This file implements a simple cross-platform JNI sockets API * It is used from different classes of the default Avian classpath */ #include "sockets.h" namespace avian { namespace classpath { namespace sockets { int last_socket_error() { #ifdef PLATFORM_WINDOWS int error = WSAGetLastError(); #else int error = errno; #endif return error; } void init(JNIEnv* ONLY_ON_WINDOWS(e)) { #ifdef PLATFORM_WINDOWS static bool wsaInitialized = false; if (not wsaInitialized) { WSADATA data; int r = WSAStartup(MAKEWORD(2, 2), &data); if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) { throwNew(e, "java/io/IOException", "WSAStartup failed"); } else { wsaInitialized = true; } } #endif } SOCKET create(JNIEnv* e) { SOCKET sock; if (INVALID_SOCKET == (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) { char buf[255]; sprintf(buf, "Can't create a socket. System error: %d", last_socket_error()); throwNew(e, "java/io/IOException", buf); return 0; // This doesn't matter cause we have risen an exception } return sock; } void connect(JNIEnv* e, SOCKET sock, long addr, short port) { sockaddr_in adr; adr.sin_family = AF_INET; #ifdef PLATFORM_WINDOWS adr.sin_addr.S_un.S_addr = htonl(addr); #else adr.sin_addr.s_addr = htonl(addr); #endif adr.sin_port = htons (port); if (SOCKET_ERROR == ::connect(sock, (sockaddr* )&adr, sizeof(adr))) { char buf[255]; sprintf(buf, "Can't connect a socket. System error: %d", last_socket_error()); throwNew(e, "java/io/IOException", buf); return; } } void bind(JNIEnv* e, SOCKET sock, long addr, short port) { sockaddr_in adr; adr.sin_family = AF_INET; #ifdef PLATFORM_WINDOWS adr.sin_addr.S_un.S_addr = htonl(addr); #else adr.sin_addr.s_addr = htonl(addr); #endif adr.sin_port = htons (port); if (SOCKET_ERROR == ::bind(sock, (sockaddr* )&adr, sizeof(adr))) { char buf[255]; sprintf(buf, "Can't bind a socket. System error: %d", last_socket_error()); throwNew(e, "java/io/IOException", buf); return; } } SOCKET accept(JNIEnv* e, SOCKET sock, long* client_addr, short* client_port) { sockaddr_in adr; SOCKET client_socket = ::accept(sock, (sockaddr* )&adr, NULL); if (INVALID_SOCKET == client_socket) { char buf[255]; sprintf(buf, "Can't accept the incoming connection. System error: %d", last_socket_error()); throwNew(e, "java/io/IOException", buf); return INVALID_SOCKET; } if (client_addr != NULL) { #ifdef PLATFORM_WINDOWS *client_addr = ntohl(adr.sin_addr.S_un.S_addr); #else *client_addr = ntohl(adr.sin_addr.s_addr); #endif } if (client_port != NULL) { *client_port = ntohs (adr.sin_port); } return client_socket; } void send(JNIEnv* e, SOCKET sock, const char* buff_ptr, int buff_size) { if (SOCKET_ERROR == ::send(sock, buff_ptr, buff_size, 0)) { char buf[255]; sprintf(buf, "Can't send data through the socket. System error: %d", last_socket_error()); throwNew(e, "java/io/IOException", buf); return; } } int recv(JNIEnv* e, SOCKET sock, char* buff_ptr, int buff_size) { int length = ::recv(sock, buff_ptr, buff_size, 0); if (SOCKET_ERROR == length) { char buf[255]; sprintf(buf, "Can't receive data through the socket. System error: %d", last_socket_error()); throwNew(e, "java/io/IOException", buf); return 0; // This doesn't matter cause we have risen an exception } return length; } void abort(JNIEnv* e, SOCKET sock) { if (SOCKET_ERROR == ::closesocket(sock)) { char buf[255]; sprintf(buf, "Can't close the socket. System error: %d", last_socket_error()); throwNew(e, "java/io/IOException", buf); } } void close(JNIEnv* e, SOCKET sock) { if (SOCKET_ERROR == ::shutdown(sock, SD_BOTH)) { int errcode = last_socket_error(); if (errcode != ENOTCONN) { char buf[255]; sprintf(buf, "Can't shutdown the socket. System error: %d", errcode); throwNew(e, "java/io/IOException", buf); } } } void close_input(JNIEnv* e, SOCKET sock) { if (SOCKET_ERROR == ::shutdown(sock, SD_RECEIVE)) { int errcode = last_socket_error(); if (errcode != ENOTCONN) { char buf[255]; sprintf(buf, "Can't shutdown the socket. System error: %d", errcode); throwNew(e, "java/io/IOException", buf); } } } void close_output(JNIEnv* e, SOCKET sock) { if (SOCKET_ERROR == ::shutdown(sock, SD_SEND)) { int errcode = last_socket_error(); if (errcode != ENOTCONN) { char buf[255]; sprintf(buf, "Can't shutdown the socket. System error: %d", errcode); throwNew(e, "java/io/IOException", buf); } } } } } } ReadyTalk-avian-1e1fff5/classpath/sockets.h000066400000000000000000000034261231440243200207730ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ /* * This file represents a simple cross-platform JNI sockets API * It is used from different classes of the default Avian classpath */ #ifndef SOCKETS_H_ #define SOCKETS_H_ #include "avian/common.h" #include "jni.h" #include "jni-util.h" #ifdef PLATFORM_WINDOWS # include # define ONLY_ON_WINDOWS(x) x # ifndef ENOTCONN # define ENOTCONN WSAENOTCONN # endif #else # include # include # include # include # define ONLY_ON_WINDOWS(x) # define SOCKET int # define INVALID_SOCKET -1 # define SOCKET_ERROR -1 # define closesocket(x) close(x) # define SD_RECEIVE SHUT_RD # define SD_SEND SHUT_WR # define SD_BOTH SHUT_RDWR #endif namespace avian { namespace classpath { namespace sockets { // Library initialization void init(JNIEnv* ONLY_ON_WINDOWS(e)); // Socket initialization SOCKET create(JNIEnv* e); void connect(JNIEnv* e, SOCKET sock, long addr, short port); void bind(JNIEnv* e, SOCKET sock, long addr, short port); SOCKET accept(JNIEnv* e, SOCKET sock, long* client_addr, short* client_port); // I/O void send(JNIEnv* e, SOCKET sock, const char* buff_ptr, int buff_size); int recv(JNIEnv* e, SOCKET sock, char* buff_ptr, int buff_size); // Socket closing void abort(JNIEnv* e, SOCKET sock); void close(JNIEnv* e, SOCKET sock); void close_input(JNIEnv* e, SOCKET sock); void close_output(JNIEnv* e, SOCKET sock); } } } #endif /* SOCKETS_H_ */ ReadyTalk-avian-1e1fff5/classpath/sun/000077500000000000000000000000001231440243200177475ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/sun/misc/000077500000000000000000000000001231440243200207025ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/sun/misc/Cleaner.java000066400000000000000000000006131231440243200231160ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package sun.misc; public class Cleaner { } ReadyTalk-avian-1e1fff5/classpath/sun/misc/Unsafe.java000066400000000000000000000056221231440243200227730ustar00rootroot00000000000000package sun.misc; import java.lang.reflect.Field; public final class Unsafe { private void Unsafe() { } private static final Unsafe theUnsafe = new Unsafe(); public static Unsafe getUnsafe() { return theUnsafe; } public native long allocateMemory(long bytes); public native void setMemory (Object base, long offset, long count, byte value); public native void freeMemory(long address); public native byte getByte(long address); public native void putByte(long address, byte x); public native short getShort(long address); public native void putShort(long address, short x); public native char getChar(long address); public native void putChar(long address, char x); public native int getInt(long address); public native void putInt(long address, int x); public native long getLong(long address); public native void putLong(long address, long x); public native float getFloat(long address); public native void putFloat(long address, float x); public native double getDouble(long address); public native void putDouble(long address, double x); public native int getIntVolatile(Object o, long offset); public native void putIntVolatile(Object o, long offset, int x); public native long getLongVolatile(Object o, long offset); public native long putLongVolatile(Object o, long offset, long x); public native long putOrderedLong(Object o, long offset, long x); public native void putOrderedInt(Object o, long offset, int x); public native Object getObject(Object o, long offset); public native void putObject(Object o, long offset, Object x); public native void putObjectVolatile(Object o, long offset, Object x); public native void putOrderedObject(Object o, long offset, Object x); public native Object getObjectVolatile(Object o, long offset); public native long getAddress(long address); public native void putAddress(long address, long x); public native int arrayBaseOffset(Class arrayClass); public native int arrayIndexScale(Class arrayClass); public native long objectFieldOffset(Field field); public native void park(boolean absolute, long time); public native void unpark(Object target); public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long count); public native boolean compareAndSwapInt(Object o, long offset, int old, int new_); public native boolean compareAndSwapLong(Object o, long offset, long old, long new_); public native boolean compareAndSwapObject(Object o, long offset, Object old, Object new_); public void copyMemory(long src, long dst, long count) { copyMemory(null, src, null, dst, count); } public native void throwException(Throwable t); } ReadyTalk-avian-1e1fff5/classpath/sun/reflect/000077500000000000000000000000001231440243200213735ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/classpath/sun/reflect/ConstantPool.java000066400000000000000000000006231231440243200246620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package sun.reflect; public class ConstantPool { } ReadyTalk-avian-1e1fff5/include/000077500000000000000000000000001231440243200166035ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/include/avian/000077500000000000000000000000001231440243200177015ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/include/avian/codegen/000077500000000000000000000000001231440243200213055ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/include/avian/codegen/architecture.h000066400000000000000000000070361231440243200241460ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ARCHITECTURE_H #define AVIAN_CODEGEN_ARCHITECTURE_H namespace vm { class Zone; } namespace avian { namespace util { class Allocator; } namespace codegen { class Assembler; class RegisterFile; class OperandMask { public: uint8_t typeMask; uint64_t registerMask; OperandMask(uint8_t typeMask, uint64_t registerMask): typeMask(typeMask), registerMask(registerMask) { } OperandMask(): typeMask(~0), registerMask(~static_cast(0)) { } }; class Architecture { public: virtual unsigned floatRegisterSize() = 0; virtual const RegisterFile* registerFile() = 0; virtual int scratch() = 0; virtual int stack() = 0; virtual int thread() = 0; virtual int returnLow() = 0; virtual int returnHigh() = 0; virtual int virtualCallTarget() = 0; virtual int virtualCallIndex() = 0; virtual bool bigEndian() = 0; virtual uintptr_t maximumImmediateJump() = 0; virtual bool alwaysCondensed(lir::BinaryOperation op) = 0; virtual bool alwaysCondensed(lir::TernaryOperation op) = 0; virtual bool reserved(int register_) = 0; virtual unsigned frameFootprint(unsigned footprint) = 0; virtual unsigned argumentFootprint(unsigned footprint) = 0; virtual bool argumentAlignment() = 0; virtual bool argumentRegisterAlignment() = 0; virtual unsigned argumentRegisterCount() = 0; virtual int argumentRegister(unsigned index) = 0; virtual bool hasLinkRegister() = 0; virtual unsigned stackAlignmentInWords() = 0; virtual bool matchCall(void* returnAddress, void* target) = 0; virtual void updateCall(lir::UnaryOperation op, void* returnAddress, void* newTarget) = 0; virtual void setConstant(void* dst, uint64_t constant) = 0; virtual unsigned alignFrameSize(unsigned sizeInWords) = 0; virtual void nextFrame(void* start, unsigned size, unsigned footprint, void* link, bool mostRecent, int targetParameterFootprint, void** ip, void** stack) = 0; virtual void* frameIp(void* stack) = 0; virtual unsigned frameHeaderSize() = 0; virtual unsigned frameReturnAddressSize() = 0; virtual unsigned frameFooterSize() = 0; virtual int returnAddressOffset() = 0; virtual int framePointerOffset() = 0; virtual void plan (lir::UnaryOperation op, unsigned aSize, OperandMask& aMask, bool* thunk) = 0; virtual void planSource (lir::BinaryOperation op, unsigned aSize, OperandMask& aMask, unsigned bSize, bool* thunk) = 0; virtual void planDestination (lir::BinaryOperation op, unsigned aSize, const OperandMask& aMask, unsigned bSize, OperandMask& bMask) = 0; virtual void planMove (unsigned size, OperandMask& src, OperandMask& tmp, const OperandMask& dst) = 0; virtual void planSource (lir::TernaryOperation op, unsigned aSize, OperandMask& aMask, unsigned bSize, OperandMask& bMask, unsigned cSize, bool* thunk) = 0; virtual void planDestination (lir::TernaryOperation op, unsigned aSize, const OperandMask& aMask, unsigned bSize, const OperandMask& bMask, unsigned cSize, OperandMask& cMask) = 0; virtual Assembler* makeAssembler(util::Allocator*, vm::Zone*) = 0; virtual void acquire() = 0; virtual void release() = 0; }; } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ARCHITECTURE_H ReadyTalk-avian-1e1fff5/include/avian/codegen/assembler.h000066400000000000000000000060731231440243200234410ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_H #define AVIAN_CODEGEN_ASSEMBLER_H #include #include "avian/zone.h" #include #include namespace avian { namespace codegen { class Architecture; class OperandInfo { public: const unsigned size; const lir::OperandType type; lir::Operand* const operand; inline OperandInfo(unsigned size, lir::OperandType type, lir::Operand* operand): size(size), type(type), operand(operand) { } }; #ifdef AVIAN_TAILS const bool TailCalls = true; #else const bool TailCalls = false; #endif #if (defined AVIAN_USE_FRAME_POINTER) || (defined ARCH_powerpc) const bool UseFramePointer = true; #else const bool UseFramePointer = false; #endif class Assembler { public: class Client { public: virtual int acquireTemporary (uint32_t mask = ~static_cast(0)) = 0; virtual void releaseTemporary(int r) = 0; virtual void save(int r) = 0; }; class Block { public: virtual unsigned resolve(unsigned start, Block* next) = 0; }; virtual void setClient(Client* client) = 0; virtual Architecture* arch() = 0; virtual void checkStackOverflow(uintptr_t handler, unsigned stackLimitOffsetFromThread) = 0; virtual void saveFrame(unsigned stackOffset, unsigned ipOffset) = 0; virtual void pushFrame(unsigned argumentCount, ...) = 0; virtual void allocateFrame(unsigned footprint) = 0; virtual void adjustFrame(unsigned difference) = 0; virtual void popFrame(unsigned footprint) = 0; virtual void popFrameForTailCall(unsigned footprint, int offset, int returnAddressSurrogate, int framePointerSurrogate) = 0; virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, unsigned argumentFootprint) = 0; virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, unsigned stackOffsetFromThread) = 0; virtual void apply(lir::Operation op) = 0; virtual void apply(lir::UnaryOperation op, OperandInfo a) = 0; virtual void apply(lir::BinaryOperation op, OperandInfo a, OperandInfo b) = 0; virtual void apply(lir::TernaryOperation op, OperandInfo a, OperandInfo b, OperandInfo c) = 0; virtual void setDestination(uint8_t* dst) = 0; virtual void write() = 0; virtual Promise* offset(bool forTrace = false) = 0; virtual Block* endBlock(bool startNew) = 0; virtual void endEvent() = 0; virtual unsigned length() = 0; virtual unsigned footerSize() = 0; virtual void dispose() = 0; }; } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_H ReadyTalk-avian-1e1fff5/include/avian/codegen/compiler.h000066400000000000000000000127731231440243200233020ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_H #define AVIAN_CODEGEN_COMPILER_H #include #include "avian/zone.h" #include "assembler.h" namespace avian { namespace codegen { class TraceHandler { public: virtual void handleTrace(Promise* address, unsigned argumentIndex) = 0; }; class Compiler { public: class Client { public: virtual intptr_t getThunk(lir::UnaryOperation op, unsigned size) = 0; virtual intptr_t getThunk(lir::BinaryOperation op, unsigned size, unsigned resultSize) = 0; virtual intptr_t getThunk(lir::TernaryOperation op, unsigned size, unsigned resultSize, bool* threadParameter) = 0; }; static const unsigned Aligned = 1 << 0; static const unsigned NoReturn = 1 << 1; static const unsigned TailJump = 1 << 2; static const unsigned LongJumpOrCall = 1 << 3; enum OperandType { ObjectType, AddressType, IntegerType, FloatType, VoidType }; class Operand { }; class State { }; class Subroutine { }; virtual State* saveState() = 0; virtual void restoreState(State* state) = 0; virtual Subroutine* startSubroutine() = 0; virtual void returnFromSubroutine(Subroutine* subroutine, Operand* address) = 0; virtual void linkSubroutine(Subroutine* subroutine) = 0; virtual void init(unsigned logicalCodeSize, unsigned parameterFootprint, unsigned localFootprint, unsigned alignedFrameSize) = 0; virtual void visitLogicalIp(unsigned logicalIp) = 0; virtual void startLogicalIp(unsigned logicalIp) = 0; virtual Promise* machineIp(unsigned logicalIp) = 0; virtual Promise* poolAppend(intptr_t value) = 0; virtual Promise* poolAppendPromise(Promise* value) = 0; virtual Operand* constant(int64_t value, OperandType type) = 0; virtual Operand* promiseConstant(Promise* value, OperandType type) = 0; virtual Operand* address(Promise* address) = 0; virtual Operand* memory(Operand* base, OperandType type, int displacement = 0, Operand* index = 0, unsigned scale = 1) = 0; virtual Operand* register_(int number) = 0; virtual void push(unsigned footprint) = 0; virtual void push(unsigned footprint, Operand* value) = 0; virtual void save(unsigned footprint, Operand* value) = 0; virtual Operand* pop(unsigned footprint) = 0; virtual void pushed() = 0; virtual void popped(unsigned footprint) = 0; virtual unsigned topOfStack() = 0; virtual Operand* peek(unsigned footprint, unsigned index) = 0; virtual Operand* call(Operand* address, unsigned flags, TraceHandler* traceHandler, unsigned resultSize, OperandType resultType, unsigned argumentCount, ...) = 0; virtual Operand* stackCall(Operand* address, unsigned flags, TraceHandler* traceHandler, unsigned resultSize, OperandType resultType, unsigned argumentFootprint) = 0; virtual void return_(unsigned size, Operand* value) = 0; virtual void initLocal(unsigned size, unsigned index, OperandType type) = 0; virtual void initLocalsFromLogicalIp(unsigned logicalIp) = 0; virtual void storeLocal(unsigned footprint, Operand* src, unsigned index) = 0; virtual Operand* loadLocal(unsigned footprint, unsigned index) = 0; virtual void saveLocals() = 0; virtual void checkBounds(Operand* object, unsigned lengthOffset, Operand* index, intptr_t handler) = 0; virtual void store(unsigned srcSize, Operand* src, unsigned dstSize, Operand* dst) = 0; virtual Operand* load(unsigned srcSize, unsigned srcSelectSize, Operand* src, unsigned dstSize) = 0; virtual Operand* loadz(unsigned size, unsigned srcSelectSize, Operand* src, unsigned dstSize) = 0; virtual void condJump(lir::TernaryOperation type, unsigned size, Operand* a, Operand* b, Operand* address) = 0; virtual void jmp(Operand* address) = 0; virtual void exit(Operand* address) = 0; virtual Operand* binaryOp(lir::TernaryOperation type, unsigned size, Operand* a, Operand* b) = 0; virtual Operand* unaryOp(lir::BinaryOperation type, unsigned size, Operand* a) = 0; virtual void nullaryOp(lir::Operation type) = 0; virtual Operand* f2f(unsigned aSize, unsigned resSize, Operand* a) = 0; virtual Operand* f2i(unsigned aSize, unsigned resSize, Operand* a) = 0; virtual Operand* i2f(unsigned aSize, unsigned resSize, Operand* a) = 0; virtual void compile(uintptr_t stackOverflowHandler, unsigned stackLimitOffset) = 0; virtual unsigned resolve(uint8_t* dst) = 0; virtual unsigned poolSize() = 0; virtual void write() = 0; virtual void dispose() = 0; }; Compiler* makeCompiler(vm::System* system, Assembler* assembler, vm::Zone* zone, Compiler::Client* client); } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_H ReadyTalk-avian-1e1fff5/include/avian/codegen/lir-ops.inc.cpp000066400000000000000000000025261231440243200241530ustar00rootroot00000000000000LIR_OP_0(Return) LIR_OP_0(LoadBarrier) LIR_OP_0(StoreStoreBarrier) LIR_OP_0(StoreLoadBarrier) LIR_OP_0(Trap) LIR_OP_1(Call) LIR_OP_1(LongCall) LIR_OP_1(AlignedLongCall) LIR_OP_1(AlignedCall) LIR_OP_1(Jump) LIR_OP_1(LongJump) LIR_OP_1(AlignedLongJump) LIR_OP_1(AlignedJump) LIR_OP_2(Move) LIR_OP_2(MoveLow) LIR_OP_2(MoveHigh) LIR_OP_2(MoveZ) LIR_OP_2(Negate) LIR_OP_2(FloatNegate) LIR_OP_2(Float2Float) LIR_OP_2(Float2Int) LIR_OP_2(Int2Float) LIR_OP_2(FloatSquareRoot) LIR_OP_2(FloatAbsolute) LIR_OP_2(Absolute) LIR_OP_3(Add) LIR_OP_3(Subtract) LIR_OP_3(Multiply) LIR_OP_3(Divide) LIR_OP_3(Remainder) LIR_OP_3(ShiftLeft) LIR_OP_3(ShiftRight) LIR_OP_3(UnsignedShiftRight) LIR_OP_3(And) LIR_OP_3(Or) LIR_OP_3(Xor) LIR_OP_3(FloatAdd) LIR_OP_3(FloatSubtract) LIR_OP_3(FloatMultiply) LIR_OP_3(FloatDivide) LIR_OP_3(FloatRemainder) LIR_OP_3(FloatMax) LIR_OP_3(FloatMin) LIR_OP_3(JumpIfLess) LIR_OP_3(JumpIfGreater) LIR_OP_3(JumpIfLessOrEqual) LIR_OP_3(JumpIfGreaterOrEqual) LIR_OP_3(JumpIfEqual) LIR_OP_3(JumpIfNotEqual) LIR_OP_3(JumpIfFloatEqual) LIR_OP_3(JumpIfFloatNotEqual) LIR_OP_3(JumpIfFloatLess) LIR_OP_3(JumpIfFloatGreater) LIR_OP_3(JumpIfFloatLessOrEqual) LIR_OP_3(JumpIfFloatGreaterOrEqual) LIR_OP_3(JumpIfFloatLessOrUnordered) LIR_OP_3(JumpIfFloatGreaterOrUnordered) LIR_OP_3(JumpIfFloatLessOrEqualOrUnordered) LIR_OP_3(JumpIfFloatGreaterOrEqualOrUnordered) ReadyTalk-avian-1e1fff5/include/avian/codegen/lir.h000066400000000000000000000065731231440243200222570ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_LIR_H #define AVIAN_CODEGEN_LIR_H namespace avian { namespace codegen { class Promise; namespace lir { enum Operation { #define LIR_OP_0(x) x, #define LIR_OP_1(x) #define LIR_OP_2(x) #define LIR_OP_3(x) #include "lir-ops.inc.cpp" #undef LIR_OP_0 #undef LIR_OP_1 #undef LIR_OP_2 #undef LIR_OP_3 }; const unsigned OperationCount = Trap + 1; enum UnaryOperation { #define LIR_OP_0(x) #define LIR_OP_1(x) x, #define LIR_OP_2(x) #define LIR_OP_3(x) #include "lir-ops.inc.cpp" #undef LIR_OP_0 #undef LIR_OP_1 #undef LIR_OP_2 #undef LIR_OP_3 NoUnaryOperation = -1 }; const unsigned UnaryOperationCount = AlignedJump + 1; enum BinaryOperation { #define LIR_OP_0(x) #define LIR_OP_1(x) #define LIR_OP_2(x) x, #define LIR_OP_3(x) #include "lir-ops.inc.cpp" #undef LIR_OP_0 #undef LIR_OP_1 #undef LIR_OP_2 #undef LIR_OP_3 NoBinaryOperation = -1 }; const unsigned BinaryOperationCount = Absolute + 1; enum TernaryOperation { #define LIR_OP_0(x) #define LIR_OP_1(x) #define LIR_OP_2(x) #define LIR_OP_3(x) x, #include "lir-ops.inc.cpp" #undef LIR_OP_0 #undef LIR_OP_1 #undef LIR_OP_2 #undef LIR_OP_3 NoTernaryOperation = -1 }; const unsigned TernaryOperationCount = JumpIfFloatGreaterOrEqualOrUnordered + 1; const unsigned NonBranchTernaryOperationCount = FloatMin + 1; const unsigned BranchOperationCount = JumpIfFloatGreaterOrEqualOrUnordered - FloatMin; enum OperandType { ConstantOperand, AddressOperand, RegisterOperand, MemoryOperand }; enum ValueType { ValueGeneral, ValueFloat }; const unsigned OperandTypeCount = MemoryOperand + 1; const int NoRegister = -1; inline bool isBranch(lir::TernaryOperation op) { return op > FloatMin; } inline bool isFloatBranch(lir::TernaryOperation op) { return op > JumpIfNotEqual; } inline bool isGeneralBranch(lir::TernaryOperation op) { return isBranch(op) && !isFloatBranch(op); } inline bool isGeneralBinaryOp(lir::TernaryOperation op) { return op < FloatAdd; } inline bool isFloatBinaryOp(lir::TernaryOperation op) { return op >= FloatAdd && op <= FloatMin; } inline bool isGeneralUnaryOp(lir::BinaryOperation op) { return op == Negate || op == Absolute; } inline bool isFloatUnaryOp(lir::BinaryOperation op) { return op == FloatNegate || op == FloatSquareRoot || op == FloatAbsolute; } class Operand { }; class Constant: public Operand { public: Constant(Promise* value): value(value) { } Promise* value; }; class Address: public Operand { public: Address(Promise* address): address(address) { } Promise* address; }; class Register: public Operand { public: Register(int low, int high = NoRegister): low(low), high(high) { } int low; int high; }; class Memory: public Operand { public: Memory(int base, int offset, int index = NoRegister, unsigned scale = 1): base(base), offset(offset), index(index), scale(scale) { } int base; int offset; int index; unsigned scale; }; } // namespace lir } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_LIR_H ReadyTalk-avian-1e1fff5/include/avian/codegen/promise.h000066400000000000000000000062631231440243200231430ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_PROMISE_H #define AVIAN_CODEGEN_PROMISE_H #include #include #include namespace avian { namespace codegen { class Promise { public: class Listener { public: virtual bool resolve(int64_t value, void** location) = 0; Listener* next; }; virtual int64_t value() = 0; virtual bool resolved() = 0; virtual Listener* listen(unsigned) { return 0; } }; class ResolvedPromise: public Promise { public: ResolvedPromise(int64_t value): value_(value) { } virtual int64_t value() { return value_; } virtual bool resolved() { return true; } int64_t value_; }; class ShiftMaskPromise: public Promise { public: ShiftMaskPromise(Promise* base, unsigned shift, int64_t mask): base(base), shift(shift), mask(mask) { } virtual int64_t value() { return (base->value() >> shift) & mask; } virtual bool resolved() { return base->resolved(); } Promise* base; unsigned shift; int64_t mask; }; class CombinedPromise: public Promise { public: CombinedPromise(Promise* low, Promise* high): low(low), high(high) { } virtual int64_t value() { return low->value() | (high->value() << 32); } virtual bool resolved() { return low->resolved() and high->resolved(); } Promise* low; Promise* high; }; class OffsetPromise: public Promise { public: OffsetPromise(Promise* base, int64_t offset): base(base), offset(offset) { } virtual int64_t value() { return base->value() + offset; } virtual bool resolved() { return base->resolved(); } Promise* base; int64_t offset; }; class ListenPromise: public Promise { public: ListenPromise(vm::System* s, util::Allocator* allocator) : s(s), allocator(allocator), listener(0) { } virtual int64_t value() { abort(s); } virtual bool resolved() { return false; } virtual Listener* listen(unsigned sizeInBytes) { Listener* l = static_cast(allocator->allocate(sizeInBytes)); l->next = listener; listener = l; return l; } vm::System* s; util::Allocator* allocator; Listener* listener; Promise* promise; }; class DelayedPromise: public ListenPromise { public: DelayedPromise(vm::System* s, util::Allocator* allocator, Promise* basis, DelayedPromise* next) : ListenPromise(s, allocator), basis(basis), next(next) { } virtual int64_t value() { abort(s); } virtual bool resolved() { return false; } virtual Listener* listen(unsigned sizeInBytes) { Listener* l = static_cast(allocator->allocate(sizeInBytes)); l->next = listener; listener = l; return l; } Promise* basis; DelayedPromise* next; }; } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_PROMISE_HReadyTalk-avian-1e1fff5/include/avian/codegen/registers.h000066400000000000000000000030701231440243200234650ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_REGISTERS_H #define AVIAN_CODEGEN_REGISTERS_H #include "avian/common.h" namespace avian { namespace codegen { class RegisterMask { public: uint32_t mask; uint8_t start; uint8_t limit; static unsigned maskStart(uint32_t mask); static unsigned maskLimit(uint32_t mask); inline RegisterMask(uint32_t mask): mask(mask), start(maskStart(mask)), limit(maskLimit(mask)) { } }; class RegisterFile { public: RegisterMask allRegisters; RegisterMask generalRegisters; RegisterMask floatRegisters; inline RegisterFile(uint32_t generalRegisterMask, uint32_t floatRegisterMask): allRegisters(generalRegisterMask | floatRegisterMask), generalRegisters(generalRegisterMask), floatRegisters(floatRegisterMask) { } }; class RegisterIterator { public: int index; const RegisterMask& mask; inline RegisterIterator(const RegisterMask& mask): index(mask.start), mask(mask) {} inline bool hasNext() { return index < mask.limit; } inline int next() { int r = index; do { index++; } while(index < mask.limit && !(mask.mask & (1 << index))); return r; } }; } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_REGISTERS_HReadyTalk-avian-1e1fff5/include/avian/codegen/runtime.h000066400000000000000000000034501231440243200231430ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_RUNTIME_H #define AVIAN_CODEGEN_RUNTIME_H namespace avian { namespace codegen { namespace runtime { int64_t compareDoublesG(uint64_t bi, uint64_t ai); int64_t compareDoublesL(uint64_t bi, uint64_t ai); int64_t compareFloatsG(uint32_t bi, uint32_t ai); int64_t compareFloatsL(uint32_t bi, uint32_t ai); int64_t compareLongs(uint64_t b, uint64_t a); uint64_t addDouble(uint64_t b, uint64_t a); uint64_t subtractDouble(uint64_t b, uint64_t a); uint64_t multiplyDouble(uint64_t b, uint64_t a); uint64_t divideDouble(uint64_t b, uint64_t a); uint64_t moduloDouble(uint64_t b, uint64_t a); uint64_t negateDouble(uint64_t a); uint64_t squareRootDouble(uint64_t a); uint64_t doubleToFloat(int64_t a); int64_t doubleToInt(int64_t a); int64_t doubleToLong(int64_t a); uint64_t addFloat(uint32_t b, uint32_t a); uint64_t subtractFloat(uint32_t b, uint32_t a); uint64_t multiplyFloat(uint32_t b, uint32_t a); uint64_t divideFloat(uint32_t b, uint32_t a); uint64_t moduloFloat(uint32_t b, uint32_t a); uint64_t negateFloat(uint32_t a); uint64_t absoluteFloat(uint32_t a); int64_t absoluteLong(int64_t a); int64_t absoluteInt(int32_t a); uint64_t floatToDouble(int32_t a); int64_t floatToInt(int32_t a); int64_t floatToLong(int32_t a); uint64_t intToDouble(int32_t a); uint64_t intToFloat(int32_t a); uint64_t longToDouble(int64_t a); uint64_t longToFloat(int64_t a); } // namespace runtime } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_RUNTIME_H ReadyTalk-avian-1e1fff5/include/avian/codegen/targets.h000066400000000000000000000016201231440243200231260ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_TARGETS_H #define AVIAN_CODEGEN_TARGETS_H namespace vm { class System; } namespace avian { namespace codegen { class Architecture; Architecture* makeArchitectureNative(vm::System* system, bool useNativeFeatures); Architecture* makeArchitectureX86(vm::System* system, bool useNativeFeatures); Architecture* makeArchitectureArm(vm::System* system, bool useNativeFeatures); Architecture* makeArchitecturePowerpc(vm::System* system, bool useNativeFeatures); } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_TARGETS_H ReadyTalk-avian-1e1fff5/include/avian/heap/000077500000000000000000000000001231440243200206165ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/include/avian/heap/heap.h000066400000000000000000000050461231440243200217110ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef HEAP_H #define HEAP_H #include #include namespace vm { // an object must survive TenureThreshold + 2 garbage collections // before being copied to gen2 (must be at least 1): const unsigned TenureThreshold = 3; const unsigned FixieTenureThreshold = TenureThreshold + 2; class Heap : public avian::util::Allocator { public: enum CollectionType { MinorCollection, MajorCollection }; enum Status { Null, Reachable, Unreachable, Tenured }; class Visitor { public: virtual void visit(void*) = 0; }; class Walker { public: virtual bool visit(unsigned) = 0; }; class Client { public: virtual void collect(void* context, CollectionType type) = 0; virtual void visitRoots(Visitor*) = 0; virtual bool isFixed(void*) = 0; virtual unsigned sizeInWords(void*) = 0; virtual unsigned copiedSizeInWords(void*) = 0; virtual void copy(void*, void*) = 0; virtual void walk(void*, Walker*) = 0; }; virtual void setClient(Client* client) = 0; virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0; virtual unsigned remaining() = 0; virtual unsigned limit() = 0; virtual bool limitExceeded(int pendingAllocation = 0) = 0; virtual void collect(CollectionType type, unsigned footprint, int pendingAllocation) = 0; virtual unsigned fixedFootprint(unsigned sizeInWords, bool objectMask) = 0; virtual void* allocateFixed(avian::util::Allocator* allocator, unsigned sizeInWords, bool objectMask) = 0; virtual void* allocateImmortalFixed(avian::util::Allocator* allocator, unsigned sizeInWords, bool objectMask) = 0; virtual void mark(void* p, unsigned offset, unsigned count) = 0; virtual void pad(void* p) = 0; virtual void* follow(void* p) = 0; virtual void postVisit() = 0; virtual Status status(void* p) = 0; virtual CollectionType collectionType() = 0; virtual void disposeFixies() = 0; virtual void dispose() = 0; }; Heap* makeHeap(System* system, unsigned limit); } // namespace vm #endif//HEAP_H ReadyTalk-avian-1e1fff5/include/avian/system/000077500000000000000000000000001231440243200212255ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/include/avian/system/signal.h000066400000000000000000000050201231440243200226500ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_SYSTEM_SIGNAL_H #define AVIAN_SYSTEM_SIGNAL_H #include namespace avian { namespace system { // Crash the process. // On posix, the just calls abort. On windows, we dereference a null pointer in // order to trigger the crash dump logic. NO_RETURN void crash(); // Registrar for unix-like "signals" (implemented with structured exceptions on windows). // TODO: remove dependence on generated code having a well-known "thread" // register. Use a thread-local variable instead. class SignalRegistrar { public: class Handler { public: // This function receives state information about the paused thread. // Returns whether to resume execution after the failure point. virtual bool handleSignal(void** ip, void** frame, void** stack, void** thread) = 0; }; enum Signal { // "Segmentation fault" exceptions (mostly null pointer dereference, but // generally access to any non-mapped memory) SegFault, DivideByZero, }; SignalRegistrar(); ~SignalRegistrar(); // Register a handler for the given signal. // After this method call, anytime the given signal is raised, it will be // handled by the given handler. // Returns true upon success, false upon failure bool registerHandler(Signal signal, Handler* handler); // Unregister a handler for the given signal. // After this method call, the given signal will no longer be handled (or, // rather, it go back to being handled by whatever was registered to handle it // before us). // Returns true upon success, false upon failure bool unregisterHandler(Signal signal); // Set the directory that a crash dump will be written to should an unhandled // exception be thrown. // Note: this only currently does anything on windows. // TODO: move this out of this class, into a separate "CrashDumper" class or // somesuch. void setCrashDumpDirectory(const char* crashDumpDirectory); // This is internal, implementation-specific data. It's declared in the // specific implementation. struct Data; private: Data* data; }; } // namespace system } // namespace avian #endif ReadyTalk-avian-1e1fff5/include/avian/system/system.h000066400000000000000000000106351231440243200227270ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef SYSTEM_H #define SYSTEM_H #include "avian/common.h" #include #include namespace vm { class System : public avian::util::Aborter { public: typedef intptr_t Status; enum FileType { TypeUnknown, TypeDoesNotExist, TypeFile, TypeDirectory }; class Thread { public: virtual void interrupt() = 0; virtual bool getAndClearInterrupted() = 0; virtual void join() = 0; virtual void dispose() = 0; }; class ThreadVisitor { public: virtual void visit(void* ip, void* stack, void* link) = 0; }; class Runnable { public: virtual void attach(Thread*) = 0; virtual void run() = 0; virtual bool interrupted() = 0; virtual void setInterrupted(bool v) = 0; }; class Mutex { public: virtual void acquire() = 0; virtual void release() = 0; virtual void dispose() = 0; }; class Monitor { public: virtual bool tryAcquire(Thread* context) = 0; virtual void acquire(Thread* context) = 0; virtual void release(Thread* context) = 0; virtual void wait(Thread* context, int64_t time) = 0; virtual bool waitAndClearInterrupted(Thread* context, int64_t time) = 0; virtual void notify(Thread* context) = 0; virtual void notifyAll(Thread* context) = 0; virtual Thread* owner() = 0; virtual void dispose() = 0; }; class Local { public: virtual void* get() = 0; virtual void set(void* p) = 0; virtual void dispose() = 0; }; class Region { public: virtual const uint8_t* start() = 0; virtual size_t length() = 0; virtual void dispose() = 0; }; class Directory { public: virtual const char* next() = 0; virtual void dispose() = 0; }; class Library { public: virtual void* resolve(const char* symbol) = 0; virtual const char* name() = 0; virtual Library* next() = 0; virtual void setNext(Library* lib) = 0; virtual void disposeAll() = 0; }; class MonitorResource { public: MonitorResource(System::Thread* t, System::Monitor* m): t(t), m(m) { m->acquire(t); } ~MonitorResource() { m->release(t); } private: System::Thread* t; System::Monitor* m; }; virtual bool success(Status) = 0; virtual void* tryAllocate(unsigned sizeInBytes) = 0; virtual void free(const void* p) = 0; #if !defined(AVIAN_AOT_ONLY) virtual void* tryAllocateExecutable(unsigned sizeInBytes) = 0; virtual void freeExecutable(const void* p, unsigned sizeInBytes) = 0; #endif virtual Status attach(Runnable*) = 0; virtual Status start(Runnable*) = 0; virtual Status make(Mutex**) = 0; virtual Status make(Monitor**) = 0; virtual Status make(Local**) = 0; virtual Status visit(Thread* thread, Thread* target, ThreadVisitor* visitor) = 0; virtual Status map(Region**, const char* name) = 0; virtual FileType stat(const char* name, unsigned* length) = 0; virtual Status open(Directory**, const char* name) = 0; virtual const char* libraryPrefix() = 0; virtual const char* librarySuffix() = 0; virtual Status load(Library**, const char* name) = 0; virtual char pathSeparator() = 0; virtual char fileSeparator() = 0; virtual const char* toAbsolutePath(avian::util::Allocator* allocator, const char* name) = 0; virtual int64_t now() = 0; virtual void yield() = 0; virtual void exit(int code) = 0; virtual void dispose() = 0; }; inline void* allocate(System* s, unsigned size) { void* p = s->tryAllocate(size); if (p == 0) s->abort(); return p; } #define ACQUIRE_MONITOR(t, m) \ System::MonitorResource MAKE_NAME(monitorResource_) (t, m) inline avian::util::Aborter* getAborter(System* s) { return s; } inline void NO_RETURN sysAbort(System* s) { abort(s); } // #ifdef NDEBUG // # define assert(a, b) // # define vm_assert(a, b) // #else // not NDEBUG // inline void // assert(System* s, bool v) // { // expect(s, v); // } // # define vm_assert(a, b) vm::assert(a, b) // #endif // not NDEBUG AVIAN_EXPORT System* makeSystem(); } // namespace vm #endif//SYSTEM_H ReadyTalk-avian-1e1fff5/include/avian/tools/000077500000000000000000000000001231440243200210415ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/include/avian/tools/object-writer/000077500000000000000000000000001231440243200236215ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/include/avian/tools/object-writer/tools.h000066400000000000000000000066441231440243200251440ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_TOOLS_H_ #define AVIAN_TOOLS_H_ #include #include #include #include "avian/environment.h" namespace avian { namespace tools { class OutputStream { public: virtual void writeChunk(const void* data, size_t size) = 0; virtual void write(uint8_t byte); virtual void writeRepeat(uint8_t byte, size_t size); }; class FileOutputStream : public OutputStream { private: FILE* file; public: FileOutputStream(const char* name); ~FileOutputStream(); bool isValid(); virtual void writeChunk(const void* data, size_t size); virtual void write(uint8_t byte); }; class SymbolInfo { public: unsigned addr; util::String name; inline SymbolInfo(uint64_t addr, const util::String& name): addr(addr), name(name) {} inline SymbolInfo(): name("") {} }; class Buffer { public: size_t capacity; size_t length; uint8_t* data; Buffer(); ~Buffer(); void ensure(size_t more); void write(const void* d, size_t size); }; class StringTable : public Buffer { public: unsigned add(util::String str); }; template class DynamicArray : public util::Slice { public: size_t capacity; DynamicArray() : util::Slice((T*)malloc(10 * sizeof(T)), 0), capacity(10) { } ~DynamicArray() { free(util::Slice::items); } void ensure(size_t more) { if (util::Slice::count + more > capacity) { capacity = capacity * 2 + more; util::Slice::items = (T*)realloc(util::Slice::items, capacity * sizeof(T)); } } void add(const T& item) { ensure(1); util::Slice::items[util::Slice::count++] = item; } }; class PlatformInfo { public: enum Format { Elf = AVIAN_FORMAT_ELF, Pe = AVIAN_FORMAT_PE, MachO = AVIAN_FORMAT_MACHO, UnknownFormat = AVIAN_FORMAT_UNKNOWN }; enum Architecture { x86 = AVIAN_ARCH_X86, x86_64 = AVIAN_ARCH_X86_64, PowerPC = AVIAN_ARCH_POWERPC, Arm = AVIAN_ARCH_ARM, UnknownArch = AVIAN_ARCH_UNKNOWN }; const Format format; const Architecture arch; static Format formatFromString(const char* format); static Architecture archFromString(const char* arch); inline PlatformInfo(Format format, Architecture arch): format(format), arch(arch) {} inline bool operator == (const PlatformInfo& other) { return format == other.format && arch == other.arch; } inline bool isLittleEndian() { return arch != PowerPC; } }; class Platform { private: Platform* next; static Platform* first; public: PlatformInfo info; inline Platform(PlatformInfo info): next(first), info(info) { first = this; } enum AccessFlags { Writable = 1 << 0, Executable = 1 << 1 }; virtual bool writeObject(OutputStream* out, util::Slice symbols, util::Slice data, unsigned accessFlags, unsigned alignment) = 0; static Platform* getPlatform(PlatformInfo info); }; } // namespace tools } // namespace avian #endif ReadyTalk-avian-1e1fff5/include/avian/util/000077500000000000000000000000001231440243200206565ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/include/avian/util/abort.h000066400000000000000000000020511231440243200221340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_UTIL_ABORT_H #define AVIAN_UTIL_ABORT_H // TODO: remove reference back into the source directory! // Note: this is needed for UNLIKELY #include namespace avian { namespace util { class Aborter { public: virtual void NO_RETURN abort() = 0; }; inline Aborter* getAborter(Aborter* a) { return a; } template inline void NO_RETURN abort(T t) { getAborter(t)->abort(); ::abort(); } template inline void expect(T t, bool v) { if(UNLIKELY(!v)) { abort(t); } } #ifdef NDEBUG #define assert(t, v) #else template inline void assert(T t, bool v) { expect(t, v); } #endif } // namespace util } // namespace avian #endif // AVIAN_UTIL_ABORT_H ReadyTalk-avian-1e1fff5/include/avian/util/allocator.h000066400000000000000000000015651231440243200230160ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_UTIL_ALLOCATOR_H #define AVIAN_UTIL_ALLOCATOR_H #include namespace avian { namespace util { class Allocator { public: // TODO: use size_t instead of unsigned virtual void* tryAllocate(unsigned size) = 0; virtual void* allocate(unsigned size) = 0; virtual void free(const void* p, unsigned size) = 0; }; } // namespace util } // namespace avian inline void* operator new(size_t size, avian::util::Allocator* allocator) { return allocator->allocate(size); } #endif // AVIAN_UTIL_ALLOCATOR_H ReadyTalk-avian-1e1fff5/include/avian/util/arg-parser.h000066400000000000000000000015721231440243200230770ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_UTIL_ARG_PARSER_H #define AVIAN_UTIL_ARG_PARSER_H namespace avian { namespace util { class Arg; class ArgParser { public: Arg* first; Arg** last; ArgParser(); bool parse(int ac, const char* const* av); void printUsage(const char* exe); }; class Arg { public: Arg* next; bool required; const char* name; const char* desc; const char* value; Arg(ArgParser& parser, bool required, const char* name, const char* desc); }; } // namespace avian } // namespace util #endif // AVIAN_UTIL_ARG_PARSER_HReadyTalk-avian-1e1fff5/include/avian/util/fixed-allocator.h000066400000000000000000000020461231440243200241060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_UTIL_FIXED_ALLOCATOR_H #define AVIAN_UTIL_FIXED_ALLOCATOR_H #include "allocator.h" #include "abort.h" #include "slice.h" namespace avian { namespace util { // An Allocator that allocates, bump-pointer style, out of a pre-defined chunk // of memory. class FixedAllocator : public Allocator { public: FixedAllocator(Aborter* a, Slice memory); virtual void* tryAllocate(unsigned size); void* allocate(unsigned size, unsigned padAlignment); virtual void* allocate(unsigned size); virtual void free(const void* p, unsigned size); Aborter* a; Slice memory; size_t offset; }; } // namespace util } // namespace avian #endif // AVIAN_UTIL_FIXED_ALLOCATOR_H ReadyTalk-avian-1e1fff5/include/avian/util/list.h000066400000000000000000000014751231440243200220110ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_UTIL_LIST_H #define AVIAN_UTIL_LIST_H #include "allocator.h" namespace avian { namespace util { template class List { public: List(const T& item, List* next): item(item), next(next) {} unsigned count() { unsigned count = 0; List* c = this; while (c) { ++ count; c = c->next; } return count; } T item; List* next; }; } // namespace util } // namespace avian #endif // AVIAN_UTIL_LIST_H ReadyTalk-avian-1e1fff5/include/avian/util/math.h000066400000000000000000000022101231440243200217530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_UTIL_MATH_H #define AVIAN_UTIL_MATH_H #undef max #undef min namespace avian { namespace util { inline unsigned max(unsigned a, unsigned b) { return (a > b ? a : b); } inline unsigned min(unsigned a, unsigned b) { return (a < b ? a : b); } inline unsigned avg(unsigned a, unsigned b) { return (a + b) / 2; } inline unsigned ceilingDivide(unsigned n, unsigned d) { return (n + d - 1) / d; } inline bool powerOfTwo(unsigned n) { for (; n > 2; n >>= 1) if (n & 1) return false; return true; } inline unsigned nextPowerOfTwo(unsigned n) { unsigned r = 1; while (r < n) r <<= 1; return r; } inline unsigned log(unsigned n) { unsigned r = 0; for (unsigned i = 1; i < n; ++r) i <<= 1; return r; } } // namespace util } // namespace avian #endif // AVIAN_UTIL_MATH_H ReadyTalk-avian-1e1fff5/include/avian/util/runtime-array.h000066400000000000000000000016471231440243200236360ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_UTIL_RUNTIME_ARRAY_H #define AVIAN_UTIL_RUNTIME_ARRAY_H #ifdef _MSC_VER template class RuntimeArray { public: RuntimeArray(unsigned size): body(static_cast(malloc(size * sizeof(T)))) { } ~RuntimeArray() { free(body); } T* body; }; # define RUNTIME_ARRAY(type, name, size) RuntimeArray name(size); # define RUNTIME_ARRAY_BODY(name) name.body #else // not _MSC_VER # define RUNTIME_ARRAY(type, name, size) type name##_body[size]; # define RUNTIME_ARRAY_BODY(name) name##_body #endif #endif // AVIAN_UTIL_RUNTIME_ARRAY_H ReadyTalk-avian-1e1fff5/include/avian/util/slice.h000066400000000000000000000027211231440243200221300ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_UTIL_SLICE_H #define AVIAN_UTIL_SLICE_H #include "allocator.h" #include "math.h" namespace avian { namespace util { template class Slice { public: T* items; size_t count; inline Slice(T* items, size_t count) : items(items), count(count) { } inline Slice(const Slice& copy) : items(copy.items), count(copy.count) { } inline T& operator[](size_t index) { return items[index]; } inline T* begin() { return items; } inline T* end() { return items + count; } static Slice alloc(Allocator* a, size_t count) { return Slice((T*)a->allocate(sizeof(T) * count), count); } Slice clone(Allocator* a) { Slice ret((T*)a->allocate(count * sizeof(T)), count); memcpy(ret.items, items, count * sizeof(T)); return ret; } void resize(Allocator* a, size_t newCount) { T* newItems = (T*)a->allocate(newCount * sizeof(T)); memcpy(newItems, items, min(count, newCount)); a->free(items, count); items = newItems; count = newCount; } }; } // namespace util } // namespace avian #endif // AVIAN_UTIL_SLICE_H ReadyTalk-avian-1e1fff5/include/avian/util/stream.h000066400000000000000000000040601231440243200223220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef STREAM_H #define STREAM_H #include "avian/common.h" namespace vm { class AbstractStream { public: class Client { public: virtual void handleError() = 0; }; AbstractStream(Client* client, unsigned size): client(client), size(size), position_(0) { } unsigned position() { return position_; } void setPosition(unsigned p) { position_ = p; } void skip(unsigned size) { if (size > this->size - position_) { client->handleError(); } else { position_ += size; } } void read(uint8_t* dst, unsigned size) { if (size > this->size - position_) { memset(dst, 0, size); client->handleError(); } else { copy(dst, position_, size); position_ += size; } } uint8_t read1() { uint8_t v; read(&v, 1); return v; } uint16_t read2() { uint16_t a = read1(); uint16_t b = read1(); return (a << 8) | b; } uint32_t read4() { uint32_t a = read2(); uint32_t b = read2(); return (a << 16) | b; } uint64_t read8() { uint64_t a = read4(); uint64_t b = read4(); return (a << 32) | b; } uint32_t readFloat() { return read4(); } uint64_t readDouble() { return read8(); } protected: virtual void copy(uint8_t* dst, unsigned offset, unsigned size) = 0; private: Client* client; unsigned size; unsigned position_; }; class Stream: public AbstractStream { public: Stream(Client* client, const uint8_t* data, unsigned size): AbstractStream(client, size), data(data) { } private: virtual void copy(uint8_t* dst, unsigned offset, unsigned size) { memcpy(dst, data + offset, size); } const uint8_t* data; }; } // namespace vm #endif//STREAM_H ReadyTalk-avian-1e1fff5/include/avian/util/string.h000066400000000000000000000024201231440243200223330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_UTIL_STRING_H #define AVIAN_UTIL_STRING_H #include namespace avian { namespace util { class String { public: const char* text; size_t length; String(const char* text): text(text), length(strlen(text)) {} inline String(const char* text, size_t length): text(text), length(length) {} }; class Tokenizer { public: Tokenizer(const char* s, char delimiter): s(s), limit(0), delimiter(delimiter) { } Tokenizer(String str, char delimiter): s(str.text), limit(str.text + str.length), delimiter(delimiter) { } bool hasMore() { while (s != limit and *s == delimiter) ++s; return s != limit and *s != 0; } String next() { const char* p = s; while (s != limit and *s and *s != delimiter) ++s; return String(p, s - p); } const char* s; const char* limit; char delimiter; }; } // namespace util } // namespace avain #endif//AVIAN_UTIL_STRING_H ReadyTalk-avian-1e1fff5/license.txt000066400000000000000000000013471231440243200173500ustar00rootroot00000000000000Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ReadyTalk-avian-1e1fff5/makefile000077500000000000000000001712201231440243200166660ustar00rootroot00000000000000MAKEFLAGS = -s name = avian version = 0.7 build-arch := $(shell uname -m \ | sed 's/^i.86$$/i386/' \ | sed 's/^x86pc$$/i386/' \ | sed 's/amd64/x86_64/' \ | sed 's/^arm.*$$/arm/' \ | sed 's/ppc/powerpc/') ifeq (Power,$(filter Power,$(build-arch))) build-arch = powerpc endif build-platform := \ $(shell uname -s | tr [:upper:] [:lower:] \ | sed 's/^mingw32.*$$/mingw32/' \ | sed 's/^cygwin.*$$/cygwin/') arch = $(build-arch) target-arch = $(arch) bootimage-platform = \ $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform))) platform = $(bootimage-platform) codegen-targets = native mode = fast process = compile ifneq ($(process),compile) options := -$(process) endif ifneq ($(mode),fast) options := $(options)-$(mode) endif ifneq ($(lzma),) options := $(options)-lzma endif ifeq ($(bootimage),true) options := $(options)-bootimage endif ifeq ($(heapdump),true) options := $(options)-heapdump endif ifeq ($(tails),true) options := $(options)-tails endif ifeq ($(continuations),true) options := $(options)-continuations endif ifeq ($(codegen-targets),all) options := $(options)-all endif aot-only = false root := $(shell (cd .. && pwd)) build = build/$(platform)-$(arch)$(options) host-build-root = $(build)/host classpath-build = $(build)/classpath test-build = $(build)/test src = src classpath-src = classpath test = test unittest = unittest win32 ?= $(root)/win32 win64 ?= $(root)/win64 winrt ?= $(root)/winrt wp8 ?= $(root)/wp8 classpath = avian test-executable = $(shell pwd)/$(executable) boot-classpath = $(classpath-build) embed-prefix = /avian-embedded native-path = echo ifeq ($(build-platform),cygwin) native-path = cygpath -m endif windows-path = echo path-separator = : ifneq (,$(filter mingw32 cygwin,$(build-platform))) path-separator = ; endif target-path-separator = : ifeq ($(platform),windows) target-path-separator = ; endif library-path-variable = LD_LIBRARY_PATH ifeq ($(build-platform),darwin) library-path-variable = DYLD_LIBRARY_PATH endif library-path = $(library-path-variable)=$(build) ifneq ($(openjdk),) openjdk-arch = $(arch) ifeq ($(arch),x86_64) openjdk-arch = amd64 endif ifneq ($(openjdk-src),) include openjdk-src.mk options := $(options)-openjdk-src classpath-objects = $(openjdk-objects) $(openjdk-local-objects) classpath-cflags = -DAVIAN_OPENJDK_SRC -DBOOT_JAVAHOME openjdk-jar-dep = $(build)/openjdk-jar.dep classpath-jar-dep = $(openjdk-jar-dep) javahome = $(embed-prefix)/javahomeJar javahome-files = lib/zi lib/currency.data lib/security/java.security \ lib/security/java.policy lib/security/cacerts local-policy = lib/security/local_policy.jar ifeq ($(shell test -e "$(openjdk)/jre/$(local-policy)" && echo found),found) javahome-files += $(local-policy) endif export-policy = lib/security/US_export_policy.jar ifeq ($(shell test -e "$(openjdk)/jre/$(export-policy)" && echo found),found) javahome-files += $(export-policy) endif ifeq ($(platform),windows) javahome-files += lib/tzmappings endif javahome-object = $(build)/javahome-jar.o boot-javahome-object = $(build)/boot-javahome.o stub-sources = $(src)/openjdk/stubs.cpp stub-objects = $(call cpp-objects,$(stub-sources),$(src),$(build)) else options := $(options)-openjdk test-executable = $(shell pwd)/$(executable-dynamic) ifeq ($(build-platform),darwin) library-path = \ $(library-path-variable)=$(build):$(openjdk)/jre/lib else library-path = \ $(library-path-variable)=$(build):$(openjdk)/jre/lib/$(openjdk-arch) endif javahome = "$$($(native-path) "$(openjdk)/jre")" endif classpath = openjdk boot-classpath := "$(boot-classpath)$(path-separator)$$($(native-path) "$(openjdk)/jre/lib/rt.jar")" build-javahome = $(openjdk)/jre endif ifneq ($(android),) options := $(options)-android classpath-jar-dep = $(build)/android.dep luni-native = $(android)/libcore/luni/src/main/native classpath-cflags = -DBOOT_JAVAHOME android-cflags := -I$(luni-native) \ -I$(android)/libnativehelper/include/nativehelper \ -I$(android)/system/core/include \ -I$(android)/external/zlib \ -I$(android)/external/icu4c/i18n \ -I$(android)/external/icu4c/common \ -I$(android)/external/expat \ -I$(android)/external/openssl/include \ -I$(android)/libcore/include \ -I$(build)/android-src/external/fdlibm \ -I$(build)/android-src \ -fno-exceptions \ -D_FILE_OFFSET_BITS=64 \ -DOS_SHARED_LIB_FORMAT_STR="\"$(so-prefix)%s$(so-suffix)\"" \ -DJNI_JARJAR_PREFIX= \ -D__DARWIN_UNIX03=1 \ -D__PROVIDE_FIXMES \ -g3 \ -Werror luni-cpps := $(shell find $(luni-native) -name '*.cpp') libnativehelper-native := $(android)/libnativehelper libnativehelper-cpps := $(libnativehelper-native)/JniConstants.cpp \ $(libnativehelper-native)/toStringArray.cpp crypto-native := $(android)/libcore/crypto/src/main/native ifeq ($(platform),windows) crypto-cpps := $(crypto-native)/org_conscrypt_NativeCrypto.cpp android-cflags += -D__STDC_CONSTANT_MACROS blacklist = $(luni-native)/java_io_Console.cpp \ $(luni-native)/java_lang_ProcessManager.cpp \ $(luni-native)/libcore_net_RawSocket.cpp \ $(luni-native)/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp \ luni-cpps := $(filter-out $(blacklist),$(luni-cpps)) icu-libs := $(android)/external/icu4c/lib/sicuin.a \ $(android)/external/icu4c/lib/sicuuc.a \ $(android)/external/icu4c/lib/sicudt.a platform-lflags := -lgdi32 else crypto-cpps := $(crypto-native)/org_conscrypt_NativeCrypto.cpp android-cflags += -fPIC -DHAVE_SYS_UIO_H icu-libs := $(android)/external/icu4c/lib/libicui18n.a \ $(android)/external/icu4c/lib/libicuuc.a \ $(android)/external/icu4c/lib/libicudata.a endif classpath-lflags := \ $(icu-libs) \ $(android)/external/fdlibm/libfdm.a \ $(android)/external/expat/.libs/libexpat.a \ $(android)/openssl-upstream/libssl.a \ $(android)/openssl-upstream/libcrypto.a \ $(platform-lflags) \ -lstdc++ ifeq ($(platform),linux) classpath-lflags += -lrt endif classpath-objects = \ $(call cpp-objects,$(luni-cpps),$(luni-native),$(build)) \ $(call cpp-objects,$(crypto-cpps),$(crypto-native),$(build)) \ $(call cpp-objects,$(libnativehelper-cpps),$(libnativehelper-native),$(build)) luni-java = $(android)/libcore/luni/src/main/java luni-javas := $(shell find $(luni-java) -name '*.java') libdvm-java = $(android)/libcore/libdvm/src/main/java libdvm-javas := $(shell find $(libdvm-java) -name '*.java') crypto-java = $(android)/libcore/crypto/src/main/java crypto-javas := $(shell find $(crypto-java) -name '*.java') dalvik-java = $(android)/libcore/dalvik/src/main/java dalvik-javas := $(shell find $(dalvik-java) -name '*.java') xml-java = $(android)/libcore/xml/src/main/java xml-javas := $(shell find $(xml-java) -name '*.java') android-classes = \ $(call java-classes,$(luni-javas),$(luni-java),$(build)/android) \ $(call java-classes,$(libdvm-javas),$(libdvm-java),$(build)/android) \ $(call java-classes,$(crypto-javas),$(crypto-java),$(build)/android) \ $(call java-classes,$(dalvik-javas),$(dalvik-java),$(build)/android) \ $(call java-classes,$(xml-javas),$(xml-java),$(build)/android) classpath = android javahome-files = tzdata javahome-object = $(build)/javahome-jar.o boot-javahome-object = $(build)/boot-javahome.o build-javahome = $(android)/bionic/libc/zoneinfo stub-sources = $(src)/android/stubs.cpp stub-objects = $(call cpp-objects,$(stub-sources),$(src),$(build)) endif ifeq ($(classpath),avian) jni-sources := $(shell find $(classpath-src) -name '*.cpp') jni-objects = $(call cpp-objects,$(jni-sources),$(classpath-src),$(build)) classpath-objects = $(jni-objects) endif input = List ifeq ($(use-clang),true) build-cxx = clang++ -std=c++11 build-cc = clang else build-cxx = g++ build-cc = gcc endif mflag = ifneq ($(platform),darwin) ifeq ($(arch),i386) mflag = -m32 endif ifeq ($(arch),x86_64) mflag = -m64 endif endif target-format = elf cxx = $(build-cxx) $(mflag) cc = $(build-cc) $(mflag) ar = ar ranlib = ranlib dlltool = dlltool vg = nice valgrind --num-callers=32 --db-attach=yes --freelist-vol=100000000 vg += --leak-check=full --suppressions=valgrind.supp db = gdb --args javac = "$(JAVA_HOME)/bin/javac" -encoding UTF-8 javah = "$(JAVA_HOME)/bin/javah" jar = "$(JAVA_HOME)/bin/jar" strip = strip strip-all = --strip-all rdynamic = -rdynamic cflags_debug = -O0 -g3 cflags_debug_fast = -O0 -g3 cflags_stress = -O0 -g3 cflags_stress_major = -O0 -g3 ifeq ($(use-clang),true) cflags_fast = -O3 -g3 cflags_small = -Oz -g3 else cflags_fast = -O3 -g3 cflags_small = -Os -g3 endif # note that we suppress the non-virtual-dtor warning because we never # use the delete operator, which means we don't need virtual # destructors: warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ -Wno-non-virtual-dtor target-cflags = -DTARGET_BYTES_PER_WORD=$(pointer-size) common-cflags = $(warnings) -fno-rtti -fno-exceptions -I$(classpath-src) \ "-I$(JAVA_HOME)/include" -I$(src) -I$(build) -Iinclude $(classpath-cflags) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ -DAVIAN_INFO="\"$(info)\"" \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" $(target-cflags) asmflags = $(target-cflags) -I$(src) ifneq (,$(filter i386 x86_64,$(arch))) ifeq ($(use-frame-pointer),true) common-cflags += -fno-omit-frame-pointer -DAVIAN_USE_FRAME_POINTER asmflags += -DAVIAN_USE_FRAME_POINTER endif endif build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread converter-cflags = -D__STDC_CONSTANT_MACROS -Iinclude/ -Isrc/ \ -fno-rtti -fno-exceptions \ -DAVIAN_TARGET_ARCH=AVIAN_ARCH_UNKNOWN \ -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_UNKNOWN \ -Wall -Wextra -Werror -Wunused-parameter -Winit-self -Wno-non-virtual-dtor cflags = $(build-cflags) common-lflags = -lm -lz ifeq ($(use-clang),true) ifeq ($(build-platform),darwin) common-lflags += -Wl,-export_dynamic else ifneq ($(platform),windows) common-lflags += -Wl,-E else common-lflags += -Wl,--export-all-symbols endif endif endif build-lflags = -lz -lpthread -ldl lflags = $(common-lflags) -lpthread -ldl soname-flag = -Wl,-soname -Wl,$(so-prefix)jvm$(so-suffix) version-script-flag = -Wl,--version-script=openjdk.ld build-system = posix system = posix asm = x86 pointer-size = 8 so-prefix = lib so-suffix = .so static-prefix = lib static-suffix = .a output = -o $(1) asm-output = -o $(1) asm-input = -c $(1) asm-format = S as = $(cc) ld = $(cc) build-ld = $(build-cc) default-remote-test-host = localhost default-remote-test-port = 22 ifeq ($(remote-test-host),) remote-test-host = $(default-remote-test-host) else remote-test = true endif ifeq ($(remote-test-port),) remote-test-port = $(default-remote-test-port) else remote-test = true endif remote-test-user = ${USER} remote-test-dir = /tmp/avian-test-${USER} static = -static shared = -shared rpath = -Wl,-rpath=\$$ORIGIN -Wl,-z,origin no-error = -Wno-error openjdk-extra-cflags = -fvisibility=hidden bootimage-cflags = -DTARGET_BYTES_PER_WORD=$(pointer-size) bootimage-symbols = _binary_bootimage_bin_start:_binary_bootimage_bin_end codeimage-symbols = _binary_codeimage_bin_start:_binary_codeimage_bin_end developer-dir := $(shell if test -d /Developer/Platforms/$(target).platform/Developer/SDKs; then echo /Developer; \ else echo /Applications/Xcode.app/Contents/Developer; fi) ifeq ($(build-arch),powerpc) ifneq ($(arch),$(build-arch)) bootimage-cflags += -DTARGET_OPPOSITE_ENDIAN endif endif ifeq ($(arch),i386) pointer-size = 4 endif ifeq ($(arch),powerpc) asm = powerpc pointer-size = 4 ifneq ($(arch),$(build-arch)) bootimage-cflags += -DTARGET_OPPOSITE_ENDIAN endif ifneq ($(platform),darwin) ifneq ($(arch),$(build-arch)) cxx = powerpc-linux-gnu-g++ cc = powerpc-linux-gnu-gcc ar = powerpc-linux-gnu-ar ranlib = powerpc-linux-gnu-ranlib strip = powerpc-linux-gnu-strip endif endif endif ifeq ($(arch),arm) asm = arm pointer-size = 4 ifeq ($(build-platform),darwin) ios = true else no-psabi = -Wno-psabi cflags += -marm $(no-psabi) endif ifneq ($(arch),$(build-arch)) ifneq ($(platform),darwin) cxx = arm-linux-gnueabi-g++ cc = arm-linux-gnueabi-gcc ar = arm-linux-gnueabi-ar ranlib = arm-linux-gnueabi-ranlib strip = arm-linux-gnueabi-strip endif endif endif ifeq ($(armv6),true) cflags += -DAVIAN_ASSUME_ARMV6 endif ifeq ($(ios),true) cflags += -DAVIAN_IOS use-lto = false endif ifeq ($(build-platform),darwin) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) cflags += -Wno-deprecated-declarations build-lflags += -framework CoreFoundation endif ifeq ($(platform),darwin) soname-flag = endif ifeq ($(platform),qnx) cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) lflags = $(common-lflags) -lsocket ifeq ($(build-platform),qnx) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) build-lflags = $(common-lflags) else ifeq ($(arch),i386) prefix = i486-pc-nto-qnx6.5.0- else prefix = arm-unknown-nto-qnx6.5.0- endif endif cxx = $(prefix)g++ cc = $(prefix)gcc ar = $(prefix)ar ranlib = $(prefix)ranlib strip = $(prefix)strip rdynamic = -Wl,--export-dynamic endif ifeq ($(platform),freebsd) # There is no -ldl on FreeBSD build-lflags = $(common-lflags) -lz -lpthread lflags = $(common-lflags) -lpthread # include/freebsd instead of include/linux build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/freebsd" -I$(src) -pthread cflags = $(build-cflags) endif ifeq ($(platform),android) ifeq ($(build-platform),cygwin) ndk = "$$(cygpath -u "$(ANDROID_NDK)")" else ndk = $(ANDROID_NDK) endif ifeq ($(android-version),) android-version = 5 endif ifeq ($(android-toolchain),) android-toolchain = 4.7 endif ifeq ($(arch),arm) android-toolchain-name = arm-linux-androideabi android-toolchain-prefix = arm-linux-androideabi- endif ifeq ($(arch),i386) android-toolchain-name = x86 android-toolchain-prefix = i686-linux-android- endif ifeq ($(android-arm-arch),) android-arm-arch = armv5 endif options := $(options)-api$(android-version)-$(android-toolchain)-$(android-arm-arch) build-cflags = $(common-cflags) -I$(src) build-lflags = -lz -lpthread ifeq ($(subst cygwin,windows,$(subst mingw32,windows,$(build-platform))),windows) toolchain-host-platform = $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform))) build-system = windows build-cxx = i686-w64-mingw32-g++ build-cc = i686-w64-mingw32-gcc sysroot = "$$(cygpath -w "$(ndk)/platforms/android-$(android-version)/arch-arm")" build-cflags += "-I$(JAVA_HOME)/include/win32" else toolchain-host-platform = $(subst cygwin,windows,$(subst mingw32,windows,$(build-platform)))-* sysroot = $(ndk)/platforms/android-$(android-version)/arch-arm build-cflags += "-I$(JAVA_HOME)/include/linux" build-lflags += -ldl endif toolchain = $(ndk)/toolchains/$(android-toolchain-name)-$(android-toolchain)/prebuilt/$(toolchain-host-platform) cflags = "-I$(sysroot)/usr/include" "-I$(JAVA_HOME)/include/linux" $(common-cflags) "-I$(src)" -std=c++11 $(no-psabi) lflags = "-L$(sysroot)/usr/lib" $(common-lflags) -llog target-format = elf use-lto = false ifeq ($(arch),arm) cflags += -marm -march=$(android-arm-arch) -ftree-vectorize -ffast-math -mfloat-abi=softfp endif ifeq ($(arch),i386) endif cxx = $(toolchain)/bin/$(android-toolchain-prefix)g++ --sysroot="$(sysroot)" cc = $(toolchain)/bin/$(android-toolchain-prefix)gcc --sysroot="$(sysroot)" as = $(cxx) ar = $(toolchain)/bin/$(android-toolchain-prefix)ar ranlib = $(toolchain)/bin/$(android-toolchain-prefix)ranlib strip = $(toolchain)/bin/$(android-toolchain-prefix)strip endif ifeq ($(platform),darwin) target-format = macho ifeq (${OSX_SDK_SYSROOT},) OSX_SDK_SYSROOT = 10.4u endif ifeq (${OSX_SDK_VERSION},) OSX_SDK_VERSION = 10.4 endif ifneq ($(build-platform),darwin) cxx = i686-apple-darwin8-g++ $(mflag) cc = i686-apple-darwin8-gcc $(mflag) ar = i686-apple-darwin8-ar ranlib = i686-apple-darwin8-ranlib strip = i686-apple-darwin8-strip sysroot = /opt/mac/SDKs/MacOSX${OSX_SDK_SYSROOT}.sdk cflags = -I$(sysroot)/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Headers/ \ $(common-cflags) -fPIC -fvisibility=hidden -I$(src) endif ifneq ($(ios),true) platform-dir = $(developer-dir)/Platforms/MacOSX.platform sdk-dir = $(platform-dir)/Developer/SDKs mac-version := $(shell \ if test -d $(sdk-dir)/MacOSX10.9.sdk; then echo 10.9; \ elif test -d $(sdk-dir)/MacOSX10.8.sdk; then echo 10.8; \ elif test -d $(sdk-dir)/MacOSX10.7.sdk; then echo 10.7; \ elif test -d $(sdk-dir)/MacOSX10.6.sdk; then echo 10.6; \ else echo; fi) sysroot = $(sdk-dir)/MacOSX$(mac-version).sdk endif version-script-flag = lflags = $(common-lflags) -ldl -framework CoreFoundation ifeq (,$(shell ld -v 2>&1 | grep cctools)) lflags += -Wl,-compatibility_version,1.0.0 endif ifneq ($(arch),arm) lflags += -framework CoreServices -framework SystemConfiguration \ -framework Security endif ifeq ($(bootimage),true) bootimage-lflags = -Wl,-segprot,__RWX,rwx,rwx endif rdynamic = strip-all = -S -x so-suffix = .dylib shared = -dynamiclib rpath = ifeq ($(ios),true) ifeq ($(arch),i386) target = iPhoneSimulator sdk = iphonesimulator$(ios-version) arch = i386 arch-flag = -arch i386 release = Release-iphonesimulator else target = iPhoneOS sdk = iphoneos$(ios-version) arch = arm arch-flag = -arch armv7 release = Release-iphoneos endif platform-dir = $(developer-dir)/Platforms/$(target).platform sdk-dir = $(platform-dir)/Developer/SDKs ios-version := $(shell \ if test -d $(sdk-dir)/$(target)7.0.sdk; then echo 7.0; \ elif test -d $(sdk-dir)/$(target)6.1.sdk; then echo 6.1; \ elif test -d $(sdk-dir)/$(target)6.0.sdk; then echo 6.0; \ elif test -d $(sdk-dir)/$(target)5.1.sdk; then echo 5.1; \ elif test -d $(sdk-dir)/$(target)5.0.sdk; then echo 5.0; \ elif test -d $(sdk-dir)/$(target)4.3.sdk; then echo 4.3; \ elif test -d $(sdk-dir)/$(target)4.2.sdk; then echo 4.2; \ else echo; fi) ifeq ($(ios-version),) x := $(error "couldn't find SDK") endif ios-bin = $(platform-dir)/Developer/usr/bin found-gcc = $(shell if test -f $(ios-bin)/gcc; then echo true; else echo false; fi) ifeq ($(found-gcc),false) use-clang = true endif ifeq ($(use-clang),true) cxx = clang -std=c++11 cc = clang else cxx = $(ios-bin)/g++ cc = $(ios-bin)/gcc endif ar = $(ios-bin)/ar ranlib = $(ios-bin)/ranlib strip = $(ios-bin)/strip flags = -isysroot $(sdk-dir)/$(target)$(ios-version).sdk \ $(arch-flag) classpath-extra-cflags += $(flags) cflags += $(flags) asmflags += $(flags) lflags += $(flags) endif ifeq ($(arch),powerpc) classpath-extra-cflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION} cflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION} asmflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION} lflags += -arch ppc -mmacosx-version-min=${OSX_SDK_VERSION} endif ifeq ($(arch),i386) classpath-extra-cflags += \ -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION} cflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION} asmflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION} lflags += -arch i386 -mmacosx-version-min=${OSX_SDK_VERSION} endif ifeq ($(arch),x86_64) classpath-extra-cflags += -arch x86_64 cflags += -arch x86_64 asmflags += -arch x86_64 lflags += -arch x86_64 endif cflags += -I$(JAVA_HOME)/include/darwin endif openjdk-extra-cflags += $(classpath-extra-cflags) ifeq ($(platform),windows) target-format = pe inc = "$(win32)/include" lib = "$(win32)/lib" embed-prefix = c:/avian-embedded system = windows so-prefix = so-suffix = .dll exe-suffix = .exe rpath = lflags = -L$(lib) $(common-lflags) -lws2_32 -liphlpapi -mconsole cflags = -I$(inc) $(common-cflags) -DWINVER=0x0500 ifeq (,$(filter mingw32 cygwin,$(build-platform))) openjdk-extra-cflags += -I$(src)/openjdk/caseSensitive prefix := $(shell i686-w64-mingw32-gcc --version >/dev/null 2>&1 \ && echo i686-w64-mingw32- || echo x86_64-w64-mingw32-) cxx = $(prefix)g++ -m32 cc = $(prefix)gcc -m32 dlltool = $(prefix)dlltool -mi386 --as-flags=--32 ar = $(prefix)ar ranlib = $(prefix)ranlib strip = $(prefix)strip --strip-all else build-system = windows common-cflags += "-I$(JAVA_HOME)/include/win32" build-cflags = $(common-cflags) -I$(src) -I$(inc) -mthreads openjdk-extra-cflags = build-lflags = -L$(lib) $(common-lflags) ifeq ($(build-platform),cygwin) build-cxx = i686-w64-mingw32-g++ build-cc = i686-w64-mingw32-gcc dlltool = i686-w64-mingw32-dlltool ar = i686-w64-mingw32-ar ranlib = i686-w64-mingw32-ranlib strip = i686-w64-mingw32-strip endif endif ifeq ($(arch),x86_64) ifeq ($(build-platform),cygwin) build-cxx = x86_64-w64-mingw32-g++ build-cc = x86_64-w64-mingw32-gcc endif cxx = x86_64-w64-mingw32-g++ $(mflag) cc = x86_64-w64-mingw32-gcc $(mflag) dlltool = dlltool ar = ar ranlib = ranlib strip = strip inc = "$(win64)/include" lib = "$(win64)/lib" else shared += -Wl,--add-stdcall-alias endif embed = $(build-embed)/embed$(exe-suffix) embed-loader = $(build-embed-loader)/embed-loader$(exe-suffix) embed-loader-o = $(build-embed)/embed-loader.o endif ifeq ($(platform),wp8) ifeq ($(shell uname -s | grep -i -c WOW64),1) programFiles = Program Files (x86) else programFiles = Program Files endif ifeq ($(MSVS_ROOT),) # Environment variable MSVS_ROOT not found. It should be something like # "C:\$(programFiles)\Microsoft Visual Studio 11.0" MSVS_ROOT = C:\$(programFiles)\Microsoft Visual Studio 11.0 endif ifeq ($(MSVC_ROOT),) # Environment variable MSVC_ROOT not found. It should be something like # "C:\$(programFiles)\Microsoft Visual Studio 11.0\VC" MSVC_ROOT = $(MSVS_ROOT)\VC endif ifeq ($(WP80_SDK),) # Environment variable WP8_SDK not found. It should be something like # "C:\Program Files[ (x86)]\Microsoft Visual Studio 11.0\VC\WPSDK\WP80" # TODO: Lookup in SOFTWARE\Microsoft\Microsoft SDKs\WindowsPhone\v8.0 WP80_SDK = $(MSVS_ROOT)\VC\WPSDK\WP80 endif ifeq ($(WP80_KIT),) # Environment variable WP8_KIT not found. It should be something like # "c:\Program Files[ (x86)]\Windows Phone Kits\8.0" # TODO: Lookup in SOFTWARE\Microsoft\Microsoft SDKs\WindowsPhone\v8.0 WP80_KIT = C:\$(programFiles)\Windows Phone Kits\8.0 endif ifeq ($(WIN8_KIT),) # Environment variable WIN8_KIT not found. It should be something like # "c:\Program Files[ (x86)]\Windows Kits\8.0" WIN8_KIT = C:\$(programFiles)\Windows Kits\8.0 endif ifeq ($(build-platform),cygwin) windows-path = cygpath -w else windows-path = $(native-path) endif windows-java-home := $(shell $(windows-path) "$(JAVA_HOME)") target-format = pe ms_cl_compiler = wp8 use-lto = false supports_avian_executable = false aot-only = true ifneq ($(bootimage),true) x := $(error Windows Phone 8 target requires bootimage=true) endif system = windows build-system = windows static-prefix = static-suffix = .lib so-prefix = so-suffix = .dll exe-suffix = .exe manifest-flags = -MANIFEST:NO ifeq ($(arch),arm) wp8_arch = \x86_arm vc_arch = \arm w8kit_arch = arm deps_arch = ARM as = "$$(cygpath -u "$(WP80_SDK)\bin\x86_arm\armasm.exe")" cxx = "$$(cygpath -u "$(WP80_SDK)\bin\x86_arm\cl.exe")" ld = "$$(cygpath -u "$(WP80_SDK)\bin\x86_arm\link.exe")" asmflags = -machine ARM -32 asm-output = -o $(1) asm-input = $(1) machine_type = ARM bootimage-symbols = binary_bootimage_bin_start:binary_bootimage_bin_end codeimage-symbols = binary_codeimage_bin_start:binary_codeimage_bin_end endif ifeq ($(arch),i386) wp8_arch = vc_arch = w8kit_arch = x86 deps_arch = x86 asmflags = $(target-cflags) -safeseh -nologo -Gd as = "$$(cygpath -u "$(WP80_SDK)\bin\ml.exe")" cxx = "$$(cygpath -u "$(WP80_SDK)\bin\cl.exe")" ld = "$$(cygpath -u "$(WP80_SDK)\bin\link.exe")" ifeq ($(mode),debug) asmflags += -Zd endif ifeq ($(mode),debug-fast) asmflags += -Zd endif asm-output = $(output) machine_type = X86 endif PATH := $(shell cygpath -u "$(MSVS_ROOT)\Common7\IDE"):$(shell cygpath -u "$(WP80_SDK)\bin$(wp8_arch)"):$(shell cygpath -u "$(WP80_SDK)\bin"):${PATH} build-cflags = $(common-cflags) -I$(src) -I$(inc) -mthreads build-lflags = -lz -lpthread cflags = -nologo \ -AI"$(WP80_KIT)\Windows Metadata" \ -I"$(WP80_SDK)\include" -I"$(WP80_KIT)\Include" -I"$(WP80_KIT)\Include\minwin" -I"$(WP80_KIT)\Include\mincore" \ -DWINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP -D_USRDLL -D_WINDLL \ -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \ -I"$(shell $(windows-path) "$(wp8)/zlib/upstream")" -I"$(shell $(windows-path) "$(wp8)/interop/avian-interop-client")" \ -I"$(shell $(windows-path) "$(wp8)/include")" -I$(src) -I$(classpath-src) \ -I"$(build)" \ -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" \ -DTARGET_BYTES_PER_WORD=$(pointer-size) \ -Gd -EHsc common-lflags = ifeq ($(mode),debug) build-type = Debug endif ifeq ($(mode),debug-fast) build-type = Debug endif ifeq ($(mode),stress_major) build-type = Release endif ifeq ($(mode),fast) build-type = Release endif ifeq ($(mode),fast) build-type = Release endif ifeq ($(mode),small) build-type = Release endif arflags = -MACHINE:$(machine_type) lflags = $(common-lflags) -nologo \ -MACHINE:$(machine_type) \ -LIBPATH:"$(WP80_KIT)\lib\$(w8kit_arch)" -LIBPATH:"$(WP80_SDK)\lib$(vc_arch)" -LIBPATH:"$(WIN8_KIT)\Lib\win8\um\$(w8kit_arch)" \ ws2_32.lib \ "$(shell $(windows-path) "$(wp8)\lib\$(deps_arch)\$(build-type)\zlib.lib")" "$(shell $(windows-path) "$(wp8)\lib\$(deps_arch)\$(build-type)\ThreadEmulation.lib")" \ "$(shell $(windows-path) "$(wp8)\lib\$(deps_arch)\$(build-type)\AvianInteropClient.lib")" lflags += -NXCOMPAT -DYNAMICBASE -SUBSYSTEM:CONSOLE -TLBID:1 lflags += -NODEFAULTLIB:"ole32.lib" -NODEFAULTLIB:"kernel32.lib" lflags += PhoneAppModelHost.lib WindowsPhoneCore.lib -WINMD -WINMDFILE:$(subst $(so-suffix),.winmd,$(@)) cc = $(cxx) asm-format = masm shared = -dll ar = "$$(cygpath -u "$(WP80_SDK)\bin\lib.exe")" arflags += -nologo ifeq ($(build-platform),cygwin) build-cxx = i686-w64-mingw32-g++ build-cc = i686-w64-mingw32-gcc dlltool = i686-w64-mingw32-dlltool ranlib = strip = endif output = -Fo$(1) #TODO: -MT or -ZW? cflags_debug = -Od -Zi -MDd cflags_debug_fast = -Od -Zi -MDd cflags_stress = -O0 -g3 -MD cflags_stress_major = -O0 -g3 -MD cflags_fast = -O2 -Zi -MD cflags_small = -O1s -Zi -MD # -GL [whole program optimization] in 'fast' and 'small' breaks compilation for some reason ifeq ($(mode),debug) cflags += lflags += endif ifeq ($(mode),debug-fast) cflags += -DNDEBUG lflags += endif ifeq ($(mode),stress_major) cflags += lflags += endif ifeq ($(mode),fast) cflags += lflags += endif # -LTCG is needed only if -GL is used ifeq ($(mode),fast) cflags += -DNDEBUG lflags += -LTCG arflags += endif ifeq ($(mode),small) cflags += -DNDEBUG lflags += -LTCG arflags += endif strip = : endif ifdef msvc no-error = target-format = pe windows-path = $(native-path) windows-java-home := $(shell $(windows-path) "$(JAVA_HOME)") zlib := $(shell $(windows-path) "$(win32)/msvc") ms_cl_compiler = regular as = $(build-cc) cxx = "$(msvc)/BIN/cl.exe" cc = $(cxx) ld = "$(msvc)/BIN/link.exe" mt = "mt.exe" ar = "$(msvc)/BIN/lib.exe" manifest-flags = -MANIFEST -MANIFESTFILE:$(@).manifest cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \ -Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I$(classpath-src) \ -I"$(build)" -Iinclude \ -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" \ -DTARGET_BYTES_PER_WORD=$(pointer-size) ifneq ($(lzma),) cflags += -I$(shell $(windows-path) "$(lzma)") endif shared = -dll lflags = -nologo -LIBPATH:"$(zlib)/lib" -DEFAULTLIB:ws2_32 \ -DEFAULTLIB:zlib -DEFAULTLIB:user32 -MANIFEST -debug output = -Fo$(1) cflags_debug = -Od -Zi -MDd cflags_debug_fast = -Od -Zi -DNDEBUG cflags_fast = -O2 -GL -Zi -DNDEBUG cflags_small = -O1s -Zi -GL -DNDEBUG ifeq ($(mode),fast) lflags += -LTCG endif ifeq ($(mode),small) lflags += -LTCG endif use-lto = false strip = : endif ifeq ($(mode),debug) optimization-cflags = $(cflags_debug) converter-cflags += $(cflags_debug) strip = : endif ifeq ($(mode),debug-fast) optimization-cflags = $(cflags_debug_fast) -DNDEBUG strip = : endif ifeq ($(mode),stress) optimization-cflags = $(cflags_stress) -DVM_STRESS strip = : endif ifeq ($(mode),stress-major) optimization-cflags = $(cflags_stress_major) -DVM_STRESS -DVM_STRESS_MAJOR strip = : endif ifeq ($(mode),fast) optimization-cflags = $(cflags_fast) -DNDEBUG ifeq ($(use-lto),) use-lto = true endif endif ifeq ($(mode),small) optimization-cflags = $(cflags_small) -DNDEBUG ifeq ($(use-lto),) use-lto = true endif endif ifeq ($(use-lto),true) ifeq ($(use-clang),true) optimization-cflags += -flto lflags += $(optimization-cflags) else # only try to use LTO when GCC 4.6.0 or greater is available gcc-major := $(shell $(cc) -dumpversion | cut -f1 -d.) gcc-minor := $(shell $(cc) -dumpversion | cut -f2 -d.) ifeq ($(shell expr 4 \< $(gcc-major) \ \| \( 4 \<= $(gcc-major) \& 6 \<= $(gcc-minor) \)),1) optimization-cflags += -flto no-lto = -fno-lto lflags += $(optimization-cflags) endif endif endif cflags += $(optimization-cflags) ifndef ms_cl_compiler ifneq ($(platform),darwin) ifeq ($(arch),i386) # this is necessary to support __sync_bool_compare_and_swap: cflags += -march=i586 lflags += -march=i586 endif endif endif c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%.o,$(x))) cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x))) asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.$(asm-format),$(3)/%-asm.o,$(x))) java-classes = $(foreach x,$(1),$(patsubst $(2)/%.java,$(3)/%.class,$(x))) generated-code = \ $(build)/type-enums.cpp \ $(build)/type-declarations.cpp \ $(build)/type-constructors.cpp \ $(build)/type-initializations.cpp \ $(build)/type-java-initializations.cpp \ $(build)/type-name-initializations.cpp \ $(build)/type-maps.cpp vm-depends := $(generated-code) \ $(shell find src include -name '*.h' -or -name '*.inc.cpp') vm-sources = \ $(src)/system/$(system).cpp \ $(src)/system/$(system)/signal.cpp \ $(src)/finder.cpp \ $(src)/machine.cpp \ $(src)/util.cpp \ $(src)/heap/heap.cpp \ $(src)/$(process).cpp \ $(src)/classpath-$(classpath).cpp \ $(src)/builtin.cpp \ $(src)/jnienv.cpp \ $(src)/process.cpp vm-asm-sources = $(src)/$(asm).$(asm-format) target-asm = $(asm) build-embed = $(build)/embed build-embed-loader = $(build)/embed-loader embed-loader-sources = $(src)/embedded-loader.cpp embed-loader-objects = $(call cpp-objects,$(embed-loader-sources),$(src),$(build-embed-loader)) embed-sources = $(src)/embed.cpp embed-objects = $(call cpp-objects,$(embed-sources),$(src),$(build-embed)) compiler-sources = \ $(src)/codegen/compiler.cpp \ $(wildcard $(src)/codegen/compiler/*.cpp) \ $(src)/codegen/registers.cpp \ $(src)/codegen/runtime.cpp \ $(src)/codegen/targets.cpp \ $(src)/util/fixed-allocator.cpp x86-assembler-sources = $(wildcard $(src)/codegen/target/x86/*.cpp) arm-assembler-sources = $(wildcard $(src)/codegen/target/arm/*.cpp) powerpc-assembler-sources = $(wildcard $(src)/codegen/target/powerpc/*.cpp) all-assembler-sources = \ $(x86-assembler-sources) \ $(arm-assembler-sources) \ $(powerpc-assembler-sources) native-assembler-sources = $($(target-asm)-assembler-sources) all-codegen-target-sources = \ $(compiler-sources) \ $(native-assembler-sources) ifeq ($(process),compile) vm-sources += $(compiler-sources) ifeq ($(codegen-targets),native) vm-sources += $(native-assembler-sources) endif ifeq ($(codegen-targets),all) vm-sources += $(all-assembler-sources) endif vm-asm-sources += $(src)/compile-$(asm).$(asm-format) endif cflags += -DAVIAN_PROCESS_$(process) ifeq ($(aot-only),true) cflags += -DAVIAN_AOT_ONLY endif vm-cpp-objects = $(call cpp-objects,$(vm-sources),$(src),$(build)) all-codegen-target-objects = $(call cpp-objects,$(all-codegen-target-sources),$(src),$(build)) vm-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(build)) vm-objects = $(vm-cpp-objects) $(vm-asm-objects) heapwalk-sources = $(src)/heapwalk.cpp heapwalk-objects = \ $(call cpp-objects,$(heapwalk-sources),$(src),$(build)) unittest-objects = $(call cpp-objects,$(unittest-sources),$(unittest),$(build)/unittest) ifeq ($(heapdump),true) vm-sources += $(src)/heapdump.cpp vm-heapwalk-objects = $(heapwalk-objects) cflags += -DAVIAN_HEAPDUMP endif ifeq ($(tails),true) cflags += -DAVIAN_TAILS endif ifeq ($(continuations),true) cflags += -DAVIAN_CONTINUATIONS asmflags += -DAVIAN_CONTINUATIONS endif bootimage-generator-sources = $(src)/tools/bootimage-generator/main.cpp $(src)/util/arg-parser.cpp $(stub-sources) ifneq ($(lzma),) bootimage-generator-sources += $(src)/lzma-encode.cpp endif bootimage-generator-objects = \ $(call cpp-objects,$(bootimage-generator-sources),$(src),$(build)) bootimage-generator = $(build)/bootimage-generator bootimage-object = $(build)/bootimage-bin.o codeimage-object = $(build)/codeimage-bin.o ifeq ($(bootimage),true) vm-classpath-objects = $(bootimage-object) $(codeimage-object) cflags += -DBOOT_IMAGE -DAVIAN_CLASSPATH=\"\" else vm-classpath-objects = $(classpath-object) cflags += -DBOOT_CLASSPATH=\"[classpathJar]\" \ -DAVIAN_CLASSPATH=\"[classpathJar]\" endif cflags += $(extra-cflags) lflags += $(extra-lflags) openjdk-cflags += $(extra-cflags) driver-source = $(src)/main.cpp driver-object = $(build)/main.o driver-dynamic-objects = \ $(build)/main-dynamic.o boot-source = $(src)/boot.cpp boot-object = $(build)/boot.o generator-depends := $(wildcard $(src)/*.h) generator-sources = \ $(src)/tools/type-generator/main.cpp \ $(src)/system/$(build-system).cpp \ $(src)/system/$(build-system)/signal.cpp \ $(src)/finder.cpp ifneq ($(lzma),) common-cflags += -I$(lzma) -DAVIAN_USE_LZMA -D_7ZIP_ST vm-sources += \ $(src)/lzma-decode.cpp generator-sources += \ $(src)/lzma-decode.cpp lzma-decode-sources = \ $(lzma)/C/LzmaDec.c lzma-decode-objects = \ $(call c-objects,$(lzma-decode-sources),$(lzma)/C,$(build)) lzma-encode-sources = \ $(lzma)/C/LzmaEnc.c \ $(lzma)/C/LzFind.c lzma-encode-objects = \ $(call c-objects,$(lzma-encode-sources),$(lzma)/C,$(build)) lzma-encoder = $(build)/lzma/lzma lzma-encoder-cflags = -D__STDC_CONSTANT_MACROS -fno-rtti -fno-exceptions \ -I$(lzma)/C lzma-encoder-sources = \ $(src)/lzma/main.cpp lzma-encoder-objects = \ $(call cpp-objects,$(lzma-encoder-sources),$(src),$(build)) lzma-encoder-lzma-sources = $(lzma-encode-sources) $(lzma-decode-sources) lzma-encoder-lzma-objects = \ $(call generator-c-objects,$(lzma-encoder-lzma-sources),$(lzma)/C,$(build)) lzma-loader = $(build)/lzma/load.o endif generator-cpp-objects = \ $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%-build.o,$(x))) generator-c-objects = \ $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%-build.o,$(x))) generator-objects = \ $(call generator-cpp-objects,$(generator-sources),$(src),$(build)) generator-lzma-objects = \ $(call generator-c-objects,$(lzma-decode-sources),$(lzma)/C,$(build)) generator = $(build)/generator all-depends = $(shell find include -name '*.h') object-writer-depends = $(shell find $(src)/tools/object-writer -name '*.h') object-writer-sources = $(shell find $(src)/tools/object-writer -name '*.cpp') object-writer-objects = $(call cpp-objects,$(object-writer-sources),$(src),$(build)) binary-to-object-depends = $(shell find $(src)/tools/binary-to-object/ -name '*.h') binary-to-object-sources = $(shell find $(src)/tools/binary-to-object/ -name '*.cpp') binary-to-object-objects = $(call cpp-objects,$(binary-to-object-sources),$(src),$(build)) converter-sources = $(object-writer-sources) converter-tool-depends = $(binary-to-object-depends) $(all-depends) converter-tool-sources = $(binary-to-object-sources) converter-objects = $(call cpp-objects,$(converter-sources),$(src),$(build)) converter-tool-objects = $(call cpp-objects,$(converter-tool-sources),$(src),$(build)) converter = $(build)/binaryToObject/binaryToObject static-library = $(build)/$(static-prefix)$(name)$(static-suffix) executable = $(build)/$(name)${exe-suffix} dynamic-library = $(build)/$(so-prefix)jvm$(so-suffix) executable-dynamic = $(build)/$(name)-dynamic$(exe-suffix) unittest-executable = $(build)/$(name)-unittest${exe-suffix} ifneq ($(classpath),avian) # Assembler, ConstantPool, and Stream are not technically needed for a # working build, but we include them since our Subroutine test uses # them to synthesize a class: classpath-sources := \ $(classpath-src)/avian/Addendum.java \ $(classpath-src)/avian/AnnotationInvocationHandler.java \ $(classpath-src)/avian/Assembler.java \ $(classpath-src)/avian/Callback.java \ $(classpath-src)/avian/Cell.java \ $(classpath-src)/avian/ClassAddendum.java \ $(classpath-src)/avian/InnerClassReference.java \ $(classpath-src)/avian/Classes.java \ $(classpath-src)/avian/ConstantPool.java \ $(classpath-src)/avian/Continuations.java \ $(classpath-src)/avian/FieldAddendum.java \ $(classpath-src)/avian/Function.java \ $(classpath-src)/avian/IncompatibleContinuationException.java \ $(classpath-src)/avian/Machine.java \ $(classpath-src)/avian/MethodAddendum.java \ $(classpath-src)/avian/Singleton.java \ $(classpath-src)/avian/Stream.java \ $(classpath-src)/avian/SystemClassLoader.java \ $(classpath-src)/avian/Traces.java \ $(classpath-src)/avian/VMClass.java \ $(classpath-src)/avian/VMField.java \ $(classpath-src)/avian/VMMethod.java \ $(classpath-src)/avian/avianvmresource/Handler.java ifeq ($(openjdk),) classpath-sources := $(classpath-sources) \ $(classpath-src)/sun/reflect/ConstantPool.java \ $(classpath-src)/java/lang/ReflectiveOperationException.java \ $(classpath-src)/java/net/ProtocolFamily.java \ $(classpath-src)/java/net/StandardProtocolFamily.java \ $(classpath-src)/sun/misc/Cleaner.java \ $(classpath-src)/sun/misc/Unsafe.java \ $(classpath-src)/java/lang/reflect/Proxy.java endif else classpath-sources := $(shell find $(classpath-src) -name '*.java') endif classpath-classes = \ $(call java-classes,$(classpath-sources),$(classpath-src),$(classpath-build)) classpath-object = $(build)/classpath-jar.o classpath-dep = $(classpath-build).dep vm-classes = \ avian/*.class \ avian/resource/*.class test-support-sources = $(shell find $(test)/avian/ -name '*.java') test-sources = $(wildcard $(test)/*.java) test-cpp-sources = $(wildcard $(test)/*.cpp) test-sources += $(test-support-sources) test-support-classes = $(call java-classes, $(test-support-sources),$(test),$(test-build)) test-classes = $(call java-classes,$(test-sources),$(test),$(test-build)) test-cpp-objects = $(call cpp-objects,$(test-cpp-sources),$(test),$(test-build)) test-library = $(build)/$(so-prefix)test$(so-suffix) test-dep = $(test-build).dep test-extra-sources = $(wildcard $(test)/extra/*.java) test-extra-classes = \ $(call java-classes,$(test-extra-sources),$(test),$(test-build)) test-extra-dep = $(test-build)-extra.dep unittest-sources = \ $(wildcard $(unittest)/*.cpp) \ $(wildcard $(unittest)/util/*.cpp) \ $(wildcard $(unittest)/codegen/*.cpp) unittest-depends = \ $(wildcard $(unittest)/*.h) ifeq ($(continuations),true) continuation-tests = \ extra.ComposableContinuations \ extra.Continuations \ extra.Coroutines \ extra.DynamicWind endif ifeq ($(tails),true) tail-tests = \ extra.Tails endif ifeq ($(target-arch),i386) cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_X86 endif ifeq ($(target-arch),x86_64) cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_X86_64 endif ifeq ($(target-arch),powerpc) cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_POWERPC endif ifeq ($(target-arch),arm) cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_ARM endif ifeq ($(target-format),elf) cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_ELF endif ifeq ($(target-format),pe) cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_PE endif ifeq ($(target-format),macho) cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_MACHO endif class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) test-flags = -Djava.library.path=$(build) -cp $(build)/test test-args = $(test-flags) $(input) .PHONY: build ifneq ($(supports_avian_executable),false) build: $(static-library) $(executable) $(dynamic-library) $(lzma-loader) \ $(lzma-encoder) $(executable-dynamic) $(classpath-dep) $(test-dep) \ $(test-extra-dep) $(embed) else build: $(static-library) $(dynamic-library) $(lzma-loader) \ $(lzma-encoder) $(classpath-dep) $(test-dep) \ $(test-extra-dep) $(embed) endif $(test-dep): $(classpath-dep) $(test-extra-dep): $(classpath-dep) .PHONY: run run: build $(library-path) $(test-executable) $(test-args) .PHONY: debug debug: build $(library-path) gdb --args $(test-executable) $(test-args) .PHONY: vg vg: build $(library-path) $(vg) $(test-executable) $(test-args) .PHONY: test test: build $(build)/run-tests.sh $(build)/test.sh $(unittest-executable) ifneq ($(remote-test),true) /bin/sh $(build)/run-tests.sh else @echo "running tests on $(remote-test-user)@$(remote-test-host):$(remote-test-port), in $(remote-test-dir)" rsync $(build) -rav --exclude '*.o' --rsh="ssh -p$(remote-test-port)" $(remote-test-user)@$(remote-test-host):$(remote-test-dir) ssh -p$(remote-test-port) $(remote-test-user)@$(remote-test-host) sh "$(remote-test-dir)/$(platform)-$(arch)$(options)/run-tests.sh" endif .PHONY: jdk-test jdk-test: $(test-dep) $(build)/classpath.jar $(build)/jdk-run-tests.sh $(build)/test.sh /bin/sh $(build)/jdk-run-tests.sh .PHONY: tarball tarball: @echo "creating build/avian-$(version).tar.bz2" @mkdir -p build (cd .. && tar --exclude=build --exclude='.*' --exclude='*~' -cjf \ avian/build/avian-$(version).tar.bz2 avian) .PHONY: javadoc javadoc: $(JAVA_HOME)/bin/javadoc -sourcepath classpath -d build/javadoc -subpackages avian:java \ -windowtitle "Avian v$(version) Class Library API" \ -doctitle "Avian v$(version) Class Library API" \ -header "Avian v$(version)" \ -bottom "http://oss.readytalk.com/avian" .PHONY: clean-current clean-current: @echo "removing $(build)" rm -rf $(build) .PHONY: clean clean: @echo "removing build" rm -rf build ifeq ($(continuations),true) $(build)/compile-x86-asm.o: $(src)/continuations-x86.$(asm-format) endif $(build)/run-tests.sh: $(test-classes) makefile $(build)/extra-dir/multi-classpath-test.txt $(build)/test/multi-classpath-test.txt echo 'cd $$(dirname $$0)' > $(@) echo "sh ./test.sh 2>/dev/null \\" >> $(@) echo "$(shell echo $(library-path) | sed 's|$(build)|\.|g') ./$(name)-unittest${exe-suffix} ./$(notdir $(test-executable)) $(mode) \"-Djava.library.path=. -cp test$(target-path-separator)extra-dir\" \\" >> $(@) echo "$(call class-names,$(test-build),$(filter-out $(test-support-classes), $(test-classes))) \\" >> $(@) echo "$(continuation-tests) $(tail-tests)" >> $(@) $(build)/jdk-run-tests.sh: $(test-classes) makefile $(build)/extra-dir/multi-classpath-test.txt $(build)/test/multi-classpath-test.txt echo 'cd $$(dirname $$0)' > $(@) echo "sh ./test.sh 2>/dev/null \\" >> $(@) echo "'' true $(JAVA_HOME)/bin/java $(mode) \"-Xmx128m -Djava.library.path=. -cp test$(path-separator)extra-dir$(path-separator)classpath\" \\" >> $(@) echo "$(call class-names,$(test-build),$(filter-out $(test-support-classes), $(test-classes))) \\" >> $(@) echo "$(continuation-tests) $(tail-tests)" >> $(@) $(build)/extra-dir/multi-classpath-test.txt: mkdir -p $(build)/extra-dir echo "$@" > $@ $(build)/test/multi-classpath-test.txt: echo "$@" > $@ $(build)/test.sh: $(test)/test.sh cp $(<) $(@) gen-arg = $(shell echo $(1) | sed -e 's:$(build)/type-\(.*\)\.cpp:\1:') $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep) @echo "generating $(@)" @mkdir -p $(dir $(@)) $(generator) $(boot-classpath) $(<) $(@) $(call gen-arg,$(@)) $(classpath-build)/%.class: $(classpath-src)/%.java @echo $(<) $(classpath-dep): $(classpath-sources) $(classpath-jar-dep) @echo "compiling classpath classes" @mkdir -p $(classpath-build) classes="$(shell $(MAKE) -s --no-print-directory build=$(build) \ $(classpath-classes))"; if [ -n "$${classes}" ]; then \ $(javac) -source 1.6 -target 1.6 \ -d $(classpath-build) -bootclasspath $(boot-classpath) \ $${classes}; fi @touch $(@) $(build)/android-src/%.cpp: $(luni-native)/%.cpp cp $(<) $(@) $(build)/android-src/%.cpp: $(libnativehelper-native)/%.cpp cp $(<) $(@) $(build)/android-src/%.cpp: $(crypto-native)/%.cpp cp $(<) $(@) $(build)/%.o: $(build)/android-src/%.cpp $(build)/android.dep @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(cxx) $(android-cflags) $(classpath-extra-cflags) -c \ $$($(windows-path) $(<)) $(call output,$(@)) $(build)/android.dep: $(luni-javas) $(libdvm-javas) $(crypto-javas) \ $(dalvik-javas) $(xml-javas) @echo "compiling luni classes" @mkdir -p $(classpath-build) @mkdir -p $(build)/android @mkdir -p $(build)/android-src/external/fdlibm @mkdir -p $(build)/android-src/libexpat cp $(android)/external/fdlibm/fdlibm.h $(build)/android-src/external/fdlibm/ cp $(android)/external/expat/lib/expat*.h $(build)/android-src/libexpat/ cp -a $(luni-java)/* $(libdvm-java)/* $(crypto-java)/* $(dalvik-java)/* \ $(xml-java)/* $(build)/android-src/ sed -i -e 's/return ordinal - o.ordinal;/return ordinal - o.ordinal();/' \ $(build)/android-src/java/lang/Enum.java # sed makes this file read-only which in turn breaks re-builds; so marking it as writable chmod +w $(build)/android-src/java/lang/Enum.java find $(build)/android-src -name '*.java' > $(build)/android.txt $(javac) -Xmaxerrs 1000 -d $(build)/android -sourcepath $(luni-java) \ @$(build)/android.txt rm $(build)/android/sun/misc/Unsafe* \ $(build)/android/java/lang/reflect/Proxy* cp -r $(build)/android/* $(classpath-build) @touch $(@) $(test-build)/%.class: $(test)/%.java @echo $(<) $(test-dep): $(test-sources) $(test-library) @echo "compiling test classes" @mkdir -p $(test-build) files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \ if test -n "$${files}"; then \ $(javac) -source 1.6 -target 1.6 \ -classpath $(test-build) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \ -bootclasspath $(boot-classpath) test/Subroutine.java @touch $(@) $(test-extra-dep): $(test-extra-sources) @echo "compiling extra test classes" @mkdir -p $(test-build) files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-extra-classes))"; \ if test -n "$${files}"; then \ $(javac) -source 1.6 -target 1.6 \ -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi @touch $(@) define compile-object @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(cxx) $(cflags) -c $$($(windows-path) $(<)) $(call output,$(@)) endef define compile-asm-object @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(as) $(asmflags) $(call asm-output,$(@)) $(call asm-input,$(<)) endef define compile-unittest-object @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(cxx) $(cflags) -c $$($(windows-path) $(<)) -I$(unittest) $(call output,$(@)) endef $(vm-cpp-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) ifeq ($(process),interpret) $(all-codegen-target-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) endif $(unittest-objects): $(build)/unittest/%.o: $(unittest)/%.cpp $(vm-depends) $(unittest-depends) $(compile-unittest-object) $(test-cpp-objects): $(test-build)/%.o: $(test)/%.cpp $(vm-depends) $(compile-object) $(test-library): $(test-cpp-objects) @echo "linking $(@)" ifdef ms_cl_compiler $(ld) $(shared) $(lflags) $(^) -out:$(@) \ -debug -PDB:$(subst $(so-suffix),.pdb,$(@)) \ -IMPLIB:$(test-build)/$(name).lib $(manifest-flags) ifdef mt $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);2" endif else $(ld) $(^) $(shared) $(lflags) -o $(@) endif ifdef embed $(embed): $(embed-objects) $(embed-loader-o) @echo "building $(embed)" ifdef ms_cl_compiler $(ld) $(lflags) $(^) -out:$(@) \ -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) $(manifest-flags) ifdef mt $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" endif else $(cxx) $(^) $(lflags) $(static) $(call output,$(@)) endif $(build-embed)/%.o: $(src)/%.cpp @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(cxx) $(cflags) -c $(<) $(call output,$(@)) $(embed-loader-o): $(embed-loader) $(converter) @mkdir -p $(dir $(@)) $(converter) $(<) $(@) _binary_loader_start \ _binary_loader_end $(target-format) $(arch) $(embed-loader): $(embed-loader-objects) $(vm-objects) $(classpath-objects) \ $(heapwalk-objects) $(lzma-decode-objects) ifdef ms_cl_compiler $(ld) $(lflags) $(^) -out:$(@) \ -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) $(manifest-flags) ifdef mt $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" endif else $(dlltool) -z $(addsuffix .def,$(basename $(@))) $(^) $(dlltool) -d $(addsuffix .def,$(basename $(@))) -e $(addsuffix .exp,$(basename $(@))) $(ld) $(addsuffix .exp,$(basename $(@))) $(^) \ $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) $(build-embed-loader)/%.o: $(src)/%.cpp @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(cxx) $(cflags) -c $(<) $(call output,$(@)) endif $(build)/%.o: $(lzma)/C/%.c @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(cc) $(cflags) $(no-error) -c $$($(windows-path) $(<)) $(call output,$(@)) $(vm-asm-objects): $(build)/%-asm.o: $(src)/%.$(asm-format) $(compile-asm-object) $(bootimage-generator-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) $(heapwalk-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) $(driver-object): $(driver-source) $(compile-object) $(build)/main-dynamic.o: $(driver-source) @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(cxx) $(cflags) -DBOOT_LIBRARY=\"$(so-prefix)jvm$(so-suffix)\" \ -c $(<) $(call output,$(@)) $(boot-object): $(boot-source) $(compile-object) $(boot-javahome-object): $(src)/boot-javahome.cpp $(compile-object) $(object-writer-objects) $(binary-to-object-objects): $(build)/%.o: $(src)/%.cpp $(binary-to-object-depends) $(object-writer-depends) $(all-depends) @mkdir -p $(dir $(@)) $(build-cxx) $(converter-cflags) -c $(<) -o $(@) $(converter): $(converter-objects) $(converter-tool-objects) @mkdir -p $(dir $(@)) $(build-cc) $(^) -g -o $(@) $(lzma-encoder-objects): $(build)/lzma/%.o: $(src)/lzma/%.cpp @mkdir -p $(dir $(@)) $(build-cxx) $(lzma-encoder-cflags) -c $(<) -o $(@) $(lzma-encoder): $(lzma-encoder-objects) $(lzma-encoder-lzma-objects) $(build-cc) $(^) -g -o $(@) $(lzma-loader): $(src)/lzma/load.cpp $(compile-object) $(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep) @echo "creating $(@)" (wd=$$(pwd) && \ cd $(classpath-build) && \ $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) $(classpath-object): $(build)/classpath.jar $(converter) @echo "creating $(@)" $(converter) $(<) $(@) _binary_classpath_jar_start \ _binary_classpath_jar_end $(target-format) $(arch) $(build)/javahome.jar: @echo "creating $(@)" (wd=$$(pwd) && \ cd "$(build-javahome)" && \ $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" $(javahome-files)) $(javahome-object): $(build)/javahome.jar $(converter) @echo "creating $(@)" $(converter) $(<) $(@) _binary_javahome_jar_start \ _binary_javahome_jar_end $(target-format) $(arch) define compile-generator-object @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \ -c $(<) -o $(@) endef $(generator-objects): $(generator-depends) $(generator-objects): $(build)/%-build.o: $(src)/%.cpp $(compile-generator-object) $(build)/%-build.o: $(lzma)/C/%.c @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \ $(no-error) -c $(<) -o $(@) $(jni-objects): $(build)/%.o: $(classpath-src)/%.cpp $(compile-object) $(static-library): $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) \ $(javahome-object) $(boot-javahome-object) $(lzma-decode-objects) @echo "creating $(@)" @rm -rf $(build)/libavian @mkdir -p $(build)/libavian rm -rf $(@) for x in $(^); \ do cp $${x} $(build)/libavian/$$(echo $${x} | sed s:/:_:g); \ done ifdef ms_cl_compiler $(ar) $(arflags) $(build)/libavian/*.o -out:$(@) else $(ar) cru $(@) $(build)/libavian/*.o $(ranlib) $(@) endif $(bootimage-object) $(codeimage-object): $(bootimage-generator) \ $(classpath-jar-dep) @echo "generating bootimage and codeimage binaries from $(classpath-build) using $(<)" $(<) -cp $(classpath-build) -bootimage $(bootimage-object) -codeimage $(codeimage-object) \ -bootimage-symbols $(bootimage-symbols) \ -codeimage-symbols $(codeimage-symbols) executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-objects) \ $(javahome-object) $(boot-javahome-object) $(lzma-decode-objects) unittest-executable-objects = $(unittest-objects) $(vm-objects) \ $(build)/util/arg-parser.o $(stub-objects) $(lzma-decode-objects) ifeq ($(process),interpret) unittest-executable-objects += $(all-codegen-target-objects) endif # apparently, make does poorly with ifs inside of defines, and indented defines. # I suggest re-indenting the following before making edits (and unindenting afterwards): ifneq ($(platform),windows) define link-executable @echo linking $(@) $(ld) $(^) $(rdynamic) $(lflags) $(classpath-lflags) $(bootimage-lflags) \ -o $(@) endef else ifdef ms_cl_compiler ifdef mt define link-executable @echo linking $(@) $(ld) $(lflags) $(^) -out:$(@) \ -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) $(manifest-flags) $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" endef else define link-executable @echo linking $(@) $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" endef endif else define link-executable @echo linking $(@) $(dlltool) -z $(@).def $(^) $(dlltool) -d $(@).def -e $(@).exp $(ld) $(@).exp $(^) $(lflags) $(classpath-lflags) -o $(@) endef endif endif $(executable): $(executable-objects) $(link-executable) $(unittest-executable): $(unittest-executable-objects) $(link-executable) $(bootimage-generator): $(bootimage-generator-objects) $(vm-objects) echo building $(bootimage-generator) arch=$(build-arch) platform=$(bootimage-platform) $(MAKE) mode=$(mode) \ ios=false \ build=$(host-build-root) \ arch=$(build-arch) \ aot-only=false \ target-arch=$(arch) \ armv6=$(armv6) \ platform=$(bootimage-platform) \ target-format=$(target-format) \ openjdk=$(openjdk) \ openjdk-src=$(openjdk-src) \ bootimage-generator= \ build-bootimage-generator=$(bootimage-generator) \ target-cflags="$(bootimage-cflags)" \ target-asm=$(asm) \ $(bootimage-generator) $(build-bootimage-generator): \ $(vm-objects) $(classpath-object) \ $(heapwalk-objects) $(bootimage-generator-objects) $(converter-objects) \ $(lzma-decode-objects) $(lzma-encode-objects) @echo "linking $(@)" ifeq ($(platform),windows) ifdef ms_cl_compiler $(ld) $(bootimage-generator-lflags) $(lflags) $(^) -out:$(@) \ -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) $(manifest-flags) ifdef mt $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" endif else $(dlltool) -z $(@).def $(^) $(dlltool) -d $(@).def -e $(@).exp $(ld) $(@).exp $(^) $(bootimage-generator-lflags) $(lflags) -o $(@) endif else $(ld) $(^) $(rdynamic) $(bootimage-generator-lflags) $(lflags) -o $(@) endif $(dynamic-library): $(vm-objects) $(dynamic-object) $(classpath-objects) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-objects) \ $(classpath-libraries) $(javahome-object) $(boot-javahome-object) \ $(lzma-decode-objects) @echo "linking $(@)" ifdef ms_cl_compiler $(ld) $(shared) $(lflags) $(^) -out:$(@) \ -debug -PDB:$(subst $(so-suffix),.pdb,$(@)) \ -IMPLIB:$(subst $(so-suffix),.lib,$(@)) $(manifest-flags) ifdef mt $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);2" endif else $(ld) $(^) $(version-script-flag) $(soname-flag) \ $(shared) $(lflags) $(classpath-lflags) $(bootimage-lflags) \ -o $(@) endif $(strip) $(strip-all) $(@) # todo: the $(no-lto) flag below is due to odd undefined reference errors on # Ubuntu 11.10 which may be fixable without disabling LTO. $(executable-dynamic): $(driver-dynamic-objects) $(dynamic-library) @echo "linking $(@)" ifdef ms_cl_compiler $(ld) $(lflags) -LIBPATH:$(build) -DEFAULTLIB:$(name) \ -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) \ $(driver-dynamic-objects) -out:$(@) $(manifest-flags) ifdef mt $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" endif else $(ld) $(driver-dynamic-objects) -L$(build) -ljvm $(lflags) $(no-lto) $(rpath) -o $(@) endif $(strip) $(strip-all) $(@) $(generator): $(generator-objects) $(generator-lzma-objects) @echo "linking $(@)" $(build-ld) $(^) $(build-lflags) -o $(@) $(openjdk-objects): $(build)/openjdk/%-openjdk.o: $(openjdk-src)/%.c \ $(openjdk-headers-dep) @echo "compiling $(@)" @mkdir -p $(dir $(@)) sed 's/^static jclass ia_class;//' < $(<) > $(build)/openjdk/$(notdir $(<)) ifeq ($(ios),true) sed \ -e 's/^#ifndef __APPLE__/#if 1/' \ -e 's/^#ifdef __APPLE__/#if 0/' \ < "$(openjdk-src)/solaris/native/java/lang/ProcessEnvironment_md.c" \ > $(build)/openjdk/ProcessEnvironment_md.c sed \ -e 's/^#ifndef __APPLE__/#if 1/' \ -e 's/^#ifdef __APPLE__/#if 0/' \ < "$(openjdk-src)/solaris/native/java/lang/UNIXProcess_md.c" \ > $(build)/openjdk/UNIXProcess_md.c endif if [ -f openjdk-patches/$(notdir $(<)).patch ]; then \ ( cd $(build) && patch -p0 ) < openjdk-patches/$(notdir $(<)).patch; \ fi $(cc) -fPIC $(openjdk-extra-cflags) $(openjdk-cflags) \ $(optimization-cflags) -w -c $(build)/openjdk/$(notdir $(<)) \ $(call output,$(@)) -Wno-return-type $(openjdk-local-objects): $(build)/openjdk/%-openjdk.o: $(src)/openjdk/%.c \ $(openjdk-headers-dep) @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(cc) -fPIC $(openjdk-extra-cflags) $(openjdk-cflags) \ $(optimization-cflags) -w -c $(<) $(call output,$(@)) $(openjdk-headers-dep): @echo "generating openjdk headers" @mkdir -p $(dir $(@)) $(javah) -d $(build)/openjdk -bootclasspath $(boot-classpath) \ $(openjdk-headers-classes) ifeq ($(platform),windows) sed 's/^#ifdef _WIN64/#if 1/' \ < "$(openjdk-src)/windows/native/java/net/net_util_md.h" \ > $(build)/openjdk/net_util_md.h sed \ -e 's/\(^#include "net_util.h"\)/\1\n#if (defined _INC_NLDEF) || (defined _WS2DEF_)\n#define HIDE(x) hide_##x\n#else\n#define HIDE(x) x\n#define _WINSOCK2API_\n#endif/' \ -e 's/\(IpPrefix[a-zA-Z_]*\)/HIDE(\1)/' \ -e 's/\(IpSuffix[a-zA-Z_]*\)/HIDE(\1)/' \ -e 's/\(IpDad[a-zA-Z_]*\)/HIDE(\1)/' \ -e 's/\(ScopeLevel[a-zA-Z_]*\)/HIDE(\1)/' \ -e 's/\(SCOPE_LEVEL[a-zA-Z_]*\)/HIDE(\1)/' \ < "$(openjdk-src)/windows/native/java/net/NetworkInterface.h" \ > $(build)/openjdk/NetworkInterface.h echo 'static int getAddrsFromAdapter(IP_ADAPTER_ADDRESSES *ptr, netaddr **netaddrPP);' >> $(build)/openjdk/NetworkInterface.h endif ifeq ($(platform),darwin) mkdir -p $(build)/openjdk/netinet for file in \ $(sysroot)/usr/include/netinet/ip.h \ $(sysroot)/usr/include/netinet/in_systm.h \ $(sysroot)/usr/include/netinet/ip_icmp.h \ $(sysroot)/usr/include/netinet/in_var.h \ $(sysroot)/usr/include/netinet/icmp6.h \ $(sysroot)/usr/include/netinet/ip_var.h; do \ if [ ! -f "$(build)/openjdk/netinet/$$(basename $${file})" ]; then \ ln "$${file}" "$(build)/openjdk/netinet/$$(basename $${file})"; \ fi; \ done mkdir -p $(build)/openjdk/netinet6 for file in \ $(sysroot)/usr/include/netinet6/in6_var.h; do \ if [ ! -f "$(build)/openjdk/netinet6/$$(basename $${file})" ]; then \ ln "$${file}" "$(build)/openjdk/netinet6/$$(basename $${file})"; \ fi; \ done mkdir -p $(build)/openjdk/net for file in \ $(sysroot)/usr/include/net/if_arp.h; do \ if [ ! -f "$(build)/openjdk/net/$$(basename $${file})" ]; then \ ln "$${file}" "$(build)/openjdk/net/$$(basename $${file})"; \ fi; \ done mkdir -p $(build)/openjdk/sys for file in \ $(sysroot)/usr/include/sys/kern_event.h \ $(sysroot)/usr/include/sys/sys_domain.h; do \ if [ ! -f "$(build)/openjdk/sys/$$(basename $${file})" ]; then \ ln "$${file}" "$(build)/openjdk/sys/$$(basename $${file})"; \ fi; \ done endif @touch $(@) $(openjdk-jar-dep): @echo "extracting openjdk classes" @mkdir -p $(dir $(@)) @mkdir -p $(classpath-build) (cd $(classpath-build) && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/rt.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jsse.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jce.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/charsets.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/ext/sunjce_provider.jar")" && \ $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/resources.jar")") @touch $(@) ReadyTalk-avian-1e1fff5/openjdk-patches/000077500000000000000000000000001231440243200202375ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/openjdk-patches/java_props_macosx.c.patch000066400000000000000000000010101231440243200252070ustar00rootroot00000000000000--- openjdk/java_props_macosx.c +++ openjdk/java_props_macosx.c @@ -37,11 +37,7 @@ // need dlopen/dlsym trick to avoid pulling in JavaRuntimeSupport before libjava.dylib is loaded static void *getJRSFramework() { - static void *jrsFwk = NULL; - if (jrsFwk == NULL) { - jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL); - } - return jrsFwk; + return NULL; } static char *getPosixLocale(int cat) { ReadyTalk-avian-1e1fff5/openjdk-src.mk000066400000000000000000000345461231440243200177440ustar00rootroot00000000000000openjdk-sources = \ $(openjdk-src)/share/native/common/check_code.c \ $(openjdk-src)/share/native/common/check_format.c \ $(openjdk-src)/share/native/common/check_version.c \ $(openjdk-src)/share/native/common/jdk_util.c \ $(openjdk-src)/share/native/common/jio.c \ $(openjdk-src)/share/native/common/jni_util.c \ $(openjdk-src)/share/native/common/verify_stub.c \ $(openjdk-src)/share/native/java/io/FileInputStream.c \ $(openjdk-src)/share/native/java/io/io_util.c \ $(openjdk-src)/share/native/java/io/ObjectInputStream.c \ $(openjdk-src)/share/native/java/io/ObjectOutputStream.c \ $(openjdk-src)/share/native/java/io/ObjectStreamClass.c \ $(openjdk-src)/share/native/java/io/RandomAccessFile.c \ $(openjdk-src)/share/native/java/lang/Class.c \ $(openjdk-src)/share/native/java/lang/ClassLoader.c \ $(openjdk-src)/share/native/java/lang/Compiler.c \ $(openjdk-src)/share/native/java/lang/Double.c \ $(openjdk-src)/share/native/java/lang/Float.c \ $(openjdk-src)/share/native/java/lang/Object.c \ $(openjdk-src)/share/native/java/lang/Package.c \ $(openjdk-src)/share/native/java/lang/ref/Finalizer.c \ $(openjdk-src)/share/native/java/lang/reflect/Array.c \ $(openjdk-src)/share/native/java/lang/reflect/Proxy.c \ $(openjdk-src)/share/native/java/lang/ResourceBundle.c \ $(openjdk-src)/share/native/java/lang/Runtime.c \ $(openjdk-src)/share/native/java/lang/SecurityManager.c \ $(openjdk-src)/share/native/java/lang/Shutdown.c \ $(openjdk-src)/share/native/java/lang/StrictMath.c \ $(openjdk-src)/share/native/java/lang/String.c \ $(openjdk-src)/share/native/java/lang/System.c \ $(openjdk-src)/share/native/java/lang/Thread.c \ $(openjdk-src)/share/native/java/lang/Throwable.c \ $(wildcard $(openjdk-src)/share/native/java/lang/fdlibm/src/*.c) \ $(openjdk-src)/share/native/java/net/DatagramPacket.c \ $(openjdk-src)/share/native/java/net/InetAddress.c \ $(openjdk-src)/share/native/java/net/Inet4Address.c \ $(openjdk-src)/share/native/java/net/Inet6Address.c \ $(openjdk-src)/share/native/java/nio/Bits.c \ $(openjdk-src)/share/native/java/security/AccessController.c \ $(openjdk-src)/share/native/java/sql/DriverManager.c \ $(openjdk-src)/share/native/java/util/concurrent/atomic/AtomicLong.c \ $(openjdk-src)/share/native/java/util/TimeZone.c \ $(openjdk-src)/share/native/java/util/zip/Adler32.c \ $(openjdk-src)/share/native/java/util/zip/CRC32.c \ $(openjdk-src)/share/native/java/util/zip/Deflater.c \ $(openjdk-src)/share/native/java/util/zip/Inflater.c \ $(openjdk-src)/share/native/java/util/zip/ZipFile.c \ $(openjdk-src)/share/native/java/util/zip/zip_util.c \ $(openjdk-src)/share/native/sun/management/VMManagementImpl.c \ $(openjdk-src)/share/native/sun/misc/GC.c \ $(openjdk-src)/share/native/sun/misc/MessageUtils.c \ $(openjdk-src)/share/native/sun/misc/NativeSignalHandler.c \ $(openjdk-src)/share/native/sun/misc/Signal.c \ $(openjdk-src)/share/native/sun/misc/Version.c \ $(openjdk-src)/share/native/sun/misc/VM.c \ $(openjdk-src)/share/native/sun/misc/VMSupport.c \ $(openjdk-src)/share/native/sun/reflect/ConstantPool.c \ $(openjdk-src)/share/native/sun/reflect/NativeAccessors.c \ $(openjdk-src)/share/native/sun/reflect/Reflection.c openjdk-headers-classes = \ java.io.Console \ java.io.FileDescriptor \ java.io.FileInputStream \ java.io.FileOutputStream \ java.io.FileSystem \ java.io.ObjectInputStream \ java.io.ObjectOutputStream \ java.io.ObjectStreamClass \ java.io.RandomAccessFile \ java.lang.Class \ java.lang.ClassLoader \ java.lang.Compiler \ java.lang.Double \ java.lang.Float \ java.lang.Integer \ java.lang.Long \ java.lang.Object \ java.lang.Package \ java.lang.Runtime \ java.lang.SecurityManager \ java.lang.Shutdown \ java.lang.StrictMath \ java.lang.String \ java.lang.System \ java.lang.Thread \ java.lang.Throwable \ java.lang.ref.Finalizer \ java.lang.reflect.Array \ java.lang.reflect.Proxy \ java.net.InetAddress \ java.net.Inet4Address \ java.net.Inet6Address \ java.net.DatagramPacket \ java.net.SocketOptions \ java.net.InetAddressImplFactory \ java.net.Inet4AddressImpl \ java.net.Inet6AddressImpl \ java.net.NetworkInterface \ java.net.PlainSocketImpl \ java.net.SocketInputStream \ java.net.SocketOutputStream \ java.nio.MappedByteBuffer \ java.security.AccessController \ java.util.ResourceBundle \ java.util.TimeZone \ java.util.concurrent.atomic.AtomicLong \ java.util.jar.JarFile \ java.util.zip.Adler32 \ java.util.zip.CRC32 \ java.util.zip.Deflater \ java.util.zip.Inflater \ java.util.zip.ZipEntry \ java.util.zip.ZipFile \ sun.management.VMManagementImpl \ sun.misc.GC \ sun.misc.MessageUtils \ sun.misc.NativeSignalHandler \ sun.misc.Signal \ sun.misc.VM \ sun.misc.VMSupport \ sun.misc.Version \ sun.net.spi.DefaultProxySelector \ sun.nio.ch.FileKey \ sun.nio.ch.FileChannelImpl \ sun.nio.ch.FileDispatcherImpl \ sun.nio.ch.DatagramChannelImpl \ sun.nio.ch.DatagramDispatcher \ sun.nio.ch.IOStatus \ sun.nio.ch.IOUtil \ sun.nio.ch.Net \ sun.nio.ch.ServerSocketChannelImpl \ sun.nio.ch.SocketChannelImpl \ sun.nio.ch.SocketDispatcher \ sun.nio.ch.PollArrayWrapper \ sun.nio.ch.NativeThread \ sun.reflect.ConstantPool \ sun.reflect.NativeConstructorAccessorImpl \ sun.reflect.NativeMethodAccessorImpl \ sun.reflect.Reflection \ sun.security.provider.NativeSeedGenerator # todo: set properties according to architecture targeted and OpenJDK # version used: openjdk-cflags = \ "-I$(src)/openjdk" \ "-I$(build)/openjdk" \ "-I$(openjdk-src)/share/javavm/export" \ "-I$(openjdk-src)/share/native/common" \ "-I$(openjdk-src)/share/native/java/io" \ "-I$(openjdk-src)/share/native/java/lang" \ "-I$(openjdk-src)/share/native/java/lang/fdlibm/include" \ "-I$(openjdk-src)/share/native/java/net" \ "-I$(openjdk-src)/share/native/java/util/zip" \ "-I$(openjdk-src)/share/native/sun/management" \ "-I$(openjdk-src)/share/native/sun/nio/ch" \ "-I$(openjdk-src)/share/javavm/include" \ -D_LITTLE_ENDIAN \ -DARCHPROPNAME=\"x86\" \ -DRELEASE=\"1.6.0\" \ -DJDK_MAJOR_VERSION=\"1\" \ -DJDK_MINOR_VERSION=\"6\" \ -DJDK_MICRO_VERSION=\"0\" \ -DJDK_BUILD_NUMBER=\"0\" \ -D_GNU_SOURCE ifeq ($(platform),darwin) openjdk-cflags += \ -D_LFS_LARGEFILE=1 \ -D_ALLBSD_SOURCE endif ifeq ($(platform),windows) openjdk-sources += \ $(openjdk-src)/windows/native/common/jni_util_md.c \ $(openjdk-src)/windows/native/java/io/canonicalize_md.c \ $(openjdk-src)/windows/native/java/io/Console_md.c \ $(openjdk-src)/windows/native/java/io/FileDescriptor_md.c \ $(openjdk-src)/windows/native/java/io/FileInputStream_md.c \ $(openjdk-src)/windows/native/java/io/FileOutputStream_md.c \ $(openjdk-src)/windows/native/java/io/FileSystem_md.c \ $(openjdk-src)/windows/native/java/io/io_util_md.c \ $(openjdk-src)/windows/native/java/io/RandomAccessFile_md.c \ $(openjdk-src)/windows/native/java/io/Win32FileSystem_md.c \ $(openjdk-src)/windows/native/java/io/WinNTFileSystem_md.c \ $(openjdk-src)/windows/native/java/lang/java_props_md.c \ $(openjdk-src)/windows/native/java/lang/ProcessEnvironment_md.c \ $(openjdk-src)/windows/native/java/lang/ProcessImpl_md.c \ $(openjdk-src)/windows/native/java/net/net_util_md.c \ $(openjdk-src)/windows/native/java/net/DualStackPlainSocketImpl.c \ $(openjdk-src)/windows/native/java/net/InetAddressImplFactory.c \ $(openjdk-src)/windows/native/java/net/Inet4AddressImpl.c \ $(openjdk-src)/windows/native/java/net/Inet6AddressImpl.c \ $(openjdk-src)/windows/native/java/net/NetworkInterface.c \ $(openjdk-src)/windows/native/java/net/NetworkInterface_winXP.c \ $(openjdk-src)/windows/native/java/net/SocketInputStream.c \ $(openjdk-src)/windows/native/java/net/SocketOutputStream.c \ $(openjdk-src)/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c \ $(openjdk-src)/windows/native/java/net/TwoStacksPlainSocketImpl.c \ $(openjdk-src)/windows/native/java/util/WindowsPreferences.c \ $(openjdk-src)/windows/native/java/util/logging.c \ $(openjdk-src)/windows/native/java/util/TimeZone_md.c \ $(openjdk-src)/windows/native/sun/io/Win32ErrorMode.c \ $(openjdk-src)/windows/native/sun/nio/ch/DatagramChannelImpl.c \ $(openjdk-src)/windows/native/sun/nio/ch/DatagramDispatcher.c \ $(openjdk-src)/windows/native/sun/nio/ch/FileChannelImpl.c \ $(openjdk-src)/windows/native/sun/nio/ch/FileDispatcherImpl.c \ $(openjdk-src)/windows/native/sun/nio/ch/FileKey.c \ $(openjdk-src)/windows/native/sun/nio/ch/IOUtil.c \ $(openjdk-src)/windows/native/sun/nio/ch/Net.c \ $(openjdk-src)/windows/native/sun/nio/ch/ServerSocketChannelImpl.c \ $(openjdk-src)/windows/native/sun/nio/ch/SocketChannelImpl.c \ $(openjdk-src)/windows/native/sun/nio/ch/SocketDispatcher.c \ $(openjdk-src)/windows/native/sun/nio/ch/WindowsSelectorImpl.c \ $(openjdk-src)/windows/native/sun/nio/fs/WindowsNativeDispatcher.c \ $(openjdk-src)/windows/native/sun/security/provider/WinCAPISeedGenerator.c openjdk-headers-classes += \ java.net.DualStackPlainSocketImpl \ java.net.SocketImpl \ java.net.TwoStacksPlainDatagramSocketImpl \ java.net.TwoStacksPlainSocketImpl \ java.lang.ProcessImpl \ sun.io.Win32ErrorMode \ sun.nio.ch.WindowsSelectorImpl \ sun.nio.fs.WindowsNativeDispatcher \ openjdk-cflags += \ "-I$(openjdk-src)/windows/javavm/export" \ "-I$(openjdk-src)/windows/native/common" \ "-I$(openjdk-src)/windows/native/java/io" \ "-I$(openjdk-src)/windows/native/java/net" \ "-I$(openjdk-src)/windows/native/java/util" \ "-I$(openjdk-src)/windows/native/sun/nio/ch" \ "-I$(openjdk-src)/windows/javavm/include" \ "-I$(root)/win32/include" \ -DLOCALE_SNAME=0x0000005c \ -DLOCALE_SISO3166CTRYNAME2=0x00000068 \ -DLOCALE_SISO639LANGNAME2=0x00000067 \ -D_JNI_IMPLEMENTATION_ \ -D_JAVASOFT_WIN32_TYPEDEF_MD_H_ \ -Ds6_words=_s6_words \ -Ds6_bytes=_s6_bytes else openjdk-sources += \ $(shell find $(openjdk-src)/solaris/native/common -name '*.c') \ $(openjdk-src)/solaris/native/java/io/canonicalize_md.c \ $(openjdk-src)/solaris/native/java/io/Console_md.c \ $(openjdk-src)/solaris/native/java/io/FileDescriptor_md.c \ $(openjdk-src)/solaris/native/java/io/FileInputStream_md.c \ $(openjdk-src)/solaris/native/java/io/FileOutputStream_md.c \ $(openjdk-src)/solaris/native/java/io/FileSystem_md.c \ $(openjdk-src)/solaris/native/java/io/io_util_md.c \ $(openjdk-src)/solaris/native/java/io/RandomAccessFile_md.c \ $(openjdk-src)/solaris/native/java/io/UnixFileSystem_md.c \ $(openjdk-src)/solaris/native/java/lang/java_props_md.c \ $(openjdk-src)/solaris/native/java/lang/ProcessEnvironment_md.c \ $(openjdk-src)/solaris/native/java/lang/UNIXProcess_md.c \ $(openjdk-src)/solaris/native/java/net/net_util_md.c \ $(openjdk-src)/solaris/native/java/net/InetAddressImplFactory.c \ $(openjdk-src)/solaris/native/java/net/Inet4AddressImpl.c \ $(openjdk-src)/solaris/native/java/net/Inet6AddressImpl.c \ $(openjdk-src)/solaris/native/java/net/NetworkInterface.c \ $(openjdk-src)/solaris/native/java/net/PlainSocketImpl.c \ $(openjdk-src)/solaris/native/java/net/PlainDatagramSocketImpl.c \ $(openjdk-src)/solaris/native/java/net/SocketInputStream.c \ $(openjdk-src)/solaris/native/java/net/SocketOutputStream.c \ $(openjdk-src)/solaris/native/java/nio/MappedByteBuffer.c \ $(openjdk-src)/solaris/native/java/util/FileSystemPreferences.c \ $(openjdk-src)/solaris/native/java/util/logging.c \ $(openjdk-src)/solaris/native/java/util/TimeZone_md.c \ $(openjdk-src)/solaris/native/sun/net/dns/ResolverConfigurationImpl.c \ $(openjdk-src)/solaris/native/sun/net/spi/DefaultProxySelector.c \ $(openjdk-src)/solaris/native/sun/nio/ch/DatagramChannelImpl.c \ $(openjdk-src)/solaris/native/sun/nio/ch/DatagramDispatcher.c \ $(openjdk-src)/solaris/native/sun/nio/ch/FileChannelImpl.c \ $(openjdk-src)/solaris/native/sun/nio/ch/FileDispatcherImpl.c \ $(openjdk-src)/solaris/native/sun/nio/ch/FileKey.c \ $(openjdk-src)/solaris/native/sun/nio/ch/IOUtil.c \ $(openjdk-src)/solaris/native/sun/nio/ch/Net.c \ $(openjdk-src)/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c \ $(openjdk-src)/solaris/native/sun/nio/ch/SocketChannelImpl.c \ $(openjdk-src)/solaris/native/sun/nio/ch/SocketDispatcher.c \ $(openjdk-src)/solaris/native/sun/nio/ch/PollArrayWrapper.c \ $(openjdk-src)/solaris/native/sun/nio/ch/InheritedChannel.c \ $(openjdk-src)/solaris/native/sun/nio/ch/NativeThread.c \ $(openjdk-src)/solaris/native/sun/nio/fs/UnixNativeDispatcher.c \ openjdk-headers-classes += \ java.net.PlainDatagramSocketImpl \ java.io.UnixFileSystem \ sun.nio.ch.InheritedChannel \ sun.nio.fs.UnixNativeDispatcher \ openjdk-cflags += \ "-I$(openjdk-src)/solaris/javavm/export" \ "-I$(openjdk-src)/solaris/native/common" \ "-I$(openjdk-src)/solaris/native/java/io" \ "-I$(openjdk-src)/solaris/native/java/lang" \ "-I$(openjdk-src)/solaris/native/java/net" \ "-I$(openjdk-src)/solaris/native/java/util" \ "-I$(openjdk-src)/solaris/native/sun/management" \ "-I$(openjdk-src)/solaris/native/sun/nio/ch" \ "-I$(openjdk-src)/solaris/javavm/include" \ "-I$(openjdk-src)/solaris/hpi/include" \ "-I$(openjdk-src)/solaris/native/common/deps" ifeq ($(platform),linux) openjdk-sources += \ $(openjdk-src)/solaris/native/java/net/linux_close.c \ $(openjdk-src)/solaris/native/sun/nio/ch/EPollArrayWrapper.c openjdk-headers-classes += \ sun.nio.ch.EPollArrayWrapper openjdk-cflags += \ "-I$(openjdk-src)/solaris/native/common/deps/glib2" \ "-I$(openjdk-src)/solaris/native/common/deps/gconf2" \ "-I$(openjdk-src)/solaris/native/common/deps/fontconfig2" \ "-I$(openjdk-src)/solaris/native/common/deps/gtk2" \ $(shell pkg-config --cflags glib-2.0) \ $(shell pkg-config --cflags gconf-2.0) endif ifeq ($(platform),darwin) openjdk-sources += \ $(openjdk-src)/solaris/native/java/net/bsd_close.c ifeq ($(ios),true) openjdk-local-sources += \ $(src)/openjdk/my_java_props_macosx.c else openjdk-sources += \ $(openjdk-src)/solaris/native/java/lang/java_props_macosx.c \ $(openjdk-src)/macosx/native/sun/nio/ch/KQueueArrayWrapper.c endif openjdk-cflags += \ -DMACOSX endif endif openjdk-local-sources += \ $(src)/openjdk/my_net_util.c \ $(src)/openjdk/my_management.c openjdk-c-objects = \ $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%-openjdk.o,$(x))) openjdk-objects = \ $(call openjdk-c-objects,$(openjdk-sources),$(openjdk-src),$(build)/openjdk) openjdk-local-objects = \ $(call openjdk-c-objects,$(openjdk-local-sources),$(src)/openjdk,$(build)/openjdk) openjdk-headers-dep = $(build)/openjdk/headers.dep ReadyTalk-avian-1e1fff5/openjdk.ld000066400000000000000000000246241231440243200171430ustar00rootroot00000000000000# # @(#)mapfile-vers-product 1.19 08/02/12 10:56:37 # # # Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 only, as # published by the Free Software Foundation. # # This code is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # version 2 for more details (a copy is included in the LICENSE file that # accompanied this code). # # You should have received a copy of the GNU General Public License version # 2 along with this work; if not, write to the Free Software Foundation, # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. # # Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. # # # Define public interface. SUNWprivate_1.1 { global: # JNI JNI_CreateJavaVM; JNI_GetCreatedJavaVMs; JNI_GetDefaultJavaVMInitArgs; # JVM JVM_Accept; JVM_ActiveProcessorCount; JVM_AllocateNewArray; JVM_AllocateNewObject; JVM_ArrayCopy; JVM_AssertionStatusDirectives; JVM_Available; JVM_Bind; JVM_ClassDepth; JVM_ClassLoaderDepth; JVM_Clone; JVM_Close; JVM_CX8Field; JVM_CompileClass; JVM_CompileClasses; JVM_CompilerCommand; JVM_Connect; JVM_ConstantPoolGetClassAt; JVM_ConstantPoolGetClassAtIfLoaded; JVM_ConstantPoolGetDoubleAt; JVM_ConstantPoolGetFieldAt; JVM_ConstantPoolGetFieldAtIfLoaded; JVM_ConstantPoolGetFloatAt; JVM_ConstantPoolGetIntAt; JVM_ConstantPoolGetLongAt; JVM_ConstantPoolGetMethodAt; JVM_ConstantPoolGetMethodAtIfLoaded; JVM_ConstantPoolGetMemberRefInfoAt; JVM_ConstantPoolGetSize; JVM_ConstantPoolGetStringAt; JVM_ConstantPoolGetUTF8At; JVM_CountStackFrames; JVM_CurrentClassLoader; JVM_CurrentLoadedClass; JVM_CurrentThread; JVM_CurrentTimeMillis; JVM_DefineClass; JVM_DefineClassWithSource; JVM_DesiredAssertionStatus; JVM_DisableCompiler; JVM_DoPrivileged; JVM_DTraceGetVersion; JVM_DTraceActivate; JVM_DTraceIsProbeEnabled; JVM_DTraceIsSupported; JVM_DTraceDispose; JVM_DumpAllStacks; JVM_DumpThreads; JVM_EnableCompiler; JVM_Exit; JVM_FillInStackTrace; JVM_FindClassFromClass; JVM_FindClassFromClassLoader; JVM_FindClassFromBootLoader; JVM_FindLibraryEntry; JVM_FindLoadedClass; JVM_FindPrimitiveClass; JVM_FindSignal; JVM_FreeMemory; JVM_GC; JVM_GetAllThreads; JVM_GetArrayElement; JVM_GetArrayLength; JVM_GetCPClassNameUTF; JVM_GetCPFieldClassNameUTF; JVM_GetCPFieldModifiers; JVM_GetCPFieldNameUTF; JVM_GetCPFieldSignatureUTF; JVM_GetCPMethodClassNameUTF; JVM_GetCPMethodModifiers; JVM_GetCPMethodNameUTF; JVM_GetCPMethodSignatureUTF; JVM_GetCallerClass; JVM_GetClassAccessFlags; JVM_GetClassAnnotations; JVM_GetClassCPEntriesCount; JVM_GetClassCPTypes; JVM_GetClassConstantPool; JVM_GetClassContext; JVM_GetClassDeclaredConstructors; JVM_GetClassDeclaredFields; JVM_GetClassDeclaredMethods; JVM_GetClassFieldsCount; JVM_GetClassInterfaces; JVM_GetClassLoader; JVM_GetClassMethodsCount; JVM_GetClassModifiers; JVM_GetClassName; JVM_GetClassNameUTF; JVM_GetClassSignature; JVM_GetClassSigners; JVM_GetComponentType; JVM_GetDeclaredClasses; JVM_GetDeclaringClass; JVM_GetEnclosingMethodInfo; JVM_GetFieldAnnotations; JVM_GetFieldIxModifiers; JVM_GetHostName; JVM_GetInheritedAccessControlContext; JVM_GetInterfaceVersion; JVM_GetLastErrorString; JVM_GetManagement; JVM_GetMethodAnnotations; JVM_GetMethodDefaultAnnotationValue; JVM_GetMethodIxArgsSize; JVM_GetMethodIxByteCode; JVM_GetMethodIxByteCodeLength; JVM_GetMethodIxExceptionIndexes; JVM_GetMethodIxExceptionTableEntry; JVM_GetMethodIxExceptionTableLength; JVM_GetMethodIxExceptionsCount; JVM_GetMethodIxLocalsCount; JVM_GetMethodIxMaxStack; JVM_GetMethodIxModifiers; JVM_GetMethodIxNameUTF; JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameterAnnotations; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetSockName; JVM_GetSockOpt; JVM_GetStackAccessControlContext; JVM_GetStackTraceDepth; JVM_GetStackTraceElement; JVM_GetSystemPackage; JVM_GetSystemPackages; JVM_GetThreadStateNames; JVM_GetThreadStateValues; JVM_GetVersionInfo; JVM_Halt; JVM_HoldsLock; JVM_IHashCode; JVM_InitAgentProperties; JVM_InitProperties; JVM_InitializeCompiler; JVM_InitializeSocketLibrary; JVM_InternString; JVM_Interrupt; JVM_InvokeMethod; JVM_IsArrayClass; JVM_IsConstructorIx; JVM_IsInterface; JVM_IsInterrupted; JVM_IsNaN; JVM_IsPrimitiveClass; JVM_IsSameClassPackage; JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; JVM_LoadLibrary; JVM_Lseek; JVM_MaxObjectInspectionAge; JVM_MaxMemory; JVM_MonitorNotify; JVM_MonitorNotifyAll; JVM_MonitorWait; JVM_NanoTime; JVM_NativePath; JVM_NewArray; JVM_NewInstanceFromConstructor; JVM_NewMultiArray; JVM_OnExit; JVM_Open; JVM_PrintStackTrace; JVM_RaiseSignal; JVM_RawMonitorCreate; JVM_RawMonitorDestroy; JVM_RawMonitorEnter; JVM_RawMonitorExit; JVM_Read; JVM_Recv; JVM_RecvFrom; JVM_RegisterSignal; JVM_ReleaseUTF; JVM_ResolveClass; JVM_ResumeThread; JVM_Send; JVM_SendTo; JVM_SetArrayElement; JVM_SetClassSigners; JVM_SetLength; JVM_SetPrimitiveArrayElement; JVM_SetProtectionDomain; JVM_SetSockOpt; JVM_SetThreadPriority; JVM_Sleep; JVM_Socket; JVM_SocketAvailable; JVM_SocketClose; JVM_SocketShutdown; JVM_StartThread; JVM_StopThread; JVM_SuspendThread; JVM_SupportsCX8; JVM_Sync; JVM_Timeout; JVM_TotalMemory; JVM_TraceInstructions; JVM_TraceMethodCalls; JVM_UnloadLibrary; JVM_Write; JVM_Yield; JVM_handle_linux_signal; # Old reflection routines # These do not need to be present in the product build in JDK 1.4 # but their code has not been removed yet because there will not # be a substantial code savings until JVM_InvokeMethod and # JVM_NewInstanceFromConstructor can also be removed; see # reflectionCompat.hpp. JVM_GetClassConstructor; JVM_GetClassConstructors; JVM_GetClassField; JVM_GetClassFields; JVM_GetClassMethod; JVM_GetClassMethods; JVM_GetField; JVM_GetPrimitiveField; JVM_NewInstance; JVM_SetField; JVM_SetPrimitiveField; # Needed for dropping VM into JDK 1.3.x, 1.4 _JVM_native_threads; jdk_sem_init; jdk_sem_post; jdk_sem_wait; jdk_pthread_sigmask; jdk_waitpid; # miscellaneous functions jio_fprintf; jio_printf; jio_snprintf; jio_vfprintf; jio_vsnprintf; fork1; numa_warn; numa_error; # Needed because there is no JVM interface for this. sysThreadAvailableStackWithSlack; # This is for Forte Analyzer profiling support. AsyncGetCallTrace; }; ReadyTalk-avian-1e1fff5/openjdk.pro000066400000000000000000000176701231440243200173470ustar00rootroot00000000000000# proguard include file (http://proguard.sourceforge.net) # This file is for use in combination with vm.pro when ProGuarding # OpenJDK-based builds # the following methods and fields are refered to by name in the VM: -keepclassmembers class java.lang.Thread { public void run(); } -keepclassmembers class java.lang.ThreadGroup { void threadTerminated(java.lang.Thread); } -keep class java.lang.System { private static void initializeSystemClass(); public static void setProperties(java.util.Properties); } -keep class sun.misc.Launcher { public static sun.misc.Launcher getLauncher(); } -keep class java.lang.ClassLoader { private static java.lang.ClassLoader scl; private static boolean sclSet; protected ClassLoader(java.lang.ClassLoader); } -keep class avian.SystemClassLoader { protected java.net.URL findResource(java.lang.String); } -keepnames class java.lang.ClassLoader { public java.lang.Class loadClass(java.lang.String); static void loadLibrary(java.lang.Class, java.lang.String, boolean); private static java.net.URL getBootstrapResource(java.lang.String); private static java.util.Enumeration getBootstrapResources(java.lang.String); } -keep class java.util.Properties { public java.lang.Object setProperty(java.lang.String, java.lang.String); public java.lang.String getProperty(java.lang.String); } -keep class java.util.Hashtable { public java.lang.Object remove(java.lang.Object); } -keep class avian.OpenJDK { ; } -keepclassmembers public class java.security.PrivilegedAction { public java.lang.Object run(); } -keepclassmembers public class * implements java.security.PrivilegedAction { public java.lang.Object run(); } -keepclassmembers public class java.security.PrivilegedExceptionAction { public java.lang.Object run(); } -keepclassmembers public class * implements java.security.PrivilegedExceptionAction { public java.lang.Object run(); } -keep public class java.security.PrivilegedActionException { public PrivilegedActionException(java.lang.Exception); } # these class names are used to disambiguate JNI method lookups: -keepnames public class java.net.URL -keepnames public class java.util.Enumeration -keepnames public class java.security.ProtectionDomain -keepnames public class java.security.PrivilegedAction -keepnames public class java.security.PrivilegedExceptionAction -keepnames public class java.security.AccessControlContext # the following methods and fields are refered to by name in the OpenJDK # native code: -keep class java.util.Properties { public java.lang.Object put(java.lang.Object, java.lang.Object); } -keepclassmembers class * { public boolean equals(java.lang.Object); public void wait(); public void notify(); public void notifyAll(); public java.lang.String toString(); } -keepclassmembers class java.lang.String { public String(byte[]); public String(byte[], java.lang.String); public byte[] getBytes(); public byte[] getBytes(java.lang.String); } -keepclassmembers class java.lang.Boolean { public boolean getBoolean(java.lang.String); } -keepclassmembers class java.util.zip.Inflater { long strm; boolean needDict; boolean finished; byte[] buf; int off; int len; } -keepclassmembers class java.io.FileDescriptor { private int fd; private long handle; } -keep class java.net.NetworkInterface { ; } -keep class java.net.InetAddress { ; } -keep class java.net.Inet4Address { ; } -keep class java.net.Inet4AddressImpl -keep class java.net.Inet6Address { ; } -keep class java.net.Inet6AddressImpl -keep class java.net.InetSocketAddress { public InetSocketAddress(java.net.InetAddress, int); } -keep class java.net.ServerSocket -keep class java.net.SocketTimeoutException -keepclassmembers class java.net.PlainSocketImpl { ; } -keepclassmembers class java.net.TwoStacksPlainSocketImpl { *** fd1; *** lastfd; } -keepclassmembers class java.net.AbstractPlainSocketImpl { *** timeout; *** trafficClass; } -keepclassmembers class java.net.SocketImpl { *** serverSocket; *** fd; *** address; *** port; *** localport; } -keepclassmembers class java.io.FileInputStream { private java.io.FileDescriptor fd; } -keepclassmembers class java.io.FileOutputStream { private java.io.FileDescriptor fd; private boolean append; } # changed in native code via sun.misc.Unsafe (todo: handle other # Atomic* classes) -keepclassmembers class java.util.concurrent.atomic.AtomicInteger { private int value; } # avoid inlining due to access check using a fixed offset into call stack: -keep,allowshrinking,allowobfuscation class java.util.concurrent.atomic.AtomicReferenceFieldUpdater { *** newUpdater(...); } # accessed reflectively via an AtomicReferenceFieldUpdater: -keepclassmembers class java.io.BufferedInputStream { protected byte[] buf; } -keep class java.lang.System { public static java.io.InputStream in; public static java.io.PrintStream out; public static java.io.PrintStream err; # avoid inlining due to access check using fixed offset into call stack: static java.lang.Class getCallerClass(); # called from jni_util.c: static java.lang.String getProperty(java.lang.String); } # refered to by name from native code: -keepnames public class java.io.InputStream -keepnames public class java.io.PrintStream # avoid inlining due to access check using fixed offset into call stack: -keep,allowshrinking,allowobfuscation class java.lang.System { static java.lang.Class getCallerClass(); } -keep class java.io.UnixFileSystem { public UnixFileSystem(); } -keep class java.io.WinNTFileSystem { public WinNTFileSystem(); } -keep class java.io.File { private java.lang.String path; } -keepclassmembers class java.lang.ClassLoader$NativeLibrary { long handle; private int jniVersion; } -keep class java.nio.charset.Charset { # called from jni_util.c: boolean isSupported(java.lang.String); } # Charsets are loaded via reflection. If you need others besides # UTF-8, you'll need to add them (e.g. sun.nio.cs.ISO_8859_1). -keep class sun.nio.cs.UTF_8 # loaded reflectively to handle embedded resources: -keep class avian.avianvmresource.Handler # refered to symbolically in MethodAccessorGenerator: -keep class sun.reflect.MethodAccessorImpl { ; } -keep class sun.reflect.ConstructorAccessorImpl { ; } -keep class sun.reflect.SerializationConstructorAccessorImpl { ; } # referred to by name in LocaleData to load resources: -keep class sun.util.resources.CalendarData -keep class sun.util.resources.TimeZoneNames -keep class sun.text.resources.FormatData # loaded via reflection from DefaultFileSystemProvider: -keep class sun.nio.fs.LinuxFileSystemProvider -keep class sun.nio.fs.BsdFileSystemProvider # loaded via JNI in UnixNativeDispatcher.c: -keep class sun.nio.fs.UnixFileAttributes { ; } -keep class sun.nio.fs.UnixFileStoreAttributes { ; } -keep class sun.nio.fs.UnixMountEntry { ; } -keep class sun.nio.fs.UnixException { UnixException(int); } -keep class sun.net.www.protocol.jar.Handler # These concurrent classes refer to certain members reflectively in their static initializers -keepclassmembers class java.util.concurrent.ConcurrentHashMap$HashEntry { *** next; } -keepclassmembers class java.util.concurrent.CopyOnWriteArrayList { *** lock; } -keepclassmembers class java.util.concurrent.CountDownLatch { *** allocationSpinLock; } -keepclassmembers class java.util.concurrent.PriorityBlockingQueue { *** allocationSpinLock; } -keepclassmembers class java.util.concurrent.SynchronousQueue$TransferStack { *** head; } -keepclassmembers class java.util.concurrent.ConcurrentLinkedQueue { *** head; *** tail; } -keepclassmembers class java.util.concurrent.ConcurrentLinkedQueue$Node { *** item; *** next; } -keepclassmembers class java.util.concurrent.SynchronousQueue$TransferStack$SNode { *** match; *** next; } ReadyTalk-avian-1e1fff5/src/000077500000000000000000000000001231440243200157475ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/android/000077500000000000000000000000001231440243200173675ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/android/stubs.cpp000066400000000000000000000003121231440243200212270ustar00rootroot00000000000000struct JavaVM; extern "C" int JNI_OnLoad(JavaVM*, void*) { return 0; } struct _JNIEnv; struct JniConstants { static void init(_JNIEnv* env); }; void JniConstants::init(_JNIEnv*) { // ignore } ReadyTalk-avian-1e1fff5/src/arm.S000066400000000000000000000051731231440243200166600ustar00rootroot00000000000000/* arm.S: JNI gluecode for ARM Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/types.h" .text #define LOCAL(x) .L##x #ifdef __APPLE__ # define GLOBAL(x) _##x #else # define GLOBAL(x) x #endif .globl GLOBAL(vmNativeCall) .align 2 GLOBAL(vmNativeCall): /* arguments: r0 -> r4 : function r1 -> r5 : stackTotal r2 : memoryTable r3 : memoryCount [sp, #0] -> r6 : gprTable [sp, #4] -> r7 : vfpTable [sp, #8] -> r8 : returnType */ mov ip, sp // save stack frame stmfd sp!, {r4-r8, lr} // save clobbered non-volatile regs // mv args into non-volatile regs mov r4, r0 mov r5, r1 ldr r6, [ip] ldr r7, [ip, #4] ldr r8, [ip, #8] // setup stack arguments if necessary sub sp, sp, r5 // allocate stack mov ip, sp LOCAL(loop): tst r3, r3 ldrne r0, [r2], #4 strne r0, [ip], #4 subne r3, r3, #4 bne LOCAL(loop) // setup argument registers if necessary tst r6, r6 #if (defined __APPLE__) && (defined __clang_major__) && (__clang_major__ >= 4) ldmiane r6, {r0-r3} #else ldmneia r6, {r0-r3} #endif #if defined(__ARM_PCS_VFP) // and VFP registers vldmia r7, {d0-d7} #endif #if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) mov lr, pc bx r4 #else blx r4 // call function #endif add sp, sp, r5 // deallocate stack #if defined(__ARM_PCS_VFP) cmp r8,#FLOAT_TYPE bne LOCAL(double) fmrs r0,s0 b LOCAL(exit) LOCAL(double): cmp r8,#DOUBLE_TYPE bne LOCAL(exit) fmrrd r0,r1,d0 #endif LOCAL(exit): ldmfd sp!, {r4-r8, pc} // restore non-volatile regs and return .globl GLOBAL(vmJump) .align 2 GLOBAL(vmJump): mov lr, r0 ldr r0, [sp] ldr r1, [sp, #4] mov sp, r2 mov r8, r3 bx lr #define CHECKPOINT_THREAD 4 #define CHECKPOINT_STACK 24 .globl GLOBAL(vmRun) .align 2 GLOBAL(vmRun): // r0: function // r1: arguments // r2: checkpoint stmfd sp!, {r4-r11, lr} // align stack sub sp, sp, #12 str sp, [r2, #CHECKPOINT_STACK] mov r12, r0 ldr r0, [r2, #CHECKPOINT_THREAD] #if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) mov lr, pc bx r12 #else blx r12 #endif .globl GLOBAL(vmRun_returnAddress) .align 2 GLOBAL(vmRun_returnAddress): add sp, sp, #12 ldmfd sp!, {r4-r11, lr} bx lr ReadyTalk-avian-1e1fff5/src/arm.masm000066400000000000000000000033621231440243200174110ustar00rootroot00000000000000; Copyright (c) 2008-2013, Avian Contributors ; ; Permission to use, copy, modify, and/or distribute this software ; for any purpose with or without fee is hereby granted, provided ; that the above copyright notice and this permission notice appear ; in all copies. ; ; There is NO WARRANTY for this software. See license.txt for ; details. ; ; ORIGIN: https://github.com/gkvas/avian/tree/wince AREA text, CODE, ARM EXPORT vmNativeCall vmNativeCall ; arguments: ; r0 -> r4 : function ; r1 -> r5 : stackTotal ; r2 : memoryTable ; r3 : memoryCount ; [sp, #0] -> r6 : gprTable mov ip, sp ; save stack frame stmfd sp!, {r4-r6, lr} ; save clobbered non-volatile regs ; mv args into non-volatile regs mov r4, r0 mov r5, r1 ldr r6, [ip] ; setup stack arguments if necessary sub sp, sp, r5 ; allocate stack mov ip, sp loop tst r3, r3 ldrne r0, [r2], #4 strne r0, [ip], #4 subne r3, r3, #4 bne loop ; setup argument registers if necessary tst r6, r6 ldmneia r6, {r0-r3} blx r4 ; call function add sp, sp, r5 ; deallocate stack ldmfd sp!, {r4-r6, pc} ; restore non-volatile regs and return EXPORT vmJump vmJump mov lr, r0 ldr r0, [sp] ldr r1, [sp, #4] mov sp, r2 mov r8, r3 bx lr CHECKPOINT_THREAD EQU 4 CHECKPOINT_STACK EQU 24 EXPORT vmRun vmRun ; r0: function ; r1: arguments ; r2: checkpoint stmfd sp!, {r4-r11, lr} ; align stack sub sp, sp, #12 str sp, [r2, #CHECKPOINT_STACK] mov r12, r0 ldr r0, [r2, #CHECKPOINT_THREAD] blx r12 EXPORT vmRun_returnAddress vmRun_returnAddress add sp, sp, #12 ldmfd sp!, {r4-r11, lr} bx lr EXPORT vmTrap vmTrap bkpt 3 ENDReadyTalk-avian-1e1fff5/src/avian/000077500000000000000000000000001231440243200170455ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/avian/alloc-vector.h000066400000000000000000000065011231440243200216120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef VECTOR_H #define VECTOR_H #include #include #include #include #include #undef max #undef min namespace vm { class Vector { public: Vector(avian::util::Aborter* a, avian::util::Allocator* allocator, size_t minimumCapacity) : a(a), allocator(allocator), data(0, 0), position(0), minimumCapacity(minimumCapacity) { } ~Vector() { dispose(); } void dispose() { if (data.items and minimumCapacity > 0) { allocator->free(data.items, data.count); data.items = 0; data.count = 0; } } void ensure(size_t space) { if (position + space > data.count) { assert(a, minimumCapacity > 0); size_t newCapacity = avian::util::max( position + space, avian::util::max(minimumCapacity, data.count * 2)); if (data.begin()) { data.resize(allocator, newCapacity); } else { data = avian::util::Slice::alloc(allocator, newCapacity); } } } void get(size_t offset, void* dst, size_t size) { assert(a, offset + size <= position); memcpy(dst, data.begin() + offset, size); } void set(size_t offset, const void* src, size_t size) { assert(a, offset + size <= position); memcpy(data.begin() + offset, src, size); } void pop(void* dst, size_t size) { get(position - size, dst, size); position -= size; } void* allocate(size_t size) { ensure(size); void* r = data.begin() + position; position += size; return r; } void* append(const void* p, size_t size) { void* r = allocate(size); memcpy(r, p, size); return r; } void append(uint8_t v) { append(&v, 1); } void append2(uint16_t v) { append(&v, 2); } void append4(uint32_t v) { append(&v, 4); } void appendTargetAddress(target_uintptr_t v) { append(&v, TargetBytesPerWord); } void appendAddress(uintptr_t v) { append(&v, BytesPerWord); } void appendAddress(void* v) { append(&v, BytesPerWord); } void set2(size_t offset, uint16_t v) { assert(a, offset <= position - 2); memcpy(data.begin() + offset, &v, 2); } size_t get(size_t offset) { uint8_t v; get(offset, &v, 1); return v; } size_t get2(size_t offset) { uint16_t v; get(offset, &v, 2); return v; } size_t get4(size_t offset) { uint32_t v; get(offset, &v, 4); return v; } uintptr_t getAddress(size_t offset) { uintptr_t v; get(offset, &v, BytesPerWord); return v; } size_t length() { return position; } template T* peek(size_t offset) { assert(a, offset + sizeof(T) <= position); return reinterpret_cast(data.begin() + offset); } avian::util::Aborter* a; avian::util::Allocator* allocator; avian::util::Slice data; size_t position; size_t minimumCapacity; }; } // namespace vm #endif//VECTOR_H ReadyTalk-avian-1e1fff5/src/avian/append.h000066400000000000000000000026771231440243200205010ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef APPEND_H #define APPEND_H #include #include namespace vm { inline const char* append(avian::util::Allocator* allocator, const char* a, const char* b, const char* c) { unsigned al = strlen(a); unsigned bl = strlen(b); unsigned cl = strlen(c); char* p = static_cast(allocator->allocate((al + bl + cl) + 1)); memcpy(p, a, al); memcpy(p + al, b, bl); memcpy(p + al + bl, c, cl + 1); return p; } inline const char* append(avian::util::Allocator* allocator, const char* a, const char* b) { unsigned al = strlen(a); unsigned bl = strlen(b); char* p = static_cast(allocator->allocate((al + bl) + 1)); memcpy(p, a, al); memcpy(p + al, b, bl + 1); return p; } inline const char* copy(avian::util::Allocator* allocator, const char* a) { unsigned al = strlen(a); char* p = static_cast(allocator->allocate(al + 1)); memcpy(p, a, al + 1); return p; } } // namespace vm #endif // APPEND_H ReadyTalk-avian-1e1fff5/src/avian/arch.h000066400000000000000000000021071231440243200201330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef ARCH_H #define ARCH_H #ifdef _MSC_VER # include "windows.h" # pragma push_macro("assert") # include "intrin.h" # pragma pop_macro("assert") # undef interface #endif #include "avian/common.h" extern "C" void NO_RETURN vmJump(void* address, void* frame, void* stack, void* thread, uintptr_t returnLow, uintptr_t returnHigh); namespace vm { inline void compileTimeMemoryBarrier() { #ifdef _MSC_VER _ReadWriteBarrier(); #else __asm__ __volatile__("": : :"memory"); #endif } } // namespace vm #if (defined ARCH_x86_32) || (defined ARCH_x86_64) # include "x86.h" #elif defined ARCH_powerpc # include "powerpc.h" #elif defined ARCH_arm # include "arm.h" #else # error unsupported architecture #endif #endif//ARCH_H ReadyTalk-avian-1e1fff5/src/avian/arm.h000066400000000000000000000200061231440243200177730ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef ARM_H #define ARM_H #include "avian/types.h" #include "avian/common.h" #include #ifdef __APPLE__ # include "libkern/OSAtomic.h" # include "libkern/OSCacheControl.h" # include "mach/mach_types.h" # include "mach/thread_act.h" # include "mach/thread_status.h" # define THREAD_STATE ARM_THREAD_STATE # define THREAD_STATE_TYPE arm_thread_state_t # define THREAD_STATE_COUNT ARM_THREAD_STATE_COUNT # if __DARWIN_UNIX03 && defined(_STRUCT_ARM_EXCEPTION_STATE) # define FIELD(x) __##x # else # define FIELD(x) x # endif # define THREAD_STATE_IP(state) ((state).FIELD(pc)) # define THREAD_STATE_STACK(state) ((state).FIELD(sp)) # define THREAD_STATE_THREAD(state) ((state).FIELD(r[8])) # define THREAD_STATE_LINK(state) ((state).FIELD(lr)) # define IP_REGISTER(context) \ THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) # define STACK_REGISTER(context) \ THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) # define THREAD_REGISTER(context) \ THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) # define LINK_REGISTER(context) \ THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) #elif (defined __QNX__) # include "arm/smpxchg.h" # include "sys/mman.h" # define IP_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_PC]) # define STACK_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_SP]) # define THREAD_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_IP]) # define LINK_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_LR]) #else # define IP_REGISTER(context) (context->uc_mcontext.arm_pc) # define STACK_REGISTER(context) (context->uc_mcontext.arm_sp) # define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip) # define LINK_REGISTER(context) (context->uc_mcontext.arm_lr) #endif #define VA_LIST(x) (&(x)) extern "C" uint64_t vmNativeCall(void* function, unsigned stackTotal, void* memoryTable, unsigned memoryCount, void* gprTable, void* vfpTable, unsigned returnType); namespace vm { inline void trap() { #ifdef _MSC_VER __debugbreak(); #else asm("bkpt"); #endif } // todo: determine the minimal operation types and domains needed to // implement the following barriers (see // http://community.arm.com/groups/processors/blog/2011/10/19/memory-access-ordering-part-3--memory-access-ordering-in-the-arm-architecture). // For now, we just use DMB SY as a conservative but not necessarily // performant choice. #ifndef _MSC_VER inline void memoryBarrier() { #ifdef __APPLE__ OSMemoryBarrier(); #elif (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) return __sync_synchronize(); #elif (! defined AVIAN_ASSUME_ARMV6) __asm__ __volatile__ ("dmb" : : : "memory"); #else __asm__ __volatile__ ("" : : : "memory"); #endif } #endif inline void storeStoreMemoryBarrier() { #ifdef _MSC_VER _ReadWriteBarrier(); #else memoryBarrier(); #endif } inline void storeLoadMemoryBarrier() { #ifdef _MSC_VER MemoryBarrier(); #else memoryBarrier(); #endif } inline void loadMemoryBarrier() { #ifdef _MSC_VER _ReadWriteBarrier(); #else memoryBarrier(); #endif } #if !defined(AVIAN_AOT_ONLY) #if defined(__ANDROID__) // http://code.google.com/p/android/issues/detail?id=1803 extern "C" void __clear_cache (void *beg __attribute__((__unused__)), void *end __attribute__((__unused__))); #endif inline void syncInstructionCache(const void* start, unsigned size) { #ifdef __APPLE__ sys_icache_invalidate(const_cast(start), size); #elif (defined __QNX__) msync(const_cast(start), size, MS_INVALIDATE_ICACHE); #else __clear_cache (const_cast(start), const_cast(static_cast(start) + size)); #endif } #endif // AVIAN_AOT_ONLY #ifndef __APPLE__ typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr); # define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) #endif inline bool atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_) { #ifdef __APPLE__ return OSAtomicCompareAndSwap32Barrier(old, new_, reinterpret_cast(p)); #elif (defined __QNX__) return old == _smp_cmpxchg(p, old, new_); #else int r = __kernel_cmpxchg(static_cast(old), static_cast(new_), reinterpret_cast(p)); return (!r ? true : false); #endif } inline bool atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_) { return atomicCompareAndSwap32(reinterpret_cast(p), old, new_); } inline uint64_t dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, unsigned argumentCount, unsigned argumentsSize UNUSED, unsigned returnType) { #ifdef __APPLE__ const unsigned Alignment = 1; #else const unsigned Alignment = 2; #endif const unsigned GprCount = 4; uintptr_t gprTable[GprCount]; unsigned gprIndex = 0; const unsigned VfpCount = 16; uintptr_t vfpTable[VfpCount]; unsigned vfpIndex = 0; unsigned vfpBackfillIndex UNUSED = 0; RUNTIME_ARRAY(uintptr_t, stack, (argumentCount * 8) / BytesPerWord); // is > argumentSize to account for padding unsigned stackIndex = 0; unsigned ai = 0; for (unsigned ati = 0; ati < argumentCount; ++ ati) { switch (argumentTypes[ati]) { case DOUBLE_TYPE: #if defined(__ARM_PCS_VFP) { if (vfpIndex + Alignment <= VfpCount) { if (vfpIndex % Alignment) { vfpBackfillIndex = vfpIndex; ++ vfpIndex; } memcpy(vfpTable + vfpIndex, arguments + ai, 8); vfpIndex += 8 / BytesPerWord; } else { vfpIndex = VfpCount; if (stackIndex % Alignment) { ++ stackIndex; } memcpy(RUNTIME_ARRAY_BODY(stack) + stackIndex, arguments + ai, 8); stackIndex += 8 / BytesPerWord; } ai += 8 / BytesPerWord; } break; case FLOAT_TYPE: if (vfpBackfillIndex) { vfpTable[vfpBackfillIndex] = arguments[ai]; vfpBackfillIndex = 0; } else if (vfpIndex < VfpCount) { vfpTable[vfpIndex++] = arguments[ai]; } else { RUNTIME_ARRAY_BODY(stack)[stackIndex++] = arguments[ai]; } ++ ai; break; #endif case INT64_TYPE: { if (gprIndex + Alignment <= GprCount) { // pass argument in register(s) if (Alignment == 1 and BytesPerWord < 8 and gprIndex + Alignment == GprCount) { gprTable[gprIndex++] = arguments[ai]; RUNTIME_ARRAY_BODY(stack)[stackIndex++] = arguments[ai + 1]; } else { if (gprIndex % Alignment) { ++gprIndex; } memcpy(gprTable + gprIndex, arguments + ai, 8); gprIndex += 8 / BytesPerWord; } } else { // pass argument on stack gprIndex = GprCount; if (stackIndex % Alignment) { ++stackIndex; } memcpy(RUNTIME_ARRAY_BODY(stack) + stackIndex, arguments + ai, 8); stackIndex += 8 / BytesPerWord; } ai += 8 / BytesPerWord; } break; default: { if (gprIndex < GprCount) { gprTable[gprIndex++] = arguments[ai]; } else { RUNTIME_ARRAY_BODY(stack)[stackIndex++] = arguments[ai]; } ++ ai; } break; } } if (gprIndex < GprCount) { // pad since assembly loads all GPRs memset(gprTable + gprIndex, 0, (GprCount-gprIndex)*4); gprIndex = GprCount; } if (vfpIndex < VfpCount) { memset(vfpTable + vfpIndex, 0, (VfpCount-vfpIndex)*4); vfpIndex = VfpCount; } unsigned stackSize = stackIndex*BytesPerWord + ((stackIndex & 1) << 2); return vmNativeCall (function, stackSize, RUNTIME_ARRAY_BODY(stack), stackIndex * BytesPerWord, (gprIndex ? gprTable : 0), (vfpIndex ? vfpTable : 0), returnType); } } // namespace vm #endif // ARM_H ReadyTalk-avian-1e1fff5/src/avian/bootimage.h000066400000000000000000000030071231440243200211640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef BOOTIMAGE_H #define BOOTIMAGE_H #include "avian/common.h" #include "java-common.h" #include "avian/target.h" #include "avian/machine.h" #include namespace vm { class BootImage { public: class Thunk { public: Thunk(): start(0), frameSavedOffset(0), length(0) { } Thunk(uint32_t start, uint32_t frameSavedOffset, uint32_t length): start(start), frameSavedOffset(frameSavedOffset), length(length) { } uint32_t start; uint32_t frameSavedOffset; uint32_t length; } PACKED; class ThunkCollection { public: #define THUNK_FIELD(name) Thunk name; #include "bootimage-fields.cpp" #undef THUNK_FIELD } PACKED; static const uint32_t Magic = 0x22377322; #define FIELD(name) uint32_t name; #include "bootimage-fields.cpp" #undef FIELD ThunkCollection thunks; } PACKED; class OffsetResolver { public: virtual unsigned fieldOffset(Thread*, object) = 0; }; #define NAME(x) Target##x #define LABEL(x) target_##x #include "bootimage-template.cpp" #undef LABEL #undef NAME #define NAME(x) x #define LABEL(x) x #include "bootimage-template.cpp" #undef LABEL #undef NAME } // namespace vm #endif//BOOTIMAGE_H ReadyTalk-avian-1e1fff5/src/avian/classpath-common.h000066400000000000000000000514621231440243200224760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef CLASSPATH_COMMON_H #define CLASSPATH_COMMON_H #include #include using namespace avian::util; namespace vm { object getTrace(Thread* t, unsigned skipCount) { class Visitor: public Processor::StackVisitor { public: Visitor(Thread* t, int skipCount): t(t), trace(0), skipCount(skipCount) { } virtual bool visit(Processor::StackWalker* walker) { if (skipCount == 0) { object method = walker->method(); if (isAssignableFrom (t, type(t, Machine::ThrowableType), methodClass(t, method)) and vm::strcmp(reinterpret_cast(""), &byteArrayBody(t, methodName(t, method), 0)) == 0) { return true; } else { trace = makeTrace(t, walker); return false; } } else { -- skipCount; return true; } } Thread* t; object trace; unsigned skipCount; } v(t, skipCount); t->m->processor->walkStack(t, &v); if (v.trace == 0) v.trace = makeObjectArray(t, 0); return v.trace; } bool compatibleArrayTypes(Thread* t, object a, object b) { return classArrayElementSize(t, a) and classArrayElementSize(t, b) and (a == b or (not ((classVmFlags(t, a) & PrimitiveFlag) or (classVmFlags(t, b) & PrimitiveFlag)))); } void arrayCopy(Thread* t, object src, int32_t srcOffset, object dst, int32_t dstOffset, int32_t length) { if (LIKELY(src and dst)) { if (LIKELY(compatibleArrayTypes (t, objectClass(t, src), objectClass(t, dst)))) { unsigned elementSize = classArrayElementSize(t, objectClass(t, src)); if (LIKELY(elementSize)) { intptr_t sl = fieldAtOffset(src, BytesPerWord); intptr_t dl = fieldAtOffset(dst, BytesPerWord); if (LIKELY(length > 0)) { if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and dstOffset >= 0 and dstOffset + length <= dl)) { uint8_t* sbody = &fieldAtOffset(src, ArrayBody); uint8_t* dbody = &fieldAtOffset(dst, ArrayBody); if (src == dst) { memmove(dbody + (dstOffset * elementSize), sbody + (srcOffset * elementSize), length * elementSize); } else { memcpy(dbody + (dstOffset * elementSize), sbody + (srcOffset * elementSize), length * elementSize); } if (classObjectMask(t, objectClass(t, dst))) { mark(t, dst, ArrayBody + (dstOffset * BytesPerWord), length); } return; } else { throwNew(t, Machine::IndexOutOfBoundsExceptionType); } } else { return; } } } } else { throwNew(t, Machine::NullPointerExceptionType); return; } throwNew(t, Machine::ArrayStoreExceptionType); } void runOnLoadIfFound(Thread* t, System::Library* library) { void* p = library->resolve("JNI_OnLoad"); #ifdef PLATFORM_WINDOWS if (p == 0) { p = library->resolve("_JNI_OnLoad@8"); if (p == 0) { p = library->resolve("JNI_OnLoad@8"); } } #endif if (p) { jint (JNICALL * JNI_OnLoad)(Machine*, void*); memcpy(&JNI_OnLoad, &p, sizeof(void*)); JNI_OnLoad(t->m, 0); } } System::Library* loadLibrary(Thread* t, const char* name) { ACQUIRE(t, t->m->classLock); System::Library* last = t->m->libraries; for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) { if (lib->name() and ::strcmp(lib->name(), name) == 0) { // already loaded return lib; } last = lib; } System::Library* lib; if (t->m->system->success(t->m->system->load(&lib, name))) { last->setNext(lib); return lib; } else { return 0; } } System::Library* loadLibrary(Thread* t, const char* path, const char* name, bool mapName, bool runOnLoad, bool throw_ = true) { ACQUIRE(t, t->m->classLock); char* mappedName; unsigned nameLength = strlen(name); if (mapName) { const char* builtins = findProperty(t, "avian.builtins"); if (builtins) { const char* s = builtins; while (*s) { if (::strncmp(s, name, nameLength) == 0 and (s[nameLength] == ',' or s[nameLength] == 0)) { // library is built in to this executable if (runOnLoad and not t->m->triedBuiltinOnLoad) { t->m->triedBuiltinOnLoad = true; // todo: release the classLock before calling this to // avoid the possibility of deadlock: runOnLoadIfFound(t, t->m->libraries); } return t->m->libraries; } else { while (*s and *s != ',') ++ s; if (*s) ++ s; } } } const char* prefix = t->m->system->libraryPrefix(); const char* suffix = t->m->system->librarySuffix(); unsigned mappedNameLength = nameLength + strlen(prefix) + strlen(suffix); mappedName = static_cast (t->m->heap->allocate(mappedNameLength + 1)); snprintf(mappedName, mappedNameLength + 1, "%s%s%s", prefix, name, suffix); name = mappedName; nameLength = mappedNameLength; } else { mappedName = 0; } THREAD_RESOURCE2 (t, char*, mappedName, unsigned, nameLength, if (mappedName) { t->m->heap->free(mappedName, nameLength + 1); }); System::Library* lib = 0; for (Tokenizer tokenizer(path, t->m->system->pathSeparator()); tokenizer.hasMore();) { String token(tokenizer.next()); unsigned fullNameLength = token.length + 1 + nameLength; THREAD_RUNTIME_ARRAY(t, char, fullName, fullNameLength + 1); snprintf(RUNTIME_ARRAY_BODY(fullName), fullNameLength + 1, "%.*s/%s", token.length, token.text, name); lib = loadLibrary(t, RUNTIME_ARRAY_BODY(fullName)); if (lib) break; } if (lib == 0) { lib = loadLibrary(t, name); } if (lib) { if (runOnLoad) { runOnLoadIfFound(t, lib); } } else if (throw_) { throwNew(t, Machine::UnsatisfiedLinkErrorType, "library not found: %s", name); } return lib; } object clone(Thread* t, object o) { PROTECT(t, o); object class_ = objectClass(t, o); unsigned size = baseSize(t, o, class_) * BytesPerWord; object clone; if (classArrayElementSize(t, class_)) { clone = static_cast(allocate(t, size, classObjectMask(t, class_))); memcpy(clone, o, size); // clear any object header flags: setObjectClass(t, o, objectClass(t, o)); } else if (instanceOf(t, type(t, Machine::CloneableType), o)) { clone = make(t, class_); memcpy(reinterpret_cast(clone) + 1, reinterpret_cast(o) + 1, size - BytesPerWord); } else { object classNameSlash = className(t, objectClass(t, o)); THREAD_RUNTIME_ARRAY(t, char, classNameDot, byteArrayLength(t, classNameSlash)); replace('/', '.', RUNTIME_ARRAY_BODY(classNameDot), reinterpret_cast(&byteArrayBody(t, classNameSlash, 0))); throwNew(t, Machine::CloneNotSupportedExceptionType, "%s", RUNTIME_ARRAY_BODY(classNameDot)); } return clone; } object makeStackTraceElement(Thread* t, object e) { PROTECT(t, e); object class_ = className(t, methodClass(t, traceElementMethod(t, e))); PROTECT(t, class_); THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, class_)); replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast(&byteArrayBody(t, class_, 0))); class_ = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); object method = methodName(t, traceElementMethod(t, e)); PROTECT(t, method); method = t->m->classpath->makeString (t, method, 0, byteArrayLength(t, method) - 1); unsigned line = t->m->processor->lineNumber (t, traceElementMethod(t, e), traceElementIp(t, e)); object file = classSourceFile(t, methodClass(t, traceElementMethod(t, e))); file = file ? t->m->classpath->makeString (t, file, 0, byteArrayLength(t, file) - 1) : 0; return makeStackTraceElement(t, class_, method, file, line); } object translateInvokeResult(Thread* t, unsigned returnCode, object o) { switch (returnCode) { case ByteField: return makeByte(t, intValue(t, o)); case BooleanField: return makeBoolean(t, intValue(t, o) != 0); case CharField: return makeChar(t, intValue(t, o)); case ShortField: return makeShort(t, intValue(t, o)); case FloatField: return makeFloat(t, intValue(t, o)); case IntField: case LongField: case ObjectField: case VoidField: return o; case DoubleField: return makeDouble(t, longValue(t, o)); default: abort(t); } } object resolveClassBySpec(Thread* t, object loader, const char* spec, unsigned specLength) { switch (*spec) { case 'L': { THREAD_RUNTIME_ARRAY(t, char, s, specLength - 1); memcpy(RUNTIME_ARRAY_BODY(s), spec + 1, specLength - 2); RUNTIME_ARRAY_BODY(s)[specLength - 2] = 0; return resolveClass(t, loader, RUNTIME_ARRAY_BODY(s)); } case '[': { THREAD_RUNTIME_ARRAY(t, char, s, specLength + 1); memcpy(RUNTIME_ARRAY_BODY(s), spec, specLength); RUNTIME_ARRAY_BODY(s)[specLength] = 0; return resolveClass(t, loader, RUNTIME_ARRAY_BODY(s)); } default: return primitiveClass(t, *spec); } } object resolveJType(Thread* t, object loader, const char* spec, unsigned specLength) { return getJClass(t, resolveClassBySpec(t, loader, spec, specLength)); } object resolveParameterTypes(Thread* t, object loader, object spec, unsigned* parameterCount, unsigned* returnTypeSpec) { PROTECT(t, loader); PROTECT(t, spec); object list = 0; PROTECT(t, list); unsigned offset = 1; unsigned count = 0; while (byteArrayBody(t, spec, offset) != ')') { switch (byteArrayBody(t, spec, offset)) { case 'L': { unsigned start = offset; ++ offset; while (byteArrayBody(t, spec, offset) != ';') ++ offset; ++ offset; object type = resolveClassBySpec (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), offset - start); list = makePair(t, type, list); ++ count; } break; case '[': { unsigned start = offset; while (byteArrayBody(t, spec, offset) == '[') ++ offset; switch (byteArrayBody(t, spec, offset)) { case 'L': ++ offset; while (byteArrayBody(t, spec, offset) != ';') ++ offset; ++ offset; break; default: ++ offset; break; } object type = resolveClassBySpec (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), offset - start); list = makePair(t, type, list); ++ count; } break; default: list = makePair (t, primitiveClass(t, byteArrayBody(t, spec, offset)), list); ++ offset; ++ count; break; } } *parameterCount = count; *returnTypeSpec = offset + 1; return list; } object resolveParameterJTypes(Thread* t, object loader, object spec, unsigned* parameterCount, unsigned* returnTypeSpec) { object list = resolveParameterTypes (t, loader, spec, parameterCount, returnTypeSpec); PROTECT(t, list); object array = makeObjectArray (t, type(t, Machine::JclassType), *parameterCount); PROTECT(t, array); for (int i = *parameterCount - 1; i >= 0; --i) { object c = getJClass(t, pairFirst(t, list)); set(t, array, ArrayBody + (i * BytesPerWord), c); list = pairSecond(t, list); } return array; } object resolveExceptionJTypes(Thread* t, object loader, object addendum) { if (addendum == 0 or methodAddendumExceptionTable(t, addendum) == 0) { return makeObjectArray(t, type(t, Machine::JclassType), 0); } PROTECT(t, loader); PROTECT(t, addendum); object array = makeObjectArray (t, type(t, Machine::JclassType), shortArrayLength(t, methodAddendumExceptionTable(t, addendum))); PROTECT(t, array); for (unsigned i = 0; i < shortArrayLength (t, methodAddendumExceptionTable(t, addendum)); ++i) { uint16_t index = shortArrayBody (t, methodAddendumExceptionTable(t, addendum), i) - 1; object o = singletonObject(t, addendumPool(t, addendum), index); if (objectClass(t, o) == type(t, Machine::ReferenceType)) { o = resolveClass(t, loader, referenceName(t, o)); set(t, addendumPool(t, addendum), SingletonBody + (index * BytesPerWord), o); } o = getJClass(t, o); set(t, array, ArrayBody + (i * BytesPerWord), o); } return array; } object invoke(Thread* t, object method, object instance, object args) { PROTECT(t, method); PROTECT(t, instance); PROTECT(t, args); if (methodFlags(t, method) & ACC_STATIC) { instance = 0; } if ((args == 0 ? 0 : objectArrayLength(t, args)) != methodParameterCount(t, method)) { throwNew(t, Machine::IllegalArgumentExceptionType); } if (methodParameterCount(t, method)) { PROTECT(t, method); unsigned specLength = byteArrayLength(t, methodSpec(t, method)); THREAD_RUNTIME_ARRAY(t, char, spec, specLength); memcpy(RUNTIME_ARRAY_BODY(spec), &byteArrayBody(t, methodSpec(t, method), 0), specLength); unsigned i = 0; for (MethodSpecIterator it(t, RUNTIME_ARRAY_BODY(spec)); it.hasNext();) { object type; bool objectType = false; const char* p = it.next(); switch (*p) { case 'Z': type = vm::type(t, Machine::BooleanType); break; case 'B': type = vm::type(t, Machine::ByteType); break; case 'S': type = vm::type(t, Machine::ShortType); break; case 'C': type = vm::type(t, Machine::CharType); break; case 'I': type = vm::type(t, Machine::IntType); break; case 'F': type = vm::type(t, Machine::FloatType); break; case 'J': type = vm::type(t, Machine::LongType); break; case 'D': type = vm::type(t, Machine::DoubleType); break; case 'L': case '[': { objectType = true; unsigned nameLength; if (*p == 'L') { ++ p; nameLength = it.s - p; } else { nameLength = (it.s - p) + 1; } THREAD_RUNTIME_ARRAY(t, char, name, nameLength); memcpy(RUNTIME_ARRAY_BODY(name), p, nameLength - 1); RUNTIME_ARRAY_BODY(name)[nameLength - 1] = 0; type = resolveClass (t, classLoader(t, methodClass(t, method)), RUNTIME_ARRAY_BODY(name)); } break; default: abort(); } object arg = objectArrayBody(t, args, i++); if ((arg == 0 and (not objectType)) or (arg and (not instanceOf(t, type, arg)))) { // fprintf(stderr, "%s is not a %s\n", arg ? &byteArrayBody(t, className(t, objectClass(t, arg)), 0) : reinterpret_cast(""), &byteArrayBody(t, className(t, type), 0)); throwNew(t, Machine::IllegalArgumentExceptionType); } } } initClass(t, methodClass(t, method)); unsigned returnCode = methodReturnCode(t, method); THREAD_RESOURCE0(t, { if (t->exception) { t->exception = makeThrowable (t, Machine::InvocationTargetExceptionType, 0, 0, t->exception); set(t, t->exception, InvocationTargetExceptionTarget, throwableCause(t, t->exception)); } }); object result; if (args) { result = t->m->processor->invokeArray(t, method, instance, args); } else { result = t->m->processor->invoke(t, method, instance); } return translateInvokeResult(t, returnCode, result); } // only safe to call during bootstrap when there's only one thread // running: void intercept(Thread* t, object c, const char* name, const char* spec, void* function, bool updateRuntimeData) { object m = findMethodOrNull(t, c, name, spec); if (m) { PROTECT(t, m); methodFlags(t, m) |= ACC_NATIVE; if (updateRuntimeData) { object clone = methodClone(t, m); // make clone private to prevent vtable updates at compilation // time. Otherwise, our interception might be bypassed by calls // through the vtable. methodFlags(t, clone) |= ACC_PRIVATE; object native = makeNativeIntercept(t, function, true, clone); PROTECT(t, native); object runtimeData = getMethodRuntimeData(t, m); set(t, runtimeData, MethodRuntimeDataNative, native); } } else { // If we can't find the method, just ignore it, since ProGuard may // have stripped it out as unused. Otherwise, the code below can // be uncommented for debugging purposes. // fprintf(stderr, "unable to find %s%s in %s\n", // name, spec, &byteArrayBody(t, className(t, c), 0)); // abort(t); } } Finder* getFinder(Thread* t, const char* name, unsigned nameLength) { ACQUIRE(t, t->m->referenceLock); for (object p = root(t, Machine::VirtualFileFinders); p; p = finderNext(t, p)) { if (byteArrayLength(t, finderName(t, p)) == nameLength and strncmp(reinterpret_cast (&byteArrayBody(t, finderName(t, p), 0)), name, nameLength)) { return static_cast(finderFinder(t, p)); } } object n = makeByteArray(t, nameLength + 1); memcpy(&byteArrayBody(t, n, 0), name, nameLength); void* p = t->m->libraries->resolve (reinterpret_cast(&byteArrayBody(t, n, 0))); if (p) { uint8_t* (*function)(unsigned*); memcpy(&function, &p, BytesPerWord); unsigned size; uint8_t* data = function(&size); if (data) { Finder* f = makeFinder(t->m->system, t->m->heap, data, size); object finder = makeFinder (t, f, n, root(t, Machine::VirtualFileFinders)); setRoot(t, Machine::VirtualFileFinders, finder); return f; } } return 0; } object getDeclaredClasses(Thread* t, object c, bool publicOnly) { object addendum = classAddendum(t, c); if (addendum) { object table = classAddendumInnerClassTable(t, addendum); if (table) { PROTECT(t, table); unsigned count = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object reference = arrayBody(t, table, i); object outer = innerClassReferenceOuter(t, reference); if (outer and byteArrayEqual(t, outer, className(t, c)) and ((not publicOnly) or (innerClassReferenceFlags(t, reference) & ACC_PUBLIC))) { ++ count; } } object result = makeObjectArray(t, type(t, Machine::JclassType), count); PROTECT(t, result); for (unsigned i = 0; i < arrayLength(t, table); ++i) { object reference = arrayBody(t, table, i); object outer = innerClassReferenceOuter(t, reference); if (outer and byteArrayEqual(t, outer, className(t, c)) and ((not publicOnly) or (innerClassReferenceFlags(t, reference) & ACC_PUBLIC))) { object inner = getJClass (t, resolveClass (t, classLoader(t, c), innerClassReferenceInner(t, arrayBody(t, table, i)))); -- count; set(t, result, ArrayBody + (count * BytesPerWord), inner); } } return result; } } return makeObjectArray(t, type(t, Machine::JclassType), 0); } object getDeclaringClass(Thread* t, object c) { object addendum = classAddendum(t, c); if (addendum) { object table = classAddendumInnerClassTable(t, addendum); if (table) { for (unsigned i = 0; i < arrayLength(t, table); ++i) { object reference = arrayBody(t, table, i); if (innerClassReferenceOuter(t, reference) and strcmp (&byteArrayBody(t, innerClassReferenceInner(t, reference), 0), &byteArrayBody(t, className(t, c), 0)) == 0) { return getJClass (t, resolveClass (t, classLoader(t, c), innerClassReferenceOuter(t, reference))); } } } } return 0; } unsigned classModifiers(Thread* t, object c) { object addendum = classAddendum(t, c); if (addendum) { object table = classAddendumInnerClassTable(t, addendum); if (table) { for (unsigned i = 0; i < arrayLength(t, table); ++i) { object reference = arrayBody(t, table, i); if (0 == strcmp (&byteArrayBody(t, className(t, c), 0), &byteArrayBody(t, innerClassReferenceInner(t, reference), 0))) { return innerClassReferenceFlags(t, reference); } } } } return classFlags(t, c); } } // namespace vm #endif//CLASSPATH_COMMON_H ReadyTalk-avian-1e1fff5/src/avian/common.h000066400000000000000000000244171231440243200205160ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_COMMON_H #define AVIAN_COMMON_H #ifndef __STDC_CONSTANT_MACROS # define __STDC_CONSTANT_MACROS #endif #include "stdlib.h" #include "stdarg.h" #include "stddef.h" #include "string.h" #include "stdio.h" #include "avian/types.h" #include "math.h" #ifdef _MSC_VER #include "float.h" #include #ifdef powerpc # undef powerpc #endif #ifdef linux # undef linux #endif // don't complain about using 'this' in member initializers: # pragma warning(disable:4355) #define strncasecmp _strnicmp #define FP_NAN 0 #define FP_INFINITE 1 #define FP_UNDEF 2 inline int fpclassify(double d) { switch(_fpclass(d)) { case _FPCLASS_SNAN: case _FPCLASS_QNAN: return FP_NAN; case _FPCLASS_PINF: case _FPCLASS_NINF: return FP_INFINITE; } return FP_UNDEF; } inline int signbit(double d) { return _copysign(1.0, d) < 0; } # define not ! # define or || # define and && # define xor ^ # define LIKELY(v) v # define UNLIKELY(v) v # define UNUSED # define NO_RETURN __declspec(noreturn) # define PACKED # define PLATFORM_WINDOWS # ifdef _M_IX86 typedef int32_t intptr_t; typedef uint32_t uintptr_t; # define ARCH_x86_32 # define BYTES_PER_WORD 4 # elif defined _M_X64 typedef int64_t intptr_t; typedef uint64_t uintptr_t; # define ARCH_x86_64 # define BYTES_PER_WORD 8 # elif defined _M_ARM_FP typedef int32_t intptr_t; typedef uint32_t uintptr_t; # define ARCH_arm # define BYTES_PER_WORD 4 # else # error "unsupported architecture" # endif namespace vm { typedef intptr_t intptr_alias_t; } // namespace vm #else // not _MSC_VER # include # define BYTES_PER_WORD __SIZEOF_POINTER__ # define LIKELY(v) __builtin_expect((v) != 0, true) # define UNLIKELY(v) __builtin_expect((v) != 0, false) # define UNUSED __attribute__((unused)) # define NO_RETURN __attribute__((noreturn)) # define PACKED __attribute__((packed)) # ifdef __MINGW32__ # define PLATFORM_WINDOWS # endif # ifdef __i386__ # define ARCH_x86_32 # elif defined __x86_64__ # define ARCH_x86_64 # elif (defined __POWERPC__) || (defined __powerpc__) # define ARCH_powerpc # elif defined __arm__ # define ARCH_arm # else # error "unsupported architecture" # endif namespace vm { typedef intptr_t __attribute__((__may_alias__)) intptr_alias_t; } // namespace vm #endif // not _MSC_VER #ifdef PLATFORM_WINDOWS # define AVIAN_EXPORT __declspec(dllexport) # define PATH_SEPARATOR ';' #else // not PLATFORM_WINDOWS # define AVIAN_EXPORT __attribute__ ((visibility("default"))) \ __attribute__ ((used)) # define PATH_SEPARATOR ':' #endif // not PLATFORM_WINDOWS #if (defined ARCH_x86_32) || (defined ARCH_powerpc) || (defined ARCH_arm) # define LD "ld" # if (defined _MSC_VER) || ((defined __MINGW32__) && __GNUC__ >= 4) # define LLD "I64d" # else # define LLD "lld" # endif # ifdef __APPLE__ # define ULD "lu" # define LX "lx" # else # define LX "x" # define ULD "u" # endif #elif defined ARCH_x86_64 # define LD "ld" # define LX "lx" # if (defined _MSC_VER) || (defined __MINGW32__) # define LLD "I64d" # define ULD "I64x" # else # ifdef __APPLE__ # define LLD "lld" # else # define LLD "ld" # endif # define ULD "lu" # endif #else # error "Unsupported architecture" #endif #ifdef PLATFORM_WINDOWS # define SO_PREFIX "" #else # define SO_PREFIX "lib" #endif #ifdef __APPLE__ # define SO_SUFFIX ".dylib" #elif defined PLATFORM_WINDOWS # define SO_SUFFIX ".dll" #else # define SO_SUFFIX ".so" #endif #define MACRO_XY(X, Y) X##Y #define MACRO_MakeNameXY(FX, LINE) MACRO_XY(FX, LINE) #define MAKE_NAME(FX) MACRO_MakeNameXY(FX, __LINE__) #define RESOURCE(type, name, release) \ class MAKE_NAME(Resource_) { \ public: \ MAKE_NAME(Resource_)(type name): name(name) { } \ ~MAKE_NAME(Resource_)() { release; } \ \ private: \ type name; \ } MAKE_NAME(resource_)(name); #ifdef _MSC_VER # pragma warning( disable : 4291 ) #endif inline void* operator new(size_t, void* p) throw() { return p; } namespace vm { inline intptr_alias_t& alias(void* p, unsigned offset) { return *reinterpret_cast(static_cast(p) + offset); } #ifdef _MSC_VER inline int vsnprintf(char* dst, size_t size, const char* format, va_list a) { return vsnprintf_s(dst, size, _TRUNCATE, format, a); } inline int snprintf(char* dst, size_t size, const char* format, ...) { va_list a; va_start(a, format); int r = vsnprintf(dst, size, format, a); va_end(a); return r; } inline FILE* fopen(const char* name, const char* mode) { FILE* file; if (fopen_s(&file, name, mode) == 0) { return file; } else { return 0; } } #else // not _MSC_VER inline int vsnprintf(char* dst, size_t size, const char* format, va_list a) { return ::vsnprintf(dst, size, format, a); } inline int snprintf(char* dst, size_t size, const char* format, ...) { va_list a; va_start(a, format); int r = vsnprintf(dst, size, format, a); va_end(a); return r; } inline FILE* fopen(const char* name, const char* mode) { return ::fopen(name, mode); } #endif // not _MSC_VER const unsigned BytesPerWord = sizeof(uintptr_t); const unsigned BitsPerWord = BytesPerWord * 8; const uintptr_t PointerMask = ((~static_cast(0)) / BytesPerWord) * BytesPerWord; const unsigned LikelyPageSizeInBytes = 4 * 1024; inline unsigned pad(unsigned n, unsigned alignment) { return (n + (alignment - 1)) & ~(alignment - 1); } inline unsigned pad(unsigned n) { return pad(n, BytesPerWord); } inline uintptr_t padWord(uintptr_t n, uintptr_t alignment) { return (n + (alignment - 1)) & ~(alignment - 1); } inline uintptr_t padWord(uintptr_t n) { return padWord(n, BytesPerWord); } inline bool fitsInInt8(int64_t v) { return v == static_cast(v); } inline bool fitsInInt16(int64_t v) { return v == static_cast(v); } inline bool fitsInInt32(int64_t v) { return v == static_cast(v); } template inline unsigned wordOf(unsigned i) { return i / (sizeof(T) * 8); } inline unsigned wordOf(unsigned i) { return wordOf(i); } template inline unsigned bitOf(unsigned i) { return i % (sizeof(T) * 8); } inline unsigned bitOf(unsigned i) { return bitOf(i); } template inline unsigned indexOf(unsigned word, unsigned bit) { return (word * (sizeof(T) * 8)) + bit; } inline unsigned indexOf(unsigned word, unsigned bit) { return indexOf(word, bit); } template inline void markBit(T* map, unsigned i) { map[wordOf(i)] |= static_cast(1) << bitOf(i); } template inline void clearBit(T* map, unsigned i) { map[wordOf(i)] &= ~(static_cast(1) << bitOf(i)); } template inline unsigned getBit(T* map, unsigned i) { return (map[wordOf(i)] & (static_cast(1) << bitOf(i))) >> bitOf(i); } // todo: the following (clearBits, setBits, and getBits) could be made // more efficient by operating on a word at a time instead of a bit at // a time: template inline void clearBits(T* map, unsigned bitsPerRecord, unsigned index) { for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) { clearBit(map, i); } } template inline void setBits(T* map, unsigned bitsPerRecord, int index, unsigned v) { for (int i = index + bitsPerRecord - 1; i >= index; --i) { if (v & 1) markBit(map, i); else clearBit(map, i); v >>= 1; } } template inline unsigned getBits(T* map, unsigned bitsPerRecord, unsigned index) { unsigned v = 0; for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) { v <<= 1; v |= getBit(map, i); } return v; } template inline T& fieldAtOffset(void* p, unsigned offset) { return *reinterpret_cast(static_cast(p) + offset); } template inline T* maskAlignedPointer(T* p) { return reinterpret_cast(reinterpret_cast(p) & PointerMask); } inline uint32_t hash(const char* s) { uint32_t h = 0; for (unsigned i = 0; s[i]; ++i) { h = (h * 31) + s[i]; } return h; } inline uint32_t hash(const uint8_t* s, unsigned length) { uint32_t h = 0; for (unsigned i = 0; i < length; ++i) { h = (h * 31) + s[i]; } return h; } inline uint32_t hash(const int8_t* s, unsigned length) { return hash(reinterpret_cast(s), length); } inline uint32_t hash(const uint16_t* s, unsigned length) { uint32_t h = 0; for (unsigned i = 0; i < length; ++i) { h = (h * 31) + s[i]; } return h; } inline void write4(uint8_t* dst, uint32_t v) { memcpy(dst, &v, 4); } inline uint32_t floatToBits(float f) { uint32_t bits; memcpy(&bits, &f, 4); return bits; } inline uint64_t doubleToBits(double d) { uint64_t bits; memcpy(&bits, &d, 8); return bits; } inline double bitsToDouble(uint64_t bits) { double d; memcpy(&d, &bits, 8); return d; } inline float bitsToFloat(uint32_t bits) { float f; memcpy(&f, &bits, 4); return f; } inline int difference(void* a, void* b) { return reinterpret_cast(a) - reinterpret_cast(b); } template inline void* voidPointer(T function) { void* p; memcpy(&p, &function, sizeof(void*)); return p; } inline void replace(char a, char b, char* c) { for (; *c; ++c) if (*c == a) *c = b; } inline void replace(char a, char b, char* dst, const char* src) { unsigned i = 0; for (; src[i]; ++ i) { dst[i] = src[i] == a ? b : src[i]; } dst[i] = 0; } inline bool equal(const void* a, unsigned al, const void* b, unsigned bl) { if (al == bl) { return memcmp(a, b, al) == 0; } else { return false; } } } // namespace vm #endif // AVIAN_COMMON_H ReadyTalk-avian-1e1fff5/src/avian/constants.h000066400000000000000000000125001231440243200212300ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef CONSTANTS_H #define CONSTANTS_H namespace vm { enum OpCode { aaload = 0x32, aastore = 0x53, aconst_null = 0x01, aload = 0x19, aload_0 = 0x2a, aload_1 = 0x2b, aload_2 = 0x2c, aload_3 = 0x2d, anewarray = 0xbd, areturn = 0xb0, arraylength = 0xbe, astore = 0x3a, astore_0 = 0x4b, astore_1 = 0x4c, astore_2 = 0x4d, astore_3 = 0x4e, athrow = 0xbf, baload = 0x33, bastore = 0x54, bipush = 0x10, breakpoint = 0xca, caload = 0x34, castore = 0x55, checkcast = 0xc0, d2f = 0x90, d2i = 0x8e, d2l = 0x8f, dadd = 0x63, daload = 0x31, dastore = 0x52, dcmpg = 0x98, dcmpl = 0x97, dconst_0 = 0x0e, dconst_1 = 0x0f, ddiv = 0x6f, dload = 0x18, dload_0 = 0x26, dload_1 = 0x27, dload_2 = 0x28, dload_3 = 0x29, dmul = 0x6b, dneg = 0x77, drem = 0x73, dreturn = 0xaf, dstore = 0x39, dstore_0 = 0x47, dstore_1 = 0x48, dstore_2 = 0x49, dstore_3 = 0x4a, dsub = 0x67, dup = 0x59, dup_x1 = 0x5a, dup_x2 = 0x5b, dup2 = 0x5c, dup2_x1 = 0x5d, dup2_x2 = 0x5e, f2d = 0x8d, f2i = 0x8b, f2l = 0x8c, fadd = 0x62, faload = 0x30, fastore = 0x51, fcmpg = 0x96, fcmpl = 0x95, fconst_0 = 0x0b, fconst_1 = 0x0c, fconst_2 = 0x0d, fdiv = 0x6e, fload = 0x17, fload_0 = 0x22, fload_1 = 0x23, fload_2 = 0x24, fload_3 = 0x25, fmul = 0x6a, fneg = 0x76, frem = 0x72, freturn = 0xae, fstore = 0x38, fstore_0 = 0x43, fstore_1 = 0x44, fstore_2 = 0x45, fstore_3 = 0x46, fsub = 0x66, getfield = 0xb4, getstatic = 0xb2, goto_ = 0xa7, goto_w = 0xc8, i2b = 0x91, i2c = 0x92, i2d = 0x87, i2f = 0x86, i2l = 0x85, i2s = 0x93, iadd = 0x60, iaload = 0x2e, iand = 0x7e, iastore = 0x4f, iconst_m1 = 0x02, iconst_0 = 0x03, iconst_1 = 0x04, iconst_2 = 0x05, iconst_3 = 0x06, iconst_4 = 0x07, iconst_5 = 0x08, idiv = 0x6c, if_acmpeq = 0xa5, if_acmpne = 0xa6, if_icmpeq = 0x9f, if_icmpne = 0xa0, if_icmplt = 0xa1, if_icmpge = 0xa2, if_icmpgt = 0xa3, if_icmple = 0xa4, ifeq = 0x99, ifge = 0x9c, ifgt = 0x9d, ifle = 0x9e, iflt = 0x9b, ifne = 0x9a, ifnonnull = 0xc7, ifnull = 0xc6, iinc = 0x84, iload = 0x15, iload_0 = 0x1a, iload_1 = 0x1b, iload_2 = 0x1c, iload_3 = 0x1d, impdep1 = 0xfe, impdep2 = 0xff, imul = 0x68, ineg = 0x74, instanceof = 0xc1, invokeinterface = 0xb9, invokespecial = 0xb7, invokestatic = 0xb8, invokevirtual = 0xb6, ior = 0x80, irem = 0x70, ireturn = 0xac, ishl = 0x78, ishr = 0x7a, istore = 0x36, istore_0 = 0x3b, istore_1 = 0x3c, istore_2 = 0x3d, istore_3 = 0x3e, isub = 0x64, iushr = 0x7c, ixor = 0x82, jsr = 0xa8, jsr_w = 0xc9, l2d = 0x8a, l2f = 0x89, l2i = 0x88, ladd = 0x61, laload = 0x2f, land = 0x7f, lastore = 0x50, lcmp = 0x94, lconst_0 = 0x09, lconst_1 = 0x0a, ldc = 0x12, ldc_w = 0x13, ldc2_w = 0x14, ldiv_ = 0x6d, lload = 0x16, lload_0 = 0x1e, lload_1 = 0x1f, lload_2 = 0x20, lload_3 = 0x21, lmul = 0x69, lneg = 0x75, lookupswitch = 0xab, lor = 0x81, lrem = 0x71, lreturn = 0xad, lshl = 0x79, lshr = 0x7b, lstore = 0x37, lstore_0 = 0x3f, lstore_1 = 0x40, lstore_2 = 0x41, lstore_3 = 0x42, lsub = 0x65, lushr = 0x7d, lxor = 0x83, monitorenter = 0xc2, monitorexit = 0xc3, multianewarray = 0xc5, new_ = 0xbb, newarray = 0xbc, nop = 0x00, pop_ = 0x57, pop2 = 0x58, putfield = 0xb5, putstatic = 0xb3, ret = 0xa9, return_ = 0xb1, saload = 0x35, sastore = 0x56, sipush = 0x11, swap = 0x5f, tableswitch = 0xaa, wide = 0xc4 }; enum TypeCode { T_BOOLEAN = 4, T_CHAR = 5, T_FLOAT = 6, T_DOUBLE = 7, T_BYTE = 8, T_SHORT = 9, T_INT = 10, T_LONG = 11 }; enum Constant { CONSTANT_Class = 7, CONSTANT_Fieldref = 9, CONSTANT_Methodref = 10, CONSTANT_InterfaceMethodref = 11, CONSTANT_String = 8, CONSTANT_Integer = 3, CONSTANT_Float = 4, CONSTANT_Long = 5, CONSTANT_Double = 6, CONSTANT_NameAndType = 12, CONSTANT_Utf8 = 1 }; const unsigned ACC_PUBLIC = 1 << 0; const unsigned ACC_PRIVATE = 1 << 1; const unsigned ACC_PROTECTED = 1 << 2; const unsigned ACC_STATIC = 1 << 3; const unsigned ACC_FINAL = 1 << 4; const unsigned ACC_SUPER = 1 << 5; const unsigned ACC_SYNCHRONIZED = ACC_SUPER; const unsigned ACC_VOLATILE = 1 << 6; const unsigned ACC_TRANSIENT = 1 << 7; const unsigned ACC_NATIVE = 1 << 8; const unsigned ACC_INTERFACE = 1 << 9; const unsigned ACC_ABSTRACT = 1 << 10; const unsigned ACC_STRICT = 1 << 11; const int AVIAN_JNI_COMMIT = 1; const int AVIAN_JNI_ABORT = 2; const int AVIAN_JNI_OK = 0; const int AVIAN_JNI_ERR = -1; const int AVIAN_JNI_EDETACHED = -2; const int AVIAN_JNI_EVERSION = -3; const int AVIAN_JNI_ENOMEM = -4; const int AVIAN_JNI_EEXIST = -5; const int AVIAN_JNI_EINVAL = -6; const int AVIAN_JNI_VERSION_1_1 = 0x00010001; const int AVIAN_JNI_VERSION_1_2 = 0x00010002; const int AVIAN_JNI_VERSION_1_4 = 0x00010004; } // namespace vm #endif//CONSTANTS_H ReadyTalk-avian-1e1fff5/src/avian/embed.h000066400000000000000000000007101231440243200202700ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef EMBED_H #define EMBED_H #define RESID_MAIN_CLASS 100 #define RESID_BOOT_JAR L"BOOT.JAR" #endif ReadyTalk-avian-1e1fff5/src/avian/environment.h000066400000000000000000000015631231440243200215670ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_ENVIRONMENT_H #define AVIAN_ENVIRONMENT_H #ifndef AVIAN_TARGET_FORMAT #error build system should have defined AVIAN_TARGET_FORMAT #endif #ifndef AVIAN_TARGET_ARCH #error build system should have defined AVIAN_TARGET_ARCH #endif #define AVIAN_FORMAT_UNKNOWN 0 #define AVIAN_FORMAT_ELF 1 #define AVIAN_FORMAT_PE 2 #define AVIAN_FORMAT_MACHO 3 #define AVIAN_ARCH_UNKNOWN 0 #define AVIAN_ARCH_X86 (1 << 8) #define AVIAN_ARCH_X86_64 (2 << 8) #define AVIAN_ARCH_ARM (3 << 8) #define AVIAN_ARCH_POWERPC (4 << 8) #endif ReadyTalk-avian-1e1fff5/src/avian/finder.h000066400000000000000000000113731231440243200204720ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef FINDER_H #define FINDER_H #include "avian/common.h" #include namespace avian { namespace util { class Allocator; } } namespace vm { const unsigned LocalHeaderSize = 30; const unsigned HeaderSize = 46; const unsigned CentralDirectorySignature = 0x06054b50; const unsigned EntrySignature = 0x02014b50; const unsigned CentralDirectorySearchStart = 22; inline uint16_t get2(const uint8_t* p) { return (static_cast(p[1]) << 8) | (static_cast(p[0]) ); } inline uint32_t get4(const uint8_t* p) { return (static_cast(p[3]) << 24) | (static_cast(p[2]) << 16) | (static_cast(p[1]) << 8) | (static_cast(p[0]) ); } inline uint32_t signature(const uint8_t* p) { return get4(p); } inline uint16_t compressionMethod(const uint8_t* centralHeader) { return get2(centralHeader + 10); } inline uint32_t fileTime(const uint8_t* centralHeader) { return get4(centralHeader + 12); } inline uint32_t fileCRC(const uint8_t* centralHeader) { return get4(centralHeader + 16); } inline uint32_t compressedSize(const uint8_t* centralHeader) { return get4(centralHeader + 20); } inline uint32_t uncompressedSize(const uint8_t* centralHeader) { return get4(centralHeader + 24); } inline uint16_t fileNameLength(const uint8_t* centralHeader) { return get2(centralHeader + 28); } inline uint16_t extraFieldLength(const uint8_t* centralHeader) { return get2(centralHeader + 30); } inline uint16_t commentFieldLength(const uint8_t* centralHeader) { return get2(centralHeader + 32); } inline uint32_t localHeaderOffset(const uint8_t* centralHeader) { return get4(centralHeader + 42); } inline uint16_t localFileNameLength(const uint8_t* localHeader) { return get2(localHeader + 26); } inline uint16_t localExtraFieldLength(const uint8_t* localHeader) { return get2(localHeader + 28); } inline uint32_t centralDirectoryOffset(const uint8_t* centralHeader) { return get4(centralHeader + 16); } inline const uint8_t* fileName(const uint8_t* centralHeader) { return centralHeader + 46; } inline const uint8_t* fileData(const uint8_t* localHeader) { return localHeader + LocalHeaderSize + localFileNameLength(localHeader) + localExtraFieldLength(localHeader); } inline const uint8_t* endOfEntry(const uint8_t* p) { return p + HeaderSize + fileNameLength(p) + extraFieldLength(p) + commentFieldLength(p); } inline bool readLine(const uint8_t* base, unsigned total, unsigned* start, unsigned* length) { const uint8_t* p = base + *start; const uint8_t* end = base + total; while (p != end and (*p == '\n' or *p == '\r')) ++ p; *start = p - base; while (p != end and not (*p == '\n' or *p == '\r')) ++ p; *length = (p - base) - *start; return *length != 0; } class Finder { public: class IteratorImp { public: virtual const char* next(unsigned* size) = 0; virtual void dispose() = 0; }; class Iterator { public: Iterator(Finder* finder): it(finder->iterator()), current(it->next(¤tSize)) { } ~Iterator() { it->dispose(); } bool hasMore() { if (current) return true; current = it->next(¤tSize); return current != 0; } const char* next(unsigned* size) { if (hasMore()) { *size = currentSize; const char* v = current; current = 0; return v; } else { return 0; } } IteratorImp* it; const char* current; unsigned currentSize; }; virtual IteratorImp* iterator() = 0; virtual System::Region* find(const char* name) = 0; virtual System::FileType stat(const char* name, unsigned* length, bool tryDirectory = false) = 0; virtual const char* urlPrefix(const char* name) = 0; virtual const char* nextUrlPrefix(const char* name, void *&finderElementPtr) = 0; virtual const char* sourceUrl(const char* name) = 0; virtual const char* path() = 0; virtual void dispose() = 0; }; AVIAN_EXPORT Finder* makeFinder(System* s, avian::util::Allocator* a, const char* path, const char* bootLibrary); Finder* makeFinder(System* s, avian::util::Allocator* a, const uint8_t* jarData, unsigned jarLength); } // namespace vm #endif//FINDER_H ReadyTalk-avian-1e1fff5/src/avian/heapwalk.h000066400000000000000000000021611231440243200210120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef HEAPWALK_H #define HEAPWALK_H #include "avian/common.h" #include "java-common.h" namespace vm { class Thread; class HeapMap { public: virtual int find(object value) = 0; virtual void dispose() = 0; }; class HeapVisitor { public: virtual void root() = 0; virtual unsigned visitNew(object value) = 0; virtual void visitOld(object value, unsigned number) = 0; virtual void push(object parent, unsigned parentNumber, unsigned childOffset) = 0; virtual void pop() = 0; }; class HeapWalker { public: virtual unsigned visitRoot(object root) = 0; virtual void visitAllRoots() = 0; virtual HeapMap* map() = 0; virtual void dispose() = 0; }; HeapWalker* makeHeapWalker(Thread* t, HeapVisitor* v); } // namespace vm #endif//HEAPWALK_H ReadyTalk-avian-1e1fff5/src/avian/java-common.h000066400000000000000000000025011231440243200214230ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef JAVA_COMMON_H #define JAVA_COMMON_H namespace vm { class Machine; class Thread; struct Object { }; typedef Object* object; typedef uint8_t jboolean; typedef int8_t jbyte; typedef uint16_t jchar; typedef int16_t jshort; typedef int32_t jint; typedef int64_t jlong; typedef float jfloat; typedef double jdouble; typedef jint jsize; typedef object* jobject; typedef jobject jclass; typedef jobject jthrowable; typedef jobject jstring; typedef jobject jweak; typedef jobject jarray; typedef jarray jbooleanArray; typedef jarray jbyteArray; typedef jarray jcharArray; typedef jarray jshortArray; typedef jarray jintArray; typedef jarray jlongArray; typedef jarray jfloatArray; typedef jarray jdoubleArray; typedef jarray jobjectArray; typedef uintptr_t jfieldID; typedef uintptr_t jmethodID; union jvalue { jboolean z; jbyte b; jchar c; jshort s; jint i; jlong j; jfloat f; jdouble d; jobject l; }; } // namespace vm #endif // JAVA_COMMON_H ReadyTalk-avian-1e1fff5/src/avian/jnienv.h000066400000000000000000000020571231440243200205130ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef JNIENV_H #define JNIENV_H #include "avian/machine.h" #define BOOTSTRAP_PROPERTY "avian.bootstrap" #define JAVA_COMMAND_PROPERTY "sun.java.command" #define JAVA_LAUNCHER_PROPERTY "sun.java.launcher" #define CRASHDIR_PROPERTY "avian.crash.dir" #define EMBED_PREFIX_PROPERTY "avian.embed.prefix" #define CLASSPATH_PROPERTY "java.class.path" #define JAVA_HOME_PROPERTY "java.home" #define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p" #define BOOTCLASSPATH_OPTION "bootclasspath" #define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" #define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" namespace vm { void populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable); } // namespace vm #endif//JNIENV_H ReadyTalk-avian-1e1fff5/src/avian/lzma-util.h000066400000000000000000000024441231440243200211400ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef LZMA_UTIL_H #define LZMA_UTIL_H #include #include #include #include namespace vm { const unsigned Padding = 16; class LzmaAllocator { public: LzmaAllocator(avian::util::Allocator* a): a(a) { allocator.Alloc = allocate; allocator.Free = free; } ISzAlloc allocator; avian::util::Allocator* a; static void* allocate(void* allocator, size_t size) { uint8_t* p = static_cast (static_cast(allocator)->a->allocate(size + Padding)); int32_t size32 = size; memcpy(p, &size32, 4); return p + Padding; } static void free(void* allocator, void* address) { if (address) { void* p = static_cast(address) - Padding; int32_t size32; memcpy(&size32, p, 4); static_cast(allocator)->a->free(p, size32 + Padding); } } }; } // namespace vm #endif // LZMA_UTIL_H ReadyTalk-avian-1e1fff5/src/avian/lzma.h000066400000000000000000000016071231440243200201650ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef LZMA_H #define LZMA_H #include namespace avian { namespace util { class Allocator; } } namespace vm { uint8_t* decodeLZMA(System* s, avian::util::Allocator* a, uint8_t* in, unsigned inSize, unsigned* outSize); uint8_t* encodeLZMA(System* s, avian::util::Allocator* a, uint8_t* in, unsigned inSize, unsigned* outSize); } // namespace vm #endif // LZMA_H ReadyTalk-avian-1e1fff5/src/avian/machine.h000066400000000000000000002476661231440243200206470ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef MACHINE_H #define MACHINE_H #include "avian/common.h" #include "java-common.h" #include #include #include #include "avian/finder.h" #include "avian/processor.h" #include "avian/constants.h" #include "avian/arch.h" using namespace avian::util; #ifdef PLATFORM_WINDOWS # define JNICALL __stdcall #else # define JNICALL #endif #define PROTECT(thread, name) \ Thread::SingleProtector MAKE_NAME(protector_) (thread, &name); #define ACQUIRE(t, x) MonitorResource MAKE_NAME(monitorResource_) (t, x) #define ACQUIRE_OBJECT(t, x) \ ObjectMonitorResource MAKE_NAME(monitorResource_) (t, x) #define ACQUIRE_FIELD_FOR_READ(t, field) \ FieldReadResource MAKE_NAME(monitorResource_) (t, field) #define ACQUIRE_FIELD_FOR_WRITE(t, field) \ FieldWriteResource MAKE_NAME(monitorResource_) (t, field) #define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x) #define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state) #define THREAD_RESOURCE0(t, releaseBody) \ class MAKE_NAME(Resource_): public Thread::Resource { \ public: \ MAKE_NAME(Resource_)(Thread* t): Resource(t) { } \ ~MAKE_NAME(Resource_)() { releaseBody; } \ virtual void release() \ { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ } MAKE_NAME(resource_)(t); #define OBJECT_RESOURCE(t, name, releaseBody) \ class MAKE_NAME(Resource_): public Thread::Resource { \ public: \ MAKE_NAME(Resource_)(Thread* t, object name): \ Resource(t), name(name), protector(t, &(this->name)) { } \ ~MAKE_NAME(Resource_)() { releaseBody; } \ virtual void release() \ { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ \ private: \ object name; \ Thread::SingleProtector protector; \ } MAKE_NAME(resource_)(t, name); #define THREAD_RESOURCE(t, type, name, releaseBody) \ class MAKE_NAME(Resource_): public Thread::Resource { \ public: \ MAKE_NAME(Resource_)(Thread* t, type name): \ Resource(t), name(name) { } \ ~MAKE_NAME(Resource_)() { releaseBody; } \ virtual void release() \ { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ \ private: \ type name; \ } MAKE_NAME(resource_)(t, name); #define THREAD_RESOURCE2(t, type1, name1, type2, name2, releaseBody) \ class MAKE_NAME(Resource_): public Thread::Resource { \ public: \ MAKE_NAME(Resource_)(Thread* t, type1 name1, type2 name2): \ Resource(t), name1(name1), name2(name2) { } \ ~MAKE_NAME(Resource_)() { releaseBody; } \ virtual void release() \ { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ \ private: \ type1 name1; \ type2 name2; \ } MAKE_NAME(resource_)(t, name1, name2); namespace vm { const bool Verbose = false; const bool DebugRun = false; const bool DebugStack = false; const bool DebugMonitors = false; const bool DebugReferences = false; const bool AbortOnOutOfMemoryError = false; const uintptr_t HashTakenMark = 1; const uintptr_t ExtendedMark = 2; const uintptr_t FixedMark = 3; const unsigned ThreadHeapSizeInBytes = 64 * 1024; const unsigned ThreadHeapSizeInWords = ThreadHeapSizeInBytes / BytesPerWord; const unsigned ThreadBackupHeapSizeInBytes = 2 * 1024; const unsigned ThreadBackupHeapSizeInWords = ThreadBackupHeapSizeInBytes / BytesPerWord; const unsigned ThreadHeapPoolSize = 64; const unsigned FixedFootprintThresholdInBytes = ThreadHeapPoolSize * ThreadHeapSizeInBytes; // number of zombie threads which may accumulate before we force a GC // to clean them up: const unsigned ZombieCollectionThreshold = 16; enum FieldCode { VoidField, ByteField, CharField, DoubleField, FloatField, IntField, LongField, ShortField, BooleanField, ObjectField }; enum StackTag { IntTag, // must be zero ObjectTag }; const int NativeLine = -2; const int UnknownLine = -1; // class vmFlags: const unsigned ReferenceFlag = 1 << 0; const unsigned WeakReferenceFlag = 1 << 1; const unsigned NeedInitFlag = 1 << 2; const unsigned InitFlag = 1 << 3; const unsigned InitErrorFlag = 1 << 4; const unsigned PrimitiveFlag = 1 << 5; const unsigned BootstrapFlag = 1 << 6; const unsigned HasFinalizerFlag = 1 << 7; const unsigned LinkFlag = 1 << 8; const unsigned HasFinalMemberFlag = 1 << 9; const unsigned SingletonFlag = 1 << 10; const unsigned ContinuationFlag = 1 << 11; // method vmFlags: const unsigned ClassInitFlag = 1 << 0; const unsigned ConstructorFlag = 1 << 1; #ifndef JNI_VERSION_1_6 #define JNI_VERSION_1_6 0x00010006 #endif typedef Machine JavaVM; typedef Thread JNIEnv; struct JNINativeMethod { char* name; char* signature; void* function; }; struct JavaVMVTable { void* reserved0; void* reserved1; void* reserved2; #if (! TARGET_RT_MAC_CFM) && defined(__ppc__) void* cfm_vectors[4]; #endif jint (JNICALL *DestroyJavaVM) (JavaVM*); jint (JNICALL *AttachCurrentThread) (JavaVM*, JNIEnv**, void*); jint (JNICALL *DetachCurrentThread) (JavaVM*); jint (JNICALL *GetEnv) (JavaVM*, JNIEnv**, jint); jint (JNICALL *AttachCurrentThreadAsDaemon) (JavaVM*, JNIEnv**, void*); #if TARGET_RT_MAC_CFM && defined(__ppc__) void* real_functions[5]; #endif }; struct JNIEnvVTable { void* reserved0; void* reserved1; void* reserved2; void* reserved3; #if (! TARGET_RT_MAC_CFM) && defined(__ppc__) void* cfm_vectors[225]; #endif jint (JNICALL *GetVersion) (JNIEnv*); jclass (JNICALL *DefineClass) (JNIEnv*, const char*, jobject, const jbyte*, jsize); jclass (JNICALL *FindClass) (JNIEnv*, const char*); jmethodID (JNICALL *FromReflectedMethod) (JNIEnv*, jobject); jfieldID (JNICALL *FromReflectedField) (JNIEnv*, jobject); jobject (JNICALL *ToReflectedMethod) (JNIEnv*, jclass, jmethodID, jboolean); jclass (JNICALL *GetSuperclass) (JNIEnv*, jclass); jboolean (JNICALL *IsAssignableFrom) (JNIEnv*, jclass, jclass); jobject (JNICALL *ToReflectedField) (JNIEnv*, jclass, jfieldID, jboolean); jint (JNICALL *Throw) (JNIEnv*, jthrowable); jint (JNICALL *ThrowNew) (JNIEnv*, jclass, const char*); jthrowable (JNICALL *ExceptionOccurred) (JNIEnv*); void (JNICALL *ExceptionDescribe) (JNIEnv*); void (JNICALL *ExceptionClear) (JNIEnv*); void (JNICALL *FatalError) (JNIEnv*, const char*); jint (JNICALL *PushLocalFrame) (JNIEnv*, jint); jobject (JNICALL *PopLocalFrame) (JNIEnv*, jobject); jobject (JNICALL *NewGlobalRef) (JNIEnv*, jobject); void (JNICALL *DeleteGlobalRef) (JNIEnv*, jobject); void (JNICALL *DeleteLocalRef) (JNIEnv*, jobject); jboolean (JNICALL *IsSameObject) (JNIEnv*, jobject, jobject); jobject (JNICALL *NewLocalRef) (JNIEnv*, jobject); jint (JNICALL *EnsureLocalCapacity) (JNIEnv*, jint); jobject (JNICALL *AllocObject) (JNIEnv*, jclass); jobject (JNICALL *NewObject) (JNIEnv*, jclass, jmethodID, ...); jobject (JNICALL *NewObjectV) (JNIEnv*, jclass, jmethodID, va_list); jobject (JNICALL *NewObjectA) (JNIEnv*, jclass, jmethodID, const jvalue*); jclass (JNICALL *GetObjectClass) (JNIEnv*, jobject); jboolean (JNICALL *IsInstanceOf) (JNIEnv*, jobject, jclass); jmethodID (JNICALL *GetMethodID) (JNIEnv*, jclass, const char*, const char*); jobject (JNICALL *CallObjectMethod) (JNIEnv*, jobject, jmethodID, ...); jobject (JNICALL *CallObjectMethodV) (JNIEnv*, jobject, jmethodID, va_list); jobject (JNICALL *CallObjectMethodA) (JNIEnv*, jobject, jmethodID, const jvalue*); jboolean (JNICALL *CallBooleanMethod) (JNIEnv*, jobject, jmethodID, ...); jboolean (JNICALL *CallBooleanMethodV) (JNIEnv*, jobject, jmethodID, va_list); jboolean (JNICALL *CallBooleanMethodA) (JNIEnv*, jobject, jmethodID, const jvalue*); jbyte (JNICALL *CallByteMethod) (JNIEnv*, jobject, jmethodID, ...); jbyte (JNICALL *CallByteMethodV) (JNIEnv*, jobject, jmethodID, va_list); jbyte (JNICALL *CallByteMethodA) (JNIEnv*, jobject, jmethodID, const jvalue*); jchar (JNICALL *CallCharMethod) (JNIEnv*, jobject, jmethodID, ...); jchar (JNICALL *CallCharMethodV) (JNIEnv*, jobject, jmethodID, va_list); jchar (JNICALL *CallCharMethodA) (JNIEnv*, jobject, jmethodID, const jvalue*); jshort (JNICALL *CallShortMethod) (JNIEnv*, jobject, jmethodID, ...); jshort (JNICALL *CallShortMethodV) (JNIEnv*, jobject, jmethodID, va_list); jshort (JNICALL *CallShortMethodA) (JNIEnv*, jobject, jmethodID, const jvalue*); jint (JNICALL *CallIntMethod) (JNIEnv*, jobject, jmethodID, ...); jint (JNICALL *CallIntMethodV) (JNIEnv*, jobject, jmethodID, va_list); jint (JNICALL *CallIntMethodA) (JNIEnv*, jobject, jmethodID, const jvalue*); jlong (JNICALL *CallLongMethod) (JNIEnv*, jobject, jmethodID, ...); jlong (JNICALL *CallLongMethodV) (JNIEnv*, jobject, jmethodID, va_list); jlong (JNICALL *CallLongMethodA) (JNIEnv*, jobject, jmethodID, const jvalue*); jfloat (JNICALL *CallFloatMethod) (JNIEnv*, jobject, jmethodID, ...); jfloat (JNICALL *CallFloatMethodV) (JNIEnv*, jobject, jmethodID, va_list); jfloat (JNICALL *CallFloatMethodA) (JNIEnv*, jobject, jmethodID, const jvalue*); jdouble (JNICALL *CallDoubleMethod) (JNIEnv*, jobject, jmethodID, ...); jdouble (JNICALL *CallDoubleMethodV) (JNIEnv*, jobject, jmethodID, va_list); jdouble (JNICALL *CallDoubleMethodA) (JNIEnv*, jobject, jmethodID, const jvalue*); void (JNICALL *CallVoidMethod) (JNIEnv*, jobject, jmethodID, ...); void (JNICALL *CallVoidMethodV) (JNIEnv*, jobject, jmethodID, va_list); void (JNICALL *CallVoidMethodA) (JNIEnv*, jobject, jmethodID, const jvalue*); jobject (JNICALL *CallNonvirtualObjectMethod) (JNIEnv*, jobject, jclass, jmethodID, ...); jobject (JNICALL *CallNonvirtualObjectMethodV) (JNIEnv*, jobject, jclass, jmethodID, va_list); jobject (JNICALL *CallNonvirtualObjectMethodA) (JNIEnv*, jobject, jclass, jmethodID, const jvalue*); jboolean (JNICALL *CallNonvirtualBooleanMethod) (JNIEnv*, jobject, jclass, jmethodID, ...); jboolean (JNICALL *CallNonvirtualBooleanMethodV) (JNIEnv*, jobject, jclass, jmethodID, va_list); jboolean (JNICALL *CallNonvirtualBooleanMethodA) (JNIEnv*, jobject, jclass, jmethodID, const jvalue*); jbyte (JNICALL *CallNonvirtualByteMethod) (JNIEnv*, jobject, jclass, jmethodID, ...); jbyte (JNICALL *CallNonvirtualByteMethodV) (JNIEnv*, jobject, jclass, jmethodID, va_list); jbyte (JNICALL *CallNonvirtualByteMethodA) (JNIEnv*, jobject, jclass, jmethodID, const jvalue*); jchar (JNICALL *CallNonvirtualCharMethod) (JNIEnv*, jobject, jclass, jmethodID, ...); jchar (JNICALL *CallNonvirtualCharMethodV) (JNIEnv*, jobject, jclass, jmethodID, va_list); jchar (JNICALL *CallNonvirtualCharMethodA) (JNIEnv*, jobject, jclass, jmethodID, const jvalue*); jshort (JNICALL *CallNonvirtualShortMethod) (JNIEnv*, jobject, jclass, jmethodID, ...); jshort (JNICALL *CallNonvirtualShortMethodV) (JNIEnv*, jobject, jclass, jmethodID, va_list); jshort (JNICALL *CallNonvirtualShortMethodA) (JNIEnv*, jobject, jclass, jmethodID, const jvalue*); jint (JNICALL *CallNonvirtualIntMethod) (JNIEnv*, jobject, jclass, jmethodID, ...); jint (JNICALL *CallNonvirtualIntMethodV) (JNIEnv*, jobject, jclass, jmethodID, va_list); jint (JNICALL *CallNonvirtualIntMethodA) (JNIEnv*, jobject, jclass, jmethodID, const jvalue*); jlong (JNICALL *CallNonvirtualLongMethod) (JNIEnv*, jobject, jclass, jmethodID, ...); jlong (JNICALL *CallNonvirtualLongMethodV) (JNIEnv*, jobject, jclass, jmethodID, va_list); jlong (JNICALL *CallNonvirtualLongMethodA) (JNIEnv*, jobject, jclass, jmethodID, const jvalue*); jfloat (JNICALL *CallNonvirtualFloatMethod) (JNIEnv*, jobject, jclass, jmethodID, ...); jfloat (JNICALL *CallNonvirtualFloatMethodV) (JNIEnv*, jobject, jclass, jmethodID, va_list); jfloat (JNICALL *CallNonvirtualFloatMethodA) (JNIEnv*, jobject, jclass, jmethodID, const jvalue*); jdouble (JNICALL *CallNonvirtualDoubleMethod) (JNIEnv*, jobject, jclass, jmethodID, ...); jdouble (JNICALL *CallNonvirtualDoubleMethodV) (JNIEnv*, jobject, jclass, jmethodID, va_list); jdouble (JNICALL *CallNonvirtualDoubleMethodA) (JNIEnv*, jobject, jclass, jmethodID, const jvalue*); void (JNICALL *CallNonvirtualVoidMethod) (JNIEnv*, jobject, jclass, jmethodID, ...); void (JNICALL *CallNonvirtualVoidMethodV) (JNIEnv*, jobject, jclass, jmethodID, va_list); void (JNICALL *CallNonvirtualVoidMethodA) (JNIEnv*, jobject, jclass, jmethodID, const jvalue*); jfieldID (JNICALL *GetFieldID) (JNIEnv*, jclass, const char*, const char*); jobject (JNICALL *GetObjectField) (JNIEnv*, jobject, jfieldID); jboolean (JNICALL *GetBooleanField) (JNIEnv*, jobject, jfieldID); jbyte (JNICALL *GetByteField) (JNIEnv*, jobject, jfieldID); jchar (JNICALL *GetCharField) (JNIEnv*, jobject, jfieldID); jshort (JNICALL *GetShortField) (JNIEnv*, jobject, jfieldID); jint (JNICALL *GetIntField) (JNIEnv*, jobject, jfieldID); jlong (JNICALL *GetLongField) (JNIEnv*, jobject, jfieldID); jfloat (JNICALL *GetFloatField) (JNIEnv*, jobject, jfieldID); jdouble (JNICALL *GetDoubleField) (JNIEnv*, jobject, jfieldID); void (JNICALL *SetObjectField) (JNIEnv*, jobject, jfieldID, jobject); void (JNICALL *SetBooleanField) (JNIEnv*, jobject, jfieldID, jboolean); void (JNICALL *SetByteField) (JNIEnv*, jobject, jfieldID, jbyte); void (JNICALL *SetCharField) (JNIEnv*, jobject, jfieldID, jchar); void (JNICALL *SetShortField) (JNIEnv*, jobject, jfieldID, jshort); void (JNICALL *SetIntField) (JNIEnv*, jobject, jfieldID, jint); void (JNICALL *SetLongField) (JNIEnv*, jobject, jfieldID, jlong); void (JNICALL *SetFloatField) (JNIEnv*, jobject, jfieldID, jfloat); void (JNICALL *SetDoubleField) (JNIEnv*, jobject, jfieldID, jdouble); jmethodID (JNICALL *GetStaticMethodID) (JNIEnv*, jclass, const char*, const char*); jobject (JNICALL *CallStaticObjectMethod) (JNIEnv*, jclass, jmethodID, ...); jobject (JNICALL *CallStaticObjectMethodV) (JNIEnv*, jclass, jmethodID, va_list); jobject (JNICALL *CallStaticObjectMethodA) (JNIEnv*, jclass, jmethodID, const jvalue*); jboolean (JNICALL *CallStaticBooleanMethod) (JNIEnv*, jclass, jmethodID, ...); jboolean (JNICALL *CallStaticBooleanMethodV) (JNIEnv*, jclass, jmethodID, va_list); jboolean (JNICALL *CallStaticBooleanMethodA) (JNIEnv*, jclass, jmethodID, const jvalue*); jbyte (JNICALL *CallStaticByteMethod) (JNIEnv*, jclass, jmethodID, ...); jbyte (JNICALL *CallStaticByteMethodV) (JNIEnv*, jclass, jmethodID, va_list); jbyte (JNICALL *CallStaticByteMethodA) (JNIEnv*, jclass, jmethodID, const jvalue*); jchar (JNICALL *CallStaticCharMethod) (JNIEnv*, jclass, jmethodID, ...); jchar (JNICALL *CallStaticCharMethodV) (JNIEnv*, jclass, jmethodID, va_list); jchar (JNICALL *CallStaticCharMethodA) (JNIEnv*, jclass, jmethodID, const jvalue*); jshort (JNICALL *CallStaticShortMethod) (JNIEnv*, jclass, jmethodID, ...); jshort (JNICALL *CallStaticShortMethodV) (JNIEnv*, jclass, jmethodID, va_list); jshort (JNICALL *CallStaticShortMethodA) (JNIEnv*, jclass, jmethodID, const jvalue*); jint (JNICALL *CallStaticIntMethod) (JNIEnv*, jclass, jmethodID, ...); jint (JNICALL *CallStaticIntMethodV) (JNIEnv*, jclass, jmethodID, va_list); jint (JNICALL *CallStaticIntMethodA) (JNIEnv*, jclass, jmethodID, const jvalue*); jlong (JNICALL *CallStaticLongMethod) (JNIEnv*, jclass, jmethodID, ...); jlong (JNICALL *CallStaticLongMethodV) (JNIEnv*, jclass, jmethodID, va_list); jlong (JNICALL *CallStaticLongMethodA) (JNIEnv*, jclass, jmethodID, const jvalue*); jfloat (JNICALL *CallStaticFloatMethod) (JNIEnv*, jclass, jmethodID, ...); jfloat (JNICALL *CallStaticFloatMethodV) (JNIEnv*, jclass, jmethodID, va_list); jfloat (JNICALL *CallStaticFloatMethodA) (JNIEnv*, jclass, jmethodID, const jvalue*); jdouble (JNICALL *CallStaticDoubleMethod) (JNIEnv*, jclass, jmethodID, ...); jdouble (JNICALL *CallStaticDoubleMethodV) (JNIEnv*, jclass, jmethodID, va_list); jdouble (JNICALL *CallStaticDoubleMethodA) (JNIEnv*, jclass, jmethodID, const jvalue*); void (JNICALL *CallStaticVoidMethod) (JNIEnv*, jclass, jmethodID, ...); void (JNICALL *CallStaticVoidMethodV) (JNIEnv*, jclass, jmethodID, va_list); void (JNICALL *CallStaticVoidMethodA) (JNIEnv*, jclass, jmethodID, const jvalue*); jfieldID (JNICALL *GetStaticFieldID) (JNIEnv*, jclass, const char*, const char*); jobject (JNICALL *GetStaticObjectField) (JNIEnv*, jclass, jfieldID); jboolean (JNICALL *GetStaticBooleanField) (JNIEnv*, jclass, jfieldID); jbyte (JNICALL *GetStaticByteField) (JNIEnv*, jclass, jfieldID); jchar (JNICALL *GetStaticCharField) (JNIEnv*, jclass, jfieldID); jshort (JNICALL *GetStaticShortField) (JNIEnv*, jclass, jfieldID); jint (JNICALL *GetStaticIntField) (JNIEnv*, jclass, jfieldID); jlong (JNICALL *GetStaticLongField) (JNIEnv*, jclass, jfieldID); jfloat (JNICALL *GetStaticFloatField) (JNIEnv*, jclass, jfieldID); jdouble (JNICALL *GetStaticDoubleField) (JNIEnv*, jclass, jfieldID); void (JNICALL *SetStaticObjectField) (JNIEnv*, jclass, jfieldID, jobject); void (JNICALL *SetStaticBooleanField) (JNIEnv*, jclass, jfieldID, jboolean); void (JNICALL *SetStaticByteField) (JNIEnv*, jclass, jfieldID, jbyte); void (JNICALL *SetStaticCharField) (JNIEnv*, jclass, jfieldID, jchar); void (JNICALL *SetStaticShortField) (JNIEnv*, jclass, jfieldID, jshort); void (JNICALL *SetStaticIntField) (JNIEnv*, jclass, jfieldID, jint); void (JNICALL *SetStaticLongField) (JNIEnv*, jclass, jfieldID, jlong); void (JNICALL *SetStaticFloatField) (JNIEnv*, jclass, jfieldID, jfloat); void (JNICALL *SetStaticDoubleField) (JNIEnv*, jclass, jfieldID, jdouble); jstring (JNICALL *NewString) (JNIEnv*, const jchar*, jsize); jsize (JNICALL *GetStringLength) (JNIEnv*, jstring); const jchar* (JNICALL *GetStringChars) (JNIEnv*, jstring, jboolean*); void (JNICALL *ReleaseStringChars) (JNIEnv*, jstring, const jchar*); jstring (JNICALL *NewStringUTF) (JNIEnv*, const char*); jsize (JNICALL *GetStringUTFLength) (JNIEnv*, jstring); const char* (JNICALL *GetStringUTFChars) (JNIEnv*, jstring, jboolean*); void (JNICALL *ReleaseStringUTFChars) (JNIEnv*, jstring, const char*); jsize (JNICALL *GetArrayLength) (JNIEnv*, jarray); jobjectArray (JNICALL *NewObjectArray) (JNIEnv*, jsize, jclass, jobject); jobject (JNICALL *GetObjectArrayElement) (JNIEnv*, jobjectArray, jsize); void (JNICALL *SetObjectArrayElement) (JNIEnv*, jobjectArray, jsize, jobject); jbooleanArray (JNICALL *NewBooleanArray) (JNIEnv*, jsize); jbyteArray (JNICALL *NewByteArray) (JNIEnv*, jsize); jcharArray (JNICALL *NewCharArray) (JNIEnv*, jsize); jshortArray (JNICALL *NewShortArray) (JNIEnv*, jsize); jintArray (JNICALL *NewIntArray) (JNIEnv*, jsize); jlongArray (JNICALL *NewLongArray) (JNIEnv*, jsize); jfloatArray (JNICALL *NewFloatArray) (JNIEnv*, jsize); jdoubleArray (JNICALL *NewDoubleArray) (JNIEnv*, jsize); jboolean* (JNICALL *GetBooleanArrayElements) (JNIEnv*, jbooleanArray, jboolean*); jbyte* (JNICALL *GetByteArrayElements) (JNIEnv*, jbyteArray, jboolean*); jchar* (JNICALL *GetCharArrayElements) (JNIEnv*, jcharArray, jboolean*); jshort* (JNICALL *GetShortArrayElements) (JNIEnv*, jshortArray, jboolean*); jint* (JNICALL *GetIntArrayElements) (JNIEnv*, jintArray, jboolean*); jlong* (JNICALL *GetLongArrayElements) (JNIEnv*, jlongArray, jboolean*); jfloat* (JNICALL *GetFloatArrayElements) (JNIEnv*, jfloatArray, jboolean*); jdouble* (JNICALL *GetDoubleArrayElements) (JNIEnv*, jdoubleArray, jboolean*); void (JNICALL *ReleaseBooleanArrayElements) (JNIEnv*, jbooleanArray, jboolean*, jint); void (JNICALL *ReleaseByteArrayElements) (JNIEnv*, jbyteArray, jbyte*, jint); void (JNICALL *ReleaseCharArrayElements) (JNIEnv*, jcharArray, jchar*, jint); void (JNICALL *ReleaseShortArrayElements) (JNIEnv*, jshortArray, jshort*, jint); void (JNICALL *ReleaseIntArrayElements) (JNIEnv*, jintArray, jint*, jint); void (JNICALL *ReleaseLongArrayElements) (JNIEnv*, jlongArray, jlong*, jint); void (JNICALL *ReleaseFloatArrayElements) (JNIEnv*, jfloatArray, jfloat*, jint); void (JNICALL *ReleaseDoubleArrayElements) (JNIEnv*, jdoubleArray, jdouble*, jint); void (JNICALL *GetBooleanArrayRegion) (JNIEnv*, jbooleanArray, jsize, jsize, jboolean*); void (JNICALL *GetByteArrayRegion) (JNIEnv*, jbyteArray, jsize, jsize, jbyte*); void (JNICALL *GetCharArrayRegion) (JNIEnv*, jcharArray, jsize, jsize, jchar*); void (JNICALL *GetShortArrayRegion) (JNIEnv*, jshortArray, jsize, jsize, jshort*); void (JNICALL *GetIntArrayRegion) (JNIEnv*, jintArray, jsize, jsize, jint*); void (JNICALL *GetLongArrayRegion) (JNIEnv*, jlongArray, jsize, jsize, jlong*); void (JNICALL *GetFloatArrayRegion) (JNIEnv*, jfloatArray, jsize, jsize, jfloat*); void (JNICALL *GetDoubleArrayRegion) (JNIEnv*, jdoubleArray, jsize, jsize, jdouble*); void (JNICALL *SetBooleanArrayRegion) (JNIEnv*, jbooleanArray, jsize, jsize, const jboolean*); void (JNICALL *SetByteArrayRegion) (JNIEnv*, jbyteArray, jsize, jsize, const jbyte*); void (JNICALL *SetCharArrayRegion) (JNIEnv*, jcharArray, jsize, jsize, const jchar*); void (JNICALL *SetShortArrayRegion) (JNIEnv*, jshortArray, jsize, jsize, const jshort*); void (JNICALL *SetIntArrayRegion) (JNIEnv*, jintArray, jsize, jsize, const jint*); void (JNICALL *SetLongArrayRegion) (JNIEnv*, jlongArray, jsize, jsize, const jlong*); void (JNICALL *SetFloatArrayRegion) (JNIEnv*, jfloatArray, jsize, jsize, const jfloat*); void (JNICALL *SetDoubleArrayRegion) (JNIEnv*, jdoubleArray, jsize, jsize, const jdouble*); jint (JNICALL *RegisterNatives) (JNIEnv*, jclass, const JNINativeMethod*, jint); jint (JNICALL *UnregisterNatives) (JNIEnv*, jclass); jint (JNICALL *MonitorEnter) (JNIEnv*, jobject); jint (JNICALL *MonitorExit) (JNIEnv*, jobject); jint (JNICALL *GetJavaVM) (JNIEnv*, JavaVM**); void (JNICALL *GetStringRegion) (JNIEnv*, jstring, jsize, jsize, jchar*); void (JNICALL *GetStringUTFRegion) (JNIEnv*, jstring, jsize, jsize, char*); void* (JNICALL *GetPrimitiveArrayCritical) (JNIEnv*, jarray, jboolean*); void (JNICALL *ReleasePrimitiveArrayCritical) (JNIEnv*, jarray, void*, jint); const jchar* (JNICALL *GetStringCritical) (JNIEnv*, jstring, jboolean*); void (JNICALL *ReleaseStringCritical) (JNIEnv*, jstring, const jchar*); jweak (JNICALL *NewWeakGlobalRef) (JNIEnv*, jobject); void (JNICALL *DeleteWeakGlobalRef) (JNIEnv*, jweak); jboolean (JNICALL *ExceptionCheck) (JNIEnv*); jobject (JNICALL *NewDirectByteBuffer) (JNIEnv*, void*, jlong); void* (JNICALL *GetDirectBufferAddress) (JNIEnv* env, jobject); jlong (JNICALL *GetDirectBufferCapacity) (JNIEnv*, jobject); #if TARGET_RT_MAC_CFM && defined(__ppc__) void* real_functions[228]; #endif }; inline void atomicOr(uint32_t* p, int v) { for (uint32_t old = *p; not atomicCompareAndSwap32(p, old, old | v); old = *p) { } } inline void atomicAnd(uint32_t* p, int v) { for (uint32_t old = *p; not atomicCompareAndSwap32(p, old, old & v); old = *p) { } } inline int strcmp(const int8_t* a, const int8_t* b) { return ::strcmp(reinterpret_cast(a), reinterpret_cast(b)); } void noop(); class Reference { public: Reference(object target, Reference** handle, bool weak): target(target), next(*handle), handle(handle), count(0), weak(weak) { if (next) { next->handle = &next; } *handle = this; } object target; Reference* next; Reference** handle; unsigned count; bool weak; }; class Classpath; class Machine { public: enum Type { #include "type-enums.cpp" }; enum AllocationType { MovableAllocation, FixedAllocation, ImmortalAllocation }; enum Root { BootLoader, AppLoader, BootstrapClassMap, PackageMap, FindLoadedClassMethod, LoadClassMethod, MonitorMap, StringMap, ByteArrayMap, PoolMap, ClassRuntimeDataTable, MethodRuntimeDataTable, JNIMethodTable, JNIFieldTable, ShutdownHooks, FinalizerThread, ObjectsToFinalize, ObjectsToClean, NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException, OutOfMemoryError, Shutdown, VirtualFileFinders, VirtualFiles, ArrayInterfaceTable, ThreadTerminated }; static const unsigned RootCount = ThreadTerminated + 1; Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder, Processor* processor, Classpath* classpath, const char** properties, unsigned propertyCount, const char** arguments, unsigned argumentCount, unsigned stackSizeInBytes); ~Machine() { dispose(); } void dispose(); JavaVMVTable* vtable; System* system; Heap::Client* heapClient; Heap* heap; Finder* bootFinder; Finder* appFinder; Processor* processor; Classpath* classpath; Thread* rootThread; Thread* exclusive; Thread* finalizeThread; Reference* jniReferences; const char** properties; unsigned propertyCount; const char** arguments; unsigned argumentCount; unsigned threadCount; unsigned activeCount; unsigned liveCount; unsigned daemonCount; unsigned fixedFootprint; unsigned stackSizeInBytes; System::Local* localThread; System::Monitor* stateLock; System::Monitor* heapLock; System::Monitor* classLock; System::Monitor* referenceLock; System::Monitor* shutdownLock; System::Library* libraries; FILE* errorLog; BootImage* bootimage; object types; object roots; object finalizers; object tenuredFinalizers; object finalizeQueue; object weakReferences; object tenuredWeakReferences; bool unsafe; bool collecting; bool triedBuiltinOnLoad; bool dumpedHeapOnOOM; bool alive; JavaVMVTable javaVMVTable; JNIEnvVTable jniEnvVTable; uintptr_t* heapPool[ThreadHeapPoolSize]; unsigned heapPoolIndex; unsigned bootimageSize; }; void printTrace(Thread* t, object exception); uint8_t& threadInterrupted(Thread* t, object thread); void enterActiveState(Thread* t); #ifdef VM_STRESS inline void stress(Thread* t); #else // not VM_STRESS #define stress(t) #endif // not VM_STRESS uint64_t runThread(Thread*, uintptr_t*); uint64_t run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments); void checkDaemon(Thread* t); object& root(Thread* t, Machine::Root root); extern "C" uint64_t vmRun(uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments, void* checkpoint); extern "C" void vmRun_returnAddress(); class Thread { public: enum State { NoState, ActiveState, IdleState, ZombieState, JoinedState, ExclusiveState, ExitState }; static const unsigned UseBackupHeapFlag = 1 << 0; static const unsigned WaitingFlag = 1 << 1; static const unsigned TracingFlag = 1 << 2; static const unsigned DaemonFlag = 1 << 3; static const unsigned StressFlag = 1 << 4; static const unsigned ActiveFlag = 1 << 5; static const unsigned SystemFlag = 1 << 6; static const unsigned JoinFlag = 1 << 7; class Protector { public: Protector(Thread* t): t(t), next(t->protector) { t->protector = this; } ~Protector() { t->protector = next; } virtual void visit(Heap::Visitor* v) = 0; Thread* t; Protector* next; }; class SingleProtector: public Protector { public: SingleProtector(Thread* t, object* p): Protector(t), p(p) { } virtual void visit(Heap::Visitor* v) { v->visit(p); } object* p; }; class Resource { public: Resource(Thread* t): t(t), next(t->resource) { t->resource = this; } ~Resource() { t->resource = next; } virtual void release() = 0; Thread* t; Resource* next; }; class ClassInitStack: public Resource { public: ClassInitStack(Thread* t, object class_): Resource(t), next(t->classInitStack), class_(class_), protector(t, &(this->class_)) { t->classInitStack = this; } ~ClassInitStack() { t->classInitStack = next; } virtual void release() { this->ClassInitStack::~ClassInitStack(); } ClassInitStack* next; object class_; SingleProtector protector; }; class Checkpoint { public: Checkpoint(Thread* t): t(t), next(t->checkpoint), resource(t->resource), protector(t->protector), noThrow(false) { t->checkpoint = this; } ~Checkpoint() { t->checkpoint = next; } virtual void NO_RETURN unwind() = 0; Thread* t; Checkpoint* next; Resource* resource; Protector* protector; bool noThrow; }; class RunCheckpoint: public Checkpoint { public: RunCheckpoint(Thread* t): Checkpoint(t), stack(0) { } virtual void unwind() { void* stack = this->stack; this->stack = 0; expect(t->m->system, stack); vmJump(voidPointer(vmRun_returnAddress), 0, stack, t, 0, 0); } void* stack; }; class Runnable: public System::Runnable { public: Runnable(Thread* t): t(t) { } virtual void attach(System::Thread* st) { t->systemThread = st; } virtual void run() { enterActiveState(t); vm::run(t, runThread, 0); if (t->exception and t->exception != root(t, Machine::Shutdown)) { printTrace(t, t->exception); } t->exit(); } virtual bool interrupted() { return t->javaThread and threadInterrupted(t, t->javaThread); } virtual void setInterrupted(bool v) { threadInterrupted(t, t->javaThread) = v; } Thread* t; }; Thread(Machine* m, object javaThread, Thread* parent); void init(); void exit(); void dispose(); JNIEnvVTable* vtable; Machine* m; Thread* parent; Thread* peer; Thread* child; Thread* waitNext; State state; unsigned criticalLevel; System::Thread* systemThread; System::Monitor* lock; object javaThread; object exception; unsigned heapIndex; unsigned heapOffset; Protector* protector; ClassInitStack* classInitStack; Resource* resource; Checkpoint* checkpoint; Runnable runnable; uintptr_t* defaultHeap; uintptr_t* heap; uintptr_t backupHeap[ThreadBackupHeapSizeInWords]; unsigned backupHeapIndex; unsigned flags; }; class Classpath { public: virtual object makeJclass(Thread* t, object class_) = 0; virtual object makeString(Thread* t, object array, int32_t offset, int32_t length) = 0; virtual object makeThread(Thread* t, Thread* parent) = 0; virtual object makeJMethod(Thread* t, object vmMethod) = 0; virtual object getVMMethod(Thread* t, object jmethod) = 0; virtual object makeJField(Thread* t, object vmField) = 0; virtual object getVMField(Thread* t, object jfield) = 0; virtual void clearInterrupted(Thread* t) = 0; virtual void runThread(Thread* t) = 0; virtual void resolveNative(Thread* t, object method) = 0; virtual void interceptMethods(Thread* t) = 0; virtual void preBoot(Thread* t) = 0; virtual void boot(Thread* t) = 0; virtual const char* bootClasspath() = 0; virtual object makeDirectByteBuffer(Thread* t, void* p, jlong capacity) = 0; virtual void* getDirectBufferAddress(Thread* t, object buffer) = 0; virtual int64_t getDirectBufferCapacity(Thread* t, object buffer) = 0; virtual bool canTailCall(Thread* t, object caller, object calleeClassName, object calleeMethodName, object calleeMethodSpec) = 0; virtual void shutDown(Thread* t) = 0; virtual void dispose() = 0; }; #ifdef _MSC_VER template class ThreadRuntimeArray: public Thread::Resource { public: ThreadRuntimeArray(Thread* t, unsigned size): Resource(t), body(static_cast(t->m->heap->allocate(size * sizeof(T)))), size(size) { } ~ThreadRuntimeArray() { t->m->heap->free(body, size * sizeof(T)); } virtual void release() { ThreadRuntimeArray::~ThreadRuntimeArray(); } T* body; unsigned size; }; # define THREAD_RUNTIME_ARRAY(thread, type, name, size) \ ThreadRuntimeArray name(thread, size); #else // not _MSC_VER # define THREAD_RUNTIME_ARRAY(thread, type, name, size) \ type name##_body[size]; #endif // not _MSC_VER Classpath* makeClasspath(System* system, Allocator* allocator, const char* javaHome, const char* embedPrefix); typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*); inline object objectClass(Thread*, object o) { return maskAlignedPointer(fieldAtOffset(o, 0)); } inline unsigned stackSizeInWords(Thread* t) { return t->m->stackSizeInBytes / BytesPerWord; } void enter(Thread* t, Thread::State state); inline void enterActiveState(Thread* t) { enter(t, Thread::ActiveState); } class StateResource: public Thread::Resource { public: StateResource(Thread* t, Thread::State state): Resource(t), oldState(t->state) { enter(t, state); } ~StateResource() { enter(t, oldState); } virtual void release() { this->StateResource::~StateResource(); } private: Thread::State oldState; }; inline void dispose(Thread* t, Reference* r) { *(r->handle) = r->next; if (r->next) { r->next->handle = r->handle; } t->m->heap->free(r, sizeof(*r)); } inline void acquire(Thread*, Reference* r) { ++ r->count; } inline void release(Thread* t, Reference* r) { if ((-- r->count) == 0) { dispose(t, r); } } void collect(Thread* t, Heap::CollectionType type, int pendingAllocation = 0); void shutDown(Thread* t); #ifdef VM_STRESS inline void stress(Thread* t) { if ((not t->m->unsafe) and (t->flags & (Thread::StressFlag | Thread::TracingFlag)) == 0 and t->state != Thread::NoState and t->state != Thread::IdleState) { atomicOr(&(t->flags), Thread::StressFlag); # ifdef VM_STRESS_MAJOR collect(t, Heap::MajorCollection); # else // not VM_STRESS_MAJOR collect(t, Heap::MinorCollection); # endif // not VM_STRESS_MAJOR atomicAnd(&(t->flags), ~Thread::StressFlag); } } #endif // not VM_STRESS inline void acquire(Thread* t, System::Monitor* m) { if (not m->tryAcquire(t->systemThread)) { ENTER(t, Thread::IdleState); m->acquire(t->systemThread); } stress(t); } inline void release(Thread* t, System::Monitor* m) { m->release(t->systemThread); } class MonitorResource: public Thread::Resource { public: MonitorResource(Thread* t, System::Monitor* m): Resource(t), m(m) { acquire(t, m); } ~MonitorResource() { vm::release(t, m); } virtual void release() { this->MonitorResource::~MonitorResource(); } private: System::Monitor* m; }; class RawMonitorResource: public Thread::Resource { public: RawMonitorResource(Thread* t, System::Monitor* m): Resource(t), m(m) { m->acquire(t->systemThread); } ~RawMonitorResource() { vm::release(t, m); } virtual void release() { this->RawMonitorResource::~RawMonitorResource(); } private: System::Monitor* m; }; inline Aborter* getAborter(Thread* t) { return t->m->system; } inline bool ensure(Thread* t, unsigned sizeInBytes) { if (t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords) { if (sizeInBytes <= ThreadBackupHeapSizeInBytes) { expect(t, (t->flags & Thread::UseBackupHeapFlag) == 0); atomicOr(&(t->flags), Thread::UseBackupHeapFlag); return true; } else { return false; } } else { return true; } } object allocate2(Thread* t, unsigned sizeInBytes, bool objectMask); object allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, unsigned sizeInBytes, bool objectMask); inline object allocateSmall(Thread* t, unsigned sizeInBytes) { assert(t, t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord) <= ThreadHeapSizeInWords); object o = reinterpret_cast(t->heap + t->heapIndex); t->heapIndex += ceilingDivide(sizeInBytes, BytesPerWord); return o; } inline object allocate(Thread* t, unsigned sizeInBytes, bool objectMask) { stress(t); if (UNLIKELY(t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords or t->m->exclusive)) { return allocate2(t, sizeInBytes, objectMask); } else { return allocateSmall(t, sizeInBytes); } } inline void mark(Thread* t, object o, unsigned offset, unsigned count) { t->m->heap->mark(o, offset / BytesPerWord, count); } inline void mark(Thread* t, object o, unsigned offset) { t->m->heap->mark(o, offset / BytesPerWord, 1); } inline void set(Thread* t, object target, unsigned offset, object value) { fieldAtOffset(target, offset) = value; mark(t, target, offset); } inline void setObjectClass(Thread*, object o, object value) { fieldAtOffset(o, 0) = reinterpret_cast (reinterpret_cast(value) | (reinterpret_cast (fieldAtOffset(o, 0)) & (~PointerMask))); } inline const char* findProperty(Machine* m, const char* name) { for (unsigned i = 0; i < m->propertyCount; ++i) { const char* p = m->properties[i]; const char* n = name; while (*p and *p != '=' and *n and *p == *n) { ++ p; ++ n; } if (*p == '=' and *n == 0) { return p + 1; } } return 0; } inline const char* findProperty(Thread* t, const char* name) { return findProperty(t->m, name); } object& arrayBodyUnsafe(Thread*, object, unsigned); bool instanceOf(Thread* t, object class_, object o); #include "type-declarations.cpp" inline uint64_t runRaw(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments) { Thread::RunCheckpoint checkpoint(t); return vmRun(function, arguments, &checkpoint); } inline uint64_t run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments) { ENTER(t, Thread::ActiveState); return runRaw(t, function, arguments); } inline void runJavaThread(Thread* t) { t->m->classpath->runThread(t); } void runFinalizeThread(Thread* t); inline uint64_t runThread(Thread* t, uintptr_t*) { t->m->localThread->set(t); checkDaemon(t); if (t == t->m->finalizeThread) { runFinalizeThread(t); } else if (t->javaThread) { runJavaThread(t); } return 1; } inline bool startThread(Thread* t, Thread* p) { p->flags |= Thread::JoinFlag; return t->m->system->success(t->m->system->start(&(p->runnable))); } inline void addThread(Thread* t, Thread* p) { ACQUIRE_RAW(t, t->m->stateLock); assert(t, p->state == Thread::NoState); expect(t, t->state == Thread::ActiveState || t->state == Thread::ExclusiveState || t->state == Thread::NoState); p->state = Thread::IdleState; ++ t->m->threadCount; ++ t->m->liveCount; p->peer = p->parent->child; p->parent->child = p; if (p->javaThread) { threadPeer(t, p->javaThread) = reinterpret_cast(p); } } inline void removeThread(Thread* t, Thread* p) { ACQUIRE_RAW(t, t->m->stateLock); assert(t, p->state == Thread::IdleState); -- t->m->liveCount; -- t->m->threadCount; t->m->stateLock->notifyAll(t->systemThread); p->parent->child = p->peer; if (p->javaThread) { threadPeer(t, p->javaThread) = 0; } p->dispose(); } inline Thread* startThread(Thread* t, object javaThread) { { PROTECT(t, javaThread); stress(t); ACQUIRE_RAW(t, t->m->stateLock); if (t->m->threadCount > t->m->liveCount + ZombieCollectionThreshold) { collect(t, Heap::MinorCollection); } } Thread* p = t->m->processor->makeThread(t->m, javaThread, t); addThread(t, p); if (startThread(t, p)) { return p; } else { removeThread(t, p); return 0; } } inline void registerDaemon(Thread* t) { ACQUIRE_RAW(t, t->m->stateLock); atomicOr(&(t->flags), Thread::DaemonFlag); ++ t->m->daemonCount; t->m->stateLock->notifyAll(t->systemThread); } inline void checkDaemon(Thread* t) { if (threadDaemon(t, t->javaThread)) { registerDaemon(t); } } inline uint64_t initAttachedThread(Thread* t, uintptr_t* arguments) { bool daemon = arguments[0]; t->javaThread = t->m->classpath->makeThread(t, t->m->rootThread); threadPeer(t, t->javaThread) = reinterpret_cast(t); if (daemon) { threadDaemon(t, t->javaThread) = true; registerDaemon(t); } t->m->localThread->set(t); return 1; } inline Thread* attachThread(Machine* m, bool daemon) { Thread* t = m->processor->makeThread(m, 0, m->rootThread); m->system->attach(&(t->runnable)); addThread(t, t); enter(t, Thread::ActiveState); uintptr_t arguments[] = { daemon }; if (run(t, initAttachedThread, arguments)) { enter(t, Thread::IdleState); return t; } else { t->exit(); return 0; } } inline object& root(Thread* t, Machine::Root root) { return arrayBody(t, t->m->roots, root); } inline void setRoot(Thread* t, Machine::Root root, object value) { set(t, t->m->roots, ArrayBody + (root * BytesPerWord), value); } inline object type(Thread* t, Machine::Type type) { return arrayBody(t, t->m->types, type); } inline void setType(Thread* t, Machine::Type type, object value) { set(t, t->m->types, ArrayBody + (type * BytesPerWord), value); } inline bool objectFixed(Thread*, object o) { return (alias(o, 0) & (~PointerMask)) == FixedMark; } inline bool objectExtended(Thread*, object o) { return (alias(o, 0) & (~PointerMask)) == ExtendedMark; } inline bool hashTaken(Thread*, object o) { return (alias(o, 0) & (~PointerMask)) == HashTakenMark; } inline unsigned baseSize(Thread* t, object o, object class_) { assert(t, classFixedSize(t, class_) >= BytesPerWord); return ceilingDivide(classFixedSize(t, class_), BytesPerWord) + ceilingDivide(classArrayElementSize(t, class_) * fieldAtOffset(o, classFixedSize(t, class_) - BytesPerWord), BytesPerWord); } object makeTrace(Thread* t, Processor::StackWalker* walker); object makeTrace(Thread* t, Thread* target); inline object makeTrace(Thread* t) { return makeTrace(t, t); } inline object makeNew(Thread* t, object class_) { assert(t, t->state == Thread::NoState or t->state == Thread::ActiveState); PROTECT(t, class_); unsigned sizeInBytes = pad(classFixedSize(t, class_)); assert(t, sizeInBytes); object instance = allocate(t, sizeInBytes, classObjectMask(t, class_)); setObjectClass(t, instance, class_); return instance; } object makeNewGeneral(Thread* t, object class_); inline object make(Thread* t, object class_) { if (UNLIKELY(classVmFlags(t, class_) & (WeakReferenceFlag | HasFinalizerFlag))) { return makeNewGeneral(t, class_); } else { return makeNew(t, class_); } } object makeByteArrayV(Thread* t, const char* format, va_list a, int size); object makeByteArray(Thread* t, const char* format, ...); object makeString(Thread* t, const char* format, ...); #ifndef HAVE_StringOffset inline unsigned stringLength(Thread* t, object string) { return charArrayLength(t, stringData(t, string)); } inline unsigned stringOffset(Thread*, object) { return 0; } inline object makeString(Thread* t, object data, unsigned offset, unsigned length, unsigned) { if (offset == 0 and length == charArrayLength(t, data)) { return makeString(t, data, 0, 0); } else { PROTECT(t, data); object array = makeCharArray(t, length); memcpy(&charArrayBody(t, array, 0), &charArrayBody(t, data, offset), length * 2); return makeString(t, array, 0, 0); } } #endif // not HAVE_StringOffset int stringUTFLength(Thread* t, object string, unsigned start, unsigned length); inline int stringUTFLength(Thread* t, object string) { return stringUTFLength(t, string, 0, stringLength(t, string)); } void stringChars(Thread* t, object string, unsigned start, unsigned length, char* chars); inline void stringChars(Thread* t, object string, char* chars) { stringChars(t, string, 0, stringLength(t, string), chars); } void stringChars(Thread* t, object string, unsigned start, unsigned length, uint16_t* chars); inline void stringChars(Thread* t, object string, uint16_t* chars) { stringChars(t, string, 0, stringLength(t, string), chars); } void stringUTFChars(Thread* t, object string, unsigned start, unsigned length, char* chars, unsigned charsLength); inline void stringUTFChars(Thread* t, object string, char* chars, unsigned charsLength) { stringUTFChars(t, string, 0, stringLength(t, string), chars, charsLength); } bool isAssignableFrom(Thread* t, object a, object b); object classInitializer(Thread* t, object class_); object frameMethod(Thread* t, int frame); inline uintptr_t& extendedWord(Thread* t UNUSED, object o, unsigned baseSize) { assert(t, objectExtended(t, o)); return fieldAtOffset(o, baseSize * BytesPerWord); } inline unsigned extendedSize(Thread* t, object o, unsigned baseSize) { return baseSize + objectExtended(t, o); } inline void markHashTaken(Thread* t, object o) { assert(t, not objectExtended(t, o)); assert(t, not objectFixed(t, o)); ACQUIRE_RAW(t, t->m->heapLock); alias(o, 0) |= HashTakenMark; t->m->heap->pad(o); } inline uint32_t takeHash(Thread*, object o) { // some broken code implicitly relies on System.identityHashCode // always returning a non-negative number (e.g. old versions of // com/sun/xml/bind/v2/util/CollisionCheckStack.hash), hence the "& // 0x7FFFFFFF": return (reinterpret_cast(o) / BytesPerWord) & 0x7FFFFFFF; } inline uint32_t objectHash(Thread* t, object o) { if (objectExtended(t, o)) { return extendedWord(t, o, baseSize(t, o, objectClass(t, o))); } else { if (not objectFixed(t, o)) { markHashTaken(t, o); } return takeHash(t, o); } } inline bool objectEqual(Thread*, object a, object b) { return a == b; } inline uint32_t byteArrayHash(Thread* t, object array) { return hash(&byteArrayBody(t, array, 0), byteArrayLength(t, array)); } inline uint32_t charArrayHash(Thread* t, object array) { return hash(&charArrayBody(t, array, 0), charArrayLength(t, array)); } inline bool byteArrayEqual(Thread* t, object a, object b) { return a == b or ((byteArrayLength(t, a) == byteArrayLength(t, b)) and memcmp(&byteArrayBody(t, a, 0), &byteArrayBody(t, b, 0), byteArrayLength(t, a)) == 0); } inline uint32_t stringHash(Thread* t, object s) { if (stringHashCode(t, s) == 0 and stringLength(t, s)) { object data = stringData(t, s); if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { stringHashCode(t, s) = hash (&byteArrayBody(t, data, stringOffset(t, s)), stringLength(t, s)); } else { stringHashCode(t, s) = hash (&charArrayBody(t, data, stringOffset(t, s)), stringLength(t, s)); } } return stringHashCode(t, s); } inline uint16_t stringCharAt(Thread* t, object s, int i) { object data = stringData(t, s); if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { return byteArrayBody(t, data, stringOffset(t, s) + i); } else { return charArrayBody(t, data, stringOffset(t, s) + i); } } inline bool stringEqual(Thread* t, object a, object b) { if (a == b) { return true; } else if (stringLength(t, a) == stringLength(t, b)) { for (unsigned i = 0; i < stringLength(t, a); ++i) { if (stringCharAt(t, a, i) != stringCharAt(t, b, i)) { return false; } } return true; } else { return false; } } inline uint32_t methodHash(Thread* t, object method) { return byteArrayHash(t, methodName(t, method)) ^ byteArrayHash(t, methodSpec(t, method)); } inline bool methodEqual(Thread* t, object a, object b) { return a == b or (byteArrayEqual(t, methodName(t, a), methodName(t, b)) and byteArrayEqual(t, methodSpec(t, a), methodSpec(t, b))); } class MethodSpecIterator { public: MethodSpecIterator(Thread* t, const char* s): t(t), s(s + 1) { } const char* next() { assert(t, *s != ')'); const char* p = s; switch (*s) { case 'L': while (*s and *s != ';') ++ s; ++ s; break; case '[': while (*s == '[') ++ s; switch (*s) { case 'L': while (*s and *s != ';') ++ s; ++ s; break; default: ++ s; break; } break; default: ++ s; break; } return p; } bool hasNext() { return *s != ')'; } const char* returnSpec() { assert(t, *s == ')'); return s + 1; } Thread* t; const char* s; }; unsigned fieldCode(Thread* t, unsigned javaCode); unsigned fieldType(Thread* t, unsigned code); unsigned primitiveSize(Thread* t, unsigned code); inline unsigned fieldSize(Thread* t, unsigned code) { if (code == ObjectField) { return BytesPerWord; } else { return primitiveSize(t, code); } } inline unsigned fieldSize(Thread* t, object field) { return fieldSize(t, fieldCode(t, field)); } inline void scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount, unsigned* returnCode) { unsigned count = 0; MethodSpecIterator it(t, s); for (; it.hasNext(); it.next()) { ++ count; } *parameterCount = count; *returnCode = fieldCode(t, *it.returnSpec()); } object findLoadedClass(Thread* t, object loader, object spec); inline bool emptyMethod(Thread* t, object method) { return ((methodFlags(t, method) & ACC_NATIVE) == 0) and (codeLength(t, methodCode(t, method)) == 1) and (codeBody(t, methodCode(t, method), 0) == return_); } object parseUtf8(Thread* t, const char* data, unsigned length); object parseUtf8(Thread* t, object array); object parseClass(Thread* t, object loader, const uint8_t* data, unsigned length, Machine::Type throwType = Machine::NoClassDefFoundErrorType); object resolveClass(Thread* t, object loader, object name, bool throw_ = true, Machine::Type throwType = Machine::NoClassDefFoundErrorType); inline object resolveClass(Thread* t, object loader, const char* name, bool throw_ = true, Machine::Type throwType = Machine::NoClassDefFoundErrorType) { PROTECT(t, loader); object n = makeByteArray(t, "%s", name); return resolveClass(t, loader, n, throw_, throwType); } object resolveSystemClass (Thread* t, object loader, object name, bool throw_ = true, Machine::Type throwType = Machine::NoClassDefFoundErrorType); inline object resolveSystemClass(Thread* t, object loader, const char* name) { return resolveSystemClass(t, loader, makeByteArray(t, "%s", name)); } void linkClass(Thread* t, object loader, object class_); object resolveMethod(Thread* t, object class_, const char* methodName, const char* methodSpec); inline object resolveMethod(Thread* t, object loader, const char* className, const char* methodName, const char* methodSpec) { return resolveMethod (t, resolveClass(t, loader, className), methodName, methodSpec); } object resolveField(Thread* t, object class_, const char* fieldName, const char* fieldSpec); inline object resolveField(Thread* t, object loader, const char* className, const char* fieldName, const char* fieldSpec) { return resolveField (t, resolveClass(t, loader, className), fieldName, fieldSpec); } bool classNeedsInit(Thread* t, object c); bool preInitClass(Thread* t, object c); void postInitClass(Thread* t, object c); void initClass(Thread* t, object c); object resolveObjectArrayClass(Thread* t, object loader, object elementClass); object makeObjectArray(Thread* t, object elementClass, unsigned count); inline object makeObjectArray(Thread* t, unsigned count) { return makeObjectArray(t, type(t, Machine::JobjectType), count); } object findFieldInClass(Thread* t, object class_, object name, object spec); inline object findFieldInClass2(Thread* t, object class_, const char* name, const char* spec) { PROTECT(t, class_); object n = makeByteArray(t, "%s", name); PROTECT(t, n); object s = makeByteArray(t, "%s", spec); return findFieldInClass(t, class_, n, s); } object findMethodInClass(Thread* t, object class_, object name, object spec); inline object makeThrowable (Thread* t, Machine::Type type, object message = 0, object trace = 0, object cause = 0) { PROTECT(t, message); PROTECT(t, trace); PROTECT(t, cause); if (trace == 0) { trace = makeTrace(t); } object result = make(t, vm::type(t, type)); set(t, result, ThrowableMessage, message); set(t, result, ThrowableTrace, trace); set(t, result, ThrowableCause, cause); return result; } inline object makeThrowableV(Thread* t, Machine::Type type, const char* format, va_list a, int size) { object s = makeByteArrayV(t, format, a, size); if (s) { object message = t->m->classpath->makeString (t, s, 0, byteArrayLength(t, s) - 1); return makeThrowable(t, type, message); } else { return 0; } } inline object makeThrowable(Thread* t, Machine::Type type, const char* format, ...) { int size = 256; while (true) { va_list a; va_start(a, format); object r = makeThrowableV(t, type, format, a, size); va_end(a); if (r) { return r; } else { size *= 2; } } } void popResources(Thread* t); } // namespace vm AVIAN_EXPORT void vmPrintTrace(vm::Thread* t); AVIAN_EXPORT void vmfPrintTrace(vm::Thread* t, FILE* out); namespace vm { void dumpHeap(Thread* t, FILE* out); inline void NO_RETURN throw_(Thread* t, object e) { assert(t, t->exception == 0); assert(t, e); expect(t, not t->checkpoint->noThrow); t->exception = e; if (objectClass(t, e) == type(t, Machine::OutOfMemoryErrorType)) { #ifdef AVIAN_HEAPDUMP if (not t->m->dumpedHeapOnOOM) { t->m->dumpedHeapOnOOM = true; const char* path = findProperty(t, "avian.heap.dump"); if (path) { FILE* out = vm::fopen(path, "wb"); if (out) { dumpHeap(t, out); fclose(out); } } } #endif//AVIAN_HEAPDUMP if (AbortOnOutOfMemoryError) { fprintf(stderr, "OutOfMemoryError\n"); vmPrintTrace(t); abort(); } } // printTrace(t, e); popResources(t); t->checkpoint->unwind(); abort(t); } inline void NO_RETURN throwNew (Thread* t, Machine::Type type, object message = 0, object trace = 0, object cause = 0) { throw_(t, makeThrowable(t, type, message, trace, cause)); } inline void NO_RETURN throwNew(Thread* t, Machine::Type type, const char* format, ...) { int size = 256; while (true) { va_list a; va_start(a, format); object r = makeThrowableV(t, type, format, a, size); va_end(a); if (r) { throw_(t, r); } else { size *= 2; } } } object findInHierarchyOrNull(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object)); inline object findInHierarchy(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object), Machine::Type errorType, bool throw_ = true) { object o = findInHierarchyOrNull(t, class_, name, spec, find); if (throw_ and o == 0) { throwNew(t, errorType, "%s %s not found in %s", &byteArrayBody(t, name, 0), &byteArrayBody(t, spec, 0), &byteArrayBody(t, className(t, class_), 0)); } return o; } inline object findMethod(Thread* t, object class_, object name, object spec) { return findInHierarchy (t, class_, name, spec, findMethodInClass, Machine::NoSuchMethodErrorType); } inline object findMethodOrNull(Thread* t, object class_, const char* name, const char* spec) { PROTECT(t, class_); object n = makeByteArray(t, "%s", name); PROTECT(t, n); object s = makeByteArray(t, "%s", spec); return findInHierarchyOrNull(t, class_, n, s, findMethodInClass); } inline object findVirtualMethod(Thread* t, object method, object class_) { return arrayBody(t, classVirtualTable(t, class_), methodOffset(t, method)); } inline object findInterfaceMethod(Thread* t, object method, object class_) { assert(t, (classVmFlags(t, class_) & BootstrapFlag) == 0); object interface = methodClass(t, method); object itable = classInterfaceTable(t, class_); for (unsigned i = 0; i < arrayLength(t, itable); i += 2) { if (arrayBody(t, itable, i) == interface) { return arrayBody (t, arrayBody(t, itable, i + 1), methodOffset(t, method)); } } abort(t); } inline unsigned objectArrayLength(Thread* t UNUSED, object array) { assert(t, classFixedSize(t, objectClass(t, array)) == BytesPerWord * 2); assert(t, classArrayElementSize(t, objectClass(t, array)) == BytesPerWord); return fieldAtOffset(array, BytesPerWord); } inline object& objectArrayBody(Thread* t UNUSED, object array, unsigned index) { assert(t, classFixedSize(t, objectClass(t, array)) == BytesPerWord * 2); assert(t, classArrayElementSize(t, objectClass(t, array)) == BytesPerWord); assert(t, classObjectMask(t, objectClass(t, array)) == classObjectMask(t, arrayBody (t, t->m->types, Machine::ArrayType))); return fieldAtOffset(array, ArrayBody + (index * BytesPerWord)); } unsigned parameterFootprint(Thread* t, const char* s, bool static_); void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)); inline bool acquireSystem(Thread* t, Thread* target) { ACQUIRE_RAW(t, t->m->stateLock); if (t->state != Thread::JoinedState) { atomicOr(&(target->flags), Thread::SystemFlag); return true; } else { return false; } } inline void releaseSystem(Thread* t, Thread* target) { ACQUIRE_RAW(t, t->m->stateLock); assert(t, t->state != Thread::JoinedState); atomicAnd(&(target->flags), ~Thread::SystemFlag); } inline bool atomicCompareAndSwapObject(Thread* t, object target, unsigned offset, object old, object new_) { if (atomicCompareAndSwap(&fieldAtOffset(target, offset), reinterpret_cast(old), reinterpret_cast(new_))) { mark(t, target, offset); return true; } else { return false; } } // The following two methods (monitorAtomicAppendAcquire and // monitorAtomicPollAcquire) use the Michael and Scott Non-Blocking // Queue Algorithm: http://www.cs.rochester.edu/u/michael/PODC96.html inline void monitorAtomicAppendAcquire(Thread* t, object monitor, object node) { if (node == 0) { PROTECT(t, monitor); node = makeMonitorNode(t, t, 0); } while (true) { object tail = monitorAcquireTail(t, monitor); loadMemoryBarrier(); object next = monitorNodeNext(t, tail); loadMemoryBarrier(); if (tail == monitorAcquireTail(t, monitor)) { if (next) { atomicCompareAndSwapObject (t, monitor, MonitorAcquireTail, tail, next); } else if (atomicCompareAndSwapObject (t, tail, MonitorNodeNext, 0, node)) { atomicCompareAndSwapObject (t, monitor, MonitorAcquireTail, tail, node); return; } } } } inline Thread* monitorAtomicPollAcquire(Thread* t, object monitor, bool remove) { while (true) { object head = monitorAcquireHead(t, monitor); loadMemoryBarrier(); object tail = monitorAcquireTail(t, monitor); loadMemoryBarrier(); object next = monitorNodeNext(t, head); loadMemoryBarrier(); if (head == monitorAcquireHead(t, monitor)) { if (head == tail) { if (next) { atomicCompareAndSwapObject (t, monitor, MonitorAcquireTail, tail, next); } else { return 0; } } else { Thread* value = static_cast(monitorNodeValue(t, next)); if ((not remove) or atomicCompareAndSwapObject (t, monitor, MonitorAcquireHead, head, next)) { return value; } } } } } inline bool monitorTryAcquire(Thread* t, object monitor) { if (monitorOwner(t, monitor) == t or (monitorAtomicPollAcquire(t, monitor, false) == 0 and atomicCompareAndSwap (reinterpret_cast(&monitorOwner(t, monitor)), 0, reinterpret_cast(t)))) { ++ monitorDepth(t, monitor); return true; } else { return false; } } inline void monitorAcquire(Thread* t, object monitor, object node = 0) { if (not monitorTryAcquire(t, monitor)) { PROTECT(t, monitor); PROTECT(t, node); ACQUIRE(t, t->lock); monitorAtomicAppendAcquire(t, monitor, node); // note that we don't try to acquire the lock until we're first in // line, both because it's fair and because we don't support // removing elements from arbitrary positions in the queue while (not (t == monitorAtomicPollAcquire(t, monitor, false) and atomicCompareAndSwap (reinterpret_cast(&monitorOwner(t, monitor)), 0, reinterpret_cast(t)))) { ENTER(t, Thread::IdleState); t->lock->wait(t->systemThread, 0); } expect(t, t == monitorAtomicPollAcquire(t, monitor, true)); ++ monitorDepth(t, monitor); } assert(t, monitorOwner(t, monitor) == t); } inline void monitorRelease(Thread* t, object monitor) { expect(t, monitorOwner(t, monitor) == t); if (-- monitorDepth(t, monitor) == 0) { monitorOwner(t, monitor) = 0; storeLoadMemoryBarrier(); Thread* next = monitorAtomicPollAcquire(t, monitor, false); if (next and acquireSystem(t, next)) { ACQUIRE(t, next->lock); next->lock->notify(t->systemThread); releaseSystem(t, next); } } } inline void monitorAppendWait(Thread* t, object monitor) { assert(t, monitorOwner(t, monitor) == t); expect(t, (t->flags & Thread::WaitingFlag) == 0); expect(t, t->waitNext == 0); atomicOr(&(t->flags), Thread::WaitingFlag); if (monitorWaitTail(t, monitor)) { static_cast(monitorWaitTail(t, monitor))->waitNext = t; } else { monitorWaitHead(t, monitor) = t; } monitorWaitTail(t, monitor) = t; } inline void monitorRemoveWait(Thread* t, object monitor) { assert(t, monitorOwner(t, monitor) == t); Thread* previous = 0; for (Thread* current = static_cast(monitorWaitHead(t, monitor)); current; current = current->waitNext) { if (t == current) { if (t == monitorWaitHead(t, monitor)) { monitorWaitHead(t, monitor) = t->waitNext; } else { previous->waitNext = t->waitNext; } if (t == monitorWaitTail(t, monitor)) { assert(t, t->waitNext == 0); monitorWaitTail(t, monitor) = previous; } t->waitNext = 0; atomicAnd(&(t->flags), ~Thread::WaitingFlag); return; } else { previous = current; } } abort(t); } inline bool monitorFindWait(Thread* t, object monitor) { assert(t, monitorOwner(t, monitor) == t); for (Thread* current = static_cast(monitorWaitHead(t, monitor)); current; current = current->waitNext) { if (t == current) { return true; } } return false; } inline bool monitorWait(Thread* t, object monitor, int64_t time) { expect(t, monitorOwner(t, monitor) == t); bool interrupted; unsigned depth; PROTECT(t, monitor); // pre-allocate monitor node so we don't get an OutOfMemoryError // when we try to re-acquire the monitor below object monitorNode = makeMonitorNode(t, t, 0); PROTECT(t, monitorNode); { ACQUIRE(t, t->lock); monitorAppendWait(t, monitor); depth = monitorDepth(t, monitor); monitorDepth(t, monitor) = 1; monitorRelease(t, monitor); ENTER(t, Thread::IdleState); interrupted = t->lock->waitAndClearInterrupted(t->systemThread, time); } monitorAcquire(t, monitor, monitorNode); monitorDepth(t, monitor) = depth; if (t->flags & Thread::WaitingFlag) { monitorRemoveWait(t, monitor); } else { expect(t, not monitorFindWait(t, monitor)); } assert(t, monitorOwner(t, monitor) == t); return interrupted; } inline Thread* monitorPollWait(Thread* t, object monitor) { assert(t, monitorOwner(t, monitor) == t); Thread* next = static_cast(monitorWaitHead(t, monitor)); if (next) { monitorWaitHead(t, monitor) = next->waitNext; atomicAnd(&(next->flags), ~Thread::WaitingFlag); next->waitNext = 0; if (next == monitorWaitTail(t, monitor)) { monitorWaitTail(t, monitor) = 0; } } else { assert(t, monitorWaitTail(t, monitor) == 0); } return next; } inline bool monitorNotify(Thread* t, object monitor) { expect(t, monitorOwner(t, monitor) == t); Thread* next = monitorPollWait(t, monitor); if (next) { ACQUIRE(t, next->lock); next->lock->notify(t->systemThread); return true; } else { return false; } } inline void monitorNotifyAll(Thread* t, object monitor) { PROTECT(t, monitor); while (monitorNotify(t, monitor)) { } } class ObjectMonitorResource { public: ObjectMonitorResource(Thread* t, object o): o(o), protector(t, &(this->o)) { monitorAcquire(protector.t, o); } ~ObjectMonitorResource() { monitorRelease(protector.t, o); } private: object o; Thread::SingleProtector protector; }; object objectMonitor(Thread* t, object o, bool createNew); inline void acquire(Thread* t, object o) { unsigned hash; if (DebugMonitors) { hash = objectHash(t, o); } object m = objectMonitor(t, o, true); if (DebugMonitors) { fprintf(stderr, "thread %p acquires %p for %x\n", t, m, hash); } monitorAcquire(t, m); } inline void release(Thread* t, object o) { unsigned hash; if (DebugMonitors) { hash = objectHash(t, o); } object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p releases %p for %x\n", t, m, hash); } monitorRelease(t, m); } inline void wait(Thread* t, object o, int64_t milliseconds) { unsigned hash; if (DebugMonitors) { hash = objectHash(t, o); } object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p waits %d millis on %p for %x\n", t, static_cast(milliseconds), m, hash); } if (m and monitorOwner(t, m) == t) { PROTECT(t, m); bool interrupted = monitorWait(t, m, milliseconds); if (interrupted) { if (t->m->alive or (t->flags & Thread::DaemonFlag) == 0) { t->m->classpath->clearInterrupted(t); throwNew(t, Machine::InterruptedExceptionType); } else { throw_(t, root(t, Machine::Shutdown)); } } } else { throwNew(t, Machine::IllegalMonitorStateExceptionType); } if (DebugMonitors) { fprintf(stderr, "thread %p wakes up on %p for %x\n", t, m, hash); } stress(t); } inline void notify(Thread* t, object o) { unsigned hash; if (DebugMonitors) { hash = objectHash(t, o); } object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p notifies on %p for %x\n", t, m, hash); } if (m and monitorOwner(t, m) == t) { monitorNotify(t, m); } else { throwNew(t, Machine::IllegalMonitorStateExceptionType); } } inline void notifyAll(Thread* t, object o) { object m = objectMonitor(t, o, false); if (DebugMonitors) { fprintf(stderr, "thread %p notifies all on %p for %x\n", t, m, objectHash(t, o)); } if (m and monitorOwner(t, m) == t) { monitorNotifyAll(t, m); } else { throwNew(t, Machine::IllegalMonitorStateExceptionType); } } inline void interrupt(Thread* t, Thread* target) { if (acquireSystem(t, target)) { target->systemThread->interrupt(); releaseSystem(t, target); } } inline bool getAndClearInterrupted(Thread* t, Thread* target) { if (acquireSystem(t, target)) { bool result = target->systemThread->getAndClearInterrupted(); releaseSystem(t, target); return result; } else { return false; } } inline bool exceptionMatch(Thread* t, object type, object exception) { return type == 0 or (exception != root(t, Machine::Shutdown) and instanceOf(t, type, t->exception)); } object intern(Thread* t, object s); void walk(Thread* t, Heap::Walker* w, object o, unsigned start); int walkNext(Thread* t, object o, int previous); void visitRoots(Machine* m, Heap::Visitor* v); inline jobject makeLocalReference(Thread* t, object o) { return t->m->processor->makeLocalReference(t, o); } inline void disposeLocalReference(Thread* t, jobject r) { t->m->processor->disposeLocalReference(t, r); } inline bool methodVirtual(Thread* t, object method) { return (methodFlags(t, method) & (ACC_STATIC | ACC_PRIVATE)) == 0 and byteArrayBody(t, methodName(t, method), 0) != '<'; } inline unsigned singletonMaskSize(unsigned count, unsigned bitsPerWord) { if (count) { return ceilingDivide(count + 2, bitsPerWord); } return 0; } inline unsigned singletonMaskSize(unsigned count) { return singletonMaskSize(count, BitsPerWord); } inline unsigned singletonMaskSize(Thread* t, object singleton) { unsigned length = singletonLength(t, singleton); if (length) { return ceilingDivide(length + 2, BitsPerWord + 1); } return 0; } inline unsigned singletonCount(Thread* t, object singleton) { return singletonLength(t, singleton) - singletonMaskSize(t, singleton); } inline uint32_t* singletonMask(Thread* t, object singleton) { assert(t, singletonLength(t, singleton)); return reinterpret_cast (&singletonBody(t, singleton, singletonCount(t, singleton))); } inline void singletonMarkObject(uint32_t* mask, unsigned index) { mask[(index + 2) / 32] |= (static_cast(1) << ((index + 2) % 32)); } inline void singletonMarkObject(Thread* t, object singleton, unsigned index) { singletonMarkObject(singletonMask(t, singleton), index); } inline bool singletonIsObject(Thread* t, object singleton, unsigned index) { assert(t, index < singletonCount(t, singleton)); return (singletonMask(t, singleton)[(index + 2) / 32] & (static_cast(1) << ((index + 2) % 32))) != 0; } inline object& singletonObject(Thread* t, object singleton, unsigned index) { assert(t, singletonIsObject(t, singleton, index)); return reinterpret_cast(singletonBody(t, singleton, index)); } inline uintptr_t& singletonValue(Thread* t, object singleton, unsigned index) { assert(t, not singletonIsObject(t, singleton, index)); return singletonBody(t, singleton, index); } inline object makeSingletonOfSize(Thread* t, unsigned count) { object o = makeSingleton(t, count + singletonMaskSize(count)); assert(t, singletonLength(t, o) == count + singletonMaskSize(t, o)); if (count) { singletonMask(t, o)[0] = 1; } return o; } inline void singletonSetBit(Thread* t, object singleton, unsigned start, unsigned index) { singletonValue(t, singleton, start + (index / BitsPerWord)) |= static_cast(1) << (index % BitsPerWord); } inline bool singletonBit(Thread* t, object singleton, unsigned start, unsigned index) { return (singletonValue(t, singleton, start + (index / BitsPerWord)) & (static_cast(1) << (index % BitsPerWord))) != 0; } inline unsigned poolMaskSize(unsigned count, unsigned bitsPerWord) { return ceilingDivide(count, bitsPerWord); } inline unsigned poolMaskSize(unsigned count) { return poolMaskSize(count, BitsPerWord); } inline unsigned poolMaskSize(Thread* t, object pool) { return ceilingDivide(singletonCount(t, pool), BitsPerWord + 1); } inline unsigned poolSize(Thread* t, object pool) { return singletonCount(t, pool) - poolMaskSize(t, pool); } inline object resolveClassInObject(Thread* t, object loader, object container, unsigned classOffset, bool throw_ = true) { object o = fieldAtOffset(container, classOffset); loadMemoryBarrier(); if (objectClass(t, o) == type(t, Machine::ByteArrayType)) { PROTECT(t, container); o = resolveClass(t, loader, o, throw_); if (o) { storeStoreMemoryBarrier(); set(t, container, classOffset, o); } } return o; } inline object resolveClassInPool(Thread* t, object loader, object method, unsigned index, bool throw_ = true) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); loadMemoryBarrier(); if (objectClass(t, o) == type(t, Machine::ReferenceType)) { PROTECT(t, method); o = resolveClass(t, loader, referenceName(t, o), throw_); if (o) { storeStoreMemoryBarrier(); set(t, codePool(t, methodCode(t, method)), SingletonBody + (index * BytesPerWord), o); } } return o; } inline object resolveClassInPool(Thread* t, object method, unsigned index, bool throw_ = true) { return resolveClassInPool(t, classLoader(t, methodClass(t, method)), method, index, throw_); } inline object resolve(Thread* t, object loader, object method, unsigned index, object (*find)(vm::Thread*, object, object, object), Machine::Type errorType, bool throw_ = true) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); loadMemoryBarrier(); if (objectClass(t, o) == type(t, Machine::ReferenceType)) { PROTECT(t, method); object reference = o; PROTECT(t, reference); object class_ = resolveClassInObject(t, loader, o, ReferenceClass, throw_); if (class_) { o = findInHierarchy (t, class_, referenceName(t, reference), referenceSpec(t, reference), find, errorType, throw_); if (o) { storeStoreMemoryBarrier(); set(t, codePool(t, methodCode(t, method)), SingletonBody + (index * BytesPerWord), o); } } else { o = 0; } } return o; } inline object resolveField(Thread* t, object loader, object method, unsigned index, bool throw_ = true) { return resolve(t, loader, method, index, findFieldInClass, Machine::NoSuchFieldErrorType, throw_); } inline object resolveField(Thread* t, object method, unsigned index, bool throw_ = true) { return resolveField (t, classLoader(t, methodClass(t, method)), method, index, throw_); } inline void acquireFieldForRead(Thread* t, object field) { if (UNLIKELY((fieldFlags(t, field) & ACC_VOLATILE) and BytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField))) { acquire(t, field); } } inline void releaseFieldForRead(Thread* t, object field) { if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { if (BytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { release(t, field); } else { loadMemoryBarrier(); } } } class FieldReadResource { public: FieldReadResource(Thread* t, object o): o(o), protector(t, &(this->o)) { acquireFieldForRead(protector.t, o); } ~FieldReadResource() { releaseFieldForRead(protector.t, o); } private: object o; Thread::SingleProtector protector; }; inline void acquireFieldForWrite(Thread* t, object field) { if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { if (BytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { acquire(t, field); } else { storeStoreMemoryBarrier(); } } } inline void releaseFieldForWrite(Thread* t, object field) { if (UNLIKELY(fieldFlags(t, field) & ACC_VOLATILE)) { if (BytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { release(t, field); } else { storeLoadMemoryBarrier(); } } } class FieldWriteResource { public: FieldWriteResource(Thread* t, object o): o(o), protector(t, &(this->o)) { acquireFieldForWrite(protector.t, o); } ~FieldWriteResource() { releaseFieldForWrite(protector.t, o); } private: object o; Thread::SingleProtector protector; }; inline object resolveMethod(Thread* t, object loader, object method, unsigned index, bool throw_ = true) { return resolve(t, loader, method, index, findMethodInClass, Machine::NoSuchMethodErrorType, throw_); } inline object resolveMethod(Thread* t, object method, unsigned index, bool throw_ = true) { return resolveMethod (t, classLoader(t, methodClass(t, method)), method, index, throw_); } object vectorAppend(Thread*, object, object); inline object getClassRuntimeDataIfExists(Thread* t, object c) { if (classRuntimeDataIndex(t, c)) { return vectorBody(t, root(t, Machine::ClassRuntimeDataTable), classRuntimeDataIndex(t, c) - 1); } else { return 0; } } inline object getClassRuntimeData(Thread* t, object c) { if (classRuntimeDataIndex(t, c) == 0) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); if (classRuntimeDataIndex(t, c) == 0) { object runtimeData = makeClassRuntimeData(t, 0, 0, 0, 0); setRoot(t, Machine::ClassRuntimeDataTable, vectorAppend (t, root(t, Machine::ClassRuntimeDataTable), runtimeData)); classRuntimeDataIndex(t, c) = vectorSize (t, root(t, Machine::ClassRuntimeDataTable)); } } return vectorBody(t, root(t, Machine::ClassRuntimeDataTable), classRuntimeDataIndex(t, c) - 1); } inline object getMethodRuntimeData(Thread* t, object method) { int index = methodRuntimeDataIndex(t, method); loadMemoryBarrier(); if (index == 0) { PROTECT(t, method); ACQUIRE(t, t->m->classLock); if (methodRuntimeDataIndex(t, method) == 0) { object runtimeData = makeMethodRuntimeData(t, 0); setRoot(t, Machine::MethodRuntimeDataTable, vectorAppend (t, root(t, Machine::MethodRuntimeDataTable), runtimeData)); storeStoreMemoryBarrier(); methodRuntimeDataIndex(t, method) = vectorSize (t, root(t, Machine::MethodRuntimeDataTable)); } } return vectorBody(t, root(t, Machine::MethodRuntimeDataTable), methodRuntimeDataIndex(t, method) - 1); } inline object getJClass(Thread* t, object c) { PROTECT(t, c); object jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); loadMemoryBarrier(); if (jclass == 0) { ACQUIRE(t, t->m->classLock); jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); if (jclass == 0) { jclass = t->m->classpath->makeJclass(t, c); storeStoreMemoryBarrier(); set(t, getClassRuntimeData(t, c), ClassRuntimeDataJclass, jclass); } } return jclass; } inline object primitiveClass(Thread* t, char name) { switch (name) { case 'B': return type(t, Machine::JbyteType); case 'C': return type(t, Machine::JcharType); case 'D': return type(t, Machine::JdoubleType); case 'F': return type(t, Machine::JfloatType); case 'I': return type(t, Machine::JintType); case 'J': return type(t, Machine::JlongType); case 'S': return type(t, Machine::JshortType); case 'V': return type(t, Machine::JvoidType); case 'Z': return type(t, Machine::JbooleanType); default: throwNew(t, Machine::IllegalArgumentExceptionType); } } inline void registerNative(Thread* t, object method, void* function) { PROTECT(t, method); expect(t, methodFlags(t, method) & ACC_NATIVE); object native = makeNative(t, function, false); PROTECT(t, native); object runtimeData = getMethodRuntimeData(t, method); // ensure other threads only see the methodRuntimeDataNative field // populated once the object it points to has been populated: storeStoreMemoryBarrier(); set(t, runtimeData, MethodRuntimeDataNative, native); } inline void unregisterNatives(Thread* t, object c) { if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); if (methodFlags(t, method) & ACC_NATIVE) { set(t, getMethodRuntimeData(t, method), MethodRuntimeDataNative, 0); } } } } void populateMultiArray(Thread* t, object array, int32_t* counts, unsigned index, unsigned dimensions); object getCaller(Thread* t, unsigned target, bool skipMethodInvoke = false); object defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length); inline object methodClone(Thread* t, object method) { return makeMethod (t, methodVmFlags(t, method), methodReturnCode(t, method), methodParameterCount(t, method), methodParameterFootprint(t, method), methodFlags(t, method), methodOffset(t, method), methodNativeID(t, method), methodRuntimeDataIndex(t, method), methodName(t, method), methodSpec(t, method), methodAddendum(t, method), methodClass(t, method), methodCode(t, method)); } inline uint64_t exceptionHandler(uint64_t start, uint64_t end, uint64_t ip, uint64_t catchType) { return (start << 48) | (end << 32) | (ip << 16) | catchType; } inline unsigned exceptionHandlerStart(uint64_t eh) { return eh >> 48; } inline unsigned exceptionHandlerEnd(uint64_t eh) { return (eh >> 32) & 0xFFFF; } inline unsigned exceptionHandlerIp(uint64_t eh) { return (eh >> 16) & 0xFFFF; } inline unsigned exceptionHandlerCatchType(uint64_t eh) { return eh & 0xFFFF; } inline uint64_t lineNumber(uint64_t ip, uint64_t line) { return (ip << 32) | line; } inline unsigned lineNumberIp(uint64_t ln) { return ln >> 32; } inline unsigned lineNumberLine(uint64_t ln) { return ln & 0xFFFFFFFF; } object interruptLock(Thread* t, object thread); void clearInterrupted(Thread* t); void threadInterrupt(Thread* t, object thread); bool threadIsInterrupted(Thread* t, object thread, bool clear); inline FILE* errorLog(Thread* t) { if (t->m->errorLog == 0) { const char* path = findProperty(t, "avian.error.log"); if (path) { t->m->errorLog = vm::fopen(path, "wb"); } else { t->m->errorLog = stderr; } } return t->m->errorLog; } } // namespace vm AVIAN_EXPORT void* vmAddressFromLine(vm::Thread* t, vm::object m, unsigned line); #endif//MACHINE_H ReadyTalk-avian-1e1fff5/src/avian/powerpc.h000066400000000000000000000147401231440243200207030ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef POWERPC_H #define POWERPC_H #include "avian/types.h" #include "avian/common.h" #ifdef __APPLE__ # include "mach/mach_types.h" # include "mach/ppc/thread_act.h" # include "mach/ppc/thread_status.h" # define THREAD_STATE PPC_THREAD_STATE # define THREAD_STATE_TYPE ppc_thread_state_t # define THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT # if __DARWIN_UNIX03 && defined(_STRUCT_PPC_EXCEPTION_STATE) # define FIELD(x) __##x # else # define FIELD(x) x # endif # define THREAD_STATE_IP(state) ((state).FIELD(srr0)) # define THREAD_STATE_STACK(state) ((state).FIELD(r1)) # define THREAD_STATE_THREAD(state) ((state).FIELD(r13)) # define THREAD_STATE_LINK(state) ((state).FIELD(lr)) # define IP_REGISTER(context) \ THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) # define STACK_REGISTER(context) \ THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) # define THREAD_REGISTER(context) \ THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) # define LINK_REGISTER(context) \ THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) #define VA_LIST(x) (&(x)) #else // not __APPLE__ # define IP_REGISTER(context) (context->uc_mcontext.regs->gpr[32]) # define STACK_REGISTER(context) (context->uc_mcontext.regs->gpr[1]) # define THREAD_REGISTER(context) (context->uc_mcontext.regs->gpr[13]) # define LINK_REGISTER(context) (context->uc_mcontext.regs->gpr[36]) #define VA_LIST(x) (x) #endif // not __APPLE__ extern "C" uint64_t vmNativeCall(void* function, unsigned stackTotal, void* memoryTable, unsigned memoryCount, unsigned memoryBase, void* gprTable, void* fprTable, unsigned returnType); namespace vm { inline void trap() { asm("trap"); } inline void memoryBarrier() { __asm__ __volatile__("sync": : :"memory"); } inline void storeStoreMemoryBarrier() { memoryBarrier(); } inline void storeLoadMemoryBarrier() { memoryBarrier(); } inline void loadMemoryBarrier() { memoryBarrier(); } inline void syncInstructionCache(const void* start, unsigned size) { const unsigned CacheLineSize = 32; const uintptr_t Mask = ~(CacheLineSize - 1); uintptr_t cacheLineStart = reinterpret_cast(start) & Mask; uintptr_t cacheLineEnd = (reinterpret_cast(start) + size + CacheLineSize - 1) & Mask; for (uintptr_t p = cacheLineStart; p < cacheLineEnd; p += CacheLineSize) { __asm__ __volatile__("dcbf 0, %0" : : "r" (p)); } __asm__ __volatile__("sync"); for (uintptr_t p = cacheLineStart; p < cacheLineEnd; p += CacheLineSize) { __asm__ __volatile__("icbi 0, %0" : : "r" (p)); } __asm__ __volatile__("isync"); } #ifdef USE_ATOMIC_OPERATIONS inline bool atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_) { #if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) return __sync_bool_compare_and_swap(p, old, new_); #else // not GCC >= 4.1 bool result; __asm__ __volatile__(" sync\n" "1:\n" " lwarx %0,0,%2\n" " cmpw %0,%3\n" " bne- 2f\n" " stwcx. %4,0,%2\n" " bne- 1b\n" " isync \n" "2:\n" " xor %0,%0,%3\n" " cntlzw %0,%0\n" " srwi %0,%0,5\n" : "=&r"(result), "+m"(*p) : "r"(p), "r"(old), "r"(new_) : "cc", "memory"); return result; #endif // not GCC >= 4.1 } inline bool atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_) { return atomicCompareAndSwap32(reinterpret_cast(p), old, new_); } #endif // USE_ATOMIC_OPERATIONS inline uint64_t dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, unsigned argumentCount, unsigned argumentsSize, unsigned returnType) { #ifdef __APPLE__ # define SKIP(var, count) var += count; # define ALIGN(var) const unsigned LinkageArea = 24; const unsigned FprCount = 13; #else # define SKIP(var, count) # define ALIGN(var) if (var & 1) ++var; const unsigned LinkageArea = 8; const unsigned FprCount = 8; #endif const unsigned GprCount = 8; uintptr_t gprTable[GprCount]; unsigned gprIndex = 0; uint64_t fprTable[FprCount]; unsigned fprIndex = 0; uintptr_t stack[argumentsSize / BytesPerWord]; unsigned stackSkip = 0; unsigned stackIndex = 0; unsigned ai = 0; for (unsigned ati = 0; ati < argumentCount; ++ ati) { switch (argumentTypes[ati]) { case FLOAT_TYPE: { if (fprIndex < FprCount) { double d = bitsToFloat(arguments[ai]); memcpy(fprTable + fprIndex, &d, 8); ++ fprIndex; SKIP(gprIndex, 1); SKIP(stackSkip, 1); } else { stack[stackIndex++] = arguments[ai]; } ++ ai; } break; case DOUBLE_TYPE: { if (fprIndex + 1 <= FprCount) { memcpy(fprTable + fprIndex, arguments + ai, 8); ++ fprIndex; SKIP(gprIndex, 8 / BytesPerWord); SKIP(stackSkip, 8 / BytesPerWord); } else { ALIGN(stackIndex); memcpy(stack + stackIndex, arguments + ai, 8); stackIndex += 8 / BytesPerWord; } ai += 8 / BytesPerWord; } break; case INT64_TYPE: { if (gprIndex + (8 / BytesPerWord) <= GprCount) { ALIGN(gprIndex); memcpy(gprTable + gprIndex, arguments + ai, 8); gprIndex += 8 / BytesPerWord; SKIP(stackSkip, 8 / BytesPerWord); } else { ALIGN(stackIndex); memcpy(stack + stackIndex, arguments + ai, 8); stackIndex += 8 / BytesPerWord; } ai += 8 / BytesPerWord; } break; default: { if (gprIndex < GprCount) { gprTable[gprIndex++] = arguments[ai]; SKIP(stackSkip, 1); } else { stack[stackIndex++] = arguments[ai]; } ++ ai; } break; } } return vmNativeCall (function, (((1 + stackSkip + stackIndex) * BytesPerWord) + LinkageArea + 15) & -16, stack, stackIndex * BytesPerWord, LinkageArea + (stackSkip * BytesPerWord), (gprIndex ? gprTable : 0), (fprIndex ? fprTable : 0), returnType); } } // namespace vm #endif//POWERPC_H ReadyTalk-avian-1e1fff5/src/avian/process.h000066400000000000000000000031441231440243200206760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef PROCESS_H #define PROCESS_H #include "avian/common.h" #include #include "avian/machine.h" #include "avian/constants.h" namespace vm { inline int16_t codeReadInt16(Thread* t, object code, unsigned& ip) { uint8_t v1 = codeBody(t, code, ip++); uint8_t v2 = codeBody(t, code, ip++); return ((v1 << 8) | v2); } inline int32_t codeReadInt32(Thread* t, object code, unsigned& ip) { uint8_t v1 = codeBody(t, code, ip++); uint8_t v2 = codeBody(t, code, ip++); uint8_t v3 = codeBody(t, code, ip++); uint8_t v4 = codeBody(t, code, ip++); return ((v1 << 24) | (v2 << 16) | (v3 << 8) | v4); } inline bool isSuperclass(Thread* t, object class_, object base) { for (object oc = classSuper(t, base); oc; oc = classSuper(t, oc)) { if (oc == class_) { return true; } } return false; } inline bool isSpecialMethod(Thread* t, object method, object class_) { return (classFlags(t, class_) & ACC_SUPER) and strcmp(reinterpret_cast(""), &byteArrayBody(t, methodName(t, method), 0)) != 0 and isSuperclass(t, methodClass(t, method), class_); } void resolveNative(Thread* t, object method); int findLineNumber(Thread* t, object method, unsigned ip); } // namespace vm #endif//PROCESS_H ReadyTalk-avian-1e1fff5/src/avian/processor.h000066400000000000000000000123011231440243200212320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef PROCESSOR_H #define PROCESSOR_H #include "avian/common.h" #include #include #include #include "bootimage.h" #include "avian/heapwalk.h" #include "avian/zone.h" namespace avian { namespace codegen { class DelayedPromise; } namespace util { template class Slice; } } namespace vm { class Processor { public: class StackWalker; class StackVisitor { public: virtual bool visit(StackWalker* walker) = 0; }; class StackWalker { public: virtual void walk(StackVisitor* v) = 0; virtual object method() = 0; virtual int ip() = 0; virtual unsigned count() = 0; }; class CompilationHandler { public: virtual void compiled(const void* code, unsigned size, unsigned frameSize, const char* name) = 0; virtual void dispose() = 0; }; virtual Thread* makeThread(Machine* m, object javaThread, Thread* parent) = 0; virtual object makeMethod(Thread* t, uint8_t vmFlags, uint8_t returnCode, uint8_t parameterCount, uint8_t parameterFootprint, uint16_t flags, uint16_t offset, object name, object spec, object addendum, object class_, object code) = 0; virtual object makeClass(Thread* t, uint16_t flags, uint16_t vmFlags, uint16_t fixedSize, uint8_t arrayElementSize, uint8_t arrayDimensions, object objectMask, object name, object sourceFile, object super, object interfaceTable, object virtualTable, object fieldTable, object methodTable, object addendum, object staticTable, object loader, unsigned vtableLength) = 0; virtual void initVtable(Thread* t, object c) = 0; virtual void visitObjects(Thread* t, Heap::Visitor* v) = 0; virtual void walkStack(Thread* t, StackVisitor* v) = 0; virtual int lineNumber(Thread* t, object method, int ip) = 0; virtual object* makeLocalReference(Thread* t, object o) = 0; virtual void disposeLocalReference(Thread* t, object* r) = 0; virtual bool pushLocalFrame(Thread* t, unsigned capacity) = 0; virtual void popLocalFrame(Thread* t) = 0; virtual object invokeArray(Thread* t, object method, object this_, object arguments) = 0; virtual object invokeArray(Thread* t, object method, object this_, const jvalue* arguments) = 0; virtual object invokeList(Thread* t, object method, object this_, bool indirectObjects, va_list arguments) = 0; virtual object invokeList(Thread* t, object loader, const char* className, const char* methodName, const char* methodSpec, object this_, va_list arguments) = 0; virtual void dispose(Thread* t) = 0; virtual void dispose() = 0; virtual object getStackTrace(Thread* t, Thread* target) = 0; virtual void initialize(BootImage* image, avian::util::Slice code) = 0; virtual void addCompilationHandler(CompilationHandler* handler) = 0; virtual void compileMethod(Thread* t, Zone* zone, object* constants, object* calls, avian::codegen::DelayedPromise** addresses, object method, OffsetResolver* resolver) = 0; virtual void visitRoots(Thread* t, HeapWalker* w) = 0; virtual void normalizeVirtualThunks(Thread* t) = 0; virtual unsigned* makeCallTable(Thread* t, HeapWalker* w) = 0; virtual void boot(Thread* t, BootImage* image, uint8_t* code) = 0; virtual void callWithCurrentContinuation(Thread* t, object receiver) = 0; virtual void dynamicWind(Thread* t, object before, object thunk, object after) = 0; virtual void feedResultToContinuation(Thread* t, object continuation, object result) = 0; virtual void feedExceptionToContinuation(Thread* t, object continuation, object exception) = 0; virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) = 0; object invoke(Thread* t, object method, object this_, ...) { va_list a; va_start(a, this_); object r = invokeList(t, method, this_, false, a); va_end(a); return r; } object invoke(Thread* t, object loader, const char* className, const char* methodName, const char* methodSpec, object this_, ...) { va_list a; va_start(a, this_); object r = invokeList (t, loader, className, methodName, methodSpec, this_, a); va_end(a); return r; } }; Processor* makeProcessor(System* system, avian::util::Allocator* allocator, const char* crashDumpDirectory, bool useNativeFeatures); } // namespace vm #endif//PROCESSOR_H ReadyTalk-avian-1e1fff5/src/avian/target-fields.h000066400000000000000000000034471231440243200217600ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_TARGET_FIELDS_H #define AVIAN_TARGET_FIELDS_H #ifdef TARGET_BYTES_PER_WORD # if (TARGET_BYTES_PER_WORD == 8) #define TARGET_THREAD_EXCEPTION 80 #define TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT 2256 #define TARGET_THREAD_EXCEPTIONOFFSET 2264 #define TARGET_THREAD_EXCEPTIONHANDLER 2272 #define TARGET_THREAD_IP 2216 #define TARGET_THREAD_STACK 2224 #define TARGET_THREAD_NEWSTACK 2232 #define TARGET_THREAD_SCRATCH 2240 #define TARGET_THREAD_CONTINUATION 2248 #define TARGET_THREAD_TAILADDRESS 2280 #define TARGET_THREAD_VIRTUALCALLTARGET 2288 #define TARGET_THREAD_VIRTUALCALLINDEX 2296 #define TARGET_THREAD_HEAPIMAGE 2304 #define TARGET_THREAD_CODEIMAGE 2312 #define TARGET_THREAD_THUNKTABLE 2320 #define TARGET_THREAD_STACKLIMIT 2368 # elif (TARGET_BYTES_PER_WORD == 4) #define TARGET_THREAD_EXCEPTION 44 #define TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT 2164 #define TARGET_THREAD_EXCEPTIONOFFSET 2168 #define TARGET_THREAD_EXCEPTIONHANDLER 2172 #define TARGET_THREAD_IP 2144 #define TARGET_THREAD_STACK 2148 #define TARGET_THREAD_NEWSTACK 2152 #define TARGET_THREAD_SCRATCH 2156 #define TARGET_THREAD_CONTINUATION 2160 #define TARGET_THREAD_TAILADDRESS 2176 #define TARGET_THREAD_VIRTUALCALLTARGET 2180 #define TARGET_THREAD_VIRTUALCALLINDEX 2184 #define TARGET_THREAD_HEAPIMAGE 2188 #define TARGET_THREAD_CODEIMAGE 2192 #define TARGET_THREAD_THUNKTABLE 2196 #define TARGET_THREAD_STACKLIMIT 2220 # else # error # endif #else # error #endif #endif ReadyTalk-avian-1e1fff5/src/avian/target.h000066400000000000000000000062101231440243200205030ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef TARGET_H #define TARGET_H #include "avian/target-fields.h" #include "avian/common.h" namespace vm { template inline T targetV1(T v) { return v; } template inline T swapV2(T v) { return (((v >> 8) & 0xFF) | ((v << 8))); } template inline T swapV4(T v) { return (((v >> 24) & 0x000000FF) | ((v >> 8) & 0x0000FF00) | ((v << 8) & 0x00FF0000) | ((v << 24))); } template inline T swapV8(T v) { return (((static_cast(v) >> 56) & UINT64_C(0x00000000000000FF)) | ((static_cast(v) >> 40) & UINT64_C(0x000000000000FF00)) | ((static_cast(v) >> 24) & UINT64_C(0x0000000000FF0000)) | ((static_cast(v) >> 8) & UINT64_C(0x00000000FF000000)) | ((static_cast(v) << 8) & UINT64_C(0x000000FF00000000)) | ((static_cast(v) << 24) & UINT64_C(0x0000FF0000000000)) | ((static_cast(v) << 40) & UINT64_C(0x00FF000000000000)) | ((static_cast(v) << 56))); } #ifdef TARGET_OPPOSITE_ENDIAN template inline T targetV2(T v) { return swapV2(v); } template inline T targetV4(T v) { return swapV4(v); } template inline T targetV8(T v) { return swapV8(v); } #else template inline T targetV2(T v) { return v; } template inline T targetV4(T v) { return v; } template inline T targetV8(T v) { return v; } #endif #ifdef TARGET_BYTES_PER_WORD # if (TARGET_BYTES_PER_WORD == 8) template inline T targetVW(T v) { return targetV8(v); } typedef uint64_t target_uintptr_t; typedef int64_t target_intptr_t; const unsigned TargetClassFixedSize = 12; const unsigned TargetClassArrayElementSize = 14; const unsigned TargetClassVtable = 128; const unsigned TargetFieldOffset = 12; # elif (TARGET_BYTES_PER_WORD == 4) template inline T targetVW(T v) { return targetV4(v); } typedef uint32_t target_uintptr_t; typedef int32_t target_intptr_t; const unsigned TargetClassFixedSize = 8; const unsigned TargetClassArrayElementSize = 10; const unsigned TargetClassVtable = 68; const unsigned TargetFieldOffset = 8; # else # error # endif #else # error #endif const unsigned TargetBytesPerWord = TARGET_BYTES_PER_WORD; const unsigned TargetBitsPerWord = TargetBytesPerWord * 8; const target_uintptr_t TargetPointerMask = ((~static_cast(0)) / TargetBytesPerWord) * TargetBytesPerWord; const unsigned TargetArrayLength = TargetBytesPerWord; const unsigned TargetArrayBody = TargetBytesPerWord * 2; inline void targetMarkBit(target_uintptr_t* map, unsigned i) { map[wordOf(i)] |= targetVW(static_cast(1) << bitOf(i)); } } // namespace vm #endif//TARGET_H ReadyTalk-avian-1e1fff5/src/avian/types.h000066400000000000000000000010721231440243200203620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef TYPES_H #define TYPES_H #define VOID_TYPE 0 #define INT8_TYPE 1 #define INT16_TYPE 2 #define INT32_TYPE 3 #define INT64_TYPE 4 #define FLOAT_TYPE 5 #define DOUBLE_TYPE 6 #define POINTER_TYPE 7 #endif//TYPES_H ReadyTalk-avian-1e1fff5/src/avian/util.h000066400000000000000000000071401231440243200201750ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef UTIL_H #define UTIL_H #include "avian/machine.h" #include "avian/zone.h" namespace vm { object hashMapFindNode(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)); inline object hashMapFind(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { object n = hashMapFindNode(t, map, key, hash, equal); return (n ? tripleSecond(t, n) : 0); } void hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object), unsigned size); void hashMapInsert(Thread* t, object map, object key, object value, uint32_t (*hash)(Thread*, object)); inline bool hashMapInsertOrReplace(Thread* t, object map, object key, object value, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { object n = hashMapFindNode(t, map, key, hash, equal); if (n == 0) { hashMapInsert(t, map, key, value, hash); return true; } else { set(t, n, TripleSecond, value); return false; } } inline bool hashMapInsertMaybe(Thread* t, object map, object key, object value, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { object n = hashMapFindNode(t, map, key, hash, equal); if (n == 0) { hashMapInsert(t, map, key, value, hash); return true; } else { return false; } } object hashMapRemove(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)); object hashMapIterator(Thread* t, object map); object hashMapIteratorNext(Thread* t, object it); void listAppend(Thread* t, object list, object value); object vectorAppend(Thread* t, object vector, object value); object growArray(Thread* t, object array); object treeQuery(Thread* t, object tree, intptr_t key, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)); object treeInsert(Thread* t, Zone* zone, object tree, intptr_t key, object value, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)); void treeUpdate(Thread* t, object tree, intptr_t key, object value, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)); class HashMapIterator: public Thread::Protector { public: HashMapIterator(Thread* t, object map): Protector(t), map(map), node(0), index(0) { find(); } void find() { object array = hashMapArray(t, map); if (array) { for (unsigned i = index; i < arrayLength(t, array); ++i) { if (arrayBody(t, array, i)) { node = arrayBody(t, array, i); index = i + 1; return; } } } node = 0; } bool hasMore() { return node != 0; } object next() { if (node) { object n = node; if (tripleThird(t, node)) { node = tripleThird(t, node); } else { find(); } return n; } else { return 0; } } virtual void visit(Heap::Visitor* v) { v->visit(&map); v->visit(&node); } object map; object node; unsigned index; }; } // vm #endif//UTIL_H ReadyTalk-avian-1e1fff5/src/avian/x86.h000066400000000000000000000222721231440243200176500ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef X86_H #define X86_H #include "avian/types.h" #include "avian/common.h" #ifdef _MSC_VER # include "windows.h" # pragma push_macro("assert") # include "intrin.h" # pragma pop_macro("assert") # undef interface #endif #if (defined ARCH_x86_32) || (defined PLATFORM_WINDOWS) # define VA_LIST(x) (&(x)) #else # define VA_LIST(x) (x) #endif #ifdef __APPLE__ # include "mach/mach_types.h" # include "mach/thread_act.h" # include "mach/thread_status.h" # if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) # define FIELD(x) __##x # else # define FIELD(x) x # endif #endif #ifdef ARCH_x86_32 # ifdef __APPLE__ # define THREAD_STATE x86_THREAD_STATE32 # define THREAD_STATE_TYPE x86_thread_state32_t # define THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT # define THREAD_STATE_IP(state) ((state).FIELD(eip)) # define THREAD_STATE_STACK(state) ((state).FIELD(esp)) # define THREAD_STATE_THREAD(state) ((state).FIELD(ebx)) # define THREAD_STATE_LINK(state) ((state).FIELD(ecx)) # define THREAD_STATE_FRAME(state) ((state).FIELD(ebp)) # define IP_REGISTER(context) \ THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) # define STACK_REGISTER(context) \ THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) # define THREAD_REGISTER(context) \ THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) # define LINK_REGISTER(context) \ THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) # define FRAME_REGISTER(context) \ THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss)) # elif (defined __QNX__) # define IP_REGISTER(context) (context->uc_mcontext.cpu.eip) # define STACK_REGISTER(context) (context->uc_mcontext.cpu.esp) # define THREAD_REGISTER(context) (context->uc_mcontext.cpu.ebx) # define LINK_REGISTER(context) (context->uc_mcontext.cpu.ecx) # define FRAME_REGISTER(context) (context->uc_mcontext.cpu.ebp) # elif (defined __FreeBSD__) # define IP_REGISTER(context) (context->uc_mcontext.mc_eip) # define STACK_REGISTER(context) (context->uc_mcontext.mc_esp) # define THREAD_REGISTER(context) (context->uc_mcontext.mc_ebx) # define LINK_REGISTER(context) (context->uc_mcontext.mc_ecx) # define FRAME_REGISTER(context) (context->uc_mcontext.mc_ebp) # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP]) # define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_EBX]) # define LINK_REGISTER(context) (context->uc_mcontext.gregs[REG_ECX]) # define FRAME_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP]) # endif extern "C" uint64_t vmNativeCall(void* function, void* stack, unsigned stackSize, unsigned returnType); namespace vm { inline uint64_t dynamicCall(void* function, uintptr_t* arguments, uint8_t*, unsigned, unsigned argumentsSize, unsigned returnType) { return vmNativeCall(function, arguments, argumentsSize, returnType); } } // namespace vm #elif defined ARCH_x86_64 # ifdef __APPLE__ # define THREAD_STATE x86_THREAD_STATE64 # define THREAD_STATE_TYPE x86_thread_state64_t # define THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT # define THREAD_STATE_IP(state) ((state).FIELD(rip)) # define THREAD_STATE_STACK(state) ((state).FIELD(rsp)) # define THREAD_STATE_THREAD(state) ((state).FIELD(rbx)) # define THREAD_STATE_LINK(state) ((state).FIELD(rcx)) # define THREAD_STATE_FRAME(state) ((state).FIELD(rbp)) # define IP_REGISTER(context) \ THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) # define STACK_REGISTER(context) \ THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) # define THREAD_REGISTER(context) \ THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) # define LINK_REGISTER(context) \ THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) # define FRAME_REGISTER(context) \ THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss)) # elif (defined __FreeBSD__) # define IP_REGISTER(context) (context->uc_mcontext.mc_rip) # define STACK_REGISTER(context) (context->uc_mcontext.mc_rsp) # define THREAD_REGISTER(context) (context->uc_mcontext.mc_rbx) # define LINK_REGISTER(context) (context->uc_mcontext.mc_rcx) # define FRAME_REGISTER(context) (context->uc_mcontext.mc_rbp) # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP]) # define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX]) # define LINK_REGISTER(context) (context->uc_mcontext.gregs[REG_RCX]) # define FRAME_REGISTER(context) (context->uc_mcontext.gregs[REG_RBP]) # endif extern "C" uint64_t # ifdef PLATFORM_WINDOWS vmNativeCall(void* function, void* stack, unsigned stackSize, unsigned returnType); # else vmNativeCall(void* function, void* stack, unsigned stackSize, void* gprTable, void* sseTable, unsigned returnType); # endif namespace vm { # ifdef PLATFORM_WINDOWS inline uint64_t dynamicCall(void* function, uint64_t* arguments, UNUSED uint8_t* argumentTypes, unsigned argumentCount, unsigned, unsigned returnType) { return vmNativeCall(function, arguments, argumentCount, returnType); } # else inline uint64_t dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, unsigned argumentCount, unsigned, unsigned returnType) { const unsigned GprCount = 6; uint64_t gprTable[GprCount]; unsigned gprIndex = 0; const unsigned SseCount = 8; uint64_t sseTable[SseCount]; unsigned sseIndex = 0; uint64_t stack[argumentCount]; unsigned stackIndex = 0; for (unsigned i = 0; i < argumentCount; ++i) { switch (argumentTypes[i]) { case FLOAT_TYPE: case DOUBLE_TYPE: { if (sseIndex < SseCount) { sseTable[sseIndex++] = arguments[i]; } else { stack[stackIndex++] = arguments[i]; } } break; default: { if (gprIndex < GprCount) { gprTable[gprIndex++] = arguments[i]; } else { stack[stackIndex++] = arguments[i]; } } break; } } return vmNativeCall(function, stack, stackIndex * BytesPerWord, (gprIndex ? gprTable : 0), (sseIndex ? sseTable : 0), returnType); } #endif } // namespace vm #else # error unsupported architecture #endif namespace vm { inline void trap() { #ifdef _MSC_VER __asm int 3 #else asm("int3"); #endif } inline void programOrderMemoryBarrier() { compileTimeMemoryBarrier(); } inline void storeStoreMemoryBarrier() { programOrderMemoryBarrier(); } inline void storeLoadMemoryBarrier() { #ifdef _MSC_VER MemoryBarrier(); #elif defined ARCH_x86_32 __asm__ __volatile__("lock; addl $0,0(%%esp)": : :"memory"); #elif defined ARCH_x86_64 __asm__ __volatile__("mfence": : :"memory"); #endif // ARCH_x86_64 } inline void loadMemoryBarrier() { programOrderMemoryBarrier(); } inline void syncInstructionCache(const void*, unsigned) { programOrderMemoryBarrier(); } #ifdef USE_ATOMIC_OPERATIONS inline bool atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_) { #ifdef _MSC_VER return old == InterlockedCompareExchange (reinterpret_cast(p), new_, old); #elif (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) return __sync_bool_compare_and_swap(p, old, new_); #else uint8_t result; __asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1" : "=m"(*p), "=q"(result) : "r"(new_), "a"(old), "m"(*p) : "memory"); return result != 0; #endif } #define AVIAN_HAS_CAS64 inline bool atomicCompareAndSwap64(uint64_t* p, uint64_t old, uint64_t new_) { #ifdef _MSC_VER return old == InterlockedCompareExchange64 (reinterpret_cast(p), new_, old); #elif (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) return __sync_bool_compare_and_swap(p, old, new_); #elif defined ARCH_x86_32 uint8_t result; __asm__ __volatile__("lock; cmpxchg8b %0; setz %1" : "=m"(*p), "=q"(result) : "a"(static_cast(old)), "d"(static_cast(old >> 32)), "b"(static_cast(new_)), "c"(static_cast(new_ >> 32)), "m"(*p) : "memory"); return result != 0; #else uint8_t result; __asm__ __volatile__("lock; cmpxchgq %2, %0; setz %1" : "=m"(*p), "=q"(result) : "r"(new_), "a"(old), "m"(*p) : "memory"); return result != 0; #endif } inline bool atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_) { #ifdef ARCH_x86_32 return atomicCompareAndSwap32(reinterpret_cast(p), old, new_); #elif defined ARCH_x86_64 return atomicCompareAndSwap64(reinterpret_cast(p), old, new_); #endif // ARCH_x86_64 } #endif // USE_ATOMIC_OPERATIONS } // namespace vm #endif//X86_H ReadyTalk-avian-1e1fff5/src/avian/zlib-custom.h000066400000000000000000000014221231440243200214650ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "zlib.h" #ifdef inflateInit2 #undef inflateInit2 #define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, static_cast(sizeof(z_stream))) #endif #ifdef deflateInit2 #undef deflateInit2 #define deflateInit2(strm, level, windowBits) \ deflateInit2_((strm), (level), Z_DEFLATED, (windowBits), 8, Z_DEFAULT_STRATEGY, ZLIB_VERSION, static_cast(sizeof(z_stream))) #endif ReadyTalk-avian-1e1fff5/src/avian/zone.h000066400000000000000000000066251231440243200202020ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef ZONE_H #define ZONE_H #include #include #include namespace vm { class Zone : public avian::util::Allocator { public: class Segment { public: Segment(Segment* next, unsigned size): next(next), size(size), position(0) { } Segment* next; uintptr_t size; uintptr_t position; uint8_t data[0]; }; Zone(System* s, Allocator* allocator, unsigned minimumFootprint): s(s), allocator(allocator), segment(0), minimumFootprint(minimumFootprint < sizeof(Segment) ? 0 : minimumFootprint - sizeof(Segment)) { } ~Zone() { dispose(); } void dispose() { for (Segment* seg = segment, *next; seg; seg = next) { next = seg->next; allocator->free(seg, sizeof(Segment) + seg->size); } segment = 0; } static unsigned padToPage(unsigned size) { return (size + (LikelyPageSizeInBytes - 1)) & ~(LikelyPageSizeInBytes - 1); } bool tryEnsure(unsigned space) { if (segment == 0 or segment->position + space > segment->size) { unsigned size = padToPage (avian::util::max (space, avian::util::max (minimumFootprint, segment == 0 ? 0 : segment->size * 2)) + sizeof(Segment)); void* p = allocator->tryAllocate(size); if (p == 0) { size = padToPage(space + sizeof(Segment)); p = allocator->tryAllocate(size); if (p == 0) { return false; } } segment = new (p) Segment(segment, size - sizeof(Segment)); } return true; } void ensure(unsigned space) { if (segment == 0 or segment->position + space > segment->size) { unsigned size = padToPage(space + sizeof(Segment)); segment = new (allocator->allocate(size)) Segment(segment, size - sizeof(Segment)); } } virtual void* tryAllocate(unsigned size) { size = pad(size); if (tryEnsure(size)) { void* r = segment->data + segment->position; segment->position += size; return r; } else { return 0; } } virtual void* allocate(unsigned size) { size = pad(size); void* p = tryAllocate(size); if (p) { return p; } else { ensure(size); void* r = segment->data + segment->position; segment->position += size; return r; } } void* peek(unsigned size) { size = pad(size); Segment* s = segment; while (s->position < size) { size -= s->position; s = s->next; } return s->data + (s->position - size); } void pop(unsigned size) { size = pad(size); Segment* s = segment; while (s->position < size) { size -= s->position; Segment* next = s->next; allocator->free(s, sizeof(Segment) + s->size); s = next; } s->position -= size; segment = s; } virtual void free(const void*, unsigned) { // not supported abort(s); } System* s; Allocator* allocator; void* context; Segment* segment; unsigned minimumFootprint; }; } // namespace vm #endif//ZONE_H ReadyTalk-avian-1e1fff5/src/boot-javahome.cpp000066400000000000000000000017771231440243200212220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifdef _MSC_VER typedef unsigned char uint8_t; #else # include "stdint.h" #endif #ifdef BOOT_JAVAHOME #if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) # define EXPORT __declspec(dllexport) # define SYMBOL(x) binary_javahome_jar_##x #else # define EXPORT __attribute__ ((visibility("default"))) \ __attribute__ ((used)) # define SYMBOL(x) _binary_javahome_jar_##x #endif extern "C" { extern const uint8_t SYMBOL(start)[]; extern const uint8_t SYMBOL(end)[]; EXPORT const uint8_t* javahomeJar(unsigned* size) { *size = SYMBOL(end) - SYMBOL(start); return SYMBOL(start); } } #undef SYMBOL #endif//BOOT_JAVAHOME ReadyTalk-avian-1e1fff5/src/boot.cpp000066400000000000000000000042121231440243200174150ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "stdlib.h" #ifdef _MSC_VER typedef unsigned char uint8_t; #else // not _MSC_VER # include "stdint.h" // since we aren't linking against libstdc++, we must implement this // ourselves: extern "C" void __cxa_pure_virtual(void) { abort(); } #endif // not _MSC_VER #if (defined __MINGW32__) || (defined _MSC_VER) # define EXPORT __declspec(dllexport) #else # define EXPORT __attribute__ ((visibility("default"))) \ __attribute__ ((used)) #endif #ifdef BOOT_IMAGE #if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) # define BOOTIMAGE_SYMBOL(x) binary_bootimage_bin_##x # define CODEIMAGE_SYMBOL(x) binary_codeimage_bin_##x #else # define BOOTIMAGE_SYMBOL(x) _binary_bootimage_bin_##x # define CODEIMAGE_SYMBOL(x) _binary_codeimage_bin_##x #endif extern "C" { extern const uint8_t BOOTIMAGE_SYMBOL(start)[]; extern const uint8_t BOOTIMAGE_SYMBOL(end)[]; EXPORT const uint8_t* bootimageBin(unsigned* size) { *size = BOOTIMAGE_SYMBOL(end) - BOOTIMAGE_SYMBOL(start); return BOOTIMAGE_SYMBOL(start); } extern const uint8_t CODEIMAGE_SYMBOL(start)[]; extern const uint8_t CODEIMAGE_SYMBOL(end)[]; EXPORT const uint8_t* codeimageBin(unsigned* size) { *size = CODEIMAGE_SYMBOL(end) - CODEIMAGE_SYMBOL(start); return CODEIMAGE_SYMBOL(start); } } #undef SYMBOL #endif//BOOT_IMAGE #ifdef BOOT_CLASSPATH #if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) # define SYMBOL(x) binary_classpath_jar_##x #else # define SYMBOL(x) _binary_classpath_jar_##x #endif extern "C" { extern const uint8_t SYMBOL(start)[]; extern const uint8_t SYMBOL(end)[]; EXPORT const uint8_t* classpathJar(unsigned* size) { *size = SYMBOL(end) - SYMBOL(start); return SYMBOL(start); } } #undef SYMBOL #endif//BOOT_CLASSPATH ReadyTalk-avian-1e1fff5/src/bootimage-fields.cpp000066400000000000000000000013041231440243200216630ustar00rootroot00000000000000#ifndef FIELD # define FIELD(name) # define FIELD_DEFINED #endif FIELD(magic) FIELD(initialized) FIELD(heapSize) FIELD(codeSize) FIELD(bootClassCount) FIELD(appClassCount) FIELD(stringCount) FIELD(callCount) FIELD(bootLoader) FIELD(appLoader) FIELD(types) FIELD(methodTree) FIELD(methodTreeSentinal) FIELD(virtualThunks) #ifdef FIELD_DEFINED # undef FIELD # undef FIELD_DEFINED #endif #ifndef THUNK_FIELD # define THUNK_FIELD(name) # define THUNK_FIELD_DEFINED #endif THUNK_FIELD(default_); THUNK_FIELD(defaultVirtual); THUNK_FIELD(native); THUNK_FIELD(aioob); THUNK_FIELD(stackOverflow); THUNK_FIELD(table); #ifdef THUNK_FIELD_DEFINED # undef THUNK_FIELD # undef THUNK_FIELD_DEFINED #endif ReadyTalk-avian-1e1fff5/src/bootimage-template.cpp000066400000000000000000000014221231440243200222310ustar00rootroot00000000000000const unsigned NAME(BootMask) = (~static_cast(0)) / NAME(BytesPerWord); const unsigned NAME(BootShift) = 32 - avian::util::log(NAME(BytesPerWord)); const unsigned NAME(BootFlatConstant) = 1 << NAME(BootShift); const unsigned NAME(BootHeapOffset) = 1 << (NAME(BootShift) + 1); inline unsigned LABEL(codeMapSize)(unsigned codeSize) { return avian::util::ceilingDivide(codeSize, TargetBitsPerWord) * TargetBytesPerWord; } inline unsigned LABEL(heapMapSize)(unsigned heapSize) { return avian::util::ceilingDivide(heapSize, TargetBitsPerWord * TargetBytesPerWord) * TargetBytesPerWord; } inline object LABEL(bootObject)(LABEL(uintptr_t)* heap, unsigned offset) { if (offset) { return reinterpret_cast(heap + offset - 1); } else { return 0; } } ReadyTalk-avian-1e1fff5/src/builtin.cpp000066400000000000000000000647051231440243200201350ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/machine.h" #include "avian/constants.h" #include "avian/processor.h" #include "avian/util.h" #include using namespace vm; namespace { int64_t search(Thread* t, object loader, object name, object (*op)(Thread*, object, object), bool replaceDots) { if (LIKELY(name)) { PROTECT(t, loader); PROTECT(t, name); object n = makeByteArray(t, stringLength(t, name) + 1); char* s = reinterpret_cast(&byteArrayBody(t, n, 0)); stringChars(t, name, s); if (replaceDots) { replace('.', '/', s); } return reinterpret_cast(op(t, loader, n)); } else { throwNew(t, Machine::NullPointerExceptionType); } } object resolveSystemClassThrow(Thread* t, object loader, object spec) { return resolveSystemClass (t, loader, spec, true, Machine::ClassNotFoundExceptionType); } object fieldForOffsetInClass(Thread* t, object c, unsigned offset) { object super = classSuper(t, c); if (super) { object field = fieldForOffsetInClass(t, super, offset); if (field) { return field; } } object table = classFieldTable(t, c); if (table) { for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { object field = objectArrayBody(t, table, i); if ((fieldFlags(t, field) & ACC_STATIC) == 0 and fieldOffset(t, field) == offset) { return field; } } } return 0; } object fieldForOffset(Thread* t, object o, unsigned offset) { object c = objectClass(t, o); if (classVmFlags(t, c) & SingletonFlag) { c = singletonObject(t, o, 0); object table = classFieldTable(t, c); if (table) { for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { object field = objectArrayBody(t, table, i); if ((fieldFlags(t, field) & ACC_STATIC) and fieldOffset(t, field) == offset) { return field; } } } abort(t); } else { object field = fieldForOffsetInClass(t, c, offset); if (field) { return field; } else { abort(t); } } } } // namespace extern "C" AVIAN_EXPORT void JNICALL Avian_avian_Classes_initialize (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); initClass(t, this_); } extern "C" AVIAN_EXPORT void JNICALL Avian_avian_Classes_acquireClassLock (Thread* t, object, uintptr_t*) { acquire(t, t->m->classLock); } extern "C" AVIAN_EXPORT void JNICALL Avian_avian_Classes_releaseClassLock (Thread* t, object, uintptr_t*) { release(t, t->m->classLock); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Classes_resolveVMClass (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); object spec = reinterpret_cast(arguments[1]); return reinterpret_cast (resolveClass(t, loader, spec, true, Machine::ClassNotFoundExceptionType)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Classes_defineVMClass (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); object b = reinterpret_cast(arguments[1]); int offset = arguments[2]; int length = arguments[3]; uint8_t* buffer = static_cast (t->m->heap->allocate(length)); THREAD_RESOURCE2(t, uint8_t*, buffer, int, length, t->m->heap->free(buffer, length)); memcpy(buffer, &byteArrayBody(t, b, offset), length); return reinterpret_cast(defineClass(t, loader, buffer, length)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_SystemClassLoader_findLoadedVMClass (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); object name = reinterpret_cast(arguments[1]); return search(t, loader, name, findLoadedClass, true); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_SystemClassLoader_vmClass (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (jclassVmClass(t, reinterpret_cast(arguments[0]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_SystemClassLoader_findVMClass (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); object name = reinterpret_cast(arguments[1]); return search(t, loader, name, resolveSystemClassThrow, true); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_SystemClassLoader_resourceURLPrefix (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); object name = reinterpret_cast(arguments[1]); if (LIKELY(name)) { THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); const char* name = static_cast (systemClassLoaderFinder(t, loader))->urlPrefix(RUNTIME_ARRAY_BODY(n)); return name ? reinterpret_cast(makeString(t, "%s", name)) : 0; } else { throwNew(t, Machine::NullPointerExceptionType); } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_SystemClassLoader_00024ResourceEnumeration_nextResourceURLPrefix (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[1]); object name = reinterpret_cast(arguments[2]); object finderElementPtrPtr = reinterpret_cast(arguments[3]); if (LIKELY(name) && LIKELY(finderElementPtrPtr)) { THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); void *&finderElementPtr = reinterpret_cast(longArrayBody(t, finderElementPtrPtr, 0)); const char* name = static_cast (systemClassLoaderFinder(t, loader))->nextUrlPrefix(RUNTIME_ARRAY_BODY(n), finderElementPtr); return name ? reinterpret_cast(makeString(t, "%s", name)) : 0; } else { throwNew(t, Machine::NullPointerExceptionType); } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_SystemClassLoader_getClass (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (getJClass(t, reinterpret_cast(arguments[0]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_SystemClassLoader_getPackageSource (Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[0]); PROTECT(t, name); ACQUIRE(t, t->m->classLock); THREAD_RUNTIME_ARRAY(t, char, chars, stringLength(t, name) + 2); stringChars(t, name, RUNTIME_ARRAY_BODY(chars)); replace('.', '/', RUNTIME_ARRAY_BODY(chars)); RUNTIME_ARRAY_BODY(chars)[stringLength(t, name)] = '/'; RUNTIME_ARRAY_BODY(chars)[stringLength(t, name) + 1] = 0; object key = makeByteArray(t, RUNTIME_ARRAY_BODY(chars)); object array = hashMapFind (t, root(t, Machine::PackageMap), key, byteArrayHash, byteArrayEqual); if (array) { return reinterpret_cast (makeLocalReference (t, t->m->classpath->makeString (t, array, 0, byteArrayLength(t, array)))); } else { return 0; } } #ifdef AVIAN_HEAPDUMP extern "C" AVIAN_EXPORT void JNICALL Avian_avian_Machine_dumpHeap (Thread* t, object, uintptr_t* arguments) { object outputFile = reinterpret_cast(*arguments); unsigned length = stringLength(t, outputFile); THREAD_RUNTIME_ARRAY(t, char, n, length + 1); stringChars(t, outputFile, RUNTIME_ARRAY_BODY(n)); FILE* out = vm::fopen(RUNTIME_ARRAY_BODY(n), "wb"); if (out) { { ENTER(t, Thread::ExclusiveState); dumpHeap(t, out); } fclose(out); } else { throwNew(t, Machine::RuntimeExceptionType, "file not found: %s", RUNTIME_ARRAY_BODY(n)); } } #endif//AVIAN_HEAPDUMP extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Runtime_exit (Thread* t, object, uintptr_t* arguments) { shutDown(t); t->m->system->exit(arguments[1]); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_avianvmresource_Handler_00024ResourceInputStream_getContentLength (Thread* t, object, uintptr_t* arguments) { object path = reinterpret_cast(*arguments); if (LIKELY(path)) { THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p)); if (r == 0) { r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); } if (r) { jint rSize = r->length(); r->dispose(); return rSize; } } return -1; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_avianvmresource_Handler_00024ResourceInputStream_open (Thread* t, object, uintptr_t* arguments) { object path = reinterpret_cast(*arguments); if (LIKELY(path)) { THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p)); if (r == 0) { r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); } return reinterpret_cast(r); } else { throwNew(t, Machine::NullPointerExceptionType); } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_avianvmresource_Handler_00024ResourceInputStream_available (Thread*, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); int32_t position = arguments[2]; System::Region* region = reinterpret_cast(peer); return static_cast(region->length()) - position; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_avianvmresource_Handler_00024ResourceInputStream_read__JI (Thread*, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); int32_t position = arguments[2]; System::Region* region = reinterpret_cast(peer); if (position >= static_cast(region->length())) { return -1; } else { return region->start()[position]; } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_avianvmresource_Handler_00024ResourceInputStream_read__JI_3BII (Thread* t, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); int32_t position = arguments[2]; object buffer = reinterpret_cast(arguments[3]); int32_t offset = arguments[4]; int32_t length = arguments[5]; if (length == 0) return 0; System::Region* region = reinterpret_cast(peer); if (length > static_cast(region->length()) - position) { length = static_cast(region->length()) - position; } if (length <= 0) { return -1; } else { memcpy(&byteArrayBody(t, buffer, offset), region->start() + position, length); return length; } } extern "C" AVIAN_EXPORT void JNICALL Avian_avian_avianvmresource_Handler_00024ResourceInputStream_close (Thread*, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); reinterpret_cast(peer)->dispose(); } extern "C" AVIAN_EXPORT void JNICALL Avian_avian_Continuations_callWithCurrentContinuation (Thread* t, object, uintptr_t* arguments) { t->m->processor->callWithCurrentContinuation (t, reinterpret_cast(*arguments)); abort(t); } extern "C" AVIAN_EXPORT void JNICALL Avian_avian_Continuations_dynamicWind2 (Thread* t, object, uintptr_t* arguments) { t->m->processor->dynamicWind (t, reinterpret_cast(arguments[0]), reinterpret_cast(arguments[1]), reinterpret_cast(arguments[2])); abort(t); } extern "C" AVIAN_EXPORT void JNICALL Avian_avian_Continuations_00024Continuation_handleResult (Thread* t, object, uintptr_t* arguments) { t->m->processor->feedResultToContinuation (t, reinterpret_cast(arguments[0]), reinterpret_cast(arguments[1])); abort(t); } extern "C" AVIAN_EXPORT void JNICALL Avian_avian_Continuations_00024Continuation_handleException (Thread* t, object, uintptr_t* arguments) { t->m->processor->feedExceptionToContinuation (t, reinterpret_cast(arguments[0]), reinterpret_cast(arguments[1])); abort(t); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Singleton_getObject (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (singletonObject(t, reinterpret_cast(arguments[0]), arguments[1])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Singleton_getInt (Thread* t, object, uintptr_t* arguments) { return singletonValue (t, reinterpret_cast(arguments[0]), arguments[1]); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Singleton_getLong (Thread* t, object, uintptr_t* arguments) { int64_t v; memcpy(&v, &singletonValue (t, reinterpret_cast(arguments[0]), arguments[1]), 8); return v; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_allocateMemory (Thread* t, object, uintptr_t* arguments) { int64_t size; memcpy(&size, arguments + 1, 8); void* p = malloc(size); if (p) { return reinterpret_cast(p); } else { throwNew(t, Machine::OutOfMemoryErrorType); } } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_freeMemory (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); if (p) { free(reinterpret_cast(p)); } } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_setMemory (Thread* t, object, uintptr_t* arguments) { object base = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int64_t count; memcpy(&count, arguments + 4, 8); int8_t value = arguments[6]; PROTECT(t, base); ACQUIRE(t, t->m->referenceLock); if (base) { memset(&fieldAtOffset(base, offset), value, count); } else { memset(reinterpret_cast(offset), value, count); } } // NB: The following primitive get/put methods are only used by the // interpreter. The JIT/AOT compiler implements them as intrinsics, // so these versions will be ignored. extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putByte__JB (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); int8_t v = arguments[3]; *reinterpret_cast(p) = v; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putShort__JS (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); int16_t v = arguments[3]; *reinterpret_cast(p) = v; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putChar__JC (Thread* t, object method, uintptr_t* arguments) { Avian_sun_misc_Unsafe_putShort__JS(t, method, arguments); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putInt__JI (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); int32_t v = arguments[3]; *reinterpret_cast(p) = v; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putFloat__JF (Thread* t, object method, uintptr_t* arguments) { Avian_sun_misc_Unsafe_putInt__JI(t, method, arguments); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putLong__JJ (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); int64_t v; memcpy(&v, arguments + 3, 8); *reinterpret_cast(p) = v; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putDouble__JD (Thread* t, object method, uintptr_t* arguments) { Avian_sun_misc_Unsafe_putLong__JJ(t, method, arguments); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putAddress__JJ (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); int64_t v; memcpy(&v, arguments + 3, 8); *reinterpret_cast(p) = v; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getByte__J (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); return *reinterpret_cast(p); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getShort__J (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); return *reinterpret_cast(p); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getChar__J (Thread* t, object method, uintptr_t* arguments) { return Avian_sun_misc_Unsafe_getShort__J(t, method, arguments); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getInt__J (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); return *reinterpret_cast(p); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getFloat__J (Thread* t, object method, uintptr_t* arguments) { return Avian_sun_misc_Unsafe_getInt__J(t, method, arguments); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getLong__J (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); return *reinterpret_cast(p); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getDouble__J (Thread* t, object method, uintptr_t* arguments) { return Avian_sun_misc_Unsafe_getLong__J(t, method, arguments); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getAddress__J (Thread*, object, uintptr_t* arguments) { int64_t p; memcpy(&p, arguments + 1, 8); return *reinterpret_cast(p); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_copyMemory (Thread* t, object, uintptr_t* arguments) { object srcBase = reinterpret_cast(arguments[1]); int64_t srcOffset; memcpy(&srcOffset, arguments + 2, 8); object dstBase = reinterpret_cast(arguments[4]); int64_t dstOffset; memcpy(&dstOffset, arguments + 5, 8); int64_t count; memcpy(&count, arguments + 7, 8); PROTECT(t, srcBase); PROTECT(t, dstBase); ACQUIRE(t, t->m->referenceLock); void* src = srcBase ? &fieldAtOffset(srcBase, srcOffset) : reinterpret_cast(srcOffset); void* dst = dstBase ? &fieldAtOffset(dstBase, dstOffset) : reinterpret_cast(dstOffset); memcpy(dst, src, count); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_arrayBaseOffset (Thread*, object, uintptr_t*) { return ArrayBody; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_arrayIndexScale (Thread* t, object, uintptr_t* arguments) { object c = jclassVmClass(t, reinterpret_cast(arguments[1])); if (c == type(t, Machine::JbooleanType) || c == type(t, Machine::JbyteType)) return 1; else if (c == type(t, Machine::JshortType) || c == type(t, Machine::JcharType)) return 2; else if (c == type(t, Machine::JintType) || c == type(t, Machine::JfloatType)) return 4; else if (c == type(t, Machine::JlongType) || c == type(t, Machine::JdoubleType)) return 8; else return BytesPerWord; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_nio_FixedArrayByteBuffer_allocateFixed (Thread* t, object, uintptr_t* arguments) { int capacity = arguments[0]; object address = reinterpret_cast(arguments[1]); PROTECT(t, address); object array = allocate3 (t, t->m->heap, Machine::FixedAllocation, ArrayBody + capacity, false); setObjectClass(t, array, type(t, Machine::ByteArrayType)); byteArrayLength(t, array) = capacity; longArrayBody(t, address, 0) = reinterpret_cast(array) + ArrayBody; return reinterpret_cast(array); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getObject (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); return fieldAtOffset(o, offset); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putObject (Thread* t, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uintptr_t value = arguments[4]; set(t, o, offset, reinterpret_cast(value)); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putObjectVolatile (Thread* t, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); object value = reinterpret_cast(arguments[4]); storeStoreMemoryBarrier(); set(t, o, offset, reinterpret_cast(value)); storeLoadMemoryBarrier(); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putOrderedObject (Thread* t, object method, uintptr_t* arguments) { Avian_sun_misc_Unsafe_putObjectVolatile(t, method, arguments); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getObjectVolatile (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uintptr_t value = fieldAtOffset(o, offset); loadMemoryBarrier(); return value; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_compareAndSwapObject (Thread* t, object, uintptr_t* arguments) { object target = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uintptr_t expect = arguments[4]; uintptr_t update = arguments[5]; bool success = atomicCompareAndSwap (&fieldAtOffset(target, offset), expect, update); if (success) { mark(t, target, offset); } return success; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_compareAndSwapInt (Thread*, object, uintptr_t* arguments) { object target = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uint32_t expect = arguments[4]; uint32_t update = arguments[5]; return atomicCompareAndSwap32 (&fieldAtOffset(target, offset), expect, update); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_compareAndSwapLong (Thread* t UNUSED, object, uintptr_t* arguments) { object target = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uint64_t expect; memcpy(&expect, arguments + 4, 8); uint64_t update; memcpy(&update, arguments + 6, 8); #ifdef AVIAN_HAS_CAS64 return atomicCompareAndSwap64 (&fieldAtOffset(target, offset), expect, update); #else ACQUIRE_FIELD_FOR_WRITE(t, fieldForOffset(t, target, offset)); if (fieldAtOffset(target, offset) == expect) { fieldAtOffset(target, offset) = update; return true; } else { return false; } #endif } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getLongVolatile (Thread* t, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); object field; if (BytesPerWord < 8) { field = fieldForOffset(t, o, offset); PROTECT(t, field); acquire(t, field); } int64_t result = fieldAtOffset(o, offset); if (BytesPerWord < 8) { release(t, field); } else { loadMemoryBarrier(); } return result; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putLongVolatile (Thread* t, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int64_t value; memcpy(&value, arguments + 4, 8); object field; if (BytesPerWord < 8) { field = fieldForOffset(t, o, offset); PROTECT(t, field); acquire(t, field); } else { storeStoreMemoryBarrier(); } fieldAtOffset(o, offset) = value; if (BytesPerWord < 8) { release(t, field); } else { storeLoadMemoryBarrier(); } } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putOrderedLong (Thread* t, object method, uintptr_t* arguments) { // todo: we might be able to use weaker barriers here than // putLongVolatile does Avian_sun_misc_Unsafe_putLongVolatile(t, method, arguments); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_unpark (Thread* t, object, uintptr_t* arguments) { object thread = reinterpret_cast(arguments[1]); monitorAcquire(t, interruptLock(t, thread)); threadUnparked(t, thread) = true; monitorNotify(t, interruptLock(t, thread)); monitorRelease(t, interruptLock(t, thread)); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_park (Thread* t, object, uintptr_t* arguments) { bool absolute = arguments[1]; int64_t time; memcpy(&time, arguments + 2, 8); int64_t then = t->m->system->now(); if (absolute) { time -= then; if (time <= 0) { return; } } else if (time) { // if not absolute, interpret time as nanoseconds, but make sure // it doesn't become zero when we convert to milliseconds, since // zero is interpreted as infinity below time = (time / (1000 * 1000)) + 1; } monitorAcquire(t, interruptLock(t, t->javaThread)); bool interrupted = false; while (time >= 0 and (not (threadUnparked(t, t->javaThread) or threadInterrupted(t, t->javaThread) or (interrupted = monitorWait (t, interruptLock(t, t->javaThread), time))))) { int64_t now = t->m->system->now(); time -= now - then; then = now; if (time == 0) { break; } } if (interrupted) { threadInterrupted(t, t->javaThread) = true; } threadUnparked(t, t->javaThread) = false; monitorRelease(t, interruptLock(t, t->javaThread)); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putIntVolatile (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int32_t value = arguments[4]; storeStoreMemoryBarrier(); fieldAtOffset(o, offset) = value; storeLoadMemoryBarrier(); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putOrderedInt (Thread* t, object method, uintptr_t* arguments) { Avian_sun_misc_Unsafe_putIntVolatile(t, method, arguments); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getIntVolatile (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int32_t result = fieldAtOffset(o, offset); loadMemoryBarrier(); return result; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_throwException (Thread* t, object, uintptr_t* arguments) { vm::throw_(t, reinterpret_cast(arguments[1])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Classes_primitiveClass (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast(primitiveClass(t, arguments[0])); } ReadyTalk-avian-1e1fff5/src/classpath-android.cpp000066400000000000000000001753141231440243200220660ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ struct JavaVM; struct _JNIEnv; struct JniConstants { static void init(_JNIEnv* env); }; extern "C" int JNI_OnLoad(JavaVM*, void*); #define _POSIX_C_SOURCE 200112L #undef _GNU_SOURCE #include "avian/machine.h" #include "avian/classpath-common.h" #include "avian/process.h" #include "avian/util.h" #ifdef PLATFORM_WINDOWS const char* getErrnoDescription(int err); // This function is defined in mingw-extensions.cpp #endif using namespace vm; extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Classes_defineVMClass (Thread*, object, uintptr_t*); namespace { namespace local { void* getDirectBufferAddress(Thread* t, object b) { PROTECT(t, b); object field = resolveField (t, objectClass(t, b), "effectiveDirectAddress", "J"); return reinterpret_cast (fieldAtOffset(b, fieldOffset(t, field))); } void JNICALL loadLibrary(Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[1]); unsigned length = stringLength(t, name); THREAD_RUNTIME_ARRAY(t, char, n, length + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), true, true); } void JNICALL finalizeAllEnqueued(Thread*, object, uintptr_t*) { // ignore } int64_t JNICALL appLoader(Thread* t, object, uintptr_t*) { return reinterpret_cast(root(t, Machine::AppLoader)); } int64_t JNICALL defineClass(Thread* t, object method, uintptr_t* arguments) { uintptr_t args[] = { arguments[0], arguments[2], arguments[3], arguments[4] }; int64_t v = Avian_avian_Classes_defineVMClass(t, method, args); if (v) { return reinterpret_cast (getJClass(t, reinterpret_cast(v))); } else { return 0; } } int64_t JNICALL mapData(Thread*, object, uintptr_t*); void JNICALL closeMemoryMappedFile(Thread*, object, uintptr_t*); object makeMethodOrConstructor(Thread* t, object c, unsigned index) { PROTECT(t, c); object method = arrayBody (t, classMethodTable(t, jclassVmClass(t, c)), index); PROTECT(t, method); unsigned parameterCount; unsigned returnTypeSpec; object parameterTypes = resolveParameterJTypes (t, classLoader(t, methodClass(t, method)), methodSpec(t, method), ¶meterCount, &returnTypeSpec); PROTECT(t, parameterTypes); object returnType = resolveJType (t, classLoader(t, methodClass(t, method)), reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), returnTypeSpec)), byteArrayLength(t, methodSpec(t, method)) - 1 - returnTypeSpec); PROTECT(t, returnType); object exceptionTypes = resolveExceptionJTypes (t, classLoader(t, methodClass(t, method)), methodAddendum(t, method)); if (byteArrayBody(t, methodName(t, method), 0) == '<') { return makeJconstructor (t, 0, c, parameterTypes, exceptionTypes, 0, 0, 0, 0, index); } else { PROTECT(t, exceptionTypes); object name = t->m->classpath->makeString (t, methodName(t, method), 0, byteArrayLength(t, methodName(t, method)) - 1); return makeJmethod (t, 0, index, c, name, parameterTypes, exceptionTypes, returnType, 0, 0, 0, 0, 0); } } object makeField(Thread* t, object c, unsigned index) { PROTECT(t, c); object field = arrayBody (t, classFieldTable(t, jclassVmClass(t, c)), index); PROTECT(t, field); object type = getJClass (t, resolveClassBySpec (t, classLoader(t, fieldClass(t, field)), reinterpret_cast (&byteArrayBody(t, fieldSpec(t, field), 0)), byteArrayLength(t, fieldSpec(t, field)) - 1)); PROTECT(t, type); object name = t->m->classpath->makeString (t, fieldName(t, field), 0, byteArrayLength(t, fieldName(t, field)) - 1); return makeJfield(t, 0, c, type, 0, 0, name, index); } void initVmThread(Thread* t, object thread, unsigned offset) { PROTECT(t, thread); if (fieldAtOffset(thread, offset) == 0) { object c = resolveClass (t, root(t, Machine::BootLoader), "java/lang/VMThread"); PROTECT(t, c); object instance = makeNew(t, c); PROTECT(t, instance); object constructor = resolveMethod (t, c, "", "(Ljava/lang/Thread;)V"); t->m->processor->invoke(t, constructor, instance, thread); set(t, thread, offset, instance); } if (threadGroup(t, thread) == 0) { set(t, thread, ThreadGroup, threadGroup(t, t->javaThread)); expect(t, threadGroup(t, thread)); } } void initVmThread(Thread* t, object thread) { initVmThread( t, thread, fieldOffset( t, resolveField( t, objectClass(t, thread), "vmThread", "Ljava/lang/VMThread;"))); } object translateStackTrace(Thread* t, object raw) { PROTECT(t, raw); object array = makeObjectArray (t, resolveClass (t, root(t, Machine::BootLoader), "java/lang/StackTraceElement"), objectArrayLength(t, raw)); PROTECT(t, array); for (unsigned i = 0; i < objectArrayLength(t, array); ++i) { object e = makeStackTraceElement(t, objectArrayBody(t, raw, i)); set(t, array, ArrayBody + (i * BytesPerWord), e); } return array; } class MyClasspath : public Classpath { public: MyClasspath(Allocator* allocator): allocator(allocator), tzdata(0) { } virtual object makeJclass(Thread* t, object class_) { PROTECT(t, class_); object c = allocate(t, FixedSizeOfJclass, true); setObjectClass(t, c, type(t, Machine::JclassType)); set(t, c, JclassVmClass, class_); return c; } virtual object makeString(Thread* t, object array, int32_t offset, int32_t length) { if (objectClass(t, array) == type(t, Machine::ByteArrayType)) { PROTECT(t, array); object charArray = makeCharArray(t, length); for (int i = 0; i < length; ++i) { expect(t, (byteArrayBody(t, array, offset + i) & 0x80) == 0); charArrayBody(t, charArray, i) = byteArrayBody(t, array, offset + i); } array = charArray; } else { expect(t, objectClass(t, array) == type(t, Machine::CharArrayType)); } return vm::makeString(t, array, offset, length, 0); } virtual object makeThread(Thread* t, Thread* parent) { const unsigned NormalPriority = 5; object group = 0; PROTECT(t, group); if (parent) { group = threadGroup(t, parent->javaThread); } else { resolveSystemClass (t, root(t, Machine::BootLoader), className(t, type(t, Machine::ThreadGroupType)), false); group = makeNew(t, type(t, Machine::ThreadGroupType)); object constructor = resolveMethod (t, type(t, Machine::ThreadGroupType), "", "()V"); t->m->processor->invoke(t, constructor, group); } resolveSystemClass (t, root(t, Machine::BootLoader), className(t, type(t, Machine::ThreadType)), false); object thread = makeNew(t, type(t, Machine::ThreadType)); PROTECT(t, thread); object constructor = resolveMethod (t, type(t, Machine::ThreadType), "", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V"); t->m->processor->invoke (t, constructor, thread, group, 0, NormalPriority, false); set(t, thread, ThreadContextClassLoader, root(t, Machine::AppLoader)); initVmThread(t, thread); return thread; } virtual object makeJMethod(Thread* t, object vmMethod) { object table = classMethodTable(t, methodClass(t, vmMethod)); for (unsigned i = 0; i < arrayLength(t, table); ++i) { if (vmMethod == arrayBody(t, table, i)) { return makeMethodOrConstructor (t, getJClass(t, methodClass(t, vmMethod)), i); } } abort(t); } virtual object getVMMethod(Thread* t, object jmethod) { return objectClass(t, jmethod) == type(t, Machine::JmethodType) ? arrayBody (t, classMethodTable (t, jclassVmClass(t, jmethodDeclaringClass(t, jmethod))), jmethodSlot(t, jmethod)) : arrayBody (t, classMethodTable (t, jclassVmClass(t, jconstructorDeclaringClass(t, jmethod))), jconstructorSlot(t, jmethod)); } virtual object makeJField(Thread* t, object vmField) { object table = classFieldTable(t, fieldClass(t, vmField)); for (unsigned i = 0; i < arrayLength(t, table); ++i) { if (vmField == arrayBody(t, table, i)) { return makeField(t, getJClass(t, fieldClass(t, vmField)), i); } } abort(t); } virtual object getVMField(Thread* t, object jfield) { return arrayBody (t, classFieldTable (t, jclassVmClass(t, jfieldDeclaringClass(t, jfield))), jfieldSlot(t, jfield)); } virtual void clearInterrupted(Thread*) { // ignore } virtual void runThread(Thread* t) { // force monitor creation so we don't get an OutOfMemory error // later when we try to acquire it: objectMonitor(t, t->javaThread, true); object field = resolveField( t, objectClass(t, t->javaThread), "vmThread", "Ljava/lang/VMThread;"); unsigned offset = fieldOffset(t, field); THREAD_RESOURCE(t, unsigned, offset, { object vmt = fieldAtOffset(t->javaThread, offset); if (vmt) { PROTECT(t, vmt); vm::acquire(t, vmt); fieldAtOffset(t->javaThread, offset) = 0; vm::notifyAll(t, vmt); vm::release(t, vmt); } vm::acquire(t, t->javaThread); t->flags &= ~Thread::ActiveFlag; vm::notifyAll(t, t->javaThread); vm::release(t, t->javaThread); }); initVmThread(t, t->javaThread, offset); object method = resolveMethod (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", "()V"); t->m->processor->invoke(t, method, t->javaThread); } virtual void resolveNative(Thread* t, object method) { vm::resolveNative(t, method); } void interceptMethods(Thread* t, bool updateRuntimeData) { { object c = resolveClass (t, root(t, Machine::BootLoader), "java/lang/Runtime", false); if (c) { PROTECT(t, c); intercept(t, c, "loadLibrary", "(Ljava/lang/String;Ljava/lang/ClassLoader;)V", voidPointer(loadLibrary), updateRuntimeData); } } { object c = resolveClass (t, root(t, Machine::BootLoader), "java/lang/ref/FinalizerReference", false); if (c) { PROTECT(t, c); intercept(t, c, "finalizeAllEnqueued", "()V", voidPointer(finalizeAllEnqueued), updateRuntimeData); } } { object c = resolveClass (t, root(t, Machine::BootLoader), "java/lang/ClassLoader", false); if (c) { PROTECT(t, c); intercept(t, c, "createSystemClassLoader", "()Ljava/lang/ClassLoader;", voidPointer(appLoader), updateRuntimeData); intercept(t, c, "defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;", voidPointer(defineClass), updateRuntimeData); } } { object c = resolveClass (t, root(t, Machine::BootLoader), "libcore/util/ZoneInfoDB", false); if (c) { PROTECT(t, c); intercept(t, c, "mapData", "()Llibcore/io/MemoryMappedFile;", voidPointer(mapData), updateRuntimeData); } } { object c = resolveClass (t, root(t, Machine::BootLoader), "libcore/io/MemoryMappedFile", false); if (c) { PROTECT(t, c); intercept(t, c, "close", "()V", voidPointer(closeMemoryMappedFile), updateRuntimeData); } } } virtual void interceptMethods(Thread* t) { interceptMethods(t, false); } virtual void preBoot(Thread* t) { // Android's System.initSystemProperties throws an NPE if // LD_LIBRARY_PATH is not set as of this writing: #ifdef PLATFORM_WINDOWS _wputenv(L"LD_LIBRARY_PATH=(dummy)"); #elif (! defined AVIAN_IOS) setenv("LD_LIBRARY_PATH", "", false); #endif interceptMethods(t, true); JniConstants::init(reinterpret_cast<_JNIEnv*>(t)); JNI_OnLoad(reinterpret_cast< ::JavaVM*>(t->m), 0); } virtual void boot(Thread* t) { object c = resolveClass (t, root(t, Machine::BootLoader), "java/lang/ClassLoader"); PROTECT(t, c); object constructor = resolveMethod (t, c, "", "(Ljava/lang/ClassLoader;Z)V"); PROTECT(t, constructor); t->m->processor->invoke (t, constructor, root(t, Machine::BootLoader), 0, true); t->m->processor->invoke (t, constructor, root(t, Machine::AppLoader), root(t, Machine::BootLoader), false); } virtual const char* bootClasspath() { return AVIAN_CLASSPATH; } virtual object makeDirectByteBuffer(Thread* t, void* p, jlong capacity) { object c = resolveClass (t, root(t, Machine::BootLoader), "java/nio/DirectByteBuffer"); PROTECT(t, c); object instance = makeNew(t, c); PROTECT(t, instance); object constructor = resolveMethod(t, c, "", "(JI)V"); t->m->processor->invoke (t, constructor, instance, reinterpret_cast(p), static_cast(capacity)); return instance; } virtual void* getDirectBufferAddress(Thread* t, object b) { return local::getDirectBufferAddress(t, b); } virtual int64_t getDirectBufferCapacity(Thread* t, object b) { PROTECT(t, b); object field = resolveField (t, objectClass(t, b), "capacity", "I"); return fieldAtOffset(b, fieldOffset(t, field)); } virtual bool canTailCall(Thread*, object, object, object, object) { return true; } virtual void shutDown(Thread*) { // ignore } virtual void dispose() { if (tzdata) { tzdata->dispose(); } allocator->free(this, sizeof(*this)); } Allocator* allocator; System::Region* tzdata; }; int64_t JNICALL mapData(Thread* t, object, uintptr_t*) { object c = resolveClass (t, root(t, Machine::BootLoader), "libcore/io/MemoryMappedFile"); PROTECT(t, c); object instance = makeNew(t, c); PROTECT(t, instance); object constructor = resolveMethod(t, c, "", "(JJ)V"); const char* jar = "javahomeJar"; Finder* finder = getFinder(t, jar, strlen(jar)); if (finder) { System::Region* r = finder->find("tzdata"); if (r) { MyClasspath* cp = static_cast(t->m->classpath); expect(t, cp->tzdata == 0); cp->tzdata = r; t->m->processor->invoke (t, constructor, instance, reinterpret_cast(r->start()), static_cast(r->length())); return reinterpret_cast(instance); } } throwNew(t, Machine::RuntimeExceptionType); } void JNICALL closeMemoryMappedFile(Thread* t, object method, uintptr_t* arguments) { object file = reinterpret_cast(arguments[0]); PROTECT(t, file); MyClasspath* cp = static_cast(t->m->classpath); if (cp->tzdata) { object field = resolveField(t, objectClass(t, file), "address", "J"); if (fieldAtOffset(file, fieldOffset(t, field)) == reinterpret_cast(cp->tzdata->start())) { cp->tzdata->dispose(); cp->tzdata = 0; fieldAtOffset(file, fieldOffset(t, field)) = 0; return; } } t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), file); } bool matchType(Thread* t, object field, object o) { switch (fieldCode(t, field)) { case ByteField: return objectClass(t, o) == type(t, Machine::ByteType); case BooleanField: return objectClass(t, o) == type(t, Machine::BooleanType); case CharField: return objectClass(t, o) == type(t, Machine::CharType); case ShortField: return objectClass(t, o) == type(t, Machine::ShortType); case IntField: return objectClass(t, o) == type(t, Machine::IntType); case LongField: return objectClass(t, o) == type(t, Machine::LongType); case FloatField: return objectClass(t, o) == type(t, Machine::FloatType); case DoubleField: return objectClass(t, o) == type(t, Machine::DoubleType); case ObjectField: if (o == 0) { return true; } else { PROTECT(t, o); object spec; if (byteArrayBody(t, fieldSpec(t, field), 0) == '[') { spec = fieldSpec(t, field);; } else { spec = makeByteArray(t, byteArrayLength(t, fieldSpec(t, field)) - 2); memcpy(&byteArrayBody(t, spec, 0), &byteArrayBody(t, fieldSpec(t, field), 1), byteArrayLength(t, fieldSpec(t, field)) - 3); byteArrayBody (t, spec, byteArrayLength(t, fieldSpec(t, field)) - 3) = 0; } return instanceOf (t, resolveClass(t, classLoader(t, fieldClass(t, field)), spec), o); } default: abort(t); } } object getField(Thread* t, object field, object instance) { PROTECT(t, field); PROTECT(t, instance); initClass(t, fieldClass(t, field)); object target; if (fieldFlags(t, field) & ACC_STATIC) { target = classStaticTable(t, fieldClass(t, field)); } else if (instanceOf(t, fieldClass(t, field), instance)){ target = instance; } else { throwNew(t, Machine::IllegalArgumentExceptionType); } unsigned offset = fieldOffset(t, field); switch (fieldCode(t, field)) { case ByteField: return makeByte(t, fieldAtOffset(target, offset)); case BooleanField: return makeBoolean(t, fieldAtOffset(target, offset)); case CharField: return makeChar(t, fieldAtOffset(target, offset)); case ShortField: return makeShort(t, fieldAtOffset(target, offset)); case IntField: return makeInt(t, fieldAtOffset(target, offset)); case LongField: return makeLong(t, fieldAtOffset(target, offset)); case FloatField: return makeFloat(t, fieldAtOffset(target, offset)); case DoubleField: return makeDouble(t, fieldAtOffset(target, offset)); case ObjectField: return fieldAtOffset(target, offset); default: abort(t); } } void setField(Thread* t, object field, object instance, object value) { PROTECT(t, field); PROTECT(t, instance); PROTECT(t, value); if (not matchType(t, field, value)) { throwNew(t, Machine::IllegalArgumentExceptionType); } object target; if ((fieldFlags(t, field) & ACC_STATIC) != 0) { target = classStaticTable(t, fieldClass(t, field)); } else if (instanceOf(t, fieldClass(t, field), instance)){ target = instance; } else { throwNew(t, Machine::IllegalArgumentExceptionType); } PROTECT(t, target); initClass(t, fieldClass(t, field)); unsigned offset = fieldOffset(t, field); switch (fieldCode(t, field)) { case ByteField: fieldAtOffset(target, offset) = byteValue(t, value); break; case BooleanField: fieldAtOffset(target, offset) = booleanValue(t, value); break; case CharField: fieldAtOffset(target, offset) = charValue(t, value); break; case ShortField: fieldAtOffset(target, offset) = shortValue(t, value); break; case IntField: fieldAtOffset(target, offset) = intValue(t, value); break; case LongField: fieldAtOffset(target, offset) = longValue(t, value); break; case FloatField: fieldAtOffset(target, offset) = floatValue(t, value); break; case DoubleField: fieldAtOffset(target, offset) = doubleValue(t, value); break; case ObjectField: set(t, target, offset, value); break; default: abort(t); } } } // namespace local } // namespace namespace vm { Classpath* makeClasspath(System*, Allocator* allocator, const char*, const char*) { return new (allocator->allocate(sizeof(local::MyClasspath))) local::MyClasspath(allocator); } } // namespace vm extern "C" int jniRegisterNativeMethods(JNIEnv* e, const char* className, const JNINativeMethod* methods, int methodCount) { jclass c = e->vtable->FindClass(e, className); if (c) { e->vtable->RegisterNatives(e, c, methods, methodCount); } else { e->vtable->ExceptionClear(e); } return 0; } extern "C" void jniLogException(JNIEnv*, int, const char*, jthrowable) { // ignore } extern "C" int jniThrowException(JNIEnv* e, const char* className, const char* message) { jclass c = e->vtable->FindClass(e, className); if (c) { e->vtable->ThrowNew(e, c, message); } return 0; } extern "C" int jniThrowExceptionFmt(JNIEnv* e, const char* className, const char* format, va_list args) { const unsigned size = 4096; char buffer[size]; ::vsnprintf(buffer, size, format, args); return jniThrowException(e, className, buffer); } extern "C" int jniThrowNullPointerException(JNIEnv* e, const char* message) { return jniThrowException(e, "java/lang/NullPointerException", message); } extern "C" int jniThrowRuntimeException(JNIEnv* e, const char* message) { return jniThrowException(e, "java/lang/RuntimeException", message); } extern "C" int jniThrowIOException(JNIEnv* e, const char* message) { return jniThrowException(e, "java/lang/IOException", message); } extern "C" const char* jniStrError(int error, char* buffer, size_t length) { #ifdef PLATFORM_WINDOWS const char* s = getErrnoDescription(error); if (strlen(s) < length) { strncpy(buffer, s, length); return buffer; } else { return 0; } #else if (static_cast(strerror_r(error, buffer, length)) == 0) { return buffer; } else { return 0; } #endif } extern "C" int __android_log_print(int priority, const char* tag, const char* format, ...) { va_list a; const unsigned size = 4096; char buffer[size]; va_start(a, format); ::vsnprintf(buffer, size, format, a); va_end(a); return fprintf(stderr, "%d %s %s\n", priority, tag, buffer); } extern "C" int jniGetFDFromFileDescriptor(JNIEnv* e, jobject descriptor) { return e->vtable->GetIntField (e, descriptor, e->vtable->GetFieldID (e, e->vtable->FindClass (e, "java/io/FileDescriptor"), "descriptor", "I")); } extern "C" void jniSetFileDescriptorOfFD(JNIEnv* e, jobject descriptor, int value) { e->vtable->SetIntField (e, descriptor, e->vtable->GetFieldID (e, e->vtable->FindClass (e, "java/io/FileDescriptor"), "descriptor", "I"), value); } extern "C" jobject jniCreateFileDescriptor(JNIEnv* e, int fd) { jobject descriptor = e->vtable->NewObject (e, e->vtable->FindClass(e, "java/io/FileDescriptor"), e->vtable->GetMethodID (e, e->vtable->FindClass(e, "java/io/FileDescriptor"), "", "()V")); jniSetFileDescriptorOfFD(e, descriptor, fd); return descriptor; } int register_org_apache_harmony_dalvik_NativeTestTarget(_JNIEnv*) { // ignore return 0; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_String_compareTo (Thread* t, object, uintptr_t* arguments) { object a = reinterpret_cast(arguments[0]); object b = reinterpret_cast(arguments[1]); unsigned length = stringLength(t, a); if (length > stringLength(t, b)) { length = stringLength(t, b); } for (unsigned i = 0; i < length; ++i) { int d = stringCharAt(t, a, i) - stringCharAt(t, b, i); if (d) { return d; } } return stringLength(t, a) - stringLength(t, b); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_String_isEmpty (Thread* t, object, uintptr_t* arguments) { return stringLength(t, reinterpret_cast(arguments[0])) == 0; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_String_length (Thread* t, object, uintptr_t* arguments) { return stringLength(t, reinterpret_cast(arguments[0])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_String_intern (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (intern(t, reinterpret_cast(arguments[0]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_String_charAt (Thread* t, object, uintptr_t* arguments) { return stringCharAt(t, reinterpret_cast(arguments[0]), arguments[1]); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_String_equals (Thread* t, object, uintptr_t* arguments) { return arguments[1] and stringEqual (t, reinterpret_cast(arguments[0]), reinterpret_cast(arguments[1])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_String_fastIndexOf (Thread* t, object, uintptr_t* arguments) { object s = reinterpret_cast(arguments[0]); unsigned c = arguments[1]; unsigned start = arguments[2]; for (unsigned i = start; i < stringLength(t, s); ++i) { if (stringCharAt(t, s, i) == c) { return i; } } return -1; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getInterfaces (Thread* t, object, uintptr_t* arguments) { object c = reinterpret_cast(arguments[0]); object addendum = classAddendum(t, jclassVmClass(t, c)); if (addendum) { object table = classAddendumInterfaceTable(t, addendum); if (table) { PROTECT(t, table); object array = makeObjectArray(t, arrayLength(t, table)); PROTECT(t, array); for (unsigned i = 0; i < arrayLength(t, table); ++i) { object c = getJClass(t, arrayBody(t, table, i)); set(t, array, ArrayBody + (i * BytesPerWord), c); } return reinterpret_cast(array); } } return reinterpret_cast (makeObjectArray(t, type(t, Machine::JclassType), 0)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getDeclaredClasses (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (getDeclaredClasses (t, jclassVmClass(t, reinterpret_cast(arguments[0])), arguments[1])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getDeclaringClass (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (getDeclaringClass (t, jclassVmClass(t, reinterpret_cast(arguments[0])))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getEnclosingMethod (Thread* t, object, uintptr_t* arguments) { object c = jclassVmClass(t, reinterpret_cast(arguments[0])); PROTECT(t, c); object addendum = classAddendum(t, c); if (addendum) { object enclosingClass = classAddendumEnclosingClass(t, addendum); if (enclosingClass) { PROTECT(t, enclosingClass); enclosingClass = getJClass (t, resolveClass(t, classLoader(t, c), enclosingClass)); object enclosingMethod = classAddendumEnclosingMethod(t, addendum); if (enclosingMethod) { PROTECT(t, enclosingMethod); return reinterpret_cast (t->m->classpath->makeJMethod (t, findMethodInClass (t, enclosingClass, pairFirst(t, enclosingMethod), pairSecond(t, enclosingMethod)))); } } } return 0; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getEnclosingConstructor (Thread* t, object method, uintptr_t* arguments) { return Avian_java_lang_Class_getEnclosingMethod(t, method, arguments); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_newInstanceImpl (Thread* t, object, uintptr_t* arguments) { object c = jclassVmClass(t, reinterpret_cast(arguments[0])); object method = resolveMethod(t, c, "", "()V"); PROTECT(t, method); object instance = makeNew(t, c); PROTECT(t, instance); t->m->processor->invoke(t, method, instance); return reinterpret_cast(instance); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getComponentType (Thread* t, object, uintptr_t* arguments) { object c = reinterpret_cast(arguments[0]); if (classArrayDimensions(t, jclassVmClass(t, c))) { uint8_t n = byteArrayBody(t, className(t, jclassVmClass(t, c)), 1); if (n != 'L' and n != '[') { return reinterpret_cast (getJClass(t, primitiveClass(t, n))); } else { return reinterpret_cast (getJClass(t, classStaticTable(t, jclassVmClass(t, c)))); } } else { return 0; } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_classForName (Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[0]); PROTECT(t, name); object loader = reinterpret_cast(arguments[2]); PROTECT(t, loader); object method = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); return reinterpret_cast (t->m->processor->invoke (t, method, 0, name, static_cast(arguments[1]), loader)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getDeclaredField (Thread* t, object, uintptr_t* arguments) { object c = reinterpret_cast(arguments[0]); PROTECT(t, c); object name = reinterpret_cast(arguments[1]); PROTECT(t, name); object method = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "findField", "(Lavian/VMClass;Ljava/lang/String;)I"); int index = intValue (t, t->m->processor->invoke (t, method, 0, jclassVmClass(t, c), name)); if (index >= 0) { return reinterpret_cast(local::makeField(t, c, index)); } else { return 0; } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getDeclaredConstructorOrMethod (Thread* t, object, uintptr_t* arguments) { object c = reinterpret_cast(arguments[0]); PROTECT(t, c); object name = reinterpret_cast(arguments[1]); PROTECT(t, name); object parameterTypes = reinterpret_cast(arguments[2]); PROTECT(t, parameterTypes); object method = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "findMethod", "(Lavian/VMClass;Ljava/lang/String;[Ljava/lang/Class;)I"); int index = intValue (t, t->m->processor->invoke (t, method, 0, jclassVmClass(t, c), name, parameterTypes)); if (index >= 0) { return reinterpret_cast (local::makeMethodOrConstructor(t, c, index)); } else { return 0; } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_SystemClassLoader_findLoadedVMClass (Thread*, object, uintptr_t*); extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_VMClassLoader_findLoadedClass (Thread* t, object method, uintptr_t* arguments) { int64_t v = Avian_avian_SystemClassLoader_findLoadedVMClass (t, method, arguments); if (v) { return reinterpret_cast (getJClass(t, reinterpret_cast(v))); } else { return 0; } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_VMClassLoader_defineClass__Ljava_lang_ClassLoader_2Ljava_lang_String_2_3BII (Thread* t, object method, uintptr_t* arguments) { uintptr_t args[] = { arguments[0], arguments[2], arguments[3], arguments[4] }; int64_t v = Avian_avian_Classes_defineVMClass(t, method, args); if (v) { return reinterpret_cast (getJClass(t, reinterpret_cast(v))); } else { return 0; } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_dalvik_system_VMRuntime_bootClassPath (Thread* t, object, uintptr_t*) { return reinterpret_cast(root(t, Machine::BootLoader)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_dalvik_system_VMRuntime_classPath (Thread* t, object, uintptr_t*) { return reinterpret_cast(root(t, Machine::AppLoader)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_dalvik_system_VMRuntime_vmVersion (Thread* t, object, uintptr_t*) { return reinterpret_cast(makeString(t, "%s", AVIAN_VERSION)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_dalvik_system_VMRuntime_properties (Thread* t, object, uintptr_t*) { object array = makeObjectArray(t, type(t, Machine::StringType), 1); PROTECT(t, array); object property = makeString(t, "java.protocol.handler.pkgs=avian"); set(t, array, ArrayBody, property); return reinterpret_cast(array); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Runtime_gc (Thread* t, object, uintptr_t*) { collect(t, Heap::MajorCollection); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Runtime_nativeLoad (Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[0]); PROTECT(t, name); unsigned length = stringLength(t, name); THREAD_RUNTIME_ARRAY(t, char, n, length + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); if (loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), false, true)) { return 0; } else { return reinterpret_cast(name); } } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_System_arraycopy (Thread* t, object, uintptr_t* arguments) { arrayCopy(t, reinterpret_cast(arguments[0]), arguments[1], reinterpret_cast(arguments[2]), arguments[3], arguments[4]); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_objectFieldOffset (Thread* t, object, uintptr_t* arguments) { object jfield = reinterpret_cast(arguments[1]); return fieldOffset (t, arrayBody (t, classFieldTable (t, jclassVmClass(t, jfieldDeclaringClass(t, jfield))), jfieldSlot(t, jfield))); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_VMThread_interrupt (Thread* t, object, uintptr_t* arguments) { object vmThread = reinterpret_cast(arguments[0]); PROTECT(t, vmThread); object field = resolveField (t, objectClass(t, vmThread), "thread", "Ljava/lang/Thread;"); interrupt (t, reinterpret_cast (threadPeer(t, fieldAtOffset(vmThread, fieldOffset(t, field))))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_VMThread_interrupted (Thread* t, object, uintptr_t*) { return getAndClearInterrupted(t, t); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_VMThread_isInterrupted (Thread* t, object, uintptr_t* arguments) { object vmThread = reinterpret_cast(arguments[0]); PROTECT(t, vmThread); object field = resolveField (t, objectClass(t, vmThread), "thread", "Ljava/lang/Thread;"); return threadInterrupted (t, fieldAtOffset(vmThread, fieldOffset(t, field))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_VMThread_getStatus (Thread*, object, uintptr_t*) { // todo return 1; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_VMThread_currentThread (Thread* t, object, uintptr_t*) { return reinterpret_cast(t->javaThread); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_VMThread_create (Thread* t, object, uintptr_t* arguments) { object thread = reinterpret_cast(arguments[0]); PROTECT(t, thread); local::initVmThread(t, thread); startThread(t, thread); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_VMThread_sleep (Thread* t, object, uintptr_t* arguments) { int64_t milliseconds; memcpy(&milliseconds, arguments, 8); if (arguments[2] > 0) ++ milliseconds; if (milliseconds <= 0) milliseconds = 1; if (threadSleepLock(t, t->javaThread) == 0) { object lock = makeJobject(t); set(t, t->javaThread, ThreadSleepLock, lock); } acquire(t, threadSleepLock(t, t->javaThread)); vm::wait(t, threadSleepLock(t, t->javaThread), milliseconds); release(t, threadSleepLock(t, t->javaThread)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_dalvik_system_VMStack_getThreadStackTrace (Thread* t, object, uintptr_t* arguments) { Thread* p = reinterpret_cast (threadPeer(t, reinterpret_cast(arguments[0]))); return reinterpret_cast (local::translateStackTrace (t, p == t ? makeTrace(t) : t->m->processor->getStackTrace(t, p))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_dalvik_system_VMStack_getCallingClassLoader (Thread* t, object, uintptr_t*) { class Visitor: public Processor::StackVisitor { public: Visitor(Thread* t): t(t), loader(0), counter(2) { } virtual bool visit(Processor::StackWalker* walker) { if (counter--) { return true; } else { this->loader = classLoader(t, methodClass(t, walker->method())); return false; } } Thread* t; object loader; unsigned counter; } v(t); t->m->processor->walkStack(t, &v); return reinterpret_cast(v.loader); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_dalvik_system_VMStack_getClasses (Thread* t, object, uintptr_t*) { class Visitor: public Processor::StackVisitor { public: Visitor(Thread* t): t(t), array(0), counter(0) { } virtual bool visit(Processor::StackWalker* walker) { if (counter < 2) { return true; } else { if (array == 0) { array = makeObjectArray (t, type(t, Machine::JclassType), walker->count()); } object c = getJClass(t, methodClass(t, walker->method())); assert(t, counter - 2 < objectArrayLength(t, array)); set(t, array, ArrayBody + ((counter - 2) * BytesPerWord), c); return true; } ++ counter; } Thread* t; object array; unsigned counter; } v(t); PROTECT(t, v.array); t->m->processor->walkStack(t, &v); return reinterpret_cast (v.array ? v.array : makeObjectArray(t, type(t, Machine::JclassType), 0)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Math_min (Thread*, object, uintptr_t* arguments) { return min(static_cast(arguments[0]), static_cast(arguments[1])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Math_max (Thread*, object, uintptr_t* arguments) { return max(static_cast(arguments[0]), static_cast(arguments[1])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Math_cos (Thread*, object, uintptr_t* arguments) { int64_t v; memcpy(&v, arguments, 8); return doubleToBits(cos(bitsToDouble(v))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Math_sin (Thread*, object, uintptr_t* arguments) { int64_t v; memcpy(&v, arguments, 8); return doubleToBits(sin(bitsToDouble(v))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Math_sqrt (Thread*, object, uintptr_t* arguments) { int64_t v; memcpy(&v, arguments, 8); return doubleToBits(sqrt(bitsToDouble(v))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Math_abs__I (Thread*, object, uintptr_t* arguments) { return abs(static_cast(arguments[0])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Math_abs__J (Thread*, object, uintptr_t* arguments) { return llabs(arguments[0]); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Math_abs__F (Thread*, object, uintptr_t* arguments) { return floatToBits(abs(bitsToFloat(arguments[0]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Float_intBitsToFloat (Thread*, object, uintptr_t* arguments) { return arguments[0]; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Float_floatToIntBits (Thread*, object, uintptr_t* arguments) { if (((arguments[0] & 0x7F800000) == 0x7F800000) and ((arguments[0] & 0x007FFFFF) != 0)) { return 0x7fc00000; } else { return arguments[0]; } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Double_doubleToRawLongBits (Thread*, object, uintptr_t* arguments) { int64_t v; memcpy(&v, arguments, 8); // todo: do we need to do NaN checks as in // Avian_java_lang_Float_floatToIntBits above? If so, update // Double.doubleToRawLongBits in the Avian class library too. return v; } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Object_wait (Thread* t, object, uintptr_t* arguments) { jlong milliseconds; memcpy(&milliseconds, arguments + 1, sizeof(jlong)); wait(t, reinterpret_cast(arguments[0]), milliseconds); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Object_notifyAll (Thread* t, object, uintptr_t* arguments) { notifyAll(t, reinterpret_cast(arguments[0])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Object_getClass (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (getJClass(t, objectClass(t, reinterpret_cast(arguments[0])))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Object_hashCode (Thread* t, object, uintptr_t* arguments) { return objectHash(t, reinterpret_cast(arguments[0])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Object_internalClone (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (clone(t, reinterpret_cast(arguments[1]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getModifiers (Thread* t, object, uintptr_t* arguments) { return classModifiers (t, jclassVmClass(t, reinterpret_cast(arguments[0]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getSuperclass (Thread* t, object, uintptr_t* arguments) { object c = jclassVmClass(t, reinterpret_cast(arguments[0])); if (classFlags(t, c) & ACC_INTERFACE) { return 0; } else { object s = classSuper(t, c); return s ? reinterpret_cast(getJClass(t, s)) : 0; } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_desiredAssertionStatus (Thread*, object, uintptr_t*) { return 1; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getNameNative (Thread* t, object, uintptr_t* arguments) { object name = className (t, jclassVmClass(t, reinterpret_cast(arguments[0]))); THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, name)); replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast(&byteArrayBody(t, name, 0))); return reinterpret_cast (makeString(t, "%s", RUNTIME_ARRAY_BODY(s))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_isInterface (Thread* t, object, uintptr_t* arguments) { return (classFlags (t, jclassVmClass(t, reinterpret_cast(arguments[0]))) & ACC_INTERFACE) != 0; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_isPrimitive (Thread* t, object, uintptr_t* arguments) { return (classVmFlags (t, jclassVmClass(t, reinterpret_cast(arguments[0]))) & PrimitiveFlag) != 0; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_isAnonymousClass (Thread* t, object, uintptr_t* arguments) { object name = className (t, jclassVmClass(t, reinterpret_cast(arguments[0]))); for (unsigned i = 0; i < byteArrayLength(t, name) - 1; ++i) { int c = byteArrayBody(t, name, i); if (c != '$' and (c < '0' or c > '9')) { return false; } } return true; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getClassLoader (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (classLoader (t, jclassVmClass(t, reinterpret_cast(arguments[0])))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_isAssignableFrom (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); object that = reinterpret_cast(arguments[1]); if (LIKELY(that)) { return isAssignableFrom (t, jclassVmClass(t, this_), jclassVmClass(t, that)); } else { throwNew(t, Machine::NullPointerExceptionType); } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_isInstance (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); object o = reinterpret_cast(arguments[1]); if (o) { return instanceOf(t, jclassVmClass(t, this_), o); } else { return 0; } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getDeclaredMethods (Thread* t, object, uintptr_t* arguments) { object c = reinterpret_cast(arguments[0]); PROTECT(t, c); bool publicOnly = arguments[1]; object get = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "getMethods", "(Lavian/VMClass;Z)[Ljava/lang/reflect/Method;"); return reinterpret_cast (t->m->processor->invoke(t, get, 0, jclassVmClass(t, c), publicOnly)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getDeclaredFields (Thread* t, object, uintptr_t* arguments) { object c = reinterpret_cast(arguments[0]); PROTECT(t, c); bool publicOnly = arguments[1]; object get = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "getFields", "(Lavian/VMClass;Z)[Ljava/lang/reflect/Field;"); return reinterpret_cast (t->m->processor->invoke(t, get, 0, jclassVmClass(t, c), publicOnly)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Method_invokeNative (Thread* t, object, uintptr_t* arguments) { object instance = reinterpret_cast(arguments[1]); object args = reinterpret_cast(arguments[2]); object method = arrayBody (t, classMethodTable (t, jclassVmClass(t, reinterpret_cast(arguments[3]))), arguments[6]); return reinterpret_cast(invoke(t, method, instance, args)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Method_getMethodModifiers (Thread* t, object, uintptr_t* arguments) { return methodFlags (t, arrayBody (t, classMethodTable (t, jclassVmClass(t, reinterpret_cast(arguments[0]))), arguments[1])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Method_isAnnotationPresent (Thread* t, object, uintptr_t* arguments) { object method = arrayBody (t, classMethodTable (t, jclassVmClass(t, reinterpret_cast(arguments[0]))), arguments[1]); object addendum = methodAddendum(t, method); if (addendum) { object table = addendumAnnotationTable(t, addendum); if (table) { for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { if (objectArrayBody(t, objectArrayBody(t, table, i), 1) == reinterpret_cast(arguments[2])) { return true; } } } } return false; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Method_getAnnotation (Thread* t, object, uintptr_t* arguments) { object method = arrayBody (t, classMethodTable (t, jclassVmClass(t, reinterpret_cast(arguments[0]))), arguments[1]); object addendum = methodAddendum(t, method); if (addendum) { object table = addendumAnnotationTable(t, addendum); if (table) { for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { if (objectArrayBody(t, objectArrayBody(t, table, i), 1) == reinterpret_cast(arguments[2])) { PROTECT(t, method); PROTECT(t, table); object get = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "getAnnotation", "(Ljava/lang/ClassLoader;[Ljava/lang/Object;)" "Ljava/lang/annotation/Annotation;"); return reinterpret_cast (t->m->processor->invoke (t, get, 0, classLoader(t, methodClass(t, method)), objectArrayBody(t, table, i))); } } } } return false; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Method_getDeclaredAnnotations (Thread* t, object, uintptr_t* arguments) { object method = arrayBody (t, classMethodTable (t, jclassVmClass(t, reinterpret_cast(arguments[0]))), arguments[1]); object addendum = methodAddendum(t, method); if (addendum) { object table = addendumAnnotationTable(t, addendum); if (table) { PROTECT(t, method); PROTECT(t, table); object array = makeObjectArray (t, resolveClass (t, root(t, Machine::BootLoader), "java/lang/annotation/Annotation"), objectArrayLength(t, table)); PROTECT(t, array); object get = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "getAnnotation", "(Ljava/lang/ClassLoader;[Ljava/lang/Object;)" "Ljava/lang/annotation/Annotation;"); PROTECT(t, get); for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { object a = t->m->processor->invoke (t, get, 0, classLoader(t, methodClass(t, method)), objectArrayBody(t, table, i)); set(t, array, ArrayBody + (i * BytesPerWord), a); } return reinterpret_cast(array); } } return reinterpret_cast (makeObjectArray (t, resolveClass (t, root(t, Machine::BootLoader), "java/lang/annotation/Annotation"), 0)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Method_getDefaultValue (Thread* t, object, uintptr_t* arguments) { object method = arrayBody (t, classMethodTable (t, jclassVmClass(t, reinterpret_cast(arguments[1]))), arguments[2]); object addendum = methodAddendum(t, method); if (addendum) { object get = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "getAnnotationDefaultValue", "(Ljava/lang/ClassLoader;Lavian/MethodAddendum;)" "Ljava/lang/Object;"); return reinterpret_cast (t->m->processor->invoke (t, get, 0, classLoader(t, methodClass(t, method)), addendum)); } return 0; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Constructor_constructNative (Thread* t, object, uintptr_t* arguments) { object args = reinterpret_cast(arguments[1]); PROTECT(t, args); object c = jclassVmClass(t, reinterpret_cast(arguments[2])); PROTECT(t, c); initClass(t, c); object method = arrayBody(t, classMethodTable(t, c), arguments[4]); PROTECT(t, method); object instance = makeNew(t, c); PROTECT(t, instance); t->m->processor->invokeArray(t, method, instance, args); return reinterpret_cast(instance); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Field_getField (Thread* t, object, uintptr_t* arguments) { object field = arrayBody (t, classFieldTable (t, jclassVmClass(t, reinterpret_cast(arguments[2]))), arguments[4]); PROTECT(t, field); object instance = reinterpret_cast(arguments[1]); PROTECT(t, instance); return reinterpret_cast(local::getField(t, field, instance)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Field_getIField (Thread* t, object, uintptr_t* arguments) { object field = arrayBody (t, classFieldTable (t, jclassVmClass(t, reinterpret_cast(arguments[2]))), arguments[4]); PROTECT(t, field); object instance = reinterpret_cast(arguments[1]); PROTECT(t, instance); return intValue(t, local::getField(t, field, instance)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Field_getJField (Thread* t, object, uintptr_t* arguments) { object field = arrayBody (t, classFieldTable (t, jclassVmClass(t, reinterpret_cast(arguments[2]))), arguments[4]); PROTECT(t, field); object instance = reinterpret_cast(arguments[1]); PROTECT(t, instance); return longValue(t, local::getField(t, field, instance)); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_reflect_Field_setField (Thread* t, object, uintptr_t* arguments) { object field = arrayBody (t, classFieldTable (t, jclassVmClass(t, reinterpret_cast(arguments[2]))), arguments[4]); PROTECT(t, field); object instance = reinterpret_cast(arguments[1]); PROTECT(t, instance); object value = reinterpret_cast(arguments[6]); PROTECT(t, value); local::setField(t, field, instance, value); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_reflect_Field_setIField (Thread* t, object, uintptr_t* arguments) { object field = arrayBody (t, classFieldTable (t, jclassVmClass(t, reinterpret_cast(arguments[2]))), arguments[4]); object instance = reinterpret_cast(arguments[1]); PROTECT(t, instance); object value = makeInt(t, arguments[7]); local::setField(t, field, instance, value); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Field_getFieldModifiers (Thread* t, object, uintptr_t* arguments) { return fieldFlags (t, arrayBody (t, classFieldTable (t, jclassVmClass(t, reinterpret_cast(arguments[1]))), arguments[2])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Field_getAnnotation (Thread* t, object, uintptr_t* arguments) { object field = arrayBody (t, classFieldTable (t, jclassVmClass(t, reinterpret_cast(arguments[0]))), arguments[1]); object addendum = fieldAddendum(t, field); if (addendum) { object table = addendumAnnotationTable(t, addendum); if (table) { for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { if (objectArrayBody(t, objectArrayBody(t, table, i), 1) == reinterpret_cast(arguments[2])) { PROTECT(t, field); PROTECT(t, table); object get = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "getAnnotation", "(Ljava/lang/ClassLoader;[Ljava/lang/Object;)" "Ljava/lang/annotation/Annotation;"); return reinterpret_cast (t->m->processor->invoke (t, get, 0, classLoader(t, fieldClass(t, field)), objectArrayBody(t, table, i))); } } } } return false; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Field_getSignatureAnnotation (Thread* t, object, uintptr_t* arguments) { object field = arrayBody (t, classFieldTable (t, jclassVmClass(t, reinterpret_cast(arguments[1]))), arguments[2]); object addendum = fieldAddendum(t, field); if (addendum) { object signature = addendumSignature(t, addendum); if (signature) { object array = makeObjectArray(t, 1); PROTECT(t, array); object string = t->m->classpath->makeString (t, signature, 0, byteArrayLength(t, signature) - 1); set(t, array, ArrayBody, string); return reinterpret_cast(array); } } return reinterpret_cast(makeObjectArray(t, 0)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Throwable_nativeFillInStackTrace (Thread* t, object, uintptr_t*) { return reinterpret_cast(getTrace(t, 2)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Throwable_nativeGetStackTrace (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (local::translateStackTrace(t, reinterpret_cast(arguments[0]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Classes_makeMethod (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (local::makeMethodOrConstructor (t, reinterpret_cast(arguments[0]), arguments[1])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Classes_makeField (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (local::makeField (t, reinterpret_cast(arguments[0]), arguments[1])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Array_createObjectArray (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (makeObjectArray (t, jclassVmClass(t, reinterpret_cast(arguments[0])), arguments[1])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_nio_ByteOrder_isLittleEndian (Thread*, object, uintptr_t*) { #ifdef ARCH_powerpc return false; #else return true; #endif } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_dalvik_system_VMRuntime_newNonMovableArray (Thread* t, object, uintptr_t* arguments) { if (jclassVmClass(t, reinterpret_cast(arguments[1])) == type(t, Machine::JbyteType)) { object array = allocate3 (t, t->m->heap, Machine::FixedAllocation, ArrayBody + arguments[2], false); setObjectClass(t, array, type(t, Machine::ByteArrayType)); byteArrayLength(t, array) = arguments[2]; return reinterpret_cast(array); } else { // todo abort(t); } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_dalvik_system_VMRuntime_addressOf (Thread*, object, uintptr_t* arguments) { return arguments[1] + ArrayBody; } extern "C" AVIAN_EXPORT void JNICALL Avian_libcore_io_Memory_pokeLong (Thread*, object, uintptr_t* arguments) { int64_t address; memcpy(&address, arguments, 8); int64_t v; memcpy(&v, arguments + 2, 8); if (arguments[4]) { v = swapV8(v); } memcpy(reinterpret_cast(address), &v, 8); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_libcore_io_Memory_peekLong (Thread*, object, uintptr_t* arguments) { int64_t address; memcpy(&address, arguments, 8); int64_t v; memcpy(&v, reinterpret_cast(address), 8); return arguments[2] ? swapV8(v) : v; } extern "C" AVIAN_EXPORT void JNICALL Avian_libcore_io_Memory_pokeInt (Thread*, object, uintptr_t* arguments) { int64_t address; memcpy(&address, arguments, 8); int32_t v = arguments[3] ? swapV4(arguments[2]) : arguments[2]; memcpy(reinterpret_cast(address), &v, 4); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_libcore_io_Memory_peekInt (Thread*, object, uintptr_t* arguments) { int64_t address; memcpy(&address, arguments, 8); int32_t v; memcpy(&v, reinterpret_cast(address), 4); return arguments[2] ? swapV4(v) : v; } extern "C" AVIAN_EXPORT void JNICALL Avian_libcore_io_Memory_pokeShort (Thread*, object, uintptr_t* arguments) { int64_t address; memcpy(&address, arguments, 8); int16_t v = arguments[3] ? swapV2(arguments[2]) : arguments[2]; memcpy(reinterpret_cast(address), &v, 2); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_libcore_io_Memory_peekShort (Thread*, object, uintptr_t* arguments) { int64_t address; memcpy(&address, arguments, 8); int16_t v; memcpy(&v, reinterpret_cast(address), 2); return arguments[2] ? swapV2(v) : v; } extern "C" AVIAN_EXPORT void JNICALL Avian_libcore_io_Memory_pokeByte (Thread*, object, uintptr_t* arguments) { int64_t address; memcpy(&address, arguments, 8); *reinterpret_cast(address) = arguments[2]; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_libcore_io_Memory_peekByte (Thread*, object, uintptr_t* arguments) { int64_t address; memcpy(&address, arguments, 8); return *reinterpret_cast(address); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_System_nanoTime (Thread* t, object, uintptr_t*) { return t->m->system->now() * 1000 * 1000; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_System_currentTimeMillis (Thread* t, object, uintptr_t*) { return t->m->system->now(); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_System_identityHashCode (Thread* t, object, uintptr_t* arguments) { return objectHash(t, reinterpret_cast(arguments[0])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_System_mapLibraryName (Thread* t, object, uintptr_t* arguments) { object original = reinterpret_cast(arguments[0]); unsigned originalLength = stringUTFLength(t, original); THREAD_RUNTIME_ARRAY(t, char, originalChars, originalLength); stringUTFChars (t, original, RUNTIME_ARRAY_BODY(originalChars), originalLength); return reinterpret_cast (makeString(t, "%s%.*s%s", t->m->system->libraryPrefix(), originalLength, RUNTIME_ARRAY_BODY(originalChars), t->m->system->librarySuffix())); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8 (Thread*, object, uintptr_t*) { return true; } #ifdef PLATFORM_WINDOWS # include void register_java_io_Console(_JNIEnv*) { } void register_java_lang_ProcessManager(_JNIEnv*) { } void register_libcore_net_RawSocket(_JNIEnv*) { } void register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(_JNIEnv*) { } extern "C" AVIAN_EXPORT void JNICALL Avian_libcore_io_OsConstants_initConstants (Thread* t, object method, uintptr_t*) { object c = methodClass(t, method); PROTECT(t, c); object table = classStaticTable(t, c); PROTECT(t, table); object field = resolveField(t, c, "STDIN_FILENO", "I"); fieldAtOffset(table, fieldOffset(t, field)) = 0; field = resolveField(t, c, "STDOUT_FILENO", "I"); fieldAtOffset(table, fieldOffset(t, field)) = 1; field = resolveField(t, c, "STDERR_FILENO", "I"); fieldAtOffset(table, fieldOffset(t, field)) = 2; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_libcore_io_Posix_getenv(Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[1]); THREAD_RUNTIME_ARRAY(t, uint16_t, chars, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(chars)); wchar_t* value = _wgetenv (reinterpret_cast(RUNTIME_ARRAY_BODY(chars))); if (value) { unsigned size = wcslen(value); object a = makeCharArray(t, size); if (size) { memcpy(&charArrayBody(t, a, 0), value, size * sizeof(jchar)); } return reinterpret_cast (t->m->classpath->makeString(t, a, 0, size)); } else { return 0; } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_libcore_io_Posix_uname(Thread* t, object, uintptr_t*) { object c = resolveClass (t, root(t, Machine::BootLoader), "libcore/io/StructUtsname"); PROTECT(t, c); object instance = makeNew(t, c); PROTECT(t, instance); #ifdef ARCH_x86_32 object arch = makeString(t, "x86"); #elif defined ARCH_x86_64 object arch = makeString(t, "x86_64"); #elif defined ARCH_powerpc object arch = makeString(t, "ppc"); #elif defined ARCH_arm object arch = makeString(t, "arm"); #else object arch = makeString(t, "unknown"); #endif set(t, instance, fieldOffset (t, resolveField(t, c, "machine", "Ljava/lang/String;")), arch); object platform = makeString(t, "Windows"); set(t, instance, fieldOffset (t, resolveField(t, c, "sysname", "Ljava/lang/String;")), platform); object version = makeString(t, "unknown"); set(t, instance, fieldOffset (t, resolveField(t, c, "release", "Ljava/lang/String;")), version); return reinterpret_cast(instance); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_libcore_io_Posix_writeBytes(Thread* t, object, uintptr_t* arguments) { object fd = reinterpret_cast(arguments[1]); PROTECT(t, fd); object buffer = reinterpret_cast(arguments[2]); PROTECT(t, buffer); int offset = arguments[3]; int count = arguments[4]; int d = jniGetFDFromFileDescriptor(t, &fd); int r; if (objectClass(t, buffer) == type(t, Machine::ByteArrayType)) { void* tmp = t->m->heap->allocate(count); memcpy(tmp, &byteArrayBody(t, buffer, offset), count); { ENTER(t, Thread::IdleState); r = _write(d, tmp, count); } t->m->heap->free(tmp, count); } else { void* p = local::getDirectBufferAddress(t, buffer); { ENTER(t, Thread::IdleState); r = _write(d, p, count); } } if (r < 0) { THREAD_RUNTIME_ARRAY(t, char, message, 256); throwNew(t, Machine::RuntimeExceptionType, "writeBytes %d: %s", d, jniStrError(errno, RUNTIME_ARRAY_BODY(message), 0)); } else { return r; } } #endif ReadyTalk-avian-1e1fff5/src/classpath-avian.cpp000066400000000000000000000474621231440243200215460ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/machine.h" #include "avian/classpath-common.h" #include "avian/process.h" #include using namespace vm; namespace { namespace local { class MyClasspath : public Classpath { public: MyClasspath(Allocator* allocator): allocator(allocator) { } virtual object makeJclass(Thread* t, object class_) { return vm::makeJclass(t, class_); } virtual object makeString(Thread* t, object array, int32_t offset, int32_t length) { return vm::makeString(t, array, offset, length, 0); } virtual object makeThread(Thread* t, Thread* parent) { object group; if (parent) { group = threadGroup(t, parent->javaThread); } else { group = makeThreadGroup(t, 0, 0, 0); } const unsigned NewState = 0; const unsigned NormalPriority = 5; return vm::makeThread (t, 0, 0, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, root(t, Machine::AppLoader), 0, 0, group, 0); } virtual object makeJMethod(Thread* t, object vmMethod) { PROTECT(t, vmMethod); object jmethod = makeJmethod(t, vmMethod, false); return byteArrayBody(t, methodName(t, vmMethod), 0) == '<' ? makeJconstructor(t, jmethod) : jmethod; } virtual object getVMMethod(Thread* t, object jmethod) { return objectClass(t, jmethod) == type(t, Machine::JmethodType) ? jmethodVmMethod(t, jmethod) : jmethodVmMethod(t, jconstructorMethod(t, jmethod)); } virtual object makeJField(Thread* t, object vmField) { return makeJfield(t, vmField, false); } virtual object getVMField(Thread* t, object jfield) { return jfieldVmField(t, jfield); } virtual void clearInterrupted(Thread*) { // ignore } virtual void runThread(Thread* t) { object method = resolveMethod (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", "(Ljava/lang/Thread;)V"); t->m->processor->invoke(t, method, 0, t->javaThread); } virtual void resolveNative(Thread* t, object method) { vm::resolveNative(t, method); } virtual void interceptMethods(Thread*) { // ignore } virtual void preBoot(Thread*) { // ignore } virtual void boot(Thread*) { // ignore } virtual const char* bootClasspath() { return AVIAN_CLASSPATH; } virtual object makeDirectByteBuffer(Thread* t, void* p, jlong capacity) { object c = resolveClass (t, root(t, Machine::BootLoader), "java/nio/DirectByteBuffer"); PROTECT(t, c); object instance = makeNew(t, c); PROTECT(t, instance); object constructor = resolveMethod(t, c, "", "(JI)V"); t->m->processor->invoke (t, constructor, instance, reinterpret_cast(p), static_cast(capacity)); return instance; } virtual void* getDirectBufferAddress(Thread* t, object b) { PROTECT(t, b); object field = resolveField(t, objectClass(t, b), "address", "J"); return reinterpret_cast (fieldAtOffset(b, fieldOffset(t, field))); } virtual int64_t getDirectBufferCapacity(Thread* t, object b) { PROTECT(t, b); object field = resolveField (t, objectClass(t, b), "capacity", "I"); return fieldAtOffset(b, fieldOffset(t, field)); } virtual bool canTailCall(Thread*, object, object, object, object) { return true; } virtual void shutDown(Thread*) { // ignore } virtual void dispose() { allocator->free(this, sizeof(*this)); } Allocator* allocator; }; void enumerateThreads(Thread* t, Thread* x, object array, unsigned* index, unsigned limit) { if (*index < limit) { set(t, array, ArrayBody + (*index * BytesPerWord), x->javaThread); ++ (*index); if (x->peer) enumerateThreads(t, x->peer, array, index, limit); if (x->child) enumerateThreads(t, x->child, array, index, limit); } } } // namespace local } // namespace namespace vm { Classpath* makeClasspath(System*, Allocator* allocator, const char*, const char*) { return new (allocator->allocate(sizeof(local::MyClasspath))) local::MyClasspath(allocator); } } // namespace vm extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Object_toString (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); unsigned hash = objectHash(t, this_); object s = makeString (t, "%s@0x%x", &byteArrayBody(t, className(t, objectClass(t, this_)), 0), hash); return reinterpret_cast(s); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Object_getVMClass (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (objectClass(t, reinterpret_cast(arguments[0]))); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Object_wait (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); int64_t milliseconds; memcpy(&milliseconds, arguments + 1, 8); vm::wait(t, this_, milliseconds); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Object_notify (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); notify(t, this_); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Object_notifyAll (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); notifyAll(t, this_); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Object_hashCode (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); return objectHash(t, this_); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Object_clone (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (clone(t, reinterpret_cast(arguments[0]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_io_ObjectInputStream_makeInstance (Thread* t, object, uintptr_t* arguments) { object c = reinterpret_cast(arguments[0]); return reinterpret_cast(make(t, c)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_LegacyObjectInputStream_makeInstance (Thread* t, object, uintptr_t* arguments) { return Avian_java_io_ObjectInputStream_makeInstance(t, NULL, arguments); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Field_getPrimitive (Thread* t, object, uintptr_t* arguments) { object instance = reinterpret_cast(arguments[0]); int code = arguments[1]; int offset = arguments[2]; switch (code) { case ByteField: return fieldAtOffset(instance, offset); case BooleanField: return fieldAtOffset(instance, offset); case CharField: return fieldAtOffset(instance, offset); case ShortField: return fieldAtOffset(instance, offset); case IntField: return fieldAtOffset(instance, offset); case LongField: return fieldAtOffset(instance, offset); case FloatField: return fieldAtOffset(instance, offset); case DoubleField: return fieldAtOffset(instance, offset); default: abort(t); } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Field_getObject (Thread*, object, uintptr_t* arguments) { object instance = reinterpret_cast(arguments[0]); int offset = arguments[1]; return reinterpret_cast(fieldAtOffset(instance, offset)); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_reflect_Field_setPrimitive (Thread* t, object, uintptr_t* arguments) { object instance = reinterpret_cast(arguments[0]); int code = arguments[1]; int offset = arguments[2]; int64_t value; memcpy(&value, arguments + 3, 8); switch (code) { case ByteField: fieldAtOffset(instance, offset) = static_cast(value); break; case BooleanField: fieldAtOffset(instance, offset) = static_cast(value); break; case CharField: fieldAtOffset(instance, offset) = static_cast(value); break; case ShortField: fieldAtOffset(instance, offset) = static_cast(value); break; case IntField: fieldAtOffset(instance, offset) = static_cast(value); break; case LongField: fieldAtOffset(instance, offset) = static_cast(value); break; case FloatField: fieldAtOffset(instance, offset) = static_cast(value); break; case DoubleField: fieldAtOffset(instance, offset) = static_cast(value); break; default: abort(t); } } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_reflect_Field_setObject (Thread* t, object, uintptr_t* arguments) { object instance = reinterpret_cast(arguments[0]); int offset = arguments[1]; object value = reinterpret_cast(arguments[2]); set(t, instance, offset, value); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Constructor_make (Thread* t, object, uintptr_t* arguments) { object c = reinterpret_cast(arguments[0]); return reinterpret_cast(make(t, c)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Method_getCaller (Thread* t, object, uintptr_t*) { return reinterpret_cast(getCaller(t, 2)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Method_invoke (Thread* t, object, uintptr_t* arguments) { object method = reinterpret_cast(arguments[0]); object instance = reinterpret_cast(arguments[1]); object args = reinterpret_cast(arguments[2]); THREAD_RESOURCE0(t, { if (t->exception) { object exception = t->exception; t->exception = makeThrowable (t, Machine::InvocationTargetExceptionType, 0, 0, exception); } }); unsigned returnCode = methodReturnCode(t, method); return reinterpret_cast (translateInvokeResult (t, returnCode, t->m->processor->invokeArray(t, method, instance, args))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Array_getLength (Thread* t, object, uintptr_t* arguments) { object array = reinterpret_cast(arguments[0]); if (LIKELY(array)) { unsigned elementSize = classArrayElementSize(t, objectClass(t, array)); if (LIKELY(elementSize)) { return fieldAtOffset(array, BytesPerWord); } else { throwNew(t, Machine::IllegalArgumentExceptionType); } } else { throwNew(t, Machine::NullPointerExceptionType); } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_reflect_Array_makeObjectArray (Thread* t, object, uintptr_t* arguments) { object elementType = reinterpret_cast(arguments[0]); int length = arguments[1]; return reinterpret_cast (makeObjectArray(t, jclassVmClass(t, elementType), length)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Float_floatToRawIntBits (Thread*, object, uintptr_t* arguments) { return static_cast(*arguments); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Float_intBitsToFloat (Thread*, object, uintptr_t* arguments) { return static_cast(*arguments); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Double_doubleToRawLongBits (Thread*, object, uintptr_t* arguments) { int64_t v; memcpy(&v, arguments, 8); return v; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Double_longBitsToDouble (Thread*, object, uintptr_t* arguments) { int64_t v; memcpy(&v, arguments, 8); return v; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_String_intern (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); return reinterpret_cast(intern(t, this_)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_System_getVMProperty (Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[0]); object found = reinterpret_cast(arguments[1]); PROTECT(t, found); unsigned length = stringLength(t, name); THREAD_RUNTIME_ARRAY(t, char, n, length + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); int64_t r = 0; if (::strcmp(RUNTIME_ARRAY_BODY(n), "java.lang.classpath") == 0) { r = reinterpret_cast (makeString(t, "%s", t->m->appFinder->path())); } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "avian.version") == 0) { r = reinterpret_cast(makeString(t, AVIAN_VERSION)); } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "file.encoding") == 0) { r = reinterpret_cast(makeString(t, "ASCII")); } else { const char* v = findProperty(t, RUNTIME_ARRAY_BODY(n)); if (v) { r = reinterpret_cast(makeString(t, v)); } } if (r) { booleanArrayBody(t, found, 0) = true; } return r; } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_System_arraycopy (Thread* t, object, uintptr_t* arguments) { arrayCopy(t, reinterpret_cast(arguments[0]), arguments[1], reinterpret_cast(arguments[2]), arguments[3], arguments[4]); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_System_identityHashCode (Thread* t, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[0]); if (LIKELY(o)) { return objectHash(t, o); } else { throwNew(t, Machine::NullPointerExceptionType); } } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Runtime_load (Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[0]); bool mapName = arguments[1]; unsigned length = stringLength(t, name); THREAD_RUNTIME_ARRAY(t, char, n, length + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), mapName, true); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Runtime_gc (Thread* t, object, uintptr_t*) { collect(t, Heap::MajorCollection); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Runtime_freeMemory (Thread* t, object, uintptr_t*) { return t->m->heap->remaining(); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Runtime_totalMemory (Thread* t, object, uintptr_t*) { return t->m->heap->limit(); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Runtime_addShutdownHook (Thread* t, object, uintptr_t* arguments) { object hook = reinterpret_cast(arguments[1]); PROTECT(t, hook); ACQUIRE(t, t->m->shutdownLock); setRoot(t, Machine::ShutdownHooks, makePair(t, hook, root(t, Machine::ShutdownHooks))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Throwable_trace (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast(getTrace(t, arguments[0])); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Throwable_resolveTrace (Thread* t, object, uintptr_t* arguments) { object trace = reinterpret_cast(*arguments); PROTECT(t, trace); unsigned length = objectArrayLength(t, trace); object elementType = type(t, Machine::StackTraceElementType); object array = makeObjectArray(t, elementType, length); PROTECT(t, array); for (unsigned i = 0; i < length; ++i) { object ste = makeStackTraceElement(t, objectArrayBody(t, trace, i)); set(t, array, ArrayBody + (i * BytesPerWord), ste); } return reinterpret_cast(array); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Thread_currentThread (Thread* t, object, uintptr_t*) { return reinterpret_cast(t->javaThread); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Thread_doStart (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (startThread(t, reinterpret_cast(*arguments))); } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Thread_interrupt (Thread* t, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); threadInterrupt(t, reinterpret_cast(peer)->javaThread); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Thread_interrupted (Thread* t, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); return threadIsInterrupted (t, reinterpret_cast(peer)->javaThread, true); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Thread_getStackTrace (Thread* t, object, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); if (reinterpret_cast(peer) == t) { return reinterpret_cast(makeTrace(t)); } else { return reinterpret_cast (t->m->processor->getStackTrace(t, reinterpret_cast(peer))); } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Thread_activeCount (Thread* t, object, uintptr_t*) { return t->m->liveCount; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Thread_enumerate (Thread* t, object, uintptr_t* arguments) { object array = reinterpret_cast(*arguments); ACQUIRE_RAW(t, t->m->stateLock); unsigned count = min(t->m->liveCount, objectArrayLength(t, array)); unsigned index = 0; local::enumerateThreads(t, t->m->rootThread, array, &index, count); return count; } extern "C" AVIAN_EXPORT void JNICALL Avian_java_lang_Thread_yield (Thread* t, object, uintptr_t*) { t->m->system->yield(); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Atomic_getOffset (Thread* t, object, uintptr_t* arguments) { return fieldOffset (t, jfieldVmField(t, reinterpret_cast(arguments[0]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_objectFieldOffset (Thread* t, object, uintptr_t* arguments) { return fieldOffset (t, jfieldVmField(t, reinterpret_cast(arguments[1]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Atomic_compareAndSwapObject (Thread* t, object, uintptr_t* arguments) { object target = reinterpret_cast(arguments[0]); int64_t offset; memcpy(&offset, arguments + 1, 8); uintptr_t expect = arguments[3]; uintptr_t update = arguments[4]; bool success = atomicCompareAndSwap (&fieldAtOffset(target, offset), expect, update); if (success) { mark(t, target, offset); } return success; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Classes_isAssignableFrom (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); object that = reinterpret_cast(arguments[1]); if (LIKELY(that)) { return vm::isAssignableFrom(t, this_, that); } else { throwNew(t, Machine::NullPointerExceptionType); } } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Classes_getVMClass (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (objectClass(t, reinterpret_cast(arguments[0]))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_avian_Classes_makeMethod (Thread* t, object, uintptr_t* arguments) { object method = arrayBody (t, classMethodTable (t, jclassVmClass(t, reinterpret_cast(arguments[0]))), arguments[1]); PROTECT(t, method); object c = resolveClass (t, root(t, Machine::BootLoader), "java/lang/reflect/Method"); PROTECT(t, c); object instance = makeNew(t, c); PROTECT(t, instance); object constructor = resolveMethod(t, c, "", "(Lavian/VMMethod;)V"); t->m->processor->invoke(t, constructor, instance, method); if (byteArrayBody(t, methodName(t, method), 0) == '<') { method = instance; c = resolveClass (t, root(t, Machine::BootLoader), "java/lang/reflect/Constructor"); object instance = makeNew(t, c); object constructor = resolveMethod (t, c, "", "(Ljava/lang/Method;)V"); t->m->processor->invoke(t, constructor, instance, method); } return reinterpret_cast(instance); } ReadyTalk-avian-1e1fff5/src/classpath-openjdk.cpp000066400000000000000000004335551231440243200221040ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/machine.h" #include "avian/classpath-common.h" #include "avian/util.h" #include "avian/process.h" #ifdef PLATFORM_WINDOWS # include # include # include # include # include # include # include # include # undef interface # define CLOSE _close # define READ _read # define WRITE _write # define FSTAT _fstat # define STAT _stat # define LSEEK _lseek # define S_ISSOCK(x) false # ifdef _MSC_VER # define S_ISREG(x) ((x) | _S_IFREG) # define S_ISDIR(x) ((x) | _S_IFDIR) # define S_IRUSR _S_IREAD # define S_IWUSR _S_IWRITE # else # define OPEN _open # endif # define O_RDONLY _O_RDONLY # if (defined AVIAN_OPENJDK_SRC) \ || ((defined __x86_64__) && (defined __MINGW32__)) # define EXPORT(x) x # else # define EXPORT(x) _##x # endif typedef int socklen_t; # define RTLD_DEFAULT 0 #else // not PLATFORM_WINDOWS # include # include # include # include # include # include # include # include # include # include # define OPEN open # define CLOSE close # define READ read # define WRITE write # define STAT stat # define FSTAT fstat # define LSEEK lseek # define EXPORT(x) x #endif // not PLATFORM_WINDOWS #define JVM_EEXIST -100 using namespace vm; namespace { #ifdef _MSC_VER inline int OPEN(string_t path, int mask, int mode) { int fd; if (_wsopen_s(&fd, path, mask, _SH_DENYNO, mode) == 0) { return fd; } else { return -1; } } #endif namespace local { const int JMM_VERSION_1_0 = 0x20010000; struct jmmOptionalSupport { unsigned isLowMemoryDetectionSupported : 1; unsigned isCompilationTimeMonitoringSupported : 1; unsigned isThreadContentionMonitoringSupported : 1; unsigned isCurrentThreadCpuTimeSupported : 1; unsigned isOtherThreadCpuTimeSupported : 1; unsigned isBootClassPathSupported : 1; unsigned isObjectMonitorUsageSupported : 1; unsigned isSynchronizerUsageSupported : 1; }; typedef unsigned jmmLongAttribute; typedef unsigned jmmBoolAttribute; typedef unsigned jmmStatisticType; typedef unsigned jmmThresholdType; typedef unsigned jmmVMGlobalType; typedef unsigned jmmVMGlobalOrigin; struct jmmVMGlobal { jstring name; jvalue value; jmmVMGlobalType type; jmmVMGlobalOrigin origin; unsigned writeable : 1; unsigned external : 1; unsigned reserved : 30; void* reserved1; void* reserved2; }; struct jmmExtAttributeInfo { const char* name; char type; const char* description; }; struct jmmGCStat { jlong gc_index; jlong start_time; jlong end_time; jobjectArray usage_before_gc; jobjectArray usage_after_gc; jint gc_ext_attribute_values_size; jvalue* gc_ext_attribute_values; jint num_gc_ext_attributes; }; struct JmmInterface { void* reserved1; void* reserved2; jint (JNICALL *GetVersion) (JNIEnv*); jint (JNICALL *GetOptionalSupport) (JNIEnv*, jmmOptionalSupport*); jobject (JNICALL *GetInputArguments) (JNIEnv*); jint (JNICALL *GetThreadInfo) (JNIEnv*, jlongArray, jint, jobjectArray); jobjectArray (JNICALL *GetInputArgumentArray) (JNIEnv*); jobjectArray (JNICALL *GetMemoryPools) (JNIEnv*, jobject); jobjectArray (JNICALL *GetMemoryManagers) (JNIEnv*, jobject); jobject (JNICALL *GetMemoryPoolUsage) (JNIEnv*, jobject); jobject (JNICALL *GetPeakMemoryPoolUsage) (JNIEnv*, jobject); void* reserved4; jobject (JNICALL *GetMemoryUsage) (JNIEnv*, jboolean); jlong (JNICALL *GetLongAttribute) (JNIEnv*, jobject, jmmLongAttribute); jboolean (JNICALL *GetBoolAttribute) (JNIEnv*, jmmBoolAttribute); jboolean (JNICALL *SetBoolAttribute) (JNIEnv*, jmmBoolAttribute, jboolean); jint (JNICALL *GetLongAttributes) (JNIEnv*, jobject, jmmLongAttribute*, jint, jlong*); jobjectArray (JNICALL *FindCircularBlockedThreads) (JNIEnv*); jlong (JNICALL *GetThreadCpuTime) (JNIEnv*, jlong); jobjectArray (JNICALL *GetVMGlobalNames) (JNIEnv*); jint (JNICALL *GetVMGlobals) (JNIEnv*, jobjectArray, jmmVMGlobal*, jint); jint (JNICALL *GetInternalThreadTimes) (JNIEnv*, jobjectArray, jlongArray); jboolean (JNICALL *ResetStatistic) (JNIEnv*, jvalue, jmmStatisticType); void (JNICALL *SetPoolSensor) (JNIEnv*, jobject, jmmThresholdType, jobject); jlong (JNICALL *SetPoolThreshold) (JNIEnv*, jobject, jmmThresholdType, jlong); jobject (JNICALL *GetPoolCollectionUsage) (JNIEnv*, jobject); jint (JNICALL *GetGCExtAttributeInfo) (JNIEnv*, jobject, jmmExtAttributeInfo*, jint); void (JNICALL *GetLastGCStat) (JNIEnv*, jobject, jmmGCStat*); jlong (JNICALL *GetThreadCpuTimeWithKind) (JNIEnv*, jlong, jboolean); void* reserved5; jint (JNICALL *DumpHeap0) (JNIEnv*, jstring, jboolean); jobjectArray (JNICALL *FindDeadlocks) (JNIEnv*, jboolean); void (JNICALL *SetVMGlobal) (JNIEnv*, jstring, jvalue ); void* reserved6; jobjectArray (JNICALL *DumpThreads) (JNIEnv*, jlongArray, jboolean, jboolean); }; const unsigned InterfaceVersion = 4; const unsigned PageSize = 4 * 1024; #ifdef AVIAN_OPENJDK_SRC const int VirtualFileBase = 1000000000; #endif Machine* globalMachine; const char* primitiveName(Thread* t, object c) { if (c == primitiveClass(t, 'V')) { return "void"; } else if (c == primitiveClass(t, 'Z')) { return "boolean"; } else if (c == primitiveClass(t, 'B')) { return "byte"; } else if (c == primitiveClass(t, 'C')) { return "char"; } else if (c == primitiveClass(t, 'S')) { return "short"; } else if (c == primitiveClass(t, 'I')) { return "int"; } else if (c == primitiveClass(t, 'F')) { return "float"; } else if (c == primitiveClass(t, 'J')) { return "long"; } else if (c == primitiveClass(t, 'D')) { return "double"; } else { abort(t); } } object getClassName(Thread* t, object c) { if (className(t, c) == 0) { if (classVmFlags(t, c) & PrimitiveFlag) { PROTECT(t, c); object name = makeByteArray(t, primitiveName(t, c)); set(t, c, ClassName, name); } else { abort(t); } } return className(t, c); } object makeClassNameString(Thread* t, object name) { THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, name)); replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast(&byteArrayBody(t, name, 0))); return makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); } object makeJmethod(Thread* t, object vmMethod, int index = -1); object makeJconstructor(Thread* t, object vmMethod, int index = -1); object makeJfield(Thread* t, object vmField, int index = -1); #ifdef AVIAN_OPENJDK_SRC void interceptFileOperations(Thread*, bool); #endif class MyClasspath : public Classpath { public: MyClasspath(System* s, Allocator* allocator, const char* javaHome, const char* embedPrefix): allocator(allocator), ranNetOnLoad(0), ranManagementOnLoad(0) { class StringBuilder { public: StringBuilder(System* s, Allocator* allocator): s(s), allocator(allocator), bufferSize(1024), buffer(static_cast(allocator->allocate(bufferSize))), offset(0) { } void ensure(unsigned capacity) { if (capacity > bufferSize) { unsigned size = max(bufferSize * 2, capacity); char* b = static_cast(allocator->allocate(size)); if (offset) { memcpy(b, buffer, offset); } allocator->free(buffer, bufferSize); buffer = b; bufferSize = size; } } void append(const char* append) { unsigned length = strlen(append); ensure(offset + length + 1); strncpy(buffer + offset, append, length + 1); offset += length; } void append(char c) { ensure(2); buffer[offset] = c; buffer[offset + 1] = 0; ++ offset; } System* s; Allocator* allocator; unsigned bufferSize; char* buffer; unsigned offset; } sb(s, allocator); unsigned javaHomeOffset = sb.offset; sb.append(javaHome); sb.append('\0'); unsigned classpathOffset = sb.offset; sb.append(AVIAN_CLASSPATH); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/rt.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/jsse.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/jce.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/ext/sunjce_provider.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/resources.jar"); sb.append('\0'); unsigned libraryPathOffset = sb.offset; sb.append(javaHome); #ifdef PLATFORM_WINDOWS # define LIB_DIR "/bin" #elif defined __APPLE__ # define LIB_DIR "/lib" #elif defined ARCH_x86_64 # define LIB_DIR "/lib/amd64" #elif defined ARCH_arm # define LIB_DIR "/lib/arm" #else // todo: handle other architectures # define LIB_DIR "/lib/i386" #endif #ifdef PLATFORM_WINDOWS sb.append(LIB_DIR); #else sb.append(LIB_DIR ":"); sb.append(javaHome); sb.append(LIB_DIR "/xawt"); #endif sb.append('\0'); unsigned tzMappingsOffset = sb.offset; sb.append(javaHome); sb.append("/lib/tzmappings"); this->tzMappingsLength = sb.offset - tzMappingsOffset; sb.append('\0'); unsigned embedPrefixOffset = sb.offset; sb.append(embedPrefix); this->embedPrefixLength = sb.offset - embedPrefixOffset; this->javaHome = sb.buffer + javaHomeOffset; this->classpath = sb.buffer + classpathOffset; this->libraryPath = sb.buffer + libraryPathOffset; this->tzMappings = sb.buffer + tzMappingsOffset; this->embedPrefix = sb.buffer + embedPrefixOffset; this->buffer = sb.buffer; this->bufferSize = sb.bufferSize; } virtual object makeJclass(Thread* t, object class_) { PROTECT(t, class_); object name = makeClassNameString(t, getClassName(t, class_)); PROTECT(t, name); object c = allocate(t, FixedSizeOfJclass, true); setObjectClass(t, c, type(t, Machine::JclassType)); set(t, c, JclassName, name); set(t, c, JclassVmClass, class_); return c; } virtual object makeString(Thread* t, object array, int32_t offset, int32_t length) { if (objectClass(t, array) == type(t, Machine::ByteArrayType)) { PROTECT(t, array); object charArray = makeCharArray(t, length); for (int i = 0; i < length; ++i) { if (byteArrayBody(t, array, offset + i) & 0x80) { object constructor = resolveMethod (t, type(t, Machine::StringType), "", "([BIILjava/lang/String;)V"); PROTECT(t, constructor); object utf8 = vm::makeString(t, "UTF8"); PROTECT(t, utf8); object s = makeNew(t, type(t, Machine::StringType)); PROTECT(t, s); t->m->processor->invoke (t, constructor, s, array, offset, length, utf8); return s; } charArrayBody(t, charArray, i) = byteArrayBody(t, array, offset + i); } array = charArray; } else { expect(t, objectClass(t, array) == type(t, Machine::CharArrayType)); } return vm::makeString(t, array, offset, length, 0); } virtual object makeThread(Thread* t, Thread* parent) { const unsigned MaxPriority = 10; const unsigned NormalPriority = 5; object group; if (parent) { group = threadGroup(t, parent->javaThread); } else { group = allocate(t, FixedSizeOfThreadGroup, true); setObjectClass(t, group, type(t, Machine::ThreadGroupType)); threadGroupMaxPriority(t, group) = MaxPriority; } PROTECT(t, group); object thread = allocate(t, FixedSizeOfThread, true); setObjectClass(t, thread, type(t, Machine::ThreadType)); threadPriority(t, thread) = NormalPriority; threadGroup(t, thread) = group; threadContextClassLoader(t, thread) = root(t, Machine::AppLoader); PROTECT(t, thread); object blockerLock = makeJobject(t); set(t, thread, ThreadBlockerLock, blockerLock); const unsigned BufferSize = 256; char buffer[BufferSize]; unsigned length = vm::snprintf(buffer, BufferSize, "Thread-%p", thread); object name = makeCharArray(t, length); for (unsigned i = 0; i < length; ++i) { charArrayBody(t, name, i) = buffer[i]; } set(t, thread, ThreadName, name); return thread; } virtual object makeJMethod(Thread* t, object vmMethod) { PROTECT(t, vmMethod); return byteArrayBody(t, methodName(t, vmMethod), 0) == '<' ? makeJconstructor(t, vmMethod) : makeJmethod(t, vmMethod); } virtual object getVMMethod(Thread* t, object jmethod) { return objectClass(t, jmethod) == type(t, Machine::JmethodType) ? arrayBody (t, classMethodTable (t, jclassVmClass(t, jmethodClazz(t, jmethod))), jmethodSlot(t, jmethod)) : arrayBody (t, classMethodTable (t, jclassVmClass(t, jconstructorClazz(t, jmethod))), jconstructorSlot(t, jmethod)); } virtual object makeJField(Thread* t, object vmField) { return makeJfield(t, vmField); } virtual object getVMField(Thread* t, object jfield) { return arrayBody (t, classFieldTable (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield)); } virtual void clearInterrupted(Thread* t) { vm::clearInterrupted(t); } virtual void runThread(Thread* t) { // force monitor creation so we don't get an OutOfMemory error // later when we try to acquire it: objectMonitor(t, t->javaThread, true); THREAD_RESOURCE0(t, { vm::acquire(t, t->javaThread); t->flags &= ~Thread::ActiveFlag; vm::notifyAll(t, t->javaThread); vm::release(t, t->javaThread); object e = t->exception; PROTECT(t, e); t->exception = 0; t->m->processor->invoke (t, root(t, Machine::ThreadTerminated), threadGroup(t, t->javaThread), t->javaThread); t->exception = e; }); object method = resolveMethod (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", "()V"); t->m->processor->invoke(t, method, t->javaThread); } virtual void resolveNative(Thread* t, object method) { if (strcmp(reinterpret_cast("sun/font/SunFontManager"), &byteArrayBody(t, className(t, methodClass(t, method)), 0)) == 0 and strcmp(reinterpret_cast("initIDs"), &byteArrayBody(t, methodName(t, method), 0)) == 0 and strcmp(reinterpret_cast("()V"), &byteArrayBody(t, methodSpec(t, method), 0)) == 0) { PROTECT(t, method); expect(t, loadLibrary(t, libraryPath, "fontmanager", true, true)); } vm::resolveNative(t, method); } virtual void interceptMethods(Thread* t UNUSED) { #ifdef AVIAN_OPENJDK_SRC interceptFileOperations(t, false); #endif } virtual void preBoot(Thread*) { // ignore } virtual void boot(Thread* t) { globalMachine = t->m; resolveSystemClass(t, root(t, Machine::BootLoader), className(t, type(t, Machine::ClassLoaderType))); setRoot(t, Machine::ThreadTerminated, resolveMethod (t, root(t, Machine::BootLoader), "java/lang/ThreadGroup", "threadTerminated", "(Ljava/lang/Thread;)V")); #ifdef AVIAN_OPENJDK_SRC interceptFileOperations(t, true); #else // not AVIAN_OPENJDK_SRC expect(t, loadLibrary(t, libraryPath, "verify", true, true)); expect(t, loadLibrary(t, libraryPath, "java", true, true)); #endif // not AVIAN_OPENJDK_SRC { object assertionLock = resolveField (t, type(t, Machine::ClassLoaderType), "assertionLock", "Ljava/lang/Object;"); set(t, root(t, Machine::BootLoader), fieldOffset(t, assertionLock), root(t, Machine::BootLoader)); } { object class_ = resolveClass (t, root(t, Machine::BootLoader), "java/util/Properties", true, Machine::NoClassDefFoundErrorType); PROTECT(t, class_); object instance = makeNew(t, class_); PROTECT(t, instance); object constructor = resolveMethod(t, class_, "", "()V"); t->m->processor->invoke(t, constructor, instance); t->m->processor->invoke (t, root(t, Machine::BootLoader), "java/lang/System", "setProperties", "(Ljava/util/Properties;)V", 0, instance); } { object constructor = resolveMethod (t, type(t, Machine::ClassLoaderType), "", "(Ljava/lang/ClassLoader;)V"); PROTECT(t, constructor); t->m->processor->invoke(t, constructor, root(t, Machine::BootLoader), 0); t->m->processor->invoke (t, constructor, root(t, Machine::AppLoader), root(t, Machine::BootLoader)); } { object scl = resolveField (t, type(t, Machine::ClassLoaderType), "scl", "Ljava/lang/ClassLoader;"); PROTECT(t, scl); object sclSet = resolveField (t, type(t, Machine::ClassLoaderType), "sclSet", "Z"); set(t, classStaticTable(t, type(t, Machine::ClassLoaderType)), fieldOffset(t, scl), root(t, Machine::AppLoader)); fieldAtOffset(classStaticTable(t, type(t, Machine::ClassLoaderType)), fieldOffset(t, sclSet)) = true; } t->m->processor->invoke (t, root(t, Machine::BootLoader), "java/lang/System", "initializeSystemClass", "()V", 0); t->m->processor->invoke (t, root(t, Machine::BootLoader), "sun/misc/Launcher", "getLauncher", "()Lsun/misc/Launcher;", 0); set(t, t->javaThread, ThreadContextClassLoader, root(t, Machine::AppLoader)); } virtual const char* bootClasspath() { return classpath; } virtual object makeDirectByteBuffer(Thread* t, void* p, jlong capacity) { object c = resolveClass (t, root(t, Machine::BootLoader), "java/nio/DirectByteBuffer"); PROTECT(t, c); object instance = makeNew(t, c); PROTECT(t, instance); object constructor = resolveMethod(t, c, "", "(JI)V"); t->m->processor->invoke (t, constructor, instance, reinterpret_cast(p), static_cast(capacity)); return instance; } virtual void* getDirectBufferAddress(Thread* t, object b) { PROTECT(t, b); object field = resolveField(t, objectClass(t, b), "address", "J"); return reinterpret_cast (fieldAtOffset(b, fieldOffset(t, field))); } virtual int64_t getDirectBufferCapacity(Thread* t, object b) { PROTECT(t, b); object field = resolveField (t, objectClass(t, b), "capacity", "I"); return fieldAtOffset(b, fieldOffset(t, field)); } virtual bool canTailCall(Thread* t, object, object calleeClassName, object calleeMethodName, object) { // we can't tail call System.loadLibrary or Runtime.loadLibrary // due to their use of System.getCallerClass, which gets confused // if we elide stack frames. return (strcmp("loadLibrary", reinterpret_cast (&byteArrayBody(t, calleeMethodName, 0))) or (strcmp("java/lang/System", reinterpret_cast (&byteArrayBody(t, calleeClassName, 0))) and strcmp("java/lang/Runtime", reinterpret_cast (&byteArrayBody(t, calleeClassName, 0))))) // and we can't tail call Reflection.getCallerClass because the // number of stack frames will be wrong and (strcmp("getCallerClass", reinterpret_cast (&byteArrayBody(t, calleeMethodName, 0))) or strcmp("sun/reflect/Reflection", reinterpret_cast (&byteArrayBody(t, calleeClassName, 0)))); } virtual void shutDown(Thread* t) { object c = resolveClass (t, root(t, Machine::BootLoader), "java/lang/Shutdown", false); if (c) { object m = findMethodOrNull(t, c, "shutdown", "()V"); if (m) { t->m->processor->invoke(t, m, 0); } } } virtual void dispose() { allocator->free(buffer, bufferSize); allocator->free(this, sizeof(*this)); } Allocator* allocator; const char* javaHome; const char* classpath; const char* libraryPath; const char* tzMappings; const char* embedPrefix; char* buffer; unsigned bufferSize; unsigned tzMappingsLength; unsigned embedPrefixLength; unsigned filePathField; unsigned fileDescriptorFdField; unsigned fileInputStreamFdField; unsigned zipFileJzfileField; unsigned zipEntryNameField; unsigned zipEntryTimeField; unsigned zipEntryCrcField; unsigned zipEntrySizeField; unsigned zipEntryCsizeField; unsigned zipEntryMethodField; bool ranNetOnLoad; bool ranManagementOnLoad; JmmInterface jmmInterface; }; struct JVM_ExceptionTableEntryType { jint start_pc; jint end_pc; jint handler_pc; jint catchType; }; struct jvm_version_info { unsigned jvm_version; unsigned update_version: 8; unsigned special_update_version: 8; unsigned reserved1: 16; unsigned reserved2; unsigned is_attach_supported: 1; unsigned is_kernel_jvm: 1; unsigned: 30; unsigned: 32; unsigned: 32; }; bool pathEqual(const char* a, const char* b, unsigned length) { #ifdef PLATFORM_WINDOWS return strncasecmp(a, b, length) == 0; #else return strncmp(a, b, length) == 0; #endif } class EmbeddedFile { public: EmbeddedFile(MyClasspath* cp, const char* path, unsigned pathLength) { if (pathEqual(cp->embedPrefix, path, cp->embedPrefixLength)) { const char* p = path + cp->embedPrefixLength; while (*p == '/') ++ p; this->jar = p; if (*p == 0) { this->jarLength = 0; this->path = 0; this->pathLength = 0; return; } while (*p and *p != '/') ++p; this->jarLength = p - this->jar; while (*p == '/') ++p; this->path = p; this->pathLength = pathLength - (p - path); } else { this->jar = 0; this->jarLength =0; this->path = 0; this->pathLength = 0; } } const char* jar; const char* path; unsigned jarLength; unsigned pathLength; }; #ifdef AVIAN_OPENJDK_SRC int64_t JNICALL getFileAttributes (Thread* t, object method, uintptr_t* arguments) { const unsigned Exists = 1; const unsigned Regular = 2; const unsigned Directory = 4; MyClasspath* cp = static_cast(t->m->classpath); object file = reinterpret_cast(arguments[1]); object path = fieldAtOffset(file, cp->filePathField); THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0) { return Exists | Directory; } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder) { if (ef.pathLength == 0) { return Exists | Directory; } unsigned length; System::FileType type = finder->stat(ef.path, &length, true); switch (type) { case System::TypeUnknown: return Exists; case System::TypeDoesNotExist: return 0; case System::TypeFile: return Exists | Regular; case System::TypeDirectory: return Exists | Directory; default: abort(t); } } else { return 0; } } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), reinterpret_cast(arguments[0]), file)); } } int64_t JNICALL checkFileAccess (Thread* t, object method, uintptr_t* arguments) { const unsigned Read = 4; MyClasspath* cp = static_cast(t->m->classpath); object file = reinterpret_cast(arguments[1]); unsigned mask = arguments[2]; object path = fieldAtOffset(file, cp->filePathField); THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0) { return mask == Read; } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder) { if (ef.pathLength == 0) { return mask == Read; } unsigned length; System::FileType type = finder->stat(ef.path, &length, true); switch (type) { case System::TypeDoesNotExist: return false; case System::TypeUnknown: case System::TypeFile: case System::TypeDirectory: return mask == Read; default: abort(t); } } else { return 0; } } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), reinterpret_cast(arguments[0]), file, mask)) != 0; } } int64_t JNICALL getFileLength (Thread* t, object method, uintptr_t* arguments) { MyClasspath* cp = static_cast(t->m->classpath); object file = reinterpret_cast(arguments[1]); object path = fieldAtOffset(file, cp->filePathField); THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0) { return 0; } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder) { if (ef.pathLength == 0) { return 0; } unsigned fileLength; finder->stat(ef.path, &fileLength); return fileLength; } return 0; } else { return longValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), reinterpret_cast(arguments[0]), file)); } } void JNICALL openFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); object path = reinterpret_cast(arguments[1]); MyClasspath* cp = static_cast(t->m->classpath); THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0 or ef.pathLength == 0) { throwNew(t, Machine::FileNotFoundExceptionType); } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder == 0) { throwNew(t, Machine::FileNotFoundExceptionType); } System::Region* r = finder->find(ef.path); if (r == 0) { throwNew(t, Machine::FileNotFoundExceptionType); } PROTECT(t, this_); ACQUIRE(t, t->m->referenceLock); int index = -1; unsigned oldLength = root(t, Machine::VirtualFiles) ? arrayLength(t, root(t, Machine::VirtualFiles)) : 0; for (unsigned i = 0; i < oldLength; ++i) { if (arrayBody(t, root(t, Machine::VirtualFiles), i) == 0) { index = i; break; } } if (index == -1) { object newArray = growArray(t, root(t, Machine::VirtualFiles)); setRoot(t, Machine::VirtualFiles, newArray); index = oldLength; } object region = makeRegion(t, r, 0); set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), region); fieldAtOffset (fieldAtOffset (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField) = index + VirtualFileBase; } else { t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_, path); } } int64_t JNICALL readByteFromFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); MyClasspath* cp = static_cast(t->m->classpath); int fd = fieldAtOffset (fieldAtOffset (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); if (region) { System::Region* r = static_cast (regionRegion(t, region)); if (r->length() > regionPosition(t, region)) { return r->start()[regionPosition(t, region)++]; } else { return -1; } } else { throwNew(t, Machine::IoExceptionType); } } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_)); } } int64_t JNICALL readBytesFromFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); object dst = reinterpret_cast(arguments[1]); int32_t offset = arguments[2]; int32_t length = arguments[3]; MyClasspath* cp = static_cast(t->m->classpath); int fd = fieldAtOffset (fieldAtOffset (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { PROTECT(t, dst); ACQUIRE(t, t->m->referenceLock); object region = arrayBody (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); if (region) { System::Region* r = static_cast (regionRegion(t, region)); int available = r->length() - regionPosition(t, region); if (available == 0) { return -1; } if (length > available) { length = available; } memcpy(&byteArrayBody(t, dst, offset), r->start() + regionPosition(t, region), length); regionPosition(t, region) += length; return length; } else { throwNew(t, Machine::IoExceptionType); } } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_, dst, offset, length)); } } int64_t JNICALL skipBytesInFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); int64_t count; memcpy(&count, arguments + 1, 8); MyClasspath* cp = static_cast(t->m->classpath); int fd = fieldAtOffset (fieldAtOffset (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); if (region) { System::Region* r = static_cast (regionRegion(t, region)); int available = r->length() - regionPosition(t, region); if (count > available) { count = available; } regionPosition(t, region) += count; return count; } else { throwNew(t, Machine::IoExceptionType); } } else { return longValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_, count)); } } int64_t JNICALL availableBytesInFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); MyClasspath* cp = static_cast(t->m->classpath); int fd = fieldAtOffset (fieldAtOffset (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); if (region) { return static_cast(regionRegion(t, region))->length() - regionPosition(t, region); } else { throwNew(t, Machine::IoExceptionType); } } else { object r = t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_); return r ? intValue(t, r) : 0; } } void JNICALL closeFile(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); MyClasspath* cp = static_cast(t->m->classpath); int fd = fieldAtOffset (fieldAtOffset (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); int index = fd - VirtualFileBase; object region = arrayBody(t, root(t, Machine::VirtualFiles), index); if (region) { static_cast(regionRegion(t, region))->dispose(); } set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), 0); } else { t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), this_); } } class ZipFile { public: class Entry { public: Entry(unsigned hash, const uint8_t* start, Entry* next): hash(hash), start(start), next(next), entry(0) { } Entry(int64_t entry): hash(0), start(0), next(0), entry(entry) { } Entry(): hash(0), start(0), next(0), entry(0) { } unsigned hash; const uint8_t* start; Entry* next; int64_t entry; }; ZipFile(Thread* t, System::Region* region, unsigned entryCount): region(region), entryCount(entryCount), indexSize(nextPowerOfTwo(entryCount)), index(reinterpret_cast (t->m->heap->allocate(sizeof(ZipFile::Entry*) * indexSize))), file(0) { memset(index, 0, sizeof(ZipFile::Entry*) * indexSize); } ZipFile(int64_t file): region(0), entryCount(0), indexSize(0), index(0), file(file) { } System::Region* region; unsigned entryCount; unsigned indexSize; Entry** index; int64_t file; Entry entries[0]; }; int64_t JNICALL openZipFile(Thread* t, object method, uintptr_t* arguments) { object path = reinterpret_cast(arguments[0]); int mode = arguments[1]; int64_t lastModified; memcpy(&lastModified, arguments + 2, 8); MyClasspath* cp = static_cast(t->m->classpath); THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0 or ef.pathLength == 0) { throwNew(t, Machine::FileNotFoundExceptionType); } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder == 0) { throwNew(t, Machine::FileNotFoundExceptionType); } System::Region* r = finder->find(ef.path); if (r == 0) { throwNew(t, Machine::FileNotFoundExceptionType); } const uint8_t* start = r->start(); const uint8_t* end = start + r->length(); unsigned entryCount = 0; for (const uint8_t* p = end - CentralDirectorySearchStart; p > start;) { if (get4(p) == CentralDirectorySignature) { p = start + centralDirectoryOffset(p); while (p < end) { if (get4(p) == EntrySignature) { ++ entryCount; p = endOfEntry(p); } else { goto make; } } } else { -- p; } } make: ZipFile* file = new (t->m->heap->allocate (sizeof(ZipFile) + (sizeof(ZipFile::Entry) * entryCount))) ZipFile(t, r, entryCount); { unsigned position = 0; for (const uint8_t* p = end - CentralDirectorySearchStart; p > start;) { if (get4(p) == CentralDirectorySignature) { p = start + centralDirectoryOffset(p); while (p < end) { if (get4(p) == EntrySignature) { unsigned h = hash(fileName(p), fileNameLength(p)); unsigned i = h & (file->indexSize - 1); file->index[i] = new (file->entries + (position++)) ZipFile::Entry(h, p, file->index[i]); p = endOfEntry(p); } else { goto exit; } } } else { -- p; } } } exit: return reinterpret_cast(file); } else { return reinterpret_cast (new (t->m->heap->allocate(sizeof(ZipFile))) ZipFile (longValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, path, mode, lastModified)))); } } int64_t JNICALL getZipFileEntryCount(Thread* t, object method, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); ZipFile* file = reinterpret_cast(peer); if (file->region) { return file->entryCount; } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, file->file)); } } ZipFile::Entry* find(ZipFile* file, const char* path, unsigned pathLength) { unsigned i = hash(path) & (file->indexSize - 1); for (ZipFile::Entry* e = file->index[i]; e; e = e->next) { const uint8_t* p = e->start; if (equal(path, pathLength, fileName(p), fileNameLength(p))) { return e; } } return 0; } int64_t JNICALL getZipFileEntry(Thread* t, object method, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); object path = reinterpret_cast(arguments[2]); bool addSlash = arguments[3]; ZipFile* file = reinterpret_cast(peer); if (file->region) { THREAD_RUNTIME_ARRAY(t, char, p, byteArrayLength(t, path) + 2); memcpy(RUNTIME_ARRAY_BODY(p), &byteArrayBody(t, path, 0), byteArrayLength(t, path)); RUNTIME_ARRAY_BODY(p)[byteArrayLength(t, path)] = 0; replace('\\', '/', RUNTIME_ARRAY_BODY(p)); if (addSlash) { RUNTIME_ARRAY_BODY(p)[byteArrayLength(t, path)] = '/'; RUNTIME_ARRAY_BODY(p)[byteArrayLength(t, path) + 1] = 0; } return reinterpret_cast (find(file, RUNTIME_ARRAY_BODY(p), byteArrayLength(t, path))); } else { int64_t entry = longValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, file->file, path, addSlash)); return entry ? reinterpret_cast (new (t->m->heap->allocate(sizeof(ZipFile::Entry))) ZipFile::Entry(entry)) : 0; } } int64_t JNICALL getZipFileEntryBytes(Thread* t, object method, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); int type = arguments[2]; ZipFile::Entry* entry = reinterpret_cast(peer); if (entry->start) { switch (type) { case 0: { // name unsigned nameLength = fileNameLength(entry->start); object array = makeByteArray(t, nameLength + 1); memcpy(&byteArrayBody(t, array, 0), fileName(entry->start), nameLength); byteArrayBody(t, array, nameLength) = 0; return reinterpret_cast(array); } break; case 1: { // extra return 0; } break; case 2: { // comment return 0; } break; default: abort(t); } return compressedSize(entry->start); } else { return reinterpret_cast (t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, entry->entry, type)); } } int64_t JNICALL getNextZipFileEntry(Thread* t, object method, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); int index = arguments[2]; ZipFile* file = reinterpret_cast(peer); if (file->region) { return reinterpret_cast(file->entries + index); } else { int64_t entry = longValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, file->file, index)); return entry ? reinterpret_cast (new (t->m->heap->allocate(sizeof(ZipFile::Entry))) ZipFile::Entry(entry)) : 0; } } int64_t JNICALL getZipFileEntryMethod(Thread* t, object method, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); ZipFile::Entry* entry = reinterpret_cast(peer); if (entry->start) { return compressionMethod(entry->start); } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, entry->entry)); } } int64_t JNICALL getZipFileEntryCompressedSize(Thread* t, object method, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); ZipFile::Entry* entry = reinterpret_cast(peer); if (entry->start) { return compressedSize(entry->start); } else { return longValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, entry->entry)); } } int64_t JNICALL getZipFileEntryUncompressedSize(Thread* t, object method, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); ZipFile::Entry* entry = reinterpret_cast(peer); if (entry->start) { return uncompressedSize(entry->start); } else { return longValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, entry->entry)); } } void JNICALL freeZipFileEntry(Thread* t, object method, uintptr_t* arguments) { int64_t filePeer; memcpy(&filePeer, arguments, 8); int64_t entryPeer; memcpy(&entryPeer, arguments + 2, 8); ZipFile* file = reinterpret_cast(filePeer); ZipFile::Entry* entry = reinterpret_cast(entryPeer); if (file->region == 0) { t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, file->file, entry->entry); } t->m->heap->free(entry, sizeof(ZipFile::Entry)); } int64_t JNICALL readZipFileEntry(Thread* t, object method, uintptr_t* arguments) { int64_t filePeer; memcpy(&filePeer, arguments, 8); int64_t entryPeer; memcpy(&entryPeer, arguments + 2, 8); int64_t position; memcpy(&position, arguments + 4, 8); object buffer = reinterpret_cast(arguments[6]); int offset = arguments[7]; int length = arguments[8]; ZipFile* file = reinterpret_cast(filePeer); ZipFile::Entry* entry = reinterpret_cast(entryPeer); if (file->region) { unsigned size = uncompressedSize(entry->start); if (position >= size) { return -1; } if (position + length > size) { length = size - position; } memcpy(&byteArrayBody(t, buffer, offset), fileData(file->region->start() + localHeaderOffset(entry->start)) + position, length); return length; } else { return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, file->file, entry->entry, position, buffer, offset, length)); } } int64_t JNICALL getZipMessage(Thread* t, object method, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); ZipFile* file = reinterpret_cast(peer); if (file->region) { return 0; } else { return reinterpret_cast (t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, file->file)); } } int64_t JNICALL getJarFileMetaInfEntryNames(Thread* t, object method, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); MyClasspath* cp = static_cast(t->m->classpath); int64_t peer = fieldAtOffset(this_, cp->zipFileJzfileField); ZipFile* file = reinterpret_cast(peer); if (file->region) { return 0; } else { PROTECT(t, method); // OpenJDK's Java_java_util_jar_JarFile_getMetaInfEntryNames // implementation expects to find a pointer to an instance of its // jzfile structure in the ZipFile.jzfile field of the object we // pass in. However, we can't pass this_ in, because its // ZipFile.jzfile field points to a ZipFile instance, not a // jzfile. So we pass in a temporary object instead which has the // desired pointer at the same offset. We assume here that // ZipFile.jzfile is the first field in that class and that // Java_java_util_jar_JarFile_getMetaInfEntryNames will not look // for any other fields in the object. object pseudoThis = makeLong(t, file->file); return reinterpret_cast (t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), pseudoThis)); } } void JNICALL closeZipFile(Thread* t, object method, uintptr_t* arguments) { int64_t peer; memcpy(&peer, arguments, 8); ZipFile* file = reinterpret_cast(peer); if (file->region) { file->region->dispose(); t->m->heap->free(file, sizeof(ZipFile) + (sizeof(ZipFile::Entry) * file->entryCount)); } else { t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), 0, file->file); t->m->heap->free(file, sizeof(ZipFile)); } } int64_t JNICALL getBootstrapResource(Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[0]); PROTECT(t, name); object m = findMethodOrNull (t, type(t, Machine::SystemClassLoaderType), "findResource", "(Ljava/lang/String;)Ljava/net/URL;"); if (m) { return reinterpret_cast (t->m->processor->invoke(t, m, root(t, Machine::BootLoader), name)); } else { return 0; } } int64_t JNICALL getBootstrapResources(Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[0]); PROTECT(t, name); object m = findMethodOrNull (t, type(t, Machine::SystemClassLoaderType), "findResources", "(Ljava/lang/String;)Ljava/util/Enumeration;"); if (m) { return reinterpret_cast (t->m->processor->invoke(t, m, root(t, Machine::BootLoader), name)); } else { return 0; } } extern "C" AVIAN_EXPORT jint JNICALL net_JNI_OnLoad(JavaVM*, void*); extern "C" AVIAN_EXPORT jint JNICALL management_JNI_OnLoad(JavaVM*, void*); void JNICALL loadLibrary(Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[1]); THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); bool absolute = arguments[2]; if (not absolute) { if (strcmp(RUNTIME_ARRAY_BODY(n), "net") == 0) { bool ran; { ACQUIRE(t, t->m->classLock); local::MyClasspath* c = static_cast (t->m->classpath); ran = c->ranNetOnLoad; c->ranNetOnLoad = true; } if (not ran) { net_JNI_OnLoad(t->m, 0); } return; } else if (strcmp(RUNTIME_ARRAY_BODY(n), "management") == 0) { bool ran; { ACQUIRE(t, t->m->classLock); local::MyClasspath* c = static_cast (t->m->classpath); ran = c->ranManagementOnLoad; c->ranManagementOnLoad = true; } if (not ran) { management_JNI_OnLoad(t->m, 0); } return; } else if (strcmp(RUNTIME_ARRAY_BODY(n), "zip") == 0 or strcmp(RUNTIME_ARRAY_BODY(n), "nio") == 0) { return; } } loadLibrary (t, static_cast(t->m->classpath)->libraryPath, RUNTIME_ARRAY_BODY(n), not absolute, true); } void interceptFileOperations(Thread* t, bool updateRuntimeData) { MyClasspath* cp = static_cast(t->m->classpath); { object fileClass = resolveClass (t, root(t, Machine::BootLoader), "java/io/File", false); if (fileClass) { object filePathField = findFieldInClass2 (t, fileClass, "path", "Ljava/lang/String;"); if (filePathField) { cp->filePathField = fieldOffset(t, filePathField); } } } { object fileDescriptorClass = resolveClass (t, root(t, Machine::BootLoader), "java/io/FileDescriptor", false); if (fileDescriptorClass) { object fileDescriptorFdField = findFieldInClass2 (t, fileDescriptorClass, "fd", "I"); if (fileDescriptorFdField) { cp->fileDescriptorFdField = fieldOffset(t, fileDescriptorFdField); } } } { object fileInputStreamClass = resolveClass (t, root(t, Machine::BootLoader), "java/io/FileInputStream", false); if (fileInputStreamClass) { PROTECT(t, fileInputStreamClass); object fileInputStreamFdField = findFieldInClass2 (t, fileInputStreamClass, "fd", "Ljava/io/FileDescriptor;"); if (fileInputStreamFdField) { cp->fileInputStreamFdField = fieldOffset(t, fileInputStreamFdField); intercept(t, fileInputStreamClass, "open", "(Ljava/lang/String;)V", voidPointer(openFile), updateRuntimeData); if(findMethodOrNull(t, fileInputStreamClass, "read0", "()I") != 0) { intercept(t, fileInputStreamClass, "read0", "()I", voidPointer(readByteFromFile), updateRuntimeData); } else { intercept(t, fileInputStreamClass, "read", "()I", voidPointer(readByteFromFile), updateRuntimeData); } intercept(t, fileInputStreamClass, "readBytes", "([BII)I", voidPointer(readBytesFromFile), updateRuntimeData); intercept(t, fileInputStreamClass, "skip", "(J)J", voidPointer(skipBytesInFile), updateRuntimeData); intercept(t, fileInputStreamClass, "available", "()I", voidPointer(availableBytesInFile), updateRuntimeData); intercept(t, fileInputStreamClass, "close0", "()V", voidPointer(closeFile), updateRuntimeData); } } } { object zipFileClass = resolveClass (t, root(t, Machine::BootLoader), "java/util/zip/ZipFile", false); if (zipFileClass) { PROTECT(t, zipFileClass); object zipFileJzfileField = findFieldInClass2 (t, zipFileClass, "jzfile", "J"); if (zipFileJzfileField) { cp->zipFileJzfileField = fieldOffset(t, zipFileJzfileField); intercept(t, zipFileClass, "open", "(Ljava/lang/String;IJZ)J", voidPointer(openZipFile), updateRuntimeData); intercept(t, zipFileClass, "getTotal", "(J)I", voidPointer(getZipFileEntryCount), updateRuntimeData); intercept(t, zipFileClass, "getEntry", "(J[BZ)J", voidPointer(getZipFileEntry), updateRuntimeData); intercept(t, zipFileClass, "getEntryBytes", "(JI)[B", voidPointer(getZipFileEntryBytes), updateRuntimeData); intercept(t, zipFileClass, "getNextEntry", "(JI)J", voidPointer(getNextZipFileEntry), updateRuntimeData); intercept(t, zipFileClass, "getEntryMethod", "(J)I", voidPointer(getZipFileEntryMethod), updateRuntimeData); intercept(t, zipFileClass, "freeEntry", "(JJ)V", voidPointer(freeZipFileEntry), updateRuntimeData); intercept(t, zipFileClass, "read", "(JJJ[BII)I", voidPointer(readZipFileEntry), updateRuntimeData); intercept(t, zipFileClass, "getEntryCSize", "(J)J", voidPointer(getZipFileEntryCompressedSize), updateRuntimeData); intercept(t, zipFileClass, "getEntrySize", "(J)J", voidPointer(getZipFileEntryUncompressedSize), updateRuntimeData); intercept(t, zipFileClass, "getZipMessage", "(J)Ljava/lang/String;", voidPointer(getZipMessage), updateRuntimeData); intercept(t, zipFileClass, "close", "(J)V", voidPointer(closeZipFile), updateRuntimeData); } } } { object jarFileClass = resolveClass (t, root(t, Machine::BootLoader), "java/util/jar/JarFile", false); if (jarFileClass) { intercept(t, jarFileClass, "getMetaInfEntryNames", "()[Ljava/lang/String;", voidPointer(getJarFileMetaInfEntryNames), updateRuntimeData); } } { #ifdef PLATFORM_WINDOWS const char* const fsClassName = "java/io/WinNTFileSystem"; const char* const gbaMethodName = "getBooleanAttributes"; #else const char* const fsClassName = "java/io/UnixFileSystem"; const char* const gbaMethodName = "getBooleanAttributes0"; #endif object fsClass = resolveClass (t, root(t, Machine::BootLoader), fsClassName, false); if (fsClass) { PROTECT(t, fsClass); intercept(t, fsClass, gbaMethodName, "(Ljava/io/File;)I", voidPointer(getFileAttributes), updateRuntimeData); intercept(t, fsClass, "checkAccess", "(Ljava/io/File;I)Z", voidPointer(checkFileAccess), updateRuntimeData); intercept(t, fsClass, "getLength", "(Ljava/io/File;)J", voidPointer(getFileLength), updateRuntimeData); } } intercept(t, type(t, Machine::ClassLoaderType), "loadLibrary", "(Ljava/lang/Class;Ljava/lang/String;Z)V", voidPointer(loadLibrary), updateRuntimeData); intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResource", "(Ljava/lang/String;)Ljava/net/URL;", voidPointer(getBootstrapResource), updateRuntimeData); intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResources", "(Ljava/lang/String;)Ljava/util/Enumeration;", voidPointer(getBootstrapResources), updateRuntimeData); } #endif // AVIAN_OPENJDK_SRC unsigned classDeclaredMethodCount(Thread* t, object c) { object addendum = classAddendum(t, c); if (addendum) { int count = classAddendumDeclaredMethodCount(t, addendum); if (count >= 0) { return count; } } object table = classMethodTable(t, c); return table == 0 ? 0 : arrayLength(t, table); } unsigned countMethods(Thread* t, object c, bool publicOnly) { object table = classMethodTable(t, c); unsigned count = 0; for (unsigned i = 0, j = classDeclaredMethodCount(t, c); i < j; ++i) { object vmMethod = arrayBody(t, table, i); if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') { ++ count; } } return count; } unsigned countFields(Thread* t, object c, bool publicOnly) { object table = classFieldTable(t, c); if (publicOnly) { unsigned count = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmField = arrayBody(t, table, i); if (fieldFlags(t, vmField) & ACC_PUBLIC) { ++ count; } } return count; } else { return objectArrayLength(t, table); } } unsigned countConstructors(Thread* t, object c, bool publicOnly) { object table = classMethodTable(t, c); unsigned count = 0; for (unsigned i = 0, j = classDeclaredMethodCount(t, c); i < j; ++i) { object vmMethod = arrayBody(t, table, i); if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) and strcmp(reinterpret_cast (&byteArrayBody(t, methodName(t, vmMethod), 0)), "") == 0) { ++ count; } } return count; } object makeJmethod(Thread* t, object vmMethod, int index) { PROTECT(t, vmMethod); object name = intern (t, t->m->classpath->makeString (t, methodName(t, vmMethod), 0, byteArrayLength (t, methodName(t, vmMethod)) - 1)); PROTECT(t, name); unsigned parameterCount; unsigned returnTypeSpec; object parameterTypes = resolveParameterJTypes (t, classLoader(t, methodClass(t, vmMethod)), methodSpec(t, vmMethod), ¶meterCount, &returnTypeSpec); PROTECT(t, parameterTypes); object returnType = resolveJType (t, classLoader(t, methodClass(t, vmMethod)), reinterpret_cast (&byteArrayBody(t, methodSpec(t, vmMethod), returnTypeSpec)), byteArrayLength(t, methodSpec(t, vmMethod)) - 1 - returnTypeSpec); PROTECT(t, returnType); object exceptionTypes = resolveExceptionJTypes (t, classLoader(t, methodClass(t, vmMethod)), methodAddendum(t, vmMethod)); PROTECT(t, exceptionTypes); object signature; object annotationTable; object parameterAnnotationTable; object annotationDefault; object addendum = methodAddendum(t, vmMethod); if (addendum) { signature = addendumSignature(t, addendum); if (signature) { PROTECT(t, addendum); signature = t->m->classpath->makeString (t, signature, 0, byteArrayLength(t, signature) - 1); } annotationTable = addendumAnnotationTable(t, addendum); parameterAnnotationTable = methodAddendumParameterAnnotationTable (t, addendum); annotationDefault = methodAddendumAnnotationDefault(t, addendum); } else { signature = 0; annotationTable = 0; parameterAnnotationTable = 0; annotationDefault = 0; } PROTECT(t, signature); PROTECT(t, annotationTable); PROTECT(t, parameterAnnotationTable); PROTECT(t, annotationDefault); if (annotationTable or parameterAnnotationTable or annotationDefault) { object runtimeData = getClassRuntimeData(t, methodClass(t, vmMethod)); set(t, runtimeData, ClassRuntimeDataPool, addendumPool(t, methodAddendum(t, vmMethod))); } if (index == -1) { object table = classMethodTable(t, methodClass(t, vmMethod)); for (unsigned i = 0; i < arrayLength(t, table); ++i) { if (vmMethod == arrayBody(t, table, i)) { index = i; break; } } } expect(t, index != -1); object jclass = getJClass(t, methodClass(t, vmMethod)); return makeJmethod (t, true, 0, jclass, index, name, returnType, parameterTypes, exceptionTypes, methodFlags(t, vmMethod), signature, 0, annotationTable, parameterAnnotationTable, annotationDefault, 0, 0, 0); } object makeJconstructor(Thread* t, object vmMethod, int index) { PROTECT(t, vmMethod); unsigned parameterCount; unsigned returnTypeSpec; object parameterTypes = resolveParameterJTypes (t, classLoader(t, methodClass(t, vmMethod)), methodSpec(t, vmMethod), ¶meterCount, &returnTypeSpec); PROTECT(t, parameterTypes); object exceptionTypes = resolveExceptionJTypes (t, classLoader(t, methodClass(t, vmMethod)), methodAddendum(t, vmMethod)); PROTECT(t, exceptionTypes); object signature; object annotationTable; object parameterAnnotationTable; object addendum = methodAddendum(t, vmMethod); if (addendum) { signature = addendumSignature(t, addendum); if (signature) { PROTECT(t, addendum); signature = t->m->classpath->makeString (t, signature, 0, byteArrayLength(t, signature) - 1); } annotationTable = addendumAnnotationTable(t, addendum); parameterAnnotationTable = methodAddendumParameterAnnotationTable (t, addendum); } else { signature = 0; annotationTable = 0; parameterAnnotationTable = 0; } PROTECT(t, signature); PROTECT(t, annotationTable); PROTECT(t, parameterAnnotationTable); if (annotationTable or parameterAnnotationTable) { object runtimeData = getClassRuntimeData(t, methodClass(t, vmMethod)); set(t, runtimeData, ClassRuntimeDataPool, addendumPool(t, methodAddendum(t, vmMethod))); } if (index == -1) { object table = classMethodTable(t, methodClass(t, vmMethod)); for (unsigned i = 0; i < arrayLength(t, table); ++i) { if (vmMethod == arrayBody(t, table, i)) { index = i; break; } } } expect(t, index != -1); object jclass = getJClass(t, methodClass(t, vmMethod)); return makeJconstructor (t, true, 0, jclass, index, parameterTypes, exceptionTypes, methodFlags (t, vmMethod), signature, 0, annotationTable, parameterAnnotationTable, 0, 0, 0); } object makeJfield(Thread* t, object vmField, int index) { PROTECT(t, vmField); object name = intern (t, t->m->classpath->makeString (t, fieldName(t, vmField), 0, byteArrayLength (t, fieldName(t, vmField)) - 1)); PROTECT(t, name); object type = resolveClassBySpec (t, classLoader(t, fieldClass(t, vmField)), reinterpret_cast (&byteArrayBody(t, fieldSpec(t, vmField), 0)), byteArrayLength(t, fieldSpec(t, vmField)) - 1); PROTECT(t, type); type = getJClass(t, type); object signature; object annotationTable; object addendum = fieldAddendum(t, vmField); if (addendum) { signature = addendumSignature(t, addendum); if (signature) { PROTECT(t, addendum); signature = t->m->classpath->makeString (t, signature, 0, byteArrayLength(t, signature) - 1); } annotationTable = addendumAnnotationTable(t, addendum); } else { signature = 0; annotationTable = 0; } PROTECT(t, signature); PROTECT(t, annotationTable); if (annotationTable) { object runtimeData = getClassRuntimeData(t, fieldClass(t, vmField)); set(t, runtimeData, ClassRuntimeDataPool, addendumPool(t, fieldAddendum(t, vmField))); } if (index == -1) { object table = classFieldTable(t, fieldClass(t, vmField)); for (unsigned i = 0; i < arrayLength(t, table); ++i) { if (vmField == arrayBody(t, table, i)) { index = i; break; } } } expect(t, index != -1); object jclass = getJClass(t, fieldClass(t, vmField)); return makeJfield (t, true, 0, jclass, index, name, type, fieldFlags (t, vmField), signature, 0, annotationTable, 0, 0, 0, 0); } void setProperty(Thread* t, object method, object properties, const char* name, const void* value, const char* format = "%s") { PROTECT(t, method); PROTECT(t, properties); object n = makeString(t, "%s", name); PROTECT(t, n); object v = makeString(t, format, value); t->m->processor->invoke(t, method, properties, n, v); } bool pipeAvailable(int fd, int* available) { #ifdef PLATFORM_WINDOWS HANDLE h = reinterpret_cast(_get_osfhandle(fd)); if (h == INVALID_HANDLE_VALUE) { return false; } DWORD n; if (PeekNamedPipe(h, 0,0, 0, &n, 0)) { *available = n; } else { if (GetLastError() != ERROR_BROKEN_PIPE) { return false; } *available = 0; } return true; #else return ioctl(fd, FIONREAD, available) >= 0; #endif } } // namespace local } // namespace namespace vm { Classpath* makeClasspath(System* s, Allocator* allocator, const char* javaHome, const char* embedPrefix) { return new (allocator->allocate(sizeof(local::MyClasspath))) local::MyClasspath(s, allocator, javaHome, embedPrefix); } } // namespace vm extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_lang_Class_getSuperclass (Thread* t, object, uintptr_t* arguments) { object class_ = jclassVmClass(t, reinterpret_cast(arguments[0])); if (classFlags(t, class_) & ACC_INTERFACE) { return 0; } else { object super = classSuper(t, class_); return super ? reinterpret_cast(getJClass(t, super)) : 0; } } extern "C" AVIAN_EXPORT void Avian_sun_misc_Unsafe_registerNatives (Thread*, object, uintptr_t*) { // ignore } extern "C" AVIAN_EXPORT void Avian_sun_misc_Perf_registerNatives (Thread*, object, uintptr_t*) { // ignore } extern "C" AVIAN_EXPORT int64_t Avian_sun_misc_Perf_createLong (Thread* t, object, uintptr_t*) { return reinterpret_cast (t->m->processor->invoke (t, resolveMethod (t, root(t, Machine::BootLoader), "java/nio/ByteBuffer", "allocate", "(I)Ljava/nio/ByteBuffer;"), 0, 8)); } extern "C" AVIAN_EXPORT int64_t Avian_sun_misc_Unsafe_addressSize (Thread*, object, uintptr_t*) { return BytesPerWord; } extern "C" AVIAN_EXPORT int64_t Avian_sun_misc_Unsafe_defineClass__Ljava_lang_String_2_3BIILjava_lang_ClassLoader_2Ljava_security_ProtectionDomain_2 (Thread* t, object, uintptr_t* arguments) { //object name = reinterpret_cast(arguments[1]); object data = reinterpret_cast(arguments[2]); int32_t offset = arguments[3]; int32_t length = arguments[4]; object loader = reinterpret_cast(arguments[5]); //object domain = reinterpret_cast(arguments[6]); uint8_t* buffer = static_cast(t->m->heap->allocate(length)); THREAD_RESOURCE2(t, uint8_t*, buffer, int, length, t->m->heap->free(buffer, length)); memcpy(buffer, &byteArrayBody(t, data, offset), length); return reinterpret_cast (getJClass(t, defineClass(t, loader, buffer, length))); } extern "C" AVIAN_EXPORT int64_t Avian_sun_misc_Unsafe_allocateInstance (Thread* t, object, uintptr_t* arguments) { object c = jclassVmClass(t, reinterpret_cast(arguments[1])); PROTECT(t, c); initClass(t, c); return reinterpret_cast(make(t, c)); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_staticFieldOffset (Thread* t, object, uintptr_t* arguments) { object jfield = reinterpret_cast(arguments[1]); return fieldOffset (t, arrayBody (t, classFieldTable (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_staticFieldBase (Thread* t, object, uintptr_t* arguments) { return reinterpret_cast (classStaticTable (t, jclassVmClass (t, jfieldClazz(t, reinterpret_cast(arguments[1]))))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_objectFieldOffset (Thread* t, object, uintptr_t* arguments) { object jfield = reinterpret_cast(arguments[1]); return fieldOffset (t, arrayBody (t, classFieldTable (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getShort__Ljava_lang_Object_2J (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); return fieldAtOffset(o, offset); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getChar__Ljava_lang_Object_2J (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); return fieldAtOffset(o, offset); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getInt__Ljava_lang_Object_2J (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); return fieldAtOffset(o, offset); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getFloat__Ljava_lang_Object_2J (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); return fieldAtOffset(o, offset); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getLong__Ljava_lang_Object_2J (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); return fieldAtOffset(o, offset); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getDouble__Ljava_lang_Object_2J (Thread* t, object method, uintptr_t* arguments) { return Avian_sun_misc_Unsafe_getLong__Ljava_lang_Object_2J (t, method, arguments); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putByte__Ljava_lang_Object_2JB (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int8_t value = arguments[4]; fieldAtOffset(o, offset) = value; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putShort__Ljava_lang_Object_2JS (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int16_t value = arguments[4]; fieldAtOffset(o, offset) = value; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putChar__Ljava_lang_Object_2JC (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uint16_t value = arguments[4]; fieldAtOffset(o, offset) = value; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putInt__Ljava_lang_Object_2JI (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int32_t value = arguments[4]; fieldAtOffset(o, offset) = value; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putFloat__Ljava_lang_Object_2JF (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int32_t value = arguments[4]; fieldAtOffset(o, offset) = value; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getByte__Ljava_lang_Object_2J (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); return fieldAtOffset(o, offset); } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getBoolean__Ljava_lang_Object_2J (Thread* t, object method, uintptr_t* arguments) { return Avian_sun_misc_Unsafe_getByte__Ljava_lang_Object_2J (t, method, arguments); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putBoolean__Ljava_lang_Object_2JZ (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); uint8_t value = arguments[4]; fieldAtOffset(o, offset) = value; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_putLong__Ljava_lang_Object_2JJ (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); int64_t value; memcpy(&value, arguments + 4, 8); fieldAtOffset(o, offset) = value; } extern "C" AVIAN_EXPORT int64_t JNICALL Avian_sun_misc_Unsafe_pageSize (Thread*, object, uintptr_t*) { return local::PageSize; } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_ensureClassInitialized (Thread* t, object, uintptr_t* arguments) { initClass(t, jclassVmClass(t, reinterpret_cast(arguments[1]))); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_monitorEnter (Thread* t, object, uintptr_t* arguments) { acquire(t, reinterpret_cast(arguments[1])); } extern "C" AVIAN_EXPORT void JNICALL Avian_sun_misc_Unsafe_monitorExit (Thread* t, object, uintptr_t* arguments) { release(t, reinterpret_cast(arguments[1])); } namespace { namespace local { extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetInterfaceVersion)() { return local::InterfaceVersion; } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_IHashCode)(Thread* t, jobject o) { ENTER(t, Thread::ActiveState); return o ? objectHash(t, *o) : 0; } uint64_t jvmWait(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jlong milliseconds; memcpy(&milliseconds, arguments + 1, sizeof(jlong)); vm::wait(t, *o, milliseconds); return 1; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_MonitorWait)(Thread* t, jobject o, jlong milliseconds) { uintptr_t arguments[1 + (sizeof(jlong) / BytesPerWord)]; arguments[0] = reinterpret_cast(o); memcpy(arguments + 1, &milliseconds, sizeof(jlong)); run(t, jvmWait, arguments); } uint64_t jvmNotify(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); notify(t, *o); return 1; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_MonitorNotify)(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(o) }; run(t, jvmNotify, arguments); } uint64_t jvmNotifyAll(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); notifyAll(t, *o); return 1; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_MonitorNotifyAll)(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(o) }; run(t, jvmNotifyAll, arguments); } uint64_t jvmClone(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); return reinterpret_cast(makeLocalReference(t, clone(t, *o))); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_Clone)(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(o) }; return reinterpret_cast(run(t, jvmClone, arguments)); } uint64_t jvmInternString(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); return reinterpret_cast(makeLocalReference(t, intern(t, *o))); } extern "C" AVIAN_EXPORT jstring JNICALL EXPORT(JVM_InternString)(Thread* t, jstring s) { uintptr_t arguments[] = { reinterpret_cast(s) }; return reinterpret_cast(run(t, jvmInternString, arguments)); } extern "C" AVIAN_EXPORT jlong JNICALL EXPORT(JVM_CurrentTimeMillis)(Thread* t, jclass) { return t->m->system->now(); } extern "C" AVIAN_EXPORT jlong JNICALL EXPORT(JVM_NanoTime)(Thread* t, jclass) { return t->m->system->now() * 1000 * 1000; } uint64_t jvmArrayCopy(Thread* t, uintptr_t* arguments) { jobject src = reinterpret_cast(arguments[0]); jint srcOffset = arguments[1]; jobject dst = reinterpret_cast(arguments[2]); jint dstOffset = arguments[3]; jint length = arguments[4]; arrayCopy(t, *src, srcOffset, *dst, dstOffset, length); return 1; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_ArrayCopy)(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, jint dstOffset, jint length) { uintptr_t arguments[] = { reinterpret_cast(src), static_cast(srcOffset), reinterpret_cast(dst), static_cast(dstOffset), static_cast(length) }; run(t, jvmArrayCopy, arguments); } uint64_t jvmInitProperties(Thread* t, uintptr_t* arguments) { jobject properties = reinterpret_cast(arguments[0]); object method = resolveMethod (t, root(t, Machine::BootLoader), "java/util/Properties", "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); PROTECT(t, method); #ifdef PLATFORM_WINDOWS local::setProperty(t, method, *properties, "line.separator", "\r\n"); local::setProperty(t, method, *properties, "file.separator", "\\"); local::setProperty(t, method, *properties, "path.separator", ";"); local::setProperty(t, method, *properties, "os.name", "Windows"); TCHAR buffer[MAX_PATH]; GetTempPath(MAX_PATH, buffer); local::setProperty(t, method, *properties, "java.io.tmpdir", buffer); local::setProperty(t, method, *properties, "java.home", buffer); local::setProperty(t, method, *properties, "user.home", _wgetenv(L"USERPROFILE"), "%ls"); GetCurrentDirectory(MAX_PATH, buffer); local::setProperty(t, method, *properties, "user.dir", buffer); #else // not PLATFORM_WINDOWS local::setProperty(t, method, *properties, "line.separator", "\n"); local::setProperty(t, method, *properties, "file.separator", "/"); local::setProperty(t, method, *properties, "path.separator", ":"); # ifdef __APPLE__ local::setProperty(t, method, *properties, "os.name", "Mac OS X"); # elif defined __FreeBSD__ local::setProperty(t, method, *properties, "os.name", "FreeBSD"); # else // not __APPLE__ local::setProperty(t, method, *properties, "os.name", "Linux"); # endif // not __APPLE__ local::setProperty(t, method, *properties, "java.io.tmpdir", "/tmp"); local::setProperty(t, method, *properties, "user.home", getenv("HOME")); char buffer[PATH_MAX]; local::setProperty(t, method, *properties, "user.dir", getcwd(buffer, PATH_MAX)); #endif // not PLATFORM_WINDOWS local::setProperty(t, method, *properties, "java.protocol.handler.pkgs", "avian"); local::setProperty(t, method, *properties, "java.vm.vendor", "Avian Contributors"); local::setProperty(t, method, *properties, "java.vm.name","Avian"); #ifdef AVIAN_VERSION local::setProperty(t, method, *properties, "java.vm.version",AVIAN_VERSION); #endif #ifdef AVIAN_INFO local::setProperty(t, method, *properties, "java.vm.info",AVIAN_INFO); #endif local::setProperty (t, method, *properties, "java.home", static_cast(t->m->classpath)->javaHome); local::setProperty (t, method, *properties, "sun.boot.library.path", static_cast(t->m->classpath)->libraryPath); local::setProperty (t, method, *properties, "sun.boot.class.path", static_cast (systemClassLoaderFinder(t, root(t, Machine::BootLoader)))->path()); local::setProperty(t, method, *properties, "file.encoding", "UTF-8"); #ifdef ARCH_x86_32 local::setProperty(t, method, *properties, "os.arch", "x86"); #elif defined ARCH_x86_64 local::setProperty(t, method, *properties, "os.arch", "x86_64"); #elif defined ARCH_powerpc local::setProperty(t, method, *properties, "os.arch", "ppc"); #elif defined ARCH_arm local::setProperty(t, method, *properties, "os.arch", "arm"); #else local::setProperty(t, method, *properties, "os.arch", "unknown"); #endif for (unsigned i = 0; i < t->m->propertyCount; ++i) { const char* start = t->m->properties[i]; const char* p = start; while (*p and *p != '=') ++p; if (*p == '=') { THREAD_RUNTIME_ARRAY(t, char, name, (p - start) + 1); memcpy(RUNTIME_ARRAY_BODY(name), start, p - start); RUNTIME_ARRAY_BODY(name)[p - start] = 0; local::setProperty (t, method, *properties, RUNTIME_ARRAY_BODY(name), p + 1); } } return reinterpret_cast(properties); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_InitProperties)(Thread* t, jobject properties) { uintptr_t arguments[] = { reinterpret_cast(properties) }; return reinterpret_cast(run(t, jvmInitProperties, arguments)); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_OnExit)(void (*)(void)) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_Exit)(jint code) { exit(code); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_Halt)(jint code) { exit(code); } uint64_t jvmGC(Thread* t, uintptr_t*) { collect(t, Heap::MajorCollection); return 1; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_GC)() { Thread* t = static_cast(local::globalMachine->localThread->get()); run(t, jvmGC, 0); } extern "C" AVIAN_EXPORT jlong JNICALL EXPORT(JVM_MaxObjectInspectionAge)(void) { return 0; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_TraceInstructions)(jboolean) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_TraceMethodCalls)(jboolean) { abort(); } extern "C" AVIAN_EXPORT jlong JNICALL EXPORT(JVM_TotalMemory)() { return 0; } extern "C" AVIAN_EXPORT jlong JNICALL EXPORT(JVM_FreeMemory)() { return 0; } extern "C" AVIAN_EXPORT jlong JNICALL EXPORT(JVM_MaxMemory)() { return local::globalMachine->heap->limit(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_ActiveProcessorCount)() { #ifdef PLATFORM_WINDOWS SYSTEM_INFO si; GetSystemInfo(&si); return si.dwNumberOfProcessors; #else return sysconf(_SC_NPROCESSORS_ONLN); #endif } uint64_t jvmLoadLibrary(Thread* t, uintptr_t* arguments) { const char* path = reinterpret_cast(arguments[0]); THREAD_RUNTIME_ARRAY(t, char, p, strlen(path) + 1); replace('\\', '/', RUNTIME_ARRAY_BODY(p), path); return reinterpret_cast (loadLibrary (t, static_cast(t->m->classpath)->libraryPath, RUNTIME_ARRAY_BODY(p), false, false)); } extern "C" AVIAN_EXPORT void* JNICALL EXPORT(JVM_LoadLibrary)(const char* path) { Thread* t = static_cast(local::globalMachine->localThread->get()); uintptr_t arguments[] = { reinterpret_cast(path) }; return reinterpret_cast(run(t, jvmLoadLibrary, arguments)); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_UnloadLibrary)(void*) { // todo: implement this correctly for POSIX and Windows } extern "C" AVIAN_EXPORT void* JNICALL EXPORT(JVM_FindLibraryEntry)(void* library, const char* name) { Thread* t = static_cast(local::globalMachine->localThread->get()); ENTER(t, Thread::ActiveState); if (library == RTLD_DEFAULT) { library = t->m->libraries; } return static_cast(library)->resolve(name); } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_IsSupportedJNIVersion)(jint version) { return version <= JNI_VERSION_1_6; } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_IsNaN)(jdouble) { abort(); } uint64_t jvmFillInStackTrace(Thread* t, uintptr_t* arguments) { jobject throwable = reinterpret_cast(arguments[0]); object trace = getTrace(t, 2); set(t, *throwable, ThrowableTrace, trace); return 1; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_FillInStackTrace)(Thread* t, jobject throwable) { uintptr_t arguments[] = { reinterpret_cast(throwable) }; run(t, jvmFillInStackTrace, arguments); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_PrintStackTrace)(Thread*, jobject, jobject) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetStackTraceDepth)(Thread* t, jobject throwable) { ENTER(t, Thread::ActiveState); return objectArrayLength(t, throwableTrace(t, *throwable)); } uint64_t jvmGetStackTraceElement(Thread* t, uintptr_t* arguments) { jobject throwable = reinterpret_cast(arguments[0]); jint index = arguments[1]; return reinterpret_cast (makeLocalReference (t, makeStackTraceElement (t, objectArrayBody(t, throwableTrace(t, *throwable), index)))); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_GetStackTraceElement)(Thread* t, jobject throwable, jint index) { uintptr_t arguments[] = { reinterpret_cast(throwable), static_cast(index) }; return reinterpret_cast(run(t, jvmGetStackTraceElement, arguments)); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_InitializeCompiler) (Thread*, jclass) { abort(); } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_IsSilentCompiler)(Thread*, jclass) { abort(); } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_CompileClass)(Thread*, jclass, jclass) { return false; } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_CompileClasses)(Thread*, jclass, jstring) { return false; } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_CompilerCommand)(Thread*, jclass, jobject) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_EnableCompiler)(Thread*, jclass) { // ignore } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_DisableCompiler)(Thread*, jclass) { // ignore } uint64_t jvmStartThread(Thread* t, uintptr_t* arguments) { jobject thread = reinterpret_cast(arguments[0]); return startThread(t, *thread) != 0; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_StartThread)(Thread* t, jobject thread) { uintptr_t arguments[] = { reinterpret_cast(thread) }; run(t, jvmStartThread, arguments); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_StopThread)(Thread*, jobject, jobject) { abort(); } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_IsThreadAlive)(Thread* t, jobject thread) { ENTER(t, Thread::ActiveState); Thread* p = reinterpret_cast(threadPeer(t, *thread)); return p and (p->flags & Thread::ActiveFlag) != 0; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_SuspendThread)(Thread*, jobject) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_ResumeThread)(Thread*, jobject) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_SetThreadPriority)(Thread*, jobject, jint) { // ignore } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_Yield)(Thread* t, jclass) { t->m->system->yield(); } uint64_t jvmSleep(Thread* t, uintptr_t* arguments) { jlong milliseconds; memcpy(&milliseconds, arguments, sizeof(jlong)); if (milliseconds <= 0) { milliseconds = 1; } if (threadSleepLock(t, t->javaThread) == 0) { object lock = makeJobject(t); set(t, t->javaThread, ThreadSleepLock, lock); } acquire(t, threadSleepLock(t, t->javaThread)); vm::wait(t, threadSleepLock(t, t->javaThread), milliseconds); release(t, threadSleepLock(t, t->javaThread)); return 1; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_Sleep)(Thread* t, jclass, jlong milliseconds) { uintptr_t arguments[sizeof(jlong) / BytesPerWord]; memcpy(arguments, &milliseconds, sizeof(jlong)); run(t, jvmSleep, arguments); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_CurrentThread)(Thread* t, jclass) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, t->javaThread); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_CountStackFrames)(Thread*, jobject) { abort(); } uint64_t jvmInterrupt(Thread* t, uintptr_t* arguments) { threadInterrupt(t, *reinterpret_cast(arguments[0])); return 1; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_Interrupt)(Thread* t, jobject thread) { uintptr_t arguments[] = { reinterpret_cast(thread) }; run(t, jvmInterrupt, arguments); } uint64_t jvmIsInterrupted(Thread* t, uintptr_t* arguments) { jobject thread = reinterpret_cast(arguments[0]); jboolean clear = arguments[1]; return threadIsInterrupted(t, *thread, clear); } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_IsInterrupted)(Thread* t, jobject thread, jboolean clear) { uintptr_t arguments[] = { reinterpret_cast(thread), clear }; return run(t, jvmIsInterrupted, arguments); } uint64_t jvmHoldsLock(Thread* t, uintptr_t* arguments) { object m = objectMonitor(t, *reinterpret_cast(arguments[0]), false); return m and monitorOwner(t, m) == t; } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_HoldsLock)(Thread* t, jclass, jobject o) { uintptr_t arguments[] = { reinterpret_cast(o) }; return run(t, jvmHoldsLock, arguments); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_DumpAllStacks)(Thread*, jclass) { abort(); } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetAllThreads)(Thread*, jclass) { abort(); } uint64_t jvmDumpThreads(Thread* t, uintptr_t* arguments) { jobjectArray threads = reinterpret_cast(arguments[0]); unsigned threadsLength = objectArrayLength(t, *threads); object arrayClass = resolveObjectArrayClass (t, classLoader(t, type(t, Machine::StackTraceElementType)), type(t, Machine::StackTraceElementType)); object result = makeObjectArray(t, arrayClass, threadsLength); PROTECT(t, result); for (unsigned threadsIndex = 0; threadsIndex < threadsLength; ++ threadsIndex) { Thread* peer = reinterpret_cast (threadPeer(t, objectArrayBody(t, *threads, threadsIndex))); if (peer) { object trace = t->m->processor->getStackTrace(t, peer); PROTECT(t, trace); unsigned traceLength = objectArrayLength(t, trace); object array = makeObjectArray (t, type(t, Machine::StackTraceElementType), traceLength); PROTECT(t, array); for (unsigned traceIndex = 0; traceIndex < traceLength; ++ traceIndex) { object ste = makeStackTraceElement (t, objectArrayBody(t, trace, traceIndex)); set(t, array, ArrayBody + (traceIndex * BytesPerWord), ste); } set(t, result, ArrayBody + (threadsIndex * BytesPerWord), array); } } return reinterpret_cast(makeLocalReference(t, result)); } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_DumpThreads)(Thread* t, jclass, jobjectArray threads) { uintptr_t arguments[] = { reinterpret_cast(threads) }; return reinterpret_cast(run(t, jvmDumpThreads, arguments)); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_CurrentLoadedClass)(Thread*) { abort(); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_CurrentClassLoader)(Thread*) { // just return null, i.e. tell SecurityManager.currentClassLoader // all permissions are granted, since Avian doesn't do any internal // security checks: return 0; } uint64_t jvmGetClassContext(Thread* t, uintptr_t*) { object trace = getTrace(t, 1); PROTECT(t, trace); object context = makeObjectArray (t, type(t, Machine::JclassType), objectArrayLength(t, trace)); PROTECT(t, context); for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { object c = getJClass (t, methodClass(t, traceElementMethod(t, objectArrayBody(t, trace, i)))); set(t, context, ArrayBody + (i * BytesPerWord), c); } return reinterpret_cast(makeLocalReference(t, context)); } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetClassContext)(Thread* t) { return reinterpret_cast(run(t, jvmGetClassContext, 0)); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_ClassDepth)(Thread*, jstring) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_ClassLoaderDepth)(Thread*) { abort(); } uint64_t jvmGetSystemPackage(Thread* t, uintptr_t* arguments) { jstring s = reinterpret_cast(arguments[0]); ACQUIRE(t, t->m->classLock); THREAD_RUNTIME_ARRAY(t, char, chars, stringLength(t, *s) + 1); stringChars(t, *s, RUNTIME_ARRAY_BODY(chars)); object key = makeByteArray(t, RUNTIME_ARRAY_BODY(chars)); object array = hashMapFind (t, root(t, Machine::PackageMap), key, byteArrayHash, byteArrayEqual); if (array) { return reinterpret_cast (makeLocalReference (t, t->m->classpath->makeString (t, array, 0, byteArrayLength(t, array)))); } else { return 0; } } extern "C" AVIAN_EXPORT jstring JNICALL EXPORT(JVM_GetSystemPackage)(Thread* t, jstring s) { uintptr_t arguments[] = { reinterpret_cast(s) }; return reinterpret_cast(run(t, jvmGetSystemPackage, arguments)); } uint64_t jvmGetSystemPackages(Thread* t, uintptr_t*) { return reinterpret_cast (makeLocalReference (t, makeObjectArray (t, resolveClass (t, root(t, Machine::BootLoader), "java/lang/Package"), 0))); } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetSystemPackages)(Thread* t) { return reinterpret_cast(run(t, jvmGetSystemPackages, 0)); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_AllocateNewObject)(Thread*, jobject, jclass, jclass) { abort(); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_AllocateNewArray)(Thread*, jobject, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_LatestUserDefinedLoader)(Thread* t) { ENTER(t, Thread::ActiveState); class Visitor: public Processor::StackVisitor { public: Visitor(Thread* t): t(t), loader(0) { } virtual bool visit(Processor::StackWalker* walker) { object loader = classLoader(t, methodClass(t, walker->method())); if (loader and loader != root(t, Machine::BootLoader) and strcmp (&byteArrayBody(t, className(t, objectClass(t, loader)), 0), reinterpret_cast ("sun/reflect/DelegatingClassLoader"))) { this->loader = loader; return false; } else { return true; } } Thread* t; object loader; } v(t); t->m->processor->walkStack(t, &v); return makeLocalReference(t, v.loader); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_LoadClass0)(Thread*, jobject, jclass, jstring) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetArrayLength)(Thread* t, jobject array) { ENTER(t, Thread::ActiveState); return fieldAtOffset(*array, BytesPerWord); } uint64_t jvmGetArrayElement(Thread* t, uintptr_t* arguments) { jobject array = reinterpret_cast(arguments[0]); jint index = arguments[1]; switch (byteArrayBody(t, className(t, objectClass(t, *array)), 1)) { case 'Z': return reinterpret_cast (makeLocalReference (t, makeBoolean(t, fieldAtOffset(*array, ArrayBody + index)))); case 'B': return reinterpret_cast (makeLocalReference (t, makeByte(t, fieldAtOffset(*array, ArrayBody + index)))); case 'C': return reinterpret_cast (makeLocalReference (t, makeChar(t, fieldAtOffset(*array, ArrayBody + (index * 2))))); case 'S': return reinterpret_cast (makeLocalReference (t, makeShort(t, fieldAtOffset(*array, ArrayBody + (index * 2))))); case 'I': return reinterpret_cast (makeLocalReference (t, makeInt(t, fieldAtOffset(*array, ArrayBody + (index * 4))))); case 'F': return reinterpret_cast (makeLocalReference (t, makeFloat(t, fieldAtOffset(*array, ArrayBody + (index * 4))))); case 'J': return reinterpret_cast (makeLocalReference (t, makeLong(t, fieldAtOffset(*array, ArrayBody + (index * 8))))); case 'D': return reinterpret_cast (makeLocalReference (t, makeDouble(t, fieldAtOffset(*array, ArrayBody + (index * 8))))); case 'L': case '[': return reinterpret_cast (makeLocalReference (t, fieldAtOffset(*array, ArrayBody + (index * BytesPerWord)))); default: abort(t); } } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_GetArrayElement)(Thread* t, jobject array, jint index) { uintptr_t arguments[] = { reinterpret_cast(array), static_cast(index) }; return reinterpret_cast(run(t, jvmGetArrayElement, arguments)); } extern "C" AVIAN_EXPORT jvalue JNICALL EXPORT(JVM_GetPrimitiveArrayElement)(Thread*, jobject, jint, jint) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_SetArrayElement)(Thread* t, jobject array, jint index, jobject value) { ENTER(t, Thread::ActiveState); switch (byteArrayBody(t, className(t, objectClass(t, *array)), 1)) { case 'Z': fieldAtOffset(*array, ArrayBody + index) = booleanValue(t, *value); break; case 'B': fieldAtOffset(*array, ArrayBody + index) = byteValue(t, *value); break; case 'C': fieldAtOffset(*array, ArrayBody + (index * 2)) = charValue(t, *value); break; case 'S': fieldAtOffset(*array, ArrayBody + (index * 2)) = shortValue(t, *value); break; case 'I': fieldAtOffset(*array, ArrayBody + (index * 4)) = intValue(t, *value); break; case 'F': fieldAtOffset(*array, ArrayBody + (index * 4)) = floatValue(t, *value); break; case 'J': fieldAtOffset(*array, ArrayBody + (index * 8)) = longValue(t, *value); break; case 'D': fieldAtOffset(*array, ArrayBody + (index * 8)) = doubleValue(t, *value); break; case 'L': case '[': set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0)); break; default: abort(t); } } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_SetPrimitiveArrayElement)(Thread*, jobject, jint, jvalue, unsigned char) { abort(); } object makeNewArray(Thread* t, object c, unsigned length) { if (classVmFlags(t, c) & PrimitiveFlag) { const char* name = reinterpret_cast (&byteArrayBody(t, local::getClassName(t, c), 0)); switch (*name) { case 'b': if (name[1] == 'o') { return makeBooleanArray(t, length); } else { return makeByteArray(t, length); } case 'c': return makeCharArray(t, length); case 'd': return makeDoubleArray(t, length); case 'f': return makeFloatArray(t, length); case 'i': return makeIntArray(t, length); case 'l': return makeLongArray(t, length); case 's': return makeShortArray(t, length); default: abort(t); } } else { return makeObjectArray(t, c, length); } } uint64_t jvmNewArray(Thread* t, uintptr_t* arguments) { jclass elementClass = reinterpret_cast(arguments[0]); jint length = arguments[1]; return reinterpret_cast (makeLocalReference (t, makeNewArray(t, jclassVmClass(t, *elementClass), length))); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_NewArray)(Thread* t, jclass elementClass, jint length) { uintptr_t arguments[] = { reinterpret_cast(elementClass), static_cast(length) }; return reinterpret_cast(run(t, jvmNewArray, arguments)); } uint64_t jvmNewMultiArray(Thread* t, uintptr_t* arguments) { jclass elementClass = reinterpret_cast(arguments[0]); jintArray dimensions = reinterpret_cast(arguments[1]); THREAD_RUNTIME_ARRAY(t, int32_t, counts, intArrayLength(t, *dimensions)); for (int i = intArrayLength(t, *dimensions) - 1; i >= 0; --i) { RUNTIME_ARRAY_BODY(counts)[i] = intArrayBody(t, *dimensions, i); if (UNLIKELY(RUNTIME_ARRAY_BODY(counts)[i] < 0)) { throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", RUNTIME_ARRAY_BODY(counts)[i]); return 0; } } object array = makeNewArray (t, jclassVmClass(t, *elementClass), RUNTIME_ARRAY_BODY(counts)[0]); PROTECT(t, array); populateMultiArray(t, array, RUNTIME_ARRAY_BODY(counts), 0, intArrayLength(t, *dimensions)); return reinterpret_cast(makeLocalReference(t, array)); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_NewMultiArray)(Thread* t, jclass elementClass, jintArray dimensions) { uintptr_t arguments[] = { reinterpret_cast(elementClass), reinterpret_cast(dimensions) }; return reinterpret_cast(run(t, jvmNewMultiArray, arguments)); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_GetCallerClass)(Thread* t, int target) { ENTER(t, Thread::ActiveState); object method = getCaller(t, target, true); return method ? makeLocalReference (t, getJClass(t, methodClass(t, method))) : 0; } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_FindPrimitiveClass)(Thread* t, const char* name) { ENTER(t, Thread::ActiveState); switch (*name) { case 'b': if (name[1] == 'o') { return makeLocalReference (t, getJClass(t, type(t, Machine::JbooleanType))); } else { return makeLocalReference (t, getJClass(t, type(t, Machine::JbyteType))); } case 'c': return makeLocalReference (t, getJClass(t, type(t, Machine::JcharType))); case 'd': return makeLocalReference (t, getJClass(t, type(t, Machine::JdoubleType))); case 'f': return makeLocalReference (t, getJClass(t, type(t, Machine::JfloatType))); case 'i': return makeLocalReference (t, getJClass(t, type(t, Machine::JintType))); case 'l': return makeLocalReference (t, getJClass(t, type(t, Machine::JlongType))); case 's': return makeLocalReference (t, getJClass(t, type(t, Machine::JshortType))); case 'v': return makeLocalReference (t, getJClass(t, type(t, Machine::JvoidType))); default: throwNew(t, Machine::IllegalArgumentExceptionType); } } uint64_t jvmResolveClass(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); object method = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "link", "(Lavian/VMClass;)V"); t->m->processor->invoke(t, method, 0, jclassVmClass(t, *c)); return 1; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_ResolveClass)(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; run(t, jvmResolveClass, arguments); } uint64_t jvmFindClassFromClassLoader(Thread* t, uintptr_t* arguments) { const char* name = reinterpret_cast(arguments[0]); jboolean init = arguments[1]; jobject loader = reinterpret_cast(arguments[2]); jboolean throwError = arguments[3]; object c = resolveClass (t, loader ? *loader : root(t, Machine::BootLoader), name, true, throwError ? Machine::NoClassDefFoundErrorType : Machine::ClassNotFoundExceptionType); if (init) { PROTECT(t, c); initClass(t, c); } return reinterpret_cast(makeLocalReference(t, getJClass(t, c))); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_FindClassFromClassLoader)(Thread* t, const char* name, jboolean init, jobject loader, jboolean throwError) { uintptr_t arguments[] = { reinterpret_cast(name), init, reinterpret_cast(loader), throwError }; return reinterpret_cast (run(t, jvmFindClassFromClassLoader, arguments)); } extern "C" AVIAN_EXPORT jclass JNICALL JVM_FindClassFromBootLoader(Thread* t, const char* name) { return EXPORT(JVM_FindClassFromClassLoader)(t, name, false, 0, false); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_FindClassFromClass)(Thread*, const char*, jboolean, jclass) { abort(); } uint64_t jvmFindLoadedClass(Thread* t, uintptr_t* arguments) { jobject loader = reinterpret_cast(arguments[0]); jstring name = reinterpret_cast(arguments[1]); object spec = makeByteArray(t, stringLength(t, *name) + 1); { char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); stringChars(t, *name, s); replace('.', '/', s); } object c = findLoadedClass(t, *loader, spec); return reinterpret_cast (c ? makeLocalReference(t, getJClass(t, c)) : 0); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_FindLoadedClass)(Thread* t, jobject loader, jstring name) { uintptr_t arguments[] = { reinterpret_cast(loader), reinterpret_cast(name) }; return reinterpret_cast(run(t, jvmFindLoadedClass, arguments)); } uint64_t jvmDefineClass(Thread* t, uintptr_t* arguments) { jobject loader = reinterpret_cast(arguments[0]); const uint8_t* data = reinterpret_cast(arguments[1]); jsize length = arguments[2]; return reinterpret_cast (makeLocalReference (t, getJClass(t, defineClass(t, *loader, data, length)))); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_DefineClass)(Thread* t, const char*, jobject loader, const uint8_t* data, jsize length, jobject) { uintptr_t arguments[] = { reinterpret_cast(loader), reinterpret_cast(data), static_cast(length) }; return reinterpret_cast(run(t, jvmDefineClass, arguments)); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_DefineClassWithSource)(Thread* t, const char*, jobject loader, const uint8_t* data, jsize length, jobject, const char*) { return EXPORT(JVM_DefineClass)(t, 0, loader, data, length, 0); } extern "C" AVIAN_EXPORT jstring JNICALL EXPORT(JVM_GetClassName)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, jclassName(t, *c)); } uint64_t jvmGetClassInterfaces(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); object addendum = classAddendum(t, jclassVmClass(t, *c)); if (addendum) { object table = classAddendumInterfaceTable(t, addendum); if (table) { PROTECT(t, table); object array = makeObjectArray (t, type(t, Machine::JclassType), arrayLength(t, table)); PROTECT(t, array); for (unsigned i = 0; i < arrayLength(t, table); ++i) { object c = getJClass(t, arrayBody(t, table, i)); set(t, array, ArrayBody + (i * BytesPerWord), c); } return reinterpret_cast(makeLocalReference(t, array)); } } return reinterpret_cast (makeLocalReference (t, makeObjectArray(t, type(t, Machine::JclassType), 0))); } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetClassInterfaces)(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return reinterpret_cast(run(t, jvmGetClassInterfaces, arguments)); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_GetClassLoader)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); object loader = classLoader(t, jclassVmClass(t, *c)); if (loader == root(t, Machine::BootLoader)) { // sun.misc.Unsafe.getUnsafe expects a null result if the class // loader is the boot classloader and will throw a // SecurityException otherwise. object caller = getCaller(t, 2); if (caller and strcmp (reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, caller)), 0)), "sun/misc/Unsafe") == 0) { return 0; } else { return makeLocalReference(t, root(t, Machine::BootLoader)); } } else { return makeLocalReference(t, loader); } } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_IsInterface)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); return (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) != 0; } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetClassSigners)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); object runtimeData = getClassRuntimeDataIfExists(t, jclassVmClass(t, *c)); return runtimeData ? makeLocalReference (t, classRuntimeDataSigners(t, runtimeData)) : 0; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_SetClassSigners)(Thread* t, jclass c, jobjectArray signers) { ENTER(t, Thread::ActiveState); object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); set(t, runtimeData, ClassRuntimeDataSigners, *signers); } uint64_t jvmGetProtectionDomain(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); object method = resolveMethod (t, root(t, Machine::BootLoader), "avian/Classes", "getProtectionDomain", "(Lavian/VMClass;)Ljava/security/ProtectionDomain;"); return reinterpret_cast (makeLocalReference (t, t->m->processor->invoke(t, method, 0, jclassVmClass(t, *c)))); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_GetProtectionDomain)(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return reinterpret_cast(run(t, jvmGetProtectionDomain, arguments)); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_SetProtectionDomain)(Thread*, jclass, jobject) { abort(); } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_IsArrayClass)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); return classArrayDimensions(t, jclassVmClass(t, *c)) != 0; } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_IsPrimitiveClass)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); return (classVmFlags(t, jclassVmClass(t, *c)) & PrimitiveFlag) != 0; } uint64_t jvmGetComponentType(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); if (classArrayDimensions(t, jclassVmClass(t, *c))) { uint8_t n = byteArrayBody(t, className(t, jclassVmClass(t, *c)), 1); if (n != 'L' and n != '[') { return reinterpret_cast (makeLocalReference(t, getJClass(t, primitiveClass(t, n)))); } else { return reinterpret_cast (makeLocalReference (t, getJClass(t, classStaticTable(t, jclassVmClass(t, *c))))); } } else { return 0; } } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_GetComponentType)(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return reinterpret_cast(run(t, jvmGetComponentType, arguments)); } uint64_t jvmGetClassModifiers(Thread* t, uintptr_t* arguments) { return classModifiers (t, jclassVmClass(t, *reinterpret_cast(arguments[0]))); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetClassModifiers)(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return run(t, jvmGetClassModifiers, arguments); } uint64_t jvmGetDeclaredClasses(Thread* t, uintptr_t* arguments) { return reinterpret_cast (makeLocalReference (t, getDeclaredClasses (t, jclassVmClass(t, *reinterpret_cast(arguments[0])), false))); } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetDeclaredClasses)(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return reinterpret_cast(run(t, jvmGetDeclaredClasses, arguments)); } uint64_t jvmGetDeclaringClass(Thread* t, uintptr_t* arguments) { return reinterpret_cast (makeLocalReference (t, getDeclaringClass (t, jclassVmClass(t, *reinterpret_cast(arguments[0]))))); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_GetDeclaringClass)(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return reinterpret_cast(run(t, jvmGetDeclaringClass, arguments)); } uint64_t jvmGetClassSignature(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); object addendum = classAddendum(t, jclassVmClass(t, *c)); if (addendum) { object signature = addendumSignature(t, addendum); if (signature) { return reinterpret_cast (makeLocalReference (t, t->m->classpath->makeString (t, signature, 0, byteArrayLength(t, signature) - 1))); } } return 0; } extern "C" AVIAN_EXPORT jstring JNICALL EXPORT(JVM_GetClassSignature)(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return reinterpret_cast(run(t, jvmGetClassSignature, arguments)); } extern "C" AVIAN_EXPORT jbyteArray JNICALL EXPORT(JVM_GetClassAnnotations)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); object addendum = classAddendum(t, jclassVmClass(t, *c)); return addendum ? makeLocalReference(t, addendumAnnotationTable(t, addendum)) : 0; } uint64_t jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); jboolean publicOnly = arguments[1]; object table = classMethodTable(t, jclassVmClass(t, *c)); if (table) { PROTECT(t, table); object array = makeObjectArray (t, type(t, Machine::JmethodType), local::countMethods(t, jclassVmClass(t, *c), publicOnly)); PROTECT(t, array); unsigned ai = 0; for (unsigned i = 0, j = classDeclaredMethodCount(t, jclassVmClass(t, *c)); i < j; ++i) { object vmMethod = arrayBody(t, table, i); PROTECT(t, vmMethod); if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') { object method = makeJmethod(t, vmMethod, i); assert(t, ai < objectArrayLength(t, array)); set(t, array, ArrayBody + ((ai++) * BytesPerWord), method); } } return reinterpret_cast(makeLocalReference(t, array)); } else { return reinterpret_cast (makeLocalReference (t, makeObjectArray(t, type(t, Machine::JmethodType), 0))); } } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetClassDeclaredMethods)(Thread* t, jclass c, jboolean publicOnly) { uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; return reinterpret_cast (run(t, jvmGetClassDeclaredMethods, arguments)); } uint64_t jvmGetClassDeclaredFields(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); jboolean publicOnly = arguments[1]; object table = classFieldTable(t, jclassVmClass(t, *c)); if (table) { PROTECT(t, table); object array = makeObjectArray (t, type(t, Machine::JfieldType), local::countFields(t, jclassVmClass(t, *c), publicOnly)); PROTECT(t, array); unsigned ai = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmField = arrayBody(t, table, i); PROTECT(t, vmField); if ((not publicOnly) or (fieldFlags(t, vmField) & ACC_PUBLIC)) { object field = makeJfield(t, vmField, i); assert(t, ai < objectArrayLength(t, array)); set(t, array, ArrayBody + ((ai++) * BytesPerWord), field); } } assert(t, ai == objectArrayLength(t, array)); return reinterpret_cast(makeLocalReference(t, array)); } else { return reinterpret_cast (makeLocalReference (t, makeObjectArray(t, type(t, Machine::JfieldType), 0))); } } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) { uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; return reinterpret_cast (run(t, jvmGetClassDeclaredFields, arguments)); } uint64_t jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); jboolean publicOnly = arguments[1]; object table = classMethodTable(t, jclassVmClass(t, *c)); if (table) { PROTECT(t, table); object array = makeObjectArray (t, type(t, Machine::JconstructorType), local::countConstructors(t, jclassVmClass(t, *c), publicOnly)); PROTECT(t, array); unsigned ai = 0; for (unsigned i = 0, j = classDeclaredMethodCount(t, jclassVmClass(t, *c)); i < j; ++i) { object vmMethod = arrayBody(t, table, i); PROTECT(t, vmMethod); if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) and strcmp(reinterpret_cast (&byteArrayBody(t, methodName(t, vmMethod), 0)), "") == 0) { object method = makeJconstructor(t, vmMethod, i); assert(t, ai < objectArrayLength(t, array)); set(t, array, ArrayBody + ((ai++) * BytesPerWord), method); } } return reinterpret_cast(makeLocalReference(t, array)); } else { return reinterpret_cast (makeLocalReference (t, makeObjectArray(t, type(t, Machine::JconstructorType), 0))); } } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c, jboolean publicOnly) { uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; return reinterpret_cast (run(t, jvmGetClassDeclaredConstructors, arguments)); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetClassAccessFlags)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); return classFlags(t, jclassVmClass(t, *c)); } uint64_t jvmInvokeMethod(Thread* t, uintptr_t* arguments) { jobject method = reinterpret_cast(arguments[0]); jobject instance = reinterpret_cast(arguments[1]); jobjectArray args = reinterpret_cast(arguments[2]); object vmMethod = arrayBody (t, classMethodTable (t, jclassVmClass(t, jmethodClazz(t, *method))), jmethodSlot(t, *method)); if (methodFlags(t, vmMethod) & ACC_STATIC) { instance = 0; } if (instance and not instanceOf(t, methodClass(t, vmMethod), *instance)) { throwNew(t, Machine::IllegalArgumentExceptionType); } return reinterpret_cast (makeLocalReference (t, invoke (t, vmMethod, instance ? *instance : 0, args ? *args : 0))); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_InvokeMethod)(Thread* t, jobject method, jobject instance, jobjectArray args) { uintptr_t arguments[] = { reinterpret_cast(method), reinterpret_cast(instance), reinterpret_cast(args) }; return reinterpret_cast(run(t, jvmInvokeMethod, arguments)); } uint64_t jvmNewInstanceFromConstructor(Thread* t, uintptr_t* arguments) { jobject constructor = reinterpret_cast(arguments[0]); jobjectArray args = reinterpret_cast(arguments[1]); object instance = make (t, jclassVmClass(t, jconstructorClazz(t, *constructor))); PROTECT(t, instance); object method = arrayBody (t, classMethodTable (t, jclassVmClass(t, jconstructorClazz(t, *constructor))), jconstructorSlot(t, *constructor)); invoke(t, method, instance, args ? *args : 0); return reinterpret_cast(makeLocalReference(t, instance)); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_NewInstanceFromConstructor)(Thread* t, jobject constructor, jobjectArray args) { uintptr_t arguments[] = { reinterpret_cast(constructor), reinterpret_cast(args) }; return reinterpret_cast (run(t, jvmNewInstanceFromConstructor, arguments)); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_GetClassConstantPool)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); object vmClass = jclassVmClass(t, *c); object addendum = classAddendum(t, vmClass); object pool; if (addendum) { pool = addendumPool(t, addendum); } else { pool = 0; } if (pool == 0) { pool = classRuntimeDataPool(t, getClassRuntimeData(t, vmClass)); } return makeLocalReference(t, makeConstantPool(t, pool)); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_ConstantPoolGetSize)(Thread* t, jobject, jobject pool) { if (pool == 0) return 0; ENTER(t, Thread::ActiveState); return singletonCount(t, *pool); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_ConstantPoolGetClassAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" AVIAN_EXPORT jclass JNICALL EXPORT(JVM_ConstantPoolGetClassAtIfLoaded)(Thread*, jobject, jobject, jint) { abort(); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_ConstantPoolGetMethodAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_ConstantPoolGetMethodAtIfLoaded)(Thread*, jobject, jobject, jint) { abort(); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_ConstantPoolGetFieldAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_ConstantPoolGetFieldAtIfLoaded)(Thread*, jobject, jobject, jint) { abort(); } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_ConstantPoolGetMemberRefInfoAt)(Thread*, jobject, jobject, jint) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_ConstantPoolGetIntAt)(Thread* t, jobject, jobject pool, jint index) { ENTER(t, Thread::ActiveState); return singletonValue(t, *pool, index - 1); } extern "C" AVIAN_EXPORT jlong JNICALL EXPORT(JVM_ConstantPoolGetLongAt)(Thread* t, jobject, jobject pool, jint index) { ENTER(t, Thread::ActiveState); uint64_t v; memcpy(&v, &singletonValue(t, *pool, index - 1), 8); return v; } extern "C" AVIAN_EXPORT jfloat JNICALL EXPORT(JVM_ConstantPoolGetFloatAt)(Thread* t, jobject, jobject pool, jint index) { ENTER(t, Thread::ActiveState); return bitsToFloat(singletonValue(t, *pool, index - 1)); } extern "C" AVIAN_EXPORT jdouble JNICALL EXPORT(JVM_ConstantPoolGetDoubleAt)(Thread* t, jobject, jobject pool, jint index) { ENTER(t, Thread::ActiveState); double v; memcpy(&v, &singletonValue(t, *pool, index - 1), 8); return v; } extern "C" AVIAN_EXPORT jstring JNICALL EXPORT(JVM_ConstantPoolGetStringAt)(Thread*, jobject, jobject, jint) { abort(); } uint64_t jvmConstantPoolGetUTF8At(Thread* t, uintptr_t* arguments) { jobject pool = reinterpret_cast(arguments[0]); jint index = arguments[1]; object array = parseUtf8(t, singletonObject(t, *pool, index - 1)); return reinterpret_cast (makeLocalReference (t, t->m->classpath->makeString (t, array, 0, fieldAtOffset(array, BytesPerWord) - 1))); } extern "C" AVIAN_EXPORT jstring JNICALL EXPORT(JVM_ConstantPoolGetUTF8At)(Thread* t, jobject, jobject pool, jint index) { uintptr_t arguments[] = { reinterpret_cast(pool), static_cast(index) }; return reinterpret_cast (run(t, jvmConstantPoolGetUTF8At, arguments)); } void maybeWrap(Thread* t, bool wrapException) { if (t->exception and wrapException and not (instanceOf(t, type(t, Machine::ErrorType), t->exception) or instanceOf (t, type(t, Machine::RuntimeExceptionType), t->exception))) { object exception = t->exception; t->exception = 0; PROTECT(t, exception); object paeClass = resolveClass (t, root(t, Machine::BootLoader), "java/security/PrivilegedActionException"); PROTECT(t, paeClass); object paeConstructor = resolveMethod (t, paeClass, "", "(Ljava/lang/Exception;)V"); PROTECT(t, paeConstructor); object result = make(t, paeClass); PROTECT(t, result); t->m->processor->invoke(t, paeConstructor, result, exception); t->exception = result; } } uint64_t jvmDoPrivileged(Thread* t, uintptr_t* arguments) { jobject action = reinterpret_cast(arguments[0]); jboolean wrapException = arguments[1]; // todo: cache these class and method lookups in the t->m->classpath // object: object privilegedAction = resolveClass (t, root(t, Machine::BootLoader), "java/security/PrivilegedAction"); object method; if (instanceOf(t, privilegedAction, *action)) { method = resolveMethod (t, privilegedAction, "run", "()Ljava/lang/Object;"); } else { object privilegedExceptionAction = resolveClass (t, root(t, Machine::BootLoader), "java/security/PrivilegedExceptionAction"); method = resolveMethod (t, privilegedExceptionAction, "run", "()Ljava/lang/Object;"); } THREAD_RESOURCE(t, jboolean, wrapException, maybeWrap(t, wrapException)); return reinterpret_cast (makeLocalReference(t, t->m->processor->invoke(t, method, *action))); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_DoPrivileged) (Thread* t, jclass, jobject action, jobject, jboolean wrapException) { uintptr_t arguments[] = { reinterpret_cast(action), wrapException }; return reinterpret_cast(run(t, jvmDoPrivileged, arguments)); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_GetInheritedAccessControlContext)(Thread*, jclass) { abort(); } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_GetStackAccessControlContext)(Thread*, jclass) { return 0; } extern "C" AVIAN_EXPORT void* JNICALL EXPORT(JVM_RegisterSignal)(jint, void*) { abort(); } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_RaiseSignal)(jint) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_FindSignal)(const char*) { return -1; } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_DesiredAssertionStatus)(Thread*, jclass, jclass) { return false; } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_AssertionStatusDirectives)(Thread*, jclass) { abort(); } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_SupportsCX8)() { return true; } extern "C" AVIAN_EXPORT const char* JNICALL EXPORT(JVM_GetClassNameUTF)(Thread*, jclass) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_GetClassCPTypes)(Thread*, jclass, unsigned char*) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetClassCPEntriesCount)(Thread*, jclass) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetClassFieldsCount)(Thread*, jclass) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetClassMethodsCount)(Thread*, jclass) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_GetMethodIxExceptionIndexes)(Thread*, jclass, jint, unsigned short*) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetMethodIxExceptionsCount)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_GetMethodIxByteCode)(Thread*, jclass, jint, unsigned char*) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetMethodIxByteCodeLength)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_GetMethodIxExceptionTableEntry)(Thread*, jclass, jint, jint, local::JVM_ExceptionTableEntryType*) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetMethodIxExceptionTableLength)(Thread*, jclass, int) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetFieldIxModifiers)(Thread*, jclass, int) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetMethodIxModifiers)(Thread*, jclass, int) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetMethodIxLocalsCount)(Thread*, jclass, int) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetMethodIxArgsSize)(Thread*, jclass, int) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetMethodIxMaxStack)(Thread*, jclass, int) { abort(); } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_IsConstructorIx)(Thread*, jclass, int) { abort(); } extern "C" AVIAN_EXPORT const char* JNICALL EXPORT(JVM_GetMethodIxNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT const char* JNICALL EXPORT(JVM_GetMethodIxSignatureUTF)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT const char* JNICALL EXPORT(JVM_GetCPFieldNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT const char* JNICALL EXPORT(JVM_GetCPMethodNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT const char* JNICALL EXPORT(JVM_GetCPMethodSignatureUTF)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT const char* JNICALL EXPORT(JVM_GetCPFieldSignatureUTF)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT const char* JNICALL EXPORT(JVM_GetCPClassNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT const char* JNICALL EXPORT(JVM_GetCPFieldClassNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT const char* JNICALL EXPORT(JVM_GetCPMethodClassNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetCPFieldModifiers)(Thread*, jclass, int, jclass) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetCPMethodModifiers)(Thread*, jclass, int, jclass) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_ReleaseUTF)(const char*) { abort(); } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_IsSameClassPackage)(Thread*, jclass, jclass) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetLastErrorString)(char* dst, int length) { strncpy(dst, strerror(errno), length); return strlen(dst); } extern "C" AVIAN_EXPORT char* JNICALL EXPORT(JVM_NativePath)(char* path) { return path; } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Open)(const char* path, jint flags, jint mode) { int r = OPEN(path, flags & 0xFFFF, mode); if (r == -1) { return errno == EEXIST ? JVM_EEXIST : -1; } else { return r; } } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Close)(jint fd) { return CLOSE(fd); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Read)(jint fd, char* dst, jint length) { return READ(fd, dst, length); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Write)(jint fd, char* src, jint length) { return WRITE(fd, src, length); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Available)(jint fd, jlong* result) { struct STAT buffer; int n; if (FSTAT(fd, &buffer) >= 0 and (S_ISCHR(buffer.st_mode) or S_ISFIFO(buffer.st_mode) or S_ISSOCK(buffer.st_mode)) and local::pipeAvailable(fd, &n)) { *result = n; return 1; } int current = LSEEK(fd, 0, SEEK_CUR); if (current == -1) return 0; int end = LSEEK(fd, 0, SEEK_END); if (end == -1) return 0; if (LSEEK(fd, current, SEEK_SET) == -1) return 0; *result = end - current; return 1; } extern "C" AVIAN_EXPORT jlong JNICALL EXPORT(JVM_Lseek)(jint fd, jlong offset, jint seek) { return LSEEK(fd, offset, seek); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_SetLength)(jint fd, jlong length) { #ifdef PLATFORM_WINDOWS HANDLE h = reinterpret_cast(_get_osfhandle(fd)); if (h == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } long high = length >> 32; DWORD r = SetFilePointer(h, static_cast(length), &high, FILE_BEGIN); if (r == 0xFFFFFFFF and GetLastError() != NO_ERROR) { errno = EIO; return -1; } if (SetEndOfFile(h)) { return 0; } else { errno = EIO; return -1; } #else return ftruncate(fd, length); #endif } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Sync)(jint fd) { #ifdef PLATFORM_WINDOWS HANDLE h = reinterpret_cast(_get_osfhandle(fd)); if (h == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } if (FlushFileBuffers(h)) { return 0; } else { errno = EIO; return -1; } #else return fsync(fd); #endif } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_InitializeSocketLibrary)() { #ifdef PLATFORM_WINDOWS static bool wsaInitialized = false; if (not wsaInitialized) { WSADATA data; int r = WSAStartup(MAKEWORD(2, 2), &data); if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) { return -1; } else { wsaInitialized = true; } } #endif return 0; } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Socket)(jint domain, jint type, jint protocol) { return socket(domain, type, protocol); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_SocketClose)(jint socket) { #ifdef PLATFORM_WINDOWS return closesocket(socket); #else return close(socket); #endif } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_SocketShutdown)(jint socket, jint how) { return shutdown(socket, how); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Recv)(jint socket, char* dst, jint count, jint flags) { return recv(socket, dst, count, flags); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Send)(jint socket, char* src, jint count, jint flags) { return send(socket, src, count, flags); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Timeout)(int, long) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Listen)(jint socket, jint count) { return listen(socket, count); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Connect)(jint socket, sockaddr* address, jint addressLength) { return connect(socket, address, addressLength); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Bind)(jint, struct sockaddr*, jint) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_Accept)(jint socket, struct sockaddr* address, jint* addressLength) { socklen_t length = *addressLength; int r = accept(socket, address, &length); *addressLength = length; return r; } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_RecvFrom)(jint, char*, int, int, struct sockaddr*, int*) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_SendTo)(jint, char*, int, int, struct sockaddr*, int) { abort(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_SocketAvailable)(jint socket, jint* count) { #ifdef PLATFORM_WINDOWS unsigned long c = *count; int r = ioctlsocket(socket, FIONREAD, &c); *count = c; return r; #else return ioctl(socket, FIONREAD, count) < 0 ? 0 : 1; #endif } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetSockName)(jint socket, struct sockaddr* address, int* addressLength) { socklen_t length = *addressLength; int r = getsockname(socket, address, &length); *addressLength = length; return r; } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_GetSockOpt)(jint socket, int level, int optionName, char* optionValue, int* optionLength) { socklen_t length = *optionLength; int rv = getsockopt(socket, level, optionName, optionValue, &length); *optionLength = length; return rv; } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_SetSockOpt)(jint socket, int level, int optionName, const char* optionValue, int optionLength) { return setsockopt(socket, level, optionName, optionValue, optionLength); } extern "C" AVIAN_EXPORT struct protoent* JNICALL EXPORT(JVM_GetProtoByName)(char*) { abort(); } extern "C" AVIAN_EXPORT struct hostent* JNICALL EXPORT(JVM_GetHostByAddr)(const char*, int, int) { abort(); } extern "C" AVIAN_EXPORT struct hostent* JNICALL EXPORT(JVM_GetHostByName)(char*) { abort(); } extern "C" AVIAN_EXPORT int JNICALL EXPORT(JVM_GetHostName)(char* name, int length) { return gethostname(name, length); } extern "C" AVIAN_EXPORT void* JNICALL EXPORT(JVM_RawMonitorCreate)(void) { System* s = local::globalMachine->system; System::Monitor* lock; if (s->success(s->make(&lock))) { return lock; } else { return 0; } } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_RawMonitorDestroy)(void* lock) { static_cast(lock)->dispose(); } extern "C" AVIAN_EXPORT jint JNICALL EXPORT(JVM_RawMonitorEnter)(void* lock) { static_cast(lock)->acquire (static_cast (local::globalMachine->localThread->get())->systemThread); return 0; } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_RawMonitorExit)(void* lock) { static_cast(lock)->release (static_cast (local::globalMachine->localThread->get())->systemThread); } int JNICALL GetVersion(Thread*) { return JMM_VERSION_1_0; } uint64_t getInputArgumentArray(Thread* t, uintptr_t*) { object array = makeObjectArray (t, type(t, Machine::StringType), t->m->argumentCount); PROTECT(t, array); for (unsigned i = 0; i < t->m->argumentCount; ++i) { object argument = makeString(t, t->m->arguments[i]); set(t, array, ArrayBody + (i * BytesPerWord), argument); } return reinterpret_cast(makeLocalReference(t, array)); } jobjectArray JNICALL GetInputArgumentArray(Thread* t) { return reinterpret_cast(run(t, getInputArgumentArray, 0)); } jint JNICALL GetOptionalSupport(Thread*, jmmOptionalSupport* support) { memset(support, 0, sizeof(jmmOptionalSupport)); return 0; } jlong JNICALL GetLongAttribute(Thread* t, jobject, jmmLongAttribute attribute) { const unsigned JMM_JVM_INIT_DONE_TIME_MS = 7; switch (attribute) { case JMM_JVM_INIT_DONE_TIME_MS: return 0; default: abort(t); } } jboolean JNICALL GetBoolAttribute(Thread* t, jmmBoolAttribute attribute) { const unsigned JMM_THREAD_CPU_TIME = 24; const unsigned JMM_THREAD_ALLOCATED_MEMORY = 25; switch (attribute) { case JMM_THREAD_CPU_TIME: case JMM_THREAD_ALLOCATED_MEMORY: return false; default: abort(t); } } uint64_t getMemoryManagers(Thread* t, uintptr_t*) { return reinterpret_cast (makeLocalReference (t, makeObjectArray (t, resolveClass (t, root(t, Machine::BootLoader), "java/lang/management/MemoryManagerMXBean"), 0))); } jobjectArray JNICALL GetMemoryManagers(Thread* t, jobject) { return reinterpret_cast(run(t, getMemoryManagers, 0)); } uint64_t getMemoryPools(Thread* t, uintptr_t*) { return reinterpret_cast (makeLocalReference (t, makeObjectArray (t, resolveClass (t, root(t, Machine::BootLoader), "java/lang/management/MemoryPoolMXBean"), 0))); } jobjectArray JNICALL GetMemoryPools(Thread* t, jobject) { return reinterpret_cast(run(t, getMemoryPools, 0)); } extern "C" AVIAN_EXPORT void* JNICALL EXPORT(JVM_GetManagement)(jint version) { if (version == JMM_VERSION_1_0) { JmmInterface* interface = &(static_cast (local::globalMachine->classpath)->jmmInterface); memset(interface, 0, sizeof(JmmInterface)); interface->GetVersion = GetVersion; interface->GetOptionalSupport = GetOptionalSupport; interface->GetLongAttribute = GetLongAttribute; interface->GetBoolAttribute = GetBoolAttribute; interface->GetMemoryManagers = GetMemoryManagers; interface->GetMemoryPools = GetMemoryPools; interface->GetInputArgumentArray = GetInputArgumentArray; return interface; } else { return 0; } } extern "C" AVIAN_EXPORT jobject JNICALL EXPORT(JVM_InitAgentProperties)(Thread*, jobject) { abort(); } uint64_t getEnclosingMethodInfo(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); object class_ = jclassVmClass(t, *c); PROTECT(t, class_); object addendum = classAddendum(t, class_); if (addendum) { object enclosingClass = classAddendumEnclosingClass(t, addendum); if (enclosingClass) { PROTECT(t, enclosingClass); object array = makeObjectArray(t, type(t, Machine::JobjectType), 3); PROTECT(t, array); enclosingClass = getJClass (t, resolveClass(t, classLoader(t, class_), enclosingClass)); set(t, array, ArrayBody, enclosingClass); object enclosingMethod = classAddendumEnclosingMethod(t, addendum); if (enclosingMethod) { PROTECT(t, enclosingMethod); object name = t->m->classpath->makeString (t, pairFirst(t, enclosingMethod), 0, byteArrayLength(t, pairFirst(t, enclosingMethod)) - 1); set(t, array, ArrayBody + BytesPerWord, name); object spec = t->m->classpath->makeString (t, pairSecond(t, enclosingMethod), 0, byteArrayLength(t, pairSecond(t, enclosingMethod)) - 1); set(t, array, ArrayBody + (2 * BytesPerWord), spec); } return reinterpret_cast(makeLocalReference(t, array)); } } return 0; } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetEnclosingMethodInfo)(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return reinterpret_cast (run(t, getEnclosingMethodInfo, arguments)); } extern "C" AVIAN_EXPORT jintArray JNICALL EXPORT(JVM_GetThreadStateValues)(JNIEnv*, jint) { abort(); } extern "C" AVIAN_EXPORT jobjectArray JNICALL EXPORT(JVM_GetThreadStateNames)(JNIEnv*, jint, jintArray) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_GetVersionInfo)(JNIEnv*, local::jvm_version_info* info, size_t size) { memset(info, 0, size); info->jvm_version = 0x01070000; } extern "C" AVIAN_EXPORT jboolean JNICALL EXPORT(JVM_CX8Field)(JNIEnv*, jobject*, jfieldID*, jlong, jlong) { abort(); } extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_SetNativeThreadName)(JNIEnv*, jobject, jstring) { abort(); } } // namespace local } // namespace extern "C" AVIAN_EXPORT int jio_vsnprintf(char* dst, size_t size, const char* format, va_list a) { return vm::vsnprintf(dst, size, format, a); } extern "C" AVIAN_EXPORT int jio_vfprintf(FILE* stream, const char* format, va_list a) { return vfprintf(stream, format, a); } #ifdef PLATFORM_WINDOWS extern "C" AVIAN_EXPORT void* JNICALL EXPORT(JVM_GetThreadInterruptEvent)() { // hack: We don't want to expose thread interruption implementation // details, so we give the class library a fake event to play with. // This means that threads won't be interruptable when blocked in // Process.waitFor. static HANDLE fake = 0; if (fake == 0) { fake = CreateEvent(0, true, false, 0); } return fake; } namespace { HMODULE jvmHandle = 0; } extern "C" int JDK_InitJvmHandle() { jvmHandle = GetModuleHandle(0); return jvmHandle != 0; } extern "C" void* JDK_FindJvmEntry(const char* name) { return voidPointer(GetProcAddress(jvmHandle, name)); } # ifdef AVIAN_OPENJDK_SRC extern "C" char* findJavaTZ_md(const char*, const char*); extern "C" AVIAN_EXPORT int64_t JNICALL Avian_java_util_TimeZone_getSystemTimeZoneID (Thread* t, object, uintptr_t* arguments) { // On Windows, findJavaTZ_md loads tzmappings from the filesystem // using fopen, so we have no opportunity to make it read straight // from the embedded JAR file as with files read from Java code. // Therefore, we must extract tzmappings to a temporary location // before calling findJavaTZ_md. We could avoid this by // implementing findJavaTZ_md ourselves from scratch, but that would // be a lot of code to implement and maintain. object country = reinterpret_cast(arguments[1]); THREAD_RUNTIME_ARRAY(t, char, countryChars, stringLength(t, country) + 1); stringChars(t, country, RUNTIME_ARRAY_BODY(countryChars)); local::MyClasspath* cp = static_cast(t->m->classpath); local::EmbeddedFile ef(cp, cp->tzMappings, cp->tzMappingsLength); if (ef.jar == 0 or ef.jarLength == 0 or ef.pathLength == 0) { return 0; } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder == 0) { return 0; } System::Region* r = finder->find(ef.path); if (r == 0) { return 0; } THREAD_RESOURCE(t, System::Region*, r, r->dispose()); char tmpPath[MAX_PATH + 1]; GetTempPathA(MAX_PATH, tmpPath); char tmpDir[MAX_PATH + 1]; vm::snprintf(tmpDir, MAX_PATH, "%s/avian-tmp", tmpPath); if (_mkdir(tmpDir) != 0 and errno != EEXIST) { return 0; } THREAD_RESOURCE(t, char*, tmpDir, rmdir(tmpDir)); char libDir[MAX_PATH + 1]; vm::snprintf(libDir, MAX_PATH, "%s/lib", tmpDir); if (mkdir(libDir) != 0 and errno != EEXIST) { return 0; } THREAD_RESOURCE(t, char*, libDir, rmdir(libDir)); char file[MAX_PATH + 1]; vm::snprintf(file, MAX_PATH, "%s/tzmappings", libDir); FILE* out = vm::fopen(file, "wb"); if (out == 0) { return 0; } THREAD_RESOURCE(t, char*, file, unlink(file)); THREAD_RESOURCE(t, FILE*, out, fclose(out)); if (fwrite(r->start(), 1, r->length(), out) != r->length() or fflush(out) != 0) { return 0; } char* javaTZ = findJavaTZ_md(tmpDir, RUNTIME_ARRAY_BODY(countryChars)); if (javaTZ) { THREAD_RESOURCE(t, char*, javaTZ, free(javaTZ)); return reinterpret_cast(makeString(t, "%s", javaTZ)); } else { return 0; } } # else // not AVIAN_OPENJDK_SRC extern "C" AVIAN_EXPORT int jio_snprintf(char* dst, size_t size, const char* format, ...) { va_list a; va_start(a, format); int r = jio_vsnprintf(dst, size, format, a); va_end(a); return r; } extern "C" AVIAN_EXPORT int jio_fprintf(FILE* stream, const char* format, ...) { va_list a; va_start(a, format); int r = jio_vfprintf(stream, format, a); va_end(a); return r; } # endif // not AVIAN_OPENJDK_SRC #endif // PLATFORM_WINDOWS ReadyTalk-avian-1e1fff5/src/codegen/000077500000000000000000000000001231440243200173535ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/codegen/compiler.cpp000066400000000000000000002060331231440243200216750ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include #include #include #include #include #include "codegen/compiler/regalloc.h" #include "codegen/compiler/context.h" #include "codegen/compiler/resource.h" #include "codegen/compiler/value.h" #include "codegen/compiler/site.h" #include "codegen/compiler/read.h" #include "codegen/compiler/event.h" #include "codegen/compiler/promise.h" #include "codegen/compiler/frame.h" #include "codegen/compiler/ir.h" using namespace vm; namespace avian { namespace codegen { namespace compiler { const bool DebugAppend = false; const bool DebugCompile = false; const bool DebugResources = false; const bool DebugFrame = false; const bool DebugControl = false; const bool DebugBuddies = false; const unsigned StealRegisterReserveCount = 2; // this should be equal to the largest number of registers used by a // compare instruction: const unsigned ResolveRegisterReserveCount = (TargetBytesPerWord == 8 ? 2 : 4); void apply(Context* c, lir::UnaryOperation op, unsigned s1Size, Site* s1Low, Site* s1High); void apply(Context* c, lir::BinaryOperation op, unsigned s1Size, Site* s1Low, Site* s1High, unsigned s2Size, Site* s2Low, Site* s2High); void apply(Context* c, lir::TernaryOperation op, unsigned s1Size, Site* s1Low, Site* s1High, unsigned s2Size, Site* s2Low, Site* s2High, unsigned s3Size, Site* s3Low, Site* s3High); class ConstantPoolNode { public: ConstantPoolNode(Promise* promise): promise(promise), next(0) { } Promise* promise; ConstantPoolNode* next; }; Read* live(Context* c UNUSED, Value* v) { assert(c, v->buddy->hasBuddy(c, v)); Value* p = v; do { if (valid(p->reads)) { return p->reads; } p = p->buddy; } while (p != v); return 0; } unsigned sitesToString(Context* c, Value* v, char* buffer, unsigned size); void deadWord(Context* c, Value* v) { Value* nextWord = v->nextWord; assert(c, nextWord != v); for (SiteIterator it(c, v, true, false); it.hasMore();) { Site* s = it.next(); if (s->registerSize(c) > TargetBytesPerWord) { it.remove(c); nextWord->addSite(c, s); } } } void deadBuddy(Context* c, Value* v, Read* r UNUSED) { assert(c, v->buddy != v); assert(c, r); if (DebugBuddies) { fprintf(stderr, "remove dead buddy %p from", v); for (Value* p = v->buddy; p != v; p = p->buddy) { fprintf(stderr, " %p", p); } fprintf(stderr, "\n"); } assert(c, v->buddy); Value* next = v->buddy; v->buddy = v; Value* p = next; while (p->buddy != v) p = p->buddy; p->buddy = next; assert(c, p->buddy); for (SiteIterator it(c, v, false, false); it.hasMore();) { Site* s = it.next(); it.remove(c); next->addSite(c, s); } } void popRead(Context* c, Event* e UNUSED, Value* v) { assert(c, e == v->reads->event); if (DebugReads) { fprintf(stderr, "pop read %p from %p next %p event %p (%s)\n", v->reads, v, v->reads->next(c), e, (e ? e->name() : 0)); } v->reads = v->reads->next(c); if (not valid(v->reads)) { Value* nextWord = v->nextWord; if (nextWord != v) { if (valid(nextWord->reads)) { deadWord(c, v); } else { deadWord(c, nextWord); } } Read* r = live(c, v); if (r) { deadBuddy(c, v, r); } else { v->clearSites(c); } } } void addBuddy(Value* original, Value* buddy) { buddy->buddy = original; Value* p = original; while (p->buddy != original) p = p->buddy; p->buddy = buddy; if (DebugBuddies) { fprintf(stderr, "add buddy %p to", buddy); for (Value* p = buddy->buddy; p != buddy; p = p->buddy) { fprintf(stderr, " %p", p); } fprintf(stderr, "\n"); } } lir::ValueType valueType(Context* c, Compiler::OperandType type) { switch (type) { case Compiler::ObjectType: case Compiler::AddressType: case Compiler::IntegerType: case Compiler::VoidType: return lir::ValueGeneral; case Compiler::FloatType: return lir::ValueFloat; default: abort(c); } } void move(Context* c, Value* value, Site* src, Site* dst); unsigned sitesToString(Context* c, Site* sites, char* buffer, unsigned size) { unsigned total = 0; for (Site* s = sites; s; s = s->next) { total += s->toString(c, buffer + total, size - total); if (s->next) { assert(c, size > total + 2); memcpy(buffer + total, ", ", 2); total += 2; } } assert(c, size > total); buffer[total] = 0; return total; } unsigned sitesToString(Context* c, Value* v, char* buffer, unsigned size) { unsigned total = 0; Value* p = v; do { if (total) { assert(c, size > total + 2); memcpy(buffer + total, "; ", 2); total += 2; } if (p->sites) { total += vm::snprintf(buffer + total, size - total, "%p has ", p); total += sitesToString(c, p->sites, buffer + total, size - total); } else { total += vm::snprintf(buffer + total, size - total, "%p has nothing", p); } p = p->buddy; } while (p != v); return total; } Site* pickTargetSite(Context* c, Read* read, bool intersectRead = false, unsigned registerReserveCount = 0, CostCalculator* costCalculator = 0) { Target target (pickTarget (c, read, intersectRead, registerReserveCount, costCalculator)); expect(c, target.cost < Target::Impossible); if (target.type == lir::MemoryOperand) { return frameSite(c, target.index); } else { return registerSite(c, target.index); } } bool acceptMatch(Context* c, Site* s, Read*, const SiteMask& mask) { return s->match(c, mask); } Site* pickSourceSite(Context* c, Read* read, Site* target = 0, unsigned* cost = 0, SiteMask* extraMask = 0, bool intersectRead = true, bool includeBuddies = true, bool includeNextWord = true, bool (*accept)(Context*, Site*, Read*, const SiteMask&) = acceptMatch) { SiteMask mask; if (extraMask) { mask = mask.intersectionWith(*extraMask); } if (intersectRead) { read->intersect(&mask); } Site* site = 0; unsigned copyCost = 0xFFFFFFFF; for (SiteIterator it(c, read->value, includeBuddies, includeNextWord); it.hasMore();) { Site* s = it.next(); if (accept(c, s, read, mask)) { unsigned v = s->copyCost(c, target); if (v < copyCost) { site = s; copyCost = v; } } } if (DebugMoves and site and target) { char srcb[256]; site->toString(c, srcb, 256); char dstb[256]; target->toString(c, dstb, 256); fprintf(stderr, "pick source %s to %s for %p cost %d\n", srcb, dstb, read->value, copyCost); } if (cost) *cost = copyCost; return site; } Site* maybeMove(Context* c, Read* read, bool intersectRead, bool includeNextWord, unsigned registerReserveCount = 0) { Value* value = read->value; unsigned size = value == value->nextWord ? TargetBytesPerWord : 8; class MyCostCalculator: public CostCalculator { public: MyCostCalculator(Value* value, unsigned size, bool includeNextWord): value(value), size(size), includeNextWord(includeNextWord) { } virtual unsigned cost(Context* c, SiteMask dstMask) { OperandMask src; OperandMask tmp; c->arch->planMove (size, src, tmp, OperandMask(dstMask.typeMask, dstMask.registerMask)); SiteMask srcMask = SiteMask::lowPart(src); for (SiteIterator it(c, value, true, includeNextWord); it.hasMore();) { Site* s = it.next(); if (s->match(c, srcMask) or s->match(c, dstMask)) { return 0; } } return Target::IndirectMovePenalty; } Value* value; unsigned size; bool includeNextWord; } costCalculator(value, size, includeNextWord); Site* dstSite = pickTargetSite (c, read, intersectRead, registerReserveCount, &costCalculator); OperandMask src; OperandMask tmp; c->arch->planMove (size, src, tmp, OperandMask(1 << dstSite->type(c), dstSite->registerMask(c))); SiteMask srcMask = SiteMask::lowPart(src); unsigned cost = 0xFFFFFFFF; Site* srcSite = 0; for (SiteIterator it(c, value, true, includeNextWord); it.hasMore();) { Site* s = it.next(); unsigned v = s->copyCost(c, dstSite); if (v == 0) { srcSite = s; cost = 0; break; } if (not s->match(c, srcMask)) { v += CopyPenalty; } if (v < cost) { srcSite = s; cost = v; } } if (cost) { if (DebugMoves) { char srcb[256]; srcSite->toString(c, srcb, 256); char dstb[256]; dstSite->toString(c, dstb, 256); fprintf(stderr, "maybe move %s to %s for %p to %p\n", srcb, dstb, value, value); } srcSite->freeze(c, value); value->addSite(c, dstSite); srcSite->thaw(c, value); if (not srcSite->match(c, srcMask)) { srcSite->freeze(c, value); dstSite->freeze(c, value); SiteMask tmpMask = SiteMask::lowPart(tmp); SingleRead tmpRead(tmpMask, 0); tmpRead.value = value; tmpRead.successor_ = value; Site* tmpSite = pickTargetSite(c, &tmpRead, true); value->addSite(c, tmpSite); move(c, value, srcSite, tmpSite); dstSite->thaw(c, value); srcSite->thaw(c, value); srcSite = tmpSite; } move(c, value, srcSite, dstSite); } return dstSite; } Site* maybeMove(Context* c, Value* v, const SiteMask& mask, bool intersectMask, bool includeNextWord, unsigned registerReserveCount = 0) { SingleRead read(mask, 0); read.value = v; read.successor_ = v; return maybeMove (c, &read, intersectMask, includeNextWord, registerReserveCount); } Site* pickSiteOrMove(Context* c, Read* read, bool intersectRead, bool includeNextWord, unsigned registerReserveCount = 0) { Site* s = pickSourceSite (c, read, 0, 0, 0, intersectRead, true, includeNextWord); if (s) { return s; } else { return maybeMove (c, read, intersectRead, includeNextWord, registerReserveCount); } } Site* pickSiteOrMove(Context* c, Value* v, const SiteMask& mask, bool intersectMask, bool includeNextWord, unsigned registerReserveCount = 0) { SingleRead read(mask, 0); read.value = v; read.successor_ = v; return pickSiteOrMove (c, &read, intersectMask, includeNextWord, registerReserveCount); } void steal(Context* c, Resource* r, Value* thief) { if (DebugResources) { char resourceBuffer[256]; r->toString(c, resourceBuffer, 256); char siteBuffer[1024]; sitesToString(c, r->value, siteBuffer, 1024); fprintf(stderr, "%p steal %s from %p (%s)\n", thief, resourceBuffer, r->value, siteBuffer); } if ((not (thief and thief->isBuddyOf(r->value)) and r->value->uniqueSite(c, r->site))) { r->site->freeze(c, r->value); maybeMove(c, live(c, r->value), false, true, StealRegisterReserveCount); r->site->thaw(c, r->value); } r->value->removeSite(c, r->site); } SiteMask generalRegisterMask(Context* c) { return SiteMask (1 << lir::RegisterOperand, c->regFile->generalRegisters.mask, NoFrameIndex); } SiteMask generalRegisterOrConstantMask(Context* c) { return SiteMask ((1 << lir::RegisterOperand) | (1 << lir::ConstantOperand), c->regFile->generalRegisters.mask, NoFrameIndex); } MultiRead* multiRead(Context* c) { return new(c->zone) MultiRead; } StubRead* stubRead(Context* c) { return new(c->zone) StubRead; } Site* pickSite(Context* c, Value* v, Site* s, unsigned index, bool includeNextWord) { for (SiteIterator it(c, v, true, includeNextWord); it.hasMore();) { Site* candidate = it.next(); if (s->matchNextWord(c, candidate, index)) { return candidate; } } return 0; } Site* pickSiteOrMove(Context* c, Value* v, Site* s, unsigned index) { Site* n = pickSite(c, v, s, index, false); if (n) { return n; } return maybeMove(c, v, s->nextWordMask(c, index), true, false); } Site* pickSiteOrMove(Context* c, Value* v, Site* s, Site** low, Site** high) { if (v->wordIndex == 0) { *low = s; *high = pickSiteOrMove(c, v->nextWord, s, 1); return *high; } else { *low = pickSiteOrMove(c, v->nextWord, s, 0); *high = s; return *low; } } Site* pickSiteOrGrow(Context* c, Value* v, Site* s, unsigned index) { Site* n = pickSite(c, v, s, index, false); if (n) { return n; } n = s->makeNextWord(c, index); v->addSite(c, n); return n; } Site* pickSiteOrGrow(Context* c, Value* v, Site* s, Site** low, Site** high) { if (v->wordIndex == 0) { *low = s; *high = pickSiteOrGrow(c, v->nextWord, s, 1); return *high; } else { *low = pickSiteOrGrow(c, v->nextWord, s, 0); *high = s; return *low; } } bool isHome(Value* v, int frameIndex) { Value* p = v; do { if (p->home == frameIndex) { return true; } p = p->buddy; } while (p != v); return false; } bool acceptForResolve(Context* c, Site* s, Read* read, const SiteMask& mask) { if (acceptMatch(c, s, read, mask) and (not s->frozen(c))) { if (s->type(c) == lir::RegisterOperand) { return c->availableGeneralRegisterCount > ResolveRegisterReserveCount; } else { assert(c, s->match(c, SiteMask(1 << lir::MemoryOperand, 0, AnyFrameIndex))); return isHome(read->value, offsetToFrameIndex (c, static_cast(s)->offset)); } } else { return false; } } void move(Context* c, Value* value, Site* src, Site* dst) { if (DebugMoves) { char srcb[256]; src->toString(c, srcb, 256); char dstb[256]; dst->toString(c, dstb, 256); fprintf(stderr, "move %s to %s for %p to %p\n", srcb, dstb, value, value); } assert(c, value->findSite(dst)); src->freeze(c, value); dst->freeze(c, value); unsigned srcSize; unsigned dstSize; if (value->nextWord == value) { srcSize = TargetBytesPerWord; dstSize = TargetBytesPerWord; } else { srcSize = src->registerSize(c); dstSize = dst->registerSize(c); } if (srcSize == dstSize) { apply(c, lir::Move, srcSize, src, src, dstSize, dst, dst); } else if (srcSize > TargetBytesPerWord) { Site* low, *high, *other = pickSiteOrGrow(c, value, dst, &low, &high); other->freeze(c, value->nextWord); apply(c, lir::Move, srcSize, src, src, srcSize, low, high); other->thaw(c, value->nextWord); } else { Site* low, *high, *other = pickSiteOrMove(c, value, src, &low, &high); other->freeze(c, value->nextWord); apply(c, lir::Move, dstSize, low, high, dstSize, dst, dst); other->thaw(c, value->nextWord); } dst->thaw(c, value); src->thaw(c, value); } void asAssemblerOperand(Context* c, Site* low, Site* high, lir::Operand* result) { low->asAssemblerOperand(c, high, result); } class OperandUnion: public lir::Operand { public: // must be large enough and aligned properly to hold any operand // type (we'd use an actual union type here, except that classes // with constructors cannot be used in a union): uintptr_t padding[4]; }; void apply(Context* c, lir::UnaryOperation op, unsigned s1Size, Site* s1Low, Site* s1High) { assert(c, s1Low->type(c) == s1High->type(c)); lir::OperandType s1Type = s1Low->type(c); OperandUnion s1Union; asAssemblerOperand(c, s1Low, s1High, &s1Union); c->assembler->apply(op, OperandInfo(s1Size, s1Type, &s1Union)); } void apply(Context* c, lir::BinaryOperation op, unsigned s1Size, Site* s1Low, Site* s1High, unsigned s2Size, Site* s2Low, Site* s2High) { assert(c, s1Low->type(c) == s1High->type(c)); assert(c, s2Low->type(c) == s2High->type(c)); lir::OperandType s1Type = s1Low->type(c); OperandUnion s1Union; asAssemblerOperand(c, s1Low, s1High, &s1Union); lir::OperandType s2Type = s2Low->type(c); OperandUnion s2Union; asAssemblerOperand(c, s2Low, s2High, &s2Union); c->assembler->apply(op, OperandInfo(s1Size, s1Type, &s1Union), OperandInfo(s2Size, s2Type, &s2Union)); } void apply(Context* c, lir::TernaryOperation op, unsigned s1Size, Site* s1Low, Site* s1High, unsigned s2Size, Site* s2Low, Site* s2High, unsigned s3Size, Site* s3Low, Site* s3High) { assert(c, s1Low->type(c) == s1High->type(c)); assert(c, s2Low->type(c) == s2High->type(c)); assert(c, s3Low->type(c) == s3High->type(c)); lir::OperandType s1Type = s1Low->type(c); OperandUnion s1Union; asAssemblerOperand(c, s1Low, s1High, &s1Union); lir::OperandType s2Type = s2Low->type(c); OperandUnion s2Union; asAssemblerOperand(c, s2Low, s2High, &s2Union); lir::OperandType s3Type = s3Low->type(c); OperandUnion s3Union; asAssemblerOperand(c, s3Low, s3High, &s3Union); c->assembler->apply(op, OperandInfo(s1Size, s1Type, &s1Union), OperandInfo(s2Size, s2Type, &s2Union), OperandInfo(s3Size, s3Type, &s3Union)); } void append(Context* c, Event* e); void saveLocals(Context* c, Event* e) { for (unsigned li = 0; li < c->localFootprint; ++li) { Local* local = e->localsBefore + li; if (local->value) { if (DebugReads) { fprintf(stderr, "local save read %p at %d of %d\n", local->value, compiler::frameIndex(c, li), totalFrameSize(c)); } e->addRead(c, local->value, SiteMask (1 << lir::MemoryOperand, 0, compiler::frameIndex(c, li))); } } } void maybeMove(Context* c, lir::BinaryOperation type, unsigned srcSize, unsigned srcSelectSize, Value* srcValue, unsigned dstSize, Value* dstValue, const SiteMask& dstMask) { Read* read = live(c, dstValue); bool isStore = read == 0; Site* target; if (dstValue->target) { target = dstValue->target; } else if (isStore) { return; } else { target = pickTargetSite(c, read); } unsigned cost = srcValue->source->copyCost(c, target); if (srcSelectSize < dstSize) cost = 1; if (cost) { // todo: let c->arch->planMove decide this: bool useTemporary = ((target->type(c) == lir::MemoryOperand and srcValue->source->type(c) == lir::MemoryOperand) or (srcSelectSize < dstSize and target->type(c) != lir::RegisterOperand)); srcValue->source->freeze(c, srcValue); dstValue->addSite(c, target); srcValue->source->thaw(c, srcValue); bool addOffset = srcSize != srcSelectSize and c->arch->bigEndian() and srcValue->source->type(c) == lir::MemoryOperand; if (addOffset) { static_cast(srcValue->source)->offset += (srcSize - srcSelectSize); } target->freeze(c, dstValue); if (target->match(c, dstMask) and not useTemporary) { if (DebugMoves) { char srcb[256]; srcValue->source->toString(c, srcb, 256); char dstb[256]; target->toString(c, dstb, 256); fprintf(stderr, "move %s to %s for %p to %p\n", srcb, dstb, srcValue, dstValue); } srcValue->source->freeze(c, srcValue); apply(c, type, min(srcSelectSize, dstSize), srcValue->source, srcValue->source, dstSize, target, target); srcValue->source->thaw(c, srcValue); } else { // pick a temporary register which is valid as both a // destination and a source for the moves we need to perform: dstValue->removeSite(c, target); bool thunk; OperandMask src; c->arch->planSource(type, dstSize, src, dstSize, &thunk); if (srcValue->type == lir::ValueGeneral) { src.registerMask &= c->regFile->generalRegisters.mask; } assert(c, thunk == 0); assert(c, dstMask.typeMask & src.typeMask & (1 << lir::RegisterOperand)); Site* tmpTarget = freeRegisterSite (c, dstMask.registerMask & src.registerMask); srcValue->source->freeze(c, srcValue); dstValue->addSite(c, tmpTarget); tmpTarget->freeze(c, dstValue); if (DebugMoves) { char srcb[256]; srcValue->source->toString(c, srcb, 256); char dstb[256]; tmpTarget->toString(c, dstb, 256); fprintf(stderr, "move %s to %s for %p to %p\n", srcb, dstb, srcValue, dstValue); } apply(c, type, srcSelectSize, srcValue->source, srcValue->source, dstSize, tmpTarget, tmpTarget); tmpTarget->thaw(c, dstValue); srcValue->source->thaw(c, srcValue); if (useTemporary or isStore) { if (DebugMoves) { char srcb[256]; tmpTarget->toString(c, srcb, 256); char dstb[256]; target->toString(c, dstb, 256); fprintf(stderr, "move %s to %s for %p to %p\n", srcb, dstb, srcValue, dstValue); } dstValue->addSite(c, target); tmpTarget->freeze(c, dstValue); apply(c, lir::Move, dstSize, tmpTarget, tmpTarget, dstSize, target, target); tmpTarget->thaw(c, dstValue); if (isStore) { dstValue->removeSite(c, tmpTarget); } } } target->thaw(c, dstValue); if (addOffset) { static_cast(srcValue->source)->offset -= (srcSize - srcSelectSize); } } else { target = srcValue->source; if (DebugMoves) { char dstb[256]; target->toString(c, dstb, 256); fprintf(stderr, "null move in %s for %p to %p\n", dstb, srcValue, dstValue); } } if (isStore) { dstValue->removeSite(c, target); } } Site* pickMatchOrMove(Context* c, Read* r, Site* nextWord, unsigned index, bool intersectRead) { Site* s = pickSite(c, r->value, nextWord, index, true); SiteMask mask; if (intersectRead) { r->intersect(&mask); } if (s and s->match(c, mask)) { return s; } return pickSiteOrMove (c, r->value, mask.intersectionWith(nextWord->nextWordMask(c, index)), true, true); } Site* pickSiteOrMove(Context* c, Value* src, Value* dst, Site* nextWord, unsigned index) { if (live(c, dst)) { Read* read = live(c, src); Site* s; if (nextWord) { s = pickMatchOrMove(c, read, nextWord, index, false); } else { s = pickSourceSite(c, read, 0, 0, 0, false, true, true); if (s == 0 or s->isVolatile(c)) { s = maybeMove(c, read, false, true); } } assert(c, s); addBuddy(src, dst); if (src->source->isVolatile(c)) { src->removeSite(c, src->source); } return s; } else { return 0; } } ConstantSite* findConstantSite(Context* c, Value* v); Site* getTarget(Context* c, Value* value, Value* result, const SiteMask& resultMask); void freezeSource(Context* c, unsigned size, Value* v); void thawSource(Context* c, unsigned size, Value* v); void removeBuddy(Context* c, Value* v) { if (v->buddy != v) { if (DebugBuddies) { fprintf(stderr, "remove buddy %p from", v); for (Value* p = v->buddy; p != v; p = p->buddy) { fprintf(stderr, " %p", p); } fprintf(stderr, "\n"); } assert(c, v->buddy); Value* next = v->buddy; v->buddy = v; Value* p = next; while (p->buddy != v) p = p->buddy; p->buddy = next; assert(c, p->buddy); if (not live(c, next)) { next->clearSites(c); } if (not live(c, v)) { v->clearSites(c); } } } Site* copy(Context* c, Site* s) { Site* start = 0; Site* end = 0; for (; s; s = s->next) { Site* n = s->copy(c); if (end) { end->next = n; } else { start = n; } end = n; } return start; } class Snapshot { public: Snapshot(Context* c, Value* value, Snapshot* next): value(value), buddy(value->buddy), sites(copy(c, value->sites)), next(next) { } Value* value; Value* buddy; Site* sites; Snapshot* next; }; Snapshot* snapshot(Context* c, Value* value, Snapshot* next) { if (DebugControl) { char buffer[256]; sitesToString(c, value->sites, buffer, 256); fprintf(stderr, "snapshot %p buddy %p sites %s\n", value, value->buddy, buffer); } return new(c->zone) Snapshot(c, value, next); } Snapshot* makeSnapshots(Context* c, Value* value, Snapshot* next) { next = snapshot(c, value, next); for (Value* p = value->buddy; p != value; p = p->buddy) { next = snapshot(c, p, next); } return next; } Value* maybeBuddy(Context* c, Value* v); Value* pushWord(Context* c, Value* v) { if (v) { v = maybeBuddy(c, v); } Stack* s = stack(c, v, c->stack); if (DebugFrame) { fprintf(stderr, "push %p\n", v); } if (v) { v->home = frameIndex(c, s->index + c->localFootprint); } c->stack = s; return v; } void push(Context* c, unsigned footprint, Value* v) { assert(c, footprint); bool bigEndian = c->arch->bigEndian(); Value* low = v; if (bigEndian) { v = pushWord(c, v); } Value* high; if (footprint > 1) { assert(c, footprint == 2); if (TargetBytesPerWord == 4) { low->maybeSplit(c); high = pushWord(c, low->nextWord); } else { high = pushWord(c, 0); } } else { high = 0; } if (not bigEndian) { v = pushWord(c, v); } if (high) { v->nextWord = high; high->nextWord = v; high->wordIndex = 1; } } void popWord(Context* c) { Stack* s = c->stack; assert(c, s->value == 0 or s->value->home >= 0); if (DebugFrame) { fprintf(stderr, "pop %p\n", s->value); } c->stack = s->next; } Value* pop(Context* c, unsigned footprint) { assert(c, footprint); Stack* s = 0; bool bigEndian = c->arch->bigEndian(); if (not bigEndian) { s = c->stack; } if (footprint > 1) { assert(c, footprint == 2); #ifndef NDEBUG Stack* low; Stack* high; if (bigEndian) { high = c->stack; low = high->next; } else { low = c->stack; high = low->next; } assert(c, (TargetBytesPerWord == 8 and low->value->nextWord == low->value and high->value == 0) or (TargetBytesPerWord == 4 and low->value->nextWord == high->value)); #endif // not NDEBUG popWord(c); } if (bigEndian) { s = c->stack; } popWord(c); return s->value; } Value* storeLocal(Context* c, unsigned footprint, Value* v, unsigned index, bool copy) { assert(c, index + footprint <= c->localFootprint); if (copy) { unsigned sizeInBytes = sizeof(Local) * c->localFootprint; Local* newLocals = static_cast(c->zone->allocate(sizeInBytes)); memcpy(newLocals, c->locals, sizeInBytes); c->locals = newLocals; } Value* high; if (footprint > 1) { assert(c, footprint == 2); unsigned highIndex; unsigned lowIndex; if (c->arch->bigEndian()) { highIndex = index + 1; lowIndex = index; } else { lowIndex = index + 1; highIndex = index; } if (TargetBytesPerWord == 4) { assert(c, v->nextWord != v); high = storeLocal(c, 1, v->nextWord, highIndex, false); } else { high = 0; } index = lowIndex; } else { high = 0; } v = maybeBuddy(c, v); if (high != 0) { v->nextWord = high; high->nextWord = v; high->wordIndex = 1; } Local* local = c->locals + index; local->value = v; if (DebugFrame) { fprintf(stderr, "store local %p at %d\n", local->value, index); } local->value->home = frameIndex(c, index); return v; } Value* loadLocal(Context* c, unsigned footprint, unsigned index) { assert(c, index + footprint <= c->localFootprint); if (footprint > 1) { assert(c, footprint == 2); if (not c->arch->bigEndian()) { ++ index; } } assert(c, c->locals[index].value); assert(c, c->locals[index].value->home >= 0); if (DebugFrame) { fprintf(stderr, "load local %p at %d\n", c->locals[index].value, index); } return c->locals[index].value; } Value* register_(Context* c, int number) { assert(c, (1 << number) & (c->regFile->generalRegisters.mask | c->regFile->floatRegisters.mask)); Site* s = registerSite(c, number); lir::ValueType type = ((1 << number) & c->regFile->floatRegisters.mask) ? lir::ValueFloat: lir::ValueGeneral; return value(c, type, s, s); } unsigned frameFootprint(Context* c, Stack* s) { return c->localFootprint + (s ? (s->index + 1) : 0); } void visit(Context* c, Link* link) { // fprintf(stderr, "visit link from %d to %d fork %p junction %p\n", // link->predecessor->logicalInstruction->index, // link->successor->logicalInstruction->index, // link->forkState, // link->junctionState); ForkState* forkState = link->forkState; if (forkState) { for (unsigned i = 0; i < forkState->readCount; ++i) { ForkElement* p = forkState->elements + i; Value* v = p->value; v->reads = p->read->nextTarget(); // fprintf(stderr, "next read %p for %p from %p\n", v->reads, v, p->read); if (not live(c, v)) { v->clearSites(c); } } } JunctionState* junctionState = link->junctionState; if (junctionState) { for (unsigned i = 0; i < junctionState->frameFootprint; ++i) { StubReadPair* p = junctionState->reads + i; if (p->value and p->value->reads) { assert(c, p->value->reads == p->read); popRead(c, 0, p->value); } } } } class BuddyEvent: public Event { public: BuddyEvent(Context* c, Value* original, Value* buddy): Event(c), original(original), buddy(buddy) { this->addRead(c, original, SiteMask(~0, ~0, AnyFrameIndex), buddy); } virtual const char* name() { return "BuddyEvent"; } virtual void compile(Context* c) { if (DebugBuddies) { fprintf(stderr, "original %p buddy %p\n", original, buddy); } assert(c, original->hasSite(c)); assert(c, original); assert(c, buddy); addBuddy(original, buddy); popRead(c, this, original); } Value* original; Value* buddy; }; void appendBuddy(Context* c, Value* original, Value* buddy) { append(c, new(c->zone) BuddyEvent(c, original, buddy)); } void append(Context* c, Event* e) { LogicalInstruction* i = c->logicalCode[c->logicalIp]; if (c->stack != i->stack or c->locals != i->locals) { appendDummy(c); } if (DebugAppend) { fprintf(stderr, " -- append %s at %d with %d stack before\n", e->name(), e->logicalInstruction->index, c->stack ? c->stack->index + 1 : 0); } if (c->lastEvent) { c->lastEvent->next = e; } else { c->firstEvent = e; } c->lastEvent = e; Event* p = c->predecessor; if (p) { if (DebugAppend) { fprintf(stderr, "%d precedes %d\n", p->logicalInstruction->index, e->logicalInstruction->index); } Link* link = compiler::link (c, p, e->predecessors, e, p->successors, c->forkState); e->predecessors = link; p->successors = link; } c->forkState = 0; c->predecessor = e; if (e->logicalInstruction->firstEvent == 0) { e->logicalInstruction->firstEvent = e; } e->logicalInstruction->lastEvent = e; } Site* readSource(Context* c, Read* r) { Value* v = r->value; if (DebugReads) { char buffer[1024]; sitesToString(c, v, buffer, 1024); fprintf(stderr, "read source for %p from %s\n", v, buffer); } if (not v->hasSite(c)) { if (DebugReads) { fprintf(stderr, "no sites found for %p\n", v); } return 0; } Value* high = r->high(c); if (high) { return pickMatchOrMove(c, r, high->source, 0, true); } else { return pickSiteOrMove(c, r, true, true); } } void propagateJunctionSites(Context* c, Event* e, Site** sites) { for (Link* pl = e->predecessors; pl; pl = pl->nextPredecessor) { Event* p = pl->predecessor; if (p->junctionSites == 0) { p->junctionSites = sites; for (Link* sl = p->successors; sl; sl = sl->nextSuccessor) { Event* s = sl->successor; propagateJunctionSites(c, s, sites); } } } } void propagateJunctionSites(Context* c, Event* e) { for (Link* sl = e->successors; sl; sl = sl->nextSuccessor) { Event* s = sl->successor; if (s->predecessors->nextPredecessor) { unsigned size = sizeof(Site*) * frameFootprint(c, e->stackAfter); Site** junctionSites = static_cast (c->zone->allocate(size)); memset(junctionSites, 0, size); propagateJunctionSites(c, s, junctionSites); break; } } } class SiteRecord { public: Site* site; Value* value; }; void init(SiteRecord* r, Site* s, Value* v) { r->site = s; r->value = v; } class SiteRecordList { public: SiteRecordList(SiteRecord* records, unsigned capacity): records(records), index(0), capacity(capacity) { } SiteRecord* records; unsigned index; unsigned capacity; }; void freeze(Context* c, SiteRecordList* frozen, Site* s, Value* v) { assert(c, frozen->index < frozen->capacity); s->freeze(c, v); init(new (frozen->records + (frozen->index ++)) SiteRecord, s, v); } void thaw(Context* c, SiteRecordList* frozen) { while (frozen->index) { SiteRecord* sr = frozen->records + (-- frozen->index); sr->site->thaw(c, sr->value); } } bool resolveOriginalSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites) { bool complete = true; for (FrameIterator it(c, e->stackAfter, e->localsAfter, true); it.hasMore();) { FrameIterator::Element el = it.next(c); Value* v = el.value; Read* r = v ? live(c, v) : 0; Site* s = sites[el.localIndex]; if (r) { if (s) { if (DebugControl) { char buffer[256]; s->toString(c, buffer, 256); fprintf(stderr, "resolve original %s for %p local %d frame %d\n", buffer, v, el.localIndex, el.frameIndex(c)); } Site* target = pickSiteOrMove (c, v, s->mask(c), true, true, ResolveRegisterReserveCount); freeze(c, frozen, target, v); } else { complete = false; } } else if (s) { if (DebugControl) { char buffer[256]; s->toString(c, buffer, 256); fprintf(stderr, "freeze original %s for %p local %d frame %d\n", buffer, v, el.localIndex, el.frameIndex(c)); } Value dummy(0, 0, lir::ValueGeneral); dummy.addSite(c, s); dummy.removeSite(c, s); freeze(c, frozen, s, 0); } } return complete; } bool resolveSourceSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites) { bool complete = true; for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { FrameIterator::Element el = it.next(c); Value* v = el.value; Read* r = live(c, v); if (r and sites[el.localIndex] == 0) { SiteMask mask((1 << lir::RegisterOperand) | (1 << lir::MemoryOperand), c->regFile->generalRegisters.mask, AnyFrameIndex); Site* s = pickSourceSite (c, r, 0, 0, &mask, true, false, true, acceptForResolve); if (s) { if (DebugControl) { char buffer[256]; s->toString(c, buffer, 256); fprintf(stderr, "resolve source %s from %p local %d frame %d\n", buffer, v, el.localIndex, el.frameIndex(c)); } freeze(c, frozen, s, v); sites[el.localIndex] = s->copy(c); } else { complete = false; } } } return complete; } void resolveTargetSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites) { for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { FrameIterator::Element el = it.next(c); Value* v = el.value; Read* r = live(c, v); if (r and sites[el.localIndex] == 0) { SiteMask mask((1 << lir::RegisterOperand) | (1 << lir::MemoryOperand), c->regFile->generalRegisters.mask, AnyFrameIndex); Site* s = pickSourceSite (c, r, 0, 0, &mask, false, true, true, acceptForResolve); if (s == 0) { s = maybeMove(c, v, mask, false, true, ResolveRegisterReserveCount); } freeze(c, frozen, s, v); sites[el.localIndex] = s->copy(c); if (DebugControl) { char buffer[256]; sites[el.localIndex]->toString(c, buffer, 256); fprintf(stderr, "resolve target %s for %p local %d frame %d\n", buffer, el.value, el.localIndex, el.frameIndex(c)); } } } } void resolveJunctionSites(Context* c, Event* e, SiteRecordList* frozen) { bool complete; if (e->junctionSites) { complete = resolveOriginalSites(c, e, frozen, e->junctionSites); } else { propagateJunctionSites(c, e); complete = false; } if (e->junctionSites) { if (not complete) { complete = resolveSourceSites(c, e, frozen, e->junctionSites); if (not complete) { resolveTargetSites(c, e, frozen, e->junctionSites); } } if (DebugControl) { fprintf(stderr, "resolved junction sites %p at %d\n", e->junctionSites, e->logicalInstruction->index); } } } void resolveBranchSites(Context* c, Event* e, SiteRecordList* frozen) { if (e->successors->nextSuccessor and e->junctionSites == 0) { unsigned footprint = frameFootprint(c, e->stackAfter); RUNTIME_ARRAY(Site*, branchSites, footprint); memset(RUNTIME_ARRAY_BODY(branchSites), 0, sizeof(Site*) * footprint); if (not resolveSourceSites(c, e, frozen, RUNTIME_ARRAY_BODY(branchSites))) { resolveTargetSites(c, e, frozen, RUNTIME_ARRAY_BODY(branchSites)); } } } void captureBranchSnapshots(Context* c, Event* e) { if (e->successors->nextSuccessor) { for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { FrameIterator::Element el = it.next(c); e->snapshots = makeSnapshots(c, el.value, e->snapshots); } for (List* sv = e->successors->forkState->saved; sv; sv = sv->next) { e->snapshots = makeSnapshots(c, sv->item, e->snapshots); } if (DebugControl) { fprintf(stderr, "captured snapshots %p at %d\n", e->snapshots, e->logicalInstruction->index); } } } void populateSiteTables(Context* c, Event* e, SiteRecordList* frozen) { resolveJunctionSites(c, e, frozen); resolveBranchSites(c, e, frozen); } void setSites(Context* c, Value* v, Site* s) { assert(c, live(c, v)); for (; s; s = s->next) { v->addSite(c, s->copy(c)); } if (DebugControl) { char buffer[256]; sitesToString(c, v->sites, buffer, 256); fprintf(stderr, "set sites %s for %p\n", buffer, v); } } void resetFrame(Context* c, Event* e) { for (FrameIterator it(c, e->stackBefore, e->localsBefore); it.hasMore();) { FrameIterator::Element el = it.next(c); el.value->clearSites(c); } while (c->acquiredResources) { c->acquiredResources->value->clearSites(c); } } void setSites(Context* c, Event* e, Site** sites) { resetFrame(c, e); for (FrameIterator it(c, e->stackBefore, e->localsBefore); it.hasMore();) { FrameIterator::Element el = it.next(c); if (sites[el.localIndex]) { if (live(c, el.value)) { setSites(c, el.value, sites[el.localIndex]); } else if (DebugControl) { char buffer[256]; sitesToString(c, sites[el.localIndex], buffer, 256); fprintf(stderr, "skip sites %s for %p local %d frame %d\n", buffer, el.value, el.localIndex, el.frameIndex(c)); } } else if (DebugControl) { fprintf(stderr, "no sites for %p local %d frame %d\n", el.value, el.localIndex, el.frameIndex(c)); } } } void removeBuddies(Context* c) { for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) { FrameIterator::Element el = it.next(c); removeBuddy(c, el.value); } } void restore(Context* c, Event* e, Snapshot* snapshots) { for (Snapshot* s = snapshots; s; s = s->next) { Value* v = s->value; Value* next = v->buddy; if (v != next) { v->buddy = v; Value* p = next; while (p->buddy != v) p = p->buddy; p->buddy = next; } } for (Snapshot* s = snapshots; s; s = s->next) { assert(c, s->buddy); s->value->buddy = s->buddy; } resetFrame(c, e); for (Snapshot* s = snapshots; s; s = s->next) { if (live(c, s->value)) { if (live(c, s->value) and s->sites and s->value->sites == 0) { setSites(c, s->value, s->sites); } } // char buffer[256]; sitesToString(c, s->sites, buffer, 256); // fprintf(stderr, "restore %p buddy %p sites %s live %p\n", // s->value, s->value->buddy, buffer, live(c, s->value)); } } void populateSources(Context* c, Event* e) { RUNTIME_ARRAY(SiteRecord, frozenRecords, e->readCount); SiteRecordList frozen(RUNTIME_ARRAY_BODY(frozenRecords), e->readCount); for (Read* r = e->reads; r; r = r->eventNext) { r->value->source = readSource(c, r); if (r->value->source) { if (DebugReads) { char buffer[256]; r->value->source->toString(c, buffer, 256); fprintf(stderr, "freeze source %s for %p\n", buffer, r->value); } freeze(c, &frozen, r->value->source, r->value); } } thaw(c, &frozen); } void setStubRead(Context* c, StubReadPair* p, Value* v) { if (v) { StubRead* r = stubRead(c); if (DebugReads) { fprintf(stderr, "add stub read %p to %p\n", r, v); } // TODO: this is rather icky looking... but despite how it looks, it will not cause an NPE ((Event*)0)->addRead(c, v, r); p->value = v; p->read = r; } } void populateJunctionReads(Context* c, Link* link) { JunctionState* state = new (c->zone->allocate (sizeof(JunctionState) + (sizeof(StubReadPair) * frameFootprint(c, c->stack)))) JunctionState(frameFootprint(c, c->stack)); memset(state->reads, 0, sizeof(StubReadPair) * frameFootprint(c, c->stack)); link->junctionState = state; for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) { FrameIterator::Element e = it.next(c); setStubRead(c, state->reads + e.localIndex, e.value); } } void updateJunctionReads(Context* c, JunctionState* state) { for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) { FrameIterator::Element e = it.next(c); StubReadPair* p = state->reads + e.localIndex; if (p->value and p->read->read == 0) { Read* r = live(c, e.value); if (r) { if (DebugReads) { fprintf(stderr, "stub read %p for %p valid: %p\n", p->read, p->value, r); } p->read->read = r; } } } for (unsigned i = 0; i < frameFootprint(c, c->stack); ++i) { StubReadPair* p = state->reads + i; if (p->value and p->read->read == 0) { if (DebugReads) { fprintf(stderr, "stub read %p for %p invalid\n", p->read, p->value); } p->read->valid_ = false; } } } void compile(Context* c, uintptr_t stackOverflowHandler, unsigned stackLimitOffset) { if (c->logicalCode[c->logicalIp]->lastEvent == 0) { appendDummy(c); } Assembler* a = c->assembler; Block* firstBlock = block(c, c->firstEvent); Block* block = firstBlock; if (stackOverflowHandler) { a->checkStackOverflow(stackOverflowHandler, stackLimitOffset); } a->allocateFrame(c->alignedFrameSize); for (Event* e = c->firstEvent; e; e = e->next) { if (DebugCompile) { fprintf(stderr, " -- compile %s at %d with %d preds %d succs %d stack\n", e->name(), e->logicalInstruction->index, e->predecessors->countPredecessors(), e->successors->countSuccessors(), e->stackBefore ? e->stackBefore->index + 1 : 0); } e->block = block; c->stack = e->stackBefore; c->locals = e->localsBefore; if (e->logicalInstruction->machineOffset == 0) { e->logicalInstruction->machineOffset = a->offset(); } if (e->predecessors) { visit(c, e->predecessors->lastPredecessor()); Event* first = e->predecessors->predecessor; if (e->predecessors->nextPredecessor) { for (Link* pl = e->predecessors; pl->nextPredecessor; pl = pl->nextPredecessor) { updateJunctionReads(c, pl->junctionState); } if (DebugControl) { fprintf(stderr, "set sites to junction sites %p at %d\n", first->junctionSites, first->logicalInstruction->index); } setSites(c, e, first->junctionSites); removeBuddies(c); } else if (first->successors->nextSuccessor) { if (DebugControl) { fprintf(stderr, "restore snapshots %p at %d\n", first->snapshots, first->logicalInstruction->index); } restore(c, e, first->snapshots); } } unsigned footprint = frameFootprint(c, e->stackAfter); RUNTIME_ARRAY(SiteRecord, frozenRecords, footprint); SiteRecordList frozen(RUNTIME_ARRAY_BODY(frozenRecords), footprint); bool branch = e->isBranch(); if (branch and e->successors) { populateSiteTables(c, e, &frozen); } populateSources(c, e); if (branch and e->successors) { captureBranchSnapshots(c, e); } thaw(c, &frozen); e->compile(c); if ((not branch) and e->successors) { populateSiteTables(c, e, &frozen); captureBranchSnapshots(c, e); thaw(c, &frozen); } if (e->visitLinks) { for (List* cell = reverseDestroy(e->visitLinks); cell; cell = cell->next) { visit(c, cell->item); } e->visitLinks = 0; } for (CodePromise* p = e->promises; p; p = p->next) { p->offset = a->offset(); } a->endEvent(); LogicalInstruction* nextInstruction = e->logicalInstruction->next(c); if (e->next == 0 or (e->next->logicalInstruction != e->logicalInstruction and (e->next->logicalInstruction != nextInstruction or e != e->logicalInstruction->lastEvent))) { Block* b = e->logicalInstruction->firstEvent->block; while (b->nextBlock) { b = b->nextBlock; } if (b != block) { b->nextBlock = block; } block->nextInstruction = nextInstruction; block->assemblerBlock = a->endBlock(e->next != 0); if (e->next) { block = compiler::block(c, e->next); } } } c->firstBlock = firstBlock; } void restore(Context* c, ForkState* state) { for (unsigned i = 0; i < state->readCount; ++i) { ForkElement* p = state->elements + i; p->value->lastRead = p->read; p->read->allocateTarget(c); } } void addForkElement(Context* c, Value* v, ForkState* state, unsigned index) { MultiRead* r = multiRead(c); if (DebugReads) { fprintf(stderr, "add multi read %p to %p\n", r, v); } // TODO: this is rather icky looking... but despite how it looks, it will not cause an NPE ((Event*)0)->addRead(c, v, r); ForkElement* p = state->elements + index; p->value = v; p->read = r; } ForkState* saveState(Context* c) { if (c->logicalCode[c->logicalIp]->lastEvent == 0) { appendDummy(c); } unsigned elementCount = frameFootprint(c, c->stack) + c->saved->count(); ForkState* state = new (c->zone->allocate (sizeof(ForkState) + (sizeof(ForkElement) * elementCount))) ForkState(c->stack, c->locals, c->saved, c->predecessor, c->logicalIp); if (c->predecessor) { c->forkState = state; unsigned count = 0; for (FrameIterator it(c, c->stack, c->locals); it.hasMore();) { FrameIterator::Element e = it.next(c); addForkElement(c, e.value, state, count++); } for (List* sv = c->saved; sv; sv = sv->next) { addForkElement(c, sv->item, state, count++); } state->readCount = count; } c->saved = 0; return state; } void restoreState(Context* c, ForkState* s) { if (c->logicalCode[c->logicalIp]->lastEvent == 0) { appendDummy(c); } c->stack = s->stack; c->locals = s->locals; c->predecessor = s->predecessor; c->logicalIp = s->logicalIp; if (c->predecessor) { c->forkState = s; restore(c, s); } } Value* maybeBuddy(Context* c, Value* v) { if (v->home >= 0) { Value* n = value(c, v->type); appendBuddy(c, v, n); return n; } else { return v; } } void linkLocals(Context* c, Local* oldLocals, Local* newLocals) { for (int i = 0; i < static_cast(c->localFootprint); ++i) { Local* local = oldLocals + i; if (local->value) { int highOffset = c->arch->bigEndian() ? 1 : -1; if (i + highOffset >= 0 and i + highOffset < static_cast(c->localFootprint) and local->value->nextWord == local[highOffset].value) { Value* v = newLocals[i].value; Value* next = newLocals[i + highOffset].value; v->nextWord = next; next->nextWord = v; next->wordIndex = 1; } } } } class Client: public Assembler::Client { public: Client(Context* c): c(c) { } virtual int acquireTemporary(uint32_t mask) { unsigned cost; int r = pickRegisterTarget(c, 0, mask, &cost); expect(c, cost < Target::Impossible); save(r); c->registerResources[r].increment(c); return r; } virtual void releaseTemporary(int r) { c->registerResources[r].decrement(c); } virtual void save(int r) { RegisterResource* reg = c->registerResources + r; assert(c, reg->referenceCount == 0); assert(c, reg->freezeCount == 0); assert(c, not reg->reserved); if (reg->value) { steal(c, reg, 0); } } Context* c; }; class MyCompiler: public Compiler { public: MyCompiler(System* s, Assembler* assembler, Zone* zone, Compiler::Client* compilerClient): c(s, assembler, zone, compilerClient), client(&c) { assembler->setClient(&client); } virtual State* saveState() { State* s = compiler::saveState(&c); restoreState(s); return s; } virtual void restoreState(State* state) { compiler::restoreState(&c, static_cast(state)); } virtual Subroutine* startSubroutine() { return c.subroutine = new(c.zone) MySubroutine; } virtual void returnFromSubroutine(Subroutine* subroutine, Operand* address) { appendSaveLocals(&c); appendJump(&c, lir::Jump, static_cast(address), false, true); static_cast(subroutine)->forkState = compiler::saveState(&c); } virtual void linkSubroutine(Subroutine* subroutine) { Local* oldLocals = c.locals; restoreState(static_cast(subroutine)->forkState); linkLocals(&c, oldLocals, c.locals); } virtual void init(unsigned logicalCodeLength, unsigned parameterFootprint, unsigned localFootprint, unsigned alignedFrameSize) { c.logicalCodeLength = logicalCodeLength; c.parameterFootprint = parameterFootprint; c.localFootprint = localFootprint; c.alignedFrameSize = alignedFrameSize; unsigned frameResourceCount = totalFrameSize(&c); c.frameResources = static_cast (c.zone->allocate(sizeof(FrameResource) * frameResourceCount)); for (unsigned i = 0; i < frameResourceCount; ++i) { new (c.frameResources + i) FrameResource; } unsigned base = frameBase(&c); c.frameResources[base + c.arch->returnAddressOffset()].reserved = true; c.frameResources[base + c.arch->framePointerOffset()].reserved = UseFramePointer; // leave room for logical instruction -1 unsigned codeSize = sizeof(LogicalInstruction*) * (logicalCodeLength + 1); c.logicalCode = static_cast (c.zone->allocate(codeSize)); memset(c.logicalCode, 0, codeSize); c.logicalCode++; c.locals = static_cast (c.zone->allocate(sizeof(Local) * localFootprint)); memset(c.locals, 0, sizeof(Local) * localFootprint); c.logicalCode[-1] = new(c.zone) LogicalInstruction(-1, c.stack, c.locals); } virtual void visitLogicalIp(unsigned logicalIp) { assert(&c, logicalIp < c.logicalCodeLength); if (c.logicalCode[c.logicalIp]->lastEvent == 0) { appendDummy(&c); } Event* e = c.logicalCode[logicalIp]->firstEvent; Event* p = c.predecessor; if (p) { if (DebugAppend) { fprintf(stderr, "visit %d pred %d\n", logicalIp, p->logicalInstruction->index); } p->stackAfter = c.stack; p->localsAfter = c.locals; Link* link = compiler::link (&c, p, e->predecessors, e, p->successors, c.forkState); e->predecessors = link; p->successors = link; c.lastEvent->visitLinks = cons(&c, link, c.lastEvent->visitLinks); if (DebugAppend) { fprintf(stderr, "populate junction reads for %d to %d\n", p->logicalInstruction->index, logicalIp); } populateJunctionReads(&c, link); } if (c.subroutine) { c.subroutine->forkState = c.logicalCode[logicalIp]->subroutine->forkState; c.subroutine = 0; } c.forkState = 0; } virtual void startLogicalIp(unsigned logicalIp) { assert(&c, logicalIp < c.logicalCodeLength); assert(&c, c.logicalCode[logicalIp] == 0); if (c.logicalCode[c.logicalIp]->lastEvent == 0) { appendDummy(&c); } Event* p = c.predecessor; if (p) { p->stackAfter = c.stack; p->localsAfter = c.locals; } c.logicalCode[logicalIp] = new(c.zone) LogicalInstruction(logicalIp, c.stack, c.locals); bool startSubroutine = c.subroutine != 0; if (startSubroutine) { c.logicalCode[logicalIp]->subroutine = c.subroutine; c.subroutine = 0; } c.logicalIp = logicalIp; if (startSubroutine) { // assume all local variables are initialized on entry to a // subroutine, since other calls to the subroutine may // initialize them: unsigned sizeInBytes = sizeof(Local) * c.localFootprint; Local* newLocals = static_cast(c.zone->allocate(sizeInBytes)); memcpy(newLocals, c.locals, sizeInBytes); c.locals = newLocals; for (unsigned li = 0; li < c.localFootprint; ++li) { Local* local = c.locals + li; if (local->value == 0) { initLocal(1, li, IntegerType); } } } } virtual Promise* machineIp(unsigned logicalIp) { return ipPromise(&c, logicalIp); } virtual Promise* poolAppend(intptr_t value) { return poolAppendPromise(resolvedPromise(&c, value)); } virtual Promise* poolAppendPromise(Promise* value) { Promise* p = poolPromise(&c, c.constantCount); ConstantPoolNode* constant = new (c.zone) ConstantPoolNode(value); if (c.firstConstant) { c.lastConstant->next = constant; } else { c.firstConstant = constant; } c.lastConstant = constant; ++ c.constantCount; return p; } virtual Operand* constant(int64_t value, Compiler::OperandType type) { return promiseConstant(resolvedPromise(&c, value), type); } virtual Operand* promiseConstant(Promise* value, Compiler::OperandType type) { return compiler::value (&c, valueType(&c, type), compiler::constantSite(&c, value)); } virtual Operand* address(Promise* address) { return value(&c, lir::ValueGeneral, compiler::addressSite(&c, address)); } virtual Operand* memory(Operand* base, OperandType type, int displacement = 0, Operand* index = 0, unsigned scale = 1) { Value* result = value(&c, valueType(&c, type)); appendMemory(&c, static_cast(base), displacement, static_cast(index), scale, result); return result; } virtual Operand* register_(int number) { return compiler::register_(&c, number); } Promise* machineIp() { return c.logicalCode[c.logicalIp]->lastEvent->makeCodePromise(&c); } virtual void push(unsigned footprint UNUSED) { assert(&c, footprint == 1); Value* v = value(&c, lir::ValueGeneral); Stack* s = compiler::stack(&c, v, c.stack); v->home = frameIndex(&c, s->index + c.localFootprint); c.stack = s; } virtual void push(unsigned footprint, Operand* value) { compiler::push(&c, footprint, static_cast(value)); } virtual void save(unsigned footprint, Operand* value) { c.saved = cons(&c, static_cast(value), c.saved); if (TargetBytesPerWord == 4 and footprint > 1) { assert(&c, footprint == 2); assert(&c, static_cast(value)->nextWord); save(1, static_cast(value)->nextWord); } } virtual Operand* pop(unsigned footprint) { return compiler::pop(&c, footprint); } virtual void pushed() { Value* v = value(&c, lir::ValueGeneral); appendFrameSite (&c, v, frameIndex (&c, (c.stack ? c.stack->index : 0) + c.localFootprint)); Stack* s = compiler::stack(&c, v, c.stack); v->home = frameIndex(&c, s->index + c.localFootprint); c.stack = s; } virtual void popped(unsigned footprint) { for (; footprint; -- footprint) { assert(&c, c.stack->value == 0 or c.stack->value->home >= 0); if (DebugFrame) { fprintf(stderr, "popped %p\n", c.stack->value); } c.stack = c.stack->next; } } virtual unsigned topOfStack() { return c.stack->index; } virtual Operand* peek(unsigned footprint, unsigned index) { Stack* s = c.stack; for (unsigned i = index; i > 0; --i) { s = s->next; } if (footprint > 1) { assert(&c, footprint == 2); bool bigEndian = c.arch->bigEndian(); #ifndef NDEBUG Stack* low; Stack* high; if (bigEndian) { high = s; low = s->next; } else { low = s; high = s->next; } assert(&c, (TargetBytesPerWord == 8 and low->value->nextWord == low->value and high->value == 0) or (TargetBytesPerWord == 4 and low->value->nextWord == high->value)); #endif // not NDEBUG if (bigEndian) { s = s->next; } } return s->value; } virtual Operand* call(Operand* address, unsigned flags, TraceHandler* traceHandler, unsigned resultSize, OperandType resultType, unsigned argumentCount, ...) { va_list a; va_start(a, argumentCount); bool bigEndian = c.arch->bigEndian(); unsigned footprint = 0; unsigned size = TargetBytesPerWord; RUNTIME_ARRAY(Value*, arguments, argumentCount); int index = 0; for (unsigned i = 0; i < argumentCount; ++i) { Value* o = va_arg(a, Value*); if (o) { if (bigEndian and size > TargetBytesPerWord) { RUNTIME_ARRAY_BODY(arguments)[index++] = o->nextWord; } RUNTIME_ARRAY_BODY(arguments)[index] = o; if ((not bigEndian) and size > TargetBytesPerWord) { RUNTIME_ARRAY_BODY(arguments)[++index] = o->nextWord; } size = TargetBytesPerWord; ++ index; } else { size = 8; } ++ footprint; } va_end(a); Stack* argumentStack = c.stack; for (int i = index - 1; i >= 0; --i) { argumentStack = compiler::stack (&c, RUNTIME_ARRAY_BODY(arguments)[i], argumentStack); } Value* result = value(&c, valueType(&c, resultType)); appendCall(&c, static_cast(address), flags, traceHandler, result, resultSize, argumentStack, index, 0); return result; } virtual Operand* stackCall(Operand* address, unsigned flags, TraceHandler* traceHandler, unsigned resultSize, OperandType resultType, unsigned argumentFootprint) { Value* result = value(&c, valueType(&c, resultType)); appendCall(&c, static_cast(address), flags, traceHandler, result, resultSize, c.stack, 0, argumentFootprint); return result; } virtual void return_(unsigned size, Operand* value) { appendReturn(&c, size, static_cast(value)); } virtual void initLocal(unsigned footprint, unsigned index, OperandType type) { assert(&c, index + footprint <= c.localFootprint); Value* v = value(&c, valueType(&c, type)); if (footprint > 1) { assert(&c, footprint == 2); unsigned highIndex; unsigned lowIndex; if (c.arch->bigEndian()) { highIndex = index + 1; lowIndex = index; } else { lowIndex = index + 1; highIndex = index; } if (TargetBytesPerWord == 4) { initLocal(1, highIndex, type); Value* next = c.locals[highIndex].value; v->nextWord = next; next->nextWord = v; next->wordIndex = 1; } index = lowIndex; } if (DebugFrame) { fprintf(stderr, "init local %p at %d (%d)\n", v, index, frameIndex(&c, index)); } appendFrameSite(&c, v, frameIndex(&c, index)); Local* local = c.locals + index; local->value = v; v->home = frameIndex(&c, index); } virtual void initLocalsFromLogicalIp(unsigned logicalIp) { assert(&c, logicalIp < c.logicalCodeLength); unsigned footprint = sizeof(Local) * c.localFootprint; Local* newLocals = static_cast(c.zone->allocate(footprint)); memset(newLocals, 0, footprint); c.locals = newLocals; Event* e = c.logicalCode[logicalIp]->firstEvent; for (int i = 0; i < static_cast(c.localFootprint); ++i) { Local* local = e->locals() + i; if (local->value) { initLocal (1, i, local->value->type == lir::ValueGeneral ? IntegerType : FloatType); } } linkLocals(&c, e->locals(), newLocals); } virtual void storeLocal(unsigned footprint, Operand* src, unsigned index) { compiler::storeLocal(&c, footprint, static_cast(src), index, true); } virtual Operand* loadLocal(unsigned footprint, unsigned index) { return compiler::loadLocal(&c, footprint, index); } virtual void saveLocals() { appendSaveLocals(&c); } virtual void checkBounds(Operand* object, unsigned lengthOffset, Operand* index, intptr_t handler) { appendBoundsCheck(&c, static_cast(object), lengthOffset, static_cast(index), handler); } virtual void store(unsigned srcSize, Operand* src, unsigned dstSize, Operand* dst) { appendMove(&c, lir::Move, srcSize, srcSize, static_cast(src), dstSize, static_cast(dst)); } virtual Operand* load(unsigned srcSize, unsigned srcSelectSize, Operand* src, unsigned dstSize) { assert(&c, dstSize >= TargetBytesPerWord); Value* dst = value(&c, static_cast(src)->type); appendMove(&c, lir::Move, srcSize, srcSelectSize, static_cast(src), dstSize, dst); return dst; } virtual Operand* loadz(unsigned srcSize, unsigned srcSelectSize, Operand* src, unsigned dstSize) { assert(&c, dstSize >= TargetBytesPerWord); Value* dst = value(&c, static_cast(src)->type); appendMove(&c, lir::MoveZ, srcSize, srcSelectSize, static_cast(src), dstSize, dst); return dst; } virtual void condJump(lir::TernaryOperation type, unsigned size, Operand* a, Operand* b, Operand* address) { assert(&c, (isGeneralBranch(type) and isGeneralValue(a) and isGeneralValue(b)) or (isFloatBranch(type) and isFloatValue(a) and isFloatValue(b))); appendBranch(&c, type, size, static_cast(a), static_cast(b), static_cast(address)); } virtual void jmp(Operand* address) { appendJump(&c, lir::Jump, static_cast(address)); } virtual void exit(Operand* address) { appendJump(&c, lir::Jump, static_cast(address), true); } virtual Operand* binaryOp(lir::TernaryOperation type, unsigned size, Operand* a, Operand* b) { assert(&c, (isGeneralBinaryOp(type) and isGeneralValue(a) and isGeneralValue(b)) or (isFloatBinaryOp(type) and isFloatValue(a) and isFloatValue(b))); Value* result = value(&c, static_cast(a)->type); appendCombine(&c, type, size, static_cast(a), size, static_cast(b), size, result); return result; } virtual Operand* unaryOp(lir::BinaryOperation type, unsigned size, Operand* a) { assert(&c, (isGeneralUnaryOp(type) and isGeneralValue(a))or( isFloatUnaryOp(type) and isFloatValue(a))); Value* result = value(&c, static_cast(a)->type); appendTranslate(&c, type, size, static_cast(a), size, result); return result; } virtual Operand* f2f(unsigned aSize, unsigned resSize, Operand* a) { assert(&c, static_cast(a)->type == lir::ValueFloat); Value* result = value(&c, lir::ValueFloat); appendTranslate (&c, lir::Float2Float, aSize, static_cast(a), resSize, result); return result; } virtual Operand* f2i(unsigned aSize, unsigned resSize, Operand* a) { assert(&c, static_cast(a)->type == lir::ValueFloat); Value* result = value(&c, lir::ValueGeneral); appendTranslate (&c, lir::Float2Int, aSize, static_cast(a), resSize, result); return result; } virtual Operand* i2f(unsigned aSize, unsigned resSize, Operand* a) { assert(&c, static_cast(a)->type == lir::ValueGeneral); Value* result = value(&c, lir::ValueFloat); appendTranslate (&c, lir::Int2Float, aSize, static_cast(a), resSize, result); return result; } virtual void nullaryOp(lir::Operation type) { appendOperation(&c, type); } virtual void compile(uintptr_t stackOverflowHandler, unsigned stackLimitOffset) { compiler::compile(&c, stackOverflowHandler, stackLimitOffset); } virtual unsigned resolve(uint8_t* dst) { c.machineCode = dst; c.assembler->setDestination(dst); Block* block = c.firstBlock; while (block->nextBlock or block->nextInstruction) { Block* next = block->nextBlock ? block->nextBlock : block->nextInstruction->firstEvent->block; next->start = block->assemblerBlock->resolve (block->start, next->assemblerBlock); block = next; } return c.machineCodeSize = block->assemblerBlock->resolve (block->start, 0) + c.assembler->footerSize(); } virtual unsigned poolSize() { return c.constantCount * TargetBytesPerWord; } virtual void write() { c.assembler->write(); int i = 0; for (ConstantPoolNode* n = c.firstConstant; n; n = n->next) { target_intptr_t* target = reinterpret_cast (c.machineCode + pad(c.machineCodeSize, TargetBytesPerWord) + i); if (n->promise->resolved()) { *target = targetVW(n->promise->value()); } else { class Listener: public Promise::Listener { public: Listener(target_intptr_t* target): target(target){ } virtual bool resolve(int64_t value, void** location) { *target = targetVW(value); if (location) *location = target; return true; } target_intptr_t* target; }; new (n->promise->listen(sizeof(Listener))) Listener(target); } i += TargetBytesPerWord; } } virtual void dispose() { // ignore } Context c; compiler::Client client; }; } // namespace compiler Compiler* makeCompiler(System* system, Assembler* assembler, Zone* zone, Compiler::Client* client) { return new(zone) compiler::MyCompiler(system, assembler, zone, client); } } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/compiler/000077500000000000000000000000001231440243200211655ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/codegen/compiler/context.cpp000066400000000000000000000036441231440243200233640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "codegen/compiler/context.h" #include "codegen/compiler/resource.h" #include namespace avian { namespace codegen { namespace compiler { Context::Context(vm::System* system, Assembler* assembler, vm::Zone* zone, Compiler::Client* client): system(system), assembler(assembler), arch(assembler->arch()), zone(zone), client(client), stack(0), locals(0), saved(0), predecessor(0), logicalCode(0), regFile(arch->registerFile()), regAlloc(system, arch->registerFile()), registerResources (static_cast (zone->allocate(sizeof(RegisterResource) * regFile->allRegisters.limit))), frameResources(0), acquiredResources(0), firstConstant(0), lastConstant(0), machineCode(0), firstEvent(0), lastEvent(0), forkState(0), subroutine(0), firstBlock(0), logicalIp(-1), constantCount(0), logicalCodeLength(0), parameterFootprint(0), localFootprint(0), machineCodeSize(0), alignedFrameSize(0), availableGeneralRegisterCount(regFile->generalRegisters.limit - regFile->generalRegisters.start) { for (unsigned i = regFile->generalRegisters.start; i < regFile->generalRegisters.limit; ++i) { new (registerResources + i) RegisterResource(arch->reserved(i)); if (registerResources[i].reserved) { -- availableGeneralRegisterCount; } } for (unsigned i = regFile->floatRegisters.start; i < regFile->floatRegisters.limit; ++i) { new (registerResources + i) RegisterResource(arch->reserved(i)); } } } // namespace compiler } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/compiler/context.h000066400000000000000000000044471231440243200230330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_CONTEXT_H #define AVIAN_CODEGEN_COMPILER_CONTEXT_H #include #include #include #include "regalloc.h" using namespace avian::util; namespace avian { namespace codegen { namespace compiler { class Stack; class Local; class Event; class LogicalInstruction; class Resource; class RegisterResource; class FrameResource; class ConstantPoolNode; class ForkState; class MySubroutine; class Block; template List* reverseDestroy(List* cell) { List* previous = 0; while (cell) { List* next = cell->next; cell->next = previous; previous = cell; cell = next; } return previous; } class Context { public: Context(vm::System* system, Assembler* assembler, vm::Zone* zone, Compiler::Client* client); vm::System* system; Assembler* assembler; Architecture* arch; vm::Zone* zone; Compiler::Client* client; Stack* stack; Local* locals; List* saved; Event* predecessor; LogicalInstruction** logicalCode; const RegisterFile* regFile; RegisterAllocator regAlloc; RegisterResource* registerResources; FrameResource* frameResources; Resource* acquiredResources; ConstantPoolNode* firstConstant; ConstantPoolNode* lastConstant; uint8_t* machineCode; Event* firstEvent; Event* lastEvent; ForkState* forkState; MySubroutine* subroutine; Block* firstBlock; int logicalIp; unsigned constantCount; unsigned logicalCodeLength; unsigned parameterFootprint; unsigned localFootprint; unsigned machineCodeSize; unsigned alignedFrameSize; unsigned availableGeneralRegisterCount; }; inline Aborter* getAborter(Context* c) { return c->system; } template List* cons(Context* c, const T& value, List* next) { return new (c->zone) List(value, next); } } // namespace compiler } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_CONTEXT_H ReadyTalk-avian-1e1fff5/src/codegen/compiler/event.cpp000066400000000000000000001344401231440243200230200ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include #include #include "codegen/compiler/context.h" #include "codegen/compiler/event.h" #include "codegen/compiler/site.h" #include "codegen/compiler/read.h" #include "codegen/compiler/value.h" #include "codegen/compiler/promise.h" #include "codegen/compiler/frame.h" #include "codegen/compiler/ir.h" using namespace avian::util; namespace avian { namespace codegen { namespace compiler { SiteMask generalRegisterMask(Context* c); SiteMask generalRegisterOrConstantMask(Context* c); CodePromise* codePromise(Context* c, Promise* offset); void saveLocals(Context* c, Event* e); void apply(Context* c, lir::UnaryOperation op, unsigned s1Size, Site* s1Low, Site* s1High); void apply(Context* c, lir::BinaryOperation op, unsigned s1Size, Site* s1Low, Site* s1High, unsigned s2Size, Site* s2Low, Site* s2High); void apply(Context* c, lir::TernaryOperation op, unsigned s1Size, Site* s1Low, Site* s1High, unsigned s2Size, Site* s2Low, Site* s2High, unsigned s3Size, Site* s3Low, Site* s3High); void append(Context* c, Event* e); void clean(Context* c, Event* e, Stack* stack, Local* locals, Read* reads, unsigned popIndex); Read* live(Context* c UNUSED, Value* v); void popRead(Context* c, Event* e UNUSED, Value* v); void maybeMove(Context* c, lir::BinaryOperation type, unsigned srcSize, unsigned srcSelectSize, Value* src, unsigned dstSize, Value* dst, const SiteMask& dstMask); Site* maybeMove(Context* c, Value* v, const SiteMask& mask, bool intersectMask, bool includeNextWord, unsigned registerReserveCount = 0); Site* maybeMove(Context* c, Read* read, bool intersectRead, bool includeNextWord, unsigned registerReserveCount = 0); Site* pickSiteOrMove(Context* c, Value* src, Value* dst, Site* nextWord, unsigned index); void push(Context* c, unsigned footprint, Value* v); Site* pickTargetSite(Context* c, Read* read, bool intersectRead = false, unsigned registerReserveCount = 0, CostCalculator* costCalculator = 0); Value* register_(Context* c, int number); Event::Event(Context* c): next(0), stackBefore(c->stack), localsBefore(c->locals), stackAfter(0), localsAfter(0), promises(0), reads(0), junctionSites(0), snapshots(0), predecessors(0), successors(0), visitLinks(0), block(0), logicalInstruction(c->logicalCode[c->logicalIp]), readCount(0) { } void Event::addRead(Context* c, Value* v, Read* r) { if (DebugReads) { fprintf(stderr, "add read %p to %p last %p event %p (%s)\n", r, v, v->lastRead, this, (this ? this->name() : 0)); } r->value = v; if (this) { r->event = this; r->eventNext = this->reads; this->reads = r; ++ this->readCount; } if (v->lastRead) { // if (DebugReads) { // fprintf(stderr, "append %p to %p for %p\n", r, v->lastRead, v); // } v->lastRead->append(c, r); } else { v->reads = r; } v->lastRead = r; } void Event::addRead(Context* c, Value* v, const SiteMask& mask, Value* successor) { this->addRead(c, v, read(c, mask, successor)); } void Event::addReads(Context* c, Value* v, unsigned size, const SiteMask& lowMask, Value* lowSuccessor, const SiteMask& highMask, Value* highSuccessor) { SingleRead* r = read(c, lowMask, lowSuccessor); this->addRead(c, v, r); if (size > vm::TargetBytesPerWord) { r->high_ = v->nextWord; this->addRead(c, v->nextWord, highMask, highSuccessor); } } void Event::addReads(Context* c, Value* v, unsigned size, const SiteMask& lowMask, const SiteMask& highMask) { this->addReads(c, v, size, lowMask, 0, highMask, 0); } CodePromise* Event::makeCodePromise(Context* c) { return this->promises = new(c->zone) CodePromise(c, this->promises); } bool Event::isUnreachable() { for (Link* p = this->predecessors; p; p = p->nextPredecessor) { if (not p->predecessor->allExits()) return false; } return this->predecessors != 0; } unsigned Link::countPredecessors() { Link* link = this; unsigned c = 0; for (; link; link = link->nextPredecessor) { ++ c; } return c; } Link* Link::lastPredecessor() { Link* link = this; while (link->nextPredecessor) { link = link->nextPredecessor; } return link; } unsigned Link::countSuccessors() { Link* link = this; unsigned c = 0; for (; link; link = link->nextSuccessor) { ++ c; } return c; } Link* link(Context* c, Event* predecessor, Link* nextPredecessor, Event* successor, Link* nextSuccessor, ForkState* forkState) { return new(c->zone) Link (predecessor, nextPredecessor, successor, nextSuccessor, forkState); } class CallEvent: public Event { public: CallEvent(Context* c, Value* address, unsigned flags, TraceHandler* traceHandler, Value* result, unsigned resultSize, Stack* argumentStack, unsigned argumentCount, unsigned stackArgumentFootprint): Event(c), address(address), traceHandler(traceHandler), result(result), returnAddressSurrogate(0), framePointerSurrogate(0), popIndex(0), stackArgumentIndex(0), flags(flags), resultSize(resultSize), stackArgumentFootprint(stackArgumentFootprint) { uint32_t registerMask = c->regFile->generalRegisters.mask; if (argumentCount) { assert(c, (flags & Compiler::TailJump) == 0); assert(c, stackArgumentFootprint == 0); Stack* s = argumentStack; unsigned index = 0; unsigned argumentIndex = 0; while (true) { unsigned footprint = (argumentIndex + 1 < argumentCount and s->value->nextWord == s->next->value) ? 2 : 1; if (index % (c->arch->argumentAlignment() ? footprint : 1)) { ++ index; } SiteMask targetMask; if (index + (c->arch->argumentRegisterAlignment() ? footprint : 1) <= c->arch->argumentRegisterCount()) { int number = c->arch->argumentRegister(index); if (DebugReads) { fprintf(stderr, "reg %d arg read %p\n", number, s->value); } targetMask = SiteMask::fixedRegisterMask(number); registerMask &= ~(1 << number); } else { if (index < c->arch->argumentRegisterCount()) { index = c->arch->argumentRegisterCount(); } unsigned frameIndex = index - c->arch->argumentRegisterCount(); if (DebugReads) { fprintf(stderr, "stack %d arg read %p\n", frameIndex, s->value); } targetMask = SiteMask(1 << lir::MemoryOperand, 0, frameIndex); } this->addRead(c, s->value, targetMask); ++ index; if ((++ argumentIndex) < argumentCount) { s = s->next; } else { break; } } } if (DebugReads) { fprintf(stderr, "address read %p\n", address); } { bool thunk; OperandMask op; c->arch->plan ((flags & Compiler::Aligned) ? lir::AlignedCall : lir::Call, vm::TargetBytesPerWord, op, &thunk); assert(c, not thunk); this->addRead(c, address, SiteMask (op.typeMask, registerMask & op.registerMask, AnyFrameIndex)); } Stack* stack = stackBefore; if (stackArgumentFootprint) { RUNTIME_ARRAY(Value*, arguments, stackArgumentFootprint); for (int i = stackArgumentFootprint - 1; i >= 0; --i) { Value* v = stack->value; stack = stack->next; if ((vm::TargetBytesPerWord == 8 and (v == 0 or (i >= 1 and stack->value == 0))) or (vm::TargetBytesPerWord == 4 and v->nextWord != v)) { assert(c, vm::TargetBytesPerWord == 8 or v->nextWord == stack->value); RUNTIME_ARRAY_BODY(arguments)[i--] = stack->value; stack = stack->next; } RUNTIME_ARRAY_BODY(arguments)[i] = v; } int returnAddressIndex; int framePointerIndex; int frameOffset; if (TailCalls and (flags & Compiler::TailJump)) { assert(c, argumentCount == 0); int base = frameBase(c); returnAddressIndex = base + c->arch->returnAddressOffset(); if (UseFramePointer) { framePointerIndex = base + c->arch->framePointerOffset(); } else { framePointerIndex = -1; } frameOffset = totalFrameSize(c) - c->arch->argumentFootprint(stackArgumentFootprint); } else { returnAddressIndex = -1; framePointerIndex = -1; frameOffset = 0; } for (unsigned i = 0; i < stackArgumentFootprint; ++i) { Value* v = RUNTIME_ARRAY_BODY(arguments)[i]; if (v) { int frameIndex = i + frameOffset; if (DebugReads) { fprintf(stderr, "stack arg read %p at %d of %d\n", v, frameIndex, totalFrameSize(c)); } if (static_cast(frameIndex) == returnAddressIndex) { returnAddressSurrogate = v; this->addRead(c, v, generalRegisterMask(c)); } else if (static_cast(frameIndex) == framePointerIndex) { framePointerSurrogate = v; this->addRead(c, v, generalRegisterMask(c)); } else { this->addRead(c, v, SiteMask(1 << lir::MemoryOperand, 0, frameIndex)); } } } } if ((not TailCalls) or (flags & Compiler::TailJump) == 0) { stackArgumentIndex = c->localFootprint; if (stackBefore) { stackArgumentIndex += stackBefore->index + 1 - stackArgumentFootprint; } popIndex = c->alignedFrameSize + c->parameterFootprint - c->arch->frameFooterSize() - stackArgumentIndex; assert(c, static_cast(popIndex) >= 0); while (stack) { if (stack->value) { unsigned logicalIndex = compiler::frameIndex (c, stack->index + c->localFootprint); if (DebugReads) { fprintf(stderr, "stack save read %p at %d of %d\n", stack->value, logicalIndex, totalFrameSize(c)); } this->addRead(c, stack->value, SiteMask (1 << lir::MemoryOperand, 0, logicalIndex)); } stack = stack->next; } saveLocals(c, this); } } virtual const char* name() { return "CallEvent"; } virtual void compile(Context* c) { lir::UnaryOperation op; if (TailCalls and (flags & Compiler::TailJump)) { if (flags & Compiler::LongJumpOrCall) { if (flags & Compiler::Aligned) { op = lir::AlignedLongJump; } else { op = lir::LongJump; } } else if (flags & Compiler::Aligned) { op = lir::AlignedJump; } else { op = lir::Jump; } assert(c, returnAddressSurrogate == 0 or returnAddressSurrogate->source->type(c) == lir::RegisterOperand); assert(c, framePointerSurrogate == 0 or framePointerSurrogate->source->type(c) == lir::RegisterOperand); int ras; if (returnAddressSurrogate) { returnAddressSurrogate->source->freeze(c, returnAddressSurrogate); ras = static_cast (returnAddressSurrogate->source)->number; } else { ras = lir::NoRegister; } int fps; if (framePointerSurrogate) { framePointerSurrogate->source->freeze(c, framePointerSurrogate); fps = static_cast (framePointerSurrogate->source)->number; } else { fps = lir::NoRegister; } int offset = static_cast(c->arch->argumentFootprint(stackArgumentFootprint)) - static_cast(c->arch->argumentFootprint(c->parameterFootprint)); c->assembler->popFrameForTailCall(c->alignedFrameSize, offset, ras, fps); } else if (flags & Compiler::LongJumpOrCall) { if (flags & Compiler::Aligned) { op = lir::AlignedLongCall; } else { op = lir::LongCall; } } else if (flags & Compiler::Aligned) { op = lir::AlignedCall; } else { op = lir::Call; } apply(c, op, vm::TargetBytesPerWord, address->source, address->source); if (traceHandler) { traceHandler->handleTrace(codePromise(c, c->assembler->offset(true)), stackArgumentIndex); } if (TailCalls) { if (flags & Compiler::TailJump) { if (returnAddressSurrogate) { returnAddressSurrogate->source->thaw(c, returnAddressSurrogate); } if (framePointerSurrogate) { framePointerSurrogate->source->thaw(c, framePointerSurrogate); } } else { unsigned footprint = c->arch->argumentFootprint (stackArgumentFootprint); if (footprint > c->arch->stackAlignmentInWords()) { c->assembler->adjustFrame (footprint - c->arch->stackAlignmentInWords()); } } } clean(c, this, stackBefore, localsBefore, reads, popIndex); if (resultSize and live(c, result)) { result->addSite(c, registerSite(c, c->arch->returnLow())); if (resultSize > vm::TargetBytesPerWord and live(c, result->nextWord)) { result->nextWord->addSite(c, registerSite(c, c->arch->returnHigh())); } } } virtual bool allExits() { return (flags & Compiler::TailJump) != 0; } Value* address; TraceHandler* traceHandler; Value* result; Value* returnAddressSurrogate; Value* framePointerSurrogate; unsigned popIndex; unsigned stackArgumentIndex; unsigned flags; unsigned resultSize; unsigned stackArgumentFootprint; }; void appendCall(Context* c, Value* address, unsigned flags, TraceHandler* traceHandler, Value* result, unsigned resultSize, Stack* argumentStack, unsigned argumentCount, unsigned stackArgumentFootprint) { append(c, new(c->zone) CallEvent(c, address, flags, traceHandler, result, resultSize, argumentStack, argumentCount, stackArgumentFootprint)); } class ReturnEvent: public Event { public: ReturnEvent(Context* c, unsigned size, Value* value): Event(c), value(value) { if (value) { this->addReads(c, value, size, SiteMask::fixedRegisterMask(c->arch->returnLow()), SiteMask::fixedRegisterMask(c->arch->returnHigh())); } } virtual const char* name() { return "ReturnEvent"; } virtual void compile(Context* c) { for (Read* r = reads; r; r = r->eventNext) { popRead(c, this, r->value); } if (not this->isUnreachable()) { c->assembler->popFrameAndPopArgumentsAndReturn (c->alignedFrameSize, c->arch->argumentFootprint(c->parameterFootprint)); } } Value* value; }; void appendReturn(Context* c, unsigned size, Value* value) { append(c, new(c->zone) ReturnEvent(c, size, value)); } class MoveEvent: public Event { public: MoveEvent(Context* c, lir::BinaryOperation type, unsigned srcSize, unsigned srcSelectSize, Value* srcValue, unsigned dstSize, Value* dstValue, const SiteMask& srcLowMask, const SiteMask& srcHighMask): Event(c), type(type), srcSize(srcSize), srcSelectSize(srcSelectSize), srcValue(srcValue), dstSize(dstSize), dstValue(dstValue) { assert(c, srcSelectSize <= srcSize); bool noop = srcSelectSize >= dstSize; if (dstSize > vm::TargetBytesPerWord) { dstValue->grow(c); } if (srcSelectSize > vm::TargetBytesPerWord) { srcValue->maybeSplit(c); } this->addReads(c, srcValue, srcSelectSize, srcLowMask, noop ? dstValue : 0, srcHighMask, noop and dstSize > vm::TargetBytesPerWord ? dstValue->nextWord : 0); } virtual const char* name() { return "MoveEvent"; } virtual void compile(Context* c) { OperandMask dst; c->arch->planDestination (type, srcSelectSize, OperandMask( 1 << srcValue->source->type(c), (static_cast(srcValue->nextWord->source->registerMask(c)) << 32) | static_cast(srcValue->source->registerMask(c))), dstSize, dst); SiteMask dstLowMask = SiteMask::lowPart(dst); SiteMask dstHighMask = SiteMask::highPart(dst); if (srcSelectSize >= vm::TargetBytesPerWord and dstSize >= vm::TargetBytesPerWord and srcSelectSize >= dstSize) { if (dstValue->target) { if (dstSize > vm::TargetBytesPerWord) { if (srcValue->source->registerSize(c) > vm::TargetBytesPerWord) { apply(c, lir::Move, srcSelectSize, srcValue->source, srcValue->source, dstSize, dstValue->target, dstValue->target); if (live(c, dstValue) == 0) { dstValue->removeSite(c, dstValue->target); if (dstSize > vm::TargetBytesPerWord) { dstValue->nextWord->removeSite(c, dstValue->nextWord->target); } } } else { srcValue->nextWord->source->freeze(c, srcValue->nextWord); maybeMove(c, lir::Move, vm::TargetBytesPerWord, vm::TargetBytesPerWord, srcValue, vm::TargetBytesPerWord, dstValue, dstLowMask); srcValue->nextWord->source->thaw(c, srcValue->nextWord); maybeMove (c, lir::Move, vm::TargetBytesPerWord, vm::TargetBytesPerWord, srcValue->nextWord, vm::TargetBytesPerWord, dstValue->nextWord, dstHighMask); } } else { maybeMove(c, lir::Move, vm::TargetBytesPerWord, vm::TargetBytesPerWord, srcValue, vm::TargetBytesPerWord, dstValue, dstLowMask); } } else { Site* low = pickSiteOrMove(c, srcValue, dstValue, 0, 0); if (dstSize > vm::TargetBytesPerWord) { pickSiteOrMove(c, srcValue->nextWord, dstValue->nextWord, low, 1); } } } else if (srcSelectSize <= vm::TargetBytesPerWord and dstSize <= vm::TargetBytesPerWord) { maybeMove(c, type, srcSize, srcSelectSize, srcValue, dstSize, dstValue, dstLowMask); } else { assert(c, srcSize == vm::TargetBytesPerWord); assert(c, srcSelectSize == vm::TargetBytesPerWord); if (dstValue->nextWord->target or live(c, dstValue->nextWord)) { assert(c, dstLowMask.typeMask & (1 << lir::RegisterOperand)); Site* low = freeRegisterSite(c, dstLowMask.registerMask); srcValue->source->freeze(c, srcValue); dstValue->addSite(c, low); low->freeze(c, dstValue); if (DebugMoves) { char srcb[256]; srcValue->source->toString(c, srcb, 256); char dstb[256]; low->toString(c, dstb, 256); fprintf(stderr, "move %s to %s for %p\n", srcb, dstb, srcValue); } apply(c, lir::Move, vm::TargetBytesPerWord, srcValue->source, srcValue->source, vm::TargetBytesPerWord, low, low); low->thaw(c, dstValue); srcValue->source->thaw(c, srcValue); assert(c, dstHighMask.typeMask & (1 << lir::RegisterOperand)); Site* high = freeRegisterSite(c, dstHighMask.registerMask); low->freeze(c, dstValue); dstValue->nextWord->addSite(c, high); high->freeze(c, dstValue->nextWord); if (DebugMoves) { char srcb[256]; low->toString(c, srcb, 256); char dstb[256]; high->toString(c, dstb, 256); fprintf(stderr, "extend %s to %s for %p %p\n", srcb, dstb, dstValue, dstValue->nextWord); } apply(c, lir::Move, vm::TargetBytesPerWord, low, low, dstSize, low, high); high->thaw(c, dstValue->nextWord); low->thaw(c, dstValue); } else { pickSiteOrMove(c, srcValue, dstValue, 0, 0); } } for (Read* r = reads; r; r = r->eventNext) { popRead(c, this, r->value); } } lir::BinaryOperation type; unsigned srcSize; unsigned srcSelectSize; Value* srcValue; unsigned dstSize; Value* dstValue; }; void appendMove(Context* c, lir::BinaryOperation type, unsigned srcSize, unsigned srcSelectSize, Value* srcValue, unsigned dstSize, Value* dstValue) { bool thunk; OperandMask src; c->arch->planSource (type, srcSelectSize, src, dstSize, &thunk); assert(c, not thunk); append(c, new(c->zone) MoveEvent (c, type, srcSize, srcSelectSize, srcValue, dstSize, dstValue, SiteMask::lowPart(src), SiteMask::highPart(src))); } void freezeSource(Context* c, unsigned size, Value* v) { v->source->freeze(c, v); if (size > vm::TargetBytesPerWord) { v->nextWord->source->freeze(c, v->nextWord); } } void thawSource(Context* c, unsigned size, Value* v) { v->source->thaw(c, v); if (size > vm::TargetBytesPerWord) { v->nextWord->source->thaw(c, v->nextWord); } } Read* liveNext(Context* c, Value* v) { assert(c, v->buddy->hasBuddy(c, v)); Read* r = v->reads->next(c); if (valid(r)) return r; for (Value* p = v->buddy; p != v; p = p->buddy) { if (valid(p->reads)) return p->reads; } return 0; } void preserve(Context* c, Value* v, Read* r, Site* s) { s->freeze(c, v); maybeMove(c, r, false, true, 0); s->thaw(c, v); } Site* getTarget(Context* c, Value* value, Value* result, const SiteMask& resultMask) { Site* s; Value* v; Read* r = liveNext(c, value); if (value->source->match (c, static_cast(resultMask)) and (r == 0 or value->source->loneMatch (c, static_cast(resultMask)))) { s = value->source; v = value; if (r and v->uniqueSite(c, s)) { preserve(c, v, r, s); } } else { SingleRead r(resultMask, 0); r.value = result; r.successor_ = result; s = pickTargetSite(c, &r, true); v = result; result->addSite(c, s); } v->removeSite(c, s); s->freeze(c, v); return s; } class CombineEvent: public Event { public: CombineEvent(Context* c, lir::TernaryOperation type, unsigned firstSize, Value* firstValue, unsigned secondSize, Value* secondValue, unsigned resultSize, Value* resultValue, const SiteMask& firstLowMask, const SiteMask& firstHighMask, const SiteMask& secondLowMask, const SiteMask& secondHighMask): Event(c), type(type), firstSize(firstSize), firstValue(firstValue), secondSize(secondSize), secondValue(secondValue), resultSize(resultSize), resultValue(resultValue) { this->addReads(c, firstValue, firstSize, firstLowMask, firstHighMask); if (resultSize > vm::TargetBytesPerWord) { resultValue->grow(c); } bool condensed = c->arch->alwaysCondensed(type); this->addReads(c, secondValue, secondSize, secondLowMask, condensed ? resultValue : 0, secondHighMask, condensed ? resultValue->nextWord : 0); } virtual const char* name() { return "CombineEvent"; } virtual void compile(Context* c) { assert(c, firstValue->source->type(c) == firstValue->nextWord->source->type(c)); // if (secondValue->source->type(c) != secondValue->nextWord->source->type(c)) { // fprintf(stderr, "%p %p %d : %p %p %d\n", // secondValue, secondValue->source, secondValue->source->type(c), // secondValue->nextWord, secondValue->nextWord->source, // secondValue->nextWord->source->type(c)); // } assert(c, secondValue->source->type(c) == secondValue->nextWord->source->type(c)); freezeSource(c, firstSize, firstValue); OperandMask cMask; c->arch->planDestination (type, firstSize, OperandMask( 1 << firstValue->source->type(c), (static_cast(firstValue->nextWord->source->registerMask(c)) << 32) | static_cast(firstValue->source->registerMask(c))), secondSize, OperandMask( 1 << secondValue->source->type(c), (static_cast(secondValue->nextWord->source->registerMask(c)) << 32) | static_cast(secondValue->source->registerMask(c))), resultSize, cMask); SiteMask resultLowMask = SiteMask::lowPart(cMask); SiteMask resultHighMask = SiteMask::highPart(cMask); Site* low = getTarget(c, secondValue, resultValue, resultLowMask); unsigned lowSize = low->registerSize(c); Site* high = (resultSize > lowSize ? getTarget(c, secondValue->nextWord, resultValue->nextWord, resultHighMask) : low); // fprintf(stderr, "combine %p:%p and %p:%p into %p:%p\n", // firstValue, firstValue->nextWord, // secondValue, secondValue->nextWord, // resultValue, resultValue->nextWord); apply(c, type, firstSize, firstValue->source, firstValue->nextWord->source, secondSize, secondValue->source, secondValue->nextWord->source, resultSize, low, high); thawSource(c, firstSize, firstValue); for (Read* r = reads; r; r = r->eventNext) { popRead(c, this, r->value); } low->thaw(c, secondValue); if (resultSize > lowSize) { high->thaw(c, secondValue->nextWord); } if (live(c, resultValue)) { resultValue->addSite(c, low); if (resultSize > lowSize and live(c, resultValue->nextWord)) { resultValue->nextWord->addSite(c, high); } } } lir::TernaryOperation type; unsigned firstSize; Value* firstValue; unsigned secondSize; Value* secondValue; unsigned resultSize; Value* resultValue; }; void appendCombine(Context* c, lir::TernaryOperation type, unsigned firstSize, Value* firstValue, unsigned secondSize, Value* secondValue, unsigned resultSize, Value* resultValue) { bool thunk; OperandMask firstMask; OperandMask secondMask; c->arch->planSource(type, firstSize, firstMask, secondSize, secondMask, resultSize, &thunk); if (thunk) { Stack* oldStack = c->stack; bool threadParameter; intptr_t handler = c->client->getThunk (type, firstSize, resultSize, &threadParameter); unsigned stackSize = ceilingDivide(secondSize, vm::TargetBytesPerWord) + ceilingDivide(firstSize, vm::TargetBytesPerWord); compiler::push(c, ceilingDivide(secondSize, vm::TargetBytesPerWord), secondValue); compiler::push(c, ceilingDivide(firstSize, vm::TargetBytesPerWord), firstValue); if (threadParameter) { ++ stackSize; compiler::push(c, 1, register_(c, c->arch->thread())); } Stack* argumentStack = c->stack; c->stack = oldStack; appendCall (c, value(c, lir::ValueGeneral, constantSite(c, handler)), 0, 0, resultValue, resultSize, argumentStack, stackSize, 0); } else { append (c, new(c->zone) CombineEvent (c, type, firstSize, firstValue, secondSize, secondValue, resultSize, resultValue, SiteMask::lowPart(firstMask), SiteMask::highPart(firstMask), SiteMask::lowPart(secondMask), SiteMask::highPart(secondMask))); } } class TranslateEvent: public Event { public: TranslateEvent(Context* c, lir::BinaryOperation type, unsigned valueSize, Value* value, unsigned resultSize, Value* resultValue, const SiteMask& valueLowMask, const SiteMask& valueHighMask): Event(c), type(type), valueSize(valueSize), resultSize(resultSize), value(value), resultValue(resultValue) { bool condensed = c->arch->alwaysCondensed(type); if (resultSize > vm::TargetBytesPerWord) { resultValue->grow(c); } this->addReads(c, value, valueSize, valueLowMask, condensed ? resultValue : 0, valueHighMask, condensed ? resultValue->nextWord : 0); } virtual const char* name() { return "TranslateEvent"; } virtual void compile(Context* c) { assert(c, value->source->type(c) == value->nextWord->source->type(c)); OperandMask bMask; c->arch->planDestination (type, valueSize, OperandMask( 1 << value->source->type(c), (static_cast(value->nextWord->source->registerMask(c)) << 32) | static_cast(value->source->registerMask(c))), resultSize, bMask); SiteMask resultLowMask = SiteMask::lowPart(bMask); SiteMask resultHighMask = SiteMask::highPart(bMask); Site* low = getTarget(c, value, resultValue, resultLowMask); unsigned lowSize = low->registerSize(c); Site* high = (resultSize > lowSize ? getTarget(c, value->nextWord, resultValue->nextWord, resultHighMask) : low); apply(c, type, valueSize, value->source, value->nextWord->source, resultSize, low, high); for (Read* r = reads; r; r = r->eventNext) { popRead(c, this, r->value); } low->thaw(c, value); if (resultSize > lowSize) { high->thaw(c, value->nextWord); } if (live(c, resultValue)) { resultValue->addSite(c, low); if (resultSize > lowSize and live(c, resultValue->nextWord)) { resultValue->nextWord->addSite(c, high); } } } lir::BinaryOperation type; unsigned valueSize; unsigned resultSize; Value* value; Value* resultValue; Read* resultRead; SiteMask resultLowMask; SiteMask resultHighMask; }; void appendTranslate(Context* c, lir::BinaryOperation type, unsigned firstSize, Value* firstValue, unsigned resultSize, Value* resultValue) { bool thunk; OperandMask first; c->arch->planSource(type, firstSize, first, resultSize, &thunk); if (thunk) { Stack* oldStack = c->stack; compiler::push(c, ceilingDivide(firstSize, vm::TargetBytesPerWord), firstValue); Stack* argumentStack = c->stack; c->stack = oldStack; appendCall (c, value (c, lir::ValueGeneral, constantSite (c, c->client->getThunk(type, firstSize, resultSize))), 0, 0, resultValue, resultSize, argumentStack, ceilingDivide(firstSize, vm::TargetBytesPerWord), 0); } else { append(c, new(c->zone) TranslateEvent (c, type, firstSize, firstValue, resultSize, resultValue, SiteMask::lowPart(first), SiteMask::highPart(first))); } } class OperationEvent: public Event { public: OperationEvent(Context* c, lir::Operation op): Event(c), op(op) { } virtual const char* name() { return "OperationEvent"; } virtual void compile(Context* c) { c->assembler->apply(op); } lir::Operation op; }; void appendOperation(Context* c, lir::Operation op) { append(c, new(c->zone) OperationEvent(c, op)); } ConstantSite* findConstantSite(Context* c, Value* v) { for (SiteIterator it(c, v); it.hasMore();) { Site* s = it.next(); if (s->type(c) == lir::ConstantOperand) { return static_cast(s); } } return 0; } void moveIfConflict(Context* c, Value* v, MemorySite* s) { if (v->reads) { SiteMask mask(1 << lir::RegisterOperand, ~0, AnyFrameIndex); v->reads->intersect(&mask); if (s->conflicts(mask)) { maybeMove(c, v->reads, true, false); v->removeSite(c, s); } } } class MemoryEvent: public Event { public: MemoryEvent(Context* c, Value* base, int displacement, Value* index, unsigned scale, Value* result): Event(c), base(base), displacement(displacement), index(index), scale(scale), result(result) { this->addRead(c, base, generalRegisterMask(c)); if (index) { this->addRead(c, index, generalRegisterOrConstantMask(c)); } } virtual const char* name() { return "MemoryEvent"; } virtual void compile(Context* c) { int indexRegister; int displacement = this->displacement; unsigned scale = this->scale; if (index) { ConstantSite* constant = findConstantSite(c, index); if (constant) { indexRegister = lir::NoRegister; displacement += (constant->value->value() * scale); scale = 1; } else { assert(c, index->source->type(c) == lir::RegisterOperand); indexRegister = static_cast(index->source)->number; } } else { indexRegister = lir::NoRegister; } assert(c, base->source->type(c) == lir::RegisterOperand); int baseRegister = static_cast(base->source)->number; popRead(c, this, base); if (index) { if (vm::TargetBytesPerWord == 8 and indexRegister != lir::NoRegister) { apply(c, lir::Move, 4, index->source, index->source, 8, index->source, index->source); } popRead(c, this, index); } MemorySite* site = memorySite (c, baseRegister, displacement, indexRegister, scale); MemorySite* low; if (result->nextWord != result) { MemorySite* high = static_cast(site->copyHigh(c)); low = static_cast(site->copyLow(c)); result->nextWord->target = high; result->nextWord->addSite(c, high); moveIfConflict(c, result->nextWord, high); } else { low = site; } result->target = low; result->addSite(c, low); moveIfConflict(c, result, low); } Value* base; int displacement; Value* index; unsigned scale; Value* result; }; void appendMemory(Context* c, Value* base, int displacement, Value* index, unsigned scale, Value* result) { append(c, new(c->zone) MemoryEvent(c, base, displacement, index, scale, result)); } double asFloat(unsigned size, int64_t v) { if (size == 4) { return vm::bitsToFloat(v); } else { return vm::bitsToDouble(v); } } bool unordered(double a, double b) { return not (a >= b or a < b); } bool shouldJump(Context* c, lir::TernaryOperation type, unsigned size, int64_t b, int64_t a) { switch (type) { case lir::JumpIfEqual: return a == b; case lir::JumpIfNotEqual: return a != b; case lir::JumpIfLess: return a < b; case lir::JumpIfGreater: return a > b; case lir::JumpIfLessOrEqual: return a <= b; case lir::JumpIfGreaterOrEqual: return a >= b; case lir::JumpIfFloatEqual: return asFloat(size, a) == asFloat(size, b); case lir::JumpIfFloatNotEqual: return asFloat(size, a) != asFloat(size, b); case lir::JumpIfFloatLess: return asFloat(size, a) < asFloat(size, b); case lir::JumpIfFloatGreater: return asFloat(size, a) > asFloat(size, b); case lir::JumpIfFloatLessOrEqual: return asFloat(size, a) <= asFloat(size, b); case lir::JumpIfFloatGreaterOrEqual: return asFloat(size, a) >= asFloat(size, b); case lir::JumpIfFloatLessOrUnordered: return asFloat(size, a) < asFloat(size, b) or unordered(asFloat(size, a), asFloat(size, b)); case lir::JumpIfFloatGreaterOrUnordered: return asFloat(size, a) > asFloat(size, b) or unordered(asFloat(size, a), asFloat(size, b)); case lir::JumpIfFloatLessOrEqualOrUnordered: return asFloat(size, a) <= asFloat(size, b) or unordered(asFloat(size, a), asFloat(size, b)); case lir::JumpIfFloatGreaterOrEqualOrUnordered: return asFloat(size, a) >= asFloat(size, b) or unordered(asFloat(size, a), asFloat(size, b)); default: abort(c); } } lir::TernaryOperation thunkBranch(Context* c, lir::TernaryOperation type) { switch (type) { case lir::JumpIfFloatEqual: return lir::JumpIfEqual; case lir::JumpIfFloatNotEqual: return lir::JumpIfNotEqual; case lir::JumpIfFloatLess: case lir::JumpIfFloatLessOrUnordered: return lir::JumpIfLess; case lir::JumpIfFloatGreater: case lir::JumpIfFloatGreaterOrUnordered: return lir::JumpIfGreater; case lir::JumpIfFloatLessOrEqual: case lir::JumpIfFloatLessOrEqualOrUnordered: return lir::JumpIfLessOrEqual; case lir::JumpIfFloatGreaterOrEqual: case lir::JumpIfFloatGreaterOrEqualOrUnordered: return lir::JumpIfGreaterOrEqual; default: abort(c); } } class BranchEvent: public Event { public: BranchEvent(Context* c, lir::TernaryOperation type, unsigned size, Value* firstValue, Value* secondValue, Value* addressValue, const SiteMask& firstLowMask, const SiteMask& firstHighMask, const SiteMask& secondLowMask, const SiteMask& secondHighMask): Event(c), type(type), size(size), firstValue(firstValue), secondValue(secondValue), addressValue(addressValue) { this->addReads(c, firstValue, size, firstLowMask, firstHighMask); this->addReads(c, secondValue, size, secondLowMask, secondHighMask); OperandMask dstMask; c->arch->planDestination(type, size, OperandMask(0, 0), size, OperandMask(0, 0), vm::TargetBytesPerWord, dstMask); this->addRead(c, addressValue, SiteMask::lowPart(dstMask)); } virtual const char* name() { return "BranchEvent"; } virtual void compile(Context* c) { ConstantSite* firstConstant = findConstantSite(c, firstValue); ConstantSite* secondConstant = findConstantSite(c, secondValue); if (not this->isUnreachable()) { if (firstConstant and secondConstant and firstConstant->value->resolved() and secondConstant->value->resolved()) { int64_t firstConstVal = firstConstant->value->value(); int64_t secondConstVal = secondConstant->value->value(); if (size > vm::TargetBytesPerWord) { firstConstVal |= findConstantSite (c, firstValue->nextWord)->value->value() << 32; secondConstVal |= findConstantSite (c, secondValue->nextWord)->value->value() << 32; } if (shouldJump(c, type, size, firstConstVal, secondConstVal)) { apply(c, lir::Jump, vm::TargetBytesPerWord, addressValue->source, addressValue->source); } } else { freezeSource(c, size, firstValue); freezeSource(c, size, secondValue); freezeSource(c, vm::TargetBytesPerWord, addressValue); apply(c, type, size, firstValue->source, firstValue->nextWord->source, size, secondValue->source, secondValue->nextWord->source, vm::TargetBytesPerWord, addressValue->source, addressValue->source); thawSource(c, vm::TargetBytesPerWord, addressValue); thawSource(c, size, secondValue); thawSource(c, size, firstValue); } } for (Read* r = reads; r; r = r->eventNext) { popRead(c, this, r->value); } } virtual bool isBranch() { return true; } lir::TernaryOperation type; unsigned size; Value* firstValue; Value* secondValue; Value* addressValue; }; void appendBranch(Context* c, lir::TernaryOperation type, unsigned size, Value* firstValue, Value* secondValue, Value* addressValue) { bool thunk; OperandMask firstMask; OperandMask secondMask; c->arch->planSource(type, size, firstMask, size, secondMask, vm::TargetBytesPerWord, &thunk); if (thunk) { Stack* oldStack = c->stack; bool threadParameter; intptr_t handler = c->client->getThunk (type, size, size, &threadParameter); assert(c, not threadParameter); compiler::push(c, ceilingDivide(size, vm::TargetBytesPerWord), secondValue); compiler::push(c, ceilingDivide(size, vm::TargetBytesPerWord), firstValue); Stack* argumentStack = c->stack; c->stack = oldStack; Value* result = value(c, lir::ValueGeneral); appendCall (c, value (c, lir::ValueGeneral, constantSite(c, handler)), 0, 0, result, 4, argumentStack, ceilingDivide(size, vm::TargetBytesPerWord) * 2, 0); appendBranch(c, thunkBranch(c, type), 4, value (c, lir::ValueGeneral, constantSite(c, static_cast(0))), result, addressValue); } else { append (c, new(c->zone) BranchEvent (c, type, size, firstValue, secondValue, addressValue, SiteMask::lowPart(firstMask), SiteMask::highPart(firstMask), SiteMask::lowPart(secondMask), SiteMask::highPart(secondMask))); } } void clean(Context* c, Value* v, unsigned popIndex) { for (SiteIterator it(c, v); it.hasMore();) { Site* s = it.next(); if (not (s->match(c, SiteMask(1 << lir::MemoryOperand, 0, AnyFrameIndex)) and offsetToFrameIndex (c, static_cast(s)->offset) >= popIndex)) { if (false and s->match(c, SiteMask(1 << lir::MemoryOperand, 0, AnyFrameIndex))) { char buffer[256]; s->toString(c, buffer, 256); fprintf(stderr, "remove %s from %p at %d pop offset 0x%x\n", buffer, v, offsetToFrameIndex (c, static_cast(s)->offset), frameIndexToOffset(c, popIndex)); } it.remove(c); } } } void clean(Context* c, Event* e, Stack* stack, Local* locals, Read* reads, unsigned popIndex) { for (FrameIterator it(c, stack, locals); it.hasMore();) { FrameIterator::Element e = it.next(c); clean(c, e.value, popIndex); } for (Read* r = reads; r; r = r->eventNext) { popRead(c, e, r->value); } } class JumpEvent: public Event { public: JumpEvent(Context* c, lir::UnaryOperation type, Value* address, bool exit, bool cleanLocals): Event(c), type(type), address(address), exit(exit), cleanLocals(cleanLocals) { bool thunk; OperandMask mask; c->arch->plan(type, vm::TargetBytesPerWord, mask, &thunk); assert(c, not thunk); this->addRead(c, address, SiteMask::lowPart(mask)); } virtual const char* name() { return "JumpEvent"; } virtual void compile(Context* c) { if (not this->isUnreachable()) { apply(c, type, vm::TargetBytesPerWord, address->source, address->source); } for (Read* r = reads; r; r = r->eventNext) { popRead(c, this, r->value); } if (cleanLocals) { for (FrameIterator it(c, 0, c->locals); it.hasMore();) { FrameIterator::Element e = it.next(c); clean(c, e.value, 0); } } } virtual bool isBranch() { return true; } virtual bool allExits() { return exit or this->isUnreachable(); } lir::UnaryOperation type; Value* address; bool exit; bool cleanLocals; }; void appendJump(Context* c, lir::UnaryOperation type, Value* address, bool exit, bool cleanLocals) { append(c, new(c->zone) JumpEvent(c, type, address, exit, cleanLocals)); } class BoundsCheckEvent: public Event { public: BoundsCheckEvent(Context* c, Value* object, unsigned lengthOffset, Value* index, intptr_t handler): Event(c), object(object), lengthOffset(lengthOffset), index(index), handler(handler) { this->addRead(c, object, generalRegisterMask(c)); this->addRead(c, index, generalRegisterOrConstantMask(c)); } virtual const char* name() { return "BoundsCheckEvent"; } virtual void compile(Context* c) { Assembler* a = c->assembler; ConstantSite* constant = findConstantSite(c, index); CodePromise* outOfBoundsPromise = 0; if (constant) { if (constant->value->value() < 0) { lir::Constant handlerConstant(resolvedPromise(c, handler)); a->apply(lir::Call, OperandInfo(vm::TargetBytesPerWord, lir::ConstantOperand, &handlerConstant)); } } else { outOfBoundsPromise = compiler::codePromise(c, static_cast(0)); ConstantSite zero(resolvedPromise(c, 0)); ConstantSite oob(outOfBoundsPromise); apply(c, lir::JumpIfLess, 4, &zero, &zero, 4, index->source, index->source, vm::TargetBytesPerWord, &oob, &oob); } if (constant == 0 or constant->value->value() >= 0) { assert(c, object->source->type(c) == lir::RegisterOperand); MemorySite length(static_cast(object->source)->number, lengthOffset, lir::NoRegister, 1); length.acquired = true; CodePromise* nextPromise = compiler::codePromise(c, static_cast(0)); freezeSource(c, vm::TargetBytesPerWord, index); ConstantSite next(nextPromise); apply(c, lir::JumpIfGreater, 4, index->source, index->source, 4, &length, &length, vm::TargetBytesPerWord, &next, &next); thawSource(c, vm::TargetBytesPerWord, index); if (constant == 0) { outOfBoundsPromise->offset = a->offset(); } lir::Constant handlerConstant(resolvedPromise(c, handler)); a->apply(lir::Call, OperandInfo(vm::TargetBytesPerWord, lir::ConstantOperand, &handlerConstant)); nextPromise->offset = a->offset(); } popRead(c, this, object); popRead(c, this, index); } Value* object; unsigned lengthOffset; Value* index; intptr_t handler; }; void appendBoundsCheck(Context* c, Value* object, unsigned lengthOffset, Value* index, intptr_t handler) { append(c, new(c->zone) BoundsCheckEvent(c, object, lengthOffset, index, handler)); } class FrameSiteEvent: public Event { public: FrameSiteEvent(Context* c, Value* value, int index): Event(c), value(value), index(index) { } virtual const char* name() { return "FrameSiteEvent"; } virtual void compile(Context* c) { if (live(c, value)) { value->addSite(c, frameSite(c, index)); } } Value* value; int index; }; void appendFrameSite(Context* c, Value* value, int index) { append(c, new(c->zone) FrameSiteEvent(c, value, index)); } class SaveLocalsEvent: public Event { public: SaveLocalsEvent(Context* c): Event(c) { saveLocals(c, this); } virtual const char* name() { return "SaveLocalsEvent"; } virtual void compile(Context* c) { for (Read* r = reads; r; r = r->eventNext) { popRead(c, this, r->value); } } }; void appendSaveLocals(Context* c) { append(c, new(c->zone) SaveLocalsEvent(c)); } class DummyEvent: public Event { public: DummyEvent(Context* c, Local* locals): Event(c), locals_(locals) { } virtual const char* name() { return "DummyEvent"; } virtual void compile(Context*) { } virtual Local* locals() { return locals_; } Local* locals_; }; void appendDummy(Context* c) { Stack* stack = c->stack; Local* locals = c->locals; LogicalInstruction* i = c->logicalCode[c->logicalIp]; c->stack = i->stack; c->locals = i->locals; append(c, new(c->zone) DummyEvent(c, locals)); c->stack = stack; c->locals = locals; } } // namespace compiler } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/compiler/event.h000066400000000000000000000102631231440243200224610ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_EVENT_H #define AVIAN_CODEGEN_COMPILER_EVENT_H namespace avian { namespace codegen { namespace compiler { class Context; class CodePromise; class Snapshot; class Link; class Site; class StubRead; const bool DebugReads = false; const bool DebugMoves = false; class Event { public: Event(Context* c); virtual const char* name() = 0; virtual void compile(Context* c) = 0; virtual bool isBranch() { return false; } virtual bool allExits() { return false; } virtual Local* locals() { return localsBefore; } void addRead(Context* c, Value* v, Read* r); void addRead(Context* c, Value* v, const SiteMask& mask, Value* successor = 0); void addReads(Context* c, Value* v, unsigned size, const SiteMask& lowMask, Value* lowSuccessor, const SiteMask& highMask, Value* highSuccessor); void addReads(Context* c, Value* v, unsigned size, const SiteMask& lowMask, const SiteMask& highMask); CodePromise* makeCodePromise(Context* c); bool isUnreachable(); Event* next; Stack* stackBefore; Local* localsBefore; Stack* stackAfter; Local* localsAfter; CodePromise* promises; Read* reads; Site** junctionSites; Snapshot* snapshots; Link* predecessors; Link* successors; List* visitLinks; Block* block; LogicalInstruction* logicalInstruction; unsigned readCount; }; class StubReadPair { public: Value* value; StubRead* read; }; class JunctionState { public: JunctionState(unsigned frameFootprint): frameFootprint(frameFootprint) { } unsigned frameFootprint; StubReadPair reads[0]; }; class Link { public: Link(Event* predecessor, Link* nextPredecessor, Event* successor, Link* nextSuccessor, ForkState* forkState): predecessor(predecessor), nextPredecessor(nextPredecessor), successor(successor), nextSuccessor(nextSuccessor), forkState(forkState), junctionState(0) { } unsigned countPredecessors(); Link* lastPredecessor(); unsigned countSuccessors(); Event* predecessor; Link* nextPredecessor; Event* successor; Link* nextSuccessor; ForkState* forkState; JunctionState* junctionState; }; Link* link(Context* c, Event* predecessor, Link* nextPredecessor, Event* successor, Link* nextSuccessor, ForkState* forkState); void appendCall(Context* c, Value* address, unsigned flags, TraceHandler* traceHandler, Value* result, unsigned resultSize, Stack* argumentStack, unsigned argumentCount, unsigned stackArgumentFootprint); void appendReturn(Context* c, unsigned size, Value* value); void appendMove(Context* c, lir::BinaryOperation type, unsigned srcSize, unsigned srcSelectSize, Value* src, unsigned dstSize, Value* dst); void appendCombine(Context* c, lir::TernaryOperation type, unsigned firstSize, Value* first, unsigned secondSize, Value* second, unsigned resultSize, Value* result); void appendTranslate(Context* c, lir::BinaryOperation type, unsigned firstSize, Value* first, unsigned resultSize, Value* result); void appendOperation(Context* c, lir::Operation op); void appendMemory(Context* c, Value* base, int displacement, Value* index, unsigned scale, Value* result); void appendBranch(Context* c, lir::TernaryOperation type, unsigned size, Value* first, Value* second, Value* address); void appendJump(Context* c, lir::UnaryOperation type, Value* address, bool exit = false, bool cleanLocals = false); void appendBoundsCheck(Context* c, Value* object, unsigned lengthOffset, Value* index, intptr_t handler); void appendFrameSite(Context* c, Value* value, int index); void appendSaveLocals(Context* c); void appendDummy(Context* c); } // namespace compiler } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_EVENT_H ReadyTalk-avian-1e1fff5/src/codegen/compiler/frame.cpp000066400000000000000000000060171231440243200227670ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include "codegen/compiler/context.h" #include "codegen/compiler/frame.h" #include namespace avian { namespace codegen { namespace compiler { unsigned totalFrameSize(Context* c) { return c->alignedFrameSize + c->arch->frameHeaderSize() + c->arch->argumentFootprint(c->parameterFootprint); } int frameIndex(Context* c, int localIndex) { assert(c, localIndex >= 0); int index = c->alignedFrameSize + c->parameterFootprint - localIndex - 1; if (localIndex < static_cast(c->parameterFootprint)) { index += c->arch->frameHeaderSize(); } else { index -= c->arch->frameFooterSize(); } assert(c, index >= 0); assert(c, static_cast(index) < totalFrameSize(c)); return index; } unsigned frameIndexToOffset(Context* c, unsigned frameIndex) { assert(c, frameIndex < totalFrameSize(c)); return (frameIndex + c->arch->frameFooterSize()) * vm::TargetBytesPerWord; } unsigned offsetToFrameIndex(Context* c, unsigned offset) { assert(c, static_cast ((offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize()) >= 0); assert(c, ((offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize()) < totalFrameSize(c)); return (offset / vm::TargetBytesPerWord) - c->arch->frameFooterSize(); } unsigned frameBase(Context* c) { return c->alignedFrameSize - c->arch->frameReturnAddressSize() - c->arch->frameFooterSize() + c->arch->frameHeaderSize(); } FrameIterator::Element::Element(Value* value, unsigned localIndex): value(value), localIndex(localIndex) { } int FrameIterator::Element::frameIndex(Context* c) { return compiler::frameIndex(c, this->localIndex); } FrameIterator::FrameIterator(Context* c, Stack* stack, Local* locals, bool includeEmpty): stack(stack), locals(locals), localIndex(c->localFootprint - 1), includeEmpty(includeEmpty) { } bool FrameIterator::hasMore() { if (not includeEmpty) { while (stack and stack->value == 0) { stack = stack->next; } while (localIndex >= 0 and locals[localIndex].value == 0) { -- localIndex; } } return stack != 0 or localIndex >= 0; } FrameIterator::Element FrameIterator::next(Context* c) { Value* v; unsigned li; if (stack) { Stack* s = stack; v = s->value; li = s->index + c->localFootprint; stack = stack->next; } else { Local* l = locals + localIndex; v = l->value; li = localIndex; -- localIndex; } return Element(v, li); } Stack* stack(Context* c, Value* value, Stack* next) { return new(c->zone) Stack(next ? next->index + 1 : 0, value, next); } } // namespace compiler } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/compiler/frame.h000066400000000000000000000030061231440243200224270ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_FRAME_H #define AVIAN_CODEGEN_COMPILER_FRAME_H namespace avian { namespace codegen { namespace compiler { unsigned totalFrameSize(Context* c); int frameIndex(Context* c, int localIndex); unsigned frameIndexToOffset(Context* c, unsigned frameIndex); unsigned offsetToFrameIndex(Context* c, unsigned offset); unsigned frameBase(Context* c); class FrameIterator { public: class Element { public: Element(Value* value, unsigned localIndex); int frameIndex(Context* c); Value* const value; const unsigned localIndex; }; FrameIterator(Context* c, Stack* stack, Local* locals, bool includeEmpty = false); bool hasMore(); Element next(Context* c); Stack* stack; Local* locals; int localIndex; bool includeEmpty; }; class Local { public: Value* value; }; class Stack { public: Stack(unsigned index, Value* value, Stack* next): index(index), value(value), next(next) { } unsigned index; Value* value; Stack* next; }; Stack* stack(Context* c, Value* value, Stack* next); } // namespace compiler } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_FRAME_H ReadyTalk-avian-1e1fff5/src/codegen/compiler/ir.cpp000066400000000000000000000024201231440243200223010ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "codegen/compiler/context.h" #include "codegen/compiler/ir.h" namespace avian { namespace codegen { namespace compiler { LogicalInstruction::LogicalInstruction(int index, Stack* stack, Local* locals): firstEvent(0), lastEvent(0), immediatePredecessor(0), stack(stack), locals(locals), machineOffset(0), subroutine(0), index(index) { } LogicalInstruction* LogicalInstruction::next(Context* c) { LogicalInstruction* i = this; for (unsigned n = i->index + 1; n < c->logicalCodeLength; ++n) { i = c->logicalCode[n]; if (i) return i; } return 0; } unsigned machineOffset(Context* c, int logicalIp) { return c->logicalCode[logicalIp]->machineOffset->value(); } Block::Block(Event* head): head(head), nextBlock(0), nextInstruction(0), assemblerBlock(0), start(0) { } Block* block(Context* c, Event* head) { return new(c->zone) Block(head); } } // namespace compiler } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/compiler/ir.h000066400000000000000000000035141231440243200217530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_IR_H #define AVIAN_CODEGEN_COMPILER_IR_H namespace avian { namespace codegen { namespace compiler { class MultiRead; class ForkElement { public: Value* value; MultiRead* read; bool local; }; class ForkState: public Compiler::State { public: ForkState(Stack* stack, Local* locals, List* saved, Event* predecessor, unsigned logicalIp): stack(stack), locals(locals), saved(saved), predecessor(predecessor), logicalIp(logicalIp), readCount(0) { } Stack* stack; Local* locals; List* saved; Event* predecessor; unsigned logicalIp; unsigned readCount; ForkElement elements[0]; }; class LogicalInstruction { public: LogicalInstruction(int index, Stack* stack, Local* locals); LogicalInstruction* next(Context* c); Event* firstEvent; Event* lastEvent; LogicalInstruction* immediatePredecessor; Stack* stack; Local* locals; Promise* machineOffset; MySubroutine* subroutine; int index; }; class MySubroutine: public Compiler::Subroutine { public: MySubroutine(): forkState(0) { } ForkState* forkState; }; class Block { public: Block(Event* head); Event* head; Block* nextBlock; LogicalInstruction* nextInstruction; Assembler::Block* assemblerBlock; unsigned start; }; Block* block(Context* c, Event* head); unsigned machineOffset(Context* c, int logicalIp); } // namespace compiler } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_IR_H ReadyTalk-avian-1e1fff5/src/codegen/compiler/promise.cpp000066400000000000000000000050631231440243200233530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include "codegen/compiler/context.h" #include "codegen/compiler/promise.h" #include "codegen/compiler/ir.h" namespace avian { namespace codegen { namespace compiler { CodePromise::CodePromise(Context* c, CodePromise* next): c(c), offset(0), next(next) { } CodePromise::CodePromise(Context* c, Promise* offset): c(c), offset(offset), next(0) { } int64_t CodePromise::value() { if (resolved()) { return reinterpret_cast(c->machineCode + offset->value()); } abort(c); } bool CodePromise::resolved() { return c->machineCode != 0 and offset and offset->resolved(); } CodePromise* codePromise(Context* c, Promise* offset) { return new (c->zone) CodePromise(c, offset); } Promise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) { return new (c->zone) ShiftMaskPromise(base, shift, mask); } Promise* combinedPromise(Context* c, Promise* low, Promise* high) { return new (c->zone) CombinedPromise(low, high); } Promise* resolvedPromise(Context* c, int64_t value) { return new (c->zone) ResolvedPromise(value); } class IpPromise: public Promise { public: IpPromise(Context* c, int logicalIp): c(c), logicalIp(logicalIp) { } virtual int64_t value() { if (resolved()) { return reinterpret_cast (c->machineCode + machineOffset(c, logicalIp)); } abort(c); } virtual bool resolved() { return c->machineCode != 0 and c->logicalCode[logicalIp]->machineOffset->resolved(); } Context* c; int logicalIp; }; Promise* ipPromise(Context* c, int logicalIp) { return new (c->zone) IpPromise(c, logicalIp); } class PoolPromise: public Promise { public: PoolPromise(Context* c, int key): c(c), key(key) { } virtual int64_t value() { if (resolved()) { return reinterpret_cast (c->machineCode + vm::pad(c->machineCodeSize, vm::TargetBytesPerWord) + (key * vm::TargetBytesPerWord)); } abort(c); } virtual bool resolved() { return c->machineCode != 0; } Context* c; int key; }; Promise* poolPromise(Context* c, int key) { return new(c->zone) PoolPromise(c, key); } } // namespace compiler } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/compiler/promise.h000066400000000000000000000022751231440243200230220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_PROMISE_H #define AVIAN_CODEGEN_COMPILER_PROMISE_H namespace avian { namespace codegen { namespace compiler { class CodePromise: public Promise { public: CodePromise(Context* c, CodePromise* next); CodePromise(Context* c, Promise* offset); virtual int64_t value(); virtual bool resolved(); Context* c; Promise* offset; CodePromise* next; }; CodePromise* codePromise(Context* c, Promise* offset); Promise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask); Promise* combinedPromise(Context* c, Promise* low, Promise* high); Promise* resolvedPromise(Context* c, int64_t value); Promise* ipPromise(Context* c, int logicalIp); Promise* poolPromise(Context* c, int key); } // namespace compiler } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_PROMISE_H ReadyTalk-avian-1e1fff5/src/codegen/compiler/read.cpp000066400000000000000000000075001231440243200226060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include "codegen/compiler/context.h" #include "codegen/compiler/value.h" #include "codegen/compiler/site.h" #include "codegen/compiler/resource.h" #include "codegen/compiler/read.h" namespace avian { namespace codegen { namespace compiler { SingleRead::SingleRead(const SiteMask& mask, Value* successor): next_(0), mask(mask), high_(0), successor_(successor) { } bool SingleRead::intersect(SiteMask* mask, unsigned) { *mask = mask->intersectionWith(this->mask); return true; } Value* SingleRead::high(Context*) { return high_; } Value* SingleRead::successor() { return successor_; } bool SingleRead::valid() { return true; } void SingleRead::append(Context* c UNUSED, Read* r) { assert(c, next_ == 0); next_ = r; } Read* SingleRead::next(Context*) { return next_; } MultiRead::MultiRead(): reads(0), lastRead(0), firstTarget(0), lastTarget(0), visited(false) { } bool MultiRead::intersect(SiteMask* mask, unsigned depth) { if (depth > 0) { // short-circuit recursion to avoid poor performance in // deeply-nested branches return reads != 0; } bool result = false; if (not visited) { visited = true; for (List** cell = &reads; *cell;) { Read* r = (*cell)->item; bool valid = r->intersect(mask, depth + 1); if (valid) { result = true; cell = &((*cell)->next); } else { *cell = (*cell)->next; } } visited = false; } return result; } Value* MultiRead::successor() { return 0; } bool MultiRead::valid() { bool result = false; if (not visited) { visited = true; for (List** cell = &reads; *cell;) { Read* r = (*cell)->item; if (r->valid()) { result = true; cell = &((*cell)->next); } else { *cell = (*cell)->next; } } visited = false; } return result; } void MultiRead::append(Context* c, Read* r) { List* cell = cons(c, r, 0); if (lastRead == 0) { reads = cell; } else { lastRead->next = cell; } lastRead = cell; // fprintf(stderr, "append %p to %p for %p\n", r, lastTarget, this); lastTarget->item = r; } Read* MultiRead::next(Context* c) { abort(c); } void MultiRead::allocateTarget(Context* c) { List* cell = cons(c, 0, 0); // fprintf(stderr, "allocate target for %p: %p\n", this, cell); if (lastTarget) { lastTarget->next = cell; } else { firstTarget = cell; } lastTarget = cell; } Read* MultiRead::nextTarget() { // fprintf(stderr, "next target for %p: %p\n", this, firstTarget); Read* r = firstTarget->item; firstTarget = firstTarget->next; return r; } StubRead::StubRead(): next_(0), read(0), visited(false), valid_(true) { } bool StubRead::intersect(SiteMask* mask, unsigned depth) { if (not visited) { visited = true; if (read) { bool valid = read->intersect(mask, depth); if (not valid) { read = 0; } } visited = false; } return valid_; } Value* StubRead::successor() { return 0; } bool StubRead::valid() { return valid_; } void StubRead::append(Context* c UNUSED, Read* r) { assert(c, next_ == 0); next_ = r; } Read* StubRead::next(Context*) { return next_; } SingleRead* read(Context* c, const SiteMask& mask, Value* successor) { assert(c, (mask.typeMask != 1 << lir::MemoryOperand) or mask.frameIndex >= 0); return new(c->zone) SingleRead(mask, successor); } } // namespace compiler } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/compiler/read.h000066400000000000000000000044451231440243200222600ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_READ_H #define AVIAN_CODEGEN_COMPILER_READ_H namespace avian { namespace codegen { namespace compiler { class Context; class SiteMask; class Value; class Event; class Read { public: Read(): value(0), event(0), eventNext(0) { } virtual bool intersect(SiteMask* mask, unsigned depth = 0) = 0; virtual Value* high(Context* c) { abort(c); } virtual Value* successor() = 0; virtual bool valid() = 0; virtual void append(Context* c, Read* r) = 0; virtual Read* next(Context* c) = 0; Value* value; Event* event; Read* eventNext; }; inline bool valid(Read* r) { return r and r->valid(); } class SingleRead: public Read { public: SingleRead(const SiteMask& mask, Value* successor); virtual bool intersect(SiteMask* mask, unsigned); virtual Value* high(Context*); virtual Value* successor(); virtual bool valid(); virtual void append(Context* c UNUSED, Read* r); virtual Read* next(Context*); Read* next_; SiteMask mask; Value* high_; Value* successor_; }; class MultiRead: public Read { public: MultiRead(); virtual bool intersect(SiteMask* mask, unsigned depth); virtual Value* successor(); virtual bool valid(); virtual void append(Context* c, Read* r); virtual Read* next(Context* c); void allocateTarget(Context* c); Read* nextTarget(); List* reads; List* lastRead; List* firstTarget; List* lastTarget; bool visited; }; class StubRead: public Read { public: StubRead(); virtual bool intersect(SiteMask* mask, unsigned depth); virtual Value* successor(); virtual bool valid(); virtual void append(Context* c UNUSED, Read* r); virtual Read* next(Context*); Read* next_; Read* read; bool visited; bool valid_; }; SingleRead* read(Context* c, const SiteMask& mask, Value* successor = 0); } // namespace compiler } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_READ_H ReadyTalk-avian-1e1fff5/src/codegen/compiler/regalloc.cpp000066400000000000000000000171371231440243200234720ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include "codegen/compiler/regalloc.h" #include "codegen/compiler/context.h" #include "codegen/compiler/site.h" #include "codegen/compiler/resource.h" #include "codegen/compiler/read.h" namespace avian { namespace codegen { namespace compiler { RegisterAllocator::RegisterAllocator(Aborter* a, const RegisterFile* registerFile): a(a), registerFile(registerFile) { } unsigned totalFrameSize(Context* c); Read* live(Context* c UNUSED, Value* v); unsigned resourceCost(Context* c, Value* v, Resource* r, SiteMask mask, CostCalculator* costCalculator) { if (r->reserved or r->freezeCount or r->referenceCount) { return Target::Impossible; } else { unsigned baseCost = costCalculator ? costCalculator->cost(c, mask) : 0; if (r->value) { assert(c, r->value->findSite(r->site)); if (v and r->value->isBuddyOf(v)) { return baseCost; } else if (r->value->uniqueSite(c, r->site)) { return baseCost + Target::StealUniquePenalty; } else { return baseCost = Target::StealPenalty; } } else { return baseCost; } } } bool pickRegisterTarget(Context* c, int i, Value* v, uint32_t mask, int* target, unsigned* cost, CostCalculator* costCalculator) { if ((1 << i) & mask) { RegisterResource* r = c->registerResources + i; unsigned myCost = resourceCost (c, v, r, SiteMask(1 << lir::RegisterOperand, 1 << i, NoFrameIndex), costCalculator) + Target::MinimumRegisterCost; if ((static_cast(1) << i) == mask) { *cost = myCost; return true; } else if (myCost < *cost) { *cost = myCost; *target = i; } } return false; } int pickRegisterTarget(Context* c, Value* v, uint32_t mask, unsigned* cost, CostCalculator* costCalculator) { int target = lir::NoRegister; *cost = Target::Impossible; if (mask & c->regFile->generalRegisters.mask) { for (int i = c->regFile->generalRegisters.limit - 1; i >= c->regFile->generalRegisters.start; --i) { if (pickRegisterTarget(c, i, v, mask, &target, cost, costCalculator)) { return i; } } } if (mask & c->regFile->floatRegisters.mask) { for (int i = c->regFile->floatRegisters.start; i < static_cast(c->regFile->floatRegisters.limit); ++i) { if (pickRegisterTarget(c, i, v, mask, &target, cost, costCalculator)) { return i; } } } return target; } Target pickRegisterTarget(Context* c, Value* v, uint32_t mask, CostCalculator* costCalculator) { unsigned cost; int number = pickRegisterTarget(c, v, mask, &cost, costCalculator); return Target(number, lir::RegisterOperand, cost); } unsigned frameCost(Context* c, Value* v, int frameIndex, CostCalculator* costCalculator) { return resourceCost (c, v, c->frameResources + frameIndex, SiteMask(1 << lir::MemoryOperand, 0, frameIndex), costCalculator) + Target::MinimumFrameCost; } Target pickFrameTarget(Context* c, Value* v, CostCalculator* costCalculator) { Target best; Value* p = v; do { if (p->home >= 0) { Target mine (p->home, lir::MemoryOperand, frameCost(c, v, p->home, costCalculator)); if (mine.cost == Target::MinimumFrameCost) { return mine; } else if (mine.cost < best.cost) { best = mine; } } p = p->buddy; } while (p != v); return best; } Target pickAnyFrameTarget(Context* c, Value* v, CostCalculator* costCalculator) { Target best; unsigned count = totalFrameSize(c); for (unsigned i = 0; i < count; ++i) { Target mine(i, lir::MemoryOperand, frameCost(c, v, i, costCalculator)); if (mine.cost == Target::MinimumFrameCost) { return mine; } else if (mine.cost < best.cost) { best = mine; } } return best; } Target pickTarget(Context* c, Value* value, const SiteMask& mask, unsigned registerPenalty, Target best, CostCalculator* costCalculator) { if (mask.typeMask & (1 << lir::RegisterOperand)) { Target mine = pickRegisterTarget (c, value, mask.registerMask, costCalculator); mine.cost += registerPenalty; if (mine.cost == Target::MinimumRegisterCost) { return mine; } else if (mine.cost < best.cost) { best = mine; } } if (mask.typeMask & (1 << lir::MemoryOperand)) { if (mask.frameIndex >= 0) { Target mine(mask.frameIndex, lir::MemoryOperand, frameCost(c, value, mask.frameIndex, costCalculator)); if (mine.cost == Target::MinimumFrameCost) { return mine; } else if (mine.cost < best.cost) { best = mine; } } else if (mask.frameIndex == AnyFrameIndex) { Target mine = pickFrameTarget(c, value, costCalculator); if (mine.cost == Target::MinimumFrameCost) { return mine; } else if (mine.cost < best.cost) { best = mine; } } } return best; } Target pickTarget(Context* c, Read* read, bool intersectRead, unsigned registerReserveCount, CostCalculator* costCalculator) { unsigned registerPenalty = (c->availableGeneralRegisterCount > registerReserveCount ? 0 : Target::LowRegisterPenalty); Value* value = read->value; uint32_t registerMask = (value->type == lir::ValueFloat ? ~0 : c->regFile->generalRegisters.mask); SiteMask mask(~0, registerMask, AnyFrameIndex); read->intersect(&mask); if (value->type == lir::ValueFloat) { uint32_t floatMask = mask.registerMask & c->regFile->floatRegisters.mask; if (floatMask) { mask.registerMask = floatMask; } } Target best; Value* successor = read->successor(); if (successor) { Read* r = live(c, successor); if (r) { SiteMask intersection = mask; if (r->intersect(&intersection)) { best = pickTarget (c, value, intersection, registerPenalty, best, costCalculator); if (best.cost <= Target::MinimumFrameCost) { return best; } } } } best = pickTarget(c, value, mask, registerPenalty, best, costCalculator); if (best.cost <= Target::MinimumFrameCost) { return best; } if (intersectRead) { if (best.cost == Target::Impossible) { fprintf(stderr, "mask type %d reg %d frame %d\n", mask.typeMask, mask.registerMask, mask.frameIndex); abort(c); } return best; } { Target mine = pickRegisterTarget(c, value, registerMask, costCalculator); mine.cost += registerPenalty; if (mine.cost == Target::MinimumRegisterCost) { return mine; } else if (mine.cost < best.cost) { best = mine; } } { Target mine = pickFrameTarget(c, value, costCalculator); if (mine.cost == Target::MinimumFrameCost) { return mine; } else if (mine.cost < best.cost) { best = mine; } } if (best.cost >= Target::StealUniquePenalty and c->availableGeneralRegisterCount == 0) { // there are no free registers left, so moving from memory to // memory isn't an option - try harder to find an available frame // site: best = pickAnyFrameTarget(c, value, costCalculator); assert(c, best.cost <= 3); } if (best.cost == Target::Impossible) { abort(c); } return best; } } // namespace regalloc } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/compiler/regalloc.h000066400000000000000000000052661231440243200231370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_REGALLOC_H #define AVIAN_CODEGEN_COMPILER_REGALLOC_H #include "avian/common.h" #include #include namespace avian { namespace util { class Aborter; } // namespace util namespace codegen { namespace compiler { using namespace avian::util; class Context; class Value; class SiteMask; class Resource; class Read; class RegisterAllocator { public: Aborter* a; const RegisterFile* registerFile; RegisterAllocator(Aborter* a, const RegisterFile* registerFile); }; class Target { public: static const unsigned MinimumRegisterCost = 0; static const unsigned MinimumFrameCost = 1; static const unsigned StealPenalty = 2; static const unsigned StealUniquePenalty = 4; static const unsigned IndirectMovePenalty = 4; static const unsigned LowRegisterPenalty = 10; static const unsigned Impossible = 20; Target(): cost(Impossible) { } Target(int index, lir::OperandType type, unsigned cost): index(index), type(type), cost(cost) { } int16_t index; lir::OperandType type; uint8_t cost; }; class CostCalculator { public: virtual unsigned cost(Context* c, SiteMask mask) = 0; }; unsigned resourceCost(Context* c, Value* v, Resource* r, SiteMask mask, CostCalculator* costCalculator); bool pickRegisterTarget(Context* c, int i, Value* v, uint32_t mask, int* target, unsigned* cost, CostCalculator* costCalculator = 0); int pickRegisterTarget(Context* c, Value* v, uint32_t mask, unsigned* cost, CostCalculator* costCalculator = 0); Target pickRegisterTarget(Context* c, Value* v, uint32_t mask, CostCalculator* costCalculator = 0); unsigned frameCost(Context* c, Value* v, int frameIndex, CostCalculator* costCalculator); Target pickFrameTarget(Context* c, Value* v, CostCalculator* costCalculator); Target pickAnyFrameTarget(Context* c, Value* v, CostCalculator* costCalculator); Target pickTarget(Context* c, Value* value, const SiteMask& mask, unsigned registerPenalty, Target best, CostCalculator* costCalculator); Target pickTarget(Context* c, Read* read, bool intersectRead, unsigned registerReserveCount, CostCalculator* costCalculator); } // namespace regalloc } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_REGALLOC_H ReadyTalk-avian-1e1fff5/src/codegen/compiler/resource.cpp000066400000000000000000000131261231440243200235230ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "codegen/compiler/context.h" #include "codegen/compiler/resource.h" #include "codegen/compiler/value.h" namespace avian { namespace codegen { namespace compiler { const bool DebugResources = false; void steal(Context* c, Resource* r, Value* thief); void decrementAvailableGeneralRegisterCount(Context* c) { assert(c, c->availableGeneralRegisterCount); -- c->availableGeneralRegisterCount; if (DebugResources) { fprintf(stderr, "%d registers available\n", c->availableGeneralRegisterCount); } } void incrementAvailableGeneralRegisterCount(Context* c) { ++ c->availableGeneralRegisterCount; if (DebugResources) { fprintf(stderr, "%d registers available\n", c->availableGeneralRegisterCount); } } void freezeResource(Context* c, Resource* r, Value* v) { if (DebugResources) { char buffer[256]; r->toString(c, buffer, 256); fprintf(stderr, "%p freeze %s to %d\n", v, buffer, r->freezeCount + 1); } ++ r->freezeCount; } void thawResource(Context* c, Resource* r, Value* v) { if (not r->reserved) { if (DebugResources) { char buffer[256]; r->toString(c, buffer, 256); fprintf(stderr, "%p thaw %s to %d\n", v, buffer, r->freezeCount - 1); } assert(c, r->freezeCount); -- r->freezeCount; } } Resource::Resource(bool reserved): value(0), site(0), previousAcquired(0), nextAcquired(0), freezeCount(0), referenceCount(0), reserved(reserved) { } RegisterResource::RegisterResource(bool reserved): Resource(reserved) { } void RegisterResource::freeze(Context* c, Value* v) { if (not reserved) { freezeResource(c, this, v); if (freezeCount == 1 and ((1 << index(c)) & c->regFile->generalRegisters.mask)) { decrementAvailableGeneralRegisterCount(c); } } } void RegisterResource::thaw(Context* c, Value* v) { if (not reserved) { thawResource(c, this, v); if (freezeCount == 0 and ((1 << index(c)) & c->regFile->generalRegisters.mask)) { incrementAvailableGeneralRegisterCount(c); } } } unsigned RegisterResource::toString(Context* c, char* buffer, unsigned bufferSize) { return vm::snprintf(buffer, bufferSize, "register %d", index(c)); } unsigned RegisterResource::index(Context* c) { return this - c->registerResources; } void RegisterResource::increment(Context* c) { if (not this->reserved) { if (DebugResources) { char buffer[256]; this->toString(c, buffer, 256); fprintf(stderr, "increment %s to %d\n", buffer, this->referenceCount + 1); } ++ this->referenceCount; if (this->referenceCount == 1 and ((1 << this->index(c)) & c->regFile->generalRegisters.mask)) { decrementAvailableGeneralRegisterCount(c); } } } void RegisterResource::decrement(Context* c) { if (not this->reserved) { if (DebugResources) { char buffer[256]; this->toString(c, buffer, 256); fprintf(stderr, "decrement %s to %d\n", buffer, this->referenceCount - 1); } assert(c, this->referenceCount > 0); -- this->referenceCount; if (this->referenceCount == 0 and ((1 << this->index(c)) & c->regFile->generalRegisters.mask)) { incrementAvailableGeneralRegisterCount(c); } } } void FrameResource::freeze(Context* c, Value* v) { freezeResource(c, this, v); } void FrameResource::thaw(Context* c, Value* v) { thawResource(c, this, v); } unsigned FrameResource::toString(Context* c, char* buffer, unsigned bufferSize) { return vm::snprintf(buffer, bufferSize, "frame %d", index(c)); } unsigned FrameResource::index(Context* c) { return this - c->frameResources; } void acquire(Context* c, Resource* resource, Value* value, Site* site) { assert(c, value); assert(c, site); if (not resource->reserved) { if (DebugResources) { char buffer[256]; resource->toString(c, buffer, 256); fprintf(stderr, "%p acquire %s\n", value, buffer); } if (resource->value) { assert(c, resource->value->findSite(resource->site)); assert(c, not value->findSite(resource->site)); steal(c, resource, value); } if (c->acquiredResources) { c->acquiredResources->previousAcquired = resource; resource->nextAcquired = c->acquiredResources; } c->acquiredResources = resource; resource->value = value; resource->site = site; } } void release(Context* c, Resource* resource, Value* value UNUSED, Site* site UNUSED) { if (not resource->reserved) { if (DebugResources) { char buffer[256]; resource->toString(c, buffer, 256); fprintf(stderr, "%p release %s\n", resource->value, buffer); } assert(c, resource->value); assert(c, resource->site); assert(c, resource->value->isBuddyOf(value)); assert(c, site == resource->site); Resource* next = resource->nextAcquired; if (next) { next->previousAcquired = resource->previousAcquired; resource->nextAcquired = 0; } Resource* previous = resource->previousAcquired; if (previous) { previous->nextAcquired = next; resource->previousAcquired = 0; } else { assert(c, c->acquiredResources == resource); c->acquiredResources = next; } resource->value = 0; resource->site = 0; } } } // namespace compiler } // namespace codegen } // namespace avianReadyTalk-avian-1e1fff5/src/codegen/compiler/resource.h000066400000000000000000000033341231440243200231700ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_RESOURCE_H #define AVIAN_CODEGEN_COMPILER_RESOURCE_H namespace avian { namespace codegen { namespace compiler { class Context; class Value; class Site; class Resource { public: Resource(bool reserved = false); virtual void freeze(Context*, Value*) = 0; virtual void thaw(Context*, Value*) = 0; virtual unsigned toString(Context*, char*, unsigned) = 0; Value* value; Site* site; Resource* previousAcquired; Resource* nextAcquired; uint8_t freezeCount; uint8_t referenceCount; bool reserved; }; class RegisterResource: public Resource { public: RegisterResource(bool reserved); virtual void freeze(Context*, Value*); virtual void thaw(Context*, Value*); virtual unsigned toString(Context* c, char* buffer, unsigned bufferSize); virtual unsigned index(Context*); void increment(Context*); void decrement(Context*); }; class FrameResource: public Resource { public: virtual void freeze(Context*, Value*); virtual void thaw(Context*, Value*); virtual unsigned toString(Context* c, char* buffer, unsigned bufferSize); virtual unsigned index(Context*); }; void acquire(Context* c, Resource* resource, Value* value, Site* site); void release(Context* c, Resource* resource, Value* value, Site* site); } // namespace compiler } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_RESOURCE_H ReadyTalk-avian-1e1fff5/src/codegen/compiler/site.cpp000066400000000000000000000372131231440243200226430ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include "codegen/compiler/context.h" #include "codegen/compiler/value.h" #include "codegen/compiler/site.h" #include "codegen/compiler/resource.h" #include "codegen/compiler/frame.h" #include "codegen/compiler/promise.h" namespace avian { namespace codegen { namespace compiler { int intersectFrameIndexes(int a, int b) { if (a == NoFrameIndex or b == NoFrameIndex) return NoFrameIndex; if (a == AnyFrameIndex) return b; if (b == AnyFrameIndex) return a; if (a == b) return a; return NoFrameIndex; } SiteMask SiteMask::intersectionWith(const SiteMask& b) { return SiteMask(typeMask & b.typeMask, registerMask & b.registerMask, intersectFrameIndexes(frameIndex, b.frameIndex)); } SiteIterator::SiteIterator(Context* c, Value* v, bool includeBuddies, bool includeNextWord): c(c), originalValue(v), currentValue(v), includeBuddies(includeBuddies), includeNextWord(includeNextWord), pass(0), next_(findNext(&(v->sites))), previous(0) { } Site** SiteIterator::findNext(Site** p) { while (true) { if (*p) { if (pass == 0 or (*p)->registerSize(c) > vm::TargetBytesPerWord) { return p; } else { p = &((*p)->next); } } else { if (includeBuddies) { Value* v = currentValue->buddy; if (v != originalValue) { currentValue = v; p = &(v->sites); continue; } } if (includeNextWord and pass == 0) { Value* v = originalValue->nextWord; if (v != originalValue) { pass = 1; originalValue = v; currentValue = v; p = &(v->sites); continue; } } return 0; } } } bool SiteIterator::hasMore() { if (previous) { next_ = findNext(&((*previous)->next)); previous = 0; } return next_ != 0; } Site* SiteIterator::next() { previous = next_; return *previous; } void SiteIterator::remove(Context* c) { (*previous)->release(c, originalValue); *previous = (*previous)->next; next_ = findNext(previous); previous = 0; } unsigned Site::registerSize(Context*) { return vm::TargetBytesPerWord; } Site* constantSite(Context* c, Promise* value) { return new(c->zone) ConstantSite(value); } Site* constantSite(Context* c, int64_t value) { return constantSite(c, resolvedPromise(c, value)); } class AddressSite: public Site { public: AddressSite(Promise* address): address(address) { } virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) { if (address->resolved()) { return vm::snprintf (buffer, bufferSize, "address %" LLD, address->value()); } else { return vm::snprintf(buffer, bufferSize, "address unresolved"); } } virtual unsigned copyCost(Context*, Site* s) { return (s == this ? 0 : AddressCopyCost); } virtual bool match(Context*, const SiteMask& mask) { return mask.typeMask & (1 << lir::AddressOperand); } virtual bool loneMatch(Context*, const SiteMask&) { return false; } virtual bool matchNextWord(Context* c, Site*, unsigned) { abort(c); } virtual lir::OperandType type(Context*) { return lir::AddressOperand; } virtual void asAssemblerOperand(Context* c UNUSED, Site* high UNUSED, lir::Operand* result) { assert(c, high == this); new (result) lir::Address(address); } virtual Site* copy(Context* c) { return addressSite(c, address); } virtual Site* copyLow(Context* c) { abort(c); } virtual Site* copyHigh(Context* c) { abort(c); } virtual Site* makeNextWord(Context* c, unsigned) { abort(c); } virtual SiteMask mask(Context*) { return SiteMask(1 << lir::AddressOperand, 0, NoFrameIndex); } virtual SiteMask nextWordMask(Context* c, unsigned) { abort(c); } Promise* address; }; Site* addressSite(Context* c, Promise* address) { return new(c->zone) AddressSite(address); } RegisterSite::RegisterSite(uint32_t mask, int number): mask_(mask), number(number) { } unsigned RegisterSite::toString(Context*, char* buffer, unsigned bufferSize) { if (number != lir::NoRegister) { return vm::snprintf(buffer, bufferSize, "%p register %d", this, number); } else { return vm::snprintf(buffer, bufferSize, "%p register unacquired (mask %d)", this, mask_); } } unsigned RegisterSite::copyCost(Context* c, Site* s) { assert(c, number != lir::NoRegister); if (s and (this == s or (s->type(c) == lir::RegisterOperand and (static_cast(s)->mask_ & (1 << number))))) { return 0; } else { return RegisterCopyCost; } } bool RegisterSite::match(Context* c UNUSED, const SiteMask& mask) { assert(c, number != lir::NoRegister); if ((mask.typeMask & (1 << lir::RegisterOperand))) { return ((static_cast(1) << number) & mask.registerMask); } else { return false; } } bool RegisterSite::loneMatch(Context* c UNUSED, const SiteMask& mask) { assert(c, number != lir::NoRegister); if ((mask.typeMask & (1 << lir::RegisterOperand))) { return ((static_cast(1) << number) == mask.registerMask); } else { return false; } } bool RegisterSite::matchNextWord(Context* c, Site* s, unsigned) { assert(c, number != lir::NoRegister); if (s->type(c) != lir::RegisterOperand) { return false; } RegisterSite* rs = static_cast(s); unsigned size = rs->registerSize(c); if (size > vm::TargetBytesPerWord) { assert(c, number != lir::NoRegister); return number == rs->number; } else { uint32_t mask = c->regFile->generalRegisters.mask; return ((1 << number) & mask) and ((1 << rs->number) & mask); } } void RegisterSite::acquire(Context* c, Value* v) { Target target; if (number != lir::NoRegister) { target = Target(number, lir::RegisterOperand, 0); } else { target = pickRegisterTarget(c, v, mask_); expect(c, target.cost < Target::Impossible); } RegisterResource* resource = c->registerResources + target.index; compiler::acquire(c, resource, v, this); number = target.index; } void RegisterSite::release(Context* c, Value* v) { assert(c, number != lir::NoRegister); compiler::release(c, c->registerResources + number, v, this); } void RegisterSite::freeze(Context* c, Value* v) { assert(c, number != lir::NoRegister); c->registerResources[number].freeze(c, v); } void RegisterSite::thaw(Context* c, Value* v) { assert(c, number != lir::NoRegister); c->registerResources[number].thaw(c, v); } bool RegisterSite::frozen(Context* c UNUSED) { assert(c, number != lir::NoRegister); return c->registerResources[number].freezeCount != 0; } lir::OperandType RegisterSite::type(Context*) { return lir::RegisterOperand; } void RegisterSite::asAssemblerOperand(Context* c UNUSED, Site* high, lir::Operand* result) { assert(c, number != lir::NoRegister); int highNumber; if (high != this) { highNumber = static_cast(high)->number; assert(c, highNumber != lir::NoRegister); } else { highNumber = lir::NoRegister; } new (result) lir::Register(number, highNumber); } Site* RegisterSite::copy(Context* c) { uint32_t mask; if (number != lir::NoRegister) { mask = 1 << number; } else { mask = mask_; } return freeRegisterSite(c, mask); } Site* RegisterSite::copyLow(Context* c) { abort(c); } Site* RegisterSite::copyHigh(Context* c) { abort(c); } Site* RegisterSite::makeNextWord(Context* c, unsigned) { assert(c, number != lir::NoRegister); assert(c, ((1 << number) & c->regFile->generalRegisters.mask)); return freeRegisterSite(c, c->regFile->generalRegisters.mask); } SiteMask RegisterSite::mask(Context* c UNUSED) { return SiteMask(1 << lir::RegisterOperand, mask_, NoFrameIndex); } SiteMask RegisterSite::nextWordMask(Context* c, unsigned) { assert(c, number != lir::NoRegister); if (registerSize(c) > vm::TargetBytesPerWord) { return SiteMask (1 << lir::RegisterOperand, number, NoFrameIndex); } else { return SiteMask (1 << lir::RegisterOperand, c->regFile->generalRegisters.mask, NoFrameIndex); } } unsigned RegisterSite::registerSize(Context* c) { assert(c, number != lir::NoRegister); if ((1 << number) & c->regFile->floatRegisters.mask) { return c->arch->floatRegisterSize(); } else { return vm::TargetBytesPerWord; } } unsigned RegisterSite::registerMask(Context* c UNUSED) { assert(c, number != lir::NoRegister); return 1 << number; } Site* registerSite(Context* c, int number) { assert(c, number >= 0); assert(c, (1 << number) & (c->regFile->generalRegisters.mask | c->regFile->floatRegisters.mask)); return new(c->zone) RegisterSite(1 << number, number); } Site* freeRegisterSite(Context* c, uint32_t mask) { return new(c->zone) RegisterSite(mask, lir::NoRegister); } MemorySite::MemorySite(int base, int offset, int index, unsigned scale): acquired(false), base(base), offset(offset), index(index), scale(scale) { } unsigned MemorySite::toString(Context*, char* buffer, unsigned bufferSize) { if (acquired) { return vm::snprintf(buffer, bufferSize, "memory %d 0x%x %d %d", base, offset, index, scale); } else { return vm::snprintf(buffer, bufferSize, "memory unacquired"); } } unsigned MemorySite::copyCost(Context* c, Site* s) { assert(c, acquired); if (s and (this == s or (s->type(c) == lir::MemoryOperand and static_cast(s)->base == base and static_cast(s)->offset == offset and static_cast(s)->index == index and static_cast(s)->scale == scale))) { return 0; } else { return MemoryCopyCost; } } bool MemorySite::conflicts(const SiteMask& mask) { return (mask.typeMask & (1 << lir::RegisterOperand)) != 0 and (((1 << base) & mask.registerMask) == 0 or (index != lir::NoRegister and ((1 << index) & mask.registerMask) == 0)); } bool MemorySite::match(Context* c, const SiteMask& mask) { assert(c, acquired); if (mask.typeMask & (1 << lir::MemoryOperand)) { if (mask.frameIndex >= 0) { if (base == c->arch->stack()) { assert(c, index == lir::NoRegister); return static_cast(frameIndexToOffset(c, mask.frameIndex)) == offset; } else { return false; } } else { return true; } } else { return false; } } bool MemorySite::loneMatch(Context* c, const SiteMask& mask) { assert(c, acquired); if (mask.typeMask & (1 << lir::MemoryOperand)) { if (base == c->arch->stack()) { assert(c, index == lir::NoRegister); if (mask.frameIndex == AnyFrameIndex) { return false; } else { return true; } } } return false; } bool MemorySite::matchNextWord(Context* c, Site* s, unsigned index) { if (s->type(c) == lir::MemoryOperand) { MemorySite* ms = static_cast(s); return ms->base == this->base and ((index == 1 and ms->offset == static_cast (this->offset + vm::TargetBytesPerWord)) or (index == 0 and this->offset == static_cast (ms->offset + vm::TargetBytesPerWord))) and ms->index == this->index and ms->scale == this->scale; } else { return false; } } void MemorySite::acquire(Context* c, Value* v) { c->registerResources[base].increment(c); if (index != lir::NoRegister) { c->registerResources[index].increment(c); } if (base == c->arch->stack()) { assert(c, index == lir::NoRegister); assert (c, not c->frameResources[offsetToFrameIndex(c, offset)].reserved); compiler::acquire (c, c->frameResources + offsetToFrameIndex(c, offset), v, this); } acquired = true; } void MemorySite::release(Context* c, Value* v) { if (base == c->arch->stack()) { assert(c, index == lir::NoRegister); assert (c, not c->frameResources[offsetToFrameIndex(c, offset)].reserved); compiler::release (c, c->frameResources + offsetToFrameIndex(c, offset), v, this); } c->registerResources[base].decrement(c); if (index != lir::NoRegister) { c->registerResources[index].decrement(c); } acquired = false; } void MemorySite::freeze(Context* c, Value* v) { if (base == c->arch->stack()) { c->frameResources[offsetToFrameIndex(c, offset)].freeze(c, v); } else { c->registerResources[base].increment(c); if (index != lir::NoRegister) { c->registerResources[index].increment(c); } } } void MemorySite::thaw(Context* c, Value* v) { if (base == c->arch->stack()) { c->frameResources[offsetToFrameIndex(c, offset)].thaw(c, v); } else { c->registerResources[base].decrement(c); if (index != lir::NoRegister) { c->registerResources[index].decrement(c); } } } bool MemorySite::frozen(Context* c) { return base == c->arch->stack() and c->frameResources[offsetToFrameIndex(c, offset)].freezeCount != 0; } lir::OperandType MemorySite::type(Context*) { return lir::MemoryOperand; } void MemorySite::asAssemblerOperand(Context* c UNUSED, Site* high UNUSED, lir::Operand* result) { // todo: endianness? assert(c, high == this or (static_cast(high)->base == base and static_cast(high)->offset == static_cast(offset + vm::TargetBytesPerWord) and static_cast(high)->index == index and static_cast(high)->scale == scale)); assert(c, acquired); new (result) lir::Memory(base, offset, index, scale); } Site* MemorySite::copy(Context* c) { return memorySite(c, base, offset, index, scale); } Site* MemorySite::copyHalf(Context* c, bool add) { if (add) { return memorySite(c, base, offset + vm::TargetBytesPerWord, index, scale); } else { return copy(c); } } Site* MemorySite::copyLow(Context* c) { return copyHalf(c, c->arch->bigEndian()); } Site* MemorySite::copyHigh(Context* c) { return copyHalf(c, not c->arch->bigEndian()); } Site* MemorySite::makeNextWord(Context* c, unsigned index) { return memorySite (c, base, offset + ((index == 1) xor c->arch->bigEndian() ? vm::TargetBytesPerWord : -vm::TargetBytesPerWord), this->index, scale); } SiteMask MemorySite::mask(Context* c) { return SiteMask(1 << lir::MemoryOperand, 0, (base == c->arch->stack()) ? static_cast(offsetToFrameIndex(c, offset)) : NoFrameIndex); } SiteMask MemorySite::nextWordMask(Context* c, unsigned index) { int frameIndex; if (base == c->arch->stack()) { assert(c, this->index == lir::NoRegister); frameIndex = static_cast(offsetToFrameIndex(c, offset)) + ((index == 1) xor c->arch->bigEndian() ? 1 : -1); } else { frameIndex = NoFrameIndex; } return SiteMask(1 << lir::MemoryOperand, 0, frameIndex); } bool MemorySite::isVolatile(Context* c) { return base != c->arch->stack(); } MemorySite* memorySite(Context* c, int base, int offset, int index, unsigned scale) { return new(c->zone) MemorySite(base, offset, index, scale); } MemorySite* frameSite(Context* c, int frameIndex) { assert(c, frameIndex >= 0); return memorySite (c, c->arch->stack(), frameIndexToOffset(c, frameIndex), lir::NoRegister, 0); } } // namespace compiler } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/compiler/site.h000066400000000000000000000176321231440243200223130ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_SITE_H #define AVIAN_CODEGEN_COMPILER_SITE_H #include #include "codegen/compiler/value.h" #include "codegen/compiler/context.h" namespace avian { namespace codegen { namespace compiler { class Context; const unsigned RegisterCopyCost = 1; const unsigned AddressCopyCost = 2; const unsigned ConstantCopyCost = 3; const unsigned MemoryCopyCost = 4; const unsigned CopyPenalty = 10; class SiteMask { public: SiteMask(): typeMask(~0), registerMask(~0), frameIndex(AnyFrameIndex) { } SiteMask(uint8_t typeMask, uint32_t registerMask, int frameIndex): typeMask(typeMask), registerMask(registerMask), frameIndex(frameIndex) { } SiteMask intersectionWith(const SiteMask& b); static SiteMask fixedRegisterMask(int number) { return SiteMask(1 << lir::RegisterOperand, 1 << number, NoFrameIndex); } static SiteMask lowPart(const OperandMask& mask) { return SiteMask(mask.typeMask, mask.registerMask, AnyFrameIndex); } static SiteMask highPart(const OperandMask& mask) { return SiteMask(mask.typeMask, mask.registerMask >> 32, AnyFrameIndex); } uint8_t typeMask; uint32_t registerMask; int frameIndex; }; class Site { public: Site(): next(0) { } virtual Site* readTarget(Context*, Read*) { return this; } virtual unsigned toString(Context*, char*, unsigned) = 0; virtual unsigned copyCost(Context*, Site*) = 0; virtual bool match(Context*, const SiteMask&) = 0; virtual bool loneMatch(Context*, const SiteMask&) = 0; virtual bool matchNextWord(Context*, Site*, unsigned) = 0; virtual void acquire(Context*, Value*) { } virtual void release(Context*, Value*) { } virtual void freeze(Context*, Value*) { } virtual void thaw(Context*, Value*) { } virtual bool frozen(Context*) { return false; } virtual lir::OperandType type(Context*) = 0; virtual void asAssemblerOperand(Context*, Site*, lir::Operand*) = 0; virtual Site* copy(Context*) = 0; virtual Site* copyLow(Context*) = 0; virtual Site* copyHigh(Context*) = 0; virtual Site* makeNextWord(Context*, unsigned) = 0; virtual SiteMask mask(Context*) = 0; virtual SiteMask nextWordMask(Context*, unsigned) = 0; virtual unsigned registerSize(Context*); virtual unsigned registerMask(Context*) { return 0; } virtual bool isVolatile(Context*) { return false; } Site* next; }; class SiteIterator { public: SiteIterator(Context* c, Value* v, bool includeBuddies = true, bool includeNextWord = true); Site** findNext(Site** p); bool hasMore(); Site* next(); void remove(Context* c); Context* c; Value* originalValue; Value* currentValue; bool includeBuddies; bool includeNextWord; uint8_t pass; Site** next_; Site** previous; }; Site* constantSite(Context* c, Promise* value); Site* constantSite(Context* c, int64_t value); Promise* combinedPromise(Context* c, Promise* low, Promise* high); Promise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask); class ConstantSite: public Site { public: ConstantSite(Promise* value): value(value) { } virtual unsigned toString(Context*, char* buffer, unsigned bufferSize) { if (value->resolved()) { return vm::snprintf (buffer, bufferSize, "constant %" LLD, value->value()); } else { return vm::snprintf(buffer, bufferSize, "constant unresolved"); } } virtual unsigned copyCost(Context*, Site* s) { return (s == this ? 0 : ConstantCopyCost); } virtual bool match(Context*, const SiteMask& mask) { return mask.typeMask & (1 << lir::ConstantOperand); } virtual bool loneMatch(Context*, const SiteMask&) { return true; } virtual bool matchNextWord(Context* c, Site* s, unsigned) { return s->type(c) == lir::ConstantOperand; } virtual lir::OperandType type(Context*) { return lir::ConstantOperand; } virtual void asAssemblerOperand(Context* c, Site* high, lir::Operand* result) { Promise* v = value; if (high != this) { v = combinedPromise(c, value, static_cast(high)->value); } new (result) lir::Constant(v); } virtual Site* copy(Context* c) { return constantSite(c, value); } virtual Site* copyLow(Context* c) { return constantSite(c, shiftMaskPromise(c, value, 0, 0xFFFFFFFF)); } virtual Site* copyHigh(Context* c) { return constantSite(c, shiftMaskPromise(c, value, 32, 0xFFFFFFFF)); } virtual Site* makeNextWord(Context* c, unsigned) { abort(c); } virtual SiteMask mask(Context*) { return SiteMask(1 << lir::ConstantOperand, 0, NoFrameIndex); } virtual SiteMask nextWordMask(Context*, unsigned) { return SiteMask(1 << lir::ConstantOperand, 0, NoFrameIndex); } Promise* value; }; Site* addressSite(Context* c, Promise* address); class RegisterSite: public Site { public: RegisterSite(uint32_t mask, int number); virtual unsigned toString(Context*, char* buffer, unsigned bufferSize); virtual unsigned copyCost(Context* c, Site* s); virtual bool match(Context* c UNUSED, const SiteMask& mask); virtual bool loneMatch(Context* c UNUSED, const SiteMask& mask); virtual bool matchNextWord(Context* c, Site* s, unsigned); virtual void acquire(Context* c, Value* v); virtual void release(Context* c, Value* v); virtual void freeze(Context* c, Value* v); virtual void thaw(Context* c, Value* v); virtual bool frozen(Context* c UNUSED); virtual lir::OperandType type(Context*); virtual void asAssemblerOperand(Context* c UNUSED, Site* high, lir::Operand* result); virtual Site* copy(Context* c); virtual Site* copyLow(Context* c); virtual Site* copyHigh(Context* c); virtual Site* makeNextWord(Context* c, unsigned); virtual SiteMask mask(Context* c UNUSED); virtual SiteMask nextWordMask(Context* c, unsigned); virtual unsigned registerSize(Context* c); virtual unsigned registerMask(Context* c UNUSED); uint32_t mask_; int number; }; Site* registerSite(Context* c, int number); Site* freeRegisterSite(Context* c, uint32_t mask); class MemorySite: public Site { public: MemorySite(int base, int offset, int index, unsigned scale); virtual unsigned toString(Context*, char* buffer, unsigned bufferSize); virtual unsigned copyCost(Context* c, Site* s); bool conflicts(const SiteMask& mask); virtual bool match(Context* c, const SiteMask& mask); virtual bool loneMatch(Context* c, const SiteMask& mask); virtual bool matchNextWord(Context* c, Site* s, unsigned index); virtual void acquire(Context* c, Value* v); virtual void release(Context* c, Value* v); virtual void freeze(Context* c, Value* v); virtual void thaw(Context* c, Value* v); virtual bool frozen(Context* c); virtual lir::OperandType type(Context*); virtual void asAssemblerOperand(Context* c UNUSED, Site* high UNUSED, lir::Operand* result); virtual Site* copy(Context* c); Site* copyHalf(Context* c, bool add); virtual Site* copyLow(Context* c); virtual Site* copyHigh(Context* c); virtual Site* makeNextWord(Context* c, unsigned index); virtual SiteMask mask(Context* c); virtual SiteMask nextWordMask(Context* c, unsigned index); virtual bool isVolatile(Context* c); bool acquired; int base; int offset; int index; unsigned scale; }; MemorySite* memorySite(Context* c, int base, int offset = 0, int index = lir::NoRegister, unsigned scale = 1); MemorySite* frameSite(Context* c, int frameIndex); } // namespace compiler } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_SITE_H ReadyTalk-avian-1e1fff5/src/codegen/compiler/value.cpp000066400000000000000000000072101231440243200230050ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include "codegen/compiler/regalloc.h" #include "codegen/compiler/site.h" namespace avian { namespace codegen { namespace compiler { Value::Value(Site* site, Site* target, lir::ValueType type): reads(0), lastRead(0), sites(site), source(0), target(target), buddy(this), nextWord(this), home(NoFrameIndex), type(type), wordIndex(0) { } bool Value::findSite(Site* site) { for (Site* s = this->sites; s; s = s->next) { if (s == site) return true; } return false; } bool Value::isBuddyOf(Value* b) { Value* a = this; if (a == b) return true; for (Value* p = a->buddy; p != a; p = p->buddy) { if (p == b) return true; } return false; } void Value::addSite(Context* c, Site* s) { if (not this->findSite(s)) { if (DebugSites) { char buffer[256]; s->toString(c, buffer, 256); fprintf(stderr, "add site %s to %p\n", buffer, this); } s->acquire(c, this); s->next = this->sites; this->sites = s; } } void Value::grow(Context* c) { assert(c, this->nextWord == this); Value* next = value(c, this->type); this->nextWord = next; next->nextWord = this; next->wordIndex = 1; } void Value::maybeSplit(Context* c) { if (this->nextWord == this) { this->split(c); } } void Value::split(Context* c) { this->grow(c); for (SiteIterator it(c, this); it.hasMore();) { Site* s = it.next(); this->removeSite(c, s); this->addSite(c, s->copyLow(c)); this->nextWord->addSite(c, s->copyHigh(c)); } } void Value::removeSite(Context* c, Site* s) { for (SiteIterator it(c, this); it.hasMore();) { if (s == it.next()) { if (DebugSites) { char buffer[256]; s->toString(c, buffer, 256); fprintf(stderr, "remove site %s from %p\n", buffer, this); } it.remove(c); break; } } if (DebugSites) { fprintf(stderr, "%p has more: %d\n", this, this->hasSite(c)); } assert(c, not this->findSite(s)); } bool Value::hasSite(Context* c) { SiteIterator it(c, this); return it.hasMore(); } bool Value::uniqueSite(Context* c, Site* s) { SiteIterator it(c, this); Site* p UNUSED = it.next(); if (it.hasMore()) { // the site is not this word's only site, but if the site is // shared with the next word, it may be that word's only site if (this->nextWord != this and s->registerSize(c) > vm::TargetBytesPerWord) { SiteIterator nit(c, this->nextWord); Site* p = nit.next(); if (nit.hasMore()) { return false; } else { return p == s; } } else { return false; } } else { assert(c, p == s); return true; } } void Value::clearSites(Context* c) { if (DebugSites) { fprintf(stderr, "clear sites for %p\n", this); } for (SiteIterator it(c, this); it.hasMore();) { it.next(); it.remove(c); } } #ifndef NDEBUG bool Value::hasBuddy(Context* c, Value* b) { Value* a = this; if (a == b) { return true; } int i = 0; for (Value* p = a->buddy; p != a; p = p->buddy) { if (p == b) { return true; } if (++i > 1000) { abort(c); } } return false; } #endif // not NDEBUG Value* value(Context* c, lir::ValueType type, Site* site, Site* target) { return new(c->zone) Value(site, target, type); } } // namespace regalloc } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/compiler/value.h000066400000000000000000000033621231440243200224560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_COMPILER_VALUE_H #define AVIAN_CODEGEN_COMPILER_VALUE_H #include #include namespace avian { namespace codegen { namespace compiler { class Read; class Site; const int AnyFrameIndex = -2; const int NoFrameIndex = -1; const bool DebugSites = false; class Value: public Compiler::Operand { public: Read* reads; Read* lastRead; Site* sites; Site* source; Site* target; Value* buddy; Value* nextWord; int16_t home; lir::ValueType type; uint8_t wordIndex; Value(Site* site, Site* target, lir::ValueType type); bool findSite(Site* site); bool isBuddyOf(Value* b); void addSite(Context* c, Site* s); void grow(Context* c); void maybeSplit(Context* c); void split(Context* c); void removeSite(Context* c, Site* s); bool hasSite(Context* c); bool uniqueSite(Context* c, Site* s); void clearSites(Context* c); #ifndef NDEBUG bool hasBuddy(Context* c, Value* b); #endif // not NDEBUG }; inline bool isGeneralValue(Compiler::Operand* a) { return static_cast(a)->type == lir::ValueGeneral; } inline bool isFloatValue(Compiler::Operand* a) { return static_cast(a)->type == lir::ValueFloat; } Value* value(Context* c, lir::ValueType type, Site* site = 0, Site* target = 0); } // namespace compiler } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_COMPILER_VALUE_H ReadyTalk-avian-1e1fff5/src/codegen/registers.cpp000066400000000000000000000013611231440243200220670ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include namespace avian { namespace codegen { unsigned RegisterMask::maskStart(uint32_t mask) { for (int i = 0; i <= 31; ++i) { if (mask & (1 << i)) return i; } return 32; } unsigned RegisterMask::maskLimit(uint32_t mask) { for (int i = 31; i >= 0; --i) { if (mask & (1 << i)) return i + 1; } return 0; } } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/runtime.cpp000066400000000000000000000125711231440243200215500ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include namespace avian { namespace codegen { namespace runtime { static bool isNaN(double v) { return fpclassify(v) == FP_NAN; } static bool isNaN(float v) { return fpclassify(v) == FP_NAN; } int64_t compareDoublesG(uint64_t bi, uint64_t ai) { double a = vm::bitsToDouble(ai); double b = vm::bitsToDouble(bi); if (isNaN(a) or isNaN(b)) { return 1; } else if (a < b) { return -1; } else if (a > b) { return 1; } else if (a == b) { return 0; } else { return 1; } } int64_t compareDoublesL(uint64_t bi, uint64_t ai) { double a = vm::bitsToDouble(ai); double b = vm::bitsToDouble(bi); if (isNaN(a) or isNaN(b)) { return -1; } else if (a < b) { return -1; } else if (a > b) { return 1; } else if (a == b) { return 0; } else { return -1; } } int64_t compareFloatsG(uint32_t bi, uint32_t ai) { float a = vm::bitsToFloat(ai); float b = vm::bitsToFloat(bi); if (isNaN(a) or isNaN(b)) { return 1; } if (a < b) { return -1; } else if (a > b) { return 1; } else if (a == b) { return 0; } else { return 1; } } int64_t compareFloatsL(uint32_t bi, uint32_t ai) { float a = vm::bitsToFloat(ai); float b = vm::bitsToFloat(bi); if (isNaN(a) or isNaN(b)) { return -1; } if (a < b) { return -1; } else if (a > b) { return 1; } else if (a == b) { return 0; } else { return -1; } } int64_t compareLongs(uint64_t b, uint64_t a) { if (a < b) { return -1; } else if (a > b) { return 1; } else { return 0; } } uint64_t addDouble(uint64_t b, uint64_t a) { return vm::doubleToBits(vm::bitsToDouble(a) + vm::bitsToDouble(b)); } uint64_t subtractDouble(uint64_t b, uint64_t a) { return vm::doubleToBits(vm::bitsToDouble(a) - vm::bitsToDouble(b)); } uint64_t multiplyDouble(uint64_t b, uint64_t a) { return vm::doubleToBits(vm::bitsToDouble(a) * vm::bitsToDouble(b)); } uint64_t divideDouble(uint64_t b, uint64_t a) { return vm::doubleToBits(vm::bitsToDouble(a) / vm::bitsToDouble(b)); } uint64_t moduloDouble(uint64_t b, uint64_t a) { return vm::doubleToBits(fmod(vm::bitsToDouble(a), vm::bitsToDouble(b))); } uint64_t negateDouble(uint64_t a) { return vm::doubleToBits(-vm::bitsToDouble(a)); } uint64_t squareRootDouble(uint64_t a) { return vm::doubleToBits(sqrt(vm::bitsToDouble(a))); } uint64_t doubleToFloat(int64_t a) { return vm::floatToBits(static_cast(vm::bitsToDouble(a))); } int64_t doubleToInt(int64_t a) { double f = vm::bitsToDouble(a); switch (fpclassify(f)) { case FP_NAN: return 0; case FP_INFINITE: return signbit(f) ? INT32_MIN : INT32_MAX; default: return f >= INT32_MAX ? INT32_MAX : (f <= INT32_MIN ? INT32_MIN : static_cast(f)); } } int64_t doubleToLong(int64_t a) { double f = vm::bitsToDouble(a); switch (fpclassify(f)) { case FP_NAN: return 0; case FP_INFINITE: return signbit(f) ? INT64_MIN : INT64_MAX; default: return f >= INT64_MAX ? INT64_MAX : (f <= INT64_MIN ? INT64_MIN : static_cast(f)); } } uint64_t addFloat(uint32_t b, uint32_t a) { return vm::floatToBits(vm::bitsToFloat(a) + vm::bitsToFloat(b)); } uint64_t subtractFloat(uint32_t b, uint32_t a) { return vm::floatToBits(vm::bitsToFloat(a) - vm::bitsToFloat(b)); } uint64_t multiplyFloat(uint32_t b, uint32_t a) { return vm::floatToBits(vm::bitsToFloat(a) * vm::bitsToFloat(b)); } uint64_t divideFloat(uint32_t b, uint32_t a) { return vm::floatToBits(vm::bitsToFloat(a) / vm::bitsToFloat(b)); } uint64_t moduloFloat(uint32_t b, uint32_t a) { return vm::floatToBits(fmod(vm::bitsToFloat(a), vm::bitsToFloat(b))); } uint64_t negateFloat(uint32_t a) { return vm::floatToBits(-vm::bitsToFloat(a)); } uint64_t absoluteFloat(uint32_t a) { return vm::floatToBits(fabsf(vm::bitsToFloat(a))); } int64_t absoluteLong(int64_t a) { return a > 0 ? a : -a; } int64_t absoluteInt(int32_t a) { return a > 0 ? a : -a; } uint64_t floatToDouble(int32_t a) { return vm::doubleToBits(static_cast(vm::bitsToFloat(a))); } int64_t floatToInt(int32_t a) { float f = vm::bitsToFloat(a); switch (fpclassify(f)) { case FP_NAN: return 0; case FP_INFINITE: return signbit(f) ? INT32_MIN : INT32_MAX; default: return f >= INT32_MAX ? INT32_MAX : (f <= INT32_MIN ? INT32_MIN : static_cast(f)); } } int64_t floatToLong(int32_t a) { float f = vm::bitsToFloat(a); switch (fpclassify(f)) { case FP_NAN: return 0; case FP_INFINITE: return signbit(f) ? INT64_MIN : INT64_MAX; default: return static_cast(f); } } uint64_t intToDouble(int32_t a) { return vm::doubleToBits(static_cast(a)); } uint64_t intToFloat(int32_t a) { return vm::floatToBits(static_cast(a)); } uint64_t longToDouble(int64_t a) { return vm::doubleToBits(static_cast(a)); } uint64_t longToFloat(int64_t a) { return vm::floatToBits(static_cast(a)); } } // namespace runtime } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/000077500000000000000000000000001231440243200206415ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/codegen/target/arm/000077500000000000000000000000001231440243200214205ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/codegen/target/arm/assembler.cpp000066400000000000000000000640421231440243200241070ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include #include "context.h" #include "block.h" #include "fixup.h" #include "multimethod.h" #include "encode.h" #include "operations.h" #include "registers.h" #include "../multimethod.h" #include "avian/alloc-vector.h" #include using namespace vm; using namespace avian::codegen; using namespace avian::util; namespace avian { namespace codegen { namespace arm { namespace isa { // HARDWARE FLAGS bool vfpSupported() { // TODO: Use at runtime detection #if defined(__ARM_PCS_VFP) // armhf return true; #else // armel // TODO: allow VFP use for -mfloat-abi=softfp armel builds. // GCC -mfloat-abi=softfp flag allows use of VFP while remaining compatible // with soft-float code. return false; #endif } } // namespace isa inline unsigned lo8(int64_t i) { return (unsigned)(i&MASK_LO8); } const RegisterFile MyRegisterFileWithoutFloats(GPR_MASK, 0); const RegisterFile MyRegisterFileWithFloats(GPR_MASK, FPR_MASK); const unsigned FrameHeaderSize = 1; const unsigned StackAlignmentInBytes = 8; const unsigned StackAlignmentInWords = StackAlignmentInBytes / TargetBytesPerWord; void resolve(MyBlock*); unsigned padding(MyBlock*, unsigned); class ConstantPoolEntry; // BEGIN OPERATION COMPILERS using namespace isa; // END OPERATION COMPILERS unsigned argumentFootprint(unsigned footprint) { return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); } void nextFrame(ArchitectureContext* con, uint32_t* start, unsigned size UNUSED, unsigned footprint, void* link, bool, int targetParameterFootprint UNUSED, void** ip, void** stack) { assert(con, *ip >= start); assert(con, *ip <= start + (size / TargetBytesPerWord)); uint32_t* instruction = static_cast(*ip); if ((*start >> 20) == 0xe59) { // skip stack overflow check start += 3; } if (instruction <= start) { *ip = link; return; } unsigned offset = footprint + FrameHeaderSize; if (instruction <= start + 2) { *ip = link; *stack = static_cast(*stack) + offset; return; } if (*instruction == 0xe12fff1e) { // return *ip = link; return; } if (TailCalls and targetParameterFootprint >= 0) { if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { offset += argumentFootprint(targetParameterFootprint) - StackAlignmentInWords; } // check for post-non-tail-call stack adjustment of the form "sub // sp, sp, #offset": if ((*instruction >> 12) == 0xe24dd) { unsigned value = *instruction & 0xff; unsigned rotation = (*instruction >> 8) & 0xf; switch (rotation) { case 0: offset -= value / TargetBytesPerWord; break; case 15: offset -= value; break; default: abort(con); } } // todo: check for and handle tail calls } *ip = static_cast(*stack)[offset - 1]; *stack = static_cast(*stack) + offset; } class MyArchitecture: public Architecture { public: MyArchitecture(System* system): con(system), referenceCount(0) { populateTables(&con); } virtual unsigned floatRegisterSize() { return vfpSupported() ? 8 : 0; } virtual const RegisterFile* registerFile() { return vfpSupported() ? &MyRegisterFileWithFloats : &MyRegisterFileWithoutFloats; } virtual int scratch() { return 5; } virtual int stack() { return StackRegister; } virtual int thread() { return ThreadRegister; } virtual int returnLow() { return 0; } virtual int returnHigh() { return 1; } virtual int virtualCallTarget() { return 4; } virtual int virtualCallIndex() { return 3; } virtual bool bigEndian() { return false; } virtual uintptr_t maximumImmediateJump() { return 0x1FFFFFF; } virtual bool reserved(int register_) { switch (register_) { case LinkRegister: case StackRegister: case ThreadRegister: case ProgramCounter: return true; default: return false; } } virtual unsigned frameFootprint(unsigned footprint) { return max(footprint, StackAlignmentInWords); } virtual unsigned argumentFootprint(unsigned footprint) { return arm::argumentFootprint(footprint); } virtual bool argumentAlignment() { #ifdef __APPLE__ return false; #else return true; #endif } virtual bool argumentRegisterAlignment() { #ifdef __APPLE__ return false; #else return true; #endif } virtual unsigned argumentRegisterCount() { return 4; } virtual int argumentRegister(unsigned index) { assert(&con, index < argumentRegisterCount()); return index; } virtual bool hasLinkRegister() { return true; } virtual unsigned stackAlignmentInWords() { return StackAlignmentInWords; } virtual bool matchCall(void* returnAddress, void* target) { uint32_t* instruction = static_cast(returnAddress) - 1; return *instruction == static_cast (bl(static_cast(target) - reinterpret_cast(instruction))); } virtual void updateCall(lir::UnaryOperation op UNUSED, void* returnAddress, void* newTarget) { switch (op) { case lir::Call: case lir::Jump: case lir::AlignedCall: case lir::AlignedJump: { updateOffset(con.s, static_cast(returnAddress) - 4, reinterpret_cast(newTarget)); } break; case lir::LongCall: case lir::LongJump: case lir::AlignedLongCall: case lir::AlignedLongJump: { uint32_t* p = static_cast(returnAddress) - 2; *reinterpret_cast(p + (((*p & PoolOffsetMask) + 8) / 4)) = newTarget; } break; default: abort(&con); } } virtual unsigned constantCallSize() { return 4; } virtual void setConstant(void* dst, uint64_t constant) { *static_cast(dst) = constant; } virtual unsigned alignFrameSize(unsigned sizeInWords) { return pad(sizeInWords + FrameHeaderSize, StackAlignmentInWords) - FrameHeaderSize; } virtual void nextFrame(void* start, unsigned size, unsigned footprint, void* link, bool mostRecent, int targetParameterFootprint, void** ip, void** stack) { arm::nextFrame(&con, static_cast(start), size, footprint, link, mostRecent, targetParameterFootprint, ip, stack); } virtual void* frameIp(void* stack) { return stack ? static_cast(stack)[returnAddressOffset()] : 0; } virtual unsigned frameHeaderSize() { return FrameHeaderSize; } virtual unsigned frameReturnAddressSize() { return 0; } virtual unsigned frameFooterSize() { return 0; } virtual int returnAddressOffset() { return -1; } virtual int framePointerOffset() { return 0; } virtual bool alwaysCondensed(lir::BinaryOperation) { return false; } virtual bool alwaysCondensed(lir::TernaryOperation) { return false; } virtual void plan (lir::UnaryOperation, unsigned, OperandMask& aMask, bool* thunk) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::ConstantOperand); aMask.registerMask = ~static_cast(0); *thunk = false; } virtual void planSource (lir::BinaryOperation op, unsigned aSize, OperandMask& aMask, unsigned bSize, bool* thunk) { *thunk = false; aMask.typeMask = ~0; aMask.registerMask = GPR_MASK64; switch (op) { case lir::Negate: aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = GPR_MASK64; break; case lir::Absolute: *thunk = true; break; case lir::FloatAbsolute: case lir::FloatSquareRoot: case lir::FloatNegate: case lir::Float2Float: if (vfpSupported()) { aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = FPR_MASK64; } else { *thunk = true; } break; case lir::Float2Int: // todo: Java requires different semantics than SSE for // converting floats to integers, we we need to either use // thunks or produce inline machine code which handles edge // cases properly. if (false && vfpSupported() && bSize == 4) { aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = FPR_MASK64; } else { *thunk = true; } break; case lir::Int2Float: if (vfpSupported() && aSize == 4) { aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = GPR_MASK64; } else { *thunk = true; } break; default: break; } } virtual void planDestination (lir::BinaryOperation op, unsigned, const OperandMask& aMask, unsigned, OperandMask& bMask) { bMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); bMask.registerMask = GPR_MASK64; switch (op) { case lir::Negate: bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = GPR_MASK64; break; case lir::FloatAbsolute: case lir::FloatSquareRoot: case lir::FloatNegate: case lir::Float2Float: case lir::Int2Float: bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = FPR_MASK64; break; case lir::Float2Int: bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = GPR_MASK64; break; case lir::Move: if (!(aMask.typeMask & 1 << lir::RegisterOperand)) { bMask.typeMask = 1 << lir::RegisterOperand; } break; default: break; } } virtual void planMove (unsigned, OperandMask& srcMask, OperandMask& tmpMask, const OperandMask& dstMask) { srcMask.typeMask = ~0; srcMask.registerMask = ~static_cast(0); tmpMask.typeMask = 0; tmpMask.registerMask = 0; if (dstMask.typeMask & (1 << lir::MemoryOperand)) { // can't move directly from memory or constant to memory srcMask.typeMask = 1 << lir::RegisterOperand; tmpMask.typeMask = 1 << lir::RegisterOperand; tmpMask.registerMask = GPR_MASK64; } else if (vfpSupported() && dstMask.typeMask & 1 << lir::RegisterOperand && dstMask.registerMask & FPR_MASK) { srcMask.typeMask = tmpMask.typeMask = 1 << lir::RegisterOperand | 1 << lir::MemoryOperand; tmpMask.registerMask = ~static_cast(0); } } virtual void planSource (lir::TernaryOperation op, unsigned, OperandMask& aMask, unsigned bSize, OperandMask& bMask, unsigned, bool* thunk) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::ConstantOperand); aMask.registerMask = GPR_MASK64; bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = GPR_MASK64; *thunk = false; switch (op) { case lir::ShiftLeft: case lir::ShiftRight: case lir::UnsignedShiftRight: if (bSize == 8) aMask.typeMask = bMask.typeMask = (1 << lir::RegisterOperand); break; case lir::Add: case lir::Subtract: case lir::Or: case lir::Xor: case lir::Multiply: aMask.typeMask = bMask.typeMask = (1 << lir::RegisterOperand); break; case lir::Divide: case lir::Remainder: case lir::FloatRemainder: *thunk = true; break; case lir::FloatAdd: case lir::FloatSubtract: case lir::FloatMultiply: case lir::FloatDivide: if (vfpSupported()) { aMask.typeMask = bMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = bMask.registerMask = FPR_MASK64; } else { *thunk = true; } break; case lir::JumpIfFloatEqual: case lir::JumpIfFloatNotEqual: case lir::JumpIfFloatLess: case lir::JumpIfFloatGreater: case lir::JumpIfFloatLessOrEqual: case lir::JumpIfFloatGreaterOrEqual: case lir::JumpIfFloatLessOrUnordered: case lir::JumpIfFloatGreaterOrUnordered: case lir::JumpIfFloatLessOrEqualOrUnordered: case lir::JumpIfFloatGreaterOrEqualOrUnordered: if (vfpSupported()) { aMask.typeMask = bMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = bMask.registerMask = FPR_MASK64; } else { *thunk = true; } break; default: break; } } virtual void planDestination (lir::TernaryOperation op, unsigned, const OperandMask& aMask UNUSED, unsigned, const OperandMask& bMask, unsigned, OperandMask& cMask) { if (isBranch(op)) { cMask.typeMask = (1 << lir::ConstantOperand); cMask.registerMask = 0; } else { cMask.typeMask = (1 << lir::RegisterOperand); cMask.registerMask = bMask.registerMask; } } virtual Assembler* makeAssembler(Allocator* allocator, Zone* zone); virtual void acquire() { ++ referenceCount; } virtual void release() { if (-- referenceCount == 0) { con.s->free(this); } } ArchitectureContext con; unsigned referenceCount; }; class MyAssembler: public Assembler { public: MyAssembler(System* s, Allocator* a, Zone* zone, MyArchitecture* arch): con(s, a, zone), arch_(arch) { } virtual void setClient(Client* client) { assert(&con, con.client == 0); con.client = client; } virtual Architecture* arch() { return arch_; } virtual void checkStackOverflow(uintptr_t handler, unsigned stackLimitOffsetFromThread) { lir::Register stack(StackRegister); lir::Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread); lir::Constant handlerConstant(new(con.zone) ResolvedPromise(handler)); branchRM(&con, lir::JumpIfGreaterOrEqual, TargetBytesPerWord, &stack, &stackLimit, &handlerConstant); } virtual void saveFrame(unsigned stackOffset, unsigned ipOffset) { lir::Register link(LinkRegister); lir::Memory linkDst(ThreadRegister, ipOffset); moveRM(&con, TargetBytesPerWord, &link, TargetBytesPerWord, &linkDst); lir::Register stack(StackRegister); lir::Memory stackDst(ThreadRegister, stackOffset); moveRM(&con, TargetBytesPerWord, &stack, TargetBytesPerWord, &stackDst); } virtual void pushFrame(unsigned argumentCount, ...) { struct Argument { unsigned size; lir::OperandType type; lir::Operand* operand; }; RUNTIME_ARRAY(Argument, arguments, argumentCount); va_list a; va_start(a, argumentCount); unsigned footprint = 0; for (unsigned i = 0; i < argumentCount; ++i) { RUNTIME_ARRAY_BODY(arguments)[i].size = va_arg(a, unsigned); RUNTIME_ARRAY_BODY(arguments)[i].type = static_cast(va_arg(a, int)); RUNTIME_ARRAY_BODY(arguments)[i].operand = va_arg(a, lir::Operand*); footprint += ceilingDivide(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord); } va_end(a); allocateFrame(arch_->alignFrameSize(footprint)); unsigned offset = 0; for (unsigned i = 0; i < argumentCount; ++i) { if (i < arch_->argumentRegisterCount()) { lir::Register dst(arch_->argumentRegister(i)); apply(lir::Move, OperandInfo( RUNTIME_ARRAY_BODY(arguments)[i].size, RUNTIME_ARRAY_BODY(arguments)[i].type, RUNTIME_ARRAY_BODY(arguments)[i].operand), OperandInfo( pad(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord), lir::RegisterOperand, &dst)); offset += ceilingDivide(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord); } else { lir::Memory dst(StackRegister, offset * TargetBytesPerWord); apply(lir::Move, OperandInfo( RUNTIME_ARRAY_BODY(arguments)[i].size, RUNTIME_ARRAY_BODY(arguments)[i].type, RUNTIME_ARRAY_BODY(arguments)[i].operand), OperandInfo( pad(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord), lir::MemoryOperand, &dst)); offset += ceilingDivide(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord); } } } virtual void allocateFrame(unsigned footprint) { footprint += FrameHeaderSize; // larger frames may require multiple subtract/add instructions // to allocate/deallocate, and nextFrame will need to be taught // how to handle them: assert(&con, footprint < 256); lir::Register stack(StackRegister); ResolvedPromise footprintPromise(footprint * TargetBytesPerWord); lir::Constant footprintConstant(&footprintPromise); subC(&con, TargetBytesPerWord, &footprintConstant, &stack, &stack); lir::Register returnAddress(LinkRegister); lir::Memory returnAddressDst (StackRegister, (footprint - 1) * TargetBytesPerWord); moveRM(&con, TargetBytesPerWord, &returnAddress, TargetBytesPerWord, &returnAddressDst); } virtual void adjustFrame(unsigned difference) { lir::Register stack(StackRegister); ResolvedPromise differencePromise(difference * TargetBytesPerWord); lir::Constant differenceConstant(&differencePromise); subC(&con, TargetBytesPerWord, &differenceConstant, &stack, &stack); } virtual void popFrame(unsigned footprint) { footprint += FrameHeaderSize; lir::Register returnAddress(LinkRegister); lir::Memory returnAddressSrc (StackRegister, (footprint - 1) * TargetBytesPerWord); moveMR(&con, TargetBytesPerWord, &returnAddressSrc, TargetBytesPerWord, &returnAddress); lir::Register stack(StackRegister); ResolvedPromise footprintPromise(footprint * TargetBytesPerWord); lir::Constant footprintConstant(&footprintPromise); addC(&con, TargetBytesPerWord, &footprintConstant, &stack, &stack); } virtual void popFrameForTailCall(unsigned footprint, int offset, int returnAddressSurrogate, int framePointerSurrogate UNUSED) { assert(&con, framePointerSurrogate == lir::NoRegister); if (TailCalls) { if (offset) { footprint += FrameHeaderSize; lir::Register link(LinkRegister); lir::Memory returnAddressSrc (StackRegister, (footprint - 1) * TargetBytesPerWord); moveMR(&con, TargetBytesPerWord, &returnAddressSrc, TargetBytesPerWord, &link); lir::Register stack(StackRegister); ResolvedPromise footprintPromise ((footprint - offset) * TargetBytesPerWord); lir::Constant footprintConstant(&footprintPromise); addC(&con, TargetBytesPerWord, &footprintConstant, &stack, &stack); if (returnAddressSurrogate != lir::NoRegister) { assert(&con, offset > 0); lir::Register ras(returnAddressSurrogate); lir::Memory dst(StackRegister, (offset - 1) * TargetBytesPerWord); moveRM(&con, TargetBytesPerWord, &ras, TargetBytesPerWord, &dst); } } else { popFrame(footprint); } } else { abort(&con); } } virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, unsigned argumentFootprint) { popFrame(frameFootprint); assert(&con, argumentFootprint >= StackAlignmentInWords); assert(&con, (argumentFootprint % StackAlignmentInWords) == 0); unsigned offset; if (TailCalls and argumentFootprint > StackAlignmentInWords) { offset = argumentFootprint - StackAlignmentInWords; lir::Register stack(StackRegister); ResolvedPromise adjustmentPromise(offset * TargetBytesPerWord); lir::Constant adjustment(&adjustmentPromise); addC(&con, TargetBytesPerWord, &adjustment, &stack, &stack); } else { offset = 0; } return_(&con); } virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, unsigned stackOffsetFromThread) { popFrame(frameFootprint); lir::Register stack(StackRegister); lir::Memory newStackSrc(ThreadRegister, stackOffsetFromThread); moveMR(&con, TargetBytesPerWord, &newStackSrc, TargetBytesPerWord, &stack); return_(&con); } virtual void apply(lir::Operation op) { arch_->con.operations[op](&con); } virtual void apply(lir::UnaryOperation op, OperandInfo a) { arch_->con.unaryOperations[Multimethod::index(op, a.type)] (&con, a.size, a.operand); } virtual void apply(lir::BinaryOperation op, OperandInfo a, OperandInfo b) { arch_->con.binaryOperations[index(&(arch_->con), op, a.type, b.type)] (&con, a.size, a.operand, b.size, b.operand); } virtual void apply(lir::TernaryOperation op, OperandInfo a, OperandInfo b, OperandInfo c) { if (isBranch(op)) { assert(&con, a.size == b.size); assert(&con, c.size == TargetBytesPerWord); assert(&con, c.type == lir::ConstantOperand); arch_->con.branchOperations[branchIndex(&(arch_->con), a.type, b.type)] (&con, op, a.size, a.operand, b.operand, c.operand); } else { assert(&con, b.size == c.size); assert(&con, b.type == lir::RegisterOperand); assert(&con, c.type == lir::RegisterOperand); arch_->con.ternaryOperations[index(&(arch_->con), op, a.type)] (&con, b.size, a.operand, b.operand, c.operand); } } virtual void setDestination(uint8_t* dst) { con.result = dst; } virtual void write() { uint8_t* dst = con.result; unsigned dstOffset = 0; for (MyBlock* b = con.firstBlock; b; b = b->next) { if (DebugPool) { fprintf(stderr, "write block %p\n", b); } unsigned blockOffset = 0; for (PoolEvent* e = b->poolEventHead; e; e = e->next) { unsigned size = e->offset - blockOffset; memcpy(dst + dstOffset, con.code.data.begin() + b->offset + blockOffset, size); blockOffset = e->offset; dstOffset += size; unsigned poolSize = 0; for (PoolOffset* o = e->poolOffsetHead; o; o = o->next) { if (DebugPool) { fprintf(stderr, "visit pool offset %p %d in block %p\n", o, o->offset, b); } unsigned entry = dstOffset + poolSize; if (needJump(b)) { entry += TargetBytesPerWord; } o->entry->address = dst + entry; unsigned instruction = o->block->start + padding(o->block, o->offset) + o->offset; int32_t v = (entry - 8) - instruction; expect(&con, v == (v & PoolOffsetMask)); int32_t* p = reinterpret_cast(dst + instruction); *p = (v & PoolOffsetMask) | ((~PoolOffsetMask) & *p); poolSize += TargetBytesPerWord; } bool jump = needJump(b); if (jump) { write4 (dst + dstOffset, isa::b((poolSize + TargetBytesPerWord - 8) >> 2)); } dstOffset += poolSize + (jump ? TargetBytesPerWord : 0); } unsigned size = b->size - blockOffset; memcpy(dst + dstOffset, con.code.data.begin() + b->offset + blockOffset, size); dstOffset += size; } for (Task* t = con.tasks; t; t = t->next) { t->run(&con); } for (ConstantPoolEntry* e = con.constantPool; e; e = e->next) { if (e->constant->resolved()) { *static_cast(e->address) = e->constant->value(); } else { new (e->constant->listen(sizeof(ConstantPoolListener))) ConstantPoolListener(con.s, static_cast(e->address), e->callOffset ? dst + e->callOffset->value() + 8 : 0); } // fprintf(stderr, "constant %p at %p\n", reinterpret_cast(e->constant->value()), e->address); } } virtual Promise* offset(bool forTrace) { return arm::offsetPromise(&con, forTrace); } virtual Block* endBlock(bool startNew) { MyBlock* b = con.lastBlock; b->size = con.code.length() - b->offset; if (startNew) { con.lastBlock = new (con.zone) MyBlock(&con, con.code.length()); } else { con.lastBlock = 0; } return b; } virtual void endEvent() { MyBlock* b = con.lastBlock; unsigned thisEventOffset = con.code.length() - b->offset; if (b->poolOffsetHead) { int32_t v = (thisEventOffset + TargetBytesPerWord - 8) - b->poolOffsetHead->offset; if (v > 0 and v != (v & PoolOffsetMask)) { appendPoolEvent (&con, b, b->lastEventOffset, b->poolOffsetHead, b->lastPoolOffsetTail); if (DebugPool) { for (PoolOffset* o = b->poolOffsetHead; o != b->lastPoolOffsetTail->next; o = o->next) { fprintf(stderr, "in endEvent, include %p %d in pool event %p at offset %d " "in block %p\n", o, o->offset, b->poolEventTail, b->lastEventOffset, b); } } b->poolOffsetHead = b->lastPoolOffsetTail->next; b->lastPoolOffsetTail->next = 0; if (b->poolOffsetHead == 0) { b->poolOffsetTail = 0; } } } b->lastEventOffset = thisEventOffset; b->lastPoolOffsetTail = b->poolOffsetTail; } virtual unsigned length() { return con.code.length(); } virtual unsigned footerSize() { return 0; } virtual void dispose() { con.code.dispose(); } Context con; MyArchitecture* arch_; }; Assembler* MyArchitecture::makeAssembler(Allocator* allocator, Zone* zone) { return new(zone) MyAssembler(this->con.s, allocator, zone, this); } } // namespace arm Architecture* makeArchitectureArm(System* system, bool) { return new (allocate(system, sizeof(arm::MyArchitecture))) arm::MyArchitecture(system); } } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/arm/block.cpp000066400000000000000000000020001231440243200232060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "context.h" #include "block.h" namespace avian { namespace codegen { namespace arm { void resolve(MyBlock*); unsigned padding(MyBlock*, unsigned); MyBlock::MyBlock(Context* context, unsigned offset): context(context), next(0), poolOffsetHead(0), poolOffsetTail(0), lastPoolOffsetTail(0), poolEventHead(0), poolEventTail(0), lastEventOffset(0), offset(offset), start(~0), size(0) { } unsigned MyBlock::resolve(unsigned start, Assembler::Block* next) { this->start = start; this->next = static_cast(next); arm::resolve(this); return start + size + padding(this, size); } } // namespace arm } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/arm/block.h000066400000000000000000000021531231440243200226640ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_ARM_BLOCK_H #define AVIAN_CODEGEN_ASSEMBLER_ARM_BLOCK_H #include #include namespace avian { namespace codegen { namespace arm { class PoolEvent; class MyBlock: public Assembler::Block { public: MyBlock(Context* context, unsigned offset); virtual unsigned resolve(unsigned start, Assembler::Block* next); Context* context; MyBlock* next; PoolOffset* poolOffsetHead; PoolOffset* poolOffsetTail; PoolOffset* lastPoolOffsetTail; PoolEvent* poolEventHead; PoolEvent* poolEventTail; unsigned lastEventOffset; unsigned offset; unsigned start; unsigned size; }; } // namespace arm } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_ARM_BLOCK_H ReadyTalk-avian-1e1fff5/src/codegen/target/arm/context.cpp000066400000000000000000000015371231440243200236160ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "context.h" #include "block.h" namespace avian { namespace codegen { namespace arm { Context::Context(vm::System* s, util::Allocator* a, vm::Zone* zone) : s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), firstBlock(new (zone) MyBlock(this, 0)), lastBlock(firstBlock), poolOffsetHead(0), poolOffsetTail(0), constantPool(0), constantPoolCount(0) { } } // namespace arm } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/arm/context.h000066400000000000000000000047261231440243200232660ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_ARM_CONTEXT_H #define AVIAN_CODEGEN_ASSEMBLER_ARM_CONTEXT_H #include #include #include "avian/alloc-vector.h" namespace vm { class System; class Zone; } // namespace vm namespace avian { namespace util { class Aborter; class Allocator; } // namespace util namespace codegen { namespace arm { class Task; class MyBlock; class PoolOffset; class ConstantPoolEntry; class Context { public: Context(vm::System* s, util::Allocator* a, vm::Zone* zone); vm::System* s; vm::Zone* zone; Assembler::Client* client; vm::Vector code; Task* tasks; uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; PoolOffset* poolOffsetHead; PoolOffset* poolOffsetTail; ConstantPoolEntry* constantPool; unsigned constantPoolCount; }; typedef void (*OperationType)(Context*); typedef void (*UnaryOperationType)(Context*, unsigned, lir::Operand*); typedef void (*BinaryOperationType) (Context*, unsigned, lir::Operand*, unsigned, lir::Operand*); typedef void (*TernaryOperationType) (Context*, unsigned, lir::Operand*, lir::Operand*, lir::Operand*); typedef void (*BranchOperationType) (Context*, lir::TernaryOperation, unsigned, lir::Operand*, lir::Operand*, lir::Operand*); class ArchitectureContext { public: ArchitectureContext(vm::System* s): s(s) { } vm::System* s; OperationType operations[lir::OperationCount]; UnaryOperationType unaryOperations[lir::UnaryOperationCount * lir::OperandTypeCount]; BinaryOperationType binaryOperations [lir::BinaryOperationCount * lir::OperandTypeCount * lir::OperandTypeCount]; TernaryOperationType ternaryOperations [lir::NonBranchTernaryOperationCount * lir::OperandTypeCount]; BranchOperationType branchOperations [lir::BranchOperationCount * lir::OperandTypeCount * lir::OperandTypeCount]; }; inline avian::util::Aborter* getAborter(Context* c) { return c->s; } inline avian::util::Aborter* getAborter(ArchitectureContext* c) { return c->s; } } // namespace arm } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_ARM_CONTEXT_H ReadyTalk-avian-1e1fff5/src/codegen/target/arm/encode.h000066400000000000000000000325351231440243200230360ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_ARM_ENCODE_H #define AVIAN_CODEGEN_ASSEMBLER_ARM_ENCODE_H #include #include namespace avian { namespace codegen { namespace arm { namespace isa { // SYSTEM REGISTERS const int FPSID = 0x0; const int FPSCR = 0x1; const int FPEXC = 0x8; // INSTRUCTION OPTIONS enum CONDITION { EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV }; enum SHIFTOP { LSL, LSR, ASR, ROR }; // INSTRUCTION FORMATS inline int DATA(int cond, int opcode, int S, int Rn, int Rd, int shift, int Sh, int Rm) { return cond<<28 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | shift<<7 | Sh<<5 | Rm; } inline int DATAS(int cond, int opcode, int S, int Rn, int Rd, int Rs, int Sh, int Rm) { return cond<<28 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | Rs<<8 | Sh<<5 | 1<<4 | Rm; } inline int DATAI(int cond, int opcode, int S, int Rn, int Rd, int rot, int imm) { return cond<<28 | 1<<25 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | rot<<8 | (imm&0xff); } inline int BRANCH(int cond, int L, int offset) { return cond<<28 | 5<<25 | L<<24 | (offset&0xffffff); } inline int BRANCHX(int cond, int L, int Rm) { return cond<<28 | 0x4bffc<<6 | L<<5 | 1<<4 | Rm; } inline int MULTIPLY(int cond, int mul, int S, int Rd, int Rn, int Rs, int Rm) { return cond<<28 | mul<<21 | S<<20 | Rd<<16 | Rn<<12 | Rs<<8 | 9<<4 | Rm; } inline int XFER(int cond, int P, int U, int B, int W, int L, int Rn, int Rd, int shift, int Sh, int Rm) { return cond<<28 | 3<<25 | P<<24 | U<<23 | B<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | shift<<7 | Sh<<5 | Rm; } inline int XFERI(int cond, int P, int U, int B, int W, int L, int Rn, int Rd, int offset) { return cond<<28 | 2<<25 | P<<24 | U<<23 | B<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | (offset&0xfff); } inline int XFER2(int cond, int P, int U, int W, int L, int Rn, int Rd, int S, int H, int Rm) { return cond<<28 | P<<24 | U<<23 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | 1<<7 | S<<6 | H<<5 | 1<<4 | Rm; } inline int XFER2I(int cond, int P, int U, int W, int L, int Rn, int Rd, int offsetH, int S, int H, int offsetL) { return cond<<28 | P<<24 | U<<23 | 1<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offsetH<<8 | 1<<7 | S<<6 | H<<5 | 1<<4 | (offsetL&0xf); } inline int COOP(int cond, int opcode_1, int CRn, int CRd, int cp_num, int opcode_2, int CRm) { return cond<<28 | 0xe<<24 | opcode_1<<20 | CRn<<16 | CRd<<12 | cp_num<<8 | opcode_2<<5 | CRm; } inline int COXFER(int cond, int P, int U, int N, int W, int L, int Rn, int CRd, int cp_num, int offset) // offset is in words, not bytes { return cond<<28 | 0x6<<25 | P<<24 | U<<23 | N<<22 | W<<21 | L<<20 | Rn<<16 | CRd<<12 | cp_num<<8 | (offset&0xff)>>2; } inline int COREG(int cond, int opcode_1, int L, int CRn, int Rd, int cp_num, int opcode_2, int CRm) { return cond<<28 | 0xe<<24 | opcode_1<<21 | L<<20 | CRn<<16 | Rd<<12 | cp_num<<8 | opcode_2<<5 | 1<<4 | CRm; } inline int COREG2(int cond, int L, int Rn, int Rd, int cp_num, int opcode, int CRm) { return cond<<28 | 0xc4<<20 | L<<20 | Rn<<16 | Rd<<12 | cp_num<<8 | opcode<<4 | CRm;} // FIELD CALCULATORS inline int calcU(int imm) { return imm >= 0 ? 1 : 0; } // INSTRUCTIONS // The "cond" and "S" fields are set using the SETCOND() and SETS() functions inline int b(int offset) { return BRANCH(AL, 0, offset); } inline int bl(int offset) { return BRANCH(AL, 1, offset); } inline int bx(int Rm) { return BRANCHX(AL, 0, Rm); } inline int blx(int Rm) { return BRANCHX(AL, 1, Rm); } inline int and_(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x0, 0, Rn, Rd, shift, Sh, Rm); } inline int eor(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x1, 0, Rn, Rd, shift, Sh, Rm); } inline int rsb(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x3, 0, Rn, Rd, shift, Sh, Rm); } inline int add(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x4, 0, Rn, Rd, shift, Sh, Rm); } inline int adc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x5, 0, Rn, Rd, shift, Sh, Rm); } inline int rsc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x7, 0, Rn, Rd, shift, Sh, Rm); } inline int cmp(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xa, 1, Rn, 0, shift, Sh, Rm); } inline int orr(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xc, 0, Rn, Rd, shift, Sh, Rm); } inline int mov(int Rd, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xd, 0, 0, Rd, shift, Sh, Rm); } inline int mvn(int Rd, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xf, 0, 0, Rd, shift, Sh, Rm); } inline int andi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x0, 0, Rn, Rd, rot, imm); } inline int subi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x2, 0, Rn, Rd, rot, imm); } inline int rsbi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x3, 0, Rn, Rd, rot, imm); } inline int addi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x4, 0, Rn, Rd, rot, imm); } inline int adci(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x5, 0, Rn, Rd, rot, imm); } inline int bici(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xe, 0, Rn, Rd, rot, imm); } inline int cmpi(int Rn, int imm, int rot=0) { return DATAI(AL, 0xa, 1, Rn, 0, rot, imm); } inline int movi(int Rd, int imm, int rot=0) { return DATAI(AL, 0xd, 0, 0, Rd, rot, imm); } inline int orrsh(int Rd, int Rn, int Rm, int Rs, int Sh) { return DATAS(AL, 0xc, 0, Rn, Rd, Rs, Sh, Rm); } inline int movsh(int Rd, int Rm, int Rs, int Sh) { return DATAS(AL, 0xd, 0, 0, Rd, Rs, Sh, Rm); } inline int mul(int Rd, int Rm, int Rs) { return MULTIPLY(AL, 0, 0, Rd, 0, Rs, Rm); } inline int mla(int Rd, int Rm, int Rs, int Rn) { return MULTIPLY(AL, 1, 0, Rd, Rn, Rs, Rm); } inline int umull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 4, 0, RdHi, RdLo, Rs, Rm); } inline int ldr(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 1, Rn, Rd, 0, 0, Rm); } inline int ldri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, calcU(imm), 0, W, 1, Rn, Rd, abs(imm)); } inline int ldrb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 1, Rn, Rd, 0, 0, Rm); } inline int ldrbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, calcU(imm), 1, 0, 1, Rn, Rd, abs(imm)); } inline int str(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 0, Rn, Rd, 0, 0, Rm); } inline int stri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, calcU(imm), 0, W, 0, Rn, Rd, abs(imm)); } inline int strb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 0, Rn, Rd, 0, 0, Rm); } inline int strbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, calcU(imm), 1, 0, 0, Rn, Rd, abs(imm)); } inline int ldrh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 0, 1, Rm); } inline int ldrhi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 0, 1, abs(imm)&0xf); } inline int strh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 0, Rn, Rd, 0, 1, Rm); } inline int strhi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 0, Rn, Rd, abs(imm)>>4 & 0xf, 0, 1, abs(imm)&0xf); } inline int ldrsh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 1, Rm); } inline int ldrshi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 1, abs(imm)&0xf); } inline int ldrsb(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 0, Rm); } inline int ldrsbi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 0, abs(imm)&0xf); } // breakpoint instruction, this really has its own instruction format inline int bkpt(int16_t immed) { return 0xe1200070 | (((unsigned)immed & 0xffff) >> 4 << 8) | (immed & 0xf); } // COPROCESSOR INSTRUCTIONS inline int mcr(int coproc, int opcode_1, int Rd, int CRn, int CRm, int opcode_2=0) { return COREG(AL, opcode_1, 0, CRn, Rd, coproc, opcode_2, CRm); } inline int mcrr(int coproc, int opcode, int Rd, int Rn, int CRm) { return COREG2(AL, 0, Rn, Rd, coproc, opcode, CRm); } inline int mrc(int coproc, int opcode_1, int Rd, int CRn, int CRm, int opcode_2=0) { return COREG(AL, opcode_1, 1, CRn, Rd, coproc, opcode_2, CRm); } inline int mrrc(int coproc, int opcode, int Rd, int Rn, int CRm) { return COREG2(AL, 1, Rn, Rd, coproc, opcode, CRm); } // VFP FLOATING-POINT INSTRUCTIONS inline int fmuls(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|2, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); } inline int fadds(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|3, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); } inline int fsubs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|3, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1)|2, Sm>>1); } inline int fdivs(int Sd, int Sn, int Sm) { return COOP(AL, (Sd&1)<<2|8, Sn>>1, Sd>>1, 10, (Sn&1)<<2|(Sm&1), Sm>>1); } inline int fmuld(int Dd, int Dn, int Dm) { return COOP(AL, 2, Dn, Dd, 11, 0, Dm); } inline int faddd(int Dd, int Dn, int Dm) { return COOP(AL, 3, Dn, Dd, 11, 0, Dm); } inline int fsubd(int Dd, int Dn, int Dm) { return COOP(AL, 3, Dn, Dd, 11, 2, Dm); } inline int fdivd(int Dd, int Dn, int Dm) { return COOP(AL, 8, Dn, Dd, 11, 0, Dm); } inline int fcpys(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0, Sd>>1, 10, 2|(Sm&1), Sm>>1); } inline int fabss(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0, Sd>>1, 10, 6|(Sm&1), Sm>>1); } inline int fnegs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 1, Sd>>1, 10, 2|(Sm&1), Sm>>1); } inline int fsqrts(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 1, Sd>>1, 10, 6|(Sm&1), Sm>>1); } inline int fcmps(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 4, Sd>>1, 10, 2|(Sm&1), Sm>>1); } inline int fcvtds(int Dd, int Sm) { return COOP(AL, 0xb, 7, Dd, 10, 6|(Sm&1), Sm>>1); } inline int fsitos(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 8, Sd>>1, 10, 6|(Sm&1), Sm>>1); } inline int ftosizs(int Sd, int Sm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 10, 6|(Sm&1), Sm>>1); } inline int fcpyd(int Dd, int Dm) { return COOP(AL, 0xb, 0, Dd, 11, 2, Dm); } inline int fabsd(int Dd, int Dm) { return COOP(AL, 0xb, 0, Dd, 11, 6, Dm); } inline int fnegd(int Dd, int Dm) { return COOP(AL, 0xb, 1, Dd, 11, 2, Dm); } inline int fsqrtd(int Dd, int Dm) { return COOP(AL, 0xb, 1, Dd, 11, 6, Dm); } // double-precision comparison instructions inline int fcmpd(int Dd, int Dm) { return COOP(AL, 0xb, 4, Dd, 11, 2, Dm); } // double-precision conversion instructions inline int fcvtsd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 7, Sd>>1, 11, 6, Dm); } inline int fsitod(int Dd, int Sm) { return COOP(AL, 0xb, 8, Dd, 11, 6|(Sm&1), Sm>>1); } inline int ftosizd(int Sd, int Dm) { return COOP(AL, 0xb|(Sd&1)<<2, 0xd, Sd>>1, 11, 6, Dm); } // single load/store instructions for both precision types inline int flds(int Sd, int Rn, int offset=0) { return COXFER(AL, 1, 1, Sd&1, 0, 1, Rn, Sd>>1, 10, offset); }; inline int fldd(int Dd, int Rn, int offset=0) { return COXFER(AL, 1, 1, 0, 0, 1, Rn, Dd, 11, offset); }; inline int fsts(int Sd, int Rn, int offset=0) { return COXFER(AL, 1, 1, Sd&1, 0, 0, Rn, Sd>>1, 10, offset); }; inline int fstd(int Dd, int Rn, int offset=0) { return COXFER(AL, 1, 1, 0, 0, 0, Rn, Dd, 11, offset); }; // move between GPRs and FPRs inline int fmsr(int Sn, int Rd) { return mcr(10, 0, Rd, Sn>>1, 0, (Sn&1)<<2); } inline int fmrs(int Rd, int Sn) { return mrc(10, 0, Rd, Sn>>1, 0, (Sn&1)<<2); } // move to/from VFP system registers inline int fmrx(int Rd, int reg) { return mrc(10, 7, Rd, reg, 0); } // these move around pairs of single-precision registers inline int fmdrr(int Dm, int Rd, int Rn) { return mcrr(11, 1, Rd, Rn, Dm); } inline int fmrrd(int Rd, int Rn, int Dm) { return mrrc(11, 1, Rd, Rn, Dm); } // FLAG SETTERS inline int SETCOND(int ins, int cond) { return ((ins&0x0fffffff) | (cond<<28)); } inline int SETS(int ins) { return ins | 1<<20; } // PSEUDO-INSTRUCTIONS inline int lsl(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, LSL); } inline int lsli(int Rd, int Rm, int imm) { return mov(Rd, Rm, LSL, imm); } inline int lsr(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, LSR); } inline int lsri(int Rd, int Rm, int imm) { return mov(Rd, Rm, LSR, imm); } inline int asr(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ASR); } inline int asri(int Rd, int Rm, int imm) { return mov(Rd, Rm, ASR, imm); } inline int beq(int offset) { return SETCOND(b(offset), EQ); } inline int bne(int offset) { return SETCOND(b(offset), NE); } inline int bls(int offset) { return SETCOND(b(offset), LS); } inline int bhi(int offset) { return SETCOND(b(offset), HI); } inline int blt(int offset) { return SETCOND(b(offset), LT); } inline int bgt(int offset) { return SETCOND(b(offset), GT); } inline int ble(int offset) { return SETCOND(b(offset), LE); } inline int bge(int offset) { return SETCOND(b(offset), GE); } inline int blo(int offset) { return SETCOND(b(offset), CC); } inline int bhs(int offset) { return SETCOND(b(offset), CS); } inline int bpl(int offset) { return SETCOND(b(offset), PL); } inline int fmstat() { return fmrx(15, FPSCR); } // todo: make this pretty: inline int dmb() { return 0xf57ff05f; } } // namespace isa inline void emit(Context* con, int code) { con->code.append4(code); } } // namespace arm } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_ARM_ENCODE_H ReadyTalk-avian-1e1fff5/src/codegen/target/arm/fixup.cpp000066400000000000000000000115311231440243200232600ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "context.h" #include "fixup.h" #include "block.h" namespace avian { namespace codegen { namespace arm { using namespace util; unsigned padding(MyBlock*, unsigned); OffsetPromise::OffsetPromise(Context* con, MyBlock* block, unsigned offset, bool forTrace): con(con), block(block), offset(offset), forTrace(forTrace) { } bool OffsetPromise::resolved() { return block->start != static_cast(~0); } int64_t OffsetPromise::value() { assert(con, resolved()); unsigned o = offset - block->offset; return block->start + padding (block, forTrace ? o - vm::TargetBytesPerWord : o) + o; } Promise* offsetPromise(Context* con, bool forTrace) { return new(con->zone) OffsetPromise(con, con->lastBlock, con->code.length(), forTrace); } OffsetListener::OffsetListener(vm::System* s, uint8_t* instruction): s(s), instruction(instruction) { } bool OffsetListener::resolve(int64_t value, void** location) { void* p = updateOffset(s, instruction, value); if (location) *location = p; return false; } OffsetTask::OffsetTask(Task* next, Promise* promise, Promise* instructionOffset): Task(next), promise(promise), instructionOffset(instructionOffset) { } void OffsetTask::run(Context* con) { if (promise->resolved()) { updateOffset (con->s, con->result + instructionOffset->value(), promise->value()); } else { new (promise->listen(sizeof(OffsetListener))) OffsetListener(con->s, con->result + instructionOffset->value()); } } void appendOffsetTask(Context* con, Promise* promise, Promise* instructionOffset) { con->tasks = new(con->zone) OffsetTask(con->tasks, promise, instructionOffset); } bool bounded(int right, int left, int32_t v) { return ((v << left) >> left) == v and ((v >> right) << right) == v; } void* updateOffset(vm::System* s, uint8_t* instruction, int64_t value) { // ARM's PC is two words ahead, and branches drop the bottom 2 bits. int32_t v = (reinterpret_cast(value) - (instruction + 8)) >> 2; int32_t mask; expect(s, bounded(0, 8, v)); mask = 0xFFFFFF; int32_t* p = reinterpret_cast(instruction); *p = (v & mask) | ((~mask) & *p); return instruction + 4; } ConstantPoolEntry::ConstantPoolEntry(Context* con, Promise* constant, ConstantPoolEntry* next, Promise* callOffset): con(con), constant(constant), next(next), callOffset(callOffset), address(0) { } int64_t ConstantPoolEntry::value() { assert(con, resolved()); return reinterpret_cast(address); } bool ConstantPoolEntry::resolved() { return address != 0; } ConstantPoolListener::ConstantPoolListener(vm::System* s, vm::target_uintptr_t* address, uint8_t* returnAddress): s(s), address(address), returnAddress(returnAddress) { } bool ConstantPoolListener::resolve(int64_t value, void** location) { *address = value; if (location) { *location = returnAddress ? static_cast(returnAddress) : address; } return true; } PoolOffset::PoolOffset(MyBlock* block, ConstantPoolEntry* entry, unsigned offset): block(block), entry(entry), next(0), offset(offset) { } PoolEvent::PoolEvent(PoolOffset* poolOffsetHead, PoolOffset* poolOffsetTail, unsigned offset): poolOffsetHead(poolOffsetHead), poolOffsetTail(poolOffsetTail), next(0), offset(offset) { } void appendConstantPoolEntry(Context* con, Promise* constant, Promise* callOffset) { if (constant->resolved()) { // make a copy, since the original might be allocated on the // stack, and we need our copy to live until assembly is complete constant = new(con->zone) ResolvedPromise(constant->value()); } con->constantPool = new(con->zone) ConstantPoolEntry(con, constant, con->constantPool, callOffset); ++ con->constantPoolCount; PoolOffset* o = new(con->zone) PoolOffset(con->lastBlock, con->constantPool, con->code.length() - con->lastBlock->offset); if (DebugPool) { fprintf(stderr, "add pool offset %p %d to block %p\n", o, o->offset, con->lastBlock); } if (con->lastBlock->poolOffsetTail) { con->lastBlock->poolOffsetTail->next = o; } else { con->lastBlock->poolOffsetHead = o; } con->lastBlock->poolOffsetTail = o; } void appendPoolEvent(Context* con, MyBlock* b, unsigned offset, PoolOffset* head, PoolOffset* tail) { PoolEvent* e = new(con->zone) PoolEvent(head, tail, offset); if (b->poolEventTail) { b->poolEventTail->next = e; } else { b->poolEventHead = e; } b->poolEventTail = e; } } // namespace arm } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/arm/fixup.h000066400000000000000000000061301231440243200227240ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_ARM_PROMISE_H #define AVIAN_CODEGEN_ASSEMBLER_ARM_PROMISE_H #include "avian/target.h" #include #include #include "avian/alloc-vector.h" namespace vm { class System; } namespace avian { namespace codegen { namespace arm { const bool DebugPool = false; const int32_t PoolOffsetMask = 0xFFF; class Task { public: Task(Task* next): next(next) { } virtual void run(Context* con) = 0; Task* next; }; class OffsetPromise: public Promise { public: OffsetPromise(Context* con, MyBlock* block, unsigned offset, bool forTrace); virtual bool resolved(); virtual int64_t value(); Context* con; MyBlock* block; unsigned offset; bool forTrace; }; Promise* offsetPromise(Context* con, bool forTrace = false); class OffsetListener: public Promise::Listener { public: OffsetListener(vm::System* s, uint8_t* instruction); virtual bool resolve(int64_t value, void** location); vm::System* s; uint8_t* instruction; }; class OffsetTask: public Task { public: OffsetTask(Task* next, Promise* promise, Promise* instructionOffset); virtual void run(Context* con); Promise* promise; Promise* instructionOffset; }; void appendOffsetTask(Context* con, Promise* promise, Promise* instructionOffset); void* updateOffset(vm::System* s, uint8_t* instruction, int64_t value); class ConstantPoolEntry: public Promise { public: ConstantPoolEntry(Context* con, Promise* constant, ConstantPoolEntry* next, Promise* callOffset); virtual int64_t value(); virtual bool resolved(); Context* con; Promise* constant; ConstantPoolEntry* next; Promise* callOffset; void* address; unsigned constantPoolCount; }; class ConstantPoolListener: public Promise::Listener { public: ConstantPoolListener(vm::System* s, vm::target_uintptr_t* address, uint8_t* returnAddress); virtual bool resolve(int64_t value, void** location); vm::System* s; vm::target_uintptr_t* address; uint8_t* returnAddress; }; class PoolOffset { public: PoolOffset(MyBlock* block, ConstantPoolEntry* entry, unsigned offset); MyBlock* block; ConstantPoolEntry* entry; PoolOffset* next; unsigned offset; }; class PoolEvent { public: PoolEvent(PoolOffset* poolOffsetHead, PoolOffset* poolOffsetTail, unsigned offset); PoolOffset* poolOffsetHead; PoolOffset* poolOffsetTail; PoolEvent* next; unsigned offset; }; void appendConstantPoolEntry(Context* con, Promise* constant, Promise* callOffset); void appendPoolEvent(Context* con, MyBlock* b, unsigned offset, PoolOffset* head, PoolOffset* tail); } // namespace arm } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_ARM_PROMISE_H ReadyTalk-avian-1e1fff5/src/codegen/target/arm/multimethod.cpp000066400000000000000000000113211231440243200244550ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "context.h" #include "operations.h" #include "multimethod.h" #include "../multimethod.h" namespace avian { namespace codegen { namespace arm { using namespace util; unsigned index(ArchitectureContext*, lir::BinaryOperation operation, lir::OperandType operand1, lir::OperandType operand2) { return operation + (lir::BinaryOperationCount * operand1) + (lir::BinaryOperationCount * lir::OperandTypeCount * operand2); } unsigned index(ArchitectureContext* con UNUSED, lir::TernaryOperation operation, lir::OperandType operand1) { assert(con, not isBranch(operation)); return operation + (lir::NonBranchTernaryOperationCount * operand1); } unsigned branchIndex(ArchitectureContext* con UNUSED, lir::OperandType operand1, lir::OperandType operand2) { return operand1 + (lir::OperandTypeCount * operand2); } void populateTables(ArchitectureContext* con) { const lir::OperandType C = lir::ConstantOperand; const lir::OperandType A = lir::AddressOperand; const lir::OperandType R = lir::RegisterOperand; const lir::OperandType M = lir::MemoryOperand; OperationType* zo = con->operations; UnaryOperationType* uo = con->unaryOperations; BinaryOperationType* bo = con->binaryOperations; TernaryOperationType* to = con->ternaryOperations; BranchOperationType* bro = con->branchOperations; zo[lir::Return] = return_; zo[lir::LoadBarrier] = loadBarrier; zo[lir::StoreStoreBarrier] = storeStoreBarrier; zo[lir::StoreLoadBarrier] = storeLoadBarrier; zo[lir::Trap] = trap; uo[Multimethod::index(lir::LongCall, C)] = CAST1(longCallC); uo[Multimethod::index(lir::AlignedLongCall, C)] = CAST1(longCallC); uo[Multimethod::index(lir::LongJump, C)] = CAST1(longJumpC); uo[Multimethod::index(lir::AlignedLongJump, C)] = CAST1(longJumpC); uo[Multimethod::index(lir::Jump, R)] = CAST1(jumpR); uo[Multimethod::index(lir::Jump, C)] = CAST1(jumpC); uo[Multimethod::index(lir::AlignedJump, R)] = CAST1(jumpR); uo[Multimethod::index(lir::AlignedJump, C)] = CAST1(jumpC); uo[Multimethod::index(lir::Call, C)] = CAST1(callC); uo[Multimethod::index(lir::Call, R)] = CAST1(callR); uo[Multimethod::index(lir::AlignedCall, C)] = CAST1(callC); uo[Multimethod::index(lir::AlignedCall, R)] = CAST1(callR); bo[index(con, lir::Move, R, R)] = CAST2(moveRR); bo[index(con, lir::Move, C, R)] = CAST2(moveCR); bo[index(con, lir::Move, C, M)] = CAST2(moveCM); bo[index(con, lir::Move, M, R)] = CAST2(moveMR); bo[index(con, lir::Move, R, M)] = CAST2(moveRM); bo[index(con, lir::Move, A, R)] = CAST2(moveAR); bo[index(con, lir::MoveZ, R, R)] = CAST2(moveZRR); bo[index(con, lir::MoveZ, M, R)] = CAST2(moveZMR); bo[index(con, lir::MoveZ, C, R)] = CAST2(moveCR); bo[index(con, lir::Negate, R, R)] = CAST2(negateRR); bo[index(con, lir::FloatAbsolute, R, R)] = CAST2(floatAbsoluteRR); bo[index(con, lir::FloatNegate, R, R)] = CAST2(floatNegateRR); bo[index(con, lir::Float2Float, R, R)] = CAST2(float2FloatRR); bo[index(con, lir::Float2Int, R, R)] = CAST2(float2IntRR); bo[index(con, lir::Int2Float, R, R)] = CAST2(int2FloatRR); bo[index(con, lir::FloatSquareRoot, R, R)] = CAST2(floatSqrtRR); to[index(con, lir::Add, R)] = CAST3(addR); to[index(con, lir::Subtract, R)] = CAST3(subR); to[index(con, lir::Multiply, R)] = CAST3(multiplyR); to[index(con, lir::FloatAdd, R)] = CAST3(floatAddR); to[index(con, lir::FloatSubtract, R)] = CAST3(floatSubtractR); to[index(con, lir::FloatMultiply, R)] = CAST3(floatMultiplyR); to[index(con, lir::FloatDivide, R)] = CAST3(floatDivideR); to[index(con, lir::ShiftLeft, R)] = CAST3(shiftLeftR); to[index(con, lir::ShiftLeft, C)] = CAST3(shiftLeftC); to[index(con, lir::ShiftRight, R)] = CAST3(shiftRightR); to[index(con, lir::ShiftRight, C)] = CAST3(shiftRightC); to[index(con, lir::UnsignedShiftRight, R)] = CAST3(unsignedShiftRightR); to[index(con, lir::UnsignedShiftRight, C)] = CAST3(unsignedShiftRightC); to[index(con, lir::And, R)] = CAST3(andR); to[index(con, lir::And, C)] = CAST3(andC); to[index(con, lir::Or, R)] = CAST3(orR); to[index(con, lir::Xor, R)] = CAST3(xorR); bro[branchIndex(con, R, R)] = CAST_BRANCH(branchRR); bro[branchIndex(con, C, R)] = CAST_BRANCH(branchCR); bro[branchIndex(con, C, M)] = CAST_BRANCH(branchCM); bro[branchIndex(con, R, M)] = CAST_BRANCH(branchRM); } } // namespace arm } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/arm/multimethod.h000066400000000000000000000025261231440243200241310ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_ARM_MULTIMETHOD_H #define AVIAN_CODEGEN_ASSEMBLER_ARM_MULTIMETHOD_H #include #include #define CAST1(x) reinterpret_cast(x) #define CAST2(x) reinterpret_cast(x) #define CAST3(x) reinterpret_cast(x) #define CAST_BRANCH(x) reinterpret_cast(x) namespace avian { namespace codegen { namespace arm { unsigned index(ArchitectureContext*, lir::BinaryOperation operation, lir::OperandType operand1, lir::OperandType operand2); unsigned index(ArchitectureContext* con UNUSED, lir::TernaryOperation operation, lir::OperandType operand1); unsigned branchIndex(ArchitectureContext* con UNUSED, lir::OperandType operand1, lir::OperandType operand2); void populateTables(ArchitectureContext* con); } // namespace arm } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_ARM_MULTIMETHOD_H ReadyTalk-avian-1e1fff5/src/codegen/target/arm/operations.cpp000066400000000000000000001064731231440243200243220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "context.h" #include "operations.h" #include "encode.h" #include "block.h" #include "fixup.h" #include "multimethod.h" namespace avian { namespace codegen { namespace arm { using namespace isa; using namespace avian::util; inline bool isOfWidth(int64_t i, int size) { return static_cast(i) >> size == 0; } inline unsigned lo8(int64_t i) { return (unsigned)(i&MASK_LO8); } void andC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst); void shiftLeftR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if (size == 8) { int tmp1 = newTemp(con), tmp2 = newTemp(con), tmp3 = newTemp(con); ResolvedPromise maskPromise(0x3F); lir::Constant mask(&maskPromise); lir::Register dst(tmp3); andC(con, 4, &mask, a, &dst); emit(con, lsl(tmp1, b->high, tmp3)); emit(con, rsbi(tmp2, tmp3, 32)); emit(con, orrsh(tmp1, tmp1, b->low, tmp2, LSR)); emit(con, SETS(subi(t->high, tmp3, 32))); emit(con, SETCOND(mov(t->high, tmp1), MI)); emit(con, SETCOND(lsl(t->high, b->low, t->high), PL)); emit(con, lsl(t->low, b->low, tmp3)); freeTemp(con, tmp1); freeTemp(con, tmp2); freeTemp(con, tmp3); } else { int tmp = newTemp(con); ResolvedPromise maskPromise(0x1F); lir::Constant mask(&maskPromise); lir::Register dst(tmp); andC(con, size, &mask, a, &dst); emit(con, lsl(t->low, b->low, tmp)); freeTemp(con, tmp); } } void moveRR(Context* con, unsigned srcSize, lir::Register* src, unsigned dstSize, lir::Register* dst); void shiftLeftC(Context* con, unsigned size UNUSED, lir::Constant* a, lir::Register* b, lir::Register* t) { assert(con, size == vm::TargetBytesPerWord); if (getValue(a) & 0x1F) { emit(con, lsli(t->low, b->low, getValue(a) & 0x1F)); } else { moveRR(con, size, b, size, t); } } void shiftRightR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if (size == 8) { int tmp1 = newTemp(con), tmp2 = newTemp(con), tmp3 = newTemp(con); ResolvedPromise maskPromise(0x3F); lir::Constant mask(&maskPromise); lir::Register dst(tmp3); andC(con, 4, &mask, a, &dst); emit(con, lsr(tmp1, b->low, tmp3)); emit(con, rsbi(tmp2, tmp3, 32)); emit(con, orrsh(tmp1, tmp1, b->high, tmp2, LSL)); emit(con, SETS(subi(t->low, tmp3, 32))); emit(con, SETCOND(mov(t->low, tmp1), MI)); emit(con, SETCOND(asr(t->low, b->high, t->low), PL)); emit(con, asr(t->high, b->high, tmp3)); freeTemp(con, tmp1); freeTemp(con, tmp2); freeTemp(con, tmp3); } else { int tmp = newTemp(con); ResolvedPromise maskPromise(0x1F); lir::Constant mask(&maskPromise); lir::Register dst(tmp); andC(con, size, &mask, a, &dst); emit(con, asr(t->low, b->low, tmp)); freeTemp(con, tmp); } } void shiftRightC(Context* con, unsigned size UNUSED, lir::Constant* a, lir::Register* b, lir::Register* t) { assert(con, size == vm::TargetBytesPerWord); if (getValue(a) & 0x1F) { emit(con, asri(t->low, b->low, getValue(a) & 0x1F)); } else { moveRR(con, size, b, size, t); } } void unsignedShiftRightR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { int tmpShift = newTemp(con); ResolvedPromise maskPromise(size == 8 ? 0x3F : 0x1F); lir::Constant mask(&maskPromise); lir::Register dst(tmpShift); andC(con, 4, &mask, a, &dst); emit(con, lsr(t->low, b->low, tmpShift)); if (size == 8) { int tmpHi = newTemp(con), tmpLo = newTemp(con); emit(con, SETS(rsbi(tmpHi, tmpShift, 32))); emit(con, lsl(tmpLo, b->high, tmpHi)); emit(con, orr(t->low, t->low, tmpLo)); emit(con, addi(tmpHi, tmpShift, -32)); emit(con, lsr(tmpLo, b->high, tmpHi)); emit(con, orr(t->low, t->low, tmpLo)); emit(con, lsr(t->high, b->high, tmpShift)); freeTemp(con, tmpHi); freeTemp(con, tmpLo); } freeTemp(con, tmpShift); } void unsignedShiftRightC(Context* con, unsigned size UNUSED, lir::Constant* a, lir::Register* b, lir::Register* t) { assert(con, size == vm::TargetBytesPerWord); if (getValue(a) & 0x1F) { emit(con, lsri(t->low, b->low, getValue(a) & 0x1F)); } else { moveRR(con, size, b, size, t); } } bool needJump(MyBlock* b) { return b->next or b->size != (b->size & PoolOffsetMask); } unsigned padding(MyBlock* b, unsigned offset) { unsigned total = 0; for (PoolEvent* e = b->poolEventHead; e; e = e->next) { if (e->offset <= offset) { if (needJump(b)) { total += vm::TargetBytesPerWord; } for (PoolOffset* o = e->poolOffsetHead; o; o = o->next) { total += vm::TargetBytesPerWord; } } else { break; } } return total; } void resolve(MyBlock* b) { Context* con = b->context; if (b->poolOffsetHead) { if (con->poolOffsetTail) { con->poolOffsetTail->next = b->poolOffsetHead; } else { con->poolOffsetHead = b->poolOffsetHead; } con->poolOffsetTail = b->poolOffsetTail; } if (con->poolOffsetHead) { bool append; if (b->next == 0 or b->next->poolEventHead) { append = true; } else { int32_t v = (b->start + b->size + b->next->size + vm::TargetBytesPerWord - 8) - (con->poolOffsetHead->offset + con->poolOffsetHead->block->start); append = (v != (v & PoolOffsetMask)); if (DebugPool) { fprintf(stderr, "current %p %d %d next %p %d %d\n", b, b->start, b->size, b->next, b->start + b->size, b->next->size); fprintf(stderr, "offset %p %d is of distance %d to next block; append? %d\n", con->poolOffsetHead, con->poolOffsetHead->offset, v, append); } } if (append) { #ifndef NDEBUG int32_t v = (b->start + b->size - 8) - (con->poolOffsetHead->offset + con->poolOffsetHead->block->start); expect(con, v == (v & PoolOffsetMask)); #endif // not NDEBUG appendPoolEvent(con, b, b->size, con->poolOffsetHead, con->poolOffsetTail); if (DebugPool) { for (PoolOffset* o = con->poolOffsetHead; o; o = o->next) { fprintf(stderr, "include %p %d in pool event %p at offset %d in block %p\n", o, o->offset, b->poolEventTail, b->size, b); } } con->poolOffsetHead = 0; con->poolOffsetTail = 0; } } } void jumpR(Context* con, unsigned size UNUSED, lir::Register* target) { assert(con, size == vm::TargetBytesPerWord); emit(con, bx(target->low)); } void swapRR(Context* con, unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b) { assert(con, aSize == vm::TargetBytesPerWord); assert(con, bSize == vm::TargetBytesPerWord); lir::Register tmp(con->client->acquireTemporary(GPR_MASK)); moveRR(con, aSize, a, bSize, &tmp); moveRR(con, bSize, b, aSize, a); moveRR(con, bSize, &tmp, bSize, b); con->client->releaseTemporary(tmp.low); } void moveRR(Context* con, unsigned srcSize, lir::Register* src, unsigned dstSize, lir::Register* dst) { bool srcIsFpr = isFpr(src); bool dstIsFpr = isFpr(dst); if (srcIsFpr || dstIsFpr) { // FPR(s) involved assert(con, srcSize == dstSize); const bool dprec = srcSize == 8; if (srcIsFpr && dstIsFpr) { // FPR to FPR if (dprec) emit(con, fcpyd(fpr64(dst), fpr64(src))); // double else emit(con, fcpys(fpr32(dst), fpr32(src))); // single } else if (srcIsFpr) { // FPR to GPR if (dprec) emit(con, fmrrd(dst->low, dst->high, fpr64(src))); else emit(con, fmrs(dst->low, fpr32(src))); } else { // GPR to FPR if (dprec) emit(con, fmdrr(fpr64(dst->low), src->low, src->high)); else emit(con, fmsr(fpr32(dst), src->low)); } return; } switch (srcSize) { case 1: emit(con, lsli(dst->low, src->low, 24)); emit(con, asri(dst->low, dst->low, 24)); break; case 2: emit(con, lsli(dst->low, src->low, 16)); emit(con, asri(dst->low, dst->low, 16)); break; case 4: case 8: if (srcSize == 4 and dstSize == 8) { moveRR(con, 4, src, 4, dst); emit(con, asri(dst->high, src->low, 31)); } else if (srcSize == 8 and dstSize == 8) { lir::Register srcHigh(src->high); lir::Register dstHigh(dst->high); if (src->high == dst->low) { if (src->low == dst->high) { swapRR(con, 4, src, 4, dst); } else { moveRR(con, 4, &srcHigh, 4, &dstHigh); moveRR(con, 4, src, 4, dst); } } else { moveRR(con, 4, src, 4, dst); moveRR(con, 4, &srcHigh, 4, &dstHigh); } } else if (src->low != dst->low) { emit(con, mov(dst->low, src->low)); } break; default: abort(con); } } void moveZRR(Context* con, unsigned srcSize, lir::Register* src, unsigned, lir::Register* dst) { switch (srcSize) { case 2: emit(con, lsli(dst->low, src->low, 16)); emit(con, lsri(dst->low, dst->low, 16)); break; default: abort(con); } } void moveCR(Context* con, unsigned size, lir::Constant* src, unsigned, lir::Register* dst); void moveCR2(Context* con, unsigned size, lir::Constant* src, lir::Register* dst, Promise* callOffset) { if (isFpr(dst)) { // floating-point lir::Register tmp = size > 4 ? makeTemp64(con) : makeTemp(con); moveCR(con, size, src, size, &tmp); moveRR(con, size, &tmp, size, dst); freeTemp(con, tmp); } else if (size > 4) { uint64_t value = (uint64_t)src->value->value(); ResolvedPromise loBits(value & MASK_LO32); lir::Constant srcLo(&loBits); ResolvedPromise hiBits(value >> 32); lir::Constant srcHi(&hiBits); lir::Register dstHi(dst->high); moveCR(con, 4, &srcLo, 4, dst); moveCR(con, 4, &srcHi, 4, &dstHi); } else if (src->value->resolved() and isOfWidth(getValue(src), 8)) { emit(con, movi(dst->low, lo8(getValue(src)))); // fits in immediate } else { appendConstantPoolEntry(con, src->value, callOffset); emit(con, ldri(dst->low, ProgramCounter, 0)); // load 32 bits } } void moveCR(Context* con, unsigned size, lir::Constant* src, unsigned, lir::Register* dst) { moveCR2(con, size, src, dst, 0); } void addR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if (size == 8) { emit(con, SETS(add(t->low, a->low, b->low))); emit(con, adc(t->high, a->high, b->high)); } else { emit(con, add(t->low, a->low, b->low)); } } void subR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if (size == 8) { emit(con, SETS(rsb(t->low, a->low, b->low))); emit(con, rsc(t->high, a->high, b->high)); } else { emit(con, rsb(t->low, a->low, b->low)); } } void addC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst) { assert(con, size == vm::TargetBytesPerWord); int32_t v = a->value->value(); if (v) { if (v > 0 and v < 256) { emit(con, addi(dst->low, b->low, v)); } else if (v > 0 and v < 1024 and v % 4 == 0) { emit(con, addi(dst->low, b->low, v >> 2, 15)); } else { // todo abort(con); } } else { moveRR(con, size, b, size, dst); } } void subC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst) { assert(con, size == vm::TargetBytesPerWord); int32_t v = a->value->value(); if (v) { if (v > 0 and v < 256) { emit(con, subi(dst->low, b->low, v)); } else if (v > 0 and v < 1024 and v % 4 == 0) { emit(con, subi(dst->low, b->low, v >> 2, 15)); } else { // todo abort(con); } } else { moveRR(con, size, b, size, dst); } } void multiplyR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if (size == 8) { bool useTemporaries = b->low == t->low; int tmpLow = useTemporaries ? con->client->acquireTemporary(GPR_MASK) : t->low; int tmpHigh = useTemporaries ? con->client->acquireTemporary(GPR_MASK) : t->high; emit(con, umull(tmpLow, tmpHigh, a->low, b->low)); emit(con, mla(tmpHigh, a->low, b->high, tmpHigh)); emit(con, mla(tmpHigh, a->high, b->low, tmpHigh)); if (useTemporaries) { emit(con, mov(t->low, tmpLow)); emit(con, mov(t->high, tmpHigh)); con->client->releaseTemporary(tmpLow); con->client->releaseTemporary(tmpHigh); } } else { emit(con, mul(t->low, a->low, b->low)); } } void floatAbsoluteRR(Context* con, unsigned size, lir::Register* a, unsigned, lir::Register* b) { if (size == 8) { emit(con, fabsd(fpr64(b), fpr64(a))); } else { emit(con, fabss(fpr32(b), fpr32(a))); } } void floatNegateRR(Context* con, unsigned size, lir::Register* a, unsigned, lir::Register* b) { if (size == 8) { emit(con, fnegd(fpr64(b), fpr64(a))); } else { emit(con, fnegs(fpr32(b), fpr32(a))); } } void float2FloatRR(Context* con, unsigned size, lir::Register* a, unsigned, lir::Register* b) { if (size == 8) { emit(con, fcvtsd(fpr32(b), fpr64(a))); } else { emit(con, fcvtds(fpr64(b), fpr32(a))); } } void float2IntRR(Context* con, unsigned size, lir::Register* a, unsigned, lir::Register* b) { int tmp = newTemp(con, FPR_MASK); int ftmp = fpr32(tmp); if (size == 8) { // double to int emit(con, ftosizd(ftmp, fpr64(a))); } else { // float to int emit(con, ftosizs(ftmp, fpr32(a))); } // else thunked emit(con, fmrs(b->low, ftmp)); freeTemp(con, tmp); } void int2FloatRR(Context* con, unsigned, lir::Register* a, unsigned size, lir::Register* b) { emit(con, fmsr(fpr32(b), a->low)); if (size == 8) { // int to double emit(con, fsitod(fpr64(b), fpr32(b))); } else { // int to float emit(con, fsitos(fpr32(b), fpr32(b))); } // else thunked } void floatSqrtRR(Context* con, unsigned size, lir::Register* a, unsigned, lir::Register* b) { if (size == 8) { emit(con, fsqrtd(fpr64(b), fpr64(a))); } else { emit(con, fsqrts(fpr32(b), fpr32(a))); } } void floatAddR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if (size == 8) { emit(con, faddd(fpr64(t), fpr64(a), fpr64(b))); } else { emit(con, fadds(fpr32(t), fpr32(a), fpr32(b))); } } void floatSubtractR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if (size == 8) { emit(con, fsubd(fpr64(t), fpr64(b), fpr64(a))); } else { emit(con, fsubs(fpr32(t), fpr32(b), fpr32(a))); } } void floatMultiplyR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if (size == 8) { emit(con, fmuld(fpr64(t), fpr64(a), fpr64(b))); } else { emit(con, fmuls(fpr32(t), fpr32(a), fpr32(b))); } } void floatDivideR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if (size == 8) { emit(con, fdivd(fpr64(t), fpr64(b), fpr64(a))); } else { emit(con, fdivs(fpr32(t), fpr32(b), fpr32(a))); } } int normalize(Context* con, int offset, int index, unsigned scale, bool* preserveIndex, bool* release) { if (offset != 0 or scale != 1) { lir::Register normalizedIndex (*preserveIndex ? con->client->acquireTemporary(GPR_MASK) : index); if (*preserveIndex) { *release = true; *preserveIndex = false; } else { *release = false; } int scaled; if (scale != 1) { lir::Register unscaledIndex(index); ResolvedPromise scalePromise(log(scale)); lir::Constant scaleConstant(&scalePromise); shiftLeftC(con, vm::TargetBytesPerWord, &scaleConstant, &unscaledIndex, &normalizedIndex); scaled = normalizedIndex.low; } else { scaled = index; } if (offset != 0) { lir::Register untranslatedIndex(scaled); ResolvedPromise offsetPromise(offset); lir::Constant offsetConstant(&offsetPromise); lir::Register tmp(con->client->acquireTemporary(GPR_MASK)); moveCR(con, vm::TargetBytesPerWord, &offsetConstant, vm::TargetBytesPerWord, &tmp); addR(con, vm::TargetBytesPerWord, &tmp, &untranslatedIndex, &normalizedIndex); con->client->releaseTemporary(tmp.low); } return normalizedIndex.low; } else { *release = false; return index; } } void store(Context* con, unsigned size, lir::Register* src, int base, int offset, int index, unsigned scale, bool preserveIndex) { if (index != lir::NoRegister) { bool release; int normalized = normalize (con, offset, index, scale, &preserveIndex, &release); if (!isFpr(src)) { // GPR store switch (size) { case 1: emit(con, strb(src->low, base, normalized)); break; case 2: emit(con, strh(src->low, base, normalized)); break; case 4: emit(con, str(src->low, base, normalized)); break; case 8: { // split into 2 32-bit stores lir::Register srcHigh(src->high); store(con, 4, &srcHigh, base, 0, normalized, 1, preserveIndex); store(con, 4, src, base, 4, normalized, 1, preserveIndex); } break; default: abort(con); } } else { // FPR store lir::Register base_(base), normalized_(normalized), absAddr = makeTemp(con); // FPR stores have only bases, so we must add the index addR(con, vm::TargetBytesPerWord, &base_, &normalized_, &absAddr); // double-precision if (size == 8) emit(con, fstd(fpr64(src), absAddr.low)); // single-precision else emit(con, fsts(fpr32(src), absAddr.low)); freeTemp(con, absAddr); } if (release) con->client->releaseTemporary(normalized); } else if (size == 8 or abs(offset) == (abs(offset) & 0xFF) or (size != 2 and abs(offset) == (abs(offset) & 0xFFF))) { if (!isFpr(src)) { // GPR store switch (size) { case 1: emit(con, strbi(src->low, base, offset)); break; case 2: emit(con, strhi(src->low, base, offset)); break; case 4: emit(con, stri(src->low, base, offset)); break; case 8: { // split into 2 32-bit stores lir::Register srcHigh(src->high); store(con, 4, &srcHigh, base, offset, lir::NoRegister, 1, false); store(con, 4, src, base, offset + 4, lir::NoRegister, 1, false); } break; default: abort(con); } } else { // FPR store // double-precision if (size == 8) emit(con, fstd(fpr64(src), base, offset)); // single-precision else emit(con, fsts(fpr32(src), base, offset)); } } else { lir::Register tmp(con->client->acquireTemporary(GPR_MASK)); ResolvedPromise offsetPromise(offset); lir::Constant offsetConstant(&offsetPromise); moveCR(con, vm::TargetBytesPerWord, &offsetConstant, vm::TargetBytesPerWord, &tmp); store(con, size, src, base, 0, tmp.low, 1, false); con->client->releaseTemporary(tmp.low); } } void moveRM(Context* con, unsigned srcSize, lir::Register* src, unsigned dstSize UNUSED, lir::Memory* dst) { assert(con, srcSize == dstSize); store(con, srcSize, src, dst->base, dst->offset, dst->index, dst->scale, true); } void load(Context* con, unsigned srcSize, int base, int offset, int index, unsigned scale, unsigned dstSize, lir::Register* dst, bool preserveIndex, bool signExtend) { if (index != lir::NoRegister) { bool release; int normalized = normalize (con, offset, index, scale, &preserveIndex, &release); if (!isFpr(dst)) { // GPR load switch (srcSize) { case 1: if (signExtend) { emit(con, ldrsb(dst->low, base, normalized)); } else { emit(con, ldrb(dst->low, base, normalized)); } break; case 2: if (signExtend) { emit(con, ldrsh(dst->low, base, normalized)); } else { emit(con, ldrh(dst->low, base, normalized)); } break; case 4: case 8: { if (srcSize == 4 and dstSize == 8) { load(con, 4, base, 0, normalized, 1, 4, dst, preserveIndex, false); moveRR(con, 4, dst, 8, dst); } else if (srcSize == 8 and dstSize == 8) { lir::Register dstHigh(dst->high); load(con, 4, base, 0, normalized, 1, 4, &dstHigh, preserveIndex, false); load(con, 4, base, 4, normalized, 1, 4, dst, preserveIndex, false); } else { emit(con, ldr(dst->low, base, normalized)); } } break; default: abort(con); } } else { // FPR load lir::Register base_(base), normalized_(normalized), absAddr = makeTemp(con); // VFP loads only have bases, so we must add the index addR(con, vm::TargetBytesPerWord, &base_, &normalized_, &absAddr); // double-precision if (srcSize == 8) emit(con, fldd(fpr64(dst), absAddr.low)); // single-precision else emit(con, flds(fpr32(dst), absAddr.low)); freeTemp(con, absAddr); } if (release) con->client->releaseTemporary(normalized); } else if ((srcSize == 8 and dstSize == 8) or abs(offset) == (abs(offset) & 0xFF) or (srcSize != 2 and (srcSize != 1 or not signExtend) and abs(offset) == (abs(offset) & 0xFFF))) { if (!isFpr(dst)) { // GPR load switch (srcSize) { case 1: if (signExtend) { emit(con, ldrsbi(dst->low, base, offset)); } else { emit(con, ldrbi(dst->low, base, offset)); } break; case 2: if (signExtend) { emit(con, ldrshi(dst->low, base, offset)); } else { emit(con, ldrhi(dst->low, base, offset)); } break; case 4: emit(con, ldri(dst->low, base, offset)); break; case 8: { if (dstSize == 8) { lir::Register dstHigh(dst->high); load(con, 4, base, offset, lir::NoRegister, 1, 4, &dstHigh, false, false); load(con, 4, base, offset + 4, lir::NoRegister, 1, 4, dst, false, false); } else { emit(con, ldri(dst->low, base, offset)); } } break; default: abort(con); } } else { // FPR load // double-precision if (srcSize == 8) emit(con, fldd(fpr64(dst), base, offset)); // single-precision else emit(con, flds(fpr32(dst), base, offset)); } } else { lir::Register tmp(con->client->acquireTemporary(GPR_MASK)); ResolvedPromise offsetPromise(offset); lir::Constant offsetConstant(&offsetPromise); moveCR(con, vm::TargetBytesPerWord, &offsetConstant, vm::TargetBytesPerWord, &tmp); load(con, srcSize, base, 0, tmp.low, 1, dstSize, dst, false, signExtend); con->client->releaseTemporary(tmp.low); } } void moveMR(Context* con, unsigned srcSize, lir::Memory* src, unsigned dstSize, lir::Register* dst) { load(con, srcSize, src->base, src->offset, src->index, src->scale, dstSize, dst, true, true); } void moveZMR(Context* con, unsigned srcSize, lir::Memory* src, unsigned dstSize, lir::Register* dst) { load(con, srcSize, src->base, src->offset, src->index, src->scale, dstSize, dst, true, false); } void andR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst) { if (size == 8) emit(con, and_(dst->high, a->high, b->high)); emit(con, and_(dst->low, a->low, b->low)); } void andC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst) { int64_t v = a->value->value(); if (size == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); lir::Constant ah(&high); ResolvedPromise low(v & 0xFFFFFFFF); lir::Constant al(&low); lir::Register bh(b->high); lir::Register dh(dst->high); andC(con, 4, &al, b, dst); andC(con, 4, &ah, &bh, &dh); } else { uint32_t v32 = static_cast(v); if (v32 != 0xFFFFFFFF) { if ((v32 & 0xFFFFFF00) == 0xFFFFFF00) { emit(con, bici(dst->low, b->low, (~(v32 & 0xFF)) & 0xFF)); } else if ((v32 & 0xFFFFFF00) == 0) { emit(con, andi(dst->low, b->low, v32 & 0xFF)); } else { // todo: there are other cases we can handle in one // instruction bool useTemporary = b->low == dst->low; lir::Register tmp(dst->low); if (useTemporary) { tmp.low = con->client->acquireTemporary(GPR_MASK); } moveCR(con, 4, a, 4, &tmp); andR(con, 4, b, &tmp, dst); if (useTemporary) { con->client->releaseTemporary(tmp.low); } } } else { moveRR(con, size, b, size, dst); } } } void orR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst) { if (size == 8) emit(con, orr(dst->high, a->high, b->high)); emit(con, orr(dst->low, a->low, b->low)); } void xorR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst) { if (size == 8) emit(con, eor(dst->high, a->high, b->high)); emit(con, eor(dst->low, a->low, b->low)); } void moveAR2(Context* con, unsigned srcSize, lir::Address* src, unsigned dstSize, lir::Register* dst) { assert(con, srcSize == 4 and dstSize == 4); lir::Constant constant(src->address); moveCR(con, srcSize, &constant, dstSize, dst); lir::Memory memory(dst->low, 0, -1, 0); moveMR(con, dstSize, &memory, dstSize, dst); } void moveAR(Context* con, unsigned srcSize, lir::Address* src, unsigned dstSize, lir::Register* dst) { moveAR2(con, srcSize, src, dstSize, dst); } void compareRR(Context* con, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(con, !(isFpr(a) ^ isFpr(b))); // regs must be of the same type if (!isFpr(a)) { // GPR compare assert(con, aSize == 4 && bSize == 4); /**///assert(con, b->low != a->low); emit(con, cmp(b->low, a->low)); } else { // FPR compare assert(con, aSize == bSize); if (aSize == 8) emit(con, fcmpd(fpr64(b), fpr64(a))); // double else emit(con, fcmps(fpr32(b), fpr32(a))); // single emit(con, fmstat()); } } void compareCR(Context* con, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(con, aSize == 4 and bSize == 4); if (!isFpr(b) && a->value->resolved() && isOfWidth(a->value->value(), 8)) { emit(con, cmpi(b->low, a->value->value())); } else { lir::Register tmp(con->client->acquireTemporary(GPR_MASK)); moveCR(con, aSize, a, bSize, &tmp); compareRR(con, bSize, &tmp, bSize, b); con->client->releaseTemporary(tmp.low); } } void compareCM(Context* con, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Memory* b) { assert(con, aSize == 4 and bSize == 4); lir::Register tmp(con->client->acquireTemporary(GPR_MASK)); moveMR(con, bSize, b, bSize, &tmp); compareCR(con, aSize, a, bSize, &tmp); con->client->releaseTemporary(tmp.low); } void compareRM(Context* con, unsigned aSize, lir::Register* a, unsigned bSize, lir::Memory* b) { assert(con, aSize == 4 and bSize == 4); lir::Register tmp(con->client->acquireTemporary(GPR_MASK)); moveMR(con, bSize, b, bSize, &tmp); compareRR(con, aSize, a, bSize, &tmp); con->client->releaseTemporary(tmp.low); } int32_t branch(Context* con, lir::TernaryOperation op) { switch (op) { case lir::JumpIfEqual: case lir::JumpIfFloatEqual: return beq(0); case lir::JumpIfNotEqual: case lir::JumpIfFloatNotEqual: return bne(0); case lir::JumpIfLess: case lir::JumpIfFloatLess: case lir::JumpIfFloatLessOrUnordered: return blt(0); case lir::JumpIfGreater: case lir::JumpIfFloatGreater: return bgt(0); case lir::JumpIfLessOrEqual: case lir::JumpIfFloatLessOrEqual: case lir::JumpIfFloatLessOrEqualOrUnordered: return ble(0); case lir::JumpIfGreaterOrEqual: case lir::JumpIfFloatGreaterOrEqual: return bge(0); case lir::JumpIfFloatGreaterOrUnordered: return bhi(0); case lir::JumpIfFloatGreaterOrEqualOrUnordered: return bpl(0); default: abort(con); } } void conditional(Context* con, int32_t branch, lir::Constant* target) { appendOffsetTask(con, target->value, offsetPromise(con)); emit(con, branch); } void branch(Context* con, lir::TernaryOperation op, lir::Constant* target) { conditional(con, branch(con, op), target); } void branchLong(Context* con, lir::TernaryOperation op, lir::Operand* al, lir::Operand* ah, lir::Operand* bl, lir::Operand* bh, lir::Constant* target, BinaryOperationType compareSigned, BinaryOperationType compareUnsigned) { compareSigned(con, 4, ah, 4, bh); unsigned next = 0; switch (op) { case lir::JumpIfEqual: case lir::JumpIfFloatEqual: next = con->code.length(); emit(con, bne(0)); compareSigned(con, 4, al, 4, bl); conditional(con, beq(0), target); break; case lir::JumpIfNotEqual: case lir::JumpIfFloatNotEqual: conditional(con, bne(0), target); compareSigned(con, 4, al, 4, bl); conditional(con, bne(0), target); break; case lir::JumpIfLess: case lir::JumpIfFloatLess: conditional(con, blt(0), target); next = con->code.length(); emit(con, bgt(0)); compareUnsigned(con, 4, al, 4, bl); conditional(con, blo(0), target); break; case lir::JumpIfGreater: case lir::JumpIfFloatGreater: conditional(con, bgt(0), target); next = con->code.length(); emit(con, blt(0)); compareUnsigned(con, 4, al, 4, bl); conditional(con, bhi(0), target); break; case lir::JumpIfLessOrEqual: case lir::JumpIfFloatLessOrEqual: conditional(con, blt(0), target); next = con->code.length(); emit(con, bgt(0)); compareUnsigned(con, 4, al, 4, bl); conditional(con, bls(0), target); break; case lir::JumpIfGreaterOrEqual: case lir::JumpIfFloatGreaterOrEqual: conditional(con, bgt(0), target); next = con->code.length(); emit(con, blt(0)); compareUnsigned(con, 4, al, 4, bl); conditional(con, bhs(0), target); break; default: abort(con); } if (next) { updateOffset(con->s, con->code.data.begin() + next, reinterpret_cast(con->code.data.begin() + con->code.length())); } } void branchRR(Context* con, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Register* b, lir::Constant* target) { if (!isFpr(a) && size > vm::TargetBytesPerWord) { lir::Register ah(a->high); lir::Register bh(b->high); branchLong(con, op, a, &ah, b, &bh, target, CAST2(compareRR), CAST2(compareRR)); } else { compareRR(con, size, a, size, b); branch(con, op, target); } } void branchCR(Context* con, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Register* b, lir::Constant* target) { assert(con, !isFloatBranch(op)); if (size > vm::TargetBytesPerWord) { int64_t v = a->value->value(); ResolvedPromise low(v & ~static_cast(0)); lir::Constant al(&low); ResolvedPromise high((v >> 32) & ~static_cast(0)); lir::Constant ah(&high); lir::Register bh(b->high); branchLong(con, op, &al, &ah, b, &bh, target, CAST2(compareCR), CAST2(compareCR)); } else { compareCR(con, size, a, size, b); branch(con, op, target); } } void branchRM(Context* con, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Memory* b, lir::Constant* target) { assert(con, !isFloatBranch(op)); assert(con, size <= vm::TargetBytesPerWord); compareRM(con, size, a, size, b); branch(con, op, target); } void branchCM(Context* con, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Memory* b, lir::Constant* target) { assert(con, !isFloatBranch(op)); assert(con, size <= vm::TargetBytesPerWord); compareCM(con, size, a, size, b); branch(con, op, target); } ShiftMaskPromise* shiftMaskPromise(Context* con, Promise* base, unsigned shift, int64_t mask) { return new(con->zone) ShiftMaskPromise(base, shift, mask); } void moveCM(Context* con, unsigned srcSize, lir::Constant* src, unsigned dstSize, lir::Memory* dst) { switch (dstSize) { case 8: { lir::Constant srcHigh (shiftMaskPromise(con, src->value, 32, 0xFFFFFFFF)); lir::Constant srcLow (shiftMaskPromise(con, src->value, 0, 0xFFFFFFFF)); lir::Memory dstLow (dst->base, dst->offset + 4, dst->index, dst->scale); moveCM(con, 4, &srcLow, 4, &dstLow); moveCM(con, 4, &srcHigh, 4, dst); } break; default: lir::Register tmp(con->client->acquireTemporary(GPR_MASK)); moveCR(con, srcSize, src, dstSize, &tmp); moveRM(con, dstSize, &tmp, dstSize, dst); con->client->releaseTemporary(tmp.low); } } void negateRR(Context* con, unsigned srcSize, lir::Register* src, unsigned dstSize UNUSED, lir::Register* dst) { assert(con, srcSize == dstSize); emit(con, mvn(dst->low, src->low)); emit(con, SETS(addi(dst->low, dst->low, 1))); if (srcSize == 8) { emit(con, mvn(dst->high, src->high)); emit(con, adci(dst->high, dst->high, 0)); } } void callR(Context* con, unsigned size UNUSED, lir::Register* target) { assert(con, size == vm::TargetBytesPerWord); emit(con, blx(target->low)); } void callC(Context* con, unsigned size UNUSED, lir::Constant* target) { assert(con, size == vm::TargetBytesPerWord); appendOffsetTask(con, target->value, offsetPromise(con)); emit(con, bl(0)); } void longCallC(Context* con, unsigned size UNUSED, lir::Constant* target) { assert(con, size == vm::TargetBytesPerWord); lir::Register tmp(4); moveCR2(con, vm::TargetBytesPerWord, target, &tmp, offsetPromise(con)); callR(con, vm::TargetBytesPerWord, &tmp); } void longJumpC(Context* con, unsigned size UNUSED, lir::Constant* target) { assert(con, size == vm::TargetBytesPerWord); lir::Register tmp(4); // a non-arg reg that we don't mind clobbering moveCR2(con, vm::TargetBytesPerWord, target, &tmp, offsetPromise(con)); jumpR(con, vm::TargetBytesPerWord, &tmp); } void jumpC(Context* con, unsigned size UNUSED, lir::Constant* target) { assert(con, size == vm::TargetBytesPerWord); appendOffsetTask(con, target->value, offsetPromise(con)); emit(con, b(0)); } void return_(Context* con) { emit(con, bx(LinkRegister)); } void trap(Context* con) { emit(con, bkpt(0)); } // todo: determine the minimal operation types and domains needed to // implement the following barriers (see // http://community.arm.com/groups/processors/blog/2011/10/19/memory-access-ordering-part-3--memory-access-ordering-in-the-arm-architecture). // For now, we just use DMB SY as a conservative but not necessarily // performant choice. void memoryBarrier(Context* con UNUSED) { #ifndef AVIAN_ASSUME_ARMV6 emit(con, dmb()); #endif } void loadBarrier(Context* con) { memoryBarrier(con); } void storeStoreBarrier(Context* con) { memoryBarrier(con); } void storeLoadBarrier(Context* con) { memoryBarrier(con); } } // namespace arm } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/arm/operations.h000066400000000000000000000200761231440243200237610ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_ARM_OPERATIONS_H #define AVIAN_CODEGEN_ASSEMBLER_ARM_OPERATIONS_H #include "registers.h" namespace vm { class System; } namespace avian { namespace codegen { namespace arm { class Context; // shortcut functions inline int newTemp(Context* con) { return con->client->acquireTemporary(GPR_MASK); } inline int newTemp(Context* con, unsigned mask) { return con->client->acquireTemporary(mask); } inline void freeTemp(Context* con, int r) { con->client->releaseTemporary(r); } inline int64_t getValue(lir::Constant* con) { return con->value->value(); } inline lir::Register makeTemp(Context* con) { lir::Register tmp(newTemp(con)); return tmp; } inline lir::Register makeTemp64(Context* con) { lir::Register tmp(newTemp(con), newTemp(con)); return tmp; } inline void freeTemp(Context* con, const lir::Register& tmp) { if (tmp.low != lir::NoRegister) freeTemp(con, tmp.low); if (tmp.high != lir::NoRegister) freeTemp(con, tmp.high); } void shiftLeftR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void moveRR(Context* con, unsigned srcSize, lir::Register* src, unsigned dstSize, lir::Register* dst); void shiftLeftC(Context* con, unsigned size UNUSED, lir::Constant* a, lir::Register* b, lir::Register* t); void shiftRightR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void shiftRightC(Context* con, unsigned size UNUSED, lir::Constant* a, lir::Register* b, lir::Register* t); void unsignedShiftRightR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void unsignedShiftRightC(Context* con, unsigned size UNUSED, lir::Constant* a, lir::Register* b, lir::Register* t); bool needJump(MyBlock* b); unsigned padding(MyBlock* b, unsigned offset); void resolve(MyBlock* b); void jumpR(Context* con, unsigned size UNUSED, lir::Register* target); void swapRR(Context* con, unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b); void moveRR(Context* con, unsigned srcSize, lir::Register* src, unsigned dstSize, lir::Register* dst); void moveZRR(Context* con, unsigned srcSize, lir::Register* src, unsigned, lir::Register* dst); void moveCR(Context* con, unsigned size, lir::Constant* src, unsigned, lir::Register* dst); void moveCR2(Context* con, unsigned size, lir::Constant* src, lir::Register* dst, Promise* callOffset); void moveCR(Context* con, unsigned size, lir::Constant* src, unsigned, lir::Register* dst); void addR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void subR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void addC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst); void subC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst); void multiplyR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void floatAbsoluteRR(Context* con, unsigned size, lir::Register* a, unsigned, lir::Register* b); void floatNegateRR(Context* con, unsigned size, lir::Register* a, unsigned, lir::Register* b); void float2FloatRR(Context* con, unsigned size, lir::Register* a, unsigned, lir::Register* b); void float2IntRR(Context* con, unsigned size, lir::Register* a, unsigned, lir::Register* b); void int2FloatRR(Context* con, unsigned, lir::Register* a, unsigned size, lir::Register* b); void floatSqrtRR(Context* con, unsigned size, lir::Register* a, unsigned, lir::Register* b); void floatAddR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void floatSubtractR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void floatMultiplyR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void floatDivideR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); int normalize(Context* con, int offset, int index, unsigned scale, bool* preserveIndex, bool* release); void store(Context* con, unsigned size, lir::Register* src, int base, int offset, int index, unsigned scale, bool preserveIndex); void moveRM(Context* con, unsigned srcSize, lir::Register* src, unsigned dstSize UNUSED, lir::Memory* dst); void load(Context* con, unsigned srcSize, int base, int offset, int index, unsigned scale, unsigned dstSize, lir::Register* dst, bool preserveIndex, bool signExtend); void moveMR(Context* con, unsigned srcSize, lir::Memory* src, unsigned dstSize, lir::Register* dst); void moveZMR(Context* con, unsigned srcSize, lir::Memory* src, unsigned dstSize, lir::Register* dst); void andR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst); void andC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst); void orR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst); void xorR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst); void moveAR2(Context* con, unsigned srcSize, lir::Address* src, unsigned dstSize, lir::Register* dst); void moveAR(Context* con, unsigned srcSize, lir::Address* src, unsigned dstSize, lir::Register* dst); void compareRR(Context* con, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void compareCR(Context* con, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void compareCM(Context* con, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Memory* b); void compareRM(Context* con, unsigned aSize, lir::Register* a, unsigned bSize, lir::Memory* b); int32_t branch(Context* con, lir::TernaryOperation op); void conditional(Context* con, int32_t branch, lir::Constant* target); void branch(Context* con, lir::TernaryOperation op, lir::Constant* target); void branchLong(Context* con, lir::TernaryOperation op, lir::Operand* al, lir::Operand* ah, lir::Operand* bl, lir::Operand* bh, lir::Constant* target, BinaryOperationType compareSigned, BinaryOperationType compareUnsigned); void branchRR(Context* con, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Register* b, lir::Constant* target); void branchCR(Context* con, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Register* b, lir::Constant* target); void branchRM(Context* con, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Memory* b, lir::Constant* target); void branchCM(Context* con, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Memory* b, lir::Constant* target); ShiftMaskPromise* shiftMaskPromise(Context* con, Promise* base, unsigned shift, int64_t mask); void moveCM(Context* con, unsigned srcSize, lir::Constant* src, unsigned dstSize, lir::Memory* dst); void negateRR(Context* con, unsigned srcSize, lir::Register* src, unsigned dstSize UNUSED, lir::Register* dst); void callR(Context* con, unsigned size UNUSED, lir::Register* target); void callC(Context* con, unsigned size UNUSED, lir::Constant* target); void longCallC(Context* con, unsigned size UNUSED, lir::Constant* target); void longJumpC(Context* con, unsigned size UNUSED, lir::Constant* target); void jumpC(Context* con, unsigned size UNUSED, lir::Constant* target); void return_(Context* con); void trap(Context* con); void loadBarrier(Context*); void storeStoreBarrier(Context*); void storeLoadBarrier(Context*); } // namespace arm } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_ARM_OPERATIONS_H ReadyTalk-avian-1e1fff5/src/codegen/target/arm/registers.h000066400000000000000000000027021231440243200236010ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_ARM_REGISTERS_H #define AVIAN_CODEGEN_ASSEMBLER_ARM_REGISTERS_H #include #include namespace avian { namespace codegen { namespace arm { const uint64_t MASK_LO32 = 0xffffffff; const unsigned MASK_LO16 = 0xffff; const unsigned MASK_LO8 = 0xff; const int N_GPRS = 16; const int N_FPRS = 16; const uint32_t GPR_MASK = 0xffff; const uint32_t FPR_MASK = 0xffff0000; const uint64_t GPR_MASK64 = GPR_MASK | (uint64_t)GPR_MASK << 32; const uint64_t FPR_MASK64 = FPR_MASK | (uint64_t)FPR_MASK << 32; inline bool isFpr(lir::Register* reg) { return reg->low >= N_GPRS; } inline int fpr64(int reg) { return reg - N_GPRS; } inline int fpr64(lir::Register* reg) { return fpr64(reg->low); } inline int fpr32(int reg) { return fpr64(reg) << 1; } inline int fpr32(lir::Register* reg) { return fpr64(reg) << 1; } const int ThreadRegister = 8; const int StackRegister = 13; const int LinkRegister = 14; const int ProgramCounter = 15; } // namespace arm } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_ARM_REGISTERS_H ReadyTalk-avian-1e1fff5/src/codegen/target/multimethod.h000066400000000000000000000013641231440243200233510ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_TARGET_MULTIMETHOD_H #define AVIAN_CODEGEN_TARGET_MULTIMETHOD_H namespace avian { namespace codegen { class Multimethod { public: inline static unsigned index(lir::UnaryOperation operation, lir::OperandType operand) { return operation + (lir::UnaryOperationCount * operand); } }; } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_TARGET_MULTIMETHOD_H ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/000077500000000000000000000000001231440243200223205ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/assembler.cpp000066400000000000000000000660161231440243200250120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include "avian/alloc-vector.h" #include #include "encode.h" #include "context.h" #include "fixup.h" #include "block.h" #include "operations.h" #include "multimethod.h" #include "../multimethod.h" using namespace vm; using namespace avian::util; namespace avian { namespace codegen { namespace powerpc { inline int unha16(int32_t high, int32_t low) { return ((high - ((low & 0x8000) ? 1 : 0)) << 16) | low; } const RegisterFile MyRegisterFile(0xFFFFFFFF, 0); #ifdef __APPLE__ const unsigned FrameFooterSize = 6; const unsigned ReturnAddressOffset = 2; const unsigned AlignArguments = false; #else const unsigned FrameFooterSize = 2; const unsigned ReturnAddressOffset = 1; const unsigned AlignArguments = true; #endif const unsigned StackAlignmentInBytes = 16; const unsigned StackAlignmentInWords = StackAlignmentInBytes / TargetBytesPerWord; const int StackRegister = 1; const int ThreadRegister = 13; const bool DebugJumps = false; class JumpOffset; unsigned padding(MyBlock*, unsigned); bool bounded(int right, int left, int32_t v); class Task; class ConstantPoolEntry; bool needJump(MyBlock* b) { return b->next or (not bounded(2, 16, b->size)); } unsigned padding(MyBlock* b, unsigned offset) { unsigned total = 0; for (JumpEvent* e = b->jumpEventHead; e; e = e->next) { if (e->offset <= offset) { for (JumpOffset* o = e->jumpOffsetHead; o; o = o->next) { total += TargetBytesPerWord; } if (needJump(b)) { total += TargetBytesPerWord; } } else { break; } } return total; } void resolve(MyBlock* b) { Context* c = b->context; for (JumpEvent** e = &(b->jumpEventHead); *e;) { for (JumpOffset** o = &((*e)->jumpOffsetHead); *o;) { if ((*o)->task->promise->resolved() and (*o)->task->instructionOffset->resolved()) { int32_t v = reinterpret_cast((*o)->task->promise->value()) - (c->result + (*o)->task->instructionOffset->value()); if (bounded(2, 16, v)) { // this conditional jump needs no indirection -- a direct // jump will suffice *o = (*o)->next; continue; } } o = &((*o)->next); } if ((*e)->jumpOffsetHead == 0) { *e = (*e)->next; } else { e = &((*e)->next); } } if (b->jumpOffsetHead) { if (c->jumpOffsetTail) { c->jumpOffsetTail->next = b->jumpOffsetHead; } else { c->jumpOffsetHead = b->jumpOffsetHead; } c->jumpOffsetTail = b->jumpOffsetTail; } if (c->jumpOffsetHead) { bool append; if (b->next == 0 or b->next->jumpEventHead) { append = true; } else { int32_t v = (b->start + b->size + b->next->size + TargetBytesPerWord) - (c->jumpOffsetHead->offset + c->jumpOffsetHead->block->start); append = not bounded(2, 16, v); if (DebugJumps) { fprintf(stderr, "current %p %d %d next %p %d %d\n", b, b->start, b->size, b->next, b->start + b->size, b->next->size); fprintf(stderr, "offset %p %d is of distance %d to next block; append? %d\n", c->jumpOffsetHead, c->jumpOffsetHead->offset, v, append); } } if (append) { #ifndef NDEBUG int32_t v = (b->start + b->size) - (c->jumpOffsetHead->offset + c->jumpOffsetHead->block->start); expect(c, bounded(2, 16, v)); #endif // not NDEBUG appendJumpEvent(c, b, b->size, c->jumpOffsetHead, c->jumpOffsetTail); if (DebugJumps) { for (JumpOffset* o = c->jumpOffsetHead; o; o = o->next) { fprintf(stderr, "include %p %d in jump event %p at offset %d in block %p\n", o, o->offset, b->jumpEventTail, b->size, b); } } c->jumpOffsetHead = 0; c->jumpOffsetTail = 0; } } } // BEGIN OPERATION COMPILERS using namespace isa; // END OPERATION COMPILERS unsigned argumentFootprint(unsigned footprint) { return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); } void nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size, unsigned footprint, void* link, bool, int targetParameterFootprint, void** ip, void** stack) { assert(c, *ip >= start); assert(c, *ip <= start + (size / BytesPerWord)); int32_t* instruction = static_cast(*ip); if ((*start >> 26) == 32) { // skip stack overflow check start += 3; } if (instruction <= start + 2 or *instruction == lwz(0, 1, 8) or *instruction == mtlr(0) or *instruction == blr()) { *ip = link; return; } unsigned offset = footprint; if (TailCalls and targetParameterFootprint >= 0) { if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { offset += argumentFootprint(targetParameterFootprint) - StackAlignmentInWords; } // check for post-non-tail-call stack adjustment of the form "lwzx // r0,0(r1); stwu r0,offset(r1)": if (instruction < start + (size / BytesPerWord) - 1 and (static_cast(instruction[1]) >> 16) == 0x9401) { offset += static_cast(instruction[1]) / BytesPerWord; } else if ((static_cast(*instruction) >> 16) == 0x9401) { offset += static_cast(*instruction) / BytesPerWord; } // todo: check for and handle tail calls } *ip = static_cast(*stack)[offset + ReturnAddressOffset]; *stack = static_cast(*stack) + offset; } class MyArchitecture: public Architecture { public: MyArchitecture(System* system): c(system), referenceCount(0) { populateTables(&c); } virtual unsigned floatRegisterSize() { return 0; } virtual const RegisterFile* registerFile() { return &MyRegisterFile; } virtual int scratch() { return 31; } virtual int stack() { return StackRegister; } virtual int thread() { return ThreadRegister; } virtual int returnLow() { return 4; } virtual int returnHigh() { return (TargetBytesPerWord == 4 ? 3 : lir::NoRegister); } virtual int virtualCallTarget() { return 4; } virtual int virtualCallIndex() { return 3; } virtual bool bigEndian() { return true; } virtual uintptr_t maximumImmediateJump() { return 0x1FFFFFF; } virtual bool reserved(int register_) { switch (register_) { case 0: // r0 has special meaning in addi and other instructions case StackRegister: case ThreadRegister: #ifndef __APPLE__ // r2 is reserved for system uses on SYSV case 2: #endif return true; default: return false; } } virtual unsigned frameFootprint(unsigned footprint) { return max(footprint, StackAlignmentInWords); } virtual unsigned argumentFootprint(unsigned footprint) { return powerpc::argumentFootprint(footprint); } virtual bool argumentAlignment() { return AlignArguments; } virtual bool argumentRegisterAlignment() { return true; } virtual unsigned argumentRegisterCount() { return 8; } virtual int argumentRegister(unsigned index) { assert(&c, index < argumentRegisterCount()); return index + 3; } virtual bool hasLinkRegister() { return true; } virtual unsigned stackAlignmentInWords() { return StackAlignmentInWords; } virtual bool matchCall(void* returnAddress, void* target) { uint32_t* instruction = static_cast(returnAddress) - 1; return *instruction == static_cast (bl(static_cast(target) - reinterpret_cast(instruction))); } virtual void updateCall(lir::UnaryOperation op UNUSED, void* returnAddress, void* newTarget) { switch (op) { case lir::Call: case lir::Jump: case lir::AlignedCall: case lir::AlignedJump: { updateOffset(c.s, static_cast(returnAddress) - 4, false, reinterpret_cast(newTarget), 0); } break; case lir::LongCall: case lir::LongJump: { updateImmediate (c.s, static_cast(returnAddress) - 12, reinterpret_cast(newTarget), TargetBytesPerWord, false); } break; case lir::AlignedLongCall: case lir::AlignedLongJump: { uint32_t* p = static_cast(returnAddress) - 4; *reinterpret_cast(unha16(p[0] & 0xFFFF, p[1] & 0xFFFF)) = newTarget; } break; default: abort(&c); } } virtual unsigned constantCallSize() { return 4; } virtual void setConstant(void* dst, uint64_t constant) { updateImmediate(c.s, dst, constant, TargetBytesPerWord, false); } virtual unsigned alignFrameSize(unsigned sizeInWords) { const unsigned alignment = StackAlignmentInWords; return (ceilingDivide(sizeInWords + FrameFooterSize, alignment) * alignment); } virtual void nextFrame(void* start, unsigned size, unsigned footprint, void* link, bool mostRecent, int targetParameterFootprint, void** ip, void** stack) { powerpc::nextFrame(&c, static_cast(start), size, footprint, link, mostRecent, targetParameterFootprint, ip, stack); } virtual void* frameIp(void* stack) { return stack ? static_cast(stack)[ReturnAddressOffset] : 0; } virtual unsigned frameHeaderSize() { return 0; } virtual unsigned frameReturnAddressSize() { return 0; } virtual unsigned frameFooterSize() { return FrameFooterSize; } virtual int returnAddressOffset() { return ReturnAddressOffset; } virtual int framePointerOffset() { return 0; } virtual bool alwaysCondensed(lir::BinaryOperation) { return false; } virtual bool alwaysCondensed(lir::TernaryOperation) { return false; } virtual void plan (lir::UnaryOperation, unsigned, OperandMask& aMask, bool* thunk) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::ConstantOperand); aMask.registerMask = ~static_cast(0); *thunk = false; } virtual void planSource (lir::BinaryOperation op, unsigned, OperandMask& aMask, unsigned, bool* thunk) { aMask.typeMask = ~0; aMask.registerMask = ~static_cast(0); *thunk = false; switch (op) { case lir::Negate: aMask.typeMask = (1 << lir::RegisterOperand); break; case lir::Absolute: case lir::FloatAbsolute: case lir::FloatSquareRoot: case lir::FloatNegate: case lir::Float2Float: case lir::Float2Int: case lir::Int2Float: *thunk = true; break; default: break; } } virtual void planDestination (lir::BinaryOperation op, unsigned, const OperandMask& aMask UNUSED, unsigned, OperandMask& bMask) { bMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); bMask.registerMask = ~static_cast(0); switch (op) { case lir::Negate: bMask.typeMask = (1 << lir::RegisterOperand); break; default: break; } } virtual void planMove (unsigned, OperandMask& srcMask, OperandMask& tmpMask, const OperandMask& dstMask) { srcMask.typeMask = ~0; srcMask.registerMask = ~static_cast(0); tmpMask.typeMask = 0; tmpMask.registerMask = 0; if (dstMask.typeMask & (1 << lir::MemoryOperand)) { // can't move directly from memory or constant to memory srcMask.typeMask = 1 << lir::RegisterOperand; tmpMask.typeMask = 1 << lir::RegisterOperand; tmpMask.registerMask = ~static_cast(0); } } virtual void planSource (lir::TernaryOperation op, unsigned aSize, OperandMask& aMask, unsigned, OperandMask& bMask, unsigned, bool* thunk) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::ConstantOperand); aMask.registerMask = ~static_cast(0); bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = ~static_cast(0); *thunk = false; switch (op) { case lir::Add: case lir::Subtract: if (aSize == 8) { aMask.typeMask = bMask.typeMask = (1 << lir::RegisterOperand); } break; case lir::Multiply: aMask.typeMask = bMask.typeMask = (1 << lir::RegisterOperand); break; case lir::Divide: case lir::Remainder: // todo: we shouldn't need to defer to thunks for integers which // are smaller than or equal to tne native word size, but // PowerPC doesn't generate traps for divide by zero, so we'd // need to do the checks ourselves. Using an inline check // should be faster than calling an out-of-line thunk, but the // thunk is easier, so they's what we do for now. if (true) {//if (TargetBytesPerWord == 4 and aSize == 8) { *thunk = true; } else { aMask.typeMask = (1 << lir::RegisterOperand); } break; case lir::FloatAdd: case lir::FloatSubtract: case lir::FloatMultiply: case lir::FloatDivide: case lir::FloatRemainder: case lir::JumpIfFloatEqual: case lir::JumpIfFloatNotEqual: case lir::JumpIfFloatLess: case lir::JumpIfFloatGreater: case lir::JumpIfFloatLessOrEqual: case lir::JumpIfFloatGreaterOrEqual: case lir::JumpIfFloatLessOrUnordered: case lir::JumpIfFloatGreaterOrUnordered: case lir::JumpIfFloatLessOrEqualOrUnordered: case lir::JumpIfFloatGreaterOrEqualOrUnordered: *thunk = true; break; default: break; } } virtual void planDestination (lir::TernaryOperation op, unsigned, const OperandMask& aMask UNUSED, unsigned, const OperandMask& bMask UNUSED, unsigned, OperandMask& cMask) { if (isBranch(op)) { cMask.typeMask = (1 << lir::ConstantOperand); cMask.registerMask = 0; } else { cMask.typeMask = (1 << lir::RegisterOperand); cMask.registerMask = ~static_cast(0); } } virtual Assembler* makeAssembler(util::Allocator* allocator, Zone* zone); virtual void acquire() { ++ referenceCount; } virtual void release() { if (-- referenceCount == 0) { c.s->free(this); } } ArchitectureContext c; unsigned referenceCount; }; class MyAssembler: public Assembler { public: MyAssembler(System* s, util::Allocator* a, Zone* zone, MyArchitecture* arch) : c(s, a, zone), arch_(arch) { } virtual void setClient(Client* client) { assert(&c, c.client == 0); c.client = client; } virtual Architecture* arch() { return arch_; } virtual void checkStackOverflow(uintptr_t handler, unsigned stackLimitOffsetFromThread) { lir::Register stack(StackRegister); lir::Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread); lir::Constant handlerConstant (new(c.zone) ResolvedPromise(handler)); branchRM(&c, lir::JumpIfGreaterOrEqual, TargetBytesPerWord, &stack, &stackLimit, &handlerConstant); } virtual void saveFrame(unsigned stackOffset, unsigned) { lir::Register returnAddress(0); emit(&c, mflr(returnAddress.low)); lir::Memory returnAddressDst (StackRegister, ReturnAddressOffset * TargetBytesPerWord); moveRM(&c, TargetBytesPerWord, &returnAddress, TargetBytesPerWord, &returnAddressDst); lir::Register stack(StackRegister); lir::Memory stackDst(ThreadRegister, stackOffset); moveRM(&c, TargetBytesPerWord, &stack, TargetBytesPerWord, &stackDst); } virtual void pushFrame(unsigned argumentCount, ...) { struct { unsigned size; lir::OperandType type; lir::Operand* operand; } arguments[argumentCount]; va_list a; va_start(a, argumentCount); unsigned footprint = 0; for (unsigned i = 0; i < argumentCount; ++i) { arguments[i].size = va_arg(a, unsigned); arguments[i].type = static_cast(va_arg(a, int)); arguments[i].operand = va_arg(a, lir::Operand*); footprint += ceilingDivide(arguments[i].size, TargetBytesPerWord); } va_end(a); allocateFrame(arch_->alignFrameSize(footprint)); unsigned offset = 0; for (unsigned i = 0; i < argumentCount; ++i) { if (i < arch_->argumentRegisterCount()) { lir::Register dst(arch_->argumentRegister(i)); apply(lir::Move, OperandInfo(arguments[i].size, arguments[i].type, arguments[i].operand), OperandInfo(pad(arguments[i].size, TargetBytesPerWord), lir::RegisterOperand, &dst)); offset += ceilingDivide(arguments[i].size, TargetBytesPerWord); } else { lir::Memory dst (ThreadRegister, (offset + FrameFooterSize) * TargetBytesPerWord); apply(lir::Move, OperandInfo(arguments[i].size, arguments[i].type, arguments[i].operand), OperandInfo(pad(arguments[i].size, TargetBytesPerWord), lir::MemoryOperand, &dst)); offset += ceilingDivide(arguments[i].size, TargetBytesPerWord); } } } virtual void allocateFrame(unsigned footprint) { lir::Register returnAddress(0); emit(&c, mflr(returnAddress.low)); lir::Memory returnAddressDst (StackRegister, ReturnAddressOffset * TargetBytesPerWord); moveRM(&c, TargetBytesPerWord, &returnAddress, TargetBytesPerWord, &returnAddressDst); lir::Register stack(StackRegister); lir::Memory stackDst(StackRegister, -footprint * TargetBytesPerWord); moveAndUpdateRM (&c, TargetBytesPerWord, &stack, TargetBytesPerWord, &stackDst); } virtual void adjustFrame(unsigned difference) { lir::Register nextStack(0); lir::Memory stackSrc(StackRegister, 0); moveMR(&c, TargetBytesPerWord, &stackSrc, TargetBytesPerWord, &nextStack); lir::Memory stackDst(StackRegister, -difference * TargetBytesPerWord); moveAndUpdateRM (&c, TargetBytesPerWord, &nextStack, TargetBytesPerWord, &stackDst); } virtual void popFrame(unsigned) { lir::Register stack(StackRegister); lir::Memory stackSrc(StackRegister, 0); moveMR(&c, TargetBytesPerWord, &stackSrc, TargetBytesPerWord, &stack); lir::Register returnAddress(0); lir::Memory returnAddressSrc (StackRegister, ReturnAddressOffset * TargetBytesPerWord); moveMR(&c, TargetBytesPerWord, &returnAddressSrc, TargetBytesPerWord, &returnAddress); emit(&c, mtlr(returnAddress.low)); } virtual void popFrameForTailCall(unsigned footprint, int offset, int returnAddressSurrogate, int framePointerSurrogate) { if (TailCalls) { if (offset) { lir::Register tmp(0); lir::Memory returnAddressSrc (StackRegister, (ReturnAddressOffset + footprint) * TargetBytesPerWord); moveMR(&c, TargetBytesPerWord, &returnAddressSrc, TargetBytesPerWord, &tmp); emit(&c, mtlr(tmp.low)); lir::Memory stackSrc(StackRegister, footprint * TargetBytesPerWord); moveMR(&c, TargetBytesPerWord, &stackSrc, TargetBytesPerWord, &tmp); lir::Memory stackDst (StackRegister, (footprint - offset) * TargetBytesPerWord); moveAndUpdateRM (&c, TargetBytesPerWord, &tmp, TargetBytesPerWord, &stackDst); if (returnAddressSurrogate != lir::NoRegister) { assert(&c, offset > 0); lir::Register ras(returnAddressSurrogate); lir::Memory dst (StackRegister, (ReturnAddressOffset + offset) * TargetBytesPerWord); moveRM(&c, TargetBytesPerWord, &ras, TargetBytesPerWord, &dst); } if (framePointerSurrogate != lir::NoRegister) { assert(&c, offset > 0); lir::Register fps(framePointerSurrogate); lir::Memory dst(StackRegister, offset * TargetBytesPerWord); moveRM(&c, TargetBytesPerWord, &fps, TargetBytesPerWord, &dst); } } else { popFrame(footprint); } } else { abort(&c); } } virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, unsigned argumentFootprint) { popFrame(frameFootprint); assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); if (TailCalls and argumentFootprint > StackAlignmentInWords) { lir::Register tmp(0); lir::Memory stackSrc(StackRegister, 0); moveMR(&c, TargetBytesPerWord, &stackSrc, TargetBytesPerWord, &tmp); lir::Memory stackDst(StackRegister, (argumentFootprint - StackAlignmentInWords) * TargetBytesPerWord); moveAndUpdateRM (&c, TargetBytesPerWord, &tmp, TargetBytesPerWord, &stackDst); } return_(&c); } virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, unsigned stackOffsetFromThread) { popFrame(frameFootprint); lir::Register tmp1(0); lir::Memory stackSrc(StackRegister, 0); moveMR(&c, TargetBytesPerWord, &stackSrc, TargetBytesPerWord, &tmp1); lir::Register tmp2(5); lir::Memory newStackSrc(ThreadRegister, stackOffsetFromThread); moveMR(&c, TargetBytesPerWord, &newStackSrc, TargetBytesPerWord, &tmp2); lir::Register stack(StackRegister); subR(&c, TargetBytesPerWord, &stack, &tmp2, &tmp2); lir::Memory stackDst(StackRegister, 0, tmp2.low); moveAndUpdateRM (&c, TargetBytesPerWord, &tmp1, TargetBytesPerWord, &stackDst); return_(&c); } virtual void apply(lir::Operation op) { arch_->c.operations[op](&c); } virtual void apply(lir::UnaryOperation op, OperandInfo a) { arch_->c.unaryOperations[Multimethod::index(op, a.type)] (&c, a.size, a.operand); } virtual void apply(lir::BinaryOperation op, OperandInfo a, OperandInfo b) { arch_->c.binaryOperations[index(&(arch_->c), op, a.type, b.type)] (&c, a.size, a.operand, b.size, b.operand); } virtual void apply(lir::TernaryOperation op, OperandInfo a, OperandInfo b, OperandInfo c) { if (isBranch(op)) { assert(&this->c, a.size == b.size); assert(&this->c, c.size == TargetBytesPerWord); assert(&this->c, c.type == lir::ConstantOperand); arch_->c.branchOperations[branchIndex(&(arch_->c), a.type, b.type)] (&this->c, op, a.size, a.operand, b.operand, c.operand); } else { assert(&this->c, b.size == c.size); assert(&this->c, b.type == lir::RegisterOperand); assert(&this->c, c.type == lir::RegisterOperand); arch_->c.ternaryOperations[index(&(arch_->c), op, a.type)] (&this->c, b.size, a.operand, b.operand, c.operand); } } virtual void setDestination(uint8_t* dst) { c.result = dst; } virtual void write() { uint8_t* dst = c.result; unsigned dstOffset = 0; for (MyBlock* b = c.firstBlock; b; b = b->next) { if (DebugJumps) { fprintf(stderr, "write block %p\n", b); } unsigned blockOffset = 0; for (JumpEvent* e = b->jumpEventHead; e; e = e->next) { unsigned size = e->offset - blockOffset; memcpy(dst + dstOffset, c.code.data.begin() + b->offset + blockOffset, size); blockOffset = e->offset; dstOffset += size; unsigned jumpTableSize = 0; for (JumpOffset* o = e->jumpOffsetHead; o; o = o->next) { if (DebugJumps) { fprintf(stderr, "visit offset %p %d in block %p\n", o, o->offset, b); } uint8_t* address = dst + dstOffset + jumpTableSize; if (needJump(b)) { address += TargetBytesPerWord; } o->task->jumpAddress = address; jumpTableSize += TargetBytesPerWord; } assert(&c, jumpTableSize); bool jump = needJump(b); if (jump) { write4(dst + dstOffset, isa::b(jumpTableSize + TargetBytesPerWord)); } dstOffset += jumpTableSize + (jump ? TargetBytesPerWord : 0); } unsigned size = b->size - blockOffset; memcpy( dst + dstOffset, c.code.data.begin() + b->offset + blockOffset, size); dstOffset += size; } unsigned index = dstOffset; assert(&c, index % TargetBytesPerWord == 0); for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { e->address = dst + index; index += TargetBytesPerWord; } for (Task* t = c.tasks; t; t = t->next) { t->run(&c); } for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { *static_cast(e->address) = e->constant->value(); // fprintf(stderr, "constant %p at %p\n", reinterpret_cast(e->constant->value()), e->address); } } virtual Promise* offset(bool) { return powerpc::offsetPromise(&c); } virtual Block* endBlock(bool startNew) { MyBlock* b = c.lastBlock; b->size = c.code.length() - b->offset; if (startNew) { c.lastBlock = new(c.zone) MyBlock(&c, c.code.length()); } else { c.lastBlock = 0; } return b; } virtual void endEvent() { MyBlock* b = c.lastBlock; unsigned thisEventOffset = c.code.length() - b->offset; if (b->jumpOffsetHead) { int32_t v = (thisEventOffset + TargetBytesPerWord) - b->jumpOffsetHead->offset; if (v > 0 and not bounded(2, 16, v)) { appendJumpEvent (&c, b, b->lastEventOffset, b->jumpOffsetHead, b->lastJumpOffsetTail); if (DebugJumps) { for (JumpOffset* o = b->jumpOffsetHead; o != b->lastJumpOffsetTail->next; o = o->next) { fprintf(stderr, "in endEvent, include %p %d in jump event %p " "at offset %d in block %p\n", o, o->offset, b->jumpEventTail, b->lastEventOffset, b); } } b->jumpOffsetHead = b->lastJumpOffsetTail->next; b->lastJumpOffsetTail->next = 0; if (b->jumpOffsetHead == 0) { b->jumpOffsetTail = 0; } } } b->lastEventOffset = thisEventOffset; b->lastJumpOffsetTail = b->jumpOffsetTail; } virtual unsigned length() { return c.code.length(); } virtual unsigned footerSize() { return c.constantPoolCount * TargetBytesPerWord; } virtual void dispose() { c.code.dispose(); } Context c; MyArchitecture* arch_; }; Assembler* MyArchitecture::makeAssembler(util::Allocator* allocator, Zone* zone) { return new(zone) MyAssembler(this->c.s, allocator, zone, this); } } // namespace powerpc Architecture* makeArchitecturePowerpc(System* system, bool) { return new (allocate(system, sizeof(powerpc::MyArchitecture))) powerpc::MyArchitecture(system); } } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/block.cpp000066400000000000000000000021211231440243200241120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "context.h" #include "block.h" #include "avian/common.h" namespace avian { namespace codegen { namespace powerpc { void resolve(MyBlock*); unsigned padding(MyBlock*, unsigned); MyBlock::MyBlock(Context* context, unsigned offset): context(context), next(0), jumpOffsetHead(0), jumpOffsetTail(0), lastJumpOffsetTail(0), jumpEventHead(0), jumpEventTail(0), lastEventOffset(0), offset(offset), start(~0), size(0), resolved(false) { } unsigned MyBlock::resolve(unsigned start, Assembler::Block* next) { this->start = start; this->next = static_cast(next); powerpc::resolve(this); this->resolved = true; return start + size + padding(this, size); } } // namespace powerpc } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/block.h000066400000000000000000000021131231440243200235600ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_POWERPC_BLOCK_H #define AVIAN_CODEGEN_ASSEMBLER_POWERPC_BLOCK_H namespace avian { namespace codegen { namespace powerpc { class JumpEvent; class MyBlock: public Assembler::Block { public: MyBlock(Context* context, unsigned offset); virtual unsigned resolve(unsigned start, Assembler::Block* next); Context* context; MyBlock* next; JumpOffset* jumpOffsetHead; JumpOffset* jumpOffsetTail; JumpOffset* lastJumpOffsetTail; JumpEvent* jumpEventHead; JumpEvent* jumpEventTail; unsigned lastEventOffset; unsigned offset; unsigned start; unsigned size; bool resolved; }; } // namespace powerpc } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_POWERPC_BLOCK_H ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/context.cpp000066400000000000000000000016011231440243200245060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "context.h" #include "block.h" #include "avian/common.h" namespace avian { namespace codegen { namespace powerpc { Context::Context(vm::System* s, util::Allocator* a, vm::Zone* zone) : s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), firstBlock(new (zone) MyBlock(this, 0)), lastBlock(firstBlock), jumpOffsetHead(0), jumpOffsetTail(0), constantPool(0), constantPoolCount(0) { } } // namespace powerpc } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/context.h000066400000000000000000000047311231440243200241620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_POWERPC_CONTEXT_H #define AVIAN_CODEGEN_ASSEMBLER_POWERPC_CONTEXT_H #include #include "avian/alloc-vector.h" #ifdef powerpc #undef powerpc #endif namespace vm { class System; class Zone; } // namespace vm namespace avian { namespace util { class Allocator; } namespace codegen { namespace powerpc { class Task; class JumpOffset; class ConstantPoolEntry; class MyBlock; class Context { public: Context(vm::System* s, util::Allocator* a, vm::Zone* zone); vm::System* s; vm::Zone* zone; Assembler::Client* client; vm::Vector code; Task* tasks; uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; JumpOffset* jumpOffsetHead; JumpOffset* jumpOffsetTail; ConstantPoolEntry* constantPool; unsigned constantPoolCount; }; typedef void (*OperationType)(Context*); typedef void (*UnaryOperationType)(Context*, unsigned, lir::Operand*); typedef void (*BinaryOperationType) (Context*, unsigned, lir::Operand*, unsigned, lir::Operand*); typedef void (*TernaryOperationType) (Context*, unsigned, lir::Operand*, lir::Operand*, lir::Operand*); typedef void (*BranchOperationType) (Context*, lir::TernaryOperation, unsigned, lir::Operand*, lir::Operand*, lir::Operand*); class ArchitectureContext { public: ArchitectureContext(vm::System* s): s(s) { } vm::System* s; OperationType operations[lir::OperationCount]; UnaryOperationType unaryOperations[lir::UnaryOperationCount * lir::OperandTypeCount]; BinaryOperationType binaryOperations [lir::BinaryOperationCount * lir::OperandTypeCount * lir::OperandTypeCount]; TernaryOperationType ternaryOperations [lir::NonBranchTernaryOperationCount * lir::OperandTypeCount]; BranchOperationType branchOperations [lir::BranchOperationCount * lir::OperandTypeCount * lir::OperandTypeCount]; }; inline avian::util::Aborter* getAborter(Context* con) { return con->s; } inline avian::util::Aborter* getAborter(ArchitectureContext* con) { return con->s; } } // namespace powerpc } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_POWERPC_CONTEXT_H ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/encode.h000066400000000000000000000212761231440243200237360ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_POWERPC_ENCODE_H #define AVIAN_CODEGEN_ASSEMBLER_POWERPC_ENCODE_H #ifdef powerpc #undef powerpc #endif namespace avian { namespace codegen { namespace powerpc { namespace isa { // INSTRUCTION FORMATS inline int D(int op, int rt, int ra, int d) { return op<<26|rt<<21|ra<<16|(d & 0xFFFF); } // inline int DS(int op, int rt, int ra, int ds, int xo) { return op<<26|rt<<21|ra<<16|ds<<2|xo; } inline int I(int op, int li, int aa, int lk) { return op<<26|(li & 0x3FFFFFC)|aa<<1|lk; } inline int B(int op, int bo, int bi, int bd, int aa, int lk) { return op<<26|bo<<21|bi<<16|(bd & 0xFFFC)|aa<<1|lk; } // inline int SC(int op, int lev) { return op<<26|lev<<5|2; } inline int X(int op, int rt, int ra, int rb, int xo, int rc) { return op<<26|rt<<21|ra<<16|rb<<11|xo<<1|rc; } inline int XL(int op, int bt, int ba, int bb, int xo, int lk) { return op<<26|bt<<21|ba<<16|bb<<11|xo<<1|lk; } inline int XFX(int op, int rt, int spr, int xo) { return op<<26|rt<<21|((spr >> 5) | ((spr << 5) & 0x3E0))<<11|xo<<1; } // inline int XFL(int op, int flm, int frb, int xo, int rc) { return op<<26|flm<<17|frb<<11|xo<<1|rc; } // inline int XS(int op, int rs, int ra, int sh, int xo, int sh2, int rc) { return op<<26|rs<<21|ra<<16|sh<<11|xo<<2|sh2<<1|rc; } inline int XO(int op, int rt, int ra, int rb, int oe, int xo, int rc) { return op<<26|rt<<21|ra<<16|rb<<11|oe<<10|xo<<1|rc; } // inline int A(int op, int frt, int fra, int frb, int frc, int xo, int rc) { return op<<26|frt<<21|fra<<16|frb<<11|frc<<6|xo<<1|rc; } inline int M(int op, int rs, int ra, int rb, int mb, int me, int rc) { return op<<26|rs<<21|ra<<16|rb<<11|mb<<6|me<<1|rc; } // inline int MD(int op, int rs, int ra, int sh, int mb, int xo, int sh2, int rc) { return op<<26|rs<<21|ra<<16|sh<<11|mb<<5|xo<<2|sh2<<1|rc; } // inline int MDS(int op, int rs, int ra, int rb, int mb, int xo, int rc) { return op<<26|rs<<21|ra<<16|rb<<11|mb<<5|xo<<1|rc; } // INSTRUCTIONS inline int lbz(int rt, int ra, int i) { return D(34, rt, ra, i); } inline int lbzx(int rt, int ra, int rb) { return X(31, rt, ra, rb, 87, 0); } inline int lha(int rt, int ra, int i) { return D(42, rt, ra, i); } inline int lhax(int rt, int ra, int rb) { return X(31, rt, ra, rb, 343, 0); } // inline int lhz(int rt, int ra, int i) { return D(40, rt, ra, i); } inline int lhzx(int rt, int ra, int rb) { return X(31, rt, ra, rb, 279, 0); } inline int lwz(int rt, int ra, int i) { return D(32, rt, ra, i); } inline int lwzx(int rt, int ra, int rb) { return X(31, rt, ra, rb, 23, 0); } inline int stb(int rs, int ra, int i) { return D(38, rs, ra, i); } inline int stbx(int rs, int ra, int rb) { return X(31, rs, ra, rb, 215, 0); } inline int sth(int rs, int ra, int i) { return D(44, rs, ra, i); } inline int sthx(int rs, int ra, int rb) { return X(31, rs, ra, rb, 407, 0); } inline int stw(int rs, int ra, int i) { return D(36, rs, ra, i); } inline int stwu(int rs, int ra, int i) { return D(37, rs, ra, i); } inline int stwux(int rs, int ra, int rb) { return X(31, rs, ra, rb, 183, 0); } inline int stwx(int rs, int ra, int rb) { return X(31, rs, ra, rb, 151, 0); } inline int add(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 266, 0); } inline int addc(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 10, 0); } inline int adde(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 138, 0); } inline int addi(int rt, int ra, int i) { return D(14, rt, ra, i); } inline int addic(int rt, int ra, int i) { return D(12, rt, ra, i); } inline int addis(int rt, int ra, int i) { return D(15, rt, ra, i); } inline int subf(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 40, 0); } inline int subfc(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 8, 0); } inline int subfe(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 136, 0); } inline int subfic(int rt, int ra, int i) { return D(8, rt, ra, i); } inline int subfze(int rt, int ra) { return XO(31, rt, ra, 0, 0, 200, 0); } inline int mullw(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 235, 0); } // inline int mulhw(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 75, 0); } inline int mulhwu(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 11, 0); } // inline int mulli(int rt, int ra, int i) { return D(7, rt, ra, i); } inline int divw(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 491, 0); } // inline int divwu(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 459, 0); } // inline int divd(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 489, 0); } // inline int divdu(int rt, int ra, int rb) { return XO(31, rt, ra, rb, 0, 457, 0); } inline int neg(int rt, int ra) { return XO(31, rt, ra, 0, 0, 104, 0); } inline int and_(int rt, int ra, int rb) { return X(31, ra, rt, rb, 28, 0); } inline int andi(int rt, int ra, int i) { return D(28, ra, rt, i); } inline int andis(int rt, int ra, int i) { return D(29, ra, rt, i); } inline int or_(int rt, int ra, int rb) { return X(31, ra, rt, rb, 444, 0); } inline int ori(int rt, int ra, int i) { return D(24, rt, ra, i); } inline int xor_(int rt, int ra, int rb) { return X(31, ra, rt, rb, 316, 0); } inline int oris(int rt, int ra, int i) { return D(25, rt, ra, i); } inline int xori(int rt, int ra, int i) { return D(26, rt, ra, i); } inline int xoris(int rt, int ra, int i) { return D(27, rt, ra, i); } inline int rlwinm(int rt, int ra, int i, int mb, int me) { return M(21, ra, rt, i, mb, me, 0); } inline int rlwimi(int rt, int ra, int i, int mb, int me) { return M(20, ra, rt, i, mb, me, 0); } inline int slw(int rt, int ra, int sh) { return X(31, ra, rt, sh, 24, 0); } // inline int sld(int rt, int ra, int rb) { return X(31, ra, rt, rb, 27, 0); } inline int srw(int rt, int ra, int sh) { return X(31, ra, rt, sh, 536, 0); } inline int sraw(int rt, int ra, int sh) { return X(31, ra, rt, sh, 792, 0); } inline int srawi(int rt, int ra, int sh) { return X(31, ra, rt, sh, 824, 0); } inline int extsb(int rt, int rs) { return X(31, rs, rt, 0, 954, 0); } inline int extsh(int rt, int rs) { return X(31, rs, rt, 0, 922, 0); } inline int mfspr(int rt, int spr) { return XFX(31, rt, spr, 339); } inline int mtspr(int spr, int rs) { return XFX(31, rs, spr, 467); } inline int b(int i) { return I(18, i, 0, 0); } inline int bl(int i) { return I(18, i, 0, 1); } inline int bcctr(int bo, int bi, int lk) { return XL(19, bo, bi, 0, 528, lk); } inline int bclr(int bo, int bi, int lk) { return XL(19, bo, bi, 0, 16, lk); } inline int bc(int bo, int bi, int bd, int lk) { return B(16, bo, bi, bd, 0, lk); } inline int cmp(int bf, int ra, int rb) { return X(31, bf << 2, ra, rb, 0, 0); } inline int cmpl(int bf, int ra, int rb) { return X(31, bf << 2, ra, rb, 32, 0); } inline int cmpi(int bf, int ra, int i) { return D(11, bf << 2, ra, i); } inline int cmpli(int bf, int ra, int i) { return D(10, bf << 2, ra, i); } inline int sync(int L) { return X(31, L, 0, 0, 598, 0); } // PSEUDO-INSTRUCTIONS inline int li(int rt, int i) { return addi(rt, 0, i); } inline int lis(int rt, int i) { return addis(rt, 0, i); } inline int slwi(int rt, int ra, int i) { return rlwinm(rt, ra, i, 0, 31-i); } inline int srwi(int rt, int ra, int i) { return rlwinm(rt, ra, 32-i, i, 31); } // inline int sub(int rt, int ra, int rb) { return subf(rt, rb, ra); } // inline int subc(int rt, int ra, int rb) { return subfc(rt, rb, ra); } // inline int subi(int rt, int ra, int i) { return addi(rt, ra, -i); } // inline int subis(int rt, int ra, int i) { return addis(rt, ra, -i); } inline int mr(int rt, int ra) { return or_(rt, ra, ra); } inline int mflr(int rx) { return mfspr(rx, 8); } inline int mtlr(int rx) { return mtspr(8, rx); } inline int mtctr(int rd) { return mtspr(9, rd); } inline int bctr() { return bcctr(20, 0, 0); } inline int bctrl() { return bcctr(20, 0, 1); } inline int blr() { return bclr(20, 0, 0); } inline int blt(int i) { return bc(12, 0, i, 0); } inline int bgt(int i) { return bc(12, 1, i, 0); } inline int bge(int i) { return bc(4, 0, i, 0); } inline int ble(int i) { return bc(4, 1, i, 0); } inline int beq(int i) { return bc(12, 2, i, 0); } inline int bne(int i) { return bc(4, 2, i, 0); } inline int cmpw(int ra, int rb) { return cmp(0, ra, rb); } inline int cmplw(int ra, int rb) { return cmpl(0, ra, rb); } inline int cmpwi(int ra, int i) { return cmpi(0, ra, i); } inline int cmplwi(int ra, int i) { return cmpli(0, ra, i); } inline int trap() { return 0x7fe00008; } // todo: macro-ify } // namespace isa } // namespace powerpc } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_POWERPC_ENCODE_H ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/fixup.cpp000066400000000000000000000146211231440243200241630ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "context.h" #include "block.h" #include "fixup.h" #include "encode.h" namespace avian { namespace codegen { namespace powerpc { using namespace isa; using namespace util; unsigned padding(MyBlock*, unsigned); int ha16(int32_t i); bool bounded(int right, int left, int32_t v) { return ((v << left) >> left) == v and ((v >> right) << right) == v; } OffsetPromise::OffsetPromise(Context* c, MyBlock* block, unsigned offset): c(c), block(block), offset(offset) { } bool OffsetPromise::resolved() { return block->resolved; } int64_t OffsetPromise::value() { assert(c, resolved()); unsigned o = offset - block->offset; return block->start + padding(block, o) + o; } Promise* offsetPromise(Context* c) { return new(c->zone) OffsetPromise(c, c->lastBlock, c->code.length()); } void* updateOffset(vm::System* s, uint8_t* instruction, bool conditional, int64_t value, void* jumpAddress) { int32_t v = reinterpret_cast(value) - instruction; int32_t mask; if (conditional) { if (not bounded(2, 16, v)) { *static_cast(jumpAddress) = isa::b(0); updateOffset(s, static_cast(jumpAddress), false, value, 0); v = static_cast(jumpAddress) - instruction; expect(s, bounded(2, 16, v)); } mask = 0xFFFC; } else { expect(s, bounded(2, 6, v)); mask = 0x3FFFFFC; } int32_t* p = reinterpret_cast(instruction); *p = vm::targetV4((v & mask) | ((~mask) & vm::targetV4(*p))); return instruction + 4; } OffsetListener::OffsetListener(vm::System* s, uint8_t* instruction, bool conditional, void* jumpAddress): s(s), instruction(instruction), jumpAddress(jumpAddress), conditional(conditional) { } bool OffsetListener::resolve(int64_t value, void** location) { void* p = updateOffset(s, instruction, conditional, value, jumpAddress); if (location) *location = p; return false; } OffsetTask::OffsetTask(Task* next, Promise* promise, Promise* instructionOffset, bool conditional): Task(next), promise(promise), instructionOffset(instructionOffset), jumpAddress(0), conditional(conditional) { } void OffsetTask::run(Context* c) { if (promise->resolved()) { updateOffset (c->s, c->result + instructionOffset->value(), conditional, promise->value(), jumpAddress); } else { new (promise->listen(sizeof(OffsetListener))) OffsetListener(c->s, c->result + instructionOffset->value(), conditional, jumpAddress); } } JumpOffset::JumpOffset(MyBlock* block, OffsetTask* task, unsigned offset): block(block), task(task), next(0), offset(offset) { } JumpEvent::JumpEvent(JumpOffset* jumpOffsetHead, JumpOffset* jumpOffsetTail, unsigned offset): jumpOffsetHead(jumpOffsetHead), jumpOffsetTail(jumpOffsetTail), next(0), offset(offset) { } void appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, bool conditional) { OffsetTask* task = new(c->zone) OffsetTask(c->tasks, promise, instructionOffset, conditional); c->tasks = task; if (conditional) { JumpOffset* offset = new(c->zone) JumpOffset(c->lastBlock, task, c->code.length() - c->lastBlock->offset); if (c->lastBlock->jumpOffsetTail) { c->lastBlock->jumpOffsetTail->next = offset; } else { c->lastBlock->jumpOffsetHead = offset; } c->lastBlock->jumpOffsetTail = offset; } } void appendJumpEvent(Context* c, MyBlock* b, unsigned offset, JumpOffset* head, JumpOffset* tail) { JumpEvent* e = new(c->zone) JumpEvent (head, tail, offset); if (b->jumpEventTail) { b->jumpEventTail->next = e; } else { b->jumpEventHead = e; } b->jumpEventTail = e; } ShiftMaskPromise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) { return new (c->zone) ShiftMaskPromise(base, shift, mask); } void updateImmediate(vm::System* s, void* dst, int32_t src, unsigned size, bool address) { switch (size) { case 4: { int32_t* p = static_cast(dst); int r = (vm::targetV4(p[1]) >> 21) & 31; if (address) { p[0] = vm::targetV4(lis(r, ha16(src))); p[1] |= vm::targetV4(src & 0xFFFF); } else { p[0] = vm::targetV4(lis(r, src >> 16)); p[1] = vm::targetV4(ori(r, r, src)); } } break; default: abort(s); } } ImmediateListener::ImmediateListener(vm::System* s, void* dst, unsigned size, unsigned offset, bool address): s(s), dst(dst), size(size), offset(offset), address(address) { } bool ImmediateListener::resolve(int64_t value, void** location) { updateImmediate(s, dst, value, size, address); if (location) *location = static_cast(dst) + offset; return false; } ImmediateTask::ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset, bool address): Task(next), promise(promise), offset(offset), size(size), promiseOffset(promiseOffset), address(address) { } void ImmediateTask::run(Context* c) { if (promise->resolved()) { updateImmediate (c->s, c->result + offset->value(), promise->value(), size, address); } else { new (promise->listen(sizeof(ImmediateListener))) ImmediateListener (c->s, c->result + offset->value(), size, promiseOffset, address); } } void appendImmediateTask(Context* c, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset, bool address) { c->tasks = new(c->zone) ImmediateTask(c->tasks, promise, offset, size, promiseOffset, address); } ConstantPoolEntry::ConstantPoolEntry(Context* c, Promise* constant): c(c), constant(constant), next(c->constantPool), address(0) { c->constantPool = this; ++ c->constantPoolCount; } int64_t ConstantPoolEntry::value() { assert(c, resolved()); return reinterpret_cast(address); } bool ConstantPoolEntry::resolved() { return address != 0; } ConstantPoolEntry* appendConstantPoolEntry(Context* c, Promise* constant) { return new (c->zone) ConstantPoolEntry(c, constant); } } // namespace powerpc } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/fixup.h000066400000000000000000000072051231440243200236300ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_POWERPC_FIXUP_H #define AVIAN_CODEGEN_ASSEMBLER_POWERPC_FIXUP_H namespace avian { namespace codegen { namespace powerpc { class Task { public: Task(Task* next): next(next) { } virtual void run(Context* c) = 0; Task* next; }; class OffsetPromise: public Promise { public: OffsetPromise(Context* c, MyBlock* block, unsigned offset); virtual bool resolved(); virtual int64_t value(); Context* c; MyBlock* block; unsigned offset; }; Promise* offsetPromise(Context* c); void* updateOffset(vm::System* s, uint8_t* instruction, bool conditional, int64_t value, void* jumpAddress); class OffsetListener: public Promise::Listener { public: OffsetListener(vm::System* s, uint8_t* instruction, bool conditional, void* jumpAddress); virtual bool resolve(int64_t value, void** location); vm::System* s; uint8_t* instruction; void* jumpAddress; bool conditional; }; class OffsetTask: public Task { public: OffsetTask(Task* next, Promise* promise, Promise* instructionOffset, bool conditional); virtual void run(Context* c); Promise* promise; Promise* instructionOffset; void* jumpAddress; bool conditional; }; class JumpOffset { public: JumpOffset(MyBlock* block, OffsetTask* task, unsigned offset); MyBlock* block; OffsetTask* task; JumpOffset* next; unsigned offset; }; class JumpEvent { public: JumpEvent(JumpOffset* jumpOffsetHead, JumpOffset* jumpOffsetTail, unsigned offset); JumpOffset* jumpOffsetHead; JumpOffset* jumpOffsetTail; JumpEvent* next; unsigned offset; }; void appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, bool conditional); void appendJumpEvent(Context* c, MyBlock* b, unsigned offset, JumpOffset* head, JumpOffset* tail); ShiftMaskPromise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask); void updateImmediate(vm::System* s, void* dst, int32_t src, unsigned size, bool address); class ImmediateListener: public Promise::Listener { public: ImmediateListener(vm::System* s, void* dst, unsigned size, unsigned offset, bool address); virtual bool resolve(int64_t value, void** location); vm::System* s; void* dst; unsigned size; unsigned offset; bool address; }; class ImmediateTask: public Task { public: ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset, bool address); virtual void run(Context* c); Promise* promise; Promise* offset; unsigned size; unsigned promiseOffset; bool address; }; void appendImmediateTask(Context* c, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset, bool address); class ConstantPoolEntry: public Promise { public: ConstantPoolEntry(Context* c, Promise* constant); virtual int64_t value(); virtual bool resolved(); Context* c; Promise* constant; ConstantPoolEntry* next; void* address; }; ConstantPoolEntry* appendConstantPoolEntry(Context* c, Promise* constant); inline int ha16(int32_t i) { return ((i >> 16) + ((i & 0x8000) ? 1 : 0)) & 0xffff; } } // namespace powerpc } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_POWERPC_FIXUP_H ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/multimethod.cpp000066400000000000000000000105441231440243200253630ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "context.h" #include "block.h" #include "avian/common.h" #include "operations.h" #include "multimethod.h" #include "../multimethod.h" namespace avian { namespace codegen { namespace powerpc { using namespace util; unsigned index(ArchitectureContext*, lir::BinaryOperation operation, lir::OperandType operand1, lir::OperandType operand2) { return operation + (lir::BinaryOperationCount * operand1) + (lir::BinaryOperationCount * lir::OperandTypeCount * operand2); } unsigned index(ArchitectureContext* c UNUSED, lir::TernaryOperation operation, lir::OperandType operand1) { assert(c, not isBranch(operation)); return operation + (lir::NonBranchTernaryOperationCount * operand1); } unsigned branchIndex(ArchitectureContext* c UNUSED, lir::OperandType operand1, lir::OperandType operand2) { return operand1 + (lir::OperandTypeCount * operand2); } void populateTables(ArchitectureContext* c) { const lir::OperandType C = lir::ConstantOperand; const lir::OperandType A = lir::AddressOperand; const lir::OperandType R = lir::RegisterOperand; const lir::OperandType M = lir::MemoryOperand; OperationType* zo = c->operations; UnaryOperationType* uo = c->unaryOperations; BinaryOperationType* bo = c->binaryOperations; TernaryOperationType* to = c->ternaryOperations; BranchOperationType* bro = c->branchOperations; zo[lir::Return] = return_; zo[lir::LoadBarrier] = memoryBarrier; zo[lir::StoreStoreBarrier] = memoryBarrier; zo[lir::StoreLoadBarrier] = memoryBarrier; zo[lir::Trap] = trap; uo[Multimethod::index(lir::LongCall, C)] = CAST1(longCallC); uo[Multimethod::index(lir::AlignedLongCall, C)] = CAST1(alignedLongCallC); uo[Multimethod::index(lir::LongJump, C)] = CAST1(longJumpC); uo[Multimethod::index(lir::AlignedLongJump, C)] = CAST1(alignedLongJumpC); uo[Multimethod::index(lir::Jump, R)] = CAST1(jumpR); uo[Multimethod::index(lir::Jump, C)] = CAST1(jumpC); uo[Multimethod::index(lir::AlignedJump, R)] = CAST1(jumpR); uo[Multimethod::index(lir::AlignedJump, C)] = CAST1(jumpC); uo[Multimethod::index(lir::Call, C)] = CAST1(callC); uo[Multimethod::index(lir::Call, R)] = CAST1(callR); uo[Multimethod::index(lir::AlignedCall, C)] = CAST1(callC); uo[Multimethod::index(lir::AlignedCall, R)] = CAST1(callR); bo[index(c, lir::Move, R, R)] = CAST2(moveRR); bo[index(c, lir::Move, C, R)] = CAST2(moveCR); bo[index(c, lir::Move, C, M)] = CAST2(moveCM); bo[index(c, lir::Move, M, R)] = CAST2(moveMR); bo[index(c, lir::Move, R, M)] = CAST2(moveRM); bo[index(c, lir::Move, A, R)] = CAST2(moveAR); bo[index(c, lir::MoveZ, R, R)] = CAST2(moveZRR); bo[index(c, lir::MoveZ, M, R)] = CAST2(moveZMR); bo[index(c, lir::MoveZ, C, R)] = CAST2(moveCR); bo[index(c, lir::Negate, R, R)] = CAST2(negateRR); to[index(c, lir::Add, R)] = CAST3(addR); to[index(c, lir::Add, C)] = CAST3(addC); to[index(c, lir::Subtract, R)] = CAST3(subR); to[index(c, lir::Subtract, C)] = CAST3(subC); to[index(c, lir::Multiply, R)] = CAST3(multiplyR); to[index(c, lir::Divide, R)] = CAST3(divideR); to[index(c, lir::Remainder, R)] = CAST3(remainderR); to[index(c, lir::ShiftLeft, R)] = CAST3(shiftLeftR); to[index(c, lir::ShiftLeft, C)] = CAST3(shiftLeftC); to[index(c, lir::ShiftRight, R)] = CAST3(shiftRightR); to[index(c, lir::ShiftRight, C)] = CAST3(shiftRightC); to[index(c, lir::UnsignedShiftRight, R)] = CAST3(unsignedShiftRightR); to[index(c, lir::UnsignedShiftRight, C)] = CAST3(unsignedShiftRightC); to[index(c, lir::And, C)] = CAST3(andC); to[index(c, lir::And, R)] = CAST3(andR); to[index(c, lir::Or, C)] = CAST3(orC); to[index(c, lir::Or, R)] = CAST3(orR); to[index(c, lir::Xor, C)] = CAST3(xorC); to[index(c, lir::Xor, R)] = CAST3(xorR); bro[branchIndex(c, R, R)] = CAST_BRANCH(branchRR); bro[branchIndex(c, C, R)] = CAST_BRANCH(branchCR); bro[branchIndex(c, C, M)] = CAST_BRANCH(branchCM); bro[branchIndex(c, R, M)] = CAST_BRANCH(branchRM); } } // namespace powerpc } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/multimethod.h000066400000000000000000000024371231440243200250320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_POWERPC_MULTIMETHOD_H #define AVIAN_CODEGEN_ASSEMBLER_POWERPC_MULTIMETHOD_H #define CAST1(x) reinterpret_cast(x) #define CAST2(x) reinterpret_cast(x) #define CAST3(x) reinterpret_cast(x) #define CAST_BRANCH(x) reinterpret_cast(x) namespace avian { namespace codegen { namespace powerpc { unsigned index(ArchitectureContext*, lir::BinaryOperation operation, lir::OperandType operand1, lir::OperandType operand2); unsigned index(ArchitectureContext* c UNUSED, lir::TernaryOperation operation, lir::OperandType operand1); unsigned branchIndex(ArchitectureContext* c UNUSED, lir::OperandType operand1, lir::OperandType operand2); void populateTables(ArchitectureContext* c); } // namespace powerpc } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_POWERPC_MULTIMETHOD_H ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/operations.cpp000066400000000000000000000724001231440243200252120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "context.h" #include "block.h" #include "avian/common.h" #include "encode.h" #include "operations.h" #include "fixup.h" #include "multimethod.h" using namespace vm; namespace avian { namespace codegen { namespace powerpc { using namespace isa; using namespace util; const int64_t MASK_LO32 = 0x0ffffffff; const int MASK_LO16 = 0x0ffff; const int MASK_LO8 = 0x0ff; // inline int lo32(int64_t i) { return (int)(i & MASK_LO32); } // inline int hi32(int64_t i) { return lo32(i >> 32); } inline int lo16(int64_t i) { return (int)(i & MASK_LO16); } inline int hi16(int64_t i) { return lo16(i >> 16); } // inline int lo8(int64_t i) { return (int)(i & MASK_LO8); } // inline int hi8(int64_t i) { return lo8(i >> 8); } inline int carry16(target_intptr_t v) { return static_cast(v) < 0 ? 1 : 0; } void andC(Context* c, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst); void shiftLeftR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if(size == 8) { lir::Register Tmp(newTemp(con), newTemp(con)); lir::Register* tmp = &Tmp; emit(con, subfic(tmp->high, a->low, 32)); emit(con, slw(t->high, b->high, a->low)); emit(con, srw(tmp->low, b->low, tmp->high)); emit(con, or_(t->high, t->high, tmp->low)); emit(con, addi(tmp->high, a->low, -32)); emit(con, slw(tmp->low, b->low, tmp->high)); emit(con, or_(t->high, t->high, tmp->low)); emit(con, slw(t->low, b->low, a->low)); freeTemp(con, tmp->high); freeTemp(con, tmp->low); } else { emit(con, slw(t->low, b->low, a->low)); } } void moveRR(Context* c, unsigned srcSize, lir::Register* src, unsigned dstSize, lir::Register* dst); void shiftLeftC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* t) { int sh = getValue(a); if (size == 8) { sh &= 0x3F; if (sh) { if (sh < 32) { emit(con, rlwinm(t->high,b->high,sh,0,31-sh)); emit(con, rlwimi(t->high,b->low,sh,32-sh,31)); emit(con, slwi(t->low, b->low, sh)); } else { emit(con, rlwinm(t->high,b->low,sh-32,0,63-sh)); emit(con, li(t->low,0)); } } else { moveRR(con, size, b, size, t); } } else { emit(con, slwi(t->low, b->low, sh & 0x1F)); } } void shiftRightR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if(size == 8) { lir::Register Tmp(newTemp(con), newTemp(con)); lir::Register* tmp = &Tmp; emit(con, subfic(tmp->high, a->low, 32)); emit(con, srw(t->low, b->low, a->low)); emit(con, slw(tmp->low, b->high, tmp->high)); emit(con, or_(t->low, t->low, tmp->low)); emit(con, addic(tmp->high, a->low, -32)); emit(con, sraw(tmp->low, b->high, tmp->high)); emit(con, ble(8)); emit(con, ori(t->low, tmp->low, 0)); emit(con, sraw(t->high, b->high, a->low)); freeTemp(con, tmp->high); freeTemp(con, tmp->low); } else { emit(con, sraw(t->low, b->low, a->low)); } } void shiftRightC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* t) { int sh = getValue(a); if(size == 8) { sh &= 0x3F; if (sh) { if (sh < 32) { emit(con, rlwinm(t->low,b->low,32-sh,sh,31)); emit(con, rlwimi(t->low,b->high,32-sh,0,sh-1)); emit(con, srawi(t->high,b->high,sh)); } else { emit(con, srawi(t->high,b->high,31)); emit(con, srawi(t->low,b->high,sh-32)); } } else { moveRR(con, size, b, size, t); } } else { emit(con, srawi(t->low, b->low, sh & 0x1F)); } } void unsignedShiftRightR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { emit(con, srw(t->low, b->low, a->low)); if(size == 8) { lir::Register Tmp(newTemp(con), newTemp(con)); lir::Register* tmp = &Tmp; emit(con, subfic(tmp->high, a->low, 32)); emit(con, slw(tmp->low, b->high, tmp->high)); emit(con, or_(t->low, t->low, tmp->low)); emit(con, addi(tmp->high, a->low, -32)); emit(con, srw(tmp->low, b->high, tmp->high)); emit(con, or_(t->low, t->low, tmp->low)); emit(con, srw(t->high, b->high, a->low)); freeTemp(con, tmp->high); freeTemp(con, tmp->low); } } void unsignedShiftRightC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* t) { int sh = getValue(a); if (size == 8) { if (sh & 0x3F) { if (sh == 32) { lir::Register high(b->high); moveRR(con, 4, &high, 4, t); emit(con, li(t->high,0)); } else if (sh < 32) { emit(con, srwi(t->low, b->low, sh)); emit(con, rlwimi(t->low,b->high,32-sh,0,sh-1)); emit(con, rlwinm(t->high,b->high,32-sh,sh,31)); } else { emit(con, rlwinm(t->low,b->high,64-sh,sh-32,31)); emit(con, li(t->high,0)); } } else { moveRR(con, size, b, size, t); } } else { if (sh & 0x1F) { emit(con, srwi(t->low, b->low, sh & 0x1F)); } else { moveRR(con, size, b, size, t); } } } void jumpR(Context* c, unsigned size UNUSED, lir::Register* target) { assert(c, size == TargetBytesPerWord); emit(c, mtctr(target->low)); emit(c, bctr()); } void swapRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b) { assert(c, aSize == TargetBytesPerWord); assert(c, bSize == TargetBytesPerWord); lir::Register tmp(c->client->acquireTemporary()); moveRR(c, aSize, a, bSize, &tmp); moveRR(c, bSize, b, aSize, a); moveRR(c, bSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } void moveRR(Context* c, unsigned srcSize, lir::Register* src, unsigned dstSize, lir::Register* dst) { switch (srcSize) { case 1: emit(c, extsb(dst->low, src->low)); break; case 2: emit(c, extsh(dst->low, src->low)); break; case 4: case 8: if (srcSize == 4 and dstSize == 8) { moveRR(c, 4, src, 4, dst); emit(c, srawi(dst->high, src->low, 31)); } else if (srcSize == 8 and dstSize == 8) { lir::Register srcHigh(src->high); lir::Register dstHigh(dst->high); if (src->high == dst->low) { if (src->low == dst->high) { swapRR(c, 4, src, 4, dst); } else { moveRR(c, 4, &srcHigh, 4, &dstHigh); moveRR(c, 4, src, 4, dst); } } else { moveRR(c, 4, src, 4, dst); moveRR(c, 4, &srcHigh, 4, &dstHigh); } } else if (src->low != dst->low) { emit(c, mr(dst->low, src->low)); } break; default: abort(c); } } void moveZRR(Context* c, unsigned srcSize, lir::Register* src, unsigned, lir::Register* dst) { switch (srcSize) { case 2: emit(c, andi(dst->low, src->low, 0xFFFF)); break; default: abort(c); } } void moveCR2(Context* c, unsigned, lir::Constant* src, unsigned dstSize, lir::Register* dst, unsigned promiseOffset) { if (dstSize <= 4) { if (src->value->resolved()) { int32_t v = src->value->value(); if (fitsInInt16(v)) { emit(c, li(dst->low, v)); } else { emit(c, lis(dst->low, v >> 16)); emit(c, ori(dst->low, dst->low, v)); } } else { appendImmediateTask (c, src->value, offsetPromise(c), TargetBytesPerWord, promiseOffset, false); emit(c, lis(dst->low, 0)); emit(c, ori(dst->low, dst->low, 0)); } } else { abort(c); // todo } } void moveCR(Context* c, unsigned srcSize, lir::Constant* src, unsigned dstSize, lir::Register* dst) { moveCR2(c, srcSize, src, dstSize, dst, 0); } void addR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if(size == 8) { emit(con, addc(t->low, a->low, b->low)); emit(con, adde(t->high, a->high, b->high)); } else { emit(con, add(t->low, a->low, b->low)); } } void addC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* t) { assert(con, size == TargetBytesPerWord); int32_t i = getValue(a); if(i) { emit(con, addi(t->low, b->low, lo16(i))); if(not fitsInInt16(i)) emit(con, addis(t->low, t->low, hi16(i) + carry16(i))); } else { moveRR(con, size, b, size, t); } } void subR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if(size == 8) { emit(con, subfc(t->low, a->low, b->low)); emit(con, subfe(t->high, a->high, b->high)); } else { emit(con, subf(t->low, a->low, b->low)); } } void subC(Context* c, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* t) { assert(c, size == TargetBytesPerWord); ResolvedPromise promise(- a->value->value()); lir::Constant constant(&promise); addC(c, size, &constant, b, t); } void multiplyR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { if(size == 8) { bool useTemporaries = b->low == t->low; int tmpLow; int tmpHigh; if (useTemporaries) { tmpLow = con->client->acquireTemporary(); tmpHigh = con->client->acquireTemporary(); } else { tmpLow = t->low; tmpHigh = t->high; } emit(con, mullw(tmpHigh, a->high, b->low)); emit(con, mullw(tmpLow, a->low, b->high)); emit(con, add(t->high, tmpHigh, tmpLow)); emit(con, mulhwu(tmpLow, a->low, b->low)); emit(con, add(t->high, t->high, tmpLow)); emit(con, mullw(t->low, a->low, b->low)); if (useTemporaries) { con->client->releaseTemporary(tmpLow); con->client->releaseTemporary(tmpHigh); } } else { emit(con, mullw(t->low, a->low, b->low)); } } void divideR(Context* con, unsigned size UNUSED, lir::Register* a, lir::Register* b, lir::Register* t) { assert(con, size == 4); emit(con, divw(t->low, b->low, a->low)); } void remainderR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t) { bool useTemporary = b->low == t->low; lir::Register tmp(t->low); if (useTemporary) { tmp.low = con->client->acquireTemporary(); } divideR(con, size, a, b, &tmp); multiplyR(con, size, a, &tmp, &tmp); subR(con, size, &tmp, b, t); if (useTemporary) { con->client->releaseTemporary(tmp.low); } } int normalize(Context* c, int offset, int index, unsigned scale, bool* preserveIndex, bool* release) { if (offset != 0 or scale != 1) { lir::Register normalizedIndex (*preserveIndex ? c->client->acquireTemporary() : index); if (*preserveIndex) { *release = true; *preserveIndex = false; } else { *release = false; } int scaled; if (scale != 1) { lir::Register unscaledIndex(index); ResolvedPromise scalePromise(log(scale)); lir::Constant scaleConstant(&scalePromise); shiftLeftC(c, TargetBytesPerWord, &scaleConstant, &unscaledIndex, &normalizedIndex); scaled = normalizedIndex.low; } else { scaled = index; } if (offset != 0) { lir::Register untranslatedIndex(scaled); ResolvedPromise offsetPromise(offset); lir::Constant offsetConstant(&offsetPromise); addC(c, TargetBytesPerWord, &offsetConstant, &untranslatedIndex, &normalizedIndex); } return normalizedIndex.low; } else { *release = false; return index; } } void store(Context* c, unsigned size, lir::Register* src, int base, int offset, int index, unsigned scale, bool preserveIndex) { if (index != lir::NoRegister) { bool release; int normalized = normalize (c, offset, index, scale, &preserveIndex, &release); switch (size) { case 1: emit(c, stbx(src->low, base, normalized)); break; case 2: emit(c, sthx(src->low, base, normalized)); break; case 4: emit(c, stwx(src->low, base, normalized)); break; case 8: { lir::Register srcHigh(src->high); store(c, 4, &srcHigh, base, 0, normalized, 1, preserveIndex); store(c, 4, src, base, 4, normalized, 1, preserveIndex); } break; default: abort(c); } if (release) c->client->releaseTemporary(normalized); } else { switch (size) { case 1: emit(c, stb(src->low, base, offset)); break; case 2: emit(c, sth(src->low, base, offset)); break; case 4: emit(c, stw(src->low, base, offset)); break; case 8: { lir::Register srcHigh(src->high); store(c, 4, &srcHigh, base, offset, lir::NoRegister, 1, false); store(c, 4, src, base, offset + 4, lir::NoRegister, 1, false); } break; default: abort(c); } } } void moveRM(Context* c, unsigned srcSize, lir::Register* src, unsigned dstSize UNUSED, lir::Memory* dst) { assert(c, srcSize == dstSize); store(c, srcSize, src, dst->base, dst->offset, dst->index, dst->scale, true); } void moveAndUpdateRM(Context* c, unsigned srcSize UNUSED, lir::Register* src, unsigned dstSize UNUSED, lir::Memory* dst) { assert(c, srcSize == TargetBytesPerWord); assert(c, dstSize == TargetBytesPerWord); if (dst->index == lir::NoRegister) { emit(c, stwu(src->low, dst->base, dst->offset)); } else { assert(c, dst->offset == 0); assert(c, dst->scale == 1); emit(c, stwux(src->low, dst->base, dst->index)); } } void load(Context* c, unsigned srcSize, int base, int offset, int index, unsigned scale, unsigned dstSize, lir::Register* dst, bool preserveIndex, bool signExtend) { if (index != lir::NoRegister) { bool release; int normalized = normalize (c, offset, index, scale, &preserveIndex, &release); switch (srcSize) { case 1: emit(c, lbzx(dst->low, base, normalized)); if (signExtend) { emit(c, extsb(dst->low, dst->low)); } break; case 2: if (signExtend) { emit(c, lhax(dst->low, base, normalized)); } else { emit(c, lhzx(dst->low, base, normalized)); } break; case 4: case 8: { if (srcSize == 4 and dstSize == 8) { load(c, 4, base, 0, normalized, 1, 4, dst, preserveIndex, false); moveRR(c, 4, dst, 8, dst); } else if (srcSize == 8 and dstSize == 8) { lir::Register dstHigh(dst->high); load(c, 4, base, 0, normalized, 1, 4, &dstHigh, preserveIndex, false); load(c, 4, base, 4, normalized, 1, 4, dst, preserveIndex, false); } else { emit(c, lwzx(dst->low, base, normalized)); } } break; default: abort(c); } if (release) c->client->releaseTemporary(normalized); } else { switch (srcSize) { case 1: emit(c, lbz(dst->low, base, offset)); if (signExtend) { emit(c, extsb(dst->low, dst->low)); } break; case 2: if (signExtend) { emit(c, lha(dst->low, base, offset)); } else { emit(c, lha(dst->low, base, offset)); } break; case 4: emit(c, lwz(dst->low, base, offset)); break; case 8: { if (dstSize == 8) { lir::Register dstHigh(dst->high); load(c, 4, base, offset, lir::NoRegister, 1, 4, &dstHigh, false, false); load(c, 4, base, offset + 4, lir::NoRegister, 1, 4, dst, false, false); } else { emit(c, lwzx(dst->low, base, offset)); } } break; default: abort(c); } } } void moveMR(Context* c, unsigned srcSize, lir::Memory* src, unsigned dstSize, lir::Register* dst) { load(c, srcSize, src->base, src->offset, src->index, src->scale, dstSize, dst, true, true); } void moveZMR(Context* c, unsigned srcSize, lir::Memory* src, unsigned dstSize, lir::Register* dst) { load(c, srcSize, src->base, src->offset, src->index, src->scale, dstSize, dst, true, false); } void andR(Context* c, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst) { if (size == 8) { lir::Register ah(a->high); lir::Register bh(b->high); lir::Register dh(dst->high); andR(c, 4, a, b, dst); andR(c, 4, &ah, &bh, &dh); } else { emit(c, and_(dst->low, a->low, b->low)); } } void andC(Context* c, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst) { int64_t v = a->value->value(); if (size == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); lir::Constant ah(&high); ResolvedPromise low(v & 0xFFFFFFFF); lir::Constant al(&low); lir::Register bh(b->high); lir::Register dh(dst->high); andC(c, 4, &al, b, dst); andC(c, 4, &ah, &bh, &dh); } else { // bitmasks of the form regex 0*1*0* can be handled in a single // rlwinm instruction, hence the following: uint32_t v32 = static_cast(v); unsigned state = 0; unsigned start = 0; unsigned end = 31; for (unsigned i = 0; i < 32; ++i) { unsigned bit = (v32 >> i) & 1; switch (state) { case 0: if (bit) { start = i; state = 1; } break; case 1: if (bit == 0) { end = i - 1; state = 2; } break; case 2: if (bit) { // not in 0*1*0* form. We can only use andi(s) if either // the topmost or bottommost 16 bits are zero. if ((v32 >> 16) == 0) { emit(c, andi(dst->low, b->low, v32)); } else if ((v32 & 0xFFFF) == 0) { emit(c, andis(dst->low, b->low, v32 >> 16)); } else { bool useTemporary = b->low == dst->low; lir::Register tmp(dst->low); if (useTemporary) { tmp.low = c->client->acquireTemporary(); } moveCR(c, 4, a, 4, &tmp); andR(c, 4, b, &tmp, dst); if (useTemporary) { c->client->releaseTemporary(tmp.low); } } return; } break; } } if (state) { if (start != 0 or end != 31) { emit(c, rlwinm(dst->low, b->low, 0, 31 - end, 31 - start)); } else { moveRR(c, 4, b, 4, dst); } } else { emit(c, li(dst->low, 0)); } } } void orR(Context* c, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst) { if (size == 8) { lir::Register ah(a->high); lir::Register bh(b->high); lir::Register dh(dst->high); orR(c, 4, a, b, dst); orR(c, 4, &ah, &bh, &dh); } else { emit(c, or_(dst->low, a->low, b->low)); } } void orC(Context* c, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst) { int64_t v = a->value->value(); if (size == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); lir::Constant ah(&high); ResolvedPromise low(v & 0xFFFFFFFF); lir::Constant al(&low); lir::Register bh(b->high); lir::Register dh(dst->high); orC(c, 4, &al, b, dst); orC(c, 4, &ah, &bh, &dh); } else { emit(c, ori(b->low, dst->low, v)); if (v >> 16) { emit(c, oris(dst->low, dst->low, v >> 16)); } } } void xorR(Context* c, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst) { if (size == 8) { lir::Register ah(a->high); lir::Register bh(b->high); lir::Register dh(dst->high); xorR(c, 4, a, b, dst); xorR(c, 4, &ah, &bh, &dh); } else { emit(c, xor_(dst->low, a->low, b->low)); } } void xorC(Context* c, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst) { uint64_t v = a->value->value(); if (size == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); lir::Constant ah(&high); ResolvedPromise low(v & 0xFFFFFFFF); lir::Constant al(&low); lir::Register bh(b->high); lir::Register dh(dst->high); xorC(c, 4, &al, b, dst); xorC(c, 4, &ah, &bh, &dh); } else { if (v >> 16) { emit(c, xoris(b->low, dst->low, v >> 16)); emit(c, xori(dst->low, dst->low, v)); } else { emit(c, xori(b->low, dst->low, v)); } } } void moveAR2(Context* c, unsigned srcSize UNUSED, lir::Address* src, unsigned dstSize, lir::Register* dst, unsigned promiseOffset) { assert(c, srcSize == 4 and dstSize == 4); lir::Memory memory(dst->low, 0, -1, 0); appendImmediateTask (c, src->address, offsetPromise(c), TargetBytesPerWord, promiseOffset, true); emit(c, lis(dst->low, 0)); moveMR(c, dstSize, &memory, dstSize, dst); } void moveAR(Context* c, unsigned srcSize, lir::Address* src, unsigned dstSize, lir::Register* dst) { moveAR2(c, srcSize, src, dstSize, dst, 0); } void compareRR(Context* c, unsigned aSize UNUSED, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == 4 and bSize == 4); emit(c, cmpw(b->low, a->low)); } void compareCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(c, aSize == 4 and bSize == 4); if (a->value->resolved() and fitsInInt16(a->value->value())) { emit(c, cmpwi(b->low, a->value->value())); } else { lir::Register tmp(c->client->acquireTemporary()); moveCR(c, aSize, a, bSize, &tmp); compareRR(c, bSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } void compareCM(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Memory* b) { assert(c, aSize == 4 and bSize == 4); lir::Register tmp(c->client->acquireTemporary()); moveMR(c, bSize, b, bSize, &tmp); compareCR(c, aSize, a, bSize, &tmp); c->client->releaseTemporary(tmp.low); } void compareRM(Context* c, unsigned aSize, lir::Register* a, unsigned bSize, lir::Memory* b) { assert(c, aSize == 4 and bSize == 4); lir::Register tmp(c->client->acquireTemporary()); moveMR(c, bSize, b, bSize, &tmp); compareRR(c, aSize, a, bSize, &tmp); c->client->releaseTemporary(tmp.low); } void compareUnsignedRR(Context* c, unsigned aSize UNUSED, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == 4 and bSize == 4); emit(c, cmplw(b->low, a->low)); } void compareUnsignedCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(c, aSize == 4 and bSize == 4); if (a->value->resolved() and (a->value->value() >> 16) == 0) { emit(c, cmplwi(b->low, a->value->value())); } else { lir::Register tmp(c->client->acquireTemporary()); moveCR(c, aSize, a, bSize, &tmp); compareUnsignedRR(c, bSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } int32_t branch(Context* c, lir::TernaryOperation op) { switch (op) { case lir::JumpIfEqual: return beq(0); case lir::JumpIfNotEqual: return bne(0); case lir::JumpIfLess: return blt(0); case lir::JumpIfGreater: return bgt(0); case lir::JumpIfLessOrEqual: return ble(0); case lir::JumpIfGreaterOrEqual: return bge(0); default: abort(c); } } void conditional(Context* c, int32_t branch, lir::Constant* target) { appendOffsetTask(c, target->value, offsetPromise(c), true); emit(c, branch); } void branch(Context* c, lir::TernaryOperation op, lir::Constant* target) { conditional(c, branch(c, op), target); } void branchLong(Context* c, lir::TernaryOperation op, lir::Operand* al, lir::Operand* ah, lir::Operand* bl, lir::Operand* bh, lir::Constant* target, BinaryOperationType compareSigned, BinaryOperationType compareUnsigned) { compareSigned(c, 4, ah, 4, bh); unsigned next = 0; switch (op) { case lir::JumpIfEqual: next = c->code.length(); emit(c, bne(0)); compareSigned(c, 4, al, 4, bl); conditional(c, beq(0), target); break; case lir::JumpIfNotEqual: conditional(c, bne(0), target); compareSigned(c, 4, al, 4, bl); conditional(c, bne(0), target); break; case lir::JumpIfLess: conditional(c, blt(0), target); next = c->code.length(); emit(c, bgt(0)); compareUnsigned(c, 4, al, 4, bl); conditional(c, blt(0), target); break; case lir::JumpIfGreater: conditional(c, bgt(0), target); next = c->code.length(); emit(c, blt(0)); compareUnsigned(c, 4, al, 4, bl); conditional(c, bgt(0), target); break; case lir::JumpIfLessOrEqual: conditional(c, blt(0), target); next = c->code.length(); emit(c, bgt(0)); compareUnsigned(c, 4, al, 4, bl); conditional(c, ble(0), target); break; case lir::JumpIfGreaterOrEqual: conditional(c, bgt(0), target); next = c->code.length(); emit(c, blt(0)); compareUnsigned(c, 4, al, 4, bl); conditional(c, bge(0), target); break; default: abort(c); } if (next) { updateOffset( c->s, c->code.data.begin() + next, true, reinterpret_cast(c->code.data.begin() + c->code.length()), 0); } } void branchRR(Context* c, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Register* b, lir::Constant* target) { if (size > TargetBytesPerWord) { lir::Register ah(a->high); lir::Register bh(b->high); branchLong(c, op, a, &ah, b, &bh, target, CAST2(compareRR), CAST2(compareUnsignedRR)); } else { compareRR(c, size, a, size, b); branch(c, op, target); } } void branchCR(Context* c, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Register* b, lir::Constant* target) { if (size > TargetBytesPerWord) { int64_t v = a->value->value(); ResolvedPromise low(v & ~static_cast(0)); lir::Constant al(&low); ResolvedPromise high((v >> 32) & ~static_cast(0)); lir::Constant ah(&high); lir::Register bh(b->high); branchLong(c, op, &al, &ah, b, &bh, target, CAST2(compareCR), CAST2(compareUnsignedCR)); } else { compareCR(c, size, a, size, b); branch(c, op, target); } } void branchRM(Context* c, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Memory* b, lir::Constant* target) { assert(c, size <= TargetBytesPerWord); compareRM(c, size, a, size, b); branch(c, op, target); } void branchCM(Context* c, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Memory* b, lir::Constant* target) { assert(c, size <= TargetBytesPerWord); compareCM(c, size, a, size, b); branch(c, op, target); } void moveCM(Context* c, unsigned srcSize, lir::Constant* src, unsigned dstSize, lir::Memory* dst) { switch (dstSize) { case 8: { lir::Constant srcHigh (shiftMaskPromise(c, src->value, 32, 0xFFFFFFFF)); lir::Constant srcLow (shiftMaskPromise(c, src->value, 0, 0xFFFFFFFF)); lir::Memory dstLow (dst->base, dst->offset + 4, dst->index, dst->scale); moveCM(c, 4, &srcLow, 4, &dstLow); moveCM(c, 4, &srcHigh, 4, dst); } break; default: lir::Register tmp(c->client->acquireTemporary()); moveCR(c, srcSize, src, dstSize, &tmp); moveRM(c, dstSize, &tmp, dstSize, dst); c->client->releaseTemporary(tmp.low); } } void negateRR(Context* c, unsigned srcSize, lir::Register* src, unsigned dstSize UNUSED, lir::Register* dst) { assert(c, srcSize == dstSize); if (srcSize == 8) { lir::Register dstHigh(dst->high); emit(c, subfic(dst->low, src->low, 0)); emit(c, subfze(dst->high, src->high)); } else { emit(c, neg(dst->low, src->low)); } } void callR(Context* c, unsigned size UNUSED, lir::Register* target) { assert(c, size == TargetBytesPerWord); emit(c, mtctr(target->low)); emit(c, bctrl()); } void callC(Context* c, unsigned size UNUSED, lir::Constant* target) { assert(c, size == TargetBytesPerWord); appendOffsetTask(c, target->value, offsetPromise(c), false); emit(c, bl(0)); } void longCallC(Context* c, unsigned size UNUSED, lir::Constant* target) { assert(c, size == TargetBytesPerWord); lir::Register tmp(0); moveCR2(c, TargetBytesPerWord, target, TargetBytesPerWord, &tmp, 12); callR(c, TargetBytesPerWord, &tmp); } void alignedLongCallC(Context* c, unsigned size UNUSED, lir::Constant* target) { assert(c, size == TargetBytesPerWord); lir::Register tmp(c->client->acquireTemporary()); lir::Address address(appendConstantPoolEntry(c, target->value)); moveAR2(c, TargetBytesPerWord, &address, TargetBytesPerWord, &tmp, 12); callR(c, TargetBytesPerWord, &tmp); c->client->releaseTemporary(tmp.low); } void longJumpC(Context* c, unsigned size UNUSED, lir::Constant* target) { assert(c, size == TargetBytesPerWord); lir::Register tmp(0); moveCR2(c, TargetBytesPerWord, target, TargetBytesPerWord, &tmp, 12); jumpR(c, TargetBytesPerWord, &tmp); } void alignedLongJumpC(Context* c, unsigned size UNUSED, lir::Constant* target) { assert(c, size == TargetBytesPerWord); lir::Register tmp(c->client->acquireTemporary()); lir::Address address(appendConstantPoolEntry(c, target->value)); moveAR2(c, TargetBytesPerWord, &address, TargetBytesPerWord, &tmp, 12); jumpR(c, TargetBytesPerWord, &tmp); c->client->releaseTemporary(tmp.low); } void jumpC(Context* c, unsigned size UNUSED, lir::Constant* target) { assert(c, size == TargetBytesPerWord); appendOffsetTask(c, target->value, offsetPromise(c), false); emit(c, b(0)); } void return_(Context* c) { emit(c, blr()); } void trap(Context* c) { emit(c, isa::trap()); } void memoryBarrier(Context* c) { emit(c, sync(0)); } } // namespace powerpc } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/operations.h000066400000000000000000000164041231440243200246610ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_POWERPC_OPERATIONS_H #define AVIAN_CODEGEN_ASSEMBLER_POWERPC_OPERATIONS_H #include "context.h" namespace avian { namespace codegen { namespace powerpc { inline void emit(Context* con, int code) { con->code.append4(vm::targetV4(code)); } inline int newTemp(Context* con) { return con->client->acquireTemporary(); } inline void freeTemp(Context* con, int r) { con->client->releaseTemporary(r); } inline int64_t getValue(lir::Constant* c) { return c->value->value(); } void andC(Context* c, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst); void shiftLeftR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void moveRR(Context* c, unsigned srcSize, lir::Register* src, unsigned dstSize, lir::Register* dst); void shiftLeftC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* t); void shiftRightR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void shiftRightC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* t); void unsignedShiftRightR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void unsignedShiftRightC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* t); void jumpR(Context* c, unsigned size UNUSED, lir::Register* target); void swapRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b); void moveRR(Context* c, unsigned srcSize, lir::Register* src, unsigned dstSize, lir::Register* dst); void moveZRR(Context* c, unsigned srcSize, lir::Register* src, unsigned, lir::Register* dst); void moveCR2(Context* c, unsigned, lir::Constant* src, unsigned dstSize, lir::Register* dst, unsigned promiseOffset); void moveCR(Context* c, unsigned srcSize, lir::Constant* src, unsigned dstSize, lir::Register* dst); void addR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void addC(Context* con, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* t); void subR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void subC(Context* c, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* t); void multiplyR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); void divideR(Context* con, unsigned size UNUSED, lir::Register* a, lir::Register* b, lir::Register* t); void remainderR(Context* con, unsigned size, lir::Register* a, lir::Register* b, lir::Register* t); int normalize(Context* c, int offset, int index, unsigned scale, bool* preserveIndex, bool* release); void store(Context* c, unsigned size, lir::Register* src, int base, int offset, int index, unsigned scale, bool preserveIndex); void moveRM(Context* c, unsigned srcSize, lir::Register* src, unsigned dstSize UNUSED, lir::Memory* dst); void moveAndUpdateRM(Context* c, unsigned srcSize UNUSED, lir::Register* src, unsigned dstSize UNUSED, lir::Memory* dst); void load(Context* c, unsigned srcSize, int base, int offset, int index, unsigned scale, unsigned dstSize, lir::Register* dst, bool preserveIndex, bool signExtend); void moveMR(Context* c, unsigned srcSize, lir::Memory* src, unsigned dstSize, lir::Register* dst); void moveZMR(Context* c, unsigned srcSize, lir::Memory* src, unsigned dstSize, lir::Register* dst); void andR(Context* c, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst); void andC(Context* c, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst); void orR(Context* c, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst); void orC(Context* c, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst); void xorR(Context* c, unsigned size, lir::Register* a, lir::Register* b, lir::Register* dst); void xorC(Context* c, unsigned size, lir::Constant* a, lir::Register* b, lir::Register* dst); void moveAR2(Context* c, unsigned srcSize UNUSED, lir::Address* src, unsigned dstSize, lir::Register* dst, unsigned promiseOffset); void moveAR(Context* c, unsigned srcSize, lir::Address* src, unsigned dstSize, lir::Register* dst); void compareRR(Context* c, unsigned aSize UNUSED, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void compareCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void compareCM(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Memory* b); void compareRM(Context* c, unsigned aSize, lir::Register* a, unsigned bSize, lir::Memory* b); void compareUnsignedRR(Context* c, unsigned aSize UNUSED, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void compareUnsignedCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); int32_t branch(Context* c, lir::TernaryOperation op); void conditional(Context* c, int32_t branch, lir::Constant* target); void branch(Context* c, lir::TernaryOperation op, lir::Constant* target); void branchLong(Context* c, lir::TernaryOperation op, lir::Operand* al, lir::Operand* ah, lir::Operand* bl, lir::Operand* bh, lir::Constant* target, BinaryOperationType compareSigned, BinaryOperationType compareUnsigned); void branchRR(Context* c, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Register* b, lir::Constant* target); void branchCR(Context* c, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Register* b, lir::Constant* target); void branchRM(Context* c, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Memory* b, lir::Constant* target); void branchCM(Context* c, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Memory* b, lir::Constant* target); void moveCM(Context* c, unsigned srcSize, lir::Constant* src, unsigned dstSize, lir::Memory* dst); void negateRR(Context* c, unsigned srcSize, lir::Register* src, unsigned dstSize UNUSED, lir::Register* dst); void callR(Context* c, unsigned size UNUSED, lir::Register* target); void callC(Context* c, unsigned size UNUSED, lir::Constant* target); void longCallC(Context* c, unsigned size UNUSED, lir::Constant* target); void alignedLongCallC(Context* c, unsigned size UNUSED, lir::Constant* target); void longJumpC(Context* c, unsigned size UNUSED, lir::Constant* target); void alignedLongJumpC(Context* c, unsigned size UNUSED, lir::Constant* target); void jumpC(Context* c, unsigned size UNUSED, lir::Constant* target); void return_(Context* c); void trap(Context* c); void memoryBarrier(Context* c); } // namespace powerpc } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_POWERPC_OPERATIONS_H ReadyTalk-avian-1e1fff5/src/codegen/target/powerpc/registers.h000066400000000000000000000011761231440243200245050ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_POWERPC_REGISTERS_H #define AVIAN_CODEGEN_ASSEMBLER_POWERPC_REGISTERS_H namespace avian { namespace codegen { namespace powerpc { } // namespace powerpc } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_POWERPC_REGISTERS_H ReadyTalk-avian-1e1fff5/src/codegen/target/x86/000077500000000000000000000000001231440243200212665ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/codegen/target/x86/assembler.cpp000066400000000000000000001025231231440243200237520ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include "avian/environment.h" #include "avian/target.h" #include "avian/alloc-vector.h" #include "avian/common.h" #include "avian/util/allocator.h" #include "avian/zone.h" #include #include #include #include #include #include #include #include #include #include "context.h" #include "block.h" #include "fixup.h" #include "padding.h" #include "registers.h" #include "operations.h" #include "detect.h" #include "multimethod.h" #include "../multimethod.h" #define CAST1(x) reinterpret_cast(x) #define CAST2(x) reinterpret_cast(x) #define CAST_BRANCH(x) reinterpret_cast(x) using namespace vm; using namespace avian::util; namespace avian { namespace codegen { namespace x86 { const unsigned FrameHeaderSize = (UseFramePointer ? 2 : 1); const unsigned StackAlignmentInBytes = 16; const unsigned StackAlignmentInWords = StackAlignmentInBytes / TargetBytesPerWord; unsigned argumentFootprint(unsigned footprint) { return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); } uint32_t read4(uint8_t* p) { uint32_t v; memcpy(&v, p, 4); return v; } void nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, unsigned footprint, void*, bool mostRecent, int targetParameterFootprint, void** ip, void** stack) { assert(c, *ip >= start); assert(c, *ip <= start + size); uint8_t* instruction = static_cast(*ip); // skip stack overflow check, if present: if (TargetBytesPerWord == 4) { if (*start == 0x39) { start += 12; } } else if (*start == 0x48 and start[1] == 0x39) { start += 13; } if (instruction <= start) { assert(c, mostRecent); *ip = static_cast(*stack)[0]; return; } if (UseFramePointer) { // skip preamble start += (TargetBytesPerWord == 4 ? 3 : 4); if (instruction <= start or *instruction == 0x5d) { assert(c, mostRecent); *ip = static_cast(*stack)[1]; *stack = static_cast(*stack) + 1; return; } } if (*instruction == 0xc3) { // return *ip = static_cast(*stack)[0]; return; } unsigned offset = footprint + FrameHeaderSize - (mostRecent ? 1 : 0); if (TailCalls and targetParameterFootprint >= 0) { if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { offset += argumentFootprint(targetParameterFootprint) - StackAlignmentInWords; } // check for post-non-tail-call stack adjustment of the form "sub // $offset,%rsp": if (TargetBytesPerWord == 4) { if ((*instruction == 0x83 or *instruction == 0x81) and instruction[1] == 0xec) { offset -= (*instruction == 0x83 ? instruction[2] : read4(instruction + 2)) / TargetBytesPerWord; } } else if (*instruction == 0x48 and (instruction[1] == 0x83 or instruction[1] == 0x81) and instruction[2] == 0xec) { offset -= (instruction[1] == 0x83 ? instruction[3] : read4(instruction + 3)) / TargetBytesPerWord; } // todo: check for and handle tail calls } if (UseFramePointer and not mostRecent) { assert(c, static_cast(*stack)[-1] + 1 == static_cast(*stack) + offset); assert(c, static_cast(*stack)[-1][1] == static_cast(*stack)[offset]); } *ip = static_cast(*stack)[offset]; *stack = static_cast(*stack) + offset; } class MyArchitecture: public Architecture { public: MyArchitecture(System* system, bool useNativeFeatures): c(system, useNativeFeatures), referenceCount(0), myRegisterFile(GeneralRegisterMask, useSSE(&c) ? FloatRegisterMask : 0) { populateTables(&c); } virtual unsigned floatRegisterSize() { if (useSSE(&c)) { return 8; } else { return 0; } } virtual const RegisterFile* registerFile() { return &myRegisterFile; } virtual int scratch() { return rax; } virtual int stack() { return rsp; } virtual int thread() { return rbx; } virtual int returnLow() { return rax; } virtual int returnHigh() { return (TargetBytesPerWord == 4 ? rdx : lir::NoRegister); } virtual int virtualCallTarget() { return rax; } virtual int virtualCallIndex() { return rdx; } virtual bool bigEndian() { return false; } virtual uintptr_t maximumImmediateJump() { return 0x7FFFFFFF; } virtual bool reserved(int register_) { switch (register_) { case rbp: return UseFramePointer; case rsp: case rbx: return true; default: return false; } } virtual unsigned frameFootprint(unsigned footprint) { #if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE return max(footprint, StackAlignmentInWords); #else return max(footprint > argumentRegisterCount() ? footprint - argumentRegisterCount() : 0, StackAlignmentInWords); #endif } virtual unsigned argumentFootprint(unsigned footprint) { return x86::argumentFootprint(footprint); } virtual bool argumentAlignment() { return false; } virtual bool argumentRegisterAlignment() { return false; } virtual unsigned argumentRegisterCount() { #if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE if (TargetBytesPerWord == 8) return 4; else #else if (TargetBytesPerWord == 8) return 6; else #endif return 0; } virtual int argumentRegister(unsigned index) { assert(&c, TargetBytesPerWord == 8); switch (index) { #if AVIAN_TARGET_FORMAT == AVIAN_FORMAT_PE case 0: return rcx; case 1: return rdx; case 2: return r8; case 3: return r9; #else case 0: return rdi; case 1: return rsi; case 2: return rdx; case 3: return rcx; case 4: return r8; case 5: return r9; #endif default: abort(&c); } } virtual bool hasLinkRegister() { return false; } virtual unsigned stackAlignmentInWords() { return StackAlignmentInWords; } virtual bool matchCall(void* returnAddress, void* target) { uint8_t* instruction = static_cast(returnAddress) - 5; int32_t actualOffset; memcpy(&actualOffset, instruction + 1, 4); void* actualTarget = static_cast(returnAddress) + actualOffset; return *instruction == 0xE8 and actualTarget == target; } virtual void updateCall(lir::UnaryOperation op, void* returnAddress, void* newTarget) { bool assertAlignment UNUSED; switch (op) { case lir::AlignedCall: op = lir::Call; assertAlignment = true; break; case lir::AlignedJump: op = lir::Jump; assertAlignment = true; break; case lir::AlignedLongCall: op = lir::LongCall; assertAlignment = true; break; case lir::AlignedLongJump: op = lir::LongJump; assertAlignment = true; break; default: assertAlignment = false; } if (TargetBytesPerWord == 4 or op == lir::Call or op == lir::Jump) { uint8_t* instruction = static_cast(returnAddress) - 5; assert(&c, ((op == lir::Call or op == lir::LongCall) and *instruction == 0xE8) or ((op == lir::Jump or op == lir::LongJump) and *instruction == 0xE9)); assert(&c, (not assertAlignment) or reinterpret_cast(instruction + 1) % 4 == 0); intptr_t v = static_cast(newTarget) - static_cast(returnAddress); assert(&c, vm::fitsInInt32(v)); int32_t v32 = v; memcpy(instruction + 1, &v32, 4); } else { uint8_t* instruction = static_cast(returnAddress) - 13; assert(&c, instruction[0] == 0x49 and instruction[1] == 0xBA); assert(&c, instruction[10] == 0x41 and instruction[11] == 0xFF); assert(&c, (op == lir::LongCall and instruction[12] == 0xD2) or (op == lir::LongJump and instruction[12] == 0xE2)); assert(&c, (not assertAlignment) or reinterpret_cast(instruction + 2) % 8 == 0); memcpy(instruction + 2, &newTarget, 8); } } virtual void setConstant(void* dst, uint64_t constant) { target_uintptr_t v = targetVW(constant); memcpy(dst, &v, TargetBytesPerWord); } virtual unsigned alignFrameSize(unsigned sizeInWords) { return pad(sizeInWords + FrameHeaderSize, StackAlignmentInWords) - FrameHeaderSize; } virtual void nextFrame(void* start, unsigned size, unsigned footprint, void* link, bool mostRecent, int targetParameterFootprint, void** ip, void** stack) { x86::nextFrame(&c, static_cast(start), size, footprint, link, mostRecent, targetParameterFootprint, ip, stack); } virtual void* frameIp(void* stack) { return stack ? *static_cast(stack) : 0; } virtual unsigned frameHeaderSize() { return FrameHeaderSize; } virtual unsigned frameReturnAddressSize() { return 1; } virtual unsigned frameFooterSize() { return 0; } virtual bool alwaysCondensed(lir::BinaryOperation op) { switch(op) { case lir::Float2Float: case lir::Float2Int: case lir::Int2Float: case lir::FloatAbsolute: case lir::FloatNegate: case lir::FloatSquareRoot: return false; case lir::Negate: case lir::Absolute: return true; default: abort(&c); } } virtual bool alwaysCondensed(lir::TernaryOperation) { return true; } virtual int returnAddressOffset() { return 0; } virtual int framePointerOffset() { return UseFramePointer ? -1 : 0; } virtual void plan (lir::UnaryOperation, unsigned, OperandMask& aMask, bool* thunk) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand) | (1 << lir::ConstantOperand); *thunk = false; } virtual void planSource (lir::BinaryOperation op, unsigned aSize, OperandMask& aMask, unsigned bSize, bool* thunk) { aMask.registerMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32); *thunk = false; switch (op) { case lir::Negate: aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = (static_cast(1) << (rdx + 32)) | (static_cast(1) << rax); break; case lir::Absolute: if (aSize <= TargetBytesPerWord) { aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = (static_cast(1) << rax); } else { *thunk = true; } break; case lir::FloatAbsolute: if (useSSE(&c)) { aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = (static_cast(FloatRegisterMask) << 32) | FloatRegisterMask; } else { *thunk = true; } break; case lir::FloatNegate: // floatNegateRR does not support doubles if (useSSE(&c) and aSize == 4 and bSize == 4) { aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = FloatRegisterMask; } else { *thunk = true; } break; case lir::FloatSquareRoot: if (useSSE(&c)) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); aMask.registerMask = (static_cast(FloatRegisterMask) << 32) | FloatRegisterMask; } else { *thunk = true; } break; case lir::Float2Float: if (useSSE(&c)) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); aMask.registerMask = (static_cast(FloatRegisterMask) << 32) | FloatRegisterMask; } else { *thunk = true; } break; case lir::Float2Int: // todo: Java requires different semantics than SSE for // converting floats to integers, we we need to either use // thunks or produce inline machine code which handles edge // cases properly. if (false and useSSE(&c) and bSize <= TargetBytesPerWord) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); aMask.registerMask = (static_cast(FloatRegisterMask) << 32) | FloatRegisterMask; } else { *thunk = true; } break; case lir::Int2Float: if (useSSE(&c) and aSize <= TargetBytesPerWord) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); aMask.registerMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32); } else { *thunk = true; } break; case lir::Move: aMask.typeMask = ~0; aMask.registerMask = ~static_cast(0); if (TargetBytesPerWord == 4) { if (aSize == 4 and bSize == 8) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); const uint32_t mask = GeneralRegisterMask & ~((1 << rax) | (1 << rdx)); aMask.registerMask = (static_cast(mask) << 32) | mask; } else if (aSize == 1 or bSize == 1) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); const uint32_t mask = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx); aMask.registerMask = (static_cast(mask) << 32) | mask; } } break; default: break; } } virtual void planDestination (lir::BinaryOperation op, unsigned aSize, const OperandMask& aMask, unsigned bSize, OperandMask& bMask) { bMask.typeMask = ~0; bMask.registerMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32); switch (op) { case lir::Absolute: bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = (static_cast(1) << rax); break; case lir::FloatAbsolute: bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = aMask.registerMask; break; case lir::Negate: bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = aMask.registerMask; break; case lir::FloatNegate: case lir::FloatSquareRoot: case lir::Float2Float: case lir::Int2Float: bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = (static_cast(FloatRegisterMask) << 32) | FloatRegisterMask; break; case lir::Float2Int: bMask.typeMask = (1 << lir::RegisterOperand); break; case lir::Move: if (aMask.typeMask & ((1 << lir::MemoryOperand) | 1 << lir::AddressOperand)) { bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32) | FloatRegisterMask; } else if (aMask.typeMask & (1 << lir::RegisterOperand)) { bMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); if (aMask.registerMask & FloatRegisterMask) { bMask.registerMask = FloatRegisterMask; } else { bMask.registerMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32); } } else { bMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); } if (TargetBytesPerWord == 4) { if (aSize == 4 and bSize == 8) { bMask.registerMask = (static_cast(1) << (rdx + 32)) | (static_cast(1) << rax); } else if (aSize == 1 or bSize == 1) { const uint32_t mask = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx); bMask.registerMask = (static_cast(mask) << 32) | mask; } } break; default: break; } } virtual void planMove (unsigned size, OperandMask& srcMask, OperandMask& tmpMask, const OperandMask& dstMask) { srcMask.typeMask = ~0; srcMask.registerMask = ~static_cast(0); tmpMask.typeMask = 0; tmpMask.registerMask = 0; if (dstMask.typeMask & (1 << lir::MemoryOperand)) { // can't move directly from memory to memory srcMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::ConstantOperand); tmpMask.typeMask = 1 << lir::RegisterOperand; tmpMask.registerMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32); } else if (dstMask.typeMask & (1 << lir::RegisterOperand)) { if (size > TargetBytesPerWord) { // can't move directly from FPR to GPR or vice-versa for // values larger than the GPR size if (dstMask.registerMask & FloatRegisterMask) { srcMask.registerMask = FloatRegisterMask | (static_cast(FloatRegisterMask) << 32); tmpMask.typeMask = 1 << lir::MemoryOperand; } else if (dstMask.registerMask & GeneralRegisterMask) { srcMask.registerMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32); tmpMask.typeMask = 1 << lir::MemoryOperand; } } if (dstMask.registerMask & FloatRegisterMask) { // can't move directly from constant to FPR srcMask.typeMask &= ~(1 << lir::ConstantOperand); if (size > TargetBytesPerWord) { tmpMask.typeMask = 1 << lir::MemoryOperand; } else { tmpMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); tmpMask.registerMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32); } } } } virtual void planSource (lir::TernaryOperation op, unsigned aSize, OperandMask& aMask, unsigned bSize, OperandMask& bMask, unsigned, bool* thunk) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::ConstantOperand); aMask.registerMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32); bMask.typeMask = (1 << lir::RegisterOperand); bMask.registerMask = GeneralRegisterMask | (static_cast(GeneralRegisterMask) << 32); *thunk = false; switch (op) { case lir::FloatAdd: case lir::FloatSubtract: case lir::FloatMultiply: case lir::FloatDivide: if (useSSE(&c)) { aMask.typeMask = (1 << lir::RegisterOperand) | (1 << lir::MemoryOperand); bMask.typeMask = (1 << lir::RegisterOperand); const uint64_t mask = (static_cast(FloatRegisterMask) << 32) | FloatRegisterMask; aMask.registerMask = mask; bMask.registerMask = mask; } else { *thunk = true; } break; case lir::FloatRemainder: *thunk = true; break; case lir::Multiply: if (TargetBytesPerWord == 4 and aSize == 8) { const uint32_t mask = GeneralRegisterMask & ~((1 << rax) | (1 << rdx)); aMask.registerMask = (static_cast(mask) << 32) | mask; bMask.registerMask = (static_cast(1) << (rdx + 32)) | mask; } else { aMask.registerMask = GeneralRegisterMask; bMask.registerMask = GeneralRegisterMask; } break; case lir::Divide: if (TargetBytesPerWord == 4 and aSize == 8) { *thunk = true; } else { aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = GeneralRegisterMask & ~((1 << rax) | (1 << rdx)); bMask.registerMask = 1 << rax; } break; case lir::Remainder: if (TargetBytesPerWord == 4 and aSize == 8) { *thunk = true; } else { aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = GeneralRegisterMask & ~((1 << rax) | (1 << rdx)); bMask.registerMask = 1 << rax; } break; case lir::ShiftLeft: case lir::ShiftRight: case lir::UnsignedShiftRight: { if (TargetBytesPerWord == 4 and bSize == 8) { const uint32_t mask = GeneralRegisterMask & ~(1 << rcx); aMask.registerMask = (static_cast(mask) << 32) | mask; bMask.registerMask = (static_cast(mask) << 32) | mask; } else { aMask.registerMask = (static_cast(GeneralRegisterMask) << 32) | (static_cast(1) << rcx); const uint32_t mask = GeneralRegisterMask & ~(1 << rcx); bMask.registerMask = (static_cast(mask) << 32) | mask; } } break; case lir::JumpIfFloatEqual: case lir::JumpIfFloatNotEqual: case lir::JumpIfFloatLess: case lir::JumpIfFloatGreater: case lir::JumpIfFloatLessOrEqual: case lir::JumpIfFloatGreaterOrEqual: case lir::JumpIfFloatLessOrUnordered: case lir::JumpIfFloatGreaterOrUnordered: case lir::JumpIfFloatLessOrEqualOrUnordered: case lir::JumpIfFloatGreaterOrEqualOrUnordered: if (useSSE(&c)) { aMask.typeMask = (1 << lir::RegisterOperand); aMask.registerMask = (static_cast(FloatRegisterMask) << 32) | FloatRegisterMask; bMask.typeMask = aMask.typeMask; bMask.registerMask = aMask.registerMask; } else { *thunk = true; } break; default: break; } } virtual void planDestination (lir::TernaryOperation op, unsigned, const OperandMask&, unsigned, const OperandMask& bMask, unsigned, OperandMask& cMask) { if (isBranch(op)) { cMask.typeMask = (1 << lir::ConstantOperand); cMask.registerMask = 0; } else { cMask.typeMask = (1 << lir::RegisterOperand); cMask.registerMask = bMask.registerMask; } } virtual Assembler* makeAssembler(util::Allocator* allocator, Zone* zone); virtual void acquire() { ++ referenceCount; } virtual void release() { if (-- referenceCount == 0) { c.s->free(this); } } ArchitectureContext c; unsigned referenceCount; const RegisterFile myRegisterFile; }; class MyAssembler: public Assembler { public: MyAssembler(System* s, util::Allocator* a, Zone* zone, MyArchitecture* arch) : c(s, a, zone, &(arch->c)), arch_(arch) { } virtual void setClient(Client* client) { assert(&c, c.client == 0); c.client = client; } virtual Architecture* arch() { return arch_; } virtual void checkStackOverflow(uintptr_t handler, unsigned stackLimitOffsetFromThread) { lir::Register stack(rsp); lir::Memory stackLimit(rbx, stackLimitOffsetFromThread); lir::Constant handlerConstant(resolvedPromise(&c, handler)); branchRM(&c, lir::JumpIfGreaterOrEqual, TargetBytesPerWord, &stack, &stackLimit, &handlerConstant); } virtual void saveFrame(unsigned stackOffset, unsigned) { lir::Register stack(rsp); lir::Memory stackDst(rbx, stackOffset); apply(lir::Move, OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &stack), OperandInfo(TargetBytesPerWord, lir::MemoryOperand, &stackDst)); } virtual void pushFrame(unsigned argumentCount, ...) { // TODO: Argument should be replaced by OperandInfo... struct Argument { unsigned size; lir::OperandType type; lir::Operand* operand; }; RUNTIME_ARRAY(Argument, arguments, argumentCount); va_list a; va_start(a, argumentCount); unsigned footprint = 0; for (unsigned i = 0; i < argumentCount; ++i) { RUNTIME_ARRAY_BODY(arguments)[i].size = va_arg(a, unsigned); RUNTIME_ARRAY_BODY(arguments)[i].type = static_cast(va_arg(a, int)); RUNTIME_ARRAY_BODY(arguments)[i].operand = va_arg(a, lir::Operand*); footprint += ceilingDivide (RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord); } va_end(a); allocateFrame(arch_->alignFrameSize(footprint)); unsigned offset = 0; for (unsigned i = 0; i < argumentCount; ++i) { if (i < arch_->argumentRegisterCount()) { lir::Register dst(arch_->argumentRegister(i)); apply(lir::Move, OperandInfo( RUNTIME_ARRAY_BODY(arguments)[i].size, RUNTIME_ARRAY_BODY(arguments)[i].type, RUNTIME_ARRAY_BODY(arguments)[i].operand), OperandInfo( pad(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord), lir::RegisterOperand, &dst)); } else { lir::Memory dst(rsp, offset * TargetBytesPerWord); apply(lir::Move, OperandInfo( RUNTIME_ARRAY_BODY(arguments)[i].size, RUNTIME_ARRAY_BODY(arguments)[i].type, RUNTIME_ARRAY_BODY(arguments)[i].operand), OperandInfo( pad(RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord), lir::MemoryOperand, &dst)); offset += ceilingDivide (RUNTIME_ARRAY_BODY(arguments)[i].size, TargetBytesPerWord); } } } virtual void allocateFrame(unsigned footprint) { lir::Register stack(rsp); if (UseFramePointer) { lir::Register base(rbp); pushR(&c, TargetBytesPerWord, &base); apply(lir::Move, OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &stack), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &base)); } lir::Constant footprintConstant(resolvedPromise(&c, footprint * TargetBytesPerWord)); apply(lir::Subtract, OperandInfo(TargetBytesPerWord, lir::ConstantOperand, &footprintConstant), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &stack), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &stack)); } virtual void adjustFrame(unsigned difference) { lir::Register stack(rsp); lir::Constant differenceConstant(resolvedPromise(&c, difference * TargetBytesPerWord)); apply(lir::Subtract, OperandInfo(TargetBytesPerWord, lir::ConstantOperand, &differenceConstant), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &stack), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &stack)); } virtual void popFrame(unsigned frameFootprint) { if (UseFramePointer) { lir::Register base(rbp); lir::Register stack(rsp); apply(lir::Move, OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &base), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &stack)); popR(&c, TargetBytesPerWord, &base); } else { lir::Register stack(rsp); lir::Constant footprint(resolvedPromise(&c, frameFootprint * TargetBytesPerWord)); apply(lir::Add, OperandInfo(TargetBytesPerWord, lir::ConstantOperand, &footprint), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &stack), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &stack)); } } virtual void popFrameForTailCall(unsigned frameFootprint, int offset, int returnAddressSurrogate, int framePointerSurrogate) { if (TailCalls) { if (offset) { lir::Register tmp(c.client->acquireTemporary()); unsigned baseSize = UseFramePointer ? 1 : 0; lir::Memory returnAddressSrc (rsp, (frameFootprint + baseSize) * TargetBytesPerWord); moveMR(&c, TargetBytesPerWord, &returnAddressSrc, TargetBytesPerWord, &tmp); lir::Memory returnAddressDst (rsp, (frameFootprint - offset + baseSize) * TargetBytesPerWord); moveRM(&c, TargetBytesPerWord, &tmp, TargetBytesPerWord, &returnAddressDst); c.client->releaseTemporary(tmp.low); if (UseFramePointer) { lir::Memory baseSrc(rsp, frameFootprint * TargetBytesPerWord); lir::Register base(rbp); moveMR(&c, TargetBytesPerWord, &baseSrc, TargetBytesPerWord, &base); } lir::Register stack(rsp); lir::Constant footprint (resolvedPromise (&c, (frameFootprint - offset + baseSize) * TargetBytesPerWord)); addCR(&c, TargetBytesPerWord, &footprint, TargetBytesPerWord, &stack); if (returnAddressSurrogate != lir::NoRegister) { assert(&c, offset > 0); lir::Register ras(returnAddressSurrogate); lir::Memory dst(rsp, offset * TargetBytesPerWord); moveRM(&c, TargetBytesPerWord, &ras, TargetBytesPerWord, &dst); } if (framePointerSurrogate != lir::NoRegister) { assert(&c, offset > 0); lir::Register fps(framePointerSurrogate); lir::Memory dst(rsp, (offset - 1) * TargetBytesPerWord); moveRM(&c, TargetBytesPerWord, &fps, TargetBytesPerWord, &dst); } } else { popFrame(frameFootprint); } } else { abort(&c); } } virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, unsigned argumentFootprint) { popFrame(frameFootprint); assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); if (TailCalls and argumentFootprint > StackAlignmentInWords) { lir::Register returnAddress(rcx); popR(&c, TargetBytesPerWord, &returnAddress); lir::Register stack(rsp); lir::Constant adjustment (resolvedPromise(&c, (argumentFootprint - StackAlignmentInWords) * TargetBytesPerWord)); addCR(&c, TargetBytesPerWord, &adjustment, TargetBytesPerWord, &stack); jumpR(&c, TargetBytesPerWord, &returnAddress); } else { return_(&c); } } virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, unsigned stackOffsetFromThread) { popFrame(frameFootprint); lir::Register returnAddress(rcx); popR(&c, TargetBytesPerWord, &returnAddress); lir::Register stack(rsp); lir::Memory stackSrc(rbx, stackOffsetFromThread); moveMR(&c, TargetBytesPerWord, &stackSrc, TargetBytesPerWord, &stack); jumpR(&c, TargetBytesPerWord, &returnAddress); } virtual void apply(lir::Operation op) { arch_->c.operations[op](&c); } virtual void apply(lir::UnaryOperation op, OperandInfo a) { arch_->c.unaryOperations[Multimethod::index(op, a.type)] (&c, a.size, a.operand); } virtual void apply(lir::BinaryOperation op, OperandInfo a, OperandInfo b) { arch_->c.binaryOperations[index(&(arch_->c), op, a.type, b.type)] (&c, a.size, a.operand, b.size, b.operand); } virtual void apply(lir::TernaryOperation op, OperandInfo a, OperandInfo b, OperandInfo c) { if (isBranch(op)) { assert(&this->c, a.size == b.size); assert(&this->c, c.size == TargetBytesPerWord); assert(&this->c, c.type == lir::ConstantOperand); arch_->c.branchOperations[branchIndex(&(arch_->c), a.type, b.type)] (&this->c, op, a.size, a.operand, b.operand, c.operand); } else { assert(&this->c, b.size == c.size); assert(&this->c, b.type == c.type); arch_->c.binaryOperations[index(&(arch_->c), op, a.type, b.type)] (&this->c, a.size, a.operand, b.size, b.operand); } } virtual void setDestination(uint8_t* dst) { c.result = dst; } virtual void write() { uint8_t* dst = c.result; for (MyBlock* b = c.firstBlock; b; b = b->next) { unsigned index = 0; unsigned padding = 0; for (AlignmentPadding* p = b->firstPadding; p; p = p->next) { unsigned size = p->offset - b->offset - index; memcpy(dst + b->start + index + padding, c.code.data.begin() + b->offset + index, size); index += size; while ((b->start + index + padding + p->instructionOffset) % p->alignment) { *(dst + b->start + index + padding) = 0x90; ++ padding; } } memcpy(dst + b->start + index + padding, c.code.data.begin() + b->offset + index, b->size - index); } for (Task* t = c.tasks; t; t = t->next) { t->run(&c); } } virtual Promise* offset(bool) { return x86::offsetPromise(&c); } virtual Block* endBlock(bool startNew) { MyBlock* b = c.lastBlock; b->size = c.code.length() - b->offset; if (startNew) { c.lastBlock = new(c.zone) MyBlock(c.code.length()); } else { c.lastBlock = 0; } return b; } virtual void endEvent() { // ignore } virtual unsigned length() { return c.code.length(); } virtual unsigned footerSize() { return 0; } virtual void dispose() { c.code.dispose(); } Context c; MyArchitecture* arch_; }; Assembler* MyArchitecture::makeAssembler(util::Allocator* allocator, Zone* zone) { return new(zone) MyAssembler(c.s, allocator, zone, this); } } // namespace x86 Architecture* makeArchitectureX86(System* system, bool useNativeFeatures) { return new (allocate(system, sizeof(x86::MyArchitecture))) x86::MyArchitecture(system, useNativeFeatures); } } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/x86/block.cpp000066400000000000000000000017001231440243200230620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "block.h" #include namespace avian { namespace codegen { namespace x86 { unsigned padding(AlignmentPadding* p, unsigned index, unsigned offset, AlignmentPadding* limit); MyBlock::MyBlock(unsigned offset): next(0), firstPadding(0), lastPadding(0), offset(offset), start(~0), size(0) { } unsigned MyBlock::resolve(unsigned start, Assembler::Block* next) { this->start = start; this->next = static_cast(next); return start + size + padding(firstPadding, start, offset, lastPadding); } } // namespace x86 } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/x86/block.h000066400000000000000000000016761231440243200225430ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_X86_BLOCK_H #define AVIAN_CODEGEN_ASSEMBLER_X86_BLOCK_H #include namespace avian { namespace codegen { namespace x86 { class AlignmentPadding; class MyBlock: public Assembler::Block { public: MyBlock(unsigned offset); virtual unsigned resolve(unsigned start, Assembler::Block* next); MyBlock* next; AlignmentPadding* firstPadding; AlignmentPadding* lastPadding; unsigned offset; unsigned start; unsigned size; }; } // namespace x86 } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_X86_BLOCK_H ReadyTalk-avian-1e1fff5/src/codegen/target/x86/context.cpp000066400000000000000000000020141231440243200234530ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/util/allocator.h" #include "avian/zone.h" #include "context.h" #include "block.h" namespace avian { namespace codegen { namespace x86 { ArchitectureContext::ArchitectureContext(vm::System* s, bool useNativeFeatures): s(s), useNativeFeatures(useNativeFeatures) { } Context::Context(vm::System* s, util::Allocator* a, vm::Zone* zone, ArchitectureContext* ac) : s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), firstBlock(new (zone) MyBlock(0)), lastBlock(firstBlock), ac(ac) { } } // namespace x86 } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/x86/context.h000066400000000000000000000050041231440243200231220ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_X86_CONTEXT_H #define AVIAN_CODEGEN_ASSEMBLER_X86_CONTEXT_H #define CAST1(x) reinterpret_cast(x) #define CAST2(x) reinterpret_cast(x) #define CAST_BRANCH(x) reinterpret_cast(x) #include #include "avian/alloc-vector.h" #include #include #include namespace vm { class System; class Allocator; class Zone; } // namespace vm namespace avian { namespace util { class Aborter; } // namespace util namespace codegen { namespace x86 { class Context; class MyBlock; class Task; typedef void (*OperationType)(Context*); typedef void (*UnaryOperationType)(Context*, unsigned, lir::Operand*); typedef void (*BinaryOperationType) (Context*, unsigned, lir::Operand*, unsigned, lir::Operand*); typedef void (*BranchOperationType) (Context*, lir::TernaryOperation, unsigned, lir::Operand*, lir::Operand*, lir::Operand*); class ArchitectureContext { public: ArchitectureContext(vm::System* s, bool useNativeFeatures); vm::System* s; bool useNativeFeatures; OperationType operations[lir::OperationCount]; UnaryOperationType unaryOperations[lir::UnaryOperationCount * lir::OperandTypeCount]; BinaryOperationType binaryOperations [(lir::BinaryOperationCount + lir::NonBranchTernaryOperationCount) * lir::OperandTypeCount * lir::OperandTypeCount]; BranchOperationType branchOperations [lir::BranchOperationCount * lir::OperandTypeCount * lir::OperandTypeCount]; }; class Context { public: Context(vm::System* s, util::Allocator* a, vm::Zone* zone, ArchitectureContext* ac); vm::System* s; vm::Zone* zone; Assembler::Client* client; vm::Vector code; Task* tasks; uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; ArchitectureContext* ac; }; inline avian::util::Aborter* getAborter(Context* c) { return c->s; } inline avian::util::Aborter* getAborter(ArchitectureContext* c) { return c->s; } } // namespace x86 } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_X86_CONTEXT_H ReadyTalk-avian-1e1fff5/src/codegen/target/x86/detect.cpp000066400000000000000000000017111231440243200232420ustar00rootroot00000000000000 /* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include "context.h" namespace avian { namespace codegen { namespace x86 { extern "C" bool detectFeature(unsigned ecx, unsigned edx); bool useSSE(ArchitectureContext* c) { if (vm::TargetBytesPerWord == 8) { // amd64 implies SSE2 support return true; } else if (c->useNativeFeatures) { static int supported = -1; if (supported == -1) { supported = detectFeature(0, 0x2000000) // SSE 1 and detectFeature(0, 0x4000000); // SSE 2 } return supported; } else { return false; } } } // namespace x86 } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/x86/detect.h000066400000000000000000000013101231440243200227020ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_X86_DETECT_H #define AVIAN_CODEGEN_ASSEMBLER_X86_DETECT_H #include namespace avian { namespace codegen { namespace x86 { class ArchitectureContext; bool useSSE(ArchitectureContext* c); } // namespace x86 } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_X86_DETECT_H ReadyTalk-avian-1e1fff5/src/codegen/target/x86/encode.cpp000066400000000000000000000221471231440243200232350ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include "avian/alloc-vector.h" #include #include #include #include #include "context.h" #include "encode.h" #include "registers.h" #include "fixup.h" using namespace avian::util; namespace { int64_t signExtend(unsigned size, int64_t v) { if (size == 4) { return static_cast(v); } else if (size == 2) { return static_cast(v); } else if (size == 1) { return static_cast(v); } else { return v; } } } // namespace namespace avian { namespace codegen { namespace x86 { #define REX_W 0x48 #define REX_R 0x44 #define REX_X 0x42 #define REX_B 0x41 #define REX_NONE 0x40 void maybeRex(Context* c, unsigned size, int a, int index, int base, bool always) { if (vm::TargetBytesPerWord == 8) { uint8_t byte; if (size == 8) { byte = REX_W; } else { byte = REX_NONE; } if (a != lir::NoRegister and (a & 8)) byte |= REX_R; if (index != lir::NoRegister and (index & 8)) byte |= REX_X; if (base != lir::NoRegister and (base & 8)) byte |= REX_B; if (always or byte != REX_NONE) c->code.append(byte); } } void maybeRex(Context* c, unsigned size, lir::Register* a, lir::Register* b) { maybeRex(c, size, a->low, lir::NoRegister, b->low, false); } void alwaysRex(Context* c, unsigned size, lir::Register* a, lir::Register* b) { maybeRex(c, size, a->low, lir::NoRegister, b->low, true); } void maybeRex(Context* c, unsigned size, lir::Register* a) { maybeRex(c, size, lir::NoRegister, lir::NoRegister, a->low, false); } void maybeRex(Context* c, unsigned size, lir::Register* a, lir::Memory* b) { maybeRex(c, size, a->low, b->index, b->base, size == 1 and (a->low & 4)); } void maybeRex(Context* c, unsigned size, lir::Memory* a) { maybeRex(c, size, lir::NoRegister, a->index, a->base, false); } void modrm(Context* c, uint8_t mod, int a, int b) { c->code.append(mod | (regCode(b) << 3) | regCode(a)); } void modrm(Context* c, uint8_t mod, lir::Register* a, lir::Register* b) { modrm(c, mod, a->low, b->low); } void sib(Context* c, unsigned scale, int index, int base) { c->code.append((util::log(scale) << 6) | (regCode(index) << 3) | regCode(base)); } void modrmSib(Context* c, int width, int a, int scale, int index, int base) { if (index == lir::NoRegister) { modrm(c, width, base, a); if (regCode(base) == rsp) { sib(c, 0x00, rsp, rsp); } } else { modrm(c, width, rsp, a); sib(c, scale, index, base); } } void modrmSibImm(Context* c, int a, int scale, int index, int base, int offset) { if (offset == 0 and regCode(base) != rbp) { modrmSib(c, 0x00, a, scale, index, base); } else if (vm::fitsInInt8(offset)) { modrmSib(c, 0x40, a, scale, index, base); c->code.append(offset); } else { modrmSib(c, 0x80, a, scale, index, base); c->code.append4(offset); } } void modrmSibImm(Context* c, lir::Register* a, lir::Memory* b) { modrmSibImm(c, a->low, b->scale, b->index, b->base, b->offset); } void opcode(Context* c, uint8_t op) { c->code.append(op); } void opcode(Context* c, uint8_t op1, uint8_t op2) { c->code.append(op1); c->code.append(op2); } void unconditional(Context* c, unsigned jump, lir::Constant* a) { appendOffsetTask(c, a->value, offsetPromise(c), 5); opcode(c, jump); c->code.append4(0); } void conditional(Context* c, unsigned condition, lir::Constant* a) { appendOffsetTask(c, a->value, offsetPromise(c), 6); opcode(c, 0x0f, condition); c->code.append4(0); } void sseMoveRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize >= 4); assert(c, aSize == bSize); if (isFloatReg(a) and isFloatReg(b)) { if (aSize == 4) { opcode(c, 0xf3); maybeRex(c, 4, a, b); opcode(c, 0x0f, 0x10); modrm(c, 0xc0, a, b); } else { opcode(c, 0xf2); maybeRex(c, 4, b, a); opcode(c, 0x0f, 0x10); modrm(c, 0xc0, a, b); } } else if (isFloatReg(a)) { opcode(c, 0x66); maybeRex(c, aSize, a, b); opcode(c, 0x0f, 0x7e); modrm(c, 0xc0, b, a); } else { opcode(c, 0x66); maybeRex(c, aSize, b, a); opcode(c, 0x0f, 0x6e); modrm(c, 0xc0, a, b); } } void sseMoveCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(c, aSize <= vm::TargetBytesPerWord); lir::Register tmp(c->client->acquireTemporary(GeneralRegisterMask)); moveCR2(c, aSize, a, aSize, &tmp, 0); sseMoveRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } void sseMoveMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize >= 4); if (vm::TargetBytesPerWord == 4 and aSize == 8) { opcode(c, 0xf3); opcode(c, 0x0f, 0x7e); modrmSibImm(c, b, a); } else { opcode(c, 0x66); maybeRex(c, aSize, b, a); opcode(c, 0x0f, 0x6e); modrmSibImm(c, b, a); } } void sseMoveRM(Context* c, unsigned aSize, lir::Register* a, UNUSED unsigned bSize, lir::Memory* b) { assert(c, aSize >= 4); assert(c, aSize == bSize); if (vm::TargetBytesPerWord == 4 and aSize == 8) { opcode(c, 0x66); opcode(c, 0x0f, 0xd6); modrmSibImm(c, a, b); } else { opcode(c, 0x66); maybeRex(c, aSize, a, b); opcode(c, 0x0f, 0x7e); modrmSibImm(c, a, b); } } void branch(Context* c, lir::TernaryOperation op, lir::Constant* target) { switch (op) { case lir::JumpIfEqual: conditional(c, 0x84, target); break; case lir::JumpIfNotEqual: conditional(c, 0x85, target); break; case lir::JumpIfLess: conditional(c, 0x8c, target); break; case lir::JumpIfGreater: conditional(c, 0x8f, target); break; case lir::JumpIfLessOrEqual: conditional(c, 0x8e, target); break; case lir::JumpIfGreaterOrEqual: conditional(c, 0x8d, target); break; default: abort(c); } } void branchFloat(Context* c, lir::TernaryOperation op, lir::Constant* target) { switch (op) { case lir::JumpIfFloatEqual: // jp past the je so we don't jump to the target if unordered: c->code.append(0x7a); c->code.append(6); conditional(c, 0x84, target); break; case lir::JumpIfFloatNotEqual: conditional(c, 0x85, target); conditional(c, 0x8a, target); break; case lir::JumpIfFloatLess: conditional(c, 0x82, target); break; case lir::JumpIfFloatGreater: conditional(c, 0x87, target); break; case lir::JumpIfFloatLessOrEqual: conditional(c, 0x86, target); break; case lir::JumpIfFloatGreaterOrEqual: conditional(c, 0x83, target); break; case lir::JumpIfFloatLessOrUnordered: conditional(c, 0x82, target); conditional(c, 0x8a, target); break; case lir::JumpIfFloatGreaterOrUnordered: conditional(c, 0x87, target); conditional(c, 0x8a, target); break; case lir::JumpIfFloatLessOrEqualOrUnordered: conditional(c, 0x86, target); conditional(c, 0x8a, target); break; case lir::JumpIfFloatGreaterOrEqualOrUnordered: conditional(c, 0x83, target); conditional(c, 0x8a, target); break; default: abort(c); } } void floatRegOp(Context* c, unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b, uint8_t op, uint8_t mod) { if (aSize == 4) { opcode(c, 0xf3); } else { opcode(c, 0xf2); } maybeRex(c, bSize, b, a); opcode(c, 0x0f, op); modrm(c, mod, a, b); } void floatMemOp(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize, lir::Register* b, uint8_t op) { if (aSize == 4) { opcode(c, 0xf3); } else { opcode(c, 0xf2); } maybeRex(c, bSize, b, a); opcode(c, 0x0f, op); modrmSibImm(c, b, a); } void moveCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void moveCR2(Context* c, UNUSED unsigned aSize, lir::Constant* a, UNUSED unsigned bSize, lir::Register* b, unsigned promiseOffset) { if (vm::TargetBytesPerWord == 4 and bSize == 8) { int64_t v = signExtend(aSize, a->value->value()); ResolvedPromise high((v >> 32) & 0xFFFFFFFF); lir::Constant ah(&high); ResolvedPromise low(v & 0xFFFFFFFF); lir::Constant al(&low); lir::Register bh(b->high); moveCR(c, 4, &al, 4, b); moveCR(c, 4, &ah, 4, &bh); } else { maybeRex(c, vm::TargetBytesPerWord, b); opcode(c, 0xb8 + regCode(b)); if (a->value->resolved()) { c->code.appendTargetAddress(signExtend(aSize, a->value->value())); } else { expect(c, aSize == vm::TargetBytesPerWord); appendImmediateTask (c, a->value, offsetPromise(c), vm::TargetBytesPerWord, promiseOffset); c->code.appendTargetAddress(static_cast(0)); } } } } // namespace x86 } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/x86/encode.h000066400000000000000000000056561231440243200227100ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_X86_ENCODE_H #define AVIAN_CODEGEN_ASSEMBLER_X86_ENCODE_H #include #include "avian/common.h" #include #include "registers.h" namespace avian { namespace codegen { namespace x86 { class Context; void maybeRex(Context* c, unsigned size, int a, int index, int base, bool always); void maybeRex(Context* c, unsigned size, lir::Register* a, lir::Register* b); void alwaysRex(Context* c, unsigned size, lir::Register* a, lir::Register* b); void maybeRex(Context* c, unsigned size, lir::Register* a); void maybeRex(Context* c, unsigned size, lir::Register* a, lir::Memory* b); void maybeRex(Context* c, unsigned size, lir::Memory* a); inline int regCode(int a) { return a & 7; } inline int regCode(lir::Register* a) { return regCode(a->low); } inline bool isFloatReg(lir::Register* a) { return a->low >= xmm0; } void modrm(Context* c, uint8_t mod, int a, int b); void modrm(Context* c, uint8_t mod, lir::Register* a, lir::Register* b); void sib(Context* c, unsigned scale, int index, int base); void modrmSib(Context* c, int width, int a, int scale, int index, int base); void modrmSibImm(Context* c, int a, int scale, int index, int base, int offset); void modrmSibImm(Context* c, lir::Register* a, lir::Memory* b); void opcode(Context* c, uint8_t op); void opcode(Context* c, uint8_t op1, uint8_t op2); void unconditional(Context* c, unsigned jump, lir::Constant* a); void conditional(Context* c, unsigned condition, lir::Constant* a); void sseMoveRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void sseMoveCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void sseMoveMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b); void sseMoveRM(Context* c, unsigned aSize, lir::Register* a, UNUSED unsigned bSize, lir::Memory* b); void branch(Context* c, lir::TernaryOperation op, lir::Constant* target); void branchFloat(Context* c, lir::TernaryOperation op, lir::Constant* target); void floatRegOp(Context* c, unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b, uint8_t op, uint8_t mod = 0xc0); void floatMemOp(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize, lir::Register* b, uint8_t op); void moveCR2(Context* c, UNUSED unsigned aSize, lir::Constant* a, UNUSED unsigned bSize, lir::Register* b, unsigned promiseOffset); } // namespace x86 } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_X86_ENCODE_H ReadyTalk-avian-1e1fff5/src/codegen/target/x86/fixup.cpp000066400000000000000000000107161231440243200231320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include "avian/util/allocator.h" #include "avian/alloc-vector.h" #include "avian/common.h" #include "avian/zone.h" #include #include #include "context.h" #include "fixup.h" #include "padding.h" #include "block.h" namespace avian { namespace codegen { namespace x86 { using namespace util; ResolvedPromise* resolvedPromise(Context* c, int64_t value) { return new(c->zone) ResolvedPromise(value); } OffsetPromise::OffsetPromise(Context* c, MyBlock* block, unsigned offset, AlignmentPadding* limit): c(c), block(block), offset(offset), limit(limit), value_(-1) { } bool OffsetPromise::resolved() { return block->start != static_cast(~0); } int64_t OffsetPromise::value() { assert(c, resolved()); if (value_ == -1) { value_ = block->start + (offset - block->offset) + padding(block->firstPadding, block->start, block->offset, limit); } return value_; } Promise* offsetPromise(Context* c) { return new(c->zone) OffsetPromise(c, c->lastBlock, c->code.length(), c->lastBlock->lastPadding); } void* resolveOffset(vm::System* s, uint8_t* instruction, unsigned instructionSize, int64_t value) { intptr_t v = reinterpret_cast(value) - instruction - instructionSize; expect(s, vm::fitsInInt32(v)); int32_t v4 = v; memcpy(instruction + instructionSize - 4, &v4, 4); return instruction + instructionSize; } OffsetListener::OffsetListener(vm::System* s, uint8_t* instruction, unsigned instructionSize): s(s), instruction(instruction), instructionSize(instructionSize) { } bool OffsetListener::resolve(int64_t value, void** location) { void* p = resolveOffset(s, instruction, instructionSize, value); if (location) *location = p; return false; } OffsetTask::OffsetTask(Task* next, Promise* promise, Promise* instructionOffset, unsigned instructionSize): Task(next), promise(promise), instructionOffset(instructionOffset), instructionSize(instructionSize) { } void OffsetTask::run(Context* c) { if (promise->resolved()) { resolveOffset (c->s, c->result + instructionOffset->value(), instructionSize, promise->value()); } else { new (promise->listen(sizeof(OffsetListener))) OffsetListener(c->s, c->result + instructionOffset->value(), instructionSize); } } void appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, unsigned instructionSize) { OffsetTask* task = new(c->zone) OffsetTask(c->tasks, promise, instructionOffset, instructionSize); c->tasks = task; } ImmediateListener::ImmediateListener(vm::System* s, void* dst, unsigned size, unsigned offset): s(s), dst(dst), size(size), offset(offset) { } void copy(vm::System* s, void* dst, int64_t src, unsigned size) { switch (size) { case 4: { int32_t v = src; memcpy(dst, &v, 4); } break; case 8: { int64_t v = src; memcpy(dst, &v, 8); } break; default: abort(s); } } bool ImmediateListener::resolve(int64_t value, void** location) { copy(s, dst, value, size); if (location) *location = static_cast(dst) + offset; return offset == 0; } ImmediateTask::ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset): Task(next), promise(promise), offset(offset), size(size), promiseOffset(promiseOffset) { } void ImmediateTask::run(Context* c) { if (promise->resolved()) { copy(c->s, c->result + offset->value(), promise->value(), size); } else { new (promise->listen(sizeof(ImmediateListener))) ImmediateListener (c->s, c->result + offset->value(), size, promiseOffset); } } void appendImmediateTask(Context* c, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset) { c->tasks = new(c->zone) ImmediateTask (c->tasks, promise, offset, size, promiseOffset); } ShiftMaskPromise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask) { return new(c->zone) ShiftMaskPromise(base, shift, mask); } } // namespace x86 } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/x86/fixup.h000066400000000000000000000053151231440243200225760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_X86_FIXUP_H #define AVIAN_CODEGEN_ASSEMBLER_X86_FIXUP_H #include #include namespace vm { class System; } namespace avian { namespace codegen { namespace x86 { class Context; class MyBlock; class AlignmentPadding; ResolvedPromise* resolvedPromise(Context* c, int64_t value); class Task { public: Task(Task* next): next(next) { } virtual void run(Context* c) = 0; Task* next; }; class OffsetPromise: public Promise { public: OffsetPromise(Context* c, MyBlock* block, unsigned offset, AlignmentPadding* limit); virtual bool resolved(); virtual int64_t value(); Context* c; MyBlock* block; unsigned offset; AlignmentPadding* limit; int value_; }; Promise* offsetPromise(Context* c); void* resolveOffset(vm::System* s, uint8_t* instruction, unsigned instructionSize, int64_t value); class OffsetListener: public Promise::Listener { public: OffsetListener(vm::System* s, uint8_t* instruction, unsigned instructionSize); virtual bool resolve(int64_t value, void** location); vm::System* s; uint8_t* instruction; unsigned instructionSize; }; class OffsetTask: public Task { public: OffsetTask(Task* next, Promise* promise, Promise* instructionOffset, unsigned instructionSize); virtual void run(Context* c); Promise* promise; Promise* instructionOffset; unsigned instructionSize; }; void appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, unsigned instructionSize); class ImmediateListener: public Promise::Listener { public: ImmediateListener(vm::System* s, void* dst, unsigned size, unsigned offset); virtual bool resolve(int64_t value, void** location); vm::System* s; void* dst; unsigned size; unsigned offset; }; class ImmediateTask: public Task { public: ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset); virtual void run(Context* c); Promise* promise; Promise* offset; unsigned size; unsigned promiseOffset; }; void appendImmediateTask(Context* c, Promise* promise, Promise* offset, unsigned size, unsigned promiseOffset = 0); ShiftMaskPromise* shiftMaskPromise(Context* c, Promise* base, unsigned shift, int64_t mask); } // namespace x86 } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_X86_FIXUP_H ReadyTalk-avian-1e1fff5/src/codegen/target/x86/multimethod.cpp000066400000000000000000000136411231440243200243320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/common.h" #include #include #include "context.h" #include "operations.h" #include "multimethod.h" #include "../multimethod.h" namespace avian { namespace codegen { namespace x86 { using namespace util; unsigned index(ArchitectureContext*, lir::BinaryOperation operation, lir::OperandType operand1, lir::OperandType operand2) { return operation + ((lir::BinaryOperationCount + lir::NonBranchTernaryOperationCount) * operand1) + ((lir::BinaryOperationCount + lir::NonBranchTernaryOperationCount) * lir::OperandTypeCount * operand2); } unsigned index(ArchitectureContext* c UNUSED, lir::TernaryOperation operation, lir::OperandType operand1, lir::OperandType operand2) { assert(c, not isBranch(operation)); return lir::BinaryOperationCount + operation + ((lir::BinaryOperationCount + lir::NonBranchTernaryOperationCount) * operand1) + ((lir::BinaryOperationCount + lir::NonBranchTernaryOperationCount) * lir::OperandTypeCount * operand2); } unsigned branchIndex(ArchitectureContext* c UNUSED, lir::OperandType operand1, lir::OperandType operand2) { return operand1 + (lir::OperandTypeCount * operand2); } void populateTables(ArchitectureContext* c) { const lir::OperandType C = lir::ConstantOperand; const lir::OperandType A = lir::AddressOperand; const lir::OperandType R = lir::RegisterOperand; const lir::OperandType M = lir::MemoryOperand; OperationType* zo = c->operations; UnaryOperationType* uo = c->unaryOperations; BinaryOperationType* bo = c->binaryOperations; BranchOperationType* bro = c->branchOperations; zo[lir::Return] = return_; zo[lir::LoadBarrier] = ignore; zo[lir::StoreStoreBarrier] = ignore; zo[lir::StoreLoadBarrier] = storeLoadBarrier; zo[lir::Trap] = trap; uo[Multimethod::index(lir::Call, C)] = CAST1(callC); uo[Multimethod::index(lir::Call, R)] = CAST1(callR); uo[Multimethod::index(lir::Call, M)] = CAST1(callM); uo[Multimethod::index(lir::AlignedCall, C)] = CAST1(alignedCallC); uo[Multimethod::index(lir::LongCall, C)] = CAST1(longCallC); uo[Multimethod::index(lir::AlignedLongCall, C)] = CAST1(alignedLongCallC); uo[Multimethod::index(lir::Jump, R)] = CAST1(jumpR); uo[Multimethod::index(lir::Jump, C)] = CAST1(jumpC); uo[Multimethod::index(lir::Jump, M)] = CAST1(jumpM); uo[Multimethod::index(lir::AlignedJump, C)] = CAST1(alignedJumpC); uo[Multimethod::index(lir::LongJump, C)] = CAST1(longJumpC); uo[Multimethod::index(lir::AlignedLongJump, C)] = CAST1(alignedLongJumpC); bo[index(c, lir::Negate, R, R)] = CAST2(negateRR); bo[index(c, lir::FloatNegate, R, R)] = CAST2(floatNegateRR); bo[index(c, lir::Move, R, R)] = CAST2(moveRR); bo[index(c, lir::Move, C, R)] = CAST2(moveCR); bo[index(c, lir::Move, M, R)] = CAST2(moveMR); bo[index(c, lir::Move, R, M)] = CAST2(moveRM); bo[index(c, lir::Move, C, M)] = CAST2(moveCM); bo[index(c, lir::Move, A, R)] = CAST2(moveAR); bo[index(c, lir::FloatSquareRoot, R, R)] = CAST2(floatSqrtRR); bo[index(c, lir::FloatSquareRoot, M, R)] = CAST2(floatSqrtMR); bo[index(c, lir::MoveZ, R, R)] = CAST2(moveZRR); bo[index(c, lir::MoveZ, M, R)] = CAST2(moveZMR); bo[index(c, lir::MoveZ, C, R)] = CAST2(moveZCR); bo[index(c, lir::Add, R, R)] = CAST2(addRR); bo[index(c, lir::Add, C, R)] = CAST2(addCR); bo[index(c, lir::Subtract, C, R)] = CAST2(subtractCR); bo[index(c, lir::Subtract, R, R)] = CAST2(subtractRR); bo[index(c, lir::FloatAdd, R, R)] = CAST2(floatAddRR); bo[index(c, lir::FloatAdd, M, R)] = CAST2(floatAddMR); bo[index(c, lir::FloatSubtract, R, R)] = CAST2(floatSubtractRR); bo[index(c, lir::FloatSubtract, M, R)] = CAST2(floatSubtractMR); bo[index(c, lir::And, R, R)] = CAST2(andRR); bo[index(c, lir::And, C, R)] = CAST2(andCR); bo[index(c, lir::Or, R, R)] = CAST2(orRR); bo[index(c, lir::Or, C, R)] = CAST2(orCR); bo[index(c, lir::Xor, R, R)] = CAST2(xorRR); bo[index(c, lir::Xor, C, R)] = CAST2(xorCR); bo[index(c, lir::Multiply, R, R)] = CAST2(multiplyRR); bo[index(c, lir::Multiply, C, R)] = CAST2(multiplyCR); bo[index(c, lir::Divide, R, R)] = CAST2(divideRR); bo[index(c, lir::FloatMultiply, R, R)] = CAST2(floatMultiplyRR); bo[index(c, lir::FloatMultiply, M, R)] = CAST2(floatMultiplyMR); bo[index(c, lir::FloatDivide, R, R)] = CAST2(floatDivideRR); bo[index(c, lir::FloatDivide, M, R)] = CAST2(floatDivideMR); bo[index(c, lir::Remainder, R, R)] = CAST2(remainderRR); bo[index(c, lir::ShiftLeft, R, R)] = CAST2(shiftLeftRR); bo[index(c, lir::ShiftLeft, C, R)] = CAST2(shiftLeftCR); bo[index(c, lir::ShiftRight, R, R)] = CAST2(shiftRightRR); bo[index(c, lir::ShiftRight, C, R)] = CAST2(shiftRightCR); bo[index(c, lir::UnsignedShiftRight, R, R)] = CAST2(unsignedShiftRightRR); bo[index(c, lir::UnsignedShiftRight, C, R)] = CAST2(unsignedShiftRightCR); bo[index(c, lir::Float2Float, R, R)] = CAST2(float2FloatRR); bo[index(c, lir::Float2Float, M, R)] = CAST2(float2FloatMR); bo[index(c, lir::Float2Int, R, R)] = CAST2(float2IntRR); bo[index(c, lir::Float2Int, M, R)] = CAST2(float2IntMR); bo[index(c, lir::Int2Float, R, R)] = CAST2(int2FloatRR); bo[index(c, lir::Int2Float, M, R)] = CAST2(int2FloatMR); bo[index(c, lir::Absolute, R, R)] = CAST2(absoluteRR); bo[index(c, lir::FloatAbsolute, R, R)] = CAST2(floatAbsoluteRR); bro[branchIndex(c, R, R)] = CAST_BRANCH(branchRR); bro[branchIndex(c, C, R)] = CAST_BRANCH(branchCR); bro[branchIndex(c, C, M)] = CAST_BRANCH(branchCM); bro[branchIndex(c, R, M)] = CAST_BRANCH(branchRM); } } // namespace x86 } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/x86/multimethod.h000066400000000000000000000022021231440243200237660ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_X86_MULTIMETHOD_H #define AVIAN_CODEGEN_ASSEMBLER_X86_MULTIMETHOD_H #include "avian/common.h" #include namespace avian { namespace codegen { namespace x86 { class ArchitectureContext; unsigned index(ArchitectureContext*, lir::BinaryOperation operation, lir::OperandType operand1, lir::OperandType operand2); unsigned index(ArchitectureContext* c UNUSED, lir::TernaryOperation operation, lir::OperandType operand1, lir::OperandType operand2); unsigned branchIndex(ArchitectureContext* c UNUSED, lir::OperandType operand1, lir::OperandType operand2); void populateTables(ArchitectureContext* c); } // namespace x86 } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_X86_MULTIMETHOD_H ReadyTalk-avian-1e1fff5/src/codegen/target/x86/operations.cpp000066400000000000000000001135301231440243200241600ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/target.h" #include "avian/alloc-vector.h" #include "avian/util/allocator.h" #include "avian/zone.h" #include #include #include #include "context.h" #include "encode.h" #include "registers.h" #include "detect.h" #include "operations.h" #include "padding.h" #include "fixup.h" using namespace avian::util; namespace avian { namespace codegen { namespace x86 { void return_(Context* c) { opcode(c, 0xc3); } void trap(Context* c) { opcode(c, 0xcc); } void ignore(Context*) { } void storeLoadBarrier(Context* c) { if (useSSE(c->ac)) { // mfence: c->code.append(0x0f); c->code.append(0xae); c->code.append(0xf0); } else { // lock addq $0x0,(%rsp): c->code.append(0xf0); if (vm::TargetBytesPerWord == 8) { c->code.append(0x48); } c->code.append(0x83); c->code.append(0x04); c->code.append(0x24); c->code.append(0x00); } } void callC(Context* c, unsigned size UNUSED, lir::Constant* a) { assert(c, size == vm::TargetBytesPerWord); unconditional(c, 0xe8, a); } void longCallC(Context* c, unsigned size, lir::Constant* a) { assert(c, size == vm::TargetBytesPerWord); if (vm::TargetBytesPerWord == 8) { lir::Register r(LongJumpRegister); moveCR2(c, size, a, size, &r, 11); callR(c, size, &r); } else { callC(c, size, a); } } void jumpR(Context* c, unsigned size UNUSED, lir::Register* a) { assert(c, size == vm::TargetBytesPerWord); maybeRex(c, 4, a); opcode(c, 0xff, 0xe0 + regCode(a)); } void jumpC(Context* c, unsigned size UNUSED, lir::Constant* a) { assert(c, size == vm::TargetBytesPerWord); unconditional(c, 0xe9, a); } void jumpM(Context* c, unsigned size UNUSED, lir::Memory* a) { assert(c, size == vm::TargetBytesPerWord); maybeRex(c, 4, a); opcode(c, 0xff); modrmSibImm(c, rsp, a->scale, a->index, a->base, a->offset); } void longJumpC(Context* c, unsigned size, lir::Constant* a) { assert(c, size == vm::TargetBytesPerWord); if (vm::TargetBytesPerWord == 8) { lir::Register r(LongJumpRegister); moveCR2(c, size, a, size, &r, 11); jumpR(c, size, &r); } else { jumpC(c, size, a); } } void callR(Context* c, unsigned size UNUSED, lir::Register* a) { assert(c, size == vm::TargetBytesPerWord); // maybeRex.W has no meaning here so we disable it maybeRex(c, 4, a); opcode(c, 0xff, 0xd0 + regCode(a)); } void callM(Context* c, unsigned size UNUSED, lir::Memory* a) { assert(c, size == vm::TargetBytesPerWord); maybeRex(c, 4, a); opcode(c, 0xff); modrmSibImm(c, rdx, a->scale, a->index, a->base, a->offset); } void alignedCallC(Context* c, unsigned size, lir::Constant* a) { new(c->zone) AlignmentPadding(c, 1, 4); callC(c, size, a); } void alignedLongCallC(Context* c, unsigned size, lir::Constant* a) { assert(c, size == vm::TargetBytesPerWord); if (vm::TargetBytesPerWord == 8) { new (c->zone) AlignmentPadding(c, 2, 8); longCallC(c, size, a); } else { alignedCallC(c, size, a); } } void alignedJumpC(Context* c, unsigned size, lir::Constant* a) { new (c->zone) AlignmentPadding(c, 1, 4); jumpC(c, size, a); } void alignedLongJumpC(Context* c, unsigned size, lir::Constant* a) { assert(c, size == vm::TargetBytesPerWord); if (vm::TargetBytesPerWord == 8) { new (c->zone) AlignmentPadding(c, 2, 8); longJumpC(c, size, a); } else { alignedJumpC(c, size, a); } } void pushR(Context* c, unsigned size, lir::Register* a) { if (vm::TargetBytesPerWord == 4 and size == 8) { lir::Register ah(a->high); pushR(c, 4, &ah); pushR(c, 4, a); } else { maybeRex(c, 4, a); opcode(c, 0x50 + regCode(a)); } } void popR(Context* c, unsigned size, lir::Register* a) { if (vm::TargetBytesPerWord == 4 and size == 8) { lir::Register ah(a->high); popR(c, 4, a); popR(c, 4, &ah); } else { maybeRex(c, 4, a); opcode(c, 0x58 + regCode(a)); if (vm::TargetBytesPerWord == 8 and size == 4) { moveRR(c, 4, a, 8, a); } } } void negateR(Context* c, unsigned size, lir::Register* a) { if (vm::TargetBytesPerWord == 4 and size == 8) { assert(c, a->low == rax and a->high == rdx); ResolvedPromise zeroPromise(0); lir::Constant zero(&zeroPromise); lir::Register ah(a->high); negateR(c, 4, a); addCarryCR(c, 4, &zero, &ah); negateR(c, 4, &ah); } else { maybeRex(c, size, a); opcode(c, 0xf7, 0xd8 + regCode(a)); } } void negateRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b UNUSED) { assert(c, aSize == bSize); negateR(c, aSize, a); } void moveCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { if (isFloatReg(b)) { sseMoveCR(c, aSize, a, bSize, b); } else { moveCR2(c, aSize, a, bSize, b, 0); } } void moveZCR(Context* c, unsigned aSize UNUSED, lir::Constant* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, not isFloatReg(b)); assert(c, aSize == 2); assert(c, bSize == vm::TargetBytesPerWord); assert(c, a->value->resolved()); maybeRex(c, vm::TargetBytesPerWord, b); opcode(c, 0xb8 + regCode(b)); c->code.appendTargetAddress(static_cast(a->value->value())); } void swapRR(Context* c, unsigned aSize UNUSED, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == bSize); assert(c, aSize == vm::TargetBytesPerWord); alwaysRex(c, aSize, a, b); opcode(c, 0x87); modrm(c, 0xc0, b, a); } void moveRR(Context* c, unsigned aSize, lir::Register* a, UNUSED unsigned bSize, lir::Register* b) { if (isFloatReg(a) or isFloatReg(b)) { sseMoveRR(c, aSize, a, bSize, b); return; } if (vm::TargetBytesPerWord == 4 and aSize == 8 and bSize == 8) { lir::Register ah(a->high); lir::Register bh(b->high); if (a->high == b->low) { if (a->low == b->high) { swapRR(c, 4, a, 4, b); } else { moveRR(c, 4, &ah, 4, &bh); moveRR(c, 4, a, 4, b); } } else { moveRR(c, 4, a, 4, b); moveRR(c, 4, &ah, 4, &bh); } } else { switch (aSize) { case 1: if (vm::TargetBytesPerWord == 4 and a->low > rbx) { assert(c, b->low <= rbx); moveRR(c, vm::TargetBytesPerWord, a, vm::TargetBytesPerWord, b); moveRR(c, 1, b, vm::TargetBytesPerWord, b); } else { alwaysRex(c, aSize, b, a); opcode(c, 0x0f, 0xbe); modrm(c, 0xc0, a, b); } break; case 2: alwaysRex(c, aSize, b, a); opcode(c, 0x0f, 0xbf); modrm(c, 0xc0, a, b); break; case 4: if (bSize == 8) { if (vm::TargetBytesPerWord == 8) { alwaysRex(c, bSize, b, a); opcode(c, 0x63); modrm(c, 0xc0, a, b); } else { if (a->low == rax and b->low == rax and b->high == rdx) { opcode(c, 0x99); //cdq } else { assert(c, b->low == rax and b->high == rdx); moveRR(c, 4, a, 4, b); moveRR(c, 4, b, 8, b); } } } else { if (a->low != b->low) { alwaysRex(c, aSize, a, b); opcode(c, 0x89); modrm(c, 0xc0, b, a); } } break; case 8: if (a->low != b->low){ maybeRex(c, aSize, a, b); opcode(c, 0x89); modrm(c, 0xc0, b, a); } break; } } } void moveMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize, lir::Register* b) { if (isFloatReg(b)) { sseMoveMR(c, aSize, a, bSize, b); return; } switch (aSize) { case 1: maybeRex(c, bSize, b, a); opcode(c, 0x0f, 0xbe); modrmSibImm(c, b, a); break; case 2: maybeRex(c, bSize, b, a); opcode(c, 0x0f, 0xbf); modrmSibImm(c, b, a); break; case 4: if (vm::TargetBytesPerWord == 8) { maybeRex(c, bSize, b, a); opcode(c, 0x63); modrmSibImm(c, b, a); } else { if (bSize == 8) { assert(c, b->low == rax and b->high == rdx); moveMR(c, 4, a, 4, b); moveRR(c, 4, b, 8, b); } else { maybeRex(c, bSize, b, a); opcode(c, 0x8b); modrmSibImm(c, b, a); } } break; case 8: if (vm::TargetBytesPerWord == 4 and bSize == 8) { lir::Memory ah(a->base, a->offset + 4, a->index, a->scale); lir::Register bh(b->high); moveMR(c, 4, a, 4, b); moveMR(c, 4, &ah, 4, &bh); } else { maybeRex(c, bSize, b, a); opcode(c, 0x8b); modrmSibImm(c, b, a); } break; default: abort(c); } } void moveRM(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Memory* b) { assert(c, aSize == bSize); if (isFloatReg(a)) { sseMoveRM(c, aSize, a, bSize, b); return; } switch (aSize) { case 1: maybeRex(c, bSize, a, b); opcode(c, 0x88); modrmSibImm(c, a, b); break; case 2: opcode(c, 0x66); maybeRex(c, bSize, a, b); opcode(c, 0x89); modrmSibImm(c, a, b); break; case 4: if (vm::TargetBytesPerWord == 8) { maybeRex(c, bSize, a, b); opcode(c, 0x89); modrmSibImm(c, a, b); break; } else { opcode(c, 0x89); modrmSibImm(c, a, b); } break; case 8: if (vm::TargetBytesPerWord == 8) { maybeRex(c, bSize, a, b); opcode(c, 0x89); modrmSibImm(c, a, b); } else { lir::Register ah(a->high); lir::Memory bh(b->base, b->offset + 4, b->index, b->scale); moveRM(c, 4, a, 4, b); moveRM(c, 4, &ah, 4, &bh); } break; default: abort(c); } } void moveAR(Context* c, unsigned aSize, lir::Address* a, unsigned bSize, lir::Register* b) { assert(c, vm::TargetBytesPerWord == 8 or (aSize == 4 and bSize == 4)); lir::Constant constant(a->address); lir::Memory memory(b->low, 0, -1, 0); moveCR(c, aSize, &constant, bSize, b); moveMR(c, bSize, &memory, bSize, b); } void moveCM(Context* c, unsigned aSize UNUSED, lir::Constant* a, unsigned bSize, lir::Memory* b) { switch (bSize) { case 1: maybeRex(c, bSize, b); opcode(c, 0xc6); modrmSibImm(c, 0, b->scale, b->index, b->base, b->offset); c->code.append(a->value->value()); break; case 2: opcode(c, 0x66); maybeRex(c, bSize, b); opcode(c, 0xc7); modrmSibImm(c, 0, b->scale, b->index, b->base, b->offset); c->code.append2(a->value->value()); break; case 4: maybeRex(c, bSize, b); opcode(c, 0xc7); modrmSibImm(c, 0, b->scale, b->index, b->base, b->offset); if (a->value->resolved()) { c->code.append4(a->value->value()); } else { appendImmediateTask(c, a->value, offsetPromise(c), 4); c->code.append4(0); } break; case 8: { if (vm::TargetBytesPerWord == 8) { if (a->value->resolved() and vm::fitsInInt32(a->value->value())) { maybeRex(c, bSize, b); opcode(c, 0xc7); modrmSibImm(c, 0, b->scale, b->index, b->base, b->offset); c->code.append4(a->value->value()); } else { lir::Register tmp (c->client->acquireTemporary(GeneralRegisterMask)); moveCR(c, 8, a, 8, &tmp); moveRM(c, 8, &tmp, 8, b); c->client->releaseTemporary(tmp.low); } } else { lir::Constant ah(shiftMaskPromise(c, a->value, 32, 0xFFFFFFFF)); lir::Constant al(shiftMaskPromise(c, a->value, 0, 0xFFFFFFFF)); lir::Memory bh(b->base, b->offset + 4, b->index, b->scale); moveCM(c, 4, &al, 4, b); moveCM(c, 4, &ah, 4, &bh); } } break; default: abort(c); } } void moveZRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { switch (aSize) { case 2: alwaysRex(c, aSize, b, a); opcode(c, 0x0f, 0xb7); modrm(c, 0xc0, a, b); break; default: abort(c); } } void moveZMR(Context* c, unsigned aSize UNUSED, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, bSize == vm::TargetBytesPerWord); assert(c, aSize == 2); maybeRex(c, bSize, b, a); opcode(c, 0x0f, 0xb7); modrmSibImm(c, b->low, a->scale, a->index, a->base, a->offset); } void addCarryRR(Context* c, unsigned size, lir::Register* a, lir::Register* b) { assert(c, vm::TargetBytesPerWord == 8 or size == 4); maybeRex(c, size, a, b); opcode(c, 0x11); modrm(c, 0xc0, b, a); } void addRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == bSize); if (vm::TargetBytesPerWord == 4 and aSize == 8) { lir::Register ah(a->high); lir::Register bh(b->high); addRR(c, 4, a, 4, b); addCarryRR(c, 4, &ah, &bh); } else { maybeRex(c, aSize, a, b); opcode(c, 0x01); modrm(c, 0xc0, b, a); } } void addCarryCR(Context* c, unsigned size, lir::Constant* a, lir::Register* b) { int64_t v = a->value->value(); maybeRex(c, size, b); if (vm::fitsInInt8(v)) { opcode(c, 0x83, 0xd0 + regCode(b)); c->code.append(v); } else { opcode(c, 0x81, 0xd0 + regCode(b)); c->code.append4(v); } } void addCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(c, aSize == bSize); int64_t v = a->value->value(); if (v) { if (vm::TargetBytesPerWord == 4 and bSize == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); lir::Constant ah(&high); ResolvedPromise low(v & 0xFFFFFFFF); lir::Constant al(&low); lir::Register bh(b->high); addCR(c, 4, &al, 4, b); addCarryCR(c, 4, &ah, &bh); } else { if (vm::fitsInInt32(v)) { maybeRex(c, aSize, b); if (vm::fitsInInt8(v)) { opcode(c, 0x83, 0xc0 + regCode(b)); c->code.append(v); } else { opcode(c, 0x81, 0xc0 + regCode(b)); c->code.append4(v); } } else { lir::Register tmp (c->client->acquireTemporary(GeneralRegisterMask)); moveCR(c, aSize, a, aSize, &tmp); addRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } } } void subtractBorrowCR(Context* c, unsigned size UNUSED, lir::Constant* a, lir::Register* b) { assert(c, vm::TargetBytesPerWord == 8 or size == 4); int64_t v = a->value->value(); if (vm::fitsInInt8(v)) { opcode(c, 0x83, 0xd8 + regCode(b)); c->code.append(v); } else { opcode(c, 0x81, 0xd8 + regCode(b)); c->code.append4(v); } } void subtractCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(c, aSize == bSize); int64_t v = a->value->value(); if (v) { if (vm::TargetBytesPerWord == 4 and bSize == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); lir::Constant ah(&high); ResolvedPromise low(v & 0xFFFFFFFF); lir::Constant al(&low); lir::Register bh(b->high); subtractCR(c, 4, &al, 4, b); subtractBorrowCR(c, 4, &ah, &bh); } else { if (vm::fitsInInt32(v)) { maybeRex(c, aSize, b); if (vm::fitsInInt8(v)) { opcode(c, 0x83, 0xe8 + regCode(b)); c->code.append(v); } else { opcode(c, 0x81, 0xe8 + regCode(b)); c->code.append4(v); } } else { lir::Register tmp (c->client->acquireTemporary(GeneralRegisterMask)); moveCR(c, aSize, a, aSize, &tmp); subtractRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } } } void subtractBorrowRR(Context* c, unsigned size, lir::Register* a, lir::Register* b) { assert(c, vm::TargetBytesPerWord == 8 or size == 4); maybeRex(c, size, a, b); opcode(c, 0x19); modrm(c, 0xc0, b, a); } void subtractRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == bSize); if (vm::TargetBytesPerWord == 4 and aSize == 8) { lir::Register ah(a->high); lir::Register bh(b->high); subtractRR(c, 4, a, 4, b); subtractBorrowRR(c, 4, &ah, &bh); } else { maybeRex(c, aSize, a, b); opcode(c, 0x29); modrm(c, 0xc0, b, a); } } void andRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == bSize); if (vm::TargetBytesPerWord == 4 and aSize == 8) { lir::Register ah(a->high); lir::Register bh(b->high); andRR(c, 4, a, 4, b); andRR(c, 4, &ah, 4, &bh); } else { maybeRex(c, aSize, a, b); opcode(c, 0x21); modrm(c, 0xc0, b, a); } } void andCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(c, aSize == bSize); int64_t v = a->value->value(); if (vm::TargetBytesPerWord == 4 and bSize == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); lir::Constant ah(&high); ResolvedPromise low(v & 0xFFFFFFFF); lir::Constant al(&low); lir::Register bh(b->high); andCR(c, 4, &al, 4, b); andCR(c, 4, &ah, 4, &bh); } else { if (vm::fitsInInt32(v)) { maybeRex(c, aSize, b); if (vm::fitsInInt8(v)) { opcode(c, 0x83, 0xe0 + regCode(b)); c->code.append(v); } else { opcode(c, 0x81, 0xe0 + regCode(b)); c->code.append4(v); } } else { lir::Register tmp (c->client->acquireTemporary(GeneralRegisterMask)); moveCR(c, aSize, a, aSize, &tmp); andRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } } void orRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == bSize); if (vm::TargetBytesPerWord == 4 and aSize == 8) { lir::Register ah(a->high); lir::Register bh(b->high); orRR(c, 4, a, 4, b); orRR(c, 4, &ah, 4, &bh); } else { maybeRex(c, aSize, a, b); opcode(c, 0x09); modrm(c, 0xc0, b, a); } } void orCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(c, aSize == bSize); int64_t v = a->value->value(); if (v) { if (vm::TargetBytesPerWord == 4 and bSize == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); lir::Constant ah(&high); ResolvedPromise low(v & 0xFFFFFFFF); lir::Constant al(&low); lir::Register bh(b->high); orCR(c, 4, &al, 4, b); orCR(c, 4, &ah, 4, &bh); } else { if (vm::fitsInInt32(v)) { maybeRex(c, aSize, b); if (vm::fitsInInt8(v)) { opcode(c, 0x83, 0xc8 + regCode(b)); c->code.append(v); } else { opcode(c, 0x81, 0xc8 + regCode(b)); c->code.append4(v); } } else { lir::Register tmp (c->client->acquireTemporary(GeneralRegisterMask)); moveCR(c, aSize, a, aSize, &tmp); orRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } } } void xorRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { if (vm::TargetBytesPerWord == 4 and aSize == 8) { lir::Register ah(a->high); lir::Register bh(b->high); xorRR(c, 4, a, 4, b); xorRR(c, 4, &ah, 4, &bh); } else { maybeRex(c, aSize, a, b); opcode(c, 0x31); modrm(c, 0xc0, b, a); } } void xorCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(c, aSize == bSize); int64_t v = a->value->value(); if (v) { if (vm::TargetBytesPerWord == 4 and bSize == 8) { ResolvedPromise high((v >> 32) & 0xFFFFFFFF); lir::Constant ah(&high); ResolvedPromise low(v & 0xFFFFFFFF); lir::Constant al(&low); lir::Register bh(b->high); xorCR(c, 4, &al, 4, b); xorCR(c, 4, &ah, 4, &bh); } else { if (vm::fitsInInt32(v)) { maybeRex(c, aSize, b); if (vm::fitsInInt8(v)) { opcode(c, 0x83, 0xf0 + regCode(b)); c->code.append(v); } else { opcode(c, 0x81, 0xf0 + regCode(b)); c->code.append4(v); } } else { lir::Register tmp (c->client->acquireTemporary(GeneralRegisterMask)); moveCR(c, aSize, a, aSize, &tmp); xorRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } } } void multiplyRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == bSize); if (vm::TargetBytesPerWord == 4 and aSize == 8) { assert(c, b->high == rdx); assert(c, b->low != rax); assert(c, a->low != rax); assert(c, a->high != rax); c->client->save(rax); lir::Register axdx(rax, rdx); lir::Register ah(a->high); lir::Register bh(b->high); lir::Register tmp(-1); lir::Register* scratch; if (a->low == b->low) { tmp.low = c->client->acquireTemporary (GeneralRegisterMask & ~(1 << rax)); scratch = &tmp; moveRR(c, 4, b, 4, scratch); } else { scratch = b; } moveRR(c, 4, b, 4, &axdx); multiplyRR(c, 4, &ah, 4, scratch); multiplyRR(c, 4, a, 4, &bh); addRR(c, 4, &bh, 4, scratch); // mul a->low,%eax%edx opcode(c, 0xf7, 0xe0 + a->low); addRR(c, 4, scratch, 4, &bh); moveRR(c, 4, &axdx, 4, b); if (tmp.low != -1) { c->client->releaseTemporary(tmp.low); } } else { maybeRex(c, aSize, b, a); opcode(c, 0x0f, 0xaf); modrm(c, 0xc0, a, b); } } void compareRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == bSize); assert(c, aSize <= vm::TargetBytesPerWord); maybeRex(c, aSize, a, b); opcode(c, 0x39); modrm(c, 0xc0, b, a); } void compareCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(c, aSize == bSize); assert(c, vm::TargetBytesPerWord == 8 or aSize == 4); if (a->value->resolved() and vm::fitsInInt32(a->value->value())) { int64_t v = a->value->value(); maybeRex(c, aSize, b); if (vm::fitsInInt8(v)) { opcode(c, 0x83, 0xf8 + regCode(b)); c->code.append(v); } else { opcode(c, 0x81, 0xf8 + regCode(b)); c->code.append4(v); } } else { lir::Register tmp(c->client->acquireTemporary(GeneralRegisterMask)); moveCR(c, aSize, a, aSize, &tmp); compareRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } void compareRM(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Memory* b) { assert(c, aSize == bSize); assert(c, vm::TargetBytesPerWord == 8 or aSize == 4); if (vm::TargetBytesPerWord == 8 and aSize == 4) { moveRR(c, 4, a, 8, a); } maybeRex(c, bSize, a, b); opcode(c, 0x39); modrmSibImm(c, a, b); } void compareCM(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Memory* b) { assert(c, aSize == bSize); assert(c, vm::TargetBytesPerWord == 8 or aSize == 4); if (a->value->resolved()) { int64_t v = a->value->value(); maybeRex(c, aSize, b); opcode(c, vm::fitsInInt8(v) ? 0x83 : 0x81); modrmSibImm(c, rdi, b->scale, b->index, b->base, b->offset); if (vm::fitsInInt8(v)) { c->code.append(v); } else if (vm::fitsInInt32(v)) { c->code.append4(v); } else { abort(c); } } else { lir::Register tmp(c->client->acquireTemporary(GeneralRegisterMask)); moveCR(c, aSize, a, bSize, &tmp); compareRM(c, bSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } void compareFloatRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == bSize); if (aSize == 8) { opcode(c, 0x66); } maybeRex(c, 4, a, b); opcode(c, 0x0f, 0x2e); modrm(c, 0xc0, a, b); } void branchLong(Context* c, lir::TernaryOperation op, lir::Operand* al, lir::Operand* ah, lir::Operand* bl, lir::Operand* bh, lir::Constant* target, BinaryOperationType compare) { compare(c, 4, ah, 4, bh); unsigned next = 0; switch (op) { case lir::JumpIfEqual: opcode(c, 0x75); // jne next = c->code.length(); c->code.append(0); compare(c, 4, al, 4, bl); conditional(c, 0x84, target); // je break; case lir::JumpIfNotEqual: conditional(c, 0x85, target); // jne compare(c, 4, al, 4, bl); conditional(c, 0x85, target); // jne break; case lir::JumpIfLess: conditional(c, 0x8c, target); // jl opcode(c, 0x7f); // jg next = c->code.length(); c->code.append(0); compare(c, 4, al, 4, bl); conditional(c, 0x82, target); // jb break; case lir::JumpIfGreater: conditional(c, 0x8f, target); // jg opcode(c, 0x7c); // jl next = c->code.length(); c->code.append(0); compare(c, 4, al, 4, bl); conditional(c, 0x87, target); // ja break; case lir::JumpIfLessOrEqual: conditional(c, 0x8c, target); // jl opcode(c, 0x7f); // jg next = c->code.length(); c->code.append(0); compare(c, 4, al, 4, bl); conditional(c, 0x86, target); // jbe break; case lir::JumpIfGreaterOrEqual: conditional(c, 0x8f, target); // jg opcode(c, 0x7c); // jl next = c->code.length(); c->code.append(0); compare(c, 4, al, 4, bl); conditional(c, 0x83, target); // jae break; default: abort(c); } if (next) { int8_t nextOffset = c->code.length() - next - 1; c->code.set(next, &nextOffset, 1); } } void branchRR(Context* c, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Register* b, lir::Constant* target) { if (isFloatBranch(op)) { compareFloatRR(c, size, a, size, b); branchFloat(c, op, target); } else if (size > vm::TargetBytesPerWord) { lir::Register ah(a->high); lir::Register bh(b->high); branchLong(c, op, a, &ah, b, &bh, target, CAST2(compareRR)); } else { compareRR(c, size, a, size, b); branch(c, op, target); } } void branchCR(Context* c, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Register* b, lir::Constant* target) { assert(c, not isFloatBranch(op)); if (size > vm::TargetBytesPerWord) { int64_t v = a->value->value(); ResolvedPromise low(v & ~static_cast(0)); lir::Constant al(&low); ResolvedPromise high((v >> 32) & ~static_cast(0)); lir::Constant ah(&high); lir::Register bh(b->high); branchLong(c, op, &al, &ah, b, &bh, target, CAST2(compareCR)); } else { compareCR(c, size, a, size, b); branch(c, op, target); } } void branchRM(Context* c, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Memory* b, lir::Constant* target) { assert(c, not isFloatBranch(op)); assert(c, size <= vm::TargetBytesPerWord); compareRM(c, size, a, size, b); branch(c, op, target); } void branchCM(Context* c, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Memory* b, lir::Constant* target) { assert(c, not isFloatBranch(op)); assert(c, size <= vm::TargetBytesPerWord); compareCM(c, size, a, size, b); branch(c, op, target); } void multiplyCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { assert(c, aSize == bSize); if (vm::TargetBytesPerWord == 4 and aSize == 8) { const uint32_t mask = GeneralRegisterMask & ~((1 << rax) | (1 << rdx)); lir::Register tmp(c->client->acquireTemporary(mask), c->client->acquireTemporary(mask)); moveCR(c, aSize, a, aSize, &tmp); multiplyRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); c->client->releaseTemporary(tmp.high); } else { int64_t v = a->value->value(); if (v != 1) { if (vm::fitsInInt32(v)) { maybeRex(c, bSize, b, b); if (vm::fitsInInt8(v)) { opcode(c, 0x6b); modrm(c, 0xc0, b, b); c->code.append(v); } else { opcode(c, 0x69); modrm(c, 0xc0, b, b); c->code.append4(v); } } else { lir::Register tmp (c->client->acquireTemporary(GeneralRegisterMask)); moveCR(c, aSize, a, aSize, &tmp); multiplyRR(c, aSize, &tmp, bSize, b); c->client->releaseTemporary(tmp.low); } } } } void divideRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b UNUSED) { assert(c, aSize == bSize); assert(c, b->low == rax); assert(c, a->low != rdx); c->client->save(rdx); maybeRex(c, aSize, a, b); opcode(c, 0x99); // cdq maybeRex(c, aSize, b, a); opcode(c, 0xf7, 0xf8 + regCode(a)); } void remainderRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, aSize == bSize); assert(c, b->low == rax); assert(c, a->low != rdx); c->client->save(rdx); maybeRex(c, aSize, a, b); opcode(c, 0x99); // cdq maybeRex(c, aSize, b, a); opcode(c, 0xf7, 0xf8 + regCode(a)); lir::Register dx(rdx); moveRR(c, vm::TargetBytesPerWord, &dx, vm::TargetBytesPerWord, b); } void doShift(Context* c, UNUSED void (*shift) (Context*, unsigned, lir::Register*, unsigned, lir::Register*), int type, UNUSED unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { int64_t v = a->value->value(); if (vm::TargetBytesPerWord == 4 and bSize == 8) { c->client->save(rcx); lir::Register cx(rcx); ResolvedPromise promise(v & 0x3F); lir::Constant masked(&promise); moveCR(c, 4, &masked, 4, &cx); shift(c, aSize, &cx, bSize, b); } else { maybeRex(c, bSize, b); if (v == 1) { opcode(c, 0xd1, type + regCode(b)); } else if (vm::fitsInInt8(v)) { opcode(c, 0xc1, type + regCode(b)); c->code.append(v); } else { abort(c); } } } void shiftLeftRR(Context* c, UNUSED unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b) { if (vm::TargetBytesPerWord == 4 and bSize == 8) { lir::Register cx(rcx); if (a->low != rcx) { c->client->save(rcx); ResolvedPromise promise(0x3F); lir::Constant mask(&promise); moveRR(c, 4, a, 4, &cx); andCR(c, 4, &mask, 4, &cx); } // shld opcode(c, 0x0f, 0xa5); modrm(c, 0xc0, b->high, b->low); // shl opcode(c, 0xd3, 0xe0 + b->low); ResolvedPromise promise(32); lir::Constant constant(&promise); compareCR(c, vm::TargetBytesPerWord, &constant, vm::TargetBytesPerWord, &cx); opcode(c, 0x7c); //jl c->code.append(2 + 2); lir::Register bh(b->high); moveRR(c, 4, b, 4, &bh); // 2 bytes xorRR(c, 4, b, 4, b); // 2 bytes } else { assert(c, a->low == rcx); maybeRex(c, bSize, a, b); opcode(c, 0xd3, 0xe0 + regCode(b)); } } void shiftLeftCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { doShift(c, shiftLeftRR, 0xe0, aSize, a, bSize, b); } void shiftRightRR(Context* c, UNUSED unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b) { if (vm::TargetBytesPerWord == 4 and bSize == 8) { lir::Register cx(rcx); if (a->low != rcx) { c->client->save(rcx); ResolvedPromise promise(0x3F); lir::Constant mask(&promise); moveRR(c, 4, a, 4, &cx); andCR(c, 4, &mask, 4, &cx); } // shrd opcode(c, 0x0f, 0xad); modrm(c, 0xc0, b->low, b->high); // sar opcode(c, 0xd3, 0xf8 + b->high); ResolvedPromise promise(32); lir::Constant constant(&promise); compareCR(c, vm::TargetBytesPerWord, &constant, vm::TargetBytesPerWord, &cx); opcode(c, 0x7c); //jl c->code.append(2 + 3); lir::Register bh(b->high); moveRR(c, 4, &bh, 4, b); // 2 bytes // sar 31,high opcode(c, 0xc1, 0xf8 + b->high); c->code.append(31); } else { assert(c, a->low == rcx); maybeRex(c, bSize, a, b); opcode(c, 0xd3, 0xf8 + regCode(b)); } } void shiftRightCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b) { doShift(c, shiftRightRR, 0xf8, aSize, a, bSize, b); } void unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b) { if (vm::TargetBytesPerWord == 4 and bSize == 8) { lir::Register cx(rcx); if (a->low != rcx) { c->client->save(rcx); ResolvedPromise promise(0x3F); lir::Constant mask(&promise); moveRR(c, 4, a, 4, &cx); andCR(c, 4, &mask, 4, &cx); } // shrd opcode(c, 0x0f, 0xad); modrm(c, 0xc0, b->low, b->high); // shr opcode(c, 0xd3, 0xe8 + b->high); ResolvedPromise promise(32); lir::Constant constant(&promise); compareCR(c, vm::TargetBytesPerWord, &constant, vm::TargetBytesPerWord, &cx); opcode(c, 0x7c); //jl c->code.append(2 + 2); lir::Register bh(b->high); moveRR(c, 4, &bh, 4, b); // 2 bytes xorRR(c, 4, &bh, 4, &bh); // 2 bytes } else { assert(c, a->low == rcx); maybeRex(c, bSize, a, b); opcode(c, 0xd3, 0xe8 + regCode(b)); } } void unsignedShiftRightCR(Context* c, unsigned aSize UNUSED, lir::Constant* a, unsigned bSize, lir::Register* b) { doShift(c, unsignedShiftRightRR, 0xe8, aSize, a, bSize, b); } void floatSqrtRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { floatRegOp(c, aSize, a, 4, b, 0x51); } void floatSqrtMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b) { floatMemOp(c, aSize, a, 4, b, 0x51); } void floatAddRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { floatRegOp(c, aSize, a, 4, b, 0x58); } void floatAddMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b) { floatMemOp(c, aSize, a, 4, b, 0x58); } void floatSubtractRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { floatRegOp(c, aSize, a, 4, b, 0x5c); } void floatSubtractMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b) { floatMemOp(c, aSize, a, 4, b, 0x5c); } void floatMultiplyRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { floatRegOp(c, aSize, a, 4, b, 0x59); } void floatMultiplyMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b) { floatMemOp(c, aSize, a, 4, b, 0x59); } void floatDivideRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { floatRegOp(c, aSize, a, 4, b, 0x5e); } void floatDivideMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b) { floatMemOp(c, aSize, a, 4, b, 0x5e); } void float2FloatRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { floatRegOp(c, aSize, a, 4, b, 0x5a); } void float2FloatMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b) { floatMemOp(c, aSize, a, 4, b, 0x5a); } void float2IntRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b) { assert(c, not isFloatReg(b)); floatRegOp(c, aSize, a, bSize, b, 0x2c); } void float2IntMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize, lir::Register* b) { floatMemOp(c, aSize, a, bSize, b, 0x2c); } void int2FloatRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b) { floatRegOp(c, bSize, a, aSize, b, 0x2a); } void int2FloatMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize, lir::Register* b) { floatMemOp(c, bSize, a, aSize, b, 0x2a); } void floatNegateRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, isFloatReg(a) and isFloatReg(b)); // unlike most of the other floating point code, this does NOT // support doubles: assert(c, aSize == 4); ResolvedPromise pcon(0x80000000); lir::Constant con(&pcon); if (a->low == b->low) { lir::Register tmp(c->client->acquireTemporary(FloatRegisterMask)); moveCR(c, 4, &con, 4, &tmp); maybeRex(c, 4, a, &tmp); opcode(c, 0x0f, 0x57); modrm(c, 0xc0, &tmp, a); c->client->releaseTemporary(tmp.low); } else { moveCR(c, 4, &con, 4, b); if (aSize == 8) opcode(c, 0x66); maybeRex(c, 4, a, b); opcode(c, 0x0f, 0x57); modrm(c, 0xc0, a, b); } } void floatAbsoluteRR(Context* c, unsigned aSize UNUSED, lir::Register* a, unsigned bSize UNUSED, lir::Register* b) { assert(c, isFloatReg(a) and isFloatReg(b)); // unlike most of the other floating point code, this does NOT // support doubles: assert(c, aSize == 4); ResolvedPromise pcon(0x7fffffff); lir::Constant con(&pcon); if (a->low == b->low) { lir::Register tmp(c->client->acquireTemporary(FloatRegisterMask)); moveCR(c, 4, &con, 4, &tmp); maybeRex(c, 4, a, &tmp); opcode(c, 0x0f, 0x54); modrm(c, 0xc0, &tmp, a); c->client->releaseTemporary(tmp.low); } else { moveCR(c, 4, &con, 4, b); maybeRex(c, 4, a, b); opcode(c, 0x0f, 0x54); modrm(c, 0xc0, a, b); } } void absoluteRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b UNUSED) { assert(c, aSize == bSize and a->low == rax and b->low == rax); lir::Register d (c->client->acquireTemporary(static_cast(1) << rdx)); maybeRex(c, aSize, a, b); opcode(c, 0x99); xorRR(c, aSize, &d, aSize, a); subtractRR(c, aSize, &d, aSize, a); c->client->releaseTemporary(rdx); } } // namespace x86 } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/x86/operations.h000066400000000000000000000223251231440243200236260ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_X86_OPERATIONS_H #define AVIAN_CODEGEN_ASSEMBLER_X86_OPERATIONS_H #include "avian/common.h" #include #include "context.h" namespace avian { namespace codegen { namespace x86 { void return_(Context* c); void trap(Context* c); void ignore(Context*); void storeLoadBarrier(Context* c); void callC(Context* c, unsigned size UNUSED, lir::Constant* a); void longCallC(Context* c, unsigned size, lir::Constant* a); void jumpR(Context* c, unsigned size UNUSED, lir::Register* a); void jumpC(Context* c, unsigned size UNUSED, lir::Constant* a); void jumpM(Context* c, unsigned size UNUSED, lir::Memory* a); void longJumpC(Context* c, unsigned size, lir::Constant* a); void callR(Context* c, unsigned size UNUSED, lir::Register* a); void callM(Context* c, unsigned size UNUSED, lir::Memory* a); void alignedCallC(Context* c, unsigned size, lir::Constant* a); void alignedLongCallC(Context* c, unsigned size, lir::Constant* a); void alignedJumpC(Context* c, unsigned size, lir::Constant* a); void alignedLongJumpC(Context* c, unsigned size, lir::Constant* a); void pushR(Context* c, unsigned size, lir::Register* a); void popR(Context* c, unsigned size, lir::Register* a); void negateR(Context* c, unsigned size, lir::Register* a); void negateRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b UNUSED); void moveCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void moveZCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void swapRR(Context* c, unsigned aSize UNUSED, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void moveRR(Context* c, unsigned aSize, lir::Register* a, UNUSED unsigned bSize, lir::Register* b); void moveMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize, lir::Register* b); void moveRM(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Memory* b); void moveAR(Context* c, unsigned aSize, lir::Address* a, unsigned bSize, lir::Register* b); void moveCM(Context* c, unsigned aSize UNUSED, lir::Constant* a, unsigned bSize, lir::Memory* b); void moveZRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void moveZMR(Context* c, unsigned aSize UNUSED, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b); void addCarryRR(Context* c, unsigned size, lir::Register* a, lir::Register* b); void addRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void addCarryCR(Context* c, unsigned size, lir::Constant* a, lir::Register* b); void addCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void subtractBorrowCR(Context* c, unsigned size UNUSED, lir::Constant* a, lir::Register* b); void subtractCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void subtractBorrowRR(Context* c, unsigned size, lir::Register* a, lir::Register* b); void subtractRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void andRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void andCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void orRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void orCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void xorRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void xorCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void multiplyRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void compareRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void compareCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void compareRM(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Memory* b); void compareCM(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Memory* b); void compareFloatRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void branchLong(Context* c, lir::TernaryOperation op, lir::Operand* al, lir::Operand* ah, lir::Operand* bl, lir::Operand* bh, lir::Constant* target, BinaryOperationType compare); void branchRR(Context* c, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Register* b, lir::Constant* target); void branchCR(Context* c, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Register* b, lir::Constant* target); void branchRM(Context* c, lir::TernaryOperation op, unsigned size, lir::Register* a, lir::Memory* b, lir::Constant* target); void branchCM(Context* c, lir::TernaryOperation op, unsigned size, lir::Constant* a, lir::Memory* b, lir::Constant* target); void multiplyCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void divideRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b UNUSED); void remainderRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void doShift(Context* c, UNUSED void (*shift) (Context*, unsigned, lir::Register*, unsigned, lir::Register*), int type, UNUSED unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void shiftLeftRR(Context* c, UNUSED unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b); void shiftLeftCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void shiftRightRR(Context* c, UNUSED unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b); void shiftRightCR(Context* c, unsigned aSize, lir::Constant* a, unsigned bSize, lir::Register* b); void unsignedShiftRightRR(Context* c, UNUSED unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b); void unsignedShiftRightCR(Context* c, unsigned aSize UNUSED, lir::Constant* a, unsigned bSize, lir::Register* b); void floatSqrtRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void floatSqrtMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b); void floatAddRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void floatAddMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b); void floatSubtractRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void floatSubtractMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b); void floatMultiplyRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void floatMultiplyMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b); void floatDivideRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void floatDivideMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b); void float2FloatRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void float2FloatMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize UNUSED, lir::Register* b); void float2IntRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b); void float2IntMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize, lir::Register* b); void int2FloatRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize, lir::Register* b); void int2FloatMR(Context* c, unsigned aSize, lir::Memory* a, unsigned bSize, lir::Register* b); void floatNegateRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void floatAbsoluteRR(Context* c, unsigned aSize UNUSED, lir::Register* a, unsigned bSize UNUSED, lir::Register* b); void absoluteRR(Context* c, unsigned aSize, lir::Register* a, unsigned bSize UNUSED, lir::Register* b UNUSED); } // namespace x86 } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_X86_OPERATIONS_H ReadyTalk-avian-1e1fff5/src/codegen/target/x86/padding.cpp000066400000000000000000000031021231440243200233740ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/alloc-vector.h" #include "context.h" #include "padding.h" #include "block.h" namespace avian { namespace codegen { namespace x86 { AlignmentPadding::AlignmentPadding(Context* c, unsigned instructionOffset, unsigned alignment): offset(c->code.length()), instructionOffset(instructionOffset), alignment(alignment), next(0), padding(-1) { if (c->lastBlock->firstPadding) { c->lastBlock->lastPadding->next = this; } else { c->lastBlock->firstPadding = this; } c->lastBlock->lastPadding = this; } unsigned padding(AlignmentPadding* p, unsigned start, unsigned offset, AlignmentPadding* limit) { unsigned padding = 0; if (limit) { if (limit->padding == -1) { for (; p; p = p->next) { if (p->padding == -1) { unsigned index = p->offset - offset; while ((start + index + padding + p->instructionOffset) % p->alignment) { ++ padding; } p->padding = padding; if (p == limit) break; } else { padding = p->padding; } } } else { padding = limit->padding; } } return padding; } } // namespace x86 } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/codegen/target/x86/padding.h000066400000000000000000000017041231440243200230470ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_X86_PADDING_H #define AVIAN_CODEGEN_ASSEMBLER_X86_PADDING_H namespace avian { namespace codegen { namespace x86 { class Context; class AlignmentPadding { public: AlignmentPadding(Context* c, unsigned instructionOffset, unsigned alignment); unsigned offset; unsigned instructionOffset; unsigned alignment; AlignmentPadding* next; int padding; }; unsigned padding(AlignmentPadding* p, unsigned start, unsigned offset, AlignmentPadding* limit); } // namespace x86 } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_X86_PADDING_H ReadyTalk-avian-1e1fff5/src/codegen/target/x86/registers.h000066400000000000000000000022371231440243200234520ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_CODEGEN_ASSEMBLER_X86_REGISTERS_H #define AVIAN_CODEGEN_ASSEMBLER_X86_REGISTERS_H namespace avian { namespace codegen { namespace x86 { enum { rax = 0, rcx = 1, rdx = 2, rbx = 3, rsp = 4, rbp = 5, rsi = 6, rdi = 7, r8 = 8, r9 = 9, r10 = 10, r11 = 11, r12 = 12, r13 = 13, r14 = 14, r15 = 15, }; enum { xmm0 = r15 + 1, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, }; const int LongJumpRegister = r10; const unsigned GeneralRegisterMask = vm::TargetBytesPerWord == 4 ? 0x000000ff : 0x0000ffff; const unsigned FloatRegisterMask = vm::TargetBytesPerWord == 4 ? 0x00ff0000 : 0xffff0000; } // namespace x86 } // namespace codegen } // namespace avian #endif // AVIAN_CODEGEN_ASSEMBLER_X86_REGISTERS_H ReadyTalk-avian-1e1fff5/src/codegen/targets.cpp000066400000000000000000000022241231440243200215300ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/common.h" #include #include "avian/environment.h" namespace avian { namespace codegen { Architecture* makeArchitectureNative(vm::System* system, bool useNativeFeatures UNUSED) { #ifndef AVIAN_TARGET_ARCH #error "Must specify native target!" #endif #if AVIAN_TARGET_ARCH == AVIAN_ARCH_UNKNOWN system->abort(); return 0; #elif (AVIAN_TARGET_ARCH == AVIAN_ARCH_X86) || (AVIAN_TARGET_ARCH == AVIAN_ARCH_X86_64) return makeArchitectureX86(system, useNativeFeatures); #elif AVIAN_TARGET_ARCH == AVIAN_ARCH_ARM return makeArchitectureArm(system, useNativeFeatures); #elif AVIAN_TARGET_ARCH == AVIAN_ARCH_POWERPC return makeArchitecturePowerpc(system, useNativeFeatures); #else #error "Unsupported codegen target" #endif } } // namespace codegen } // namespace avian ReadyTalk-avian-1e1fff5/src/compile-arm.S000066400000000000000000000144311231440243200203030ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/types.h" #include "avian/target-fields.h" .text #define BYTES_PER_WORD 4 #define LOCAL(x) .L##x #ifdef __APPLE__ # define GLOBAL(x) _##x #else # define GLOBAL(x) x #endif #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 #define CONTINUATION_RETURN_ADDRESS_OFFSET 20 #define CONTINUATION_FRAME_POINTER_OFFSET 24 #define CONTINUATION_LENGTH 28 #define CONTINUATION_BODY 32 .globl GLOBAL(vmInvoke) .align 2 GLOBAL(vmInvoke): /* arguments r0 : thread r1 : function r2 : arguments r3 : argumentFootprint [sp, #0] : frameSize (not used) [sp, #4] : returnType */ // save all non-volatile registers stmfd sp!, {r4-r11, lr} // save return type ldr r4, [sp, #4] str r4, [sp, #-4]! str sp, [r0, #TARGET_THREAD_SCRATCH] // align stack, if necessary eor r4, sp, r3 tst r4, #4 subne sp, sp, #4 // copy arguments into place sub sp, r3 mov r4, #0 b LOCAL(vmInvoke_argumentTest) LOCAL(vmInvoke_argumentLoop): ldr r5, [r2, r4] str r5, [sp, r4] add r4, r4, #BYTES_PER_WORD LOCAL(vmInvoke_argumentTest): cmp r4, r3 blt LOCAL(vmInvoke_argumentLoop) // we use r8 to hold the thread pointer, by convention mov r8, r0 // load and call function address #if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) mov lr, pc bx r1 #else blx r1 #endif .globl GLOBAL(vmInvoke_returnAddress) .align 2 GLOBAL(vmInvoke_returnAddress): // restore stack pointer ldr sp, [r8, #TARGET_THREAD_SCRATCH] // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See // MyProcess::getStackTrace in compile.cpp for details on how we get // a reliable stack trace from a thread that might be interrupted at // any point in its execution. mov r5, #0 str r5, [r8, #TARGET_THREAD_STACK] .globl GLOBAL(vmInvoke_safeStack) .align 2 GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS // call the next continuation, if any ldr r5,[r8,#TARGET_THREAD_CONTINUATION] cmp r5,#0 beq LOCAL(vmInvoke_exit) ldr r6,[r5,#CONTINUATION_LENGTH] lsl r6,r6,#2 neg r7,r6 add r7,r7,#-80 mov r4,sp str r4,[sp,r7]! add r7,r5,#CONTINUATION_BODY mov r11,#0 b LOCAL(vmInvoke_continuationTest) LOCAL(vmInvoke_continuationLoop): ldr r9,[r7,r11] str r9,[sp,r11] add r11,r11,#4 LOCAL(vmInvoke_continuationTest): cmp r11,r6 ble LOCAL(vmInvoke_continuationLoop) ldr r7,[r5,#CONTINUATION_RETURN_ADDRESS_OFFSET] #ifdef __APPLE__ movw r11, :lower16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmInvoke_getAddress)+8)) movt r11, :upper16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmInvoke_getAddress)+8)) LOCAL(vmInvoke_getAddress): add r11, pc, r11 #else // not __APPLE__ ldr r10,LOCAL(vmInvoke_returnAddress_word) ldr r11,LOCAL(vmInvoke_getAddress_word) LOCAL(vmInvoke_getAddress): add r11,pc,r11 ldr r11,[r11,r10] #endif // not __APPLE__ str r11,[sp,r7] ldr r7,[r5,#CONTINUATION_NEXT] str r7,[r8,#TARGET_THREAD_CONTINUATION] // call the continuation unless we're handling an exception ldr r7,[r8,#TARGET_THREAD_EXCEPTION] cmp r7,#0 bne LOCAL(vmInvoke_handleException) ldr r7,[r5,#CONTINUATION_ADDRESS] bx r7 LOCAL(vmInvoke_handleException): // we're handling an exception - call the exception handler instead mov r11,#0 str r11,[r8,#TARGET_THREAD_EXCEPTION] ldr r11,[r8,#TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT] ldr r9,[sp] neg r11,r11 str r9,[sp,r11]! ldr r11,[r8,#TARGET_THREAD_EXCEPTIONOFFSET] str r7,[sp,r11] ldr r7,[r8,#TARGET_THREAD_EXCEPTIONHANDLER] bx r7 LOCAL(vmInvoke_exit): #endif // AVIAN_CONTINUATIONS mov ip, #0 str ip, [r8, #TARGET_THREAD_STACK] // restore return type ldr ip, [sp], #4 // restore callee-saved registers ldmfd sp!, {r4-r11, lr} LOCAL(vmInvoke_return): bx lr .globl GLOBAL(vmJumpAndInvoke) .align 2 GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // r0: thread // r1: address // r2: stack // r3: argumentFootprint // [sp,#0]: arguments // [sp,#4]: frameSize ldr r5,[sp,#0] ldr r6,[sp,#4] // allocate new frame, adding room for callee-saved registers, plus // 4 bytes of padding since the calculation of frameSize assumes 4 // bytes have already been allocated to save the return address, // which is not true in this case sub r2,r2,r6 sub r2,r2,#84 mov r8,r0 // copy arguments into place mov r6,#0 b LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): ldr r12,[r5,r6] str r12,[r2,r6] add r6,r6,#4 LOCAL(vmJumpAndInvoke_argumentTest): cmp r6,r3 ble LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack // pointer now mov sp,r2 // set return address to vmInvoke_returnAddress #ifdef __APPLE__ movw r11, :lower16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmJumpAndInvoke_getAddress)+8)) movt r11, :upper16:(GLOBAL(vmInvoke_returnAddress)-(LOCAL(vmJumpAndInvoke_getAddress)+8)) LOCAL(vmJumpAndInvoke_getAddress): add r11, pc, r11 #else // not __APPLE__ ldr r10,LOCAL(vmInvoke_returnAddress_word) ldr r11,LOCAL(vmJumpAndInvoke_getAddress_word) LOCAL(vmJumpAndInvoke_getAddress): add r11,pc,r11 #endif // not __APPLE__ ldr lr,[r11,r10] bx r1 #ifndef __APPLE__ LOCAL(vmInvoke_returnAddress_word): .word GLOBAL(vmInvoke_returnAddress)(GOT) LOCAL(vmInvoke_getAddress_word): .word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmInvoke_getAddress)+8) LOCAL(vmJumpAndInvoke_getAddress_word): .word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmJumpAndInvoke_getAddress)+8) #endif // not __APPLE__ #else // not AVIAN_CONTINUATIONS // vmJumpAndInvoke should only be called when continuations are // enabled, so we force a crash if we reach here: mov r1,#0 ldr r1,[r1] #endif // not AVIAN_CONTINUATIONS ReadyTalk-avian-1e1fff5/src/compile-arm.masm000066400000000000000000000134731231440243200210430ustar00rootroot00000000000000; Copyright (c) 2008-2013, Avian Contributors ; ; Permission to use, copy, modify, and/or distribute this software ; for any purpose with or without fee is hereby granted, provided ; that the above copyright notice and this permission notice appear ; in all copies. ; ; There is NO WARRANTY for this software. See license.txt for ; details. ; ; ORIGIN: https://github.com/gkvas/avian/tree/wince ; types.inc VOID_TYPE equ 0 INT8_TYPE equ 1 INT16_TYPE equ 2 INT32_TYPE equ 3 INT64_TYPE equ 4 FLOAT_TYPE equ 5 DOUBLE_TYPE equ 6 POINTER_TYPE equ 7 ; target-fields.inc ;TARGET_BYTES_PER_WORD = 4 TARGET_THREAD_EXCEPTION equ 44 TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT equ 2164 TARGET_THREAD_EXCEPTIONOFFSET equ 2168 TARGET_THREAD_EXCEPTIONHANDLER equ 2172 TARGET_THREAD_IP equ 2144 TARGET_THREAD_STACK equ 2148 TARGET_THREAD_NEWSTACK equ 2152 TARGET_THREAD_SCRATCH equ 2156 TARGET_THREAD_CONTINUATION equ 2160 TARGET_THREAD_TAILADDRESS equ 2176 TARGET_THREAD_VIRTUALCALLTARGET equ 2180 TARGET_THREAD_VIRTUALCALLINDEX equ 2184 TARGET_THREAD_HEAPIMAGE equ 2188 TARGET_THREAD_CODEIMAGE equ 2192 TARGET_THREAD_THUNKTABLE equ 2196 TARGET_THREAD_STACKLIMIT equ 2220 AREA text, CODE, ARM BYTES_PER_WORD equ 4 CONTINUATION_NEXT equ 4 CONTINUATION_ADDRESS equ 16 CONTINUATION_RETURN_ADDRESS_OFFSET equ 20 CONTINUATION_FRAME_POINTER_OFFSET equ 24 CONTINUATION_LENGTH equ 28 CONTINUATION_BODY equ 32 EXPORT vmInvoke vmInvoke ; arguments ; r0 : thread ; r1 : function ; r2 : arguments ; r3 : argumentFootprint ; [sp, #0] : frameSize (not used) ; [sp, #4] : returnType ; save all non-volatile registers stmfd sp!, {r4-r11, lr} ; save return type ldr r4, [sp, #4] str r4, [sp, #-4]! str sp, [r0, #TARGET_THREAD_SCRATCH] ; align stack, if necessary eor r4, sp, r3 tst r4, #4 subne sp, sp, #4 ; copy arguments into place sub sp, sp, r3 mov r4, #0 b vmInvoke_argumentTest vmInvoke_argumentLoop ldr r5, [r2, r4] str r5, [sp, r4] add r4, r4, #BYTES_PER_WORD vmInvoke_argumentTest cmp r4, r3 blt vmInvoke_argumentLoop ; we use r8 to hold the thread pointer, by convention mov r8, r0 ; load and call function address blx r1 EXPORT vmInvoke_returnAddress vmInvoke_returnAddress ; restore stack pointer ldr sp, [r8, #TARGET_THREAD_SCRATCH] ; clear MyThread::stack to avoid confusing another thread calling ; java.lang.Thread.getStackTrace on this one. See ; MyProcess::getStackTrace in compile.cpp for details on how we get ; a reliable stack trace from a thread that might be interrupted at ; any point in its execution. mov r5, #0 str r5, [r8, #TARGET_THREAD_STACK] EXPORT vmInvoke_safeStack vmInvoke_safeStack ;if AVIAN_CONTINUATIONS ; ; call the next continuation, if any ; ldr r5,[r8,#TARGET_THREAD_CONTINUATION] ; cmp r5,#0 ; beq vmInvoke_exit) ; ; ldr r6,[r5,#CONTINUATION_LENGTH] ; lsl r6,r6,#2 ; neg r7,r6 ; add r7,r7,#-80 ; mov r4,sp ; str r4,[sp,r7]! ; ; add r7,r5,#CONTINUATION_BODY ; ; mov r11,#0 ; b vmInvoke_continuationTest ; ;vmInvoke_continuationLoop ; ldr r9,[r7,r11] ; str r9,[sp,r11] ; add r11,r11,#4 ; ;vmInvoke_continuationTest ; cmp r11,r6 ; ble vmInvoke_continuationLoop) ; ; ldr r7,[r5,#CONTINUATION_RETURN_ADDRESS_OFFSET] ; ldr r10,vmInvoke_returnAddress_word ; ldr r11,vmInvoke_getAddress_word ;vmInvoke_getAddress ; add r11,pc,r11 ; ldr r11,[r11,r10] ; str r11,[sp,r7] ; ; ldr r7,[r5,#CONTINUATION_NEXT] ; str r7,[r8,#TARGET_THREAD_CONTINUATION] ; ; ; call the continuation unless we're handling an exception ; ldr r7,[r8,#TARGET_THREAD_EXCEPTION] ; cmp r7,#0 ; bne vmInvoke_handleException) ; ldr r7,[r5,#CONTINUATION_ADDRESS] ; bx r7 ; ;vmInvoke_handleException ; ; we're handling an exception - call the exception handler instead ; mov r11,#0 ; str r11,[r8,#TARGET_THREAD_EXCEPTION] ; ldr r11,[r8,#TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT] ; ldr r9,[sp] ; neg r11,r11 ; str r9,[sp,r11]! ; ldr r11,[r8,#TARGET_THREAD_EXCEPTIONOFFSET] ; str r7,[sp,r11] ; ; ldr r7,[r8,#TARGET_THREAD_EXCEPTIONHANDLER] ; bx r7 ; ;vmInvoke_exit ;endif ; AVIAN_CONTINUATIONS mov ip, #0 str ip, [r8, #TARGET_THREAD_STACK] ; restore return type ldr ip, [sp], #4 ; restore callee-saved registers ldmfd sp!, {r4-r11, lr} vmInvoke_return bx lr EXPORT vmJumpAndInvoke vmJumpAndInvoke ;if :DEF:AVIAN_CONTINUATIONS ; ; r0: thread ; ; r1: address ; ; r2: stack ; ; r3: argumentFootprint ; ; [sp,#0]: arguments ; ; [sp,#4]: frameSize ; ; ldr r5,[sp,#0] ; ldr r6,[sp,#4] ; ; ; allocate new frame, adding room for callee-saved registers, plus ; ; 4 bytes of padding since the calculation of frameSize assumes 4 ; ; bytes have already been allocated to save the return address, ; ; which is not true in this case ; sub r2,r2,r6 ; sub r2,r2,#84 ; ; mov r8,r0 ; ; ; copy arguments into place ; mov r6,#0 ; b vmJumpAndInvoke_argumentTest ; ;vmJumpAndInvoke_argumentLoop ; ldr r12,[r5,r6] ; str r12,[r2,r6] ; add r6,r6,#4 ; ;vmJumpAndInvoke_argumentTest ; cmp r6,r3 ; ble vmJumpAndInvoke_argumentLoop ; ; ; the arguments have been copied, so we can set the real stack ; ; pointer now ; mov sp,r2 ; ; ; set return address to vmInvoke_returnAddress ; ldr r10,vmInvoke_returnAddress_word) ; ldr r11,vmJumpAndInvoke_getAddress_word) ;vmJumpAndInvoke_getAddress ; add r11,pc,r11 ; ldr lr,[r11,r10] ; ; bx r1 ; ;vmInvoke_returnAddress_word ; .word GLOBAL(vmInvoke_returnAddress)(GOT) ;vmInvoke_getAddress_word ; .word _GLOBAL_OFFSET_TABLE_-(vmInvoke_getAddress)+8) ;vmJumpAndInvoke_getAddress_word ; .word _GLOBAL_OFFSET_TABLE_-(vmJumpAndInvoke_getAddress)+8) ; ;else ; not AVIAN_CONTINUATIONS ; vmJumpAndInvoke should only be called when continuations are ; enabled bkpt 0 ;endif ; not AVIAN_CONTINUATIONS ENDReadyTalk-avian-1e1fff5/src/compile-powerpc.S000066400000000000000000000151671231440243200212120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/types.h" #include "avian/target-fields.h" .text #define BYTES_PER_WORD 4 #ifdef __APPLE__ # define GLOBAL(x) _##x # define LOCAL(x) L##x # define LINKAGE_AREA 6 # define RETURN_ADDRESS_OFFSET 8 #else # define GLOBAL(x) x # define LOCAL(x) .L##x # define LINKAGE_AREA 2 # define RETURN_ADDRESS_OFFSET 4 # include "powerpc-regs.S" #endif #define ARGUMENT_BASE BYTES_PER_WORD * LINKAGE_AREA #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 #define CONTINUATION_RETURN_ADDRESS_OFFSET 20 #define CONTINUATION_FRAME_POINTER_OFFSET 24 #define CONTINUATION_LENGTH 28 #define CONTINUATION_BODY 32 .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): // save return address mflr r0 stw r0,RETURN_ADDRESS_OFFSET(r1) // r3: thread // r4: function // r5: arguments // r6: argumentFootprint // r7: frameSize // r8: returnType // r9: temporary // allocate stack space, adding room for callee-saved registers and // return type subfic r9,r7,-80 stwux r1,r1,r9 // save callee-saved registers add r9,r7,r1 stw r13,0(r9) stw r14,4(r9) stw r15,8(r9) stw r16,12(r9) stw r17,16(r9) stw r18,20(r9) stw r19,24(r9) stw r20,28(r9) stw r21,32(r9) stw r22,36(r9) stw r23,40(r9) stw r24,44(r9) stw r25,48(r9) stw r26,52(r9) stw r27,56(r9) stw r28,60(r9) stw r29,64(r9) stw r30,68(r9) stw r31,72(r9) // save return type stw r8,76(r9) // we use r13 to hold the thread pointer, by convention mr r13,r3 // copy arguments into place li r16,0 addi r18,r1,ARGUMENT_BASE b LOCAL(vmInvoke_argumentTest) LOCAL(vmInvoke_argumentLoop): lwzx r17,r16,r5 stwx r17,r16,r18 addi r16,r16,BYTES_PER_WORD LOCAL(vmInvoke_argumentTest): cmplw r16,r6 blt LOCAL(vmInvoke_argumentLoop) // load and call function address mtctr r4 bctrl .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): // restore stack pointer lwz r1,0(r1) // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See // MyProcess::getStackTrace in compile.cpp for details on how we get // a reliable stack trace from a thread that might be interrupted at // any point in its execution. li r5,0 stw r5,TARGET_THREAD_STACK(r13) .globl GLOBAL(vmInvoke_safeStack) GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS // call the next continuation, if any lwz r5,TARGET_THREAD_CONTINUATION(r13) cmplwi r5,0 beq LOCAL(vmInvoke_exit) lwz r6,CONTINUATION_LENGTH(r5) slwi r6,r6,2 subfic r7,r6,-80 stwux r1,r1,r7 addi r7,r5,CONTINUATION_BODY li r8,0 addi r10,r1,ARGUMENT_BASE b LOCAL(vmInvoke_continuationTest) LOCAL(vmInvoke_continuationLoop): lwzx r9,r7,r8 stwx r9,r10,r8 addi r8,r8,4 LOCAL(vmInvoke_continuationTest): cmplw r8,r6 ble LOCAL(vmInvoke_continuationLoop) lwz r7,CONTINUATION_RETURN_ADDRESS_OFFSET(r5) bl LOCAL(vmInvoke_getPC) LOCAL(vmInvoke_getPC): mflr r10 #ifdef __APPLE__ la r10,lo16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_getPC))(r10) #else lwz r10,LOCAL(vmInvoke_returnAddress_address)-LOCAL(vmInvoke_getPC)(r10) #endif stwx r10,r1,r7 lwz r7,CONTINUATION_FRAME_POINTER_OFFSET(r5) lwz r8,0(r1) add r7,r7,r1 stw r8,0(r7) stw r7,0(r1) lwz r7,CONTINUATION_NEXT(r5) stw r7,TARGET_THREAD_CONTINUATION(r13) // call the continuation unless we're handling an exception lwz r7,TARGET_THREAD_EXCEPTION(r13) cmpwi r7,0 bne LOCAL(vmInvoke_handleException) lwz r7,CONTINUATION_ADDRESS(r5) mtctr r7 bctr LOCAL(vmInvoke_handleException): // we're handling an exception - call the exception handler instead li r8,0 stw r8,TARGET_THREAD_EXCEPTION(r13) lwz r8,TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT(r13) lwz r9,0(r1) subfic r8,r8,0 stwux r9,r1,r8 lwz r8,TARGET_THREAD_EXCEPTIONOFFSET(r13) stwx r7,r1,r8 lwz r7,TARGET_THREAD_EXCEPTIONHANDLER(r13) mtctr r7 bctr LOCAL(vmInvoke_exit): #endif // AVIAN_CONTINUATIONS // restore callee-saved registers subi r9,r1,80 lwz r13,0(r9) lwz r14,4(r9) lwz r15,8(r9) lwz r16,12(r9) lwz r17,16(r9) lwz r18,20(r9) lwz r19,24(r9) lwz r20,28(r9) lwz r21,32(r9) lwz r22,36(r9) lwz r23,40(r9) lwz r24,44(r9) lwz r25,48(r9) lwz r26,52(r9) lwz r27,56(r9) lwz r28,60(r9) lwz r29,64(r9) lwz r30,68(r9) lwz r31,72(r9) // handle return value based on expected type lwz r8,76(r9) LOCAL(vmInvoke_return): // load return address lwz r0,RETURN_ADDRESS_OFFSET(r1) mtlr r0 // return blr #ifndef __APPLE__ LOCAL(vmInvoke_returnAddress_address): .long GLOBAL(vmInvoke_returnAddress) #endif .globl GLOBAL(vmJumpAndInvoke) GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // r3: thread // r4: address // r5: stack // r6: argumentFootprint // r7: arguments // r8: frameSize // restore (pseudo)-stack pointer (we don't want to touch the real // stack pointer, since we haven't copied the arguments yet) lwz r5,0(r5) // make everything between r1 and r5 one big stack frame while we // shuffle things around stw r5,0(r1) // allocate new frame, adding room for callee-saved registers subfic r10,r8,-80 stwux r5,r5,r10 mr r13,r3 // copy arguments into place li r8,0 addi r11,r5,ARGUMENT_BASE b LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): lwzx r12,r7,r8 stwx r12,r11,r8 addi r8,r8,4 LOCAL(vmJumpAndInvoke_argumentTest): cmplw r8,r6 ble LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack // pointer now mr r1,r5 // set return address to vmInvoke_returnAddress bl LOCAL(vmJumpAndInvoke_getPC) LOCAL(vmJumpAndInvoke_getPC): mflr r10 #ifdef __APPLE__ la r10,lo16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_getPC))(r10) #else lwz r10,LOCAL(vmInvoke_returnAddress_address)-LOCAL(vmJumpAndInvoke_getPC)(r10) #endif mtlr r10 mtctr r4 bctr #else // not AVIAN_CONTINUATIONS // vmJumpAndInvoke should only be called when continuations are // enabled trap #endif // not AVIAN_CONTINUATIONS ReadyTalk-avian-1e1fff5/src/compile-x86.S000066400000000000000000000260401231440243200201500ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/types.h" #include "avian/target-fields.h" #define LOCAL(x) .L##x #if defined __APPLE__ \ || ((defined __MINGW32__ || defined __CYGWIN32__) && ! defined __x86_64__) # define GLOBAL(x) _##x #else # define GLOBAL(x) x #endif .text #ifdef __x86_64__ #ifdef AVIAN_USE_FRAME_POINTER # define ALIGNMENT_ADJUSTMENT 0 #else # define ALIGNMENT_ADJUSTMENT 8 #endif #if defined __MINGW32__ || defined __CYGWIN32__ #define CALLEE_SAVED_REGISTER_FOOTPRINT 64 + ALIGNMENT_ADJUSTMENT .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): pushq %rbp movq %rsp,%rbp // %rcx: thread // %rdx: function // %r8 : arguments // %r9 : argumentsFootprint // 48(%rbp) : frameSize // 56(%rbp) : returnType (ignored) // allocate stack space for callee-saved registers subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp // remember this stack position, since we won't be able to rely on // %rbp being restored when the call returns movq %rsp,TARGET_THREAD_SCRATCH(%rcx) // save callee-saved registers movq %rbx,0(%rsp) movq %r12,8(%rsp) movq %r13,16(%rsp) movq %r14,24(%rsp) movq %r15,32(%rsp) movq %rsi,40(%rsp) movq %rdi,48(%rsp) // allocate stack space for arguments movl 48(%rbp),%eax subq %rax,%rsp // we use rbx to hold the thread pointer, by convention mov %rcx,%rbx // copy arguments into place movq $0,%r11 jmp LOCAL(vmInvoke_argumentTest) LOCAL(vmInvoke_argumentLoop): movq (%r8,%r11,1),%rsi movq %rsi,(%rsp,%r11,1) addq $8,%r11 LOCAL(vmInvoke_argumentTest): cmpq %r9,%r11 jb LOCAL(vmInvoke_argumentLoop) // call function call *%rdx .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): // restore stack pointer movq TARGET_THREAD_SCRATCH(%rbx),%rsp // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See // MyProcess::getStackTrace in compile.cpp for details on how we get // a reliable stack trace from a thread that might be interrupted at // any point in its execution. movq $0,TARGET_THREAD_STACK(%rbx) .globl GLOBAL(vmInvoke_safeStack) GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS # include "continuations-x86.S" #endif // AVIAN_CONTINUATIONS // restore callee-saved registers movq 0(%rsp),%rbx movq 8(%rsp),%r12 movq 16(%rsp),%r13 movq 24(%rsp),%r14 movq 32(%rsp),%r15 movq 40(%rsp),%rsi movq 48(%rsp),%rdi addq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp // return popq %rbp ret .globl GLOBAL(vmJumpAndInvoke) GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // %rcx: thread // %rdx: address // %r8 : stack // %r9 : argumentFootprint // 40(%rsp): arguments // 48(%rsp): frameSize // allocate new frame, adding room for callee-saved registers movl 48(%rsp),%eax subq %rax,%r8 subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r8 movq %rcx,%rbx // set return address leaq GLOBAL(vmInvoke_returnAddress)(%rip),%r10 movq %r10,(%r8) // copy arguments into place movq $0,%r11 movl 40(%rsp),%eax jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): movq (%rax,%r11,1),%r10 movq %r10,8(%r8,%r11,1) addq $8,%r11 LOCAL(vmJumpAndInvoke_argumentTest): cmpq %r9,%r11 jb LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack // pointer now movq %r8,%rsp jmp *%rdx #else // not AVIAN_CONTINUATIONS // vmJumpAndInvoke should only be called when continuations are // enabled int3 #endif // not AVIAN_CONTINUATIONS #else // not __MINGW32__ || __CYGWIN32__ #define CALLEE_SAVED_REGISTER_FOOTPRINT 48 + ALIGNMENT_ADJUSTMENT .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): pushq %rbp movq %rsp,%rbp // %rdi: thread // %rsi: function // %rdx: arguments // %rcx: argumentFootprint // %r8 : frameSize // %r9 : returnType (ignored) // allocate stack space for callee-saved registers subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp // remember this stack position, since we won't be able to rely on // %rbp being restored when the call returns movq %rsp,TARGET_THREAD_SCRATCH(%rdi) // save callee-saved registers movq %rbx,0(%rsp) movq %r12,8(%rsp) movq %r13,16(%rsp) movq %r14,24(%rsp) movq %r15,32(%rsp) // allocate stack space for arguments subq %r8,%rsp // we use rbx to hold the thread pointer, by convention mov %rdi,%rbx // copy arguments into place movq $0,%r9 jmp LOCAL(vmInvoke_argumentTest) LOCAL(vmInvoke_argumentLoop): movq (%rdx,%r9,1),%r8 movq %r8,(%rsp,%r9,1) addq $8,%r9 LOCAL(vmInvoke_argumentTest): cmpq %rcx,%r9 jb LOCAL(vmInvoke_argumentLoop) // call function call *%rsi .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): // restore stack pointer movq TARGET_THREAD_SCRATCH(%rbx),%rsp // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See // MyProcess::getStackTrace in compile.cpp for details on how we get // a reliable stack trace from a thread that might be interrupted at // any point in its execution. movq $0,TARGET_THREAD_STACK(%rbx) .globl GLOBAL(vmInvoke_safeStack) GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS # include "continuations-x86.S" #endif // AVIAN_CONTINUATIONS // restore callee-saved registers movq 0(%rsp),%rbx movq 8(%rsp),%r12 movq 16(%rsp),%r13 movq 24(%rsp),%r14 movq 32(%rsp),%r15 addq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp // return popq %rbp ret .globl GLOBAL(vmJumpAndInvoke) GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // %rdi: thread // %rsi: address // %rdx: stack // %rcx: argumentFootprint // %r8 : arguments // %r9 : frameSize // allocate new frame, adding room for callee-saved registers subq %r9,%rdx subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rdx movq %rdi,%rbx // set return address movq GLOBAL(vmInvoke_returnAddress)@GOTPCREL(%rip),%r10 movq %r10,(%rdx) // copy arguments into place movq $0,%r11 jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): movq (%r8,%r11,1),%r10 movq %r10,8(%rdx,%r11,1) addq $8,%r11 LOCAL(vmJumpAndInvoke_argumentTest): cmpq %rcx,%r11 jb LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack // pointer now movq %rdx,%rsp jmp *%rsi #else // not AVIAN_CONTINUATIONS // vmJumpAndInvoke should only be called when continuations are // enabled int3 #endif // not AVIAN_CONTINUATIONS #endif // not __MINGW32__ || __CYGWIN32__ #elif defined __i386__ #ifdef AVIAN_USE_FRAME_POINTER # define ALIGNMENT_ADJUSTMENT 0 #else # define ALIGNMENT_ADJUSTMENT 12 #endif #define CALLEE_SAVED_REGISTER_FOOTPRINT 16 + ALIGNMENT_ADJUSTMENT .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): pushl %ebp movl %esp,%ebp // 8(%ebp): thread // 12(%ebp): function // 16(%ebp): arguments // 20(%ebp): argumentFootprint // 24(%ebp): frameSize // 28(%ebp): returnType // allocate stack space for callee-saved registers subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp // remember this stack position, since we won't be able to rely on // %rbp being restored when the call returns movl 8(%ebp),%eax movl %esp,TARGET_THREAD_SCRATCH(%eax) movl %ebx,0(%esp) movl %esi,4(%esp) movl %edi,8(%esp) // allocate stack space for arguments subl 24(%ebp),%esp // we use ebx to hold the thread pointer, by convention mov %eax,%ebx // copy arguments into place movl $0,%ecx movl 16(%ebp),%edx jmp LOCAL(vmInvoke_argumentTest) LOCAL(vmInvoke_argumentLoop): movl (%edx,%ecx,1),%eax movl %eax,(%esp,%ecx,1) addl $4,%ecx LOCAL(vmInvoke_argumentTest): cmpl 20(%ebp),%ecx jb LOCAL(vmInvoke_argumentLoop) // call function call *12(%ebp) .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): // restore stack pointer movl TARGET_THREAD_SCRATCH(%ebx),%esp // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See // MyProcess::getStackTrace in compile.cpp for details on how we get // a reliable stack trace from a thread that might be interrupted at // any point in its execution. movl $0,TARGET_THREAD_STACK(%ebx) .globl GLOBAL(vmInvoke_safeStack) GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS # include "continuations-x86.S" #endif // AVIAN_CONTINUATIONS // restore callee-saved registers movl 0(%esp),%ebx movl 4(%esp),%esi movl 8(%esp),%edi addl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp // handle return value based on expected type movl 28(%esp),%ecx popl %ebp ret LOCAL(getPC): movl (%esp),%esi ret .globl GLOBAL(vmJumpAndInvoke) GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // 4(%esp): thread // 8(%esp): address // 12(%esp): stack // 16(%esp): argumentFootprint // 20(%esp): arguments // 24(%esp): frameSize movl 12(%esp),%ecx // allocate new frame, adding room for callee-saved registers subl 24(%esp),%ecx subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx movl 4(%esp),%ebx // set return address #if defined __MINGW32__ || defined __CYGWIN32__ movl $GLOBAL(vmInvoke_returnAddress),%esi #else call LOCAL(getPC) # if defined __APPLE__ LOCAL(vmJumpAndInvoke_offset): leal GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_offset)(%esi),%esi # else addl $_GLOBAL_OFFSET_TABLE_,%esi movl GLOBAL(vmInvoke_returnAddress)@GOT(%esi),%esi # endif #endif movl %esi,(%ecx) // copy arguments into place movl $0,%esi movl 16(%esp),%edx movl 20(%esp),%eax jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): movl (%eax,%esi,1),%edi movl %edi,4(%ecx,%esi,1) addl $4,%esi LOCAL(vmJumpAndInvoke_argumentTest): cmpl %edx,%esi jb LOCAL(vmJumpAndInvoke_argumentLoop) movl 8(%esp),%esi // the arguments have been copied, so we can set the real stack // pointer now movl %ecx,%esp jmp *%esi #else // not AVIAN_CONTINUATIONS // vmJumpAndInvoke should only be called when continuations are // enabled int3 #endif // AVIAN_CONTINUATIONS #else #error unsupported architecture #endif //def __x86_64__ ReadyTalk-avian-1e1fff5/src/compile-x86.masm000066400000000000000000000076471231440243200207170ustar00rootroot00000000000000comment # Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. ORIGIN: https://github.com/gkvas/avian/tree/wince # .586 .MODEL FLAT, C comment # types.h # VOID_TYPE equ 0 INT8_TYPE equ 1 INT16_TYPE equ 2 INT32_TYPE equ 3 INT64_TYPE equ 4 FLOAT_TYPE equ 5 DOUBLE_TYPE equ 6 POINTER_TYPE equ 7 comment # target-fields.h # ifdef TARGET_BYTES_PER_WORD if TARGET_BYTES_PER_WORD eq 8 TARGET_THREAD_EXCEPTION equ 80 TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT equ 2256 TARGET_THREAD_EXCEPTIONOFFSET equ 2264 TARGET_THREAD_EXCEPTIONHANDLER equ 2272 TARGET_THREAD_IP equ 2216 TARGET_THREAD_STACK equ 2224 TARGET_THREAD_NEWSTACK equ 2232 TARGET_THREAD_SCRATCH equ 2240 TARGET_THREAD_CONTINUATION equ 2248 TARGET_THREAD_TAILADDRESS equ 2280 TARGET_THREAD_VIRTUALCALLTARGET equ 2288 TARGET_THREAD_VIRTUALCALLINDEX equ 2296 TARGET_THREAD_HEAPIMAGE equ 2304 TARGET_THREAD_CODEIMAGE equ 2312 TARGET_THREAD_THUNKTABLE equ 2320 TARGET_THREAD_STACKLIMIT equ 2368 elseif TARGET_BYTES_PER_WORD eq 4 TARGET_THREAD_EXCEPTION equ 44 TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT equ 2164 TARGET_THREAD_EXCEPTIONOFFSET equ 2168 TARGET_THREAD_EXCEPTIONHANDLER equ 2172 TARGET_THREAD_IP equ 2144 TARGET_THREAD_STACK equ 2148 TARGET_THREAD_NEWSTACK equ 2152 TARGET_THREAD_SCRATCH equ 2156 TARGET_THREAD_CONTINUATION equ 2160 TARGET_THREAD_TAILADDRESS equ 2176 TARGET_THREAD_VIRTUALCALLTARGET equ 2180 TARGET_THREAD_VIRTUALCALLINDEX equ 2184 TARGET_THREAD_HEAPIMAGE equ 2188 TARGET_THREAD_CODEIMAGE equ 2192 TARGET_THREAD_THUNKTABLE equ 2196 TARGET_THREAD_STACKLIMIT equ 2220 else error endif else error endif ifdef AVIAN_USE_FRAME_POINTER ALIGNMENT_ADJUSTMENT equ 0 else ALIGNMENT_ADJUSTMENT equ 12 endif CALLEE_SAVED_REGISTER_FOOTPRINT equ 16 + ALIGNMENT_ADJUSTMENT _TEXT SEGMENT public C vmInvoke vmInvoke: push ebp mov ebp,esp ; 8(%ebp): thread ; 12(%ebp): function ; 16(%ebp): arguments ; 20(%ebp): argumentFootprint ; 24(%ebp): frameSize ; 28(%ebp): returnType ; allocate stack space for callee-saved registers sub esp,offset CALLEE_SAVED_REGISTER_FOOTPRINT ; remember this stack position, since we won't be able to rely on ; %rbp being restored when the call returns mov eax,ds:dword ptr[8+ebp] mov ds:dword ptr[TARGET_THREAD_SCRATCH+eax],esp mov ds:dword ptr[0+esp],ebx mov ds:dword ptr[4+esp],esi mov ds:dword ptr[8+esp],edi ; allocate stack space for arguments sub esp,ds:dword ptr[24+ebp] ; we use ebx to hold the thread pointer, by convention mov ebx,eax ; copy arguments into place mov ecx,0 mov edx,ds:dword ptr[16+ebp] jmp LvmInvoke_argumentTest LvmInvoke_argumentLoop: mov eax,ds:dword ptr[edx+ecx*1] mov ds:dword ptr[esp+ecx*1],eax add ecx,4 LvmInvoke_argumentTest: cmp ecx,ds:dword ptr[20+ebp] jb LvmInvoke_argumentLoop ; call function call dword ptr[12+ebp] public vmInvoke_returnAddress vmInvoke_returnAddress: ; restore stack pointer mov esp,ds:dword ptr[TARGET_THREAD_SCRATCH+ebx] ; clear MyThread::stack to avoid confusing another thread calling ; java.lang.Thread.getStackTrace on this one. See ; MyProcess::getStackTrace in compile.cpp for details on how we get ; a reliable stack trace from a thread that might be interrupted at ; any point in its execution. mov ds:dword ptr[TARGET_THREAD_STACK+ebx],0 public vmInvoke_safeStack vmInvoke_safeStack: ; restore callee-saved registers mov ebx,ds:dword ptr[0+esp] mov esi,ds:dword ptr[4+esp] mov edi,ds:dword ptr[8+esp] add esp,offset CALLEE_SAVED_REGISTER_FOOTPRINT mov ecx,ds:dword ptr[28+esp] pop ebp ret LgetPC: mov esi,ds:dword ptr[esp] ret public vmJumpAndInvoke vmJumpAndInvoke: ; vmJumpAndInvoke should only be called when continuations are ; enabled int 3 _TEXT ENDS END ReadyTalk-avian-1e1fff5/src/compile.cpp000066400000000000000000010254131231440243200201110ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/machine.h" #include "avian/util.h" #include "avian/alloc-vector.h" #include "avian/process.h" #include "avian/target.h" #include "avian/arch.h" #include #include #include #include #include #include #include #include #include #include using namespace vm; extern "C" uint64_t vmInvoke(void* thread, void* function, void* arguments, unsigned argumentFootprint, unsigned frameSize, unsigned returnType); extern "C" void vmInvoke_returnAddress(); extern "C" void vmInvoke_safeStack(); extern "C" void vmJumpAndInvoke(void* thread, void* function, void* stack, unsigned argumentFootprint, uintptr_t* arguments, unsigned frameSize); using namespace avian::codegen; using namespace avian::system; namespace { namespace local { const bool DebugCompile = false; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; const bool DebugFrameMaps = false; const bool CheckArrayBounds = true; #ifdef AVIAN_CONTINUATIONS const bool Continuations = true; #else const bool Continuations = false; #endif const unsigned MaxNativeCallFootprint = TargetBytesPerWord == 8 ? 4 : 5; const unsigned InitialZoneCapacityInBytes = 64 * 1024; const unsigned ExecutableAreaSizeInBytes = 30 * 1024 * 1024; enum Root { CallTable, MethodTree, MethodTreeSentinal, ObjectPools, StaticTableArray, VirtualThunks, ReceiveMethod, WindMethod, RewindMethod }; enum ThunkIndex { compileMethodIndex, compileVirtualMethodIndex, invokeNativeIndex, throwArrayIndexOutOfBoundsIndex, throwStackOverflowIndex, #define THUNK(s) s##Index, #include "thunks.cpp" #undef THUNK dummyIndex }; const unsigned RootCount = RewindMethod + 1; inline bool isVmInvokeUnsafeStack(void* ip) { return reinterpret_cast(ip) >= reinterpret_cast(voidPointer(vmInvoke_returnAddress)) and reinterpret_cast(ip) < reinterpret_cast (voidPointer(vmInvoke_safeStack)); } class MyThread; void* getIp(MyThread*); class MyThread: public Thread { public: class CallTrace { public: CallTrace(MyThread* t, object method): t(t), ip(getIp(t)), stack(t->stack), scratch(t->scratch), continuation(t->continuation), nativeMethod((methodFlags(t, method) & ACC_NATIVE) ? method : 0), targetMethod(0), originalMethod(method), next(t->trace) { doTransition(t, 0, 0, 0, this); } ~CallTrace() { assert(t, t->stack == 0); t->scratch = scratch; doTransition(t, ip, stack, continuation, next); } MyThread* t; void* ip; void* stack; void* scratch; object continuation; object nativeMethod; object targetMethod; object originalMethod; CallTrace* next; }; class Context { public: class MyProtector: public Thread::Protector { public: MyProtector(MyThread* t, Context* context): Protector(t), context(context) { } virtual void visit(Heap::Visitor* v) { v->visit(&(context->continuation)); } Context* context; }; Context(MyThread* t, void* ip, void* stack, object continuation, CallTrace* trace): ip(ip), stack(stack), continuation(continuation), trace(trace), protector(t, this) { } void* ip; void* stack; object continuation; CallTrace* trace; MyProtector protector; }; class TraceContext: public Context { public: TraceContext(MyThread* t, void* ip, void* stack, object continuation, CallTrace* trace): Context(t, ip, stack, continuation, trace), t(t), link(0), next(t->traceContext), methodIsMostRecent(false) { t->traceContext = this; } TraceContext(MyThread* t, void* link): Context(t, t->ip, t->stack, t->continuation, t->trace), t(t), link(link), next(t->traceContext), methodIsMostRecent(false) { t->traceContext = this; } ~TraceContext() { t->traceContext = next; } MyThread* t; void* link; TraceContext* next; bool methodIsMostRecent; }; static void doTransition(MyThread* t, void* ip, void* stack, object continuation, MyThread::CallTrace* trace) { // in this function, we "atomically" update the thread context // fields in such a way to ensure that another thread may // interrupt us at any time and still get a consistent, accurate // stack trace. See MyProcessor::getStackTrace for details. assert(t, t->transition == 0); Context c(t, ip, stack, continuation, trace); compileTimeMemoryBarrier(); t->transition = &c; compileTimeMemoryBarrier(); t->ip = ip; t->stack = stack; t->continuation = continuation; t->trace = trace; compileTimeMemoryBarrier(); t->transition = 0; } MyThread(Machine* m, object javaThread, MyThread* parent, bool useNativeFeatures): Thread(m, javaThread, parent), ip(0), stack(0), newStack(0), scratch(0), continuation(0), exceptionStackAdjustment(0), exceptionOffset(0), exceptionHandler(0), tailAddress(0), virtualCallTarget(0), virtualCallIndex(0), heapImage(0), codeImage(0), thunkTable(0), trace(0), reference(0), arch(parent ? parent->arch : avian::codegen::makeArchitectureNative(m->system, useNativeFeatures)), transition(0), traceContext(0), stackLimit(0), referenceFrame(0), methodLockIsClean(true) { arch->acquire(); } void* ip; void* stack; void* newStack; void* scratch; object continuation; uintptr_t exceptionStackAdjustment; uintptr_t exceptionOffset; void* exceptionHandler; void* tailAddress; void* virtualCallTarget; uintptr_t virtualCallIndex; uintptr_t* heapImage; uint8_t* codeImage; void** thunkTable; CallTrace* trace; Reference* reference; avian::codegen::Architecture* arch; Context* transition; TraceContext* traceContext; uintptr_t stackLimit; List* referenceFrame; bool methodLockIsClean; }; void transition(MyThread* t, void* ip, void* stack, object continuation, MyThread::CallTrace* trace) { MyThread::doTransition(t, ip, stack, continuation, trace); } object resolveThisPointer(MyThread* t, void* stack) { return reinterpret_cast(stack) [t->arch->frameFooterSize() + t->arch->frameReturnAddressSize()]; } object findMethod(Thread* t, object method, object instance) { if ((methodFlags(t, method) & ACC_STATIC) == 0) { if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { return findInterfaceMethod(t, method, objectClass(t, instance)); } else if (methodVirtual(t, method)) { return findVirtualMethod(t, method, objectClass(t, instance)); } } return method; } object resolveTarget(MyThread* t, void* stack, object method) { object class_ = objectClass(t, resolveThisPointer(t, stack)); if (classVmFlags(t, class_) & BootstrapFlag) { PROTECT(t, method); PROTECT(t, class_); resolveSystemClass(t, root(t, Machine::BootLoader), className(t, class_)); } if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { return findInterfaceMethod(t, method, class_); } else { return findVirtualMethod(t, method, class_); } } object resolveTarget(MyThread* t, object class_, unsigned index) { if (classVmFlags(t, class_) & BootstrapFlag) { PROTECT(t, class_); resolveSystemClass(t, root(t, Machine::BootLoader), className(t, class_)); } return arrayBody(t, classVirtualTable(t, class_), index); } object& root(Thread* t, Root root); void setRoot(Thread* t, Root root, object value); intptr_t methodCompiled(Thread* t, object method) { return codeCompiled(t, methodCode(t, method)); } unsigned methodCompiledSize(Thread* t, object method) { return codeCompiledSize(t, methodCode(t, method)); } intptr_t compareIpToMethodBounds(Thread* t, intptr_t ip, object method) { intptr_t start = methodCompiled(t, method); if (DebugMethodTree) { fprintf(stderr, "find %p in (%p,%p)\n", reinterpret_cast(ip), reinterpret_cast(start), reinterpret_cast(start + methodCompiledSize(t, method))); } if (ip < start) { return -1; } else if (ip < start + static_cast (methodCompiledSize(t, method))) { return 0; } else { return 1; } } object methodForIp(MyThread* t, void* ip) { if (DebugMethodTree) { fprintf(stderr, "query for method containing %p\n", ip); } // we must use a version of the method tree at least as recent as the // compiled form of the method containing the specified address (see // compile(MyThread*, FixedAllocator*, BootContext*, object)): loadMemoryBarrier(); return treeQuery(t, root(t, MethodTree), reinterpret_cast(ip), root(t, MethodTreeSentinal), compareIpToMethodBounds); } unsigned localSize(MyThread* t, object method) { unsigned size = codeMaxLocals(t, methodCode(t, method)); if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC)) == ACC_SYNCHRONIZED) { ++ size; } return size; } unsigned alignedFrameSize(MyThread* t, object method) { return t->arch->alignFrameSize (localSize(t, method) - methodParameterFootprint(t, method) + codeMaxStack(t, methodCode(t, method)) + t->arch->frameFootprint(MaxNativeCallFootprint)); } void nextFrame(MyThread* t, void** ip, void** sp, object method, object target, bool mostRecent) { object code = methodCode(t, method); intptr_t start = codeCompiled(t, code); void* link; bool methodIsMostRecent; if (t->traceContext) { link = t->traceContext->link; methodIsMostRecent = mostRecent and t->traceContext->methodIsMostRecent; } else { link = 0; methodIsMostRecent = false; } // fprintf(stderr, "nextFrame %s.%s%s target %s.%s%s ip %p sp %p\n", // &byteArrayBody(t, className(t, methodClass(t, method)), 0), // &byteArrayBody(t, methodName(t, method), 0), // &byteArrayBody(t, methodSpec(t, method), 0), // target // ? &byteArrayBody(t, className(t, methodClass(t, target)), 0) // : 0, // target // ? &byteArrayBody(t, methodName(t, target), 0) // : 0, // target // ? &byteArrayBody(t, methodSpec(t, target), 0) // : 0, // *ip, *sp); t->arch->nextFrame (reinterpret_cast(start), codeCompiledSize(t, code), alignedFrameSize(t, method), link, methodIsMostRecent, target ? methodParameterFootprint(t, target) : -1, ip, sp); // fprintf(stderr, "next frame ip %p sp %p\n", *ip, *sp); } void* getIp(MyThread* t, void* ip, void* stack) { // Here we use the convention that, if the return address is neither // pushed on to the stack automatically as part of the call nor // stored in the caller's frame, it will be saved in MyThread::ip // instead of on the stack. See the various implementations of // Assembler::saveFrame for details on how this is done. return t->arch->returnAddressOffset() < 0 ? ip : t->arch->frameIp(stack); } void* getIp(MyThread* t) { return getIp(t, t->ip, t->stack); } class MyStackWalker: public Processor::StackWalker { public: enum State { Start, Next, Trace, Continuation, Method, NativeMethod, Finish }; class MyProtector: public Thread::Protector { public: MyProtector(MyStackWalker* walker): Protector(walker->t), walker(walker) { } virtual void visit(Heap::Visitor* v) { v->visit(&(walker->method_)); v->visit(&(walker->target)); v->visit(&(walker->continuation)); } MyStackWalker* walker; }; MyStackWalker(MyThread* t): t(t), state(Start), method_(0), target(0), count_(0), protector(this) { if (t->traceContext) { ip_ = t->traceContext->ip; stack = t->traceContext->stack; trace = t->traceContext->trace; continuation = t->traceContext->continuation; } else { ip_ = getIp(t); stack = t->stack; trace = t->trace; continuation = t->continuation; } } MyStackWalker(MyStackWalker* w): t(w->t), state(w->state), ip_(w->ip_), stack(w->stack), trace(w->trace), method_(w->method_), target(w->target), continuation(w->continuation), count_(w->count_), protector(this) { } virtual void walk(Processor::StackVisitor* v) { for (MyStackWalker it(this); it.valid();) { MyStackWalker walker(&it); if (not v->visit(&walker)) { break; } it.next(); } } bool valid() { while (true) { // fprintf(stderr, "state: %d\n", state); switch (state) { case Start: if (trace and trace->nativeMethod) { method_ = trace->nativeMethod; state = NativeMethod; } else { state = Next; } break; case Next: if (stack) { target = method_; method_ = methodForIp(t, ip_); if (method_) { state = Method; } else if (continuation) { method_ = continuationMethod(t, continuation); state = Continuation; } else { state = Trace; } } else { state = Trace; } break; case Trace: { if (trace) { continuation = trace->continuation; stack = trace->stack; ip_ = trace->ip; trace = trace->next; state = Start; } else { state = Finish; } } break; case Continuation: case Method: case NativeMethod: return true; case Finish: return false; default: abort(t); } } } void next() { expect(t, count_ <= stackSizeInWords(t)); switch (state) { case Continuation: continuation = continuationNext(t, continuation); break; case Method: nextFrame(t, &ip_, &stack, method_, target, count_ == 0); break; case NativeMethod: break; default: abort(t); } ++ count_; state = Next; } virtual object method() { // fprintf(stderr, "method %s.%s\n", &byteArrayBody // (t, className(t, methodClass(t, method_)), 0), // &byteArrayBody(t, methodName(t, method_), 0)); return method_; } virtual int ip() { switch (state) { case Continuation: return reinterpret_cast(continuationAddress(t, continuation)) - methodCompiled(t, continuationMethod(t, continuation)); case Method: return reinterpret_cast(ip_) - methodCompiled(t, method_); case NativeMethod: return 0; default: abort(t); } } virtual unsigned count() { unsigned count = 0; for (MyStackWalker walker(this); walker.valid();) { walker.next(); ++ count; } return count; } MyThread* t; State state; void* ip_; void* stack; MyThread::CallTrace* trace; object method_; object target; object continuation; unsigned count_; MyProtector protector; }; int localOffset(MyThread* t, int v, object method) { int parameterFootprint = methodParameterFootprint(t, method); int frameSize = alignedFrameSize(t, method); int offset = ((v < parameterFootprint) ? (frameSize + parameterFootprint + t->arch->frameFooterSize() + t->arch->frameHeaderSize() - v - 1) : (frameSize + parameterFootprint - v - 1)); assert(t, offset >= 0); return offset; } int localOffsetFromStack(MyThread* t, int index, object method) { return localOffset(t, index, method) + t->arch->frameReturnAddressSize(); } object* localObject(MyThread* t, void* stack, object method, unsigned index) { return static_cast(stack) + localOffsetFromStack(t, index, method); } int stackOffsetFromFrame(MyThread* t, object method) { return alignedFrameSize(t, method) + t->arch->frameHeaderSize(); } void* stackForFrame(MyThread* t, void* frame, object method) { return static_cast(frame) - stackOffsetFromFrame(t, method); } class PoolElement: public avian::codegen::Promise { public: PoolElement(Thread* t, object target, PoolElement* next): t(t), target(target), address(0), next(next) { } virtual int64_t value() { assert(t, resolved()); return address; } virtual bool resolved() { return address != 0; } Thread* t; object target; intptr_t address; PoolElement* next; }; class Context; class SubroutineCall; class Subroutine { public: Subroutine(unsigned ip, unsigned logIndex, Subroutine* listNext, Subroutine* stackNext): listNext(listNext), stackNext(stackNext), calls(0), handle(0), ip(ip), logIndex(logIndex), stackIndex(0), callCount(0), tableIndex(0), visited(false) { } Subroutine* listNext; Subroutine* stackNext; SubroutineCall* calls; Compiler::Subroutine* handle; unsigned ip; unsigned logIndex; unsigned stackIndex; unsigned callCount; unsigned tableIndex; bool visited; }; class SubroutinePath; class SubroutineCall { public: SubroutineCall(Subroutine* subroutine, avian::codegen::Promise* returnAddress): subroutine(subroutine), returnAddress(returnAddress), paths(0), next(subroutine->calls) { subroutine->calls = this; ++ subroutine->callCount; } Subroutine* subroutine; avian::codegen::Promise* returnAddress; SubroutinePath* paths; SubroutineCall* next; }; class SubroutinePath { public: SubroutinePath(SubroutineCall* call, SubroutinePath* stackNext, uintptr_t* rootTable): call(call), stackNext(stackNext), listNext(call->paths), rootTable(rootTable) { call->paths = this; } SubroutineCall* call; SubroutinePath* stackNext; SubroutinePath* listNext; uintptr_t* rootTable; }; void print(SubroutinePath* path) { if (path) { fprintf(stderr, " ("); while (true) { fprintf(stderr, "%p", path->call->returnAddress->resolved() ? reinterpret_cast(path->call->returnAddress->value()) : 0); path = path->stackNext; if (path) { fprintf(stderr, ", "); } else { break; } } fprintf(stderr, ")"); } } class SubroutineTrace { public: SubroutineTrace(SubroutinePath* path, SubroutineTrace* next, unsigned mapSize): path(path), next(next), watch(false) { memset(map, 0, mapSize * BytesPerWord); } SubroutinePath* path; SubroutineTrace* next; bool watch; uintptr_t map[0]; }; class TraceElement: public avian::codegen::TraceHandler { public: static const unsigned VirtualCall = 1 << 0; static const unsigned TailCall = 1 << 1; static const unsigned LongCall = 1 << 2; TraceElement(Context* context, unsigned ip, object target, unsigned flags, TraceElement* next, unsigned mapSize): context(context), address(0), next(next), subroutineTrace(0), target(target), ip(ip), subroutineTraceCount(0), argumentIndex(0), flags(flags), watch(false) { memset(map, 0xFF, mapSize * BytesPerWord); } virtual void handleTrace(avian::codegen::Promise* address, unsigned argumentIndex) { if (this->address == 0) { this->address = address; this->argumentIndex = argumentIndex; } } Context* context; avian::codegen::Promise* address; TraceElement* next; SubroutineTrace* subroutineTrace; object target; unsigned ip; unsigned subroutineTraceCount; unsigned argumentIndex; unsigned flags; bool watch; uintptr_t map[0]; }; class TraceElementPromise: public avian::codegen::Promise { public: TraceElementPromise(System* s, TraceElement* trace): s(s), trace(trace) { } virtual int64_t value() { assert(s, resolved()); return trace->address->value(); } virtual bool resolved() { return trace->address != 0 and trace->address->resolved(); } System* s; TraceElement* trace; }; enum Event { PushContextEvent, PopContextEvent, IpEvent, MarkEvent, ClearEvent, PushExceptionHandlerEvent, TraceEvent, PushSubroutineEvent, PopSubroutineEvent }; unsigned frameMapSizeInBits(MyThread* t, object method) { return localSize(t, method) + codeMaxStack(t, methodCode(t, method)); } unsigned frameMapSizeInWords(MyThread* t, object method) { return ceilingDivide(frameMapSizeInBits(t, method), BitsPerWord); } uint16_t* makeVisitTable(MyThread* t, Zone* zone, object method) { unsigned size = codeLength(t, methodCode(t, method)) * 2; uint16_t* table = static_cast(zone->allocate(size)); memset(table, 0, size); return table; } uintptr_t* makeRootTable(MyThread* t, Zone* zone, object method) { unsigned size = frameMapSizeInWords(t, method) * codeLength(t, methodCode(t, method)) * BytesPerWord; uintptr_t* table = static_cast(zone->allocate(size)); memset(table, 0xFF, size); return table; } enum Thunk { #define THUNK(s) s##Thunk, #include "thunks.cpp" #undef THUNK }; const unsigned ThunkCount = idleIfNecessaryThunk + 1; intptr_t getThunk(MyThread* t, Thunk thunk); class BootContext { public: class MyProtector: public Thread::Protector { public: MyProtector(Thread* t, BootContext* c): Protector(t), c(c) { } virtual void visit(Heap::Visitor* v) { v->visit(&(c->constants)); v->visit(&(c->calls)); } BootContext* c; }; BootContext(Thread* t, object constants, object calls, avian::codegen::DelayedPromise* addresses, Zone* zone, OffsetResolver* resolver): protector(t, this), constants(constants), calls(calls), addresses(addresses), addressSentinal(addresses), zone(zone), resolver(resolver) { } MyProtector protector; object constants; object calls; avian::codegen::DelayedPromise* addresses; avian::codegen::DelayedPromise* addressSentinal; Zone* zone; OffsetResolver* resolver; }; class Context { public: class MyResource: public Thread::Resource { public: MyResource(Context* c): Resource(c->thread), c(c) { } virtual void release() { c->dispose(); } Context* c; }; class MyProtector: public Thread::Protector { public: MyProtector(Context* c): Protector(c->thread), c(c) { } virtual void visit(Heap::Visitor* v) { v->visit(&(c->method)); for (PoolElement* p = c->objectPool; p; p = p->next) { v->visit(&(p->target)); } for (TraceElement* p = c->traceLog; p; p = p->next) { v->visit(&(p->target)); } } Context* c; }; class MyClient: public Compiler::Client { public: MyClient(MyThread* t): t(t) { } virtual intptr_t getThunk(avian::codegen::lir::UnaryOperation, unsigned) { abort(t); } virtual intptr_t getThunk(avian::codegen::lir::BinaryOperation op, unsigned size, unsigned resultSize) { if (size == 8) { switch(op) { case avian::codegen::lir::Absolute: assert(t, resultSize == 8); return local::getThunk(t, absoluteLongThunk); case avian::codegen::lir::FloatNegate: assert(t, resultSize == 8); return local::getThunk(t, negateDoubleThunk); case avian::codegen::lir::FloatSquareRoot: assert(t, resultSize == 8); return local::getThunk(t, squareRootDoubleThunk); case avian::codegen::lir::Float2Float: assert(t, resultSize == 4); return local::getThunk(t, doubleToFloatThunk); case avian::codegen::lir::Float2Int: if (resultSize == 8) { return local::getThunk(t, doubleToLongThunk); } else { assert(t, resultSize == 4); return local::getThunk(t, doubleToIntThunk); } case avian::codegen::lir::Int2Float: if (resultSize == 8) { return local::getThunk(t, longToDoubleThunk); } else { assert(t, resultSize == 4); return local::getThunk(t, longToFloatThunk); } default: abort(t); } } else { assert(t, size == 4); switch(op) { case avian::codegen::lir::Absolute: assert(t, resultSize == 4); return local::getThunk(t, absoluteIntThunk); case avian::codegen::lir::FloatNegate: assert(t, resultSize == 4); return local::getThunk(t, negateFloatThunk); case avian::codegen::lir::FloatAbsolute: assert(t, resultSize == 4); return local::getThunk(t, absoluteFloatThunk); case avian::codegen::lir::Float2Float: assert(t, resultSize == 8); return local::getThunk(t, floatToDoubleThunk); case avian::codegen::lir::Float2Int: if (resultSize == 4) { return local::getThunk(t, floatToIntThunk); } else { assert(t, resultSize == 8); return local::getThunk(t, floatToLongThunk); } case avian::codegen::lir::Int2Float: if (resultSize == 4) { return local::getThunk(t, intToFloatThunk); } else { assert(t, resultSize == 8); return local::getThunk(t, intToDoubleThunk); } default: abort(t); } } } virtual intptr_t getThunk(avian::codegen::lir::TernaryOperation op, unsigned size, unsigned, bool* threadParameter) { *threadParameter = false; if (size == 8) { switch (op) { case avian::codegen::lir::Divide: *threadParameter = true; return local::getThunk(t, divideLongThunk); case avian::codegen::lir::Remainder: *threadParameter = true; return local::getThunk(t, moduloLongThunk); case avian::codegen::lir::FloatAdd: return local::getThunk(t, addDoubleThunk); case avian::codegen::lir::FloatSubtract: return local::getThunk(t, subtractDoubleThunk); case avian::codegen::lir::FloatMultiply: return local::getThunk(t, multiplyDoubleThunk); case avian::codegen::lir::FloatDivide: return local::getThunk(t, divideDoubleThunk); case avian::codegen::lir::FloatRemainder: return local::getThunk(t, moduloDoubleThunk); case avian::codegen::lir::JumpIfFloatEqual: case avian::codegen::lir::JumpIfFloatNotEqual: case avian::codegen::lir::JumpIfFloatLess: case avian::codegen::lir::JumpIfFloatGreater: case avian::codegen::lir::JumpIfFloatLessOrEqual: case avian::codegen::lir::JumpIfFloatGreaterOrUnordered: case avian::codegen::lir::JumpIfFloatGreaterOrEqualOrUnordered: return local::getThunk(t, compareDoublesGThunk); case avian::codegen::lir::JumpIfFloatGreaterOrEqual: case avian::codegen::lir::JumpIfFloatLessOrUnordered: case avian::codegen::lir::JumpIfFloatLessOrEqualOrUnordered: return local::getThunk(t, compareDoublesLThunk); default: abort(t); } } else { assert(t, size == 4); switch (op) { case avian::codegen::lir::Divide: *threadParameter = true; return local::getThunk(t, divideIntThunk); case avian::codegen::lir::Remainder: *threadParameter = true; return local::getThunk(t, moduloIntThunk); case avian::codegen::lir::FloatAdd: return local::getThunk(t, addFloatThunk); case avian::codegen::lir::FloatSubtract: return local::getThunk(t, subtractFloatThunk); case avian::codegen::lir::FloatMultiply: return local::getThunk(t, multiplyFloatThunk); case avian::codegen::lir::FloatDivide: return local::getThunk(t, divideFloatThunk); case avian::codegen::lir::FloatRemainder: return local::getThunk(t, moduloFloatThunk); case avian::codegen::lir::JumpIfFloatEqual: case avian::codegen::lir::JumpIfFloatNotEqual: case avian::codegen::lir::JumpIfFloatLess: case avian::codegen::lir::JumpIfFloatGreater: case avian::codegen::lir::JumpIfFloatLessOrEqual: case avian::codegen::lir::JumpIfFloatGreaterOrUnordered: case avian::codegen::lir::JumpIfFloatGreaterOrEqualOrUnordered: return local::getThunk(t, compareFloatsGThunk); case avian::codegen::lir::JumpIfFloatGreaterOrEqual: case avian::codegen::lir::JumpIfFloatLessOrUnordered: case avian::codegen::lir::JumpIfFloatLessOrEqualOrUnordered: return local::getThunk(t, compareFloatsLThunk); default: abort(t); } } } MyThread* t; }; Context(MyThread* t, BootContext* bootContext, object method): thread(t), zone(t->m->system, t->m->heap, InitialZoneCapacityInBytes), assembler(t->arch->makeAssembler(t->m->heap, &zone)), client(t), compiler(makeCompiler(t->m->system, assembler, &zone, &client)), method(method), bootContext(bootContext), objectPool(0), subroutines(0), traceLog(0), visitTable(makeVisitTable(t, &zone, method)), rootTable(makeRootTable(t, &zone, method)), subroutineTable(0), executableAllocator(0), executableStart(0), executableSize(0), objectPoolCount(0), traceLogCount(0), dirtyRoots(false), leaf(true), eventLog(t->m->system, t->m->heap, 1024), protector(this), resource(this) { } Context(MyThread* t): thread(t), zone(t->m->system, t->m->heap, InitialZoneCapacityInBytes), assembler(t->arch->makeAssembler(t->m->heap, &zone)), client(t), compiler(0), method(0), bootContext(0), objectPool(0), subroutines(0), traceLog(0), visitTable(0), rootTable(0), subroutineTable(0), executableAllocator(0), executableStart(0), executableSize(0), objectPoolCount(0), traceLogCount(0), dirtyRoots(false), leaf(true), eventLog(t->m->system, t->m->heap, 0), protector(this), resource(this) { } ~Context() { dispose(); } void dispose() { if (compiler) { compiler->dispose(); } assembler->dispose(); if (executableAllocator) { executableAllocator->free(executableStart, executableSize); } eventLog.dispose(); zone.dispose(); } MyThread* thread; Zone zone; avian::codegen::Assembler* assembler; MyClient client; avian::codegen::Compiler* compiler; object method; BootContext* bootContext; PoolElement* objectPool; Subroutine* subroutines; TraceElement* traceLog; uint16_t* visitTable; uintptr_t* rootTable; Subroutine** subroutineTable; Allocator* executableAllocator; void* executableStart; unsigned executableSize; unsigned objectPoolCount; unsigned traceLogCount; bool dirtyRoots; bool leaf; Vector eventLog; MyProtector protector; MyResource resource; }; unsigned translateLocalIndex(Context* context, unsigned footprint, unsigned index) { unsigned parameterFootprint = methodParameterFootprint (context->thread, context->method); if (index < parameterFootprint) { return parameterFootprint - index - footprint; } else { return index; } } Compiler::Operand* loadLocal(Context* context, unsigned footprint, unsigned index) { return context->compiler->loadLocal (footprint, translateLocalIndex(context, footprint, index)); } void storeLocal(Context* context, unsigned footprint, Compiler::Operand* value, unsigned index) { context->compiler->storeLocal (footprint, value, translateLocalIndex(context, footprint, index)); } avian::util::FixedAllocator* codeAllocator(MyThread* t); class Frame { public: enum StackType { Integer, Long, Object }; typedef Compiler::Operand* Value; Frame(Context* context, uint8_t* stackMap): context(context), t(context->thread), c(context->compiler), subroutine(0), stackMap(stackMap), ip(0), sp(localSize()), level(0) { memset(stackMap, 0, codeMaxStack(t, methodCode(t, context->method))); } Frame(Frame* f, uint8_t* stackMap): context(f->context), t(context->thread), c(context->compiler), subroutine(f->subroutine), stackMap(stackMap), ip(f->ip), sp(f->sp), level(f->level + 1) { memcpy(stackMap, f->stackMap, codeMaxStack (t, methodCode(t, context->method))); if (level > 1) { context->eventLog.append(PushContextEvent); } } ~Frame() { dispose(); } void dispose() { if (level > 1) { context->eventLog.append(PopContextEvent); } } Value append(object o) { BootContext* bc = context->bootContext; if (bc) { avian::codegen::Promise* p = new (bc->zone) avian::codegen::ListenPromise(t->m->system, bc->zone); PROTECT(t, o); object pointer = makePointer(t, p); bc->constants = makeTriple(t, o, pointer, bc->constants); return c->binaryOp(lir::Add, TargetBytesPerWord, c->memory (c->register_(t->arch->thread()), Compiler::AddressType, TARGET_THREAD_HEAPIMAGE), c->promiseConstant (p, Compiler::AddressType)); } else { for (PoolElement* e = context->objectPool; e; e = e->next) { if (o == e->target) { return c->address(e); } } context->objectPool = new(&context->zone) PoolElement(t, o, context->objectPool); ++ context->objectPoolCount; return c->address(context->objectPool); } } unsigned localSize() { return local::localSize(t, context->method); } unsigned stackSize() { return codeMaxStack(t, methodCode(t, context->method)); } unsigned frameSize() { return localSize() + stackSize(); } void set(unsigned index, uint8_t type) { assert(t, index < frameSize()); if (type == Object) { context->eventLog.append(MarkEvent); context->eventLog.append2(index); } else { context->eventLog.append(ClearEvent); context->eventLog.append2(index); } int si = index - localSize(); if (si >= 0) { stackMap[si] = type; } } uint8_t get(unsigned index) { assert(t, index < frameSize()); int si = index - localSize(); assert(t, si >= 0); return stackMap[si]; } void pushedInt() { assert(t, sp + 1 <= frameSize()); set(sp++, Integer); } void pushedLong() { assert(t, sp + 2 <= frameSize()); set(sp++, Long); set(sp++, Long); } void pushedObject() { assert(t, sp + 1 <= frameSize()); set(sp++, Object); } void popped(unsigned count) { assert(t, sp >= count); assert(t, sp - count >= localSize()); while (count) { set(--sp, Integer); -- count; } } void poppedInt() { assert(t, sp >= 1); assert(t, sp - 1 >= localSize()); assert(t, get(sp - 1) == Integer); -- sp; } void poppedLong() { assert(t, sp >= 1); assert(t, sp - 2 >= localSize()); assert(t, get(sp - 1) == Long); assert(t, get(sp - 2) == Long); sp -= 2; } void poppedObject() { assert(t, sp >= 1); assert(t, sp - 1 >= localSize()); assert(t, get(sp - 1) == Object); set(--sp, Integer); } void storedInt(unsigned index) { assert(t, index < localSize()); set(index, Integer); } void storedLong(unsigned index) { assert(t, index + 1 < localSize()); set(index, Long); set(index + 1, Long); } void storedObject(unsigned index) { assert(t, index < localSize()); set(index, Object); } void dupped() { assert(t, sp + 1 <= frameSize()); assert(t, sp - 1 >= localSize()); set(sp, get(sp - 1)); ++ sp; } void duppedX1() { assert(t, sp + 1 <= frameSize()); assert(t, sp - 2 >= localSize()); uint8_t b2 = get(sp - 2); uint8_t b1 = get(sp - 1); set(sp - 1, b2); set(sp - 2, b1); set(sp , b1); ++ sp; } void duppedX2() { assert(t, sp + 1 <= frameSize()); assert(t, sp - 3 >= localSize()); uint8_t b3 = get(sp - 3); uint8_t b2 = get(sp - 2); uint8_t b1 = get(sp - 1); set(sp - 2, b3); set(sp - 1, b2); set(sp - 3, b1); set(sp , b1); ++ sp; } void dupped2() { assert(t, sp + 2 <= frameSize()); assert(t, sp - 2 >= localSize()); uint8_t b2 = get(sp - 2); uint8_t b1 = get(sp - 1); set(sp, b2); set(sp + 1, b1); sp += 2; } void dupped2X1() { assert(t, sp + 2 <= frameSize()); assert(t, sp - 3 >= localSize()); uint8_t b3 = get(sp - 3); uint8_t b2 = get(sp - 2); uint8_t b1 = get(sp - 1); set(sp - 1, b3); set(sp - 3, b2); set(sp , b2); set(sp - 2, b1); set(sp + 1, b1); sp += 2; } void dupped2X2() { assert(t, sp + 2 <= frameSize()); assert(t, sp - 4 >= localSize()); uint8_t b4 = get(sp - 4); uint8_t b3 = get(sp - 3); uint8_t b2 = get(sp - 2); uint8_t b1 = get(sp - 1); set(sp - 2, b4); set(sp - 1, b3); set(sp - 4, b2); set(sp , b2); set(sp - 3, b1); set(sp + 1, b1); sp += 2; } void swapped() { assert(t, sp - 2 >= localSize()); uint8_t saved = get(sp - 1); set(sp - 1, get(sp - 2)); set(sp - 2, saved); } avian::codegen::Promise* addressPromise(avian::codegen::Promise* p) { BootContext* bc = context->bootContext; if (bc) { bc->addresses = new(bc->zone) avian::codegen::DelayedPromise(t->m->system, bc->zone, p, bc->addresses); return bc->addresses; } else { return p; } } Value addressOperand(avian::codegen::Promise* p) { return c->promiseConstant(p, Compiler::AddressType); } Value absoluteAddressOperand(avian::codegen::Promise* p) { return context->bootContext ? c->binaryOp( lir::Add, TargetBytesPerWord, c->memory(c->register_(t->arch->thread()), Compiler::AddressType, TARGET_THREAD_CODEIMAGE), c->promiseConstant( new (&context->zone) avian::codegen::OffsetPromise( p, -reinterpret_cast( codeAllocator(t)->memory.begin())), Compiler::AddressType)) : addressOperand(p); } Value machineIp(unsigned logicalIp) { return c->promiseConstant(c->machineIp(logicalIp), Compiler::AddressType); } void visitLogicalIp(unsigned ip) { c->visitLogicalIp(ip); context->eventLog.append(IpEvent); context->eventLog.append2(ip); } void startLogicalIp(unsigned ip) { if (subroutine) { context->subroutineTable[ip] = subroutine; } c->startLogicalIp(ip); context->eventLog.append(IpEvent); context->eventLog.append2(ip); this->ip = ip; } void pushQuiet(unsigned footprint, Value o) { c->push(footprint, o); } void pushLongQuiet(Value o) { pushQuiet(2, o); } Value popQuiet(unsigned footprint) { return c->pop(footprint); } Value popLongQuiet() { return popQuiet(2); } void pushInt(Value o) { pushQuiet(1, o); pushedInt(); } void pushAddress(Value o) { pushQuiet(1, o); pushedInt(); } void pushObject(Value o) { pushQuiet(1, o); pushedObject(); } void pushObject() { c->pushed(); pushedObject(); } void pushLong(Value o) { pushLongQuiet(o); pushedLong(); } void pop(unsigned count) { popped(count); c->popped(count); } Value popInt() { poppedInt(); return popQuiet(1); } Value popLong() { poppedLong(); return popLongQuiet(); } Value popObject() { poppedObject(); return popQuiet(1); } void loadInt(unsigned index) { assert(t, index < localSize()); pushInt(loadLocal(context, 1, index)); } void loadLong(unsigned index) { assert(t, index < static_cast(localSize() - 1)); pushLong(loadLocal(context, 2, index)); } void loadObject(unsigned index) { assert(t, index < localSize()); pushObject(loadLocal(context, 1, index)); } void storeInt(unsigned index) { storeLocal(context, 1, popInt(), index); storedInt(translateLocalIndex(context, 1, index)); } void storeLong(unsigned index) { storeLocal(context, 2, popLong(), index); storedLong(translateLocalIndex(context, 2, index)); } void storeObject(unsigned index) { storeLocal(context, 1, popObject(), index); storedObject(translateLocalIndex(context, 1, index)); } void storeObjectOrAddress(unsigned index) { storeLocal(context, 1, popQuiet(1), index); assert(t, sp >= 1); assert(t, sp - 1 >= localSize()); if (get(sp - 1) == Object) { storedObject(translateLocalIndex(context, 1, index)); } else { storedInt(translateLocalIndex(context, 1, index)); } popped(1); } void dup() { pushQuiet(1, c->peek(1, 0)); dupped(); } void dupX1() { Value s0 = popQuiet(1); Value s1 = popQuiet(1); pushQuiet(1, s0); pushQuiet(1, s1); pushQuiet(1, s0); duppedX1(); } void dupX2() { Value s0 = popQuiet(1); if (get(sp - 2) == Long) { Value s1 = popLongQuiet(); pushQuiet(1, s0); pushLongQuiet(s1); pushQuiet(1, s0); } else { Value s1 = popQuiet(1); Value s2 = popQuiet(1); pushQuiet(1, s0); pushQuiet(1, s2); pushQuiet(1, s1); pushQuiet(1, s0); } duppedX2(); } void dup2() { if (get(sp - 1) == Long) { pushLongQuiet(c->peek(2, 0)); } else { Value s0 = popQuiet(1); Value s1 = popQuiet(1); pushQuiet(1, s1); pushQuiet(1, s0); pushQuiet(1, s1); pushQuiet(1, s0); } dupped2(); } void dup2X1() { if (get(sp - 1) == Long) { Value s0 = popLongQuiet(); Value s1 = popQuiet(1); pushLongQuiet(s0); pushQuiet(1, s1); pushLongQuiet(s0); } else { Value s0 = popQuiet(1); Value s1 = popQuiet(1); Value s2 = popQuiet(1); pushQuiet(1, s1); pushQuiet(1, s0); pushQuiet(1, s2); pushQuiet(1, s1); pushQuiet(1, s0); } dupped2X1(); } void dup2X2() { if (get(sp - 1) == Long) { Value s0 = popLongQuiet(); if (get(sp - 3) == Long) { Value s1 = popLongQuiet(); pushLongQuiet(s0); pushLongQuiet(s1); pushLongQuiet(s0); } else { Value s1 = popQuiet(1); Value s2 = popQuiet(1); pushLongQuiet(s0); pushQuiet(1, s2); pushQuiet(1, s1); pushLongQuiet(s0); } } else { Value s0 = popQuiet(1); Value s1 = popQuiet(1); Value s2 = popQuiet(1); Value s3 = popQuiet(1); pushQuiet(1, s1); pushQuiet(1, s0); pushQuiet(1, s3); pushQuiet(1, s2); pushQuiet(1, s1); pushQuiet(1, s0); } dupped2X2(); } void swap() { Value s0 = popQuiet(1); Value s1 = popQuiet(1); pushQuiet(1, s0); pushQuiet(1, s1); swapped(); } TraceElement* trace(object target, unsigned flags) { unsigned mapSize = frameMapSizeInWords(t, context->method); TraceElement* e = context->traceLog = new (context->zone.allocate(sizeof(TraceElement) + (mapSize * BytesPerWord))) TraceElement(context, ip, target, flags, context->traceLog, mapSize); ++ context->traceLogCount; context->eventLog.append(TraceEvent); context->eventLog.appendAddress(e); return e; } unsigned startSubroutine(unsigned ip, avian::codegen::Promise* returnAddress) { pushAddress(absoluteAddressOperand(returnAddress)); Subroutine* subroutine = 0; for (Subroutine* s = context->subroutines; s; s = s->listNext) { if (s->ip == ip) { subroutine = s; break; } } if (subroutine == 0) { context->subroutines = subroutine = new (context->zone.allocate(sizeof(Subroutine))) Subroutine(ip, context->eventLog.length() + 1 + BytesPerWord + 2, context->subroutines, this->subroutine); if (context->subroutineTable == 0) { unsigned size = codeLength(t, methodCode(t, context->method)) * sizeof(Subroutine*); context->subroutineTable = static_cast (context->zone.allocate(size)); memset(context->subroutineTable, 0, size); } } subroutine->handle = c->startSubroutine(); this->subroutine = subroutine; SubroutineCall* call = new(&context->zone) SubroutineCall(subroutine, returnAddress); context->eventLog.append(PushSubroutineEvent); context->eventLog.appendAddress(call); unsigned nextIndexIndex = context->eventLog.length(); context->eventLog.append2(0); c->saveLocals(); return nextIndexIndex; } void returnFromSubroutine(unsigned returnAddressLocal) { c->returnFromSubroutine (subroutine->handle, loadLocal(context, 1, returnAddressLocal)); subroutine->stackIndex = localOffsetFromStack (t, translateLocalIndex(context, 1, returnAddressLocal), context->method); } void endSubroutine(unsigned nextIndexIndex) { c->linkSubroutine(subroutine->handle); poppedInt(); context->eventLog.append(PopSubroutineEvent); context->eventLog.set2(nextIndexIndex, context->eventLog.length()); subroutine = subroutine->stackNext; } Context* context; MyThread* t; avian::codegen::Compiler* c; Subroutine* subroutine; uint8_t* stackMap; unsigned ip; unsigned sp; unsigned level; }; unsigned savedTargetIndex(MyThread* t, object method) { return codeMaxLocals(t, methodCode(t, method)); } object findCallNode(MyThread* t, void* address); void insertCallNode(MyThread* t, object node); void* findExceptionHandler(Thread* t, object method, void* ip) { if (t->exception) { object table = codeExceptionHandlerTable(t, methodCode(t, method)); if (table) { object index = arrayBody(t, table, 0); uint8_t* compiled = reinterpret_cast (methodCompiled(t, method)); for (unsigned i = 0; i < arrayLength(t, table) - 1; ++i) { unsigned start = intArrayBody(t, index, i * 3); unsigned end = intArrayBody(t, index, (i * 3) + 1); unsigned key = difference(ip, compiled) - 1; if (key >= start and key < end) { object catchType = arrayBody(t, table, i + 1); if (exceptionMatch(t, catchType, t->exception)) { return compiled + intArrayBody(t, index, (i * 3) + 2); } } } } } return 0; } void releaseLock(MyThread* t, object method, void* stack) { if (methodFlags(t, method) & ACC_SYNCHRONIZED) { if (t->methodLockIsClean) { object lock; if (methodFlags(t, method) & ACC_STATIC) { lock = methodClass(t, method); } else { lock = *localObject (t, stackForFrame(t, stack, method), method, savedTargetIndex(t, method)); } release(t, lock); } else { // got an exception while trying to acquire the lock for a // synchronized method -- don't try to release it, since we // never succeeded in acquiring it. t->methodLockIsClean = true; } } } void findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, void** targetStack, object* targetContinuation) { void* ip; void* stack; object continuation; if (t->traceContext) { ip = t->traceContext->ip; stack = t->traceContext->stack; continuation = t->traceContext->continuation; } else { ip = getIp(t); stack = t->stack; continuation = t->continuation; } object target = t->trace->targetMethod; bool mostRecent = true; *targetIp = 0; while (*targetIp == 0) { object method = methodForIp(t, ip); if (method) { void* handler = findExceptionHandler(t, method, ip); if (handler) { *targetIp = handler; nextFrame(t, &ip, &stack, method, target, mostRecent); void** sp = static_cast(stackForFrame(t, stack, method)) + t->arch->frameReturnAddressSize(); *targetFrame = static_cast (stack) + t->arch->framePointerOffset(); *targetStack = sp; *targetContinuation = continuation; sp[localOffset(t, localSize(t, method), method)] = t->exception; t->exception = 0; } else { nextFrame(t, &ip, &stack, method, target, mostRecent); if (t->exception) { releaseLock(t, method, stack); } target = method; } } else { expect(t, ip); *targetIp = ip; *targetFrame = 0; *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); *targetContinuation = continuation; while (Continuations and *targetContinuation) { object c = *targetContinuation; object method = continuationMethod(t, c); void* handler = findExceptionHandler (t, method, continuationAddress(t, c)); if (handler) { t->exceptionHandler = handler; t->exceptionStackAdjustment = (stackOffsetFromFrame(t, method) - ((continuationFramePointerOffset(t, c) / BytesPerWord) - t->arch->framePointerOffset() + t->arch->frameReturnAddressSize())) * BytesPerWord; t->exceptionOffset = localOffset(t, localSize(t, method), method) * BytesPerWord; break; } else if (t->exception) { releaseLock(t, method, reinterpret_cast(c) + ContinuationBody + continuationReturnAddressOffset(t, c) - t->arch->returnAddressOffset()); } *targetContinuation = continuationNext(t, c); } } mostRecent = false; } } object makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack) { void* ip = getIp(t); void* stack = t->stack; object context = t->continuation ? continuationContext(t, t->continuation) : makeContinuationContext(t, 0, 0, 0, 0, t->trace->originalMethod); PROTECT(t, context); object target = t->trace->targetMethod; PROTECT(t, target); object first = 0; PROTECT(t, first); object last = 0; PROTECT(t, last); bool mostRecent = true; *targetIp = 0; while (*targetIp == 0) { object method = methodForIp(t, ip); if (method) { PROTECT(t, method); void** top = static_cast(stack) + t->arch->frameReturnAddressSize() + t->arch->frameFooterSize(); unsigned argumentFootprint = t->arch->argumentFootprint(methodParameterFootprint(t, target)); unsigned alignment = t->arch->stackAlignmentInWords(); if (avian::codegen::TailCalls and argumentFootprint > alignment) { top += argumentFootprint - alignment; } void* nextIp = ip; nextFrame(t, &nextIp, &stack, method, target, mostRecent); void** bottom = static_cast(stack) + t->arch->frameReturnAddressSize(); unsigned frameSize = bottom - top; unsigned totalSize = frameSize + t->arch->frameFooterSize() + t->arch->argumentFootprint(methodParameterFootprint(t, method)); object c = makeContinuation (t, 0, context, method, ip, (frameSize + t->arch->frameFooterSize() + t->arch->returnAddressOffset() - t->arch->frameReturnAddressSize()) * BytesPerWord, (frameSize + t->arch->frameFooterSize() + t->arch->framePointerOffset() - t->arch->frameReturnAddressSize()) * BytesPerWord, totalSize); memcpy(&continuationBody(t, c, 0), top, totalSize * BytesPerWord); if (last) { set(t, last, ContinuationNext, c); } else { first = c; } last = c; ip = nextIp; target = method; } else { *targetIp = ip; *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); } mostRecent = false; } expect(t, last); set(t, last, ContinuationNext, t->continuation); return first; } void NO_RETURN unwind(MyThread* t) { void* ip; void* frame; void* stack; object continuation; findUnwindTarget(t, &ip, &frame, &stack, &continuation); t->trace->targetMethod = 0; t->trace->nativeMethod = 0; transition(t, ip, stack, continuation, t->trace); vmJump(ip, frame, stack, t, 0, 0); } class MyCheckpoint: public Thread::Checkpoint { public: MyCheckpoint(MyThread* t): Checkpoint(t) { } virtual void unwind() { local::unwind(static_cast(t)); } }; uintptr_t defaultThunk(MyThread* t); uintptr_t nativeThunk(MyThread* t); uintptr_t bootNativeThunk(MyThread* t); uintptr_t aioobThunk(MyThread* t); uintptr_t stackOverflowThunk(MyThread* t); uintptr_t virtualThunk(MyThread* t, unsigned index); bool unresolved(MyThread* t, uintptr_t methodAddress); uintptr_t methodAddress(Thread* t, object method) { if (methodFlags(t, method) & ACC_NATIVE) { return bootNativeThunk(static_cast(t)); } else { return methodCompiled(t, method); } } void tryInitClass(MyThread* t, object class_) { initClass(t, class_); } void compile(MyThread* t, FixedAllocator* allocator, BootContext* bootContext, object method); object resolveMethod(Thread* t, object pair) { object reference = pairSecond(t, pair); PROTECT(t, reference); object class_ = resolveClassInObject (t, classLoader(t, methodClass(t, pairFirst(t, pair))), reference, ReferenceClass); return findInHierarchy (t, class_, referenceName(t, reference), referenceSpec(t, reference), findMethodInClass, Machine::NoSuchMethodErrorType); } bool methodAbstract(Thread* t, object method) { return methodCode(t, method) == 0 and (methodFlags(t, method) & ACC_NATIVE) == 0; } int64_t prepareMethodForCall(MyThread* t, object target) { if (methodAbstract(t, target)) { throwNew(t, Machine::AbstractMethodErrorType, "%s.%s%s", &byteArrayBody(t, className(t, methodClass(t, target)), 0), &byteArrayBody(t, methodName(t, target), 0), &byteArrayBody(t, methodSpec(t, target), 0)); } else { if (unresolved(t, methodAddress(t, target))) { PROTECT(t, target); compile(t, codeAllocator(t), 0, target); } if (methodFlags(t, target) & ACC_NATIVE) { t->trace->nativeMethod = target; } return methodAddress(t, target); } } int64_t findInterfaceMethodFromInstance(MyThread* t, object method, object instance) { if (instance) { return prepareMethodForCall (t, findInterfaceMethod(t, method, objectClass(t, instance))); } else { throwNew(t, Machine::NullPointerExceptionType); } } int64_t findInterfaceMethodFromInstanceAndReference (MyThread* t, object pair, object instance) { PROTECT(t, instance); object method = resolveMethod(t, pair); return findInterfaceMethodFromInstance(t, method, instance); } void checkMethod(Thread* t, object method, bool shouldBeStatic) { if (((methodFlags(t, method) & ACC_STATIC) == 0) == shouldBeStatic) { throwNew(t, Machine::IncompatibleClassChangeErrorType, "expected %s.%s%s to be %s", &byteArrayBody(t, className(t, methodClass(t, method)), 0), &byteArrayBody(t, methodName(t, method), 0), &byteArrayBody(t, methodSpec(t, method), 0), shouldBeStatic ? "static" : "non-static"); } } void checkField(Thread* t, object field, bool shouldBeStatic) { if (((fieldFlags(t, field) & ACC_STATIC) == 0) == shouldBeStatic) { throwNew(t, Machine::IncompatibleClassChangeErrorType, "expected %s.%s to be %s", &byteArrayBody(t, className(t, fieldClass(t, field)), 0), &byteArrayBody(t, fieldName(t, field), 0), shouldBeStatic ? "static" : "non-static"); } } int64_t findSpecialMethodFromReference(MyThread* t, object pair) { PROTECT(t, pair); object target = resolveMethod(t, pair); object class_ = methodClass(t, pairFirst(t, pair)); if (isSpecialMethod(t, target, class_)) { target = findVirtualMethod(t, target, classSuper(t, class_)); } checkMethod(t, target, false); return prepareMethodForCall(t, target); } int64_t findStaticMethodFromReference(MyThread* t, object pair) { object target = resolveMethod(t, pair); checkMethod(t, target, true); return prepareMethodForCall(t, target); } int64_t findVirtualMethodFromReference(MyThread* t, object pair, object instance) { PROTECT(t, instance); object target = resolveMethod(t, pair); target = findVirtualMethod(t, target, objectClass(t, instance)); checkMethod(t, target, false); return prepareMethodForCall(t, target); } int64_t getMethodAddress(MyThread* t, object target) { return prepareMethodForCall(t, target); } int64_t getJClassFromReference(MyThread* t, object pair) { return reinterpret_cast (getJClass (t, resolveClass (t, classLoader(t, methodClass(t, pairFirst(t, pair))), referenceName(t, pairSecond(t, pair))))); } unsigned traceSize(Thread* t) { class Counter: public Processor::StackVisitor { public: Counter(): count(0) { } virtual bool visit(Processor::StackWalker*) { ++ count; return true; } unsigned count; } counter; t->m->processor->walkStack(t, &counter); return FixedSizeOfArray + (counter.count * ArrayElementSizeOfArray) + (counter.count * FixedSizeOfTraceElement); } void NO_RETURN throwArithmetic(MyThread* t) { if (ensure(t, FixedSizeOfArithmeticException + traceSize(t))) { atomicOr(&(t->flags), Thread::TracingFlag); THREAD_RESOURCE0(t, atomicAnd(&(t->flags), ~Thread::TracingFlag)); throwNew(t, Machine::ArithmeticExceptionType); } else { // not enough memory available for a new exception and stack trace // -- use a preallocated instance instead throw_(t, root(t, Machine::ArithmeticException)); } } int64_t divideLong(MyThread* t, int64_t b, int64_t a) { if (LIKELY(b)) { return a / b; } else { throwArithmetic(t); } } int64_t divideInt(MyThread* t, int32_t b, int32_t a) { if (LIKELY(b)) { return a / b; } else { throwArithmetic(t); } } int64_t moduloLong(MyThread* t, int64_t b, int64_t a) { if (LIKELY(b)) { return a % b; } else { throwArithmetic(t); } } int64_t moduloInt(MyThread* t, int32_t b, int32_t a) { if (LIKELY(b)) { return a % b; } else { throwArithmetic(t); } } uint64_t makeBlankObjectArray(MyThread* t, object class_, int32_t length) { if (length >= 0) { return reinterpret_cast(makeObjectArray(t, class_, length)); } else { throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", length); } } uint64_t makeBlankObjectArrayFromReference(MyThread* t, object pair, int32_t length) { return makeBlankObjectArray (t, resolveClass (t, classLoader(t, methodClass(t, pairFirst(t, pair))), referenceName(t, pairSecond(t, pair))), length); } uint64_t makeBlankArray(MyThread* t, unsigned type, int32_t length) { if (length >= 0) { object (*constructor)(Thread*, uintptr_t); switch (type) { case T_BOOLEAN: constructor = makeBooleanArray; break; case T_CHAR: constructor = makeCharArray; break; case T_FLOAT: constructor = makeFloatArray; break; case T_DOUBLE: constructor = makeDoubleArray; break; case T_BYTE: constructor = makeByteArray; break; case T_SHORT: constructor = makeShortArray; break; case T_INT: constructor = makeIntArray; break; case T_LONG: constructor = makeLongArray; break; default: abort(t); } return reinterpret_cast(constructor(t, length)); } else { throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", length); } } uint64_t lookUpAddress(int32_t key, uintptr_t* start, int32_t count, uintptr_t default_) { int32_t bottom = 0; int32_t top = count; for (int32_t span = top - bottom; span; span = top - bottom) { int32_t middle = bottom + (span / 2); uintptr_t* p = start + (middle * 2); int32_t k = *p; if (key < k) { top = middle; } else if (key > k) { bottom = middle + 1; } else { return p[1]; } } return default_; } void setMaybeNull(MyThread* t, object o, unsigned offset, object value) { if (LIKELY(o)) { set(t, o, offset, value); } else { throwNew(t, Machine::NullPointerExceptionType); } } void acquireMonitorForObject(MyThread* t, object o) { if (LIKELY(o)) { acquire(t, o); } else { throwNew(t, Machine::NullPointerExceptionType); } } void acquireMonitorForObjectOnEntrance(MyThread* t, object o) { if (LIKELY(o)) { t->methodLockIsClean = false; acquire(t, o); t->methodLockIsClean = true; } else { throwNew(t, Machine::NullPointerExceptionType); } } void releaseMonitorForObject(MyThread* t, object o) { if (LIKELY(o)) { release(t, o); } else { throwNew(t, Machine::NullPointerExceptionType); } } object makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* countStack, int32_t dimensions) { PROTECT(t, class_); THREAD_RUNTIME_ARRAY(t, int32_t, counts, dimensions); for (int i = dimensions - 1; i >= 0; --i) { RUNTIME_ARRAY_BODY(counts)[i] = countStack[dimensions - i - 1]; if (UNLIKELY(RUNTIME_ARRAY_BODY(counts)[i] < 0)) { throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", RUNTIME_ARRAY_BODY(counts)[i]); return 0; } } object array = makeArray(t, RUNTIME_ARRAY_BODY(counts)[0]); setObjectClass(t, array, class_); PROTECT(t, array); populateMultiArray(t, array, RUNTIME_ARRAY_BODY(counts), 0, dimensions); return array; } uint64_t makeMultidimensionalArray(MyThread* t, object class_, int32_t dimensions, int32_t offset) { return reinterpret_cast (makeMultidimensionalArray2 (t, class_, static_cast(t->stack) + offset, dimensions)); } uint64_t makeMultidimensionalArrayFromReference(MyThread* t, object pair, int32_t dimensions, int32_t offset) { return makeMultidimensionalArray (t, resolveClass (t, classLoader(t, methodClass(t, pairFirst(t, pair))), referenceName(t, pairSecond(t, pair))), dimensions, offset); } void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t) { if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { atomicOr(&(t->flags), Thread::TracingFlag); THREAD_RESOURCE0(t, atomicAnd(&(t->flags), ~Thread::TracingFlag)); throwNew(t, Machine::ArrayIndexOutOfBoundsExceptionType); } else { // not enough memory available for a new exception and stack trace // -- use a preallocated instance instead throw_(t, root(t, Machine::ArrayIndexOutOfBoundsException)); } } void NO_RETURN throwStackOverflow(MyThread* t) { throwNew(t, Machine::StackOverflowErrorType); } void NO_RETURN throw_(MyThread* t, object o) { if (LIKELY(o)) { vm::throw_(t, o); } else { throwNew(t, Machine::NullPointerExceptionType); } } void checkCast(MyThread* t, object class_, object o) { if (UNLIKELY(o and not isAssignableFrom(t, class_, objectClass(t, o)))) { object classNameFrom = className(t, objectClass(t, o)); object classNameTo = className(t, class_); THREAD_RUNTIME_ARRAY(t, char, classFrom, byteArrayLength(t, classNameFrom)); THREAD_RUNTIME_ARRAY(t, char, classTo, byteArrayLength(t, classNameTo)); replace('/', '.', RUNTIME_ARRAY_BODY(classFrom), reinterpret_cast(&byteArrayBody(t, classNameFrom, 0))); replace('/', '.', RUNTIME_ARRAY_BODY(classTo), reinterpret_cast(&byteArrayBody(t, classNameTo, 0))); throwNew (t, Machine::ClassCastExceptionType, "%s cannot be cast to %s", RUNTIME_ARRAY_BODY(classFrom), RUNTIME_ARRAY_BODY(classTo)); } } void checkCastFromReference(MyThread* t, object pair, object o) { PROTECT(t, o); object c = resolveClass (t, classLoader(t, methodClass(t, pairFirst(t, pair))), referenceName(t, pairSecond(t, pair))); checkCast(t, c, o); } object resolveField(Thread* t, object pair) { object reference = pairSecond(t, pair); PROTECT(t, reference); object class_ = resolveClassInObject (t, classLoader(t, methodClass(t, pairFirst(t, pair))), reference, ReferenceClass); return findInHierarchy (t, class_, referenceName(t, reference), referenceSpec(t, reference), findFieldInClass, Machine::NoSuchFieldErrorType); } uint64_t getFieldValue(Thread* t, object target, object field) { switch (fieldCode(t, field)) { case ByteField: case BooleanField: return fieldAtOffset(target, fieldOffset(t, field)); case CharField: case ShortField: return fieldAtOffset(target, fieldOffset(t, field)); case FloatField: case IntField: return fieldAtOffset(target, fieldOffset(t, field)); case DoubleField: case LongField: return fieldAtOffset(target, fieldOffset(t, field)); case ObjectField: return fieldAtOffset(target, fieldOffset(t, field)); default: abort(t); } } uint64_t getStaticFieldValueFromReference(MyThread* t, object pair) { object field = resolveField(t, pair); PROTECT(t, field); initClass(t, fieldClass(t, field)); ACQUIRE_FIELD_FOR_READ(t, field); return getFieldValue(t, classStaticTable(t, fieldClass(t, field)), field); } uint64_t getFieldValueFromReference(MyThread* t, object pair, object instance) { PROTECT(t, instance); object field = resolveField(t, pair); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return getFieldValue(t, instance, field); } void setStaticLongFieldValueFromReference(MyThread* t, object pair, uint64_t value) { object field = resolveField(t, pair); PROTECT(t, field); initClass(t, fieldClass(t, field)); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, fieldClass(t, field)), fieldOffset(t, field)) = value; } void setLongFieldValueFromReference(MyThread* t, object pair, object instance, uint64_t value) { PROTECT(t, instance); object field = resolveField(t, pair); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(instance, fieldOffset(t, field)) = value; } void setStaticObjectFieldValueFromReference(MyThread* t, object pair, object value) { PROTECT(t, value); object field = resolveField(t, pair); PROTECT(t, field); initClass(t, fieldClass(t, field)); ACQUIRE_FIELD_FOR_WRITE(t, field); set(t, classStaticTable(t, fieldClass(t, field)), fieldOffset(t, field), value); } void setObjectFieldValueFromReference(MyThread* t, object pair, object instance, object value) { PROTECT(t, instance); PROTECT(t, value); object field = resolveField(t, pair); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); set(t, instance, fieldOffset(t, field), value); } void setFieldValue(MyThread* t, object target, object field, uint32_t value) { switch (fieldCode(t, field)) { case ByteField: case BooleanField: fieldAtOffset(target, fieldOffset(t, field)) = value; break; case CharField: case ShortField: fieldAtOffset(target, fieldOffset(t, field)) = value; break; case FloatField: case IntField: fieldAtOffset(target, fieldOffset(t, field)) = value; break; default: abort(t); } } void setStaticFieldValueFromReference(MyThread* t, object pair, uint32_t value) { object field = resolveField(t, pair); PROTECT(t, field); initClass(t, fieldClass(t, field)); ACQUIRE_FIELD_FOR_WRITE(t, field); setFieldValue(t, classStaticTable(t, fieldClass(t, field)), field, value); } void setFieldValueFromReference(MyThread* t, object pair, object instance, uint32_t value) { PROTECT(t, instance); object field = resolveField(t, pair); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); setFieldValue(t, instance, field, value); } uint64_t instanceOf64(Thread* t, object class_, object o) { return instanceOf(t, class_, o); } uint64_t instanceOfFromReference(Thread* t, object pair, object o) { PROTECT(t, o); object c = resolveClass (t, classLoader(t, methodClass(t, pairFirst(t, pair))), referenceName(t, pairSecond(t, pair))); return instanceOf64(t, c, o); } uint64_t makeNewGeneral64(Thread* t, object class_) { PROTECT(t, class_); initClass(t, class_); return reinterpret_cast(makeNewGeneral(t, class_)); } uint64_t makeNew64(Thread* t, object class_) { PROTECT(t, class_); initClass(t, class_); return reinterpret_cast(makeNew(t, class_)); } uint64_t makeNewFromReference(Thread* t, object pair) { object class_ = resolveClass (t, classLoader(t, methodClass(t, pairFirst(t, pair))), referenceName(t, pairSecond(t, pair))); PROTECT(t, class_); initClass(t, class_); return makeNewGeneral64(t, class_); } uint64_t getJClass64(Thread* t, object class_) { return reinterpret_cast(getJClass(t, class_)); } void gcIfNecessary(MyThread* t) { stress(t); if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { collect(t, Heap::MinorCollection); } } void idleIfNecessary(MyThread* t) { ENTER(t, Thread::IdleState); } unsigned resultSize(MyThread* t, unsigned code) { switch (code) { case ByteField: case BooleanField: case CharField: case ShortField: case FloatField: case IntField: return 4; case ObjectField: return TargetBytesPerWord; case LongField: case DoubleField: return 8; case VoidField: return 0; default: abort(t); } } void pushReturnValue(MyThread* t, Frame* frame, unsigned code, Compiler::Operand* result) { switch (code) { case ByteField: case BooleanField: case CharField: case ShortField: case FloatField: case IntField: return frame->pushInt(result); case ObjectField: return frame->pushObject(result); case LongField: case DoubleField: return frame->pushLong(result); default: abort(t); } } Compiler::Operand* popField(MyThread* t, Frame* frame, int code) { switch (code) { case ByteField: case BooleanField: case CharField: case ShortField: case FloatField: case IntField: return frame->popInt(); case DoubleField: case LongField: return frame->popLong(); case ObjectField: return frame->popObject(); default: abort(t); } } Compiler::OperandType operandTypeForFieldCode(Thread* t, unsigned code) { switch (code) { case ByteField: case BooleanField: case CharField: case ShortField: case IntField: case LongField: return Compiler::IntegerType; case ObjectField: return Compiler::ObjectType; case FloatField: case DoubleField: return Compiler::FloatType; case VoidField: return Compiler::VoidType; default: abort(t); } } bool useLongJump(MyThread* t, uintptr_t target) { uintptr_t reach = t->arch->maximumImmediateJump(); FixedAllocator* a = codeAllocator(t); uintptr_t start = reinterpret_cast(a->memory.begin()); uintptr_t end = reinterpret_cast(a->memory.begin()) + a->memory.count; assert(t, end - start < reach); return (target > end && (target - start) > reach) or (target < start && (end - target) > reach); } void compileSafePoint(MyThread* t, Compiler* c, Frame* frame) { c->call (c->constant(getThunk(t, idleIfNecessaryThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 1, c->register_(t->arch->thread())); } Compiler::Operand* compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, bool useThunk, unsigned rSize, avian::codegen::Promise* addressPromise) { avian::codegen::Compiler* c = frame->c; unsigned flags = (avian::codegen::TailCalls and tailCall ? Compiler::TailJump : 0); unsigned traceFlags; if (addressPromise == 0 and useLongJump(t, methodAddress(t, target))) { flags |= Compiler::LongJumpOrCall; traceFlags = TraceElement::LongCall; } else { traceFlags = 0; } if (useThunk or (avian::codegen::TailCalls and tailCall and (methodFlags(t, target) & ACC_NATIVE))) { if (frame->context->bootContext == 0) { flags |= Compiler::Aligned; } if (avian::codegen::TailCalls and tailCall) { traceFlags |= TraceElement::TailCall; TraceElement* trace = frame->trace(target, traceFlags); avian::codegen::Promise* returnAddressPromise = new (frame->context->zone.allocate(sizeof(TraceElementPromise))) TraceElementPromise(t->m->system, trace); Compiler::Operand* result = c->stackCall (c->promiseConstant(returnAddressPromise, Compiler::AddressType), flags, trace, rSize, operandTypeForFieldCode(t, methodReturnCode(t, target)), methodParameterFootprint(t, target)); c->store (TargetBytesPerWord, frame->absoluteAddressOperand(returnAddressPromise), TargetBytesPerWord, c->memory (c->register_(t->arch->thread()), Compiler::AddressType, TARGET_THREAD_TAILADDRESS)); c->exit (c->constant ((methodFlags(t, target) & ACC_NATIVE) ? nativeThunk(t) : defaultThunk(t), Compiler::AddressType)); return result; } else { return c->stackCall (c->constant(defaultThunk(t), Compiler::AddressType), flags, frame->trace(target, traceFlags), rSize, operandTypeForFieldCode(t, methodReturnCode(t, target)), methodParameterFootprint(t, target)); } } else { Compiler::Operand* address = (addressPromise ? c->promiseConstant(addressPromise, Compiler::AddressType) : c->constant(methodAddress(t, target), Compiler::AddressType)); return c->stackCall (address, flags, tailCall ? 0 : frame->trace ((methodFlags(t, target) & ACC_NATIVE) ? target : 0, 0), rSize, operandTypeForFieldCode(t, methodReturnCode(t, target)), methodParameterFootprint(t, target)); } } bool compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall) { unsigned rSize = resultSize(t, methodReturnCode(t, target)); Compiler::Operand* result = 0; // don't bother calling an empty method unless calling it might // cause the class to be initialized, which may have side effects if (emptyMethod(t, target) and (not classNeedsInit(t, methodClass(t, target)))) { tailCall = false; } else { BootContext* bc = frame->context->bootContext; if (bc) { if ((methodClass(t, target) == methodClass(t, frame->context->method) or (not classNeedsInit(t, methodClass(t, target)))) and (not (avian::codegen::TailCalls and tailCall and (methodFlags(t, target) & ACC_NATIVE)))) { avian::codegen::Promise* p = new(bc->zone) avian::codegen::ListenPromise(t->m->system, bc->zone); PROTECT(t, target); object pointer = makePointer(t, p); bc->calls = makeTriple(t, target, pointer, bc->calls); result = compileDirectInvoke (t, frame, target, tailCall, false, rSize, p); } else { result = compileDirectInvoke (t, frame, target, tailCall, true, rSize, 0); } } else if (unresolved(t, methodAddress(t, target)) or classNeedsInit(t, methodClass(t, target))) { result = compileDirectInvoke (t, frame, target, tailCall, true, rSize, 0); } else { result = compileDirectInvoke (t, frame, target, tailCall, false, rSize, 0); } } frame->pop(methodParameterFootprint(t, target)); if (rSize) { pushReturnValue(t, frame, methodReturnCode(t, target), result); } return tailCall; } unsigned methodReferenceParameterFootprint(Thread* t, object reference, bool isStatic) { return parameterFootprint (t, reinterpret_cast (&byteArrayBody(t, referenceSpec(t, reference), 0)), isStatic); } int methodReferenceReturnCode(Thread* t, object reference) { unsigned parameterCount; unsigned returnCode; scanMethodSpec (t, reinterpret_cast (&byteArrayBody(t, referenceSpec(t, reference), 0)), ¶meterCount, &returnCode); return returnCode; } void compileReferenceInvoke(MyThread* t, Frame* frame, Compiler::Operand* method, object reference, bool isStatic, bool tailCall) { unsigned parameterFootprint = methodReferenceParameterFootprint(t, reference, isStatic); int returnCode = methodReferenceReturnCode(t, reference); unsigned rSize = resultSize(t, returnCode); Compiler::Operand* result = frame->c->stackCall (method, tailCall ? Compiler::TailJump : 0, frame->trace(0, 0), rSize, operandTypeForFieldCode(t, returnCode), parameterFootprint); frame->pop(parameterFootprint); if (rSize) { pushReturnValue(t, frame, returnCode, result); } } void compileDirectReferenceInvoke(MyThread* t, Frame* frame, Thunk thunk, object reference, bool isStatic, bool tailCall) { avian::codegen::Compiler* c = frame->c; PROTECT(t, reference); object pair = makePair(t, frame->context->method, reference); compileReferenceInvoke (t, frame, c->call (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), TargetBytesPerWord, Compiler::AddressType, 2, c->register_(t->arch->thread()), frame->append(pair)), reference, isStatic, tailCall); } void compileAbstractInvoke(MyThread* t, Frame* frame, Compiler::Operand* method, object target, bool tailCall) { unsigned parameterFootprint = methodParameterFootprint(t, target); int returnCode = methodReturnCode(t, target); unsigned rSize = resultSize(t, returnCode); Compiler::Operand* result = frame->c->stackCall (method, tailCall ? Compiler::TailJump : 0, frame->trace(0, 0), rSize, operandTypeForFieldCode(t, returnCode), parameterFootprint); frame->pop(parameterFootprint); if (rSize) { pushReturnValue(t, frame, returnCode, result); } } void compileDirectAbstractInvoke(MyThread* t, Frame* frame, Thunk thunk, object target, bool tailCall) { avian::codegen::Compiler* c = frame->c; compileAbstractInvoke (t, frame, c->call (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), TargetBytesPerWord, Compiler::AddressType, 2, c->register_(t->arch->thread()), frame->append(target)), target, tailCall); } void handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) { avian::codegen::Compiler* c = frame->c; object method = frame->context->method; if (methodFlags(t, method) & ACC_SYNCHRONIZED) { Compiler::Operand* lock; if (methodFlags(t, method) & ACC_STATIC) { PROTECT(t, method); lock = frame->append(methodClass(t, method)); } else { lock = loadLocal(frame->context, 1, savedTargetIndex(t, method)); } c->call(c->constant(function, Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), lock); } } void handleEntrance(MyThread* t, Frame* frame) { object method = frame->context->method; if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC)) == ACC_SYNCHRONIZED) { // save 'this' pointer in case it is overwritten. unsigned index = savedTargetIndex(t, method); storeLocal(frame->context, 1, loadLocal(frame->context, 1, 0), index); frame->set(index, Frame::Object); } handleMonitorEvent (t, frame, getThunk(t, acquireMonitorForObjectOnEntranceThunk)); } void handleExit(MyThread* t, Frame* frame) { handleMonitorEvent (t, frame, getThunk(t, releaseMonitorForObjectThunk)); } bool inTryBlock(MyThread* t, object code, unsigned ip) { object table = codeExceptionHandlerTable(t, code); if (table) { unsigned length = exceptionHandlerTableLength(t, table); for (unsigned i = 0; i < length; ++i) { uint64_t eh = exceptionHandlerTableBody(t, table, i); if (ip >= exceptionHandlerStart(eh) and ip < exceptionHandlerEnd(eh)) { return true; } } } return false; } bool needsReturnBarrier(MyThread* t, object method) { return (methodFlags(t, method) & ConstructorFlag) and (classVmFlags(t, methodClass(t, method)) & HasFinalMemberFlag); } bool returnsNext(MyThread* t, object code, unsigned ip) { switch (codeBody(t, code, ip)) { case return_: case areturn: case ireturn: case freturn: case lreturn: case dreturn: return true; case goto_: { uint32_t offset = codeReadInt16(t, code, ++ip); uint32_t newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); return returnsNext(t, code, newIp); } case goto_w: { uint32_t offset = codeReadInt32(t, code, ++ip); uint32_t newIp = (ip - 5) + offset; assert(t, newIp < codeLength(t, code)); return returnsNext(t, code, newIp); } default: return false; } } bool isTailCall(MyThread* t, object code, unsigned ip, object caller, int calleeReturnCode, object calleeClassName, object calleeMethodName, object calleeMethodSpec) { return avian::codegen::TailCalls and ((methodFlags(t, caller) & ACC_SYNCHRONIZED) == 0) and (not inTryBlock(t, code, ip - 1)) and (not needsReturnBarrier(t, caller)) and (methodReturnCode(t, caller) == VoidField or methodReturnCode(t, caller) == calleeReturnCode) and returnsNext(t, code, ip) and t->m->classpath->canTailCall (t, caller, calleeClassName, calleeMethodName, calleeMethodSpec); } bool isTailCall(MyThread* t, object code, unsigned ip, object caller, object callee) { return isTailCall (t, code, ip, caller, methodReturnCode(t, callee), className(t, methodClass(t, callee)), methodName(t, callee), methodSpec(t, callee)); } bool isReferenceTailCall(MyThread* t, object code, unsigned ip, object caller, object calleeReference) { object c = referenceClass(t, calleeReference); if (objectClass(t, c) == type(t, Machine::ClassType)) { c = className(t, c); } return isTailCall (t, code, ip, caller, methodReferenceReturnCode(t, calleeReference), c, referenceName(t, calleeReference), referenceSpec(t, calleeReference)); } lir::TernaryOperation toCompilerJumpOp(MyThread* t, unsigned instruction) { switch(instruction) { case ifeq: case if_icmpeq: case if_acmpeq: case ifnull: return lir::JumpIfEqual; case ifne: case if_icmpne: case if_acmpne: case ifnonnull: return lir::JumpIfNotEqual; case ifgt: case if_icmpgt: return lir::JumpIfGreater; case ifge: case if_icmpge: return lir::JumpIfGreaterOrEqual; case iflt: case if_icmplt: return lir::JumpIfLess; case ifle: case if_icmple: return lir::JumpIfLessOrEqual; default: abort(t); } } bool integerBranch(MyThread* t, Frame* frame, object code, unsigned& ip, unsigned size, Compiler::Operand* a, Compiler::Operand* b, unsigned* newIpp) { if (ip + 3 > codeLength(t, code)) { return false; } avian::codegen::Compiler* c = frame->c; unsigned instruction = codeBody(t, code, ip++); uint32_t offset = codeReadInt16(t, code, ip); uint32_t newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); Compiler::Operand* target = frame->machineIp(newIp); switch (instruction) { case ifeq: case ifne: case ifgt: case ifge: case iflt: case ifle: c->condJump(toCompilerJumpOp(t, instruction), size, a, b, target); break; default: ip -= 3; return false; } *newIpp = newIp; return true; } lir::TernaryOperation toCompilerFloatJumpOp(MyThread* t, unsigned instruction, bool lessIfUnordered) { switch(instruction) { case ifeq: return lir::JumpIfFloatEqual; case ifne: return lir::JumpIfFloatNotEqual; case ifgt: if (lessIfUnordered) { return lir::JumpIfFloatGreater; } else { return lir::JumpIfFloatGreaterOrUnordered; } case ifge: if (lessIfUnordered) { return lir::JumpIfFloatGreaterOrEqual; } else { return lir::JumpIfFloatGreaterOrEqualOrUnordered; } case iflt: if (lessIfUnordered) { return lir::JumpIfFloatLessOrUnordered; } else { return lir::JumpIfFloatLess; } case ifle: if (lessIfUnordered) { return lir::JumpIfFloatLessOrEqualOrUnordered; } else { return lir::JumpIfFloatLessOrEqual; } default: abort(t); } } bool floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip, unsigned size, bool lessIfUnordered, Compiler::Operand* a, Compiler::Operand* b, unsigned* newIpp) { if (ip + 3 > codeLength(t, code)) { return false; } avian::codegen::Compiler* c = frame->c; unsigned instruction = codeBody(t, code, ip++); uint32_t offset = codeReadInt16(t, code, ip); uint32_t newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); Compiler::Operand* target = frame->machineIp(newIp); switch (instruction) { case ifeq: case ifne: case ifgt: case ifge: case iflt: case ifle: c->condJump(toCompilerFloatJumpOp(t, instruction, lessIfUnordered), size, a, b, target); break; default: ip -= 3; return false; } *newIpp = newIp; return true; } Compiler::Operand* popLongAddress(Frame* frame) { return TargetBytesPerWord == 8 ? frame->popLong() : frame->c->load (8, 8, frame->popLong(), TargetBytesPerWord); } bool intrinsic(MyThread* t, Frame* frame, object target) { #define MATCH(name, constant) \ (byteArrayLength(t, name) == sizeof(constant) \ and ::strcmp(reinterpret_cast(&byteArrayBody(t, name, 0)), \ constant) == 0) object className = vm::className(t, methodClass(t, target)); if (UNLIKELY(MATCH(className, "java/lang/Math"))) { avian::codegen::Compiler* c = frame->c; if (MATCH(methodName(t, target), "sqrt") and MATCH(methodSpec(t, target), "(D)D")) { frame->pushLong(c->unaryOp(lir::FloatSquareRoot, 8, frame->popLong())); return true; } else if (MATCH(methodName(t, target), "abs")) { if (MATCH(methodSpec(t, target), "(I)I")) { frame->pushInt(c->unaryOp(lir::Absolute, 4, frame->popInt())); return true; } else if (MATCH(methodSpec(t, target), "(J)J")) { frame->pushLong(c->unaryOp(lir::Absolute, 8, frame->popLong())); return true; } else if (MATCH(methodSpec(t, target), "(F)F")) { frame->pushInt(c->unaryOp(lir::FloatAbsolute, 4, frame->popInt())); return true; } } } else if (UNLIKELY(MATCH(className, "sun/misc/Unsafe"))) { avian::codegen::Compiler* c = frame->c; if (MATCH(methodName(t, target), "getByte") and MATCH(methodSpec(t, target), "(J)B")) { Compiler::Operand* address = popLongAddress(frame); frame->popObject(); frame->pushInt (c->load (1, 1, c->memory(address, Compiler::IntegerType, 0, 0, 1), TargetBytesPerWord)); return true; } else if (MATCH(methodName(t, target), "putByte") and MATCH(methodSpec(t, target), "(JB)V")) { Compiler::Operand* value = frame->popInt(); Compiler::Operand* address = popLongAddress(frame); frame->popObject(); c->store (TargetBytesPerWord, value, 1, c->memory (address, Compiler::IntegerType, 0, 0, 1)); return true; } else if ((MATCH(methodName(t, target), "getShort") and MATCH(methodSpec(t, target), "(J)S")) or (MATCH(methodName(t, target), "getChar") and MATCH(methodSpec(t, target), "(J)C"))) { Compiler::Operand* address = popLongAddress(frame); frame->popObject(); frame->pushInt (c->load (2, 2, c->memory(address, Compiler::IntegerType, 0, 0, 1), TargetBytesPerWord)); return true; } else if ((MATCH(methodName(t, target), "putShort") and MATCH(methodSpec(t, target), "(JS)V")) or (MATCH(methodName(t, target), "putChar") and MATCH(methodSpec(t, target), "(JC)V"))) { Compiler::Operand* value = frame->popInt(); Compiler::Operand* address = popLongAddress(frame); frame->popObject(); c->store (TargetBytesPerWord, value, 2, c->memory (address, Compiler::IntegerType, 0, 0, 1)); return true; } else if ((MATCH(methodName(t, target), "getInt") and MATCH(methodSpec(t, target), "(J)I")) or (MATCH(methodName(t, target), "getFloat") and MATCH(methodSpec(t, target), "(J)F"))) { Compiler::Operand* address = popLongAddress(frame); frame->popObject(); frame->pushInt (c->load (4, 4, c->memory (address, MATCH(methodName(t, target), "getInt") ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1), TargetBytesPerWord)); return true; } else if ((MATCH(methodName(t, target), "putInt") and MATCH(methodSpec(t, target), "(JI)V")) or (MATCH(methodName(t, target), "putFloat") and MATCH(methodSpec(t, target), "(JF)V"))) { Compiler::Operand* value = frame->popInt(); Compiler::Operand* address = popLongAddress(frame); frame->popObject(); c->store (TargetBytesPerWord, value, 4, c->memory (address, MATCH(methodName(t, target), "putInt") ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1)); return true; } else if ((MATCH(methodName(t, target), "getLong") and MATCH(methodSpec(t, target), "(J)J")) or (MATCH(methodName(t, target), "getDouble") and MATCH(methodSpec(t, target), "(J)D"))) { Compiler::Operand* address = popLongAddress(frame); frame->popObject(); frame->pushLong (c->load (8, 8, c->memory (address, MATCH(methodName(t, target), "getLong") ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1), 8)); return true; } else if ((MATCH(methodName(t, target), "putLong") and MATCH(methodSpec(t, target), "(JJ)V")) or (MATCH(methodName(t, target), "putDouble") and MATCH(methodSpec(t, target), "(JD)V"))) { Compiler::Operand* value = frame->popLong(); Compiler::Operand* address = popLongAddress(frame); frame->popObject(); c->store (8, value, 8, c->memory (address, MATCH(methodName(t, target), "putLong") ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1)); return true; } else if (MATCH(methodName(t, target), "getAddress") and MATCH(methodSpec(t, target), "(J)J")) { Compiler::Operand* address = popLongAddress(frame); frame->popObject(); frame->pushLong (c->load (TargetBytesPerWord, TargetBytesPerWord, c->memory(address, Compiler::AddressType, 0, 0, 1), 8)); return true; } else if (MATCH(methodName(t, target), "putAddress") and MATCH(methodSpec(t, target), "(JJ)V")) { Compiler::Operand* value = frame->popLong(); Compiler::Operand* address = popLongAddress(frame); frame->popObject(); c->store (8, value, TargetBytesPerWord, c->memory (address, Compiler::AddressType, 0, 0, 1)); return true; } } return false; } unsigned targetFieldOffset(Context* context, object field) { if (context->bootContext) { return context->bootContext->resolver->fieldOffset(context->thread, field); } else { return fieldOffset(context->thread, field); } } class Stack { public: class MyResource: public Thread::Resource { public: MyResource(Stack* s): Resource(s->thread), s(s) { } virtual void release() { s->zone.dispose(); } Stack* s; }; Stack(MyThread* t): thread(t), zone(t->m->system, t->m->heap, 0), resource(this) { } ~Stack() { zone.dispose(); } void pushValue(uintptr_t v) { *static_cast(push(BytesPerWord)) = v; } uintptr_t peekValue(unsigned offset) { return *static_cast(peek((offset + 1) * BytesPerWord)); } uintptr_t popValue() { uintptr_t v = peekValue(0); pop(BytesPerWord); return v; } void* push(unsigned size) { return zone.allocate(size); } void* peek(unsigned size) { return zone.peek(size); } void pop(unsigned size) { zone.pop(size); } MyThread* thread; Zone zone; MyResource resource; }; class SwitchState { public: SwitchState(Compiler::State* state, unsigned count, unsigned defaultIp, Compiler::Operand* key, avian::codegen::Promise* start, int bottom, int top): state(state), count(count), defaultIp(defaultIp), key(key), start(start), bottom(bottom), top(top), index(0) { } Frame* frame() { return reinterpret_cast (reinterpret_cast(this) - pad(count * 4) - pad(sizeof(Frame))); } uint32_t* ipTable() { return reinterpret_cast (reinterpret_cast(this) - pad(count * 4)); } Compiler::State* state; unsigned count; unsigned defaultIp; Compiler::Operand* key; avian::codegen::Promise* start; int bottom; int top; unsigned index; }; lir::TernaryOperation toCompilerBinaryOp(MyThread* t, unsigned instruction) { switch (instruction) { case iadd: case ladd: return lir::Add; case ior: case lor: return lir::Or; case ishl: case lshl: return lir::ShiftLeft; case ishr: case lshr: return lir::ShiftRight; case iushr: case lushr: return lir::UnsignedShiftRight; case fadd: case dadd: return lir::FloatAdd; case fsub: case dsub: return lir::FloatSubtract; case fmul: case dmul: return lir::FloatMultiply; case fdiv: case ddiv: return lir::FloatDivide; case frem: case vm::drem: return lir::FloatRemainder; case iand: case land: return lir::And; case isub: case lsub: return lir::Subtract; case ixor: case lxor: return lir::Xor; case imul: case lmul: return lir::Multiply; default: abort(t); } } void compile(MyThread* t, Frame* initialFrame, unsigned initialIp, int exceptionHandlerStart = -1) { enum { Return, Unbranch, Unsubroutine, Untable0, Untable1, Unswitch }; Frame* frame = initialFrame; avian::codegen::Compiler* c = frame->c; Context* context = frame->context; unsigned stackSize = codeMaxStack(t, methodCode(t, context->method)); Stack stack(t); unsigned ip = initialIp; unsigned newIp; stack.pushValue(Return); start: uint8_t* stackMap = static_cast(stack.push(stackSize)); frame = new (stack.push(sizeof(Frame))) Frame(frame, stackMap); loop: object code = methodCode(t, context->method); PROTECT(t, code); while (ip < codeLength(t, code)) { if (context->visitTable[ip] ++) { // we've already visited this part of the code frame->visitLogicalIp(ip); goto next; } frame->startLogicalIp(ip); if (exceptionHandlerStart >= 0) { c->initLocalsFromLogicalIp(exceptionHandlerStart); exceptionHandlerStart = -1; frame->pushObject(); c->call (c->constant(getThunk(t, gcIfNecessaryThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 1, c->register_(t->arch->thread())); } // fprintf(stderr, "ip: %d map: %ld\n", ip, *(frame->map)); unsigned instruction = codeBody(t, code, ip++); switch (instruction) { case aaload: case baload: case caload: case daload: case faload: case iaload: case laload: case saload: { Compiler::Operand* index = frame->popInt(); Compiler::Operand* array = frame->popObject(); if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); frame->trace(0, 0); } if (CheckArrayBounds) { c->checkBounds(array, TargetArrayLength, index, aioobThunk(t)); } switch (instruction) { case aaload: frame->pushObject (c->load (TargetBytesPerWord, TargetBytesPerWord, c->memory (array, Compiler::ObjectType, TargetArrayBody, index, TargetBytesPerWord), TargetBytesPerWord)); break; case faload: frame->pushInt (c->load (4, 4, c->memory (array, Compiler::FloatType, TargetArrayBody, index, 4), TargetBytesPerWord)); break; case iaload: frame->pushInt (c->load (4, 4, c->memory (array, Compiler::IntegerType, TargetArrayBody, index, 4), TargetBytesPerWord)); break; case baload: frame->pushInt (c->load (1, 1, c->memory (array, Compiler::IntegerType, TargetArrayBody, index, 1), TargetBytesPerWord)); break; case caload: frame->pushInt (c->loadz (2, 2, c->memory (array, Compiler::IntegerType, TargetArrayBody, index, 2), TargetBytesPerWord)); break; case daload: frame->pushLong (c->load (8, 8, c->memory (array, Compiler::FloatType, TargetArrayBody, index, 8), 8)); break; case laload: frame->pushLong (c->load (8, 8, c->memory (array, Compiler::IntegerType, TargetArrayBody, index, 8), 8)); break; case saload: frame->pushInt (c->load (2, 2, c->memory (array, Compiler::IntegerType, TargetArrayBody, index, 2), TargetBytesPerWord)); break; } } break; case aastore: case bastore: case castore: case dastore: case fastore: case iastore: case lastore: case sastore: { Compiler::Operand* value; if (instruction == dastore or instruction == lastore) { value = frame->popLong(); } else if (instruction == aastore) { value = frame->popObject(); } else { value = frame->popInt(); } Compiler::Operand* index = frame->popInt(); Compiler::Operand* array = frame->popObject(); if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); frame->trace(0, 0); } if (CheckArrayBounds) { c->checkBounds(array, TargetArrayLength, index, aioobThunk(t)); } switch (instruction) { case aastore: { c->call (c->constant(getThunk(t, setMaybeNullThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 4, c->register_(t->arch->thread()), array, c->binaryOp(lir::Add, 4, c->constant(TargetArrayBody, Compiler::IntegerType), c->binaryOp(lir::ShiftLeft, 4, c->constant(log(TargetBytesPerWord), Compiler::IntegerType), index)), value); } break; case fastore: c->store (TargetBytesPerWord, value, 4, c->memory (array, Compiler::FloatType, TargetArrayBody, index, 4)); break; case iastore: c->store (TargetBytesPerWord, value, 4, c->memory (array, Compiler::IntegerType, TargetArrayBody, index, 4)); break; case bastore: c->store (TargetBytesPerWord, value, 1, c->memory (array, Compiler::IntegerType, TargetArrayBody, index, 1)); break; case castore: case sastore: c->store (TargetBytesPerWord, value, 2, c->memory (array, Compiler::IntegerType, TargetArrayBody, index, 2)); break; case dastore: c->store (8, value, 8, c->memory (array, Compiler::FloatType, TargetArrayBody, index, 8)); break; case lastore: c->store (8, value, 8, c->memory (array, Compiler::IntegerType, TargetArrayBody, index, 8)); break; } } break; case aconst_null: frame->pushObject(c->constant(0, Compiler::ObjectType)); break; case aload: frame->loadObject(codeBody(t, code, ip++)); break; case aload_0: frame->loadObject(0); break; case aload_1: frame->loadObject(1); break; case aload_2: frame->loadObject(2); break; case aload_3: frame->loadObject(3); break; case anewarray: { uint16_t index = codeReadInt16(t, code, ip); object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object class_ = resolveClassInPool(t, context->method, index - 1, false); Compiler::Operand* length = frame->popInt(); object argument; Thunk thunk; if (LIKELY(class_)) { argument = class_; thunk = makeBlankObjectArrayThunk; } else { argument = makePair(t, context->method, reference); thunk = makeBlankObjectArrayFromReferenceThunk; } frame->pushObject (c->call (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), TargetBytesPerWord, Compiler::ObjectType, 3, c->register_(t->arch->thread()), frame->append(argument), length)); } break; case areturn: { handleExit(t, frame); c->return_(TargetBytesPerWord, frame->popObject()); } goto next; case arraylength: { frame->pushInt (c->load (TargetBytesPerWord, TargetBytesPerWord, c->memory (frame->popObject(), Compiler::IntegerType, TargetArrayLength, 0, 1), TargetBytesPerWord)); } break; case astore: frame->storeObjectOrAddress(codeBody(t, code, ip++)); break; case astore_0: frame->storeObjectOrAddress(0); break; case astore_1: frame->storeObjectOrAddress(1); break; case astore_2: frame->storeObjectOrAddress(2); break; case astore_3: frame->storeObjectOrAddress(3); break; case athrow: { Compiler::Operand* target = frame->popObject(); c->call (c->constant(getThunk(t, throw_Thunk), Compiler::AddressType), Compiler::NoReturn, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), target); c->nullaryOp(lir::Trap); } goto next; case bipush: frame->pushInt (c->constant (static_cast(codeBody(t, code, ip++)), Compiler::IntegerType)); break; case checkcast: { uint16_t index = codeReadInt16(t, code, ip); object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object class_ = resolveClassInPool(t, context->method, index - 1, false); object argument; Thunk thunk; if (LIKELY(class_)) { argument = class_; thunk = checkCastThunk; } else { argument = makePair(t, context->method, reference); thunk = checkCastFromReferenceThunk; } Compiler::Operand* instance = c->peek(1, 0); c->call (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 3, c->register_(t->arch->thread()), frame->append(argument), instance); } break; case d2f: { frame->pushInt(c->f2f(8, 4, frame->popLong())); } break; case d2i: { frame->pushInt(c->f2i(8, 4, frame->popLong())); } break; case d2l: { frame->pushLong(c->f2i(8, 8, frame->popLong())); } break; case dadd: case dsub: case dmul: case ddiv: case vm::drem: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); frame->pushLong(c->binaryOp(toCompilerBinaryOp(t, instruction), 8, a, b)); } break; case dcmpg: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); if (floatBranch(t, frame, code, ip, 8, false, a, b, &newIp)) { goto branch; } else { frame->pushInt (c->call (c->constant (getThunk(t, compareDoublesGThunk), Compiler::AddressType), 0, 0, 4, Compiler::IntegerType, 4, static_cast(0), a, static_cast(0), b)); } } break; case dcmpl: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); if (floatBranch(t, frame, code, ip, 8, true, a, b, &newIp)) { goto branch; } else { frame->pushInt (c->call (c->constant (getThunk(t, compareDoublesLThunk), Compiler::AddressType), 0, 0, 4, Compiler::IntegerType, 4, static_cast(0), a, static_cast(0), b)); } } break; case dconst_0: frame->pushLong(c->constant(doubleToBits(0.0), Compiler::FloatType)); break; case dconst_1: frame->pushLong(c->constant(doubleToBits(1.0), Compiler::FloatType)); break; case dneg: { frame->pushLong(c->unaryOp(lir::FloatNegate, 8, frame->popLong())); } break; case dup: frame->dup(); break; case dup_x1: frame->dupX1(); break; case dup_x2: frame->dupX2(); break; case dup2: frame->dup2(); break; case dup2_x1: frame->dup2X1(); break; case dup2_x2: frame->dup2X2(); break; case f2d: { frame->pushLong(c->f2f(4, 8, frame->popInt())); } break; case f2i: { frame->pushInt(c->f2i(4, 4, frame->popInt())); } break; case f2l: { frame->pushLong(c->f2i(4, 8, frame->popInt())); } break; case fadd: case fsub: case fmul: case fdiv: case frem: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); frame->pushInt(c->binaryOp(toCompilerBinaryOp(t, instruction), 4, a, b)); } break; case fcmpg: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); if (floatBranch(t, frame, code, ip, 4, false, a, b, &newIp)) { goto branch; } else { frame->pushInt (c->call (c->constant (getThunk(t, compareFloatsGThunk), Compiler::AddressType), 0, 0, 4, Compiler::IntegerType, 2, a, b)); } } break; case fcmpl: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); if (floatBranch(t, frame, code, ip, 4, true, a, b, &newIp)) { goto branch; } else { frame->pushInt (c->call (c->constant (getThunk(t, compareFloatsLThunk), Compiler::AddressType), 0, 0, 4, Compiler::IntegerType, 2, a, b)); } } break; case fconst_0: frame->pushInt(c->constant(floatToBits(0.0), Compiler::FloatType)); break; case fconst_1: frame->pushInt(c->constant(floatToBits(1.0), Compiler::FloatType)); break; case fconst_2: frame->pushInt(c->constant(floatToBits(2.0), Compiler::FloatType)); break; case fneg: { frame->pushInt(c->unaryOp(lir::FloatNegate, 4, frame->popInt())); } break; case getfield: case getstatic: { uint16_t index = codeReadInt16(t, code, ip); object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object field = resolveField(t, context->method, index - 1, false); if (LIKELY(field)) { if ((fieldFlags(t, field) & ACC_VOLATILE) and TargetBytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { PROTECT(t, field); c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), frame->append(field)); } Compiler::Operand* table; if (instruction == getstatic) { checkField(t, field, true); PROTECT(t, field); if (classNeedsInit(t, fieldClass(t, field))) { c->call (c->constant (getThunk(t, tryInitClassThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), frame->append(fieldClass(t, field))); } table = frame->append(classStaticTable(t, fieldClass(t, field))); } else { checkField(t, field, false); table = frame->popObject(); if (inTryBlock(t, code, ip - 3)) { c->saveLocals(); frame->trace(0, 0); } } switch (fieldCode(t, field)) { case ByteField: case BooleanField: frame->pushInt (c->load (1, 1, c->memory (table, Compiler::IntegerType, targetFieldOffset (context, field), 0, 1), TargetBytesPerWord)); break; case CharField: frame->pushInt (c->loadz (2, 2, c->memory (table, Compiler::IntegerType, targetFieldOffset (context, field), 0, 1), TargetBytesPerWord)); break; case ShortField: frame->pushInt (c->load (2, 2, c->memory (table, Compiler::IntegerType, targetFieldOffset (context, field), 0, 1), TargetBytesPerWord)); break; case FloatField: frame->pushInt (c->load (4, 4, c->memory (table, Compiler::FloatType, targetFieldOffset (context, field), 0, 1), TargetBytesPerWord)); break; case IntField: frame->pushInt (c->load (4, 4, c->memory (table, Compiler::IntegerType, targetFieldOffset (context, field), 0, 1), TargetBytesPerWord)); break; case DoubleField: frame->pushLong (c->load (8, 8, c->memory (table, Compiler::FloatType, targetFieldOffset (context, field), 0, 1), 8)); break; case LongField: frame->pushLong (c->load (8, 8, c->memory (table, Compiler::IntegerType, targetFieldOffset (context, field), 0, 1), 8)); break; case ObjectField: frame->pushObject (c->load (TargetBytesPerWord, TargetBytesPerWord, c->memory (table, Compiler::ObjectType, targetFieldOffset (context, field), 0, 1), TargetBytesPerWord)); break; default: abort(t); } if (fieldFlags(t, field) & ACC_VOLATILE) { if (TargetBytesPerWord == 4 and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { c->call (c->constant (getThunk(t, releaseMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), frame->append(field)); } else { c->nullaryOp(lir::LoadBarrier); } } } else { int fieldCode = vm::fieldCode (t, byteArrayBody(t, referenceSpec(t, reference), 0)); object pair = makePair(t, context->method, reference); unsigned rSize = resultSize(t, fieldCode); Compiler::OperandType rType = operandTypeForFieldCode(t, fieldCode); Compiler::Operand* result; if (instruction == getstatic) { result = c->call (c->constant (getThunk(t, getStaticFieldValueFromReferenceThunk), Compiler::AddressType), 0, frame->trace(0, 0), rSize, rType, 2, c->register_(t->arch->thread()), frame->append(pair)); } else { Compiler::Operand* instance = frame->popObject(); result = c->call (c->constant (getThunk(t, getFieldValueFromReferenceThunk), Compiler::AddressType), 0, frame->trace(0, 0), rSize, rType, 3, c->register_(t->arch->thread()), frame->append(pair), instance); } pushReturnValue(t, frame, fieldCode, result); } } break; case goto_: { uint32_t offset = codeReadInt16(t, code, ip); uint32_t newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); if(newIp <= ip) { compileSafePoint(t, c, frame); } c->jmp(frame->machineIp(newIp)); ip = newIp; } break; case goto_w: { uint32_t offset = codeReadInt32(t, code, ip); uint32_t newIp = (ip - 5) + offset; assert(t, newIp < codeLength(t, code)); if(newIp <= ip) { compileSafePoint(t, c, frame); } c->jmp(frame->machineIp(newIp)); ip = newIp; } break; case i2b: { frame->pushInt (c->load(TargetBytesPerWord, 1, frame->popInt(), TargetBytesPerWord)); } break; case i2c: { frame->pushInt (c->loadz(TargetBytesPerWord, 2, frame->popInt(), TargetBytesPerWord)); } break; case i2d: { frame->pushLong(c->i2f(4, 8, frame->popInt())); } break; case i2f: { frame->pushInt(c->i2f(4, 4, frame->popInt())); } break; case i2l: frame->pushLong(c->load(TargetBytesPerWord, 4, frame->popInt(), 8)); break; case i2s: { frame->pushInt (c->load(TargetBytesPerWord, 2, frame->popInt(), TargetBytesPerWord)); } break; case iadd: case iand: case ior: case ishl: case ishr: case iushr: case isub: case ixor: case imul: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); frame->pushInt(c->binaryOp(toCompilerBinaryOp(t, instruction), 4, a, b)); } break; case iconst_m1: frame->pushInt(c->constant(-1, Compiler::IntegerType)); break; case iconst_0: frame->pushInt(c->constant(0, Compiler::IntegerType)); break; case iconst_1: frame->pushInt(c->constant(1, Compiler::IntegerType)); break; case iconst_2: frame->pushInt(c->constant(2, Compiler::IntegerType)); break; case iconst_3: frame->pushInt(c->constant(3, Compiler::IntegerType)); break; case iconst_4: frame->pushInt(c->constant(4, Compiler::IntegerType)); break; case iconst_5: frame->pushInt(c->constant(5, Compiler::IntegerType)); break; case idiv: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); frame->trace(0, 0); } frame->pushInt(c->binaryOp(lir::Divide, 4, a, b)); } break; case if_acmpeq: case if_acmpne: { uint32_t offset = codeReadInt16(t, code, ip); newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); if(newIp <= ip) { compileSafePoint(t, c, frame); } Compiler::Operand* a = frame->popObject(); Compiler::Operand* b = frame->popObject(); Compiler::Operand* target = frame->machineIp(newIp); c->condJump(toCompilerJumpOp(t, instruction), TargetBytesPerWord, a, b, target); } goto branch; case if_icmpeq: case if_icmpne: case if_icmpgt: case if_icmpge: case if_icmplt: case if_icmple: { uint32_t offset = codeReadInt16(t, code, ip); newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); if(newIp <= ip) { compileSafePoint(t, c, frame); } Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); Compiler::Operand* target = frame->machineIp(newIp); c->condJump(toCompilerJumpOp(t, instruction), 4, a, b, target); } goto branch; case ifeq: case ifne: case ifgt: case ifge: case iflt: case ifle: { uint32_t offset = codeReadInt16(t, code, ip); newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); Compiler::Operand* target = frame->machineIp(newIp); if(newIp <= ip) { compileSafePoint(t, c, frame); } Compiler::Operand* a = c->constant(0, Compiler::IntegerType); Compiler::Operand* b = frame->popInt(); c->condJump(toCompilerJumpOp(t, instruction), 4, a, b, target); } goto branch; case ifnull: case ifnonnull: { uint32_t offset = codeReadInt16(t, code, ip); newIp = (ip - 3) + offset; assert(t, newIp < codeLength(t, code)); if(newIp <= ip) { compileSafePoint(t, c, frame); } Compiler::Operand* a = c->constant(0, Compiler::ObjectType); Compiler::Operand* b = frame->popObject(); Compiler::Operand* target = frame->machineIp(newIp); c->condJump(toCompilerJumpOp(t, instruction), TargetBytesPerWord, a, b, target); } goto branch; case iinc: { uint8_t index = codeBody(t, code, ip++); int8_t count = codeBody(t, code, ip++); storeLocal (context, 1, c->binaryOp(lir::Add, 4, c->constant(count, Compiler::IntegerType), loadLocal(context, 1, index)), index); } break; case iload: case fload: frame->loadInt(codeBody(t, code, ip++)); break; case iload_0: case fload_0: frame->loadInt(0); break; case iload_1: case fload_1: frame->loadInt(1); break; case iload_2: case fload_2: frame->loadInt(2); break; case iload_3: case fload_3: frame->loadInt(3); break; case ineg: { frame->pushInt(c->unaryOp(lir::Negate, 4, frame->popInt())); } break; case instanceof: { uint16_t index = codeReadInt16(t, code, ip); object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object class_ = resolveClassInPool(t, context->method, index - 1, false); Compiler::Operand* instance = frame->popObject(); object argument; Thunk thunk; if (LIKELY(class_)) { argument = class_; thunk = instanceOf64Thunk; } else { argument = makePair(t, context->method, reference); thunk = instanceOfFromReferenceThunk; } frame->pushInt (c->call (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), 4, Compiler::IntegerType, 3, c->register_(t->arch->thread()), frame->append(argument), instance)); } break; case invokeinterface: { context->leaf = false; uint16_t index = codeReadInt16(t, code, ip); ip += 2; object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object target = resolveMethod(t, context->method, index - 1, false); object argument; Thunk thunk; unsigned parameterFootprint; int returnCode; bool tailCall; if (LIKELY(target)) { checkMethod(t, target, false); argument = target; thunk = findInterfaceMethodFromInstanceThunk; parameterFootprint = methodParameterFootprint(t, target); returnCode = methodReturnCode(t, target); tailCall = isTailCall(t, code, ip, context->method, target); } else { argument = makePair(t, context->method, reference); thunk = findInterfaceMethodFromInstanceAndReferenceThunk; parameterFootprint = methodReferenceParameterFootprint (t, reference, false); returnCode = methodReferenceReturnCode(t, reference); tailCall = isReferenceTailCall (t, code, ip, context->method, reference); } unsigned rSize = resultSize(t, returnCode); Compiler::Operand* result = c->stackCall (c->call (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), TargetBytesPerWord, Compiler::AddressType, 3, c->register_(t->arch->thread()), frame->append(argument), c->peek(1, parameterFootprint - 1)), tailCall ? Compiler::TailJump : 0, frame->trace(0, 0), rSize, operandTypeForFieldCode(t, returnCode), parameterFootprint); frame->pop(parameterFootprint); if (rSize) { pushReturnValue(t, frame, returnCode, result); } } break; case invokespecial: { context->leaf = false; uint16_t index = codeReadInt16(t, code, ip); object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object target = resolveMethod(t, context->method, index - 1, false); if (LIKELY(target)) { object class_ = methodClass(t, context->method); if (isSpecialMethod(t, target, class_)) { target = findVirtualMethod(t, target, classSuper(t, class_)); } checkMethod(t, target, false); bool tailCall = isTailCall(t, code, ip, context->method, target); if (UNLIKELY(methodAbstract(t, target))) { compileDirectAbstractInvoke (t, frame, getMethodAddressThunk, target, tailCall); } else { compileDirectInvoke(t, frame, target, tailCall); } } else { compileDirectReferenceInvoke (t, frame, findSpecialMethodFromReferenceThunk, reference, false, isReferenceTailCall(t, code, ip, context->method, reference)); } } break; case invokestatic: { context->leaf = false; uint16_t index = codeReadInt16(t, code, ip); object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object target = resolveMethod(t, context->method, index - 1, false); if (LIKELY(target)) { checkMethod(t, target, true); if (not intrinsic(t, frame, target)) { bool tailCall = isTailCall(t, code, ip, context->method, target); compileDirectInvoke(t, frame, target, tailCall); } } else { compileDirectReferenceInvoke (t, frame, findStaticMethodFromReferenceThunk, reference, true, isReferenceTailCall(t, code, ip, context->method, reference)); } } break; case invokevirtual: { context->leaf = false; uint16_t index = codeReadInt16(t, code, ip); object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object target = resolveMethod(t, context->method, index - 1, false); if (LIKELY(target)) { checkMethod(t, target, false); if (not intrinsic(t, frame, target)) { bool tailCall = isTailCall(t, code, ip, context->method, target); if (LIKELY(methodVirtual(t, target))) { unsigned parameterFootprint = methodParameterFootprint(t, target); unsigned offset = TargetClassVtable + (methodOffset(t, target) * TargetBytesPerWord); Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); unsigned rSize = resultSize(t, methodReturnCode(t, target)); Compiler::Operand* result = c->stackCall (c->memory (c->binaryOp(lir::And, TargetBytesPerWord, c->constant (TargetPointerMask, Compiler::IntegerType), c->memory(instance, Compiler::ObjectType, 0, 0, 1)), Compiler::ObjectType, offset, 0, 1), tailCall ? Compiler::TailJump : 0, frame->trace(0, 0), rSize, operandTypeForFieldCode(t, methodReturnCode(t, target)), parameterFootprint); frame->pop(parameterFootprint); if (rSize) { pushReturnValue(t, frame, methodReturnCode(t, target), result); } } else { // OpenJDK generates invokevirtual calls to private methods // (e.g. readObject and writeObject for serialization), so // we must handle such cases here. compileDirectInvoke(t, frame, target, tailCall); } } } else { PROTECT(t, reference); object pair = makePair(t, context->method, reference); compileReferenceInvoke (t, frame, c->call (c->constant(getThunk(t, findVirtualMethodFromReferenceThunk), Compiler::AddressType), 0, frame->trace(0, 0), TargetBytesPerWord, Compiler::AddressType, 3, c->register_(t->arch->thread()), frame->append(pair), c->peek(1, methodReferenceParameterFootprint (t, reference, false) - 1)), reference, false, isReferenceTailCall (t, code, ip, context->method, reference)); } } break; case irem: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); frame->trace(0, 0); } frame->pushInt(c->binaryOp(lir::Remainder, 4, a, b)); } break; case ireturn: case freturn: { handleExit(t, frame); c->return_(4, frame->popInt()); } goto next; case istore: case fstore: frame->storeInt(codeBody(t, code, ip++)); break; case istore_0: case fstore_0: frame->storeInt(0); break; case istore_1: case fstore_1: frame->storeInt(1); break; case istore_2: case fstore_2: frame->storeInt(2); break; case istore_3: case fstore_3: frame->storeInt(3); break; case jsr: case jsr_w: { uint32_t thisIp; if (instruction == jsr) { uint32_t offset = codeReadInt16(t, code, ip); thisIp = ip - 3; newIp = thisIp + offset; } else { uint32_t offset = codeReadInt32(t, code, ip); thisIp = ip - 5; newIp = thisIp + offset; } assert(t, newIp < codeLength(t, code)); unsigned start = frame->startSubroutine(newIp, c->machineIp(ip)); c->jmp(frame->machineIp(newIp)); stack.pushValue(start); stack.pushValue(ip); stack.pushValue(Unsubroutine); ip = newIp; } goto start; case l2d: { frame->pushLong(c->i2f(8, 8, frame->popLong())); } break; case l2f: { frame->pushInt(c->i2f(8, 4, frame->popLong())); } break; case l2i: frame->pushInt(c->load(8, 8, frame->popLong(), TargetBytesPerWord)); break; case ladd: case land: case lor: case lsub: case lxor: case lmul: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); frame->pushLong(c->binaryOp(toCompilerBinaryOp(t, instruction), 8, a, b)); } break; case lcmp: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); if (integerBranch(t, frame, code, ip, 8, a, b, &newIp)) { goto branch; } else { frame->pushInt (c->call (c->constant (getThunk(t, compareLongsThunk), Compiler::AddressType), 0, 0, 4, Compiler::IntegerType, 4, static_cast(0), a, static_cast(0), b)); } } break; case lconst_0: frame->pushLong(c->constant(0, Compiler::IntegerType)); break; case lconst_1: frame->pushLong(c->constant(1, Compiler::IntegerType)); break; case ldc: case ldc_w: { uint16_t index; if (instruction == ldc) { index = codeBody(t, code, ip++); } else { index = codeReadInt16(t, code, ip); } object pool = codePool(t, code); if (singletonIsObject(t, pool, index - 1)) { object v = singletonObject(t, pool, index - 1); loadMemoryBarrier(); if (objectClass(t, v) == type(t, Machine::ReferenceType)) { object reference = v; PROTECT(t, reference); v = resolveClassInPool(t, context->method, index - 1, false); if (UNLIKELY(v == 0)) { frame->pushObject (c->call (c->constant (getThunk(t, getJClassFromReferenceThunk), Compiler::AddressType), 0, frame->trace(0, 0), TargetBytesPerWord, Compiler::ObjectType, 2, c->register_(t->arch->thread()), frame->append(makePair(t, context->method, reference)))); } } if (v) { if (objectClass(t, v) == type(t, Machine::ClassType)) { frame->pushObject (c->call (c->constant (getThunk(t, getJClass64Thunk), Compiler::AddressType), 0, frame->trace(0, 0), TargetBytesPerWord, Compiler::ObjectType, 2, c->register_(t->arch->thread()), frame->append(v))); } else { frame->pushObject(frame->append(v)); } } } else { frame->pushInt (c->constant (singletonValue(t, pool, index - 1), singletonBit(t, pool, poolSize(t, pool), index - 1) ? Compiler::FloatType : Compiler::IntegerType)); } } break; case ldc2_w: { uint16_t index = codeReadInt16(t, code, ip); object pool = codePool(t, code); uint64_t v; memcpy(&v, &singletonValue(t, pool, index - 1), 8); frame->pushLong (c->constant (v, singletonBit(t, pool, poolSize(t, pool), index - 1) ? Compiler::FloatType : Compiler::IntegerType)); } break; case ldiv_: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); frame->trace(0, 0); } frame->pushLong(c->binaryOp(lir::Divide, 8, a, b)); } break; case lload: case dload: frame->loadLong(codeBody(t, code, ip++)); break; case lload_0: case dload_0: frame->loadLong(0); break; case lload_1: case dload_1: frame->loadLong(1); break; case lload_2: case dload_2: frame->loadLong(2); break; case lload_3: case dload_3: frame->loadLong(3); break; case lneg: frame->pushLong(c->unaryOp(lir::Negate, 8, frame->popLong())); break; case lookupswitch: { int32_t base = ip - 1; ip = (ip + 3) & ~3; // pad to four byte boundary Compiler::Operand* key = frame->popInt(); uint32_t defaultIp = base + codeReadInt32(t, code, ip); assert(t, defaultIp < codeLength(t, code)); int32_t pairCount = codeReadInt32(t, code, ip); if (pairCount) { Compiler::Operand* default_ = frame->addressOperand (frame->addressPromise(c->machineIp(defaultIp))); avian::codegen::Promise* start = 0; uint32_t* ipTable = static_cast (stack.push(sizeof(uint32_t) * pairCount)); for (int32_t i = 0; i < pairCount; ++i) { unsigned index = ip + (i * 8); int32_t key = codeReadInt32(t, code, index); uint32_t newIp = base + codeReadInt32(t, code, index); assert(t, newIp < codeLength(t, code)); ipTable[i] = newIp; avian::codegen::Promise* p = c->poolAppend(key); if (i == 0) { start = p; } c->poolAppendPromise (frame->addressPromise(c->machineIp(newIp))); } assert(t, start); Compiler::Operand* address = c->call (c->constant(getThunk(t, lookUpAddressThunk), Compiler::AddressType), 0, 0, TargetBytesPerWord, Compiler::AddressType, 4, key, frame->absoluteAddressOperand(start), c->constant(pairCount, Compiler::IntegerType), default_); c->jmp (context->bootContext ? c->binaryOp(lir::Add, TargetBytesPerWord, c->memory (c->register_(t->arch->thread()), Compiler::AddressType, TARGET_THREAD_CODEIMAGE), address) : address); new (stack.push(sizeof(SwitchState))) SwitchState (c->saveState(), pairCount, defaultIp, 0, 0, 0, 0); goto switchloop; } else { // a switch statement with no cases, apparently c->jmp(frame->machineIp(defaultIp)); ip = defaultIp; } } break; case lrem: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); frame->trace(0, 0); } frame->pushLong(c->binaryOp(lir::Remainder, 8, a, b)); } break; case lreturn: case dreturn: { handleExit(t, frame); c->return_(8, frame->popLong()); } goto next; case lshl: case lshr: case lushr: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popLong(); frame->pushLong(c->binaryOp(toCompilerBinaryOp(t, instruction), 8, a, b)); } break; case lstore: case dstore: frame->storeLong(codeBody(t, code, ip++)); break; case lstore_0: case dstore_0: frame->storeLong(0); break; case lstore_1: case dstore_1: frame->storeLong(1); break; case lstore_2: case dstore_2: frame->storeLong(2); break; case lstore_3: case dstore_3: frame->storeLong(3); break; case monitorenter: { Compiler::Operand* target = frame->popObject(); c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), target); } break; case monitorexit: { Compiler::Operand* target = frame->popObject(); c->call (c->constant (getThunk(t, releaseMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), target); } break; case multianewarray: { uint16_t index = codeReadInt16(t, code, ip); uint8_t dimensions = codeBody(t, code, ip++); object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object class_ = resolveClassInPool(t, context->method, index - 1, false); object argument; Thunk thunk; if (LIKELY(class_)) { argument = class_; thunk = makeMultidimensionalArrayThunk; } else { argument = makePair(t, context->method, reference); thunk = makeMultidimensionalArrayFromReferenceThunk; } unsigned offset = localOffset (t, localSize(t, context->method) + c->topOfStack(), context->method) + t->arch->frameReturnAddressSize(); Compiler::Operand* result = c->call (c->constant (getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), TargetBytesPerWord, Compiler::ObjectType, 4, c->register_(t->arch->thread()), frame->append(argument), c->constant(dimensions, Compiler::IntegerType), c->constant(offset, Compiler::IntegerType)); frame->pop(dimensions); frame->pushObject(result); } break; case new_: { uint16_t index = codeReadInt16(t, code, ip); object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object class_ = resolveClassInPool(t, context->method, index - 1, false); object argument; Thunk thunk; if (LIKELY(class_)) { argument = class_; if (classVmFlags(t, class_) & (WeakReferenceFlag | HasFinalizerFlag)) { thunk = makeNewGeneral64Thunk; } else { thunk = makeNew64Thunk; } } else { argument = makePair(t, context->method, reference); thunk = makeNewFromReferenceThunk; } frame->pushObject (c->call (c->constant(getThunk(t, thunk), Compiler::AddressType), 0, frame->trace(0, 0), TargetBytesPerWord, Compiler::ObjectType, 2, c->register_(t->arch->thread()), frame->append(argument))); } break; case newarray: { uint8_t type = codeBody(t, code, ip++); Compiler::Operand* length = frame->popInt(); frame->pushObject (c->call (c->constant(getThunk(t, makeBlankArrayThunk), Compiler::AddressType), 0, frame->trace(0, 0), TargetBytesPerWord, Compiler::ObjectType, 3, c->register_(t->arch->thread()), c->constant(type, Compiler::IntegerType), length)); } break; case nop: break; case pop_: frame->pop(1); break; case pop2: frame->pop(2); break; case putfield: case putstatic: { uint16_t index = codeReadInt16(t, code, ip); object reference = singletonObject (t, codePool(t, methodCode(t, context->method)), index - 1); PROTECT(t, reference); object field = resolveField(t, context->method, index - 1, false); if (LIKELY(field)) { int fieldCode = vm::fieldCode(t, field); object staticTable = 0; if (instruction == putstatic) { checkField(t, field, true); if (classNeedsInit(t, fieldClass(t, field))) { PROTECT(t, field); c->call (c->constant (getThunk(t, tryInitClassThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), frame->append(fieldClass(t, field))); } staticTable = classStaticTable(t, fieldClass(t, field)); } else { checkField(t, field, false); if (inTryBlock(t, code, ip - 3)) { c->saveLocals(); frame->trace(0, 0); } } if (fieldFlags(t, field) & ACC_VOLATILE) { if (TargetBytesPerWord == 4 and (fieldCode == DoubleField or fieldCode == LongField)) { PROTECT(t, field); c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), frame->append(field)); } else { c->nullaryOp(lir::StoreStoreBarrier); } } Compiler::Operand* value = popField(t, frame, fieldCode); Compiler::Operand* table; if (instruction == putstatic) { PROTECT(t, field); table = frame->append(staticTable); } else { table = frame->popObject(); } switch (fieldCode) { case ByteField: case BooleanField: c->store (TargetBytesPerWord, value, 1, c->memory (table, Compiler::IntegerType, targetFieldOffset (context, field), 0, 1)); break; case CharField: case ShortField: c->store (TargetBytesPerWord, value, 2, c->memory (table, Compiler::IntegerType, targetFieldOffset (context, field), 0, 1)); break; case FloatField: c->store (TargetBytesPerWord, value, 4, c->memory (table, Compiler::FloatType, targetFieldOffset (context, field), 0, 1)); break; case IntField: c->store (TargetBytesPerWord, value, 4, c->memory (table, Compiler::IntegerType, targetFieldOffset (context, field), 0, 1)); break; case DoubleField: c->store (8, value, 8, c->memory (table, Compiler::FloatType, targetFieldOffset (context, field), 0, 1)); break; case LongField: c->store (8, value, 8, c->memory (table, Compiler::IntegerType, targetFieldOffset (context, field), 0, 1)); break; case ObjectField: if (instruction == putfield) { c->call (c->constant (getThunk(t, setMaybeNullThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 4, c->register_(t->arch->thread()), table, c->constant(targetFieldOffset(context, field), Compiler::IntegerType), value); } else { c->call (c->constant(getThunk(t, setThunk), Compiler::AddressType), 0, 0, 0, Compiler::VoidType, 4, c->register_(t->arch->thread()), table, c->constant(targetFieldOffset(context, field), Compiler::IntegerType), value); } break; default: abort(t); } if (fieldFlags(t, field) & ACC_VOLATILE) { if (TargetBytesPerWord == 4 and (fieldCode == DoubleField or fieldCode == LongField)) { c->call (c->constant (getThunk(t, releaseMonitorForObjectThunk), Compiler::AddressType), 0, frame->trace(0, 0), 0, Compiler::VoidType, 2, c->register_(t->arch->thread()), frame->append(field)); } else { c->nullaryOp(lir::StoreLoadBarrier); } } } else { int fieldCode = vm::fieldCode (t, byteArrayBody(t, referenceSpec(t, reference), 0)); Compiler::Operand* value = popField(t, frame, fieldCode); unsigned rSize = resultSize(t, fieldCode); Compiler::OperandType rType = operandTypeForFieldCode(t, fieldCode); object pair = makePair(t, context->method, reference); switch (fieldCode) { case ByteField: case BooleanField: case CharField: case ShortField: case FloatField: case IntField: { if (instruction == putstatic) { c->call (c->constant (getThunk(t, setStaticFieldValueFromReferenceThunk), Compiler::AddressType), 0, frame->trace(0, 0), rSize, rType, 3, c->register_(t->arch->thread()), frame->append(pair), value); } else { Compiler::Operand* instance = frame->popObject(); c->call (c->constant (getThunk(t, setFieldValueFromReferenceThunk), Compiler::AddressType), 0, frame->trace(0, 0), rSize, rType, 4, c->register_(t->arch->thread()), frame->append(pair), instance, value); } } break; case DoubleField: case LongField: { if (instruction == putstatic) { c->call (c->constant (getThunk(t, setStaticLongFieldValueFromReferenceThunk), Compiler::AddressType), 0, frame->trace(0, 0), rSize, rType, 4, c->register_(t->arch->thread()), frame->append(pair), static_cast(0), value); } else { Compiler::Operand* instance = frame->popObject(); c->call (c->constant (getThunk(t, setLongFieldValueFromReferenceThunk), Compiler::AddressType), 0, frame->trace(0, 0), rSize, rType, 5, c->register_(t->arch->thread()), frame->append(pair), instance, static_cast(0), value); } } break; case ObjectField: { if (instruction == putstatic) { c->call (c->constant (getThunk(t, setStaticObjectFieldValueFromReferenceThunk), Compiler::AddressType), 0, frame->trace(0, 0), rSize, rType, 3, c->register_(t->arch->thread()), frame->append(pair), value); } else { Compiler::Operand* instance = frame->popObject(); c->call (c->constant (getThunk(t, setObjectFieldValueFromReferenceThunk), Compiler::AddressType), 0, frame->trace(0, 0), rSize, rType, 4, c->register_(t->arch->thread()), frame->append(pair), instance, value); } } break; default: abort(t); } } } break; case ret: { unsigned index = codeBody(t, code, ip); frame->returnFromSubroutine(index); } goto next; case return_: if (needsReturnBarrier(t, context->method)) { c->nullaryOp(lir::StoreStoreBarrier); } handleExit(t, frame); c->return_(0, 0); goto next; case sipush: frame->pushInt (c->constant (static_cast(codeReadInt16(t, code, ip)), Compiler::IntegerType)); break; case swap: frame->swap(); break; case tableswitch: { int32_t base = ip - 1; ip = (ip + 3) & ~3; // pad to four byte boundary uint32_t defaultIp = base + codeReadInt32(t, code, ip); assert(t, defaultIp < codeLength(t, code)); int32_t bottom = codeReadInt32(t, code, ip); int32_t top = codeReadInt32(t, code, ip); avian::codegen::Promise* start = 0; unsigned count = top - bottom + 1; uint32_t* ipTable = static_cast (stack.push(sizeof(uint32_t) * count)); for (int32_t i = 0; i < top - bottom + 1; ++i) { unsigned index = ip + (i * 4); uint32_t newIp = base + codeReadInt32(t, code, index); assert(t, newIp < codeLength(t, code)); ipTable[i] = newIp; avian::codegen::Promise* p = c->poolAppendPromise (frame->addressPromise(c->machineIp(newIp))); if (i == 0) { start = p; } } assert(t, start); Compiler::Operand* key = frame->popInt(); c->condJump(lir::JumpIfLess, 4, c->constant(bottom, Compiler::IntegerType), key, frame->machineIp(defaultIp)); c->save(1, key); new (stack.push(sizeof(SwitchState))) SwitchState (c->saveState(), count, defaultIp, key, start, bottom, top); stack.pushValue(Untable0); ip = defaultIp; } goto start; case wide: { switch (codeBody(t, code, ip++)) { case aload: { frame->loadObject(codeReadInt16(t, code, ip)); } break; case astore: { frame->storeObject(codeReadInt16(t, code, ip)); } break; case iinc: { uint16_t index = codeReadInt16(t, code, ip); int16_t count = codeReadInt16(t, code, ip); storeLocal (context, 1, c->binaryOp(lir::Add, 4, c->constant(count, Compiler::IntegerType), loadLocal(context, 1, index)), index); } break; case iload: { frame->loadInt(codeReadInt16(t, code, ip)); } break; case istore: { frame->storeInt(codeReadInt16(t, code, ip)); } break; case lload: { frame->loadLong(codeReadInt16(t, code, ip)); } break; case lstore: { frame->storeLong(codeReadInt16(t, code, ip)); } break; case ret: { unsigned index = codeReadInt16(t, code, ip); c->jmp(loadLocal(context, 1, index)); frame->returnFromSubroutine(index); } goto next; default: abort(t); } } break; default: abort(t); } } next: frame->dispose(); frame = 0; stack.pop(sizeof(Frame)); stack.pop(stackSize); switch (stack.popValue()) { case Return: return; case Unbranch: ip = stack.popValue(); c->restoreState(reinterpret_cast(stack.popValue())); frame = static_cast(stack.peek(sizeof(Frame))); goto loop; case Untable0: { SwitchState* s = static_cast (stack.peek(sizeof(SwitchState))); frame = s->frame(); c->restoreState(s->state); c->condJump(lir::JumpIfGreater, 4, c->constant(s->top, Compiler::IntegerType), s->key, frame->machineIp(s->defaultIp)); c->save(1, s->key); ip = s->defaultIp; stack.pushValue(Untable1); } goto start; case Untable1: { SwitchState* s = static_cast (stack.peek(sizeof(SwitchState))); frame = s->frame(); c->restoreState(s->state); Compiler::Operand* normalizedKey = (s->bottom ? c->binaryOp(lir::Subtract, 4, c->constant(s->bottom, Compiler::IntegerType), s->key) : s->key); Compiler::Operand* entry = c->memory (frame->absoluteAddressOperand(s->start), Compiler::AddressType, 0, normalizedKey, TargetBytesPerWord); c->jmp (c->load (TargetBytesPerWord, TargetBytesPerWord, context->bootContext ? c->binaryOp(lir::Add, TargetBytesPerWord, c->memory (c->register_(t->arch->thread()), Compiler::AddressType, TARGET_THREAD_CODEIMAGE), entry) : entry, TargetBytesPerWord)); s->state = c->saveState(); } goto switchloop; case Unswitch: { SwitchState* s = static_cast (stack.peek(sizeof(SwitchState))); frame = s->frame(); c->restoreState (static_cast(stack.peek(sizeof(SwitchState)))->state); } goto switchloop; case Unsubroutine: { ip = stack.popValue(); unsigned start = stack.popValue(); frame = reinterpret_cast(stack.peek(sizeof(Frame))); frame->endSubroutine(start); } goto loop; default: abort(t); } switchloop: { SwitchState* s = static_cast (stack.peek(sizeof(SwitchState))); if (s->index < s->count) { ip = s->ipTable()[s->index++]; stack.pushValue(Unswitch); goto start; } else { ip = s->defaultIp; unsigned count = s->count * 4; stack.pop(sizeof(SwitchState)); stack.pop(count); frame = reinterpret_cast(stack.peek(sizeof(Frame))); goto loop; } } branch: stack.pushValue(reinterpret_cast(c->saveState())); stack.pushValue(ip); stack.pushValue(Unbranch); ip = newIp; goto start; } FILE* compileLog = 0; void logCompile(MyThread* t, const void* code, unsigned size, const char* class_, const char* name, const char* spec); int resolveIpForwards(Context* context, int start, int end) { if (start < 0) { start = 0; } while (start < end and context->visitTable[start] == 0) { ++ start; } if (start >= end) { return -1; } else { return start; } } int resolveIpBackwards(Context* context, int start, int end) { Thread* t = context->thread; if (start >= static_cast (codeLength(t, methodCode(t, context->method)))) { start = codeLength(t, methodCode(t, context->method)); } else { while (start >= end and context->visitTable[start] == 0) { -- start; } } if (start < end) { return -1; } else { return start; } } object truncateIntArray(Thread* t, object array, unsigned length) { expect(t, intArrayLength(t, array) > length); PROTECT(t, array); object newArray = makeIntArray(t, length); if (length) { memcpy(&intArrayBody(t, newArray, 0), &intArrayBody(t, array, 0), length * 4); } return newArray; } object truncateArray(Thread* t, object array, unsigned length) { expect(t, arrayLength(t, array) > length); PROTECT(t, array); object newArray = makeArray(t, length); if (length) { memcpy(&arrayBody(t, newArray, 0), &arrayBody(t, array, 0), length * BytesPerWord); } return newArray; } object truncateLineNumberTable(Thread* t, object table, unsigned length) { expect(t, lineNumberTableLength(t, table) > length); PROTECT(t, table); object newTable = makeLineNumberTable(t, length); if (length) { memcpy(&lineNumberTableBody(t, newTable, 0), &lineNumberTableBody(t, table, 0), length * sizeof(uint64_t)); } return newTable; } object translateExceptionHandlerTable(MyThread* t, Context* context, intptr_t start, intptr_t end) { avian::codegen::Compiler* c = context->compiler; object oldTable = codeExceptionHandlerTable (t, methodCode(t, context->method)); if (oldTable) { PROTECT(t, oldTable); unsigned length = exceptionHandlerTableLength(t, oldTable); object newIndex = makeIntArray(t, length * 3); PROTECT(t, newIndex); object newTable = makeArray(t, length + 1); PROTECT(t, newTable); unsigned ni = 0; for (unsigned oi = 0; oi < length; ++ oi) { uint64_t oldHandler = exceptionHandlerTableBody (t, oldTable, oi); int handlerStart = resolveIpForwards (context, exceptionHandlerStart(oldHandler), exceptionHandlerEnd(oldHandler)); if (LIKELY(handlerStart >= 0)) { assert(t, handlerStart < static_cast (codeLength(t, methodCode(t, context->method)))); int handlerEnd = resolveIpBackwards (context, exceptionHandlerEnd(oldHandler), exceptionHandlerStart(oldHandler)); assert(t, handlerEnd >= 0); assert(t, handlerEnd <= static_cast (codeLength(t, methodCode(t, context->method)))); intArrayBody(t, newIndex, ni * 3) = c->machineIp(handlerStart)->value() - start; intArrayBody(t, newIndex, (ni * 3) + 1) = (handlerEnd == static_cast (codeLength(t, methodCode(t, context->method))) ? end : c->machineIp(handlerEnd)->value()) - start; intArrayBody(t, newIndex, (ni * 3) + 2) = c->machineIp(exceptionHandlerIp(oldHandler))->value() - start; object type; if (exceptionHandlerCatchType(oldHandler)) { type = resolveClassInPool (t, context->method, exceptionHandlerCatchType(oldHandler) - 1); } else { type = 0; } set(t, newTable, ArrayBody + ((ni + 1) * BytesPerWord), type); ++ ni; } } if (UNLIKELY(ni < length)) { newIndex = truncateIntArray(t, newIndex, ni * 3); newTable = truncateArray(t, newTable, ni + 1); } set(t, newTable, ArrayBody, newIndex); return newTable; } else { return 0; } } object translateLineNumberTable(MyThread* t, Context* context, intptr_t start) { object oldTable = codeLineNumberTable(t, methodCode(t, context->method)); if (oldTable) { PROTECT(t, oldTable); unsigned length = lineNumberTableLength(t, oldTable); object newTable = makeLineNumberTable(t, length); unsigned ni = 0; for (unsigned oi = 0; oi < length; ++oi) { uint64_t oldLine = lineNumberTableBody(t, oldTable, oi); int ip = resolveIpForwards (context, lineNumberIp(oldLine), oi + 1 < length ? lineNumberIp(lineNumberTableBody(t, oldTable, oi + 1)) - 1 : lineNumberIp(oldLine) + 1); if (LIKELY(ip >= 0)) { lineNumberTableBody(t, newTable, ni++) = lineNumber (context->compiler->machineIp(ip)->value() - start, lineNumberLine(oldLine)); } } if (UNLIKELY(ni < length)) { newTable = truncateLineNumberTable(t, newTable, ni); } return newTable; } else { return 0; } } void printSet(uintptr_t* m, unsigned limit) { if (limit) { for (unsigned i = 0; i < 32; ++i) { if ((*m >> i) & 1) { fprintf(stderr, "1"); } else { fprintf(stderr, "_"); } } } } void calculateTryCatchRoots(Context* context, SubroutinePath* subroutinePath, uintptr_t* roots, unsigned mapSize, unsigned start, unsigned end) { memset(roots, 0xFF, mapSize * BytesPerWord); if (DebugFrameMaps) { fprintf(stderr, "calculate try/catch roots from %d to %d", start, end); if (subroutinePath) { fprintf(stderr, " "); print(subroutinePath); } fprintf(stderr, "\n"); } for (TraceElement* te = context->traceLog; te; te = te->next) { if (te->ip >= start and te->ip < end) { uintptr_t* traceRoots = 0; if (subroutinePath == 0) { traceRoots = te->map; te->watch = true; } else { for (SubroutineTrace* t = te->subroutineTrace; t; t = t->next) { if (t->path == subroutinePath) { traceRoots = t->map; t->watch = true; break; } } } if (traceRoots) { if (DebugFrameMaps) { fprintf(stderr, " use roots at ip %3d: ", te->ip); printSet(traceRoots, mapSize); fprintf(stderr, "\n"); } for (unsigned wi = 0; wi < mapSize; ++wi) { roots[wi] &= traceRoots[wi]; } } else { if (DebugFrameMaps) { fprintf(stderr, " skip roots at ip %3d\n", te->ip); } } } } if (DebugFrameMaps) { fprintf(stderr, "result roots : "); printSet(roots, mapSize); fprintf(stderr, "\n"); } } unsigned calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, unsigned eventIndex, SubroutinePath* subroutinePath = 0, uintptr_t* resultRoots = 0) { // for each instruction with more than one predecessor, and for each // stack position, determine if there exists a path to that // instruction such that there is not an object pointer left at that // stack position (i.e. it is uninitialized or contains primitive // data). unsigned mapSize = frameMapSizeInWords(t, context->method); THREAD_RUNTIME_ARRAY(t, uintptr_t, roots, mapSize); if (originalRoots) { memcpy(RUNTIME_ARRAY_BODY(roots), originalRoots, mapSize * BytesPerWord); } else { memset(RUNTIME_ARRAY_BODY(roots), 0, mapSize * BytesPerWord); } int32_t ip = -1; // invariant: for each stack position, roots contains a zero at that // position if there exists some path to the current instruction // such that there is definitely not an object pointer at that // position. Otherwise, roots contains a one at that position, // meaning either all known paths result in an object pointer at // that position, or the contents of that position are as yet // unknown. unsigned length = context->eventLog.length(); while (eventIndex < length) { Event e = static_cast(context->eventLog.get(eventIndex++)); switch (e) { case PushContextEvent: { eventIndex = calculateFrameMaps (t, context, RUNTIME_ARRAY_BODY(roots), eventIndex, subroutinePath, resultRoots); } break; case PopContextEvent: goto exit; case IpEvent: { ip = context->eventLog.get2(eventIndex); eventIndex += 2; if (DebugFrameMaps) { fprintf(stderr, " roots at ip %3d: ", ip); printSet(RUNTIME_ARRAY_BODY(roots), mapSize); fprintf(stderr, "\n"); } uintptr_t* tableRoots = (subroutinePath ? subroutinePath->rootTable : context->rootTable) + (ip * mapSize); if (context->visitTable[ip] > 1) { for (unsigned wi = 0; wi < mapSize; ++wi) { uintptr_t newRoots = tableRoots[wi] & RUNTIME_ARRAY_BODY(roots)[wi]; if ((eventIndex == length or context->eventLog.get(eventIndex) == PopContextEvent) and newRoots != tableRoots[wi]) { if (DebugFrameMaps) { fprintf(stderr, "dirty roots!\n"); } context->dirtyRoots = true; } tableRoots[wi] = newRoots; RUNTIME_ARRAY_BODY(roots)[wi] &= tableRoots[wi]; } if (DebugFrameMaps) { fprintf(stderr, " table roots at ip %3d: ", ip); printSet(tableRoots, mapSize); fprintf(stderr, "\n"); } } else { memcpy(tableRoots, RUNTIME_ARRAY_BODY(roots), mapSize * BytesPerWord); } } break; case MarkEvent: { unsigned i = context->eventLog.get2(eventIndex); eventIndex += 2; markBit(RUNTIME_ARRAY_BODY(roots), i); } break; case ClearEvent: { unsigned i = context->eventLog.get2(eventIndex); eventIndex += 2; clearBit(RUNTIME_ARRAY_BODY(roots), i); } break; case PushExceptionHandlerEvent: { unsigned start = context->eventLog.get2(eventIndex); eventIndex += 2; unsigned end = context->eventLog.get2(eventIndex); eventIndex += 2; if (context->subroutineTable and context->subroutineTable[start]) { Subroutine* s = context->subroutineTable[start]; unsigned originalEventIndex = eventIndex; for (SubroutineCall* c = s->calls; c; c = c->next) { for (SubroutinePath* p = c->paths; p; p = p->listNext) { calculateTryCatchRoots (context, p, RUNTIME_ARRAY_BODY(roots), mapSize, start, end); eventIndex = calculateFrameMaps (t, context, RUNTIME_ARRAY_BODY(roots), originalEventIndex, p); } } } else { calculateTryCatchRoots (context, 0, RUNTIME_ARRAY_BODY(roots), mapSize, start, end); eventIndex = calculateFrameMaps (t, context, RUNTIME_ARRAY_BODY(roots), eventIndex, 0); } } break; case TraceEvent: { TraceElement* te; context->eventLog.get(eventIndex, &te, BytesPerWord); if (DebugFrameMaps) { fprintf(stderr, " trace roots at ip %3d: ", ip); printSet(RUNTIME_ARRAY_BODY(roots), mapSize); if (subroutinePath) { fprintf(stderr, " "); print(subroutinePath); } fprintf(stderr, "\n"); } uintptr_t* map; bool watch; if (subroutinePath == 0) { map = te->map; watch = te->watch; } else { SubroutineTrace* trace = 0; for (SubroutineTrace* t = te->subroutineTrace; t; t = t->next) { if (t->path == subroutinePath) { trace = t; break; } } if (trace == 0) { te->subroutineTrace = trace = new (context->zone.allocate (sizeof(SubroutineTrace) + (mapSize * BytesPerWord))) SubroutineTrace(subroutinePath, te->subroutineTrace, mapSize); ++ te->subroutineTraceCount; } map = trace->map; watch = trace->watch; } for (unsigned wi = 0; wi < mapSize; ++wi) { uintptr_t v = RUNTIME_ARRAY_BODY(roots)[wi]; if (watch and map[wi] != v) { if (DebugFrameMaps) { fprintf(stderr, "dirty roots due to trace watch!\n"); } context->dirtyRoots = true; } map[wi] = v; } eventIndex += BytesPerWord; } break; case PushSubroutineEvent: { SubroutineCall* call; context->eventLog.get(eventIndex, &call, BytesPerWord); eventIndex += BytesPerWord; unsigned nextIndex = context->eventLog.get2(eventIndex); eventIndex = nextIndex; SubroutinePath* path = 0; for (SubroutinePath* p = call->paths; p; p = p->listNext) { if (p->stackNext == subroutinePath) { path = p; break; } } if (path == 0) { path = new(&context->zone) SubroutinePath(call, subroutinePath, makeRootTable(t, &(context->zone), context->method)); } THREAD_RUNTIME_ARRAY(t, uintptr_t, subroutineRoots, mapSize); calculateFrameMaps (t, context, RUNTIME_ARRAY_BODY(roots), call->subroutine->logIndex, path, RUNTIME_ARRAY_BODY(subroutineRoots)); for (unsigned wi = 0; wi < mapSize; ++wi) { RUNTIME_ARRAY_BODY(roots)[wi] &= RUNTIME_ARRAY_BODY(subroutineRoots)[wi]; } } break; case PopSubroutineEvent: eventIndex = static_cast(-1); goto exit; default: abort(t); } } exit: if (resultRoots and ip != -1) { if (DebugFrameMaps) { fprintf(stderr, "result roots at ip %3d: ", ip); printSet(RUNTIME_ARRAY_BODY(roots), mapSize); if (subroutinePath) { fprintf(stderr, " "); print(subroutinePath); } fprintf(stderr, "\n"); } memcpy(resultRoots, RUNTIME_ARRAY_BODY(roots), mapSize * BytesPerWord); } return eventIndex; } int compareTraceElementPointers(const void* va, const void* vb) { TraceElement* a = *static_cast(va); TraceElement* b = *static_cast(vb); if (a->address->value() > b->address->value()) { return 1; } else if (a->address->value() < b->address->value()) { return -1; } else { return 0; } } unsigned simpleFrameMapTableSize(MyThread* t, object method, object map) { int size = frameMapSizeInBits(t, method); return ceilingDivide(intArrayLength(t, map) * size, 32 + size); } uint8_t* finish(MyThread* t, FixedAllocator* allocator, avian::codegen::Assembler* a, const char* name, unsigned length) { uint8_t* start = static_cast (allocator->allocate(length, TargetBytesPerWord)); a->setDestination(start); a->write(); logCompile(t, start, length, 0, name, 0); return start; } void setBit(int32_t* dst, unsigned index) { dst[index / 32] |= static_cast(1) << (index % 32); } void clearBit(int32_t* dst, unsigned index) { dst[index / 32] &= ~(static_cast(1) << (index % 32)); } void copyFrameMap(int32_t* dst, uintptr_t* src, unsigned mapSizeInBits, unsigned offset, TraceElement* p, SubroutinePath* subroutinePath) { if (DebugFrameMaps) { fprintf(stderr, " orig roots at ip %3d: ", p->ip); printSet(src, ceilingDivide(mapSizeInBits, BitsPerWord)); print(subroutinePath); fprintf(stderr, "\n"); fprintf(stderr, " final roots at ip %3d: ", p->ip); } for (unsigned j = 0; j < p->argumentIndex; ++j) { if (getBit(src, j)) { if (DebugFrameMaps) { fprintf(stderr, "1"); } setBit(dst, offset + j); } else { if (DebugFrameMaps) { fprintf(stderr, "_"); } clearBit(dst, offset + j); } } if (DebugFrameMaps) { print(subroutinePath); fprintf(stderr, "\n"); } } class FrameMapTableHeader { public: FrameMapTableHeader(unsigned indexCount): indexCount(indexCount) { } unsigned indexCount; }; class FrameMapTableIndexElement { public: FrameMapTableIndexElement(int offset, unsigned base, unsigned path): offset(offset), base(base), path(path) { } int offset; unsigned base; unsigned path; }; class FrameMapTablePath { public: FrameMapTablePath(unsigned stackIndex, unsigned elementCount, unsigned next): stackIndex(stackIndex), elementCount(elementCount), next(next) { } unsigned stackIndex; unsigned elementCount; unsigned next; int32_t elements[0]; }; int compareInt32s(const void* va, const void* vb) { return *static_cast(va) - *static_cast(vb); } int compare(SubroutinePath* a, SubroutinePath* b) { if (a->stackNext) { int d = compare(a->stackNext, b->stackNext); if (d) return d; } int64_t av = a->call->returnAddress->value(); int64_t bv = b->call->returnAddress->value(); if (av > bv) { return 1; } else if (av < bv) { return -1; } else { return 0; } } int compareSubroutineTracePointers(const void* va, const void* vb) { return compare((*static_cast(va))->path, (*static_cast(vb))->path); } object makeGeneralFrameMapTable(MyThread* t, Context* context, uint8_t* start, TraceElement** elements, unsigned elementCount, unsigned pathFootprint, unsigned mapCount) { unsigned mapSize = frameMapSizeInBits(t, context->method); unsigned indexOffset = sizeof(FrameMapTableHeader); unsigned mapsOffset = indexOffset + (elementCount * sizeof(FrameMapTableIndexElement)); unsigned pathsOffset = mapsOffset + (ceilingDivide(mapCount * mapSize, 32) * 4); object table = makeByteArray(t, pathsOffset + pathFootprint); int8_t* body = &byteArrayBody(t, table, 0); new (body) FrameMapTableHeader(elementCount); unsigned nextTableIndex = pathsOffset; unsigned nextMapIndex = 0; for (unsigned i = 0; i < elementCount; ++i) { TraceElement* p = elements[i]; unsigned mapBase = nextMapIndex; unsigned pathIndex; if (p->subroutineTrace) { FrameMapTablePath* previous = 0; Subroutine* subroutine = p->subroutineTrace->path->call->subroutine; for (Subroutine* s = subroutine; s; s = s->stackNext) { if (s->tableIndex == 0) { unsigned pathObjectSize = sizeof(FrameMapTablePath) + (sizeof(int32_t) * s->callCount); assert(t, nextTableIndex + pathObjectSize <= byteArrayLength(t, table)); s->tableIndex = nextTableIndex; nextTableIndex += pathObjectSize; FrameMapTablePath* current = new (body + s->tableIndex) FrameMapTablePath (s->stackIndex, s->callCount, s->stackNext ? s->stackNext->tableIndex : 0); unsigned i = 0; for (SubroutineCall* c = subroutine->calls; c; c = c->next) { assert(t, i < s->callCount); current->elements[i++] = static_cast(c->returnAddress->value()) - reinterpret_cast(start); } assert(t, i == s->callCount); qsort(current->elements, s->callCount, sizeof(int32_t), compareInt32s); if (previous) { previous->next = s->tableIndex; } previous = current; } else { break; } } pathIndex = subroutine->tableIndex; THREAD_RUNTIME_ARRAY (t, SubroutineTrace*, traces, p->subroutineTraceCount); unsigned i = 0; for (SubroutineTrace* trace = p->subroutineTrace; trace; trace = trace->next) { assert(t, i < p->subroutineTraceCount); RUNTIME_ARRAY_BODY(traces)[i++] = trace; } assert(t, i == p->subroutineTraceCount); qsort(RUNTIME_ARRAY_BODY(traces), p->subroutineTraceCount, sizeof(SubroutineTrace*), compareSubroutineTracePointers); for (unsigned i = 0; i < p->subroutineTraceCount; ++i) { assert(t, mapsOffset + ceilingDivide(nextMapIndex + mapSize, 32) * 4 <= pathsOffset); copyFrameMap(reinterpret_cast(body + mapsOffset), RUNTIME_ARRAY_BODY(traces)[i]->map, mapSize, nextMapIndex, p, RUNTIME_ARRAY_BODY(traces)[i]->path); nextMapIndex += mapSize; } } else { pathIndex = 0; assert(t, mapsOffset + ceilingDivide(nextMapIndex + mapSize, 32) * 4 <= pathsOffset); copyFrameMap(reinterpret_cast(body + mapsOffset), p->map, mapSize, nextMapIndex, p, 0); nextMapIndex += mapSize; } unsigned elementIndex = indexOffset + (i * sizeof(FrameMapTableIndexElement)); assert(t, elementIndex + sizeof(FrameMapTableIndexElement) <= mapsOffset); new (body + elementIndex) FrameMapTableIndexElement (static_cast(p->address->value()) - reinterpret_cast(start), mapBase, pathIndex); } assert(t, nextMapIndex == mapCount * mapSize); return table; } object makeSimpleFrameMapTable(MyThread* t, Context* context, uint8_t* start, TraceElement** elements, unsigned elementCount) { unsigned mapSize = frameMapSizeInBits(t, context->method); object table = makeIntArray (t, elementCount + ceilingDivide(elementCount * mapSize, 32)); assert(t, intArrayLength(t, table) == elementCount + simpleFrameMapTableSize(t, context->method, table)); for (unsigned i = 0; i < elementCount; ++i) { TraceElement* p = elements[i]; intArrayBody(t, table, i) = static_cast(p->address->value()) - reinterpret_cast(start); assert(t, elementCount + ceilingDivide((i + 1) * mapSize, 32) <= intArrayLength(t, table)); if (mapSize) { copyFrameMap(&intArrayBody(t, table, elementCount), p->map, mapSize, i * mapSize, p, 0); } } return table; } void finish(MyThread* t, FixedAllocator* allocator, Context* context) { avian::codegen::Compiler* c = context->compiler; if (false) { logCompile (t, 0, 0, reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)), reinterpret_cast (&byteArrayBody(t, methodName(t, context->method), 0)), reinterpret_cast (&byteArrayBody(t, methodSpec(t, context->method), 0))); } // for debugging: if (false and ::strcmp (reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)), "java/lang/System") == 0 and ::strcmp (reinterpret_cast (&byteArrayBody(t, methodName(t, context->method), 0)), "") == 0) { trap(); } // todo: this is a CPU-intensive operation, so consider doing it // earlier before we've acquired the global class lock to improve // parallelism (the downside being that it may end up being a waste // of cycles if another thread compiles the same method in parallel, // which might be mitigated by fine-grained, per-method locking): c->compile(context->leaf ? 0 : stackOverflowThunk(t), TARGET_THREAD_STACKLIMIT); // we must acquire the class lock here at the latest unsigned codeSize = c->resolve(allocator->memory.begin() + allocator->offset); unsigned total = pad(codeSize, TargetBytesPerWord) + pad(c->poolSize(), TargetBytesPerWord); target_uintptr_t* code = static_cast (allocator->allocate(total, TargetBytesPerWord)); uint8_t* start = reinterpret_cast(code); context->executableAllocator = allocator; context->executableStart = code; context->executableSize = total; if (context->objectPool) { object pool = allocate3 (t, allocator, Machine::ImmortalAllocation, FixedSizeOfArray + ((context->objectPoolCount + 1) * BytesPerWord), true); context->executableSize = (allocator->memory.begin() + allocator->offset) - static_cast(context->executableStart); initArray(t, pool, context->objectPoolCount + 1); mark(t, pool, 0); set(t, pool, ArrayBody, root(t, ObjectPools)); setRoot(t, ObjectPools, pool); unsigned i = 1; for (PoolElement* p = context->objectPool; p; p = p->next) { unsigned offset = ArrayBody + ((i++) * BytesPerWord); p->address = reinterpret_cast(pool) + offset; set(t, pool, offset, p->target); } } c->write(); BootContext* bc = context->bootContext; if (bc) { for (avian::codegen::DelayedPromise* p = bc->addresses; p != bc->addressSentinal; p = p->next) { p->basis = new(bc->zone) avian::codegen::ResolvedPromise(p->basis->value()); } } { object newExceptionHandlerTable = translateExceptionHandlerTable (t, context, reinterpret_cast(start), reinterpret_cast(start) + codeSize); PROTECT(t, newExceptionHandlerTable); object newLineNumberTable = translateLineNumberTable (t, context, reinterpret_cast(start)); object code = methodCode(t, context->method); code = makeCode (t, 0, newExceptionHandlerTable, newLineNumberTable, reinterpret_cast(start), codeSize, codeMaxStack(t, code), codeMaxLocals(t, code), 0); set(t, context->method, MethodCode, code); } if (context->traceLogCount) { THREAD_RUNTIME_ARRAY(t, TraceElement*, elements, context->traceLogCount); unsigned index = 0; unsigned pathFootprint = 0; unsigned mapCount = 0; for (TraceElement* p = context->traceLog; p; p = p->next) { assert(t, index < context->traceLogCount); if (p->address) { SubroutineTrace* trace = p->subroutineTrace; unsigned myMapCount = 1; if (trace) { for (Subroutine* s = trace->path->call->subroutine; s; s = s->stackNext) { unsigned callCount = s->callCount; myMapCount *= callCount; if (not s->visited) { s->visited = true; pathFootprint += sizeof(FrameMapTablePath) + (sizeof(int32_t) * callCount); } } } mapCount += myMapCount; RUNTIME_ARRAY_BODY(elements)[index++] = p; if (p->target) { insertCallNode (t, makeCallNode (t, p->address->value(), p->target, p->flags, 0)); } } } qsort(RUNTIME_ARRAY_BODY(elements), index, sizeof(TraceElement*), compareTraceElementPointers); object map; if (pathFootprint) { map = makeGeneralFrameMapTable (t, context, start, RUNTIME_ARRAY_BODY(elements), index, pathFootprint, mapCount); } else { map = makeSimpleFrameMapTable (t, context, start, RUNTIME_ARRAY_BODY(elements), index); } set(t, methodCode(t, context->method), CodePool, map); } logCompile (t, start, codeSize, reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)), reinterpret_cast (&byteArrayBody(t, methodName(t, context->method), 0)), reinterpret_cast (&byteArrayBody(t, methodSpec(t, context->method), 0))); // for debugging: if (false and ::strcmp (reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)), "java/lang/System") == 0 and ::strcmp (reinterpret_cast (&byteArrayBody(t, methodName(t, context->method), 0)), "") == 0) { trap(); } #if !defined(AVIAN_AOT_ONLY) syncInstructionCache(start, codeSize); #endif } void compile(MyThread* t, Context* context) { avian::codegen::Compiler* c = context->compiler; // fprintf(stderr, "compiling %s.%s%s\n", // &byteArrayBody(t, className(t, methodClass(t, context->method)), 0), // &byteArrayBody(t, methodName(t, context->method), 0), // &byteArrayBody(t, methodSpec(t, context->method), 0)); unsigned footprint = methodParameterFootprint(t, context->method); unsigned locals = localSize(t, context->method); c->init(codeLength(t, methodCode(t, context->method)), footprint, locals, alignedFrameSize(t, context->method)); THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap, codeMaxStack(t, methodCode(t, context->method))); Frame frame(context, RUNTIME_ARRAY_BODY(stackMap)); unsigned index = methodParameterFootprint(t, context->method); if ((methodFlags(t, context->method) & ACC_STATIC) == 0) { frame.set(--index, Frame::Object); c->initLocal(1, index, Compiler::ObjectType); } for (MethodSpecIterator it (t, reinterpret_cast (&byteArrayBody(t, methodSpec(t, context->method), 0))); it.hasNext();) { switch (*it.next()) { case 'L': case '[': frame.set(--index, Frame::Object); c->initLocal(1, index, Compiler::ObjectType); break; case 'J': frame.set(--index, Frame::Long); frame.set(--index, Frame::Long); c->initLocal(2, index, Compiler::IntegerType); break; case 'D': frame.set(--index, Frame::Long); frame.set(--index, Frame::Long); c->initLocal(2, index, Compiler::FloatType); break; case 'F': frame.set(--index, Frame::Integer); c->initLocal(1, index, Compiler::FloatType); break; default: frame.set(--index, Frame::Integer); c->initLocal(1, index, Compiler::IntegerType); break; } } handleEntrance(t, &frame); Compiler::State* state = c->saveState(); compile(t, &frame, 0); context->dirtyRoots = false; unsigned eventIndex = calculateFrameMaps(t, context, 0, 0); object eht = codeExceptionHandlerTable(t, methodCode(t, context->method)); if (eht) { PROTECT(t, eht); unsigned visitCount = exceptionHandlerTableLength(t, eht); THREAD_RUNTIME_ARRAY(t, bool, visited, visitCount); memset(RUNTIME_ARRAY_BODY(visited), 0, visitCount * sizeof(bool)); bool progress = true; while (progress) { progress = false; for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) { uint64_t eh = exceptionHandlerTableBody(t, eht, i); int start = resolveIpForwards (context, exceptionHandlerStart(eh), exceptionHandlerEnd(eh)); if ((not RUNTIME_ARRAY_BODY(visited)[i]) and start >= 0 and context->visitTable[start]) { RUNTIME_ARRAY_BODY(visited)[i] = true; progress = true; c->restoreState(state); THREAD_RUNTIME_ARRAY (t, uint8_t, stackMap, codeMaxStack(t, methodCode(t, context->method))); Frame frame2(&frame, RUNTIME_ARRAY_BODY(stackMap)); unsigned end = exceptionHandlerEnd(eh); if (exceptionHandlerIp(eh) >= static_cast(start) and exceptionHandlerIp(eh) < end) { end = exceptionHandlerIp(eh); } context->eventLog.append(PushExceptionHandlerEvent); context->eventLog.append2(start); context->eventLog.append2(end); for (unsigned i = 1; i < codeMaxStack(t, methodCode(t, context->method)); ++i) { frame2.set(localSize(t, context->method) + i, Frame::Integer); } compile(t, &frame2, exceptionHandlerIp(eh), start); context->eventLog.append(PopContextEvent); eventIndex = calculateFrameMaps(t, context, 0, eventIndex); } } } } while (context->dirtyRoots) { context->dirtyRoots = false; calculateFrameMaps(t, context, 0, 0); } } void updateCall(MyThread* t, avian::codegen::lir::UnaryOperation op, void* returnAddress, void* target) { t->arch->updateCall(op, returnAddress, target); } void* compileMethod2(MyThread* t, void* ip); uint64_t compileMethod(MyThread* t) { void* ip; if (t->tailAddress) { ip = t->tailAddress; t->tailAddress = 0; } else { ip = getIp(t); } return reinterpret_cast(compileMethod2(t, ip)); } void* compileVirtualMethod2(MyThread* t, object class_, unsigned index) { // If class_ has BootstrapFlag set, that means its vtable is not yet // available. However, we must set t->trace->targetMethod to an // appropriate method to ensure we can accurately scan the stack for // GC roots. We find such a method by looking for a superclass with // a vtable and using it instead: object c = class_; while (classVmFlags(t, c) & BootstrapFlag) { c = classSuper(t, c); } t->trace->targetMethod = arrayBody(t, classVirtualTable(t, c), index); THREAD_RESOURCE0(t, static_cast(t)->trace->targetMethod = 0;); PROTECT(t, class_); object target = resolveTarget(t, class_, index); PROTECT(t, target); compile(t, codeAllocator(t), 0, target); void* address = reinterpret_cast(methodAddress(t, target)); if (methodFlags(t, target) & ACC_NATIVE) { t->trace->nativeMethod = target; } else { classVtable(t, class_, methodOffset(t, target)) = address; } return address; } uint64_t compileVirtualMethod(MyThread* t) { object class_ = objectClass(t, static_cast(t->virtualCallTarget)); t->virtualCallTarget = 0; unsigned index = t->virtualCallIndex; t->virtualCallIndex = 0; return reinterpret_cast(compileVirtualMethod2(t, class_, index)); } uint64_t invokeNativeFast(MyThread* t, object method, void* function) { FastNativeFunction f; memcpy(&f, &function, sizeof(void*)); return f(t, method, static_cast(t->stack) + t->arch->frameFooterSize() + t->arch->frameReturnAddressSize()); } uint64_t invokeNativeSlow(MyThread* t, object method, void* function) { PROTECT(t, method); unsigned footprint = methodParameterFootprint(t, method) + 1; if (methodFlags(t, method) & ACC_STATIC) { ++ footprint; } unsigned count = methodParameterCount(t, method) + 2; THREAD_RUNTIME_ARRAY(t, uintptr_t, args, footprint); unsigned argOffset = 0; THREAD_RUNTIME_ARRAY(t, uint8_t, types, count); unsigned typeOffset = 0; RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(t); RUNTIME_ARRAY_BODY(types)[typeOffset++] = POINTER_TYPE; uintptr_t* sp = static_cast(t->stack) + t->arch->frameFooterSize() + t->arch->frameReturnAddressSize(); object jclass = 0; PROTECT(t, jclass); if (methodFlags(t, method) & ACC_STATIC) { jclass = getJClass(t, methodClass(t, method)); RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(&jclass); } else { RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(sp++); } RUNTIME_ARRAY_BODY(types)[typeOffset++] = POINTER_TYPE; MethodSpecIterator it (t, reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), 0))); while (it.hasNext()) { unsigned type = RUNTIME_ARRAY_BODY(types)[typeOffset++] = fieldType(t, fieldCode(t, *it.next())); switch (type) { case INT8_TYPE: case INT16_TYPE: case INT32_TYPE: case FLOAT_TYPE: RUNTIME_ARRAY_BODY(args)[argOffset++] = *(sp++); break; case INT64_TYPE: case DOUBLE_TYPE: { memcpy(RUNTIME_ARRAY_BODY(args) + argOffset, sp, 8); argOffset += (8 / BytesPerWord); sp += 2; } break; case POINTER_TYPE: { if (*sp) { RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(sp); } else { RUNTIME_ARRAY_BODY(args)[argOffset++] = 0; } ++ sp; } break; default: abort(t); } } unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); uint64_t result; if (DebugNatives) { fprintf(stderr, "invoke native method %s.%s\n", &byteArrayBody(t, className(t, methodClass(t, method)), 0), &byteArrayBody(t, methodName(t, method), 0)); } if (methodFlags(t, method) & ACC_SYNCHRONIZED) { if (methodFlags(t, method) & ACC_STATIC) { acquire(t, methodClass(t, method)); } else { acquire(t, *reinterpret_cast(RUNTIME_ARRAY_BODY(args)[1])); } } Reference* reference = t->reference; { ENTER(t, Thread::IdleState); bool noThrow = t->checkpoint->noThrow; t->checkpoint->noThrow = true; THREAD_RESOURCE(t, bool, noThrow, t->checkpoint->noThrow = noThrow); result = vm::dynamicCall(function, RUNTIME_ARRAY_BODY(args), RUNTIME_ARRAY_BODY(types), count, footprint * BytesPerWord, returnType); } if (methodFlags(t, method) & ACC_SYNCHRONIZED) { if (methodFlags(t, method) & ACC_STATIC) { release(t, methodClass(t, method)); } else { release(t, *reinterpret_cast(RUNTIME_ARRAY_BODY(args)[1])); } } if (DebugNatives) { fprintf(stderr, "return from native method %s.%s\n", &byteArrayBody(t, className(t, methodClass(t, method)), 0), &byteArrayBody(t, methodName(t, method), 0)); } if (UNLIKELY(t->exception)) { object exception = t->exception; t->exception = 0; vm::throw_(t, exception); } switch (returnCode) { case ByteField: case BooleanField: result = static_cast(result); break; case CharField: result = static_cast(result); break; case ShortField: result = static_cast(result); break; case FloatField: case IntField: result = static_cast(result); break; case LongField: case DoubleField: break; case ObjectField: result = static_cast(result) ? *reinterpret_cast (static_cast(result)) : 0; break; case VoidField: result = 0; break; default: abort(t); } while (t->reference != reference) { dispose(t, t->reference); } return result; } uint64_t invokeNative2(MyThread* t, object method) { object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method)); if (nativeFast(t, native)) { return invokeNativeFast(t, method, nativeFunction(t, native)); } else { return invokeNativeSlow(t, method, nativeFunction(t, native)); } } uint64_t invokeNative(MyThread* t) { if (t->trace->nativeMethod == 0) { void* ip; if (t->tailAddress) { ip = t->tailAddress; t->tailAddress = 0; } else { ip = getIp(t); } object node = findCallNode(t, ip); object target = callNodeTarget(t, node); if (callNodeFlags(t, node) & TraceElement::VirtualCall) { target = resolveTarget(t, t->stack, target); } t->trace->nativeMethod = target; } assert(t, t->tailAddress == 0); uint64_t result = 0; t->trace->targetMethod = t->trace->nativeMethod; t->m->classpath->resolveNative(t, t->trace->nativeMethod); result = invokeNative2(t, t->trace->nativeMethod); unsigned parameterFootprint = methodParameterFootprint (t, t->trace->targetMethod); uintptr_t* stack = static_cast(t->stack); if (avian::codegen::TailCalls and t->arch->argumentFootprint(parameterFootprint) > t->arch->stackAlignmentInWords()) { stack += t->arch->argumentFootprint(parameterFootprint) - t->arch->stackAlignmentInWords(); } stack += t->arch->frameReturnAddressSize(); t->trace->targetMethod = 0; t->trace->nativeMethod = 0; t->newStack = stack; return result; } void findFrameMapInSimpleTable(MyThread* t, object method, object table, int32_t offset, int32_t** map, unsigned* start) { unsigned tableSize = simpleFrameMapTableSize(t, method, table); unsigned indexSize = intArrayLength(t, table) - tableSize; *map = &intArrayBody(t, table, indexSize); unsigned bottom = 0; unsigned top = indexSize; for (unsigned span = top - bottom; span; span = top - bottom) { unsigned middle = bottom + (span / 2); int32_t v = intArrayBody(t, table, middle); if (offset == v) { *start = frameMapSizeInBits(t, method) * middle; return; } else if (offset < v) { top = middle; } else { bottom = middle + 1; } } abort(t); } unsigned findFrameMap(MyThread* t, void* stack, object method, object table, unsigned pathIndex) { if (pathIndex) { FrameMapTablePath* path = reinterpret_cast (&byteArrayBody(t, table, pathIndex)); void* address = static_cast(stack)[path->stackIndex]; uint8_t* base = reinterpret_cast(methodAddress(t, method)); for (unsigned i = 0; i < path->elementCount; ++i) { if (address == base + path->elements[i]) { return i + (path->elementCount * findFrameMap (t, stack, method, table, path->next)); } } abort(t); } else { return 0; } } void findFrameMapInGeneralTable(MyThread* t, void* stack, object method, object table, int32_t offset, int32_t** map, unsigned* start) { FrameMapTableHeader* header = reinterpret_cast (&byteArrayBody(t, table, 0)); FrameMapTableIndexElement* index = reinterpret_cast (&byteArrayBody(t, table, sizeof(FrameMapTableHeader))); *map = reinterpret_cast(index + header->indexCount); unsigned bottom = 0; unsigned top = header->indexCount; for (unsigned span = top - bottom; span; span = top - bottom) { unsigned middle = bottom + (span / 2); FrameMapTableIndexElement* v = index + middle; if (offset == v->offset) { *start = v->base + (findFrameMap(t, stack, method, table, v->path) * frameMapSizeInBits(t, method)); return; } else if (offset < v->offset) { top = middle; } else { bottom = middle + 1; } } abort(t); } void findFrameMap(MyThread* t, void* stack, object method, int32_t offset, int32_t** map, unsigned* start) { object table = codePool(t, methodCode(t, method)); if (objectClass(t, table) == type(t, Machine::IntArrayType)) { findFrameMapInSimpleTable(t, method, table, offset, map, start); } else { findFrameMapInGeneralTable(t, stack, method, table, offset, map, start); } } void visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* frame, object method, void* ip) { unsigned count = frameMapSizeInBits(t, method); if (count) { void* stack = stackForFrame(t, frame, method); int32_t* map; unsigned offset; findFrameMap (t, stack, method, difference (ip, reinterpret_cast(methodAddress(t, method))), &map, &offset); for (unsigned i = 0; i < count; ++i) { int j = offset + i; if (map[j / 32] & (static_cast(1) << (j % 32))) { v->visit(localObject(t, stack, method, i)); } } } } void visitArgument(MyThread* t, Heap::Visitor* v, void* stack, unsigned index) { v->visit(static_cast(stack) + index + t->arch->frameReturnAddressSize() + t->arch->frameFooterSize()); } void visitArguments(MyThread* t, Heap::Visitor* v, void* stack, object method) { unsigned index = 0; if ((methodFlags(t, method) & ACC_STATIC) == 0) { visitArgument(t, v, stack, index++); } for (MethodSpecIterator it (t, reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), 0))); it.hasNext();) { switch (*it.next()) { case 'L': case '[': visitArgument(t, v, stack, index++); break; case 'J': case 'D': index += 2; break; default: ++ index; break; } } } void visitStack(MyThread* t, Heap::Visitor* v) { void* ip = getIp(t); void* stack = t->stack; MyThread::CallTrace* trace = t->trace; object targetMethod = (trace ? trace->targetMethod : 0); object target = targetMethod; bool mostRecent = true; while (stack) { if (targetMethod) { visitArguments(t, v, stack, targetMethod); targetMethod = 0; } object method = methodForIp(t, ip); if (method) { PROTECT(t, method); void* nextIp = ip; nextFrame(t, &nextIp, &stack, method, target, mostRecent); visitStackAndLocals(t, v, stack, method, ip); ip = nextIp; target = method; } else if (trace) { stack = trace->stack; ip = trace->ip; trace = trace->next; if (trace) { targetMethod = trace->targetMethod; target = targetMethod; } else { target = 0; } } else { break; } mostRecent = false; } } void walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start) { const int BodyOffset = ContinuationBody / BytesPerWord; object method = static_cast (t->m->heap->follow(continuationMethod(t, c))); int count = frameMapSizeInBits(t, method); if (count) { int stack = BodyOffset + (continuationFramePointerOffset(t, c) / BytesPerWord) - t->arch->framePointerOffset() - stackOffsetFromFrame(t, method); int first = stack + localOffsetFromStack(t, count - 1, method); if (start > first) { count -= start - first; } int32_t* map; unsigned offset; findFrameMap (t, reinterpret_cast(c) + stack, method, difference (continuationAddress(t, c), reinterpret_cast(methodAddress(t, method))), &map, &offset); for (int i = count - 1; i >= 0; --i) { int j = offset + i; if (map[j / 32] & (static_cast(1) << (j % 32))) { if (not w->visit(stack + localOffsetFromStack(t, i, method))) { return; } } } } } void callContinuation(MyThread* t, object continuation, object result, object exception, void* ip, void* stack) { assert(t, t->exception == 0); if (exception) { t->exception = exception; MyThread::TraceContext c(t, ip, stack, continuation, t->trace); void* frame; findUnwindTarget(t, &ip, &frame, &stack, &continuation); } t->trace->nativeMethod = 0; t->trace->targetMethod = 0; popResources(t); transition(t, ip, stack, continuation, t->trace); vmJump(ip, 0, stack, t, reinterpret_cast(result), 0); } int8_t* returnSpec(MyThread* t, object method) { int8_t* s = &byteArrayBody(t, methodSpec(t, method), 0); while (*s and *s != ')') ++ s; expect(t, *s == ')'); return s + 1; } object returnClass(MyThread* t, object method) { PROTECT(t, method); int8_t* spec = returnSpec(t, method); unsigned length = strlen(reinterpret_cast(spec)); object name; if (*spec == '[') { name = makeByteArray(t, length + 1); memcpy(&byteArrayBody(t, name, 0), spec, length); } else { assert(t, *spec == 'L'); assert(t, spec[length - 1] == ';'); name = makeByteArray(t, length - 1); memcpy(&byteArrayBody(t, name, 0), spec + 1, length - 2); } return resolveClass(t, classLoader(t, methodClass(t, method)), name); } bool compatibleReturnType(MyThread* t, object oldMethod, object newMethod) { if (oldMethod == newMethod) { return true; } else if (methodReturnCode(t, oldMethod) == methodReturnCode(t, newMethod)) { if (methodReturnCode(t, oldMethod) == ObjectField) { PROTECT(t, newMethod); object oldClass = returnClass(t, oldMethod); PROTECT(t, oldClass); object newClass = returnClass(t, newMethod); return isAssignableFrom(t, oldClass, newClass); } else { return true; } } else { return methodReturnCode(t, oldMethod) == VoidField; } } void jumpAndInvoke(MyThread* t, object method, void* stack, ...) { t->trace->targetMethod = 0; if (methodFlags(t, method) & ACC_NATIVE) { t->trace->nativeMethod = method; } else { t->trace->nativeMethod = 0; } unsigned argumentCount = methodParameterFootprint(t, method); THREAD_RUNTIME_ARRAY(t, uintptr_t, arguments, argumentCount); va_list a; va_start(a, stack); for (unsigned i = 0; i < argumentCount; ++i) { RUNTIME_ARRAY_BODY(arguments)[i] = va_arg(a, uintptr_t); } va_end(a); assert(t, t->exception == 0); popResources(t); vmJumpAndInvoke (t, reinterpret_cast(methodAddress(t, method)), stack, argumentCount * BytesPerWord, RUNTIME_ARRAY_BODY(arguments), (t->arch->alignFrameSize(t->arch->argumentFootprint(argumentCount)) + t->arch->frameReturnAddressSize()) * BytesPerWord); } void callContinuation(MyThread* t, object continuation, object result, object exception) { enum { Call, Unwind, Rewind } action; object nextContinuation = 0; if (t->continuation == 0 or continuationContext(t, t->continuation) != continuationContext(t, continuation)) { PROTECT(t, continuation); PROTECT(t, result); PROTECT(t, exception); if (compatibleReturnType (t, t->trace->originalMethod, continuationContextMethod (t, continuationContext(t, continuation)))) { object oldContext; object unwindContext; if (t->continuation) { oldContext = continuationContext(t, t->continuation); unwindContext = oldContext; } else { oldContext = 0; unwindContext = 0; } object rewindContext = 0; for (object newContext = continuationContext(t, continuation); newContext; newContext = continuationContextNext(t, newContext)) { if (newContext == oldContext) { unwindContext = 0; break; } else { rewindContext = newContext; } } if (unwindContext and continuationContextContinuation(t, unwindContext)) { nextContinuation = continuationContextContinuation(t, unwindContext); result = makeUnwindResult(t, continuation, result, exception); action = Unwind; } else if (rewindContext and continuationContextContinuation(t, rewindContext)) { nextContinuation = continuationContextContinuation(t, rewindContext); action = Rewind; if (root(t, RewindMethod) == 0) { PROTECT(t, nextContinuation); object method = resolveMethod (t, root(t, Machine::BootLoader), "avian/Continuations", "rewind", "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" "Ljava/lang/Throwable;)V"); PROTECT(t, method); compile(t, local::codeAllocator(t), 0, method); setRoot(t, RewindMethod, method); } } else { action = Call; } } else { throwNew(t, Machine::IncompatibleContinuationExceptionType); } } else { action = Call; } void* ip; void* frame; void* stack; object threadContinuation; findUnwindTarget(t, &ip, &frame, &stack, &threadContinuation); switch (action) { case Call: { callContinuation(t, continuation, result, exception, ip, stack); } break; case Unwind: { callContinuation(t, nextContinuation, result, 0, ip, stack); } break; case Rewind: { transition(t, 0, 0, nextContinuation, t->trace); jumpAndInvoke (t, root(t, RewindMethod), stack, continuationContextBefore(t, continuationContext(t, nextContinuation)), continuation, result, exception); } break; default: abort(t); } } void callWithCurrentContinuation(MyThread* t, object receiver) { object method = 0; void* ip = 0; void* stack = 0; { PROTECT(t, receiver); if (root(t, ReceiveMethod) == 0) { object m = resolveMethod (t, root(t, Machine::BootLoader), "avian/Function", "call", "(Ljava/lang/Object;)Ljava/lang/Object;"); if (m) { setRoot(t, ReceiveMethod, m); object continuationClass = type(t, Machine::ContinuationType); if (classVmFlags(t, continuationClass) & BootstrapFlag) { resolveSystemClass (t, root(t, Machine::BootLoader), vm::className(t, continuationClass)); } } } method = findInterfaceMethod (t, root(t, ReceiveMethod), objectClass(t, receiver)); PROTECT(t, method); compile(t, local::codeAllocator(t), 0, method); t->continuation = makeCurrentContinuation(t, &ip, &stack); } jumpAndInvoke(t, method, stack, receiver, t->continuation); } void dynamicWind(MyThread* t, object before, object thunk, object after) { void* ip = 0; void* stack = 0; { PROTECT(t, before); PROTECT(t, thunk); PROTECT(t, after); if (root(t, WindMethod) == 0) { object method = resolveMethod (t, root(t, Machine::BootLoader), "avian/Continuations", "wind", "(Ljava/lang/Runnable;Ljava/util/concurrent/Callable;" "Ljava/lang/Runnable;)Lavian/Continuations$UnwindResult;"); if (method) { setRoot(t, WindMethod, method); compile(t, local::codeAllocator(t), 0, method); } } t->continuation = makeCurrentContinuation(t, &ip, &stack); object newContext = makeContinuationContext (t, continuationContext(t, t->continuation), before, after, t->continuation, t->trace->originalMethod); set(t, t->continuation, ContinuationContext, newContext); } jumpAndInvoke(t, root(t, WindMethod), stack, before, thunk, after); } class ArgumentList { public: ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask, object this_, const char* spec, bool indirectObjects, va_list arguments): t(static_cast(t)), array(array), objectMask(objectMask), size(size), position(0), protector(this) { if (this_) { addObject(this_); } for (MethodSpecIterator it(t, spec); it.hasNext();) { switch (*it.next()) { case 'L': case '[': if (indirectObjects) { object* v = va_arg(arguments, object*); addObject(v ? *v : 0); } else { addObject(va_arg(arguments, object)); } break; case 'J': addLong(va_arg(arguments, uint64_t)); break; case 'D': addLong(doubleToBits(va_arg(arguments, double))); break; case 'F': addInt(floatToBits(va_arg(arguments, double))); break; default: addInt(va_arg(arguments, uint32_t)); break; } } } ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask, object this_, const char* spec, const jvalue* arguments): t(static_cast(t)), array(array), objectMask(objectMask), size(size), position(0), protector(this) { if (this_) { addObject(this_); } unsigned index = 0; for (MethodSpecIterator it(t, spec); it.hasNext();) { switch (*it.next()) { case 'L': case '[': { object* v = arguments[index++].l; addObject(v ? *v : 0); } break; case 'J': addLong(arguments[index++].j); break; case 'D': addLong(doubleToBits(arguments[index++].d)); break; case 'F': addInt(floatToBits(arguments[index++].f)); break; default: addInt(arguments[index++].i); break; } } } ArgumentList(Thread* t, uintptr_t* array, unsigned size, bool* objectMask, object this_, const char* spec, object arguments): t(static_cast(t)), array(array), objectMask(objectMask), size(size), position(0), protector(this) { if (this_) { addObject(this_); } unsigned index = 0; for (MethodSpecIterator it(t, spec); it.hasNext();) { switch (*it.next()) { case 'L': case '[': addObject(objectArrayBody(t, arguments, index++)); break; case 'J': case 'D': addLong(fieldAtOffset(objectArrayBody(t, arguments, index++), 8)); break; default: addInt(fieldAtOffset(objectArrayBody(t, arguments, index++), BytesPerWord)); break; } } } void addObject(object v) { assert(t, position < size); array[position] = reinterpret_cast(v); objectMask[position] = true; ++ position; } void addInt(uintptr_t v) { assert(t, position < size); array[position] = v; objectMask[position] = false; ++ position; } void addLong(uint64_t v) { assert(t, position < size - 1); memcpy(array + position, &v, 8); objectMask[position] = false; objectMask[position + 1] = false; position += 2; } MyThread* t; uintptr_t* array; bool* objectMask; unsigned size; unsigned position; class MyProtector: public Thread::Protector { public: MyProtector(ArgumentList* list): Protector(list->t), list(list) { } virtual void visit(Heap::Visitor* v) { for (unsigned i = 0; i < list->position; ++i) { if (list->objectMask[i]) { v->visit(reinterpret_cast(list->array + i)); } } } ArgumentList* list; } protector; }; object invoke(Thread* thread, object method, ArgumentList* arguments) { MyThread* t = static_cast(thread); if (false) { PROTECT(t, method); compile(t, local::codeAllocator(static_cast(t)), 0, resolveMethod (t, root(t, Machine::AppLoader), "foo/ClassName", "methodName", "()V")); } uintptr_t stackLimit = t->stackLimit; uintptr_t stackPosition = reinterpret_cast(&t); if (stackLimit == 0) { t->stackLimit = stackPosition - t->m->stackSizeInBytes; } else if (stackPosition < stackLimit) { throwNew(t, Machine::StackOverflowErrorType); } THREAD_RESOURCE(t, uintptr_t, stackLimit, static_cast(t)->stackLimit = stackLimit); unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); uint64_t result; { MyThread::CallTrace trace(t, method); MyCheckpoint checkpoint(t); assert(t, arguments->position == arguments->size); result = vmInvoke (t, reinterpret_cast(methodAddress(t, method)), arguments->array, arguments->position * BytesPerWord, t->arch->alignFrameSize (t->arch->argumentFootprint(arguments->position)) * BytesPerWord, returnType); } if (t->exception) { if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { collect(t, Heap::MinorCollection); } object exception = t->exception; t->exception = 0; vm::throw_(t, exception); } object r; switch (returnCode) { case ByteField: case BooleanField: case CharField: case ShortField: case FloatField: case IntField: r = makeInt(t, result); break; case LongField: case DoubleField: r = makeLong(t, result); break; case ObjectField: r = reinterpret_cast(result); break; case VoidField: r = 0; break; default: abort(t); } return r; } class SignalHandler: public SignalRegistrar::Handler { public: SignalHandler(Machine::Type type, Machine::Root root, unsigned fixedSize): m(0), type(type), root(root), fixedSize(fixedSize) { } virtual bool handleSignal(void** ip, void** frame, void** stack, void** thread) { MyThread* t = static_cast(m->localThread->get()); if (t and t->state == Thread::ActiveState) { object node = methodForIp(t, *ip); if (node) { // add one to the IP since findLineNumber will subtract one // when we make the trace: MyThread::TraceContext context (t, static_cast(*ip) + 1, static_cast(*stack) - t->arch->frameReturnAddressSize(), t->continuation, t->trace); if (ensure(t, fixedSize + traceSize(t))) { atomicOr(&(t->flags), Thread::TracingFlag); t->exception = makeThrowable(t, type); atomicAnd(&(t->flags), ~Thread::TracingFlag); } else { // not enough memory available for a new exception and stack // trace -- use a preallocated instance instead t->exception = vm::root(t, root); } // printTrace(t, t->exception); object continuation; findUnwindTarget(t, ip, frame, stack, &continuation); transition(t, ip, stack, continuation, t->trace); *thread = t; return true; } } if (compileLog) { fflush(compileLog); } return false; } Machine* m; Machine::Type type; Machine::Root root; unsigned fixedSize; }; bool isThunk(MyThread* t, void* ip); bool isVirtualThunk(MyThread* t, void* ip); bool isThunkUnsafeStack(MyThread* t, void* ip); void boot(MyThread* t, BootImage* image, uint8_t* code); class MyProcessor; MyProcessor* processor(MyThread* t); void compileThunks(MyThread* t, FixedAllocator* allocator); class CompilationHandlerList { public: CompilationHandlerList(CompilationHandlerList* next, Processor::CompilationHandler* handler): next(next), handler(handler) {} void dispose(Allocator* allocator) { if(this) { next->dispose(allocator); handler->dispose(); allocator->free(this, sizeof(*this)); } } CompilationHandlerList* next; Processor::CompilationHandler* handler; }; template int checkConstant(MyThread* t, size_t expected, T C::* field, const char* name) { size_t actual = reinterpret_cast(&(t->*field)) - reinterpret_cast(t); if(expected != actual) { fprintf(stderr, "constant mismatch (%s): \n\tconstant says: %d\n\tc++ compiler " "says: %d\n", name, (unsigned)expected, (unsigned)actual); return 1; } return 0; } class MyProcessor: public Processor { public: class Thunk { public: Thunk(): start(0), frameSavedOffset(0), length(0) { } Thunk(uint8_t* start, unsigned frameSavedOffset, unsigned length): start(start), frameSavedOffset(frameSavedOffset), length(length) { } uint8_t* start; unsigned frameSavedOffset; unsigned length; }; class ThunkCollection { public: Thunk default_; Thunk defaultVirtual; Thunk native; Thunk aioob; Thunk stackOverflow; Thunk table; }; MyProcessor(System* s, Allocator* allocator, const char* crashDumpDirectory, bool useNativeFeatures) : s(s), allocator(allocator), roots(0), bootImage(0), heapImage(0), codeImage(0), codeImageSize(0), segFaultHandler(Machine::NullPointerExceptionType, Machine::NullPointerException, FixedSizeOfNullPointerException), divideByZeroHandler(Machine::ArithmeticExceptionType, Machine::ArithmeticException, FixedSizeOfArithmeticException), codeAllocator(s, Slice(0, 0)), callTableSize(0), useNativeFeatures(useNativeFeatures), compilationHandlers(0) { thunkTable[compileMethodIndex] = voidPointer(local::compileMethod); thunkTable[compileVirtualMethodIndex] = voidPointer(compileVirtualMethod); thunkTable[invokeNativeIndex] = voidPointer(invokeNative); thunkTable[throwArrayIndexOutOfBoundsIndex] = voidPointer (throwArrayIndexOutOfBounds); thunkTable[throwStackOverflowIndex] = voidPointer(throwStackOverflow); using namespace avian::codegen::runtime; #define THUNK(s) thunkTable[s##Index] = voidPointer(s); #include "thunks.cpp" #undef THUNK // Set the dummyIndex entry to a constant which should require the // maximum number of bytes to represent in assembly code // (i.e. can't be represented by a smaller number of bytes and // implicitly sign- or zero-extended). We'll use this property // later to determine the maximum size of a thunk in the thunk // table. thunkTable[dummyIndex] = reinterpret_cast (static_cast(UINT64_C(0x5555555555555555))); signals.setCrashDumpDirectory(crashDumpDirectory); } virtual Thread* makeThread(Machine* m, object javaThread, Thread* parent) { MyThread* t = new (m->heap->allocate(sizeof(MyThread))) MyThread(m, javaThread, static_cast(parent), useNativeFeatures); t->heapImage = heapImage; t->codeImage = codeImage; t->thunkTable = thunkTable; #if TARGET_BYTES_PER_WORD == BYTES_PER_WORD int mismatches = checkConstant(t, TARGET_THREAD_EXCEPTION, &Thread::exception, "TARGET_THREAD_EXCEPTION") + checkConstant(t, TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT, &MyThread::exceptionStackAdjustment, "TARGET_THREAD_EXCEPTIONSTACKADJUSTMENT") + checkConstant(t, TARGET_THREAD_EXCEPTIONOFFSET, &MyThread::exceptionOffset, "TARGET_THREAD_EXCEPTIONOFFSET") + checkConstant(t, TARGET_THREAD_EXCEPTIONHANDLER, &MyThread::exceptionHandler, "TARGET_THREAD_EXCEPTIONHANDLER") + checkConstant( t, TARGET_THREAD_IP, &MyThread::ip, "TARGET_THREAD_IP") + checkConstant( t, TARGET_THREAD_STACK, &MyThread::stack, "TARGET_THREAD_STACK") + checkConstant(t, TARGET_THREAD_NEWSTACK, &MyThread::newStack, "TARGET_THREAD_NEWSTACK") + checkConstant(t, TARGET_THREAD_TAILADDRESS, &MyThread::tailAddress, "TARGET_THREAD_TAILADDRESS") + checkConstant(t, TARGET_THREAD_VIRTUALCALLTARGET, &MyThread::virtualCallTarget, "TARGET_THREAD_VIRTUALCALLTARGET") + checkConstant(t, TARGET_THREAD_VIRTUALCALLINDEX, &MyThread::virtualCallIndex, "TARGET_THREAD_VIRTUALCALLINDEX") + checkConstant(t, TARGET_THREAD_HEAPIMAGE, &MyThread::heapImage, "TARGET_THREAD_HEAPIMAGE") + checkConstant(t, TARGET_THREAD_CODEIMAGE, &MyThread::codeImage, "TARGET_THREAD_CODEIMAGE") + checkConstant(t, TARGET_THREAD_THUNKTABLE, &MyThread::thunkTable, "TARGET_THREAD_THUNKTABLE") + checkConstant(t, TARGET_THREAD_STACKLIMIT, &MyThread::stackLimit, "TARGET_THREAD_STACKLIMIT"); if(mismatches > 0) { fprintf(stderr, "%d constant mismatches\n", mismatches); abort(t); } #endif t->init(); return t; } virtual object makeMethod(vm::Thread* t, uint8_t vmFlags, uint8_t returnCode, uint8_t parameterCount, uint8_t parameterFootprint, uint16_t flags, uint16_t offset, object name, object spec, object addendum, object class_, object code) { if (code) { codeCompiled(t, code) = local::defaultThunk(static_cast(t)); } return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, offset, 0, 0, name, spec, addendum, class_, code); } virtual object makeClass(vm::Thread* t, uint16_t flags, uint16_t vmFlags, uint16_t fixedSize, uint8_t arrayElementSize, uint8_t arrayDimensions, object objectMask, object name, object sourceFile, object super, object interfaceTable, object virtualTable, object fieldTable, object methodTable, object staticTable, object addendum, object loader, unsigned vtableLength) { return vm::makeClass (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, 0, objectMask, name, sourceFile, super, interfaceTable, virtualTable, fieldTable, methodTable, staticTable, addendum, loader, 0, vtableLength); } virtual void initVtable(Thread* t, object c) { PROTECT(t, c); for (int i = classLength(t, c) - 1; i >= 0; --i) { void* thunk = reinterpret_cast (virtualThunk(static_cast(t), i)); classVtable(t, c, i) = thunk; } } virtual void visitObjects(Thread* vmt, Heap::Visitor* v) { MyThread* t = static_cast(vmt); if (t == t->m->rootThread) { v->visit(&roots); } for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { v->visit(&(trace->continuation)); v->visit(&(trace->nativeMethod)); v->visit(&(trace->targetMethod)); v->visit(&(trace->originalMethod)); } v->visit(&(t->continuation)); for (Reference* r = t->reference; r; r = r->next) { v->visit(&(r->target)); } visitStack(t, v); } virtual void walkStack(Thread* vmt, StackVisitor* v) { MyThread* t = static_cast(vmt); MyStackWalker walker(t); walker.walk(v); } virtual int lineNumber(Thread* vmt, object method, int ip) { return findLineNumber(static_cast(vmt), method, ip); } virtual object* makeLocalReference(Thread* vmt, object o) { if (o) { MyThread* t = static_cast(vmt); for (Reference* r = t->reference; r; r = r->next) { if (r->target == o) { acquire(t, r); return &(r->target); } } Reference* r = new (t->m->heap->allocate(sizeof(Reference))) Reference(o, &(t->reference), false); acquire(t, r); return &(r->target); } else { return 0; } } virtual void disposeLocalReference(Thread* t, object* r) { if (r) { release(t, reinterpret_cast(r)); } } virtual bool pushLocalFrame(Thread* vmt, unsigned) { MyThread* t = static_cast(vmt); t->referenceFrame = new (t->m->heap->allocate(sizeof(List))) List(t->reference, t->referenceFrame); return true; } virtual void popLocalFrame(Thread* vmt) { MyThread* t = static_cast(vmt); List* f = t->referenceFrame; t->referenceFrame = f->next; while (t->reference != f->item) { vm::dispose(t, t->reference); } t->m->heap->free(f, sizeof(List)); } virtual object invokeArray(Thread* t, object method, object this_, object arguments) { assert(t, t->exception == 0); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); method = findMethod(t, method, this_); const char* spec = reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), 0)); unsigned size = methodParameterFootprint(t, method); THREAD_RUNTIME_ARRAY(t, uintptr_t, array, size); THREAD_RUNTIME_ARRAY(t, bool, objectMask, size); ArgumentList list (t, RUNTIME_ARRAY_BODY(array), size, RUNTIME_ARRAY_BODY(objectMask), this_, spec, arguments); PROTECT(t, method); compile(static_cast(t), local::codeAllocator(static_cast(t)), 0, method); return local::invoke(t, method, &list); } virtual object invokeArray(Thread* t, object method, object this_, const jvalue* arguments) { assert(t, t->exception == 0); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); method = findMethod(t, method, this_); const char* spec = reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), 0)); unsigned size = methodParameterFootprint(t, method); THREAD_RUNTIME_ARRAY(t, uintptr_t, array, size); THREAD_RUNTIME_ARRAY(t, bool, objectMask, size); ArgumentList list (t, RUNTIME_ARRAY_BODY(array), size, RUNTIME_ARRAY_BODY(objectMask), this_, spec, arguments); PROTECT(t, method); compile(static_cast(t), local::codeAllocator(static_cast(t)), 0, method); return local::invoke(t, method, &list); } virtual object invokeList(Thread* t, object method, object this_, bool indirectObjects, va_list arguments) { assert(t, t->exception == 0); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); method = findMethod(t, method, this_); const char* spec = reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), 0)); unsigned size = methodParameterFootprint(t, method); THREAD_RUNTIME_ARRAY(t, uintptr_t, array, size); THREAD_RUNTIME_ARRAY(t, bool, objectMask, size); ArgumentList list (t, RUNTIME_ARRAY_BODY(array), size, RUNTIME_ARRAY_BODY(objectMask), this_, spec, indirectObjects, arguments); PROTECT(t, method); compile(static_cast(t), local::codeAllocator(static_cast(t)), 0, method); return local::invoke(t, method, &list); } virtual object invokeList(Thread* t, object loader, const char* className, const char* methodName, const char* methodSpec, object this_, va_list arguments) { assert(t, t->exception == 0); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); unsigned size = parameterFootprint(t, methodSpec, this_ == 0); THREAD_RUNTIME_ARRAY(t, uintptr_t, array, size); THREAD_RUNTIME_ARRAY(t, bool, objectMask, size); ArgumentList list (t, RUNTIME_ARRAY_BODY(array), size, RUNTIME_ARRAY_BODY(objectMask), this_, methodSpec, false, arguments); object method = resolveMethod (t, loader, className, methodName, methodSpec); assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); PROTECT(t, method); compile(static_cast(t), local::codeAllocator(static_cast(t)), 0, method); return local::invoke(t, method, &list); } virtual void dispose(Thread* vmt) { MyThread* t = static_cast(vmt); while (t->reference) { vm::dispose(t, t->reference); } t->arch->release(); t->m->heap->free(t, sizeof(*t)); } virtual void dispose() { if (codeAllocator.memory.begin()) { #if !defined(AVIAN_AOT_ONLY) s->freeExecutable(codeAllocator.memory.begin(), codeAllocator.memory.count); #endif } compilationHandlers->dispose(allocator); signals.unregisterHandler(SignalRegistrar::SegFault); signals.unregisterHandler(SignalRegistrar::DivideByZero); signals.setCrashDumpDirectory(0); allocator->free(this, sizeof(*this)); } virtual object getStackTrace(Thread* vmt, Thread* vmTarget) { MyThread* t = static_cast(vmt); MyThread* target = static_cast(vmTarget); MyProcessor* p = this; class Visitor: public System::ThreadVisitor { public: Visitor(MyThread* t, MyProcessor* p, MyThread* target): t(t), p(p), target(target), trace(0) { } virtual void visit(void* ip, void* stack, void* link) { MyThread::TraceContext c(target, link); if (methodForIp(t, ip)) { // we caught the thread in Java code - use the register values c.ip = ip; c.stack = stack; c.methodIsMostRecent = true; } else if (target->transition) { // we caught the thread in native code while in the middle // of updating the context fields (MyThread::stack, etc.) static_cast(c) = *(target->transition); } else if (isVmInvokeUnsafeStack(ip)) { // we caught the thread in native code just after returning // from java code, but before clearing MyThread::stack // (which now contains a garbage value), and the most recent // Java frame, if any, can be found in // MyThread::continuation or MyThread::trace c.ip = 0; c.stack = 0; } else if (target->stack and (not isThunkUnsafeStack(t, ip)) and (not isVirtualThunk(t, ip))) { // we caught the thread in a thunk or native code, and the // saved stack pointer indicates the most recent Java frame // on the stack c.ip = getIp(target); c.stack = target->stack; } else if (isThunk(t, ip) or isVirtualThunk(t, ip)) { // we caught the thread in a thunk where the stack register // indicates the most recent Java frame on the stack // On e.g. x86, the return address will have already been // pushed onto the stack, in which case we use getIp to // retrieve it. On e.g. PowerPC and ARM, it will be in the // link register. Note that we can't just check if the link // argument is null here, since we use ecx/rcx as a // pseudo-link register on x86 for the purpose of tail // calls. c.ip = t->arch->hasLinkRegister() ? link : getIp(t, link, stack); c.stack = stack; } else { // we caught the thread in native code, and the most recent // Java frame, if any, can be found in // MyThread::continuation or MyThread::trace c.ip = 0; c.stack = 0; } if (ensure(t, traceSize(target))) { atomicOr(&(t->flags), Thread::TracingFlag); trace = makeTrace(t, target); atomicAnd(&(t->flags), ~Thread::TracingFlag); } } MyThread* t; MyProcessor* p; MyThread* target; object trace; } visitor(t, p, target); t->m->system->visit(t->systemThread, target->systemThread, &visitor); if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { PROTECT(t, visitor.trace); collect(t, Heap::MinorCollection); } return visitor.trace ? visitor.trace : makeObjectArray(t, 0); } virtual void initialize(BootImage* image, Slice code) { bootImage = image; codeAllocator.memory = code; } virtual void addCompilationHandler(CompilationHandler* handler) { compilationHandlers = new (allocator->allocate(sizeof(CompilationHandlerList))) CompilationHandlerList(compilationHandlers, handler); } virtual void compileMethod(Thread* vmt, Zone* zone, object* constants, object* calls, avian::codegen::DelayedPromise** addresses, object method, OffsetResolver* resolver) { MyThread* t = static_cast(vmt); BootContext bootContext(t, *constants, *calls, *addresses, zone, resolver); compile(t, &codeAllocator, &bootContext, method); *constants = bootContext.constants; *calls = bootContext.calls; *addresses = bootContext.addresses; } virtual void visitRoots(Thread* t, HeapWalker* w) { bootImage->methodTree = w->visitRoot(root(t, MethodTree)); bootImage->methodTreeSentinal = w->visitRoot(root(t, MethodTreeSentinal)); bootImage->virtualThunks = w->visitRoot(root(t, VirtualThunks)); } virtual void normalizeVirtualThunks(Thread* t) { for (unsigned i = 0; i < wordArrayLength(t, root(t, VirtualThunks)); i += 2) { if (wordArrayBody(t, root(t, VirtualThunks), i)) { wordArrayBody(t, root(t, VirtualThunks), i) -= reinterpret_cast(codeAllocator.memory.begin()); } } } virtual unsigned* makeCallTable(Thread* t, HeapWalker* w) { bootImage->codeSize = codeAllocator.offset; bootImage->callCount = callTableSize; unsigned* table = static_cast (t->m->heap->allocate(callTableSize * sizeof(unsigned) * 2)); unsigned index = 0; for (unsigned i = 0; i < arrayLength(t, root(t, CallTable)); ++i) { for (object p = arrayBody(t, root(t, CallTable), i); p; p = callNodeNext(t, p)) { table[index++] = targetVW( callNodeAddress(t, p) - reinterpret_cast(codeAllocator.memory.begin())); table[index++] = targetVW( w->map()->find(callNodeTarget(t, p)) | (static_cast(callNodeFlags(t, p)) << TargetBootShift)); } } return table; } virtual void boot(Thread* t, BootImage* image, uint8_t* code) { #if !defined(AVIAN_AOT_ONLY) if (codeAllocator.memory.begin() == 0) { codeAllocator.memory.items = static_cast( s->tryAllocateExecutable(ExecutableAreaSizeInBytes)); codeAllocator.memory.count = ExecutableAreaSizeInBytes; } #endif if (image and code) { local::boot(static_cast(t), image, code); } else { roots = makeArray(t, RootCount); setRoot(t, CallTable, makeArray(t, 128)); setRoot(t, MethodTreeSentinal, makeTreeNode(t, 0, 0, 0)); setRoot(t, MethodTree, root(t, MethodTreeSentinal)); set(t, root(t, MethodTree), TreeNodeLeft, root(t, MethodTreeSentinal)); set(t, root(t, MethodTree), TreeNodeRight, root(t, MethodTreeSentinal)); } #ifdef AVIAN_AOT_ONLY thunks = bootThunks; #else local::compileThunks(static_cast(t), &codeAllocator); if (not (image and code)) { bootThunks = thunks; } #endif segFaultHandler.m = t->m; expect(t, signals.registerHandler(SignalRegistrar::SegFault, &segFaultHandler)); divideByZeroHandler.m = t->m; expect(t, signals.registerHandler(SignalRegistrar::DivideByZero, ÷ByZeroHandler)); } virtual void callWithCurrentContinuation(Thread* t, object receiver) { if (Continuations) { local::callWithCurrentContinuation(static_cast(t), receiver); } else { abort(t); } } virtual void dynamicWind(Thread* t, object before, object thunk, object after) { if (Continuations) { local::dynamicWind(static_cast(t), before, thunk, after); } else { abort(t); } } virtual void feedResultToContinuation(Thread* t, object continuation, object result) { if (Continuations) { callContinuation(static_cast(t), continuation, result, 0); } else { abort(t); } } virtual void feedExceptionToContinuation(Thread* t, object continuation, object exception) { if (Continuations) { callContinuation(static_cast(t), continuation, 0, exception); } else { abort(t); } } virtual void walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) { if (Continuations) { local::walkContinuationBody(static_cast(t), w, o, start); } else { abort(t); } } System* s; SignalRegistrar signals; Allocator* allocator; object roots; BootImage* bootImage; uintptr_t* heapImage; uint8_t* codeImage; unsigned codeImageSize; SignalHandler segFaultHandler; SignalHandler divideByZeroHandler; FixedAllocator codeAllocator; ThunkCollection thunks; ThunkCollection bootThunks; unsigned callTableSize; bool useNativeFeatures; void* thunkTable[dummyIndex + 1]; CompilationHandlerList* compilationHandlers; }; const char* stringOrNull(const char* str) { if(str) { return str; } else { return "(null)"; } } size_t stringOrNullSize(const char* str) { return strlen(stringOrNull(str)); } void logCompile(MyThread* t, const void* code, unsigned size, const char* class_, const char* name, const char* spec) { static bool open = false; if (not open) { open = true; const char* path = findProperty(t, "avian.jit.log"); if (path) { compileLog = vm::fopen(path, "wb"); } else if (DebugCompile) { compileLog = stderr; } } if (compileLog) { fprintf(compileLog, "%p,%p %s.%s%s\n", code, static_cast(code) + size, class_, name, spec); } size_t nameLength = stringOrNullSize(class_) + stringOrNullSize(name) + stringOrNullSize(spec) + 2; THREAD_RUNTIME_ARRAY(t, char, completeName, nameLength); sprintf(RUNTIME_ARRAY_BODY(completeName), "%s.%s%s", stringOrNull(class_), stringOrNull(name), stringOrNull(spec)); MyProcessor* p = static_cast(t->m->processor); for(CompilationHandlerList* h = p->compilationHandlers; h; h = h->next) { h->handler->compiled(code, 0, 0, RUNTIME_ARRAY_BODY(completeName)); } } void* compileMethod2(MyThread* t, void* ip) { object node = findCallNode(t, ip); object target = callNodeTarget(t, node); PROTECT(t, node); PROTECT(t, target); t->trace->targetMethod = target; THREAD_RESOURCE0(t, static_cast(t)->trace->targetMethod = 0); compile(t, codeAllocator(t), 0, target); uint8_t* updateIp = static_cast(ip); MyProcessor* p = processor(t); bool updateCaller = updateIp < p->codeImage or updateIp >= p->codeImage + p->codeImageSize; uintptr_t address; if (methodFlags(t, target) & ACC_NATIVE) { address = useLongJump(t, reinterpret_cast(ip)) or (not updateCaller) ? bootNativeThunk(t) : nativeThunk(t); } else { address = methodAddress(t, target); } if (updateCaller) { avian::codegen::lir::UnaryOperation op; if (callNodeFlags(t, node) & TraceElement::LongCall) { if (callNodeFlags(t, node) & TraceElement::TailCall) { op = avian::codegen::lir::AlignedLongJump; } else { op = avian::codegen::lir::AlignedLongCall; } } else if (callNodeFlags(t, node) & TraceElement::TailCall) { op = avian::codegen::lir::AlignedJump; } else { op = avian::codegen::lir::AlignedCall; } updateCall(t, op, updateIp, reinterpret_cast(address)); } return reinterpret_cast(address); } bool isThunk(MyProcessor::ThunkCollection* thunks, void* ip) { uint8_t* thunkStart = thunks->default_.start; uint8_t* thunkEnd = thunks->table.start + (thunks->table.length * ThunkCount); return (reinterpret_cast(ip) >= reinterpret_cast(thunkStart) and reinterpret_cast(ip) < reinterpret_cast(thunkEnd)); } bool isThunk(MyThread* t, void* ip) { MyProcessor* p = processor(t); return isThunk(&(p->thunks), ip) or isThunk(&(p->bootThunks), ip); } bool isThunkUnsafeStack(MyProcessor::Thunk* thunk, void* ip) { return reinterpret_cast(ip) >= reinterpret_cast(thunk->start) and reinterpret_cast(ip) < reinterpret_cast(thunk->start + thunk->frameSavedOffset); } bool isThunkUnsafeStack(MyProcessor::ThunkCollection* thunks, void* ip) { const unsigned NamedThunkCount = 5; MyProcessor::Thunk table[NamedThunkCount + ThunkCount]; table[0] = thunks->default_; table[1] = thunks->defaultVirtual; table[2] = thunks->native; table[3] = thunks->aioob; table[4] = thunks->stackOverflow; for (unsigned i = 0; i < ThunkCount; ++i) { new (table + NamedThunkCount + i) MyProcessor::Thunk (thunks->table.start + (i * thunks->table.length), thunks->table.frameSavedOffset, thunks->table.length); } for (unsigned i = 0; i < NamedThunkCount + ThunkCount; ++i) { if (isThunkUnsafeStack(table + i, ip)) { return true; } } return false; } bool isVirtualThunk(MyThread* t, void* ip) { for (unsigned i = 0; i < wordArrayLength(t, root(t, VirtualThunks)); i += 2) { uintptr_t start = wordArrayBody(t, root(t, VirtualThunks), i); uintptr_t end = start + wordArrayBody(t, root(t, VirtualThunks), i + 1); if (reinterpret_cast(ip) >= start and reinterpret_cast(ip) < end) { return true; } } return false; } bool isThunkUnsafeStack(MyThread* t, void* ip) { MyProcessor* p = processor(t); return isThunk(t, ip) and (isThunkUnsafeStack(&(p->thunks), ip) or isThunkUnsafeStack(&(p->bootThunks), ip)); } object findCallNode(MyThread* t, void* address) { if (DebugCallTable) { fprintf(stderr, "find call node %p\n", address); } // we must use a version of the call table at least as recent as the // compiled form of the method containing the specified address (see // compile(MyThread*, Allocator*, BootContext*, object)): loadMemoryBarrier(); object table = root(t, CallTable); intptr_t key = reinterpret_cast(address); unsigned index = static_cast(key) & (arrayLength(t, table) - 1); for (object n = arrayBody(t, table, index); n; n = callNodeNext(t, n)) { intptr_t k = callNodeAddress(t, n); if (k == key) { return n; } } return 0; } object resizeTable(MyThread* t, object oldTable, unsigned newLength) { PROTECT(t, oldTable); object oldNode = 0; PROTECT(t, oldNode); object newTable = makeArray(t, newLength); PROTECT(t, newTable); for (unsigned i = 0; i < arrayLength(t, oldTable); ++i) { for (oldNode = arrayBody(t, oldTable, i); oldNode; oldNode = callNodeNext(t, oldNode)) { intptr_t k = callNodeAddress(t, oldNode); unsigned index = k & (newLength - 1); object newNode = makeCallNode (t, callNodeAddress(t, oldNode), callNodeTarget(t, oldNode), callNodeFlags(t, oldNode), arrayBody(t, newTable, index)); set(t, newTable, ArrayBody + (index * BytesPerWord), newNode); } } return newTable; } object insertCallNode(MyThread* t, object table, unsigned* size, object node) { if (DebugCallTable) { fprintf(stderr, "insert call node %p\n", reinterpret_cast(callNodeAddress(t, node))); } PROTECT(t, table); PROTECT(t, node); ++ (*size); if (*size >= arrayLength(t, table) * 2) { table = resizeTable(t, table, arrayLength(t, table) * 2); } intptr_t key = callNodeAddress(t, node); unsigned index = static_cast(key) & (arrayLength(t, table) - 1); set(t, node, CallNodeNext, arrayBody(t, table, index)); set(t, table, ArrayBody + (index * BytesPerWord), node); return table; } void insertCallNode(MyThread* t, object node) { setRoot(t, CallTable, insertCallNode (t, root(t, CallTable), &(processor(t)->callTableSize), node)); } object makeClassMap(Thread* t, unsigned* table, unsigned count, uintptr_t* heap) { object array = makeArray(t, nextPowerOfTwo(count)); object map = makeHashMap(t, 0, array); PROTECT(t, map); for (unsigned i = 0; i < count; ++i) { object c = bootObject(heap, table[i]); hashMapInsert(t, map, className(t, c), c, byteArrayHash); } return map; } object makeStaticTableArray(Thread* t, unsigned* bootTable, unsigned bootCount, unsigned* appTable, unsigned appCount, uintptr_t* heap) { object array = makeArray(t, bootCount + appCount); for (unsigned i = 0; i < bootCount; ++i) { set(t, array, ArrayBody + (i * BytesPerWord), classStaticTable(t, bootObject(heap, bootTable[i]))); } for (unsigned i = 0; i < appCount; ++i) { set(t, array, ArrayBody + ((bootCount + i) * BytesPerWord), classStaticTable(t, bootObject(heap, appTable[i]))); } return array; } object makeStringMap(Thread* t, unsigned* table, unsigned count, uintptr_t* heap) { object array = makeArray(t, nextPowerOfTwo(count)); object map = makeWeakHashMap(t, 0, array); PROTECT(t, map); for (unsigned i = 0; i < count; ++i) { object s = bootObject(heap, table[i]); hashMapInsert(t, map, s, 0, stringHash); } return map; } object makeCallTable(MyThread* t, uintptr_t* heap, unsigned* calls, unsigned count, uintptr_t base) { object table = makeArray(t, nextPowerOfTwo(count)); PROTECT(t, table); unsigned size = 0; for (unsigned i = 0; i < count; ++i) { unsigned address = calls[i * 2]; unsigned target = calls[(i * 2) + 1]; object node = makeCallNode (t, base + address, bootObject(heap, target & BootMask), target >> BootShift, 0); table = insertCallNode(t, table, &size, node); } return table; } void fixupHeap(MyThread* t UNUSED, uintptr_t* map, unsigned size, uintptr_t* heap) { for (unsigned word = 0; word < size; ++word) { uintptr_t w = map[word]; if (w) { for (unsigned bit = 0; bit < BitsPerWord; ++bit) { if (w & (static_cast(1) << bit)) { unsigned index = indexOf(word, bit); uintptr_t* p = heap + index; assert(t, *p); uintptr_t number = *p & BootMask; uintptr_t mark = *p >> BootShift; if (number) { *p = reinterpret_cast(heap + (number - 1)) | mark; // fprintf(stderr, "fixup %d: %d 0x%x\n", index, // static_cast(number), static_cast(*p)); } else { *p = mark; } } } } } } void resetClassRuntimeState(Thread* t, object c, uintptr_t* heap, unsigned heapSize) { classRuntimeDataIndex(t, c) = 0; if (classArrayElementSize(t, c) == 0) { object staticTable = classStaticTable(t, c); if (staticTable) { for (unsigned i = 0; i < singletonCount(t, staticTable); ++i) { if (singletonIsObject(t, staticTable, i) and (reinterpret_cast (singletonObject(t, staticTable, i)) < heap or reinterpret_cast (singletonObject(t, staticTable, i)) > heap + heapSize)) { singletonObject(t, staticTable, i) = 0; } } } } if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object m = arrayBody(t, classMethodTable(t, c), i); methodNativeID(t, m) = 0; methodRuntimeDataIndex(t, m) = 0; if (methodVmFlags(t, m) & ClassInitFlag) { classVmFlags(t, c) |= NeedInitFlag; classVmFlags(t, c) &= ~InitErrorFlag; } } } t->m->processor->initVtable(t, c); } void resetRuntimeState(Thread* t, object map, uintptr_t* heap, unsigned heapSize) { for (HashMapIterator it(t, map); it.hasMore();) { resetClassRuntimeState(t, tripleSecond(t, it.next()), heap, heapSize); } } void fixupMethods(Thread* t, object map, BootImage* image UNUSED, uint8_t* code) { for (HashMapIterator it(t, map); it.hasMore();) { object c = tripleSecond(t, it.next()); if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); if (methodCode(t, method)) { assert(t, methodCompiled(t, method) <= static_cast(image->codeSize)); codeCompiled(t, methodCode(t, method)) = methodCompiled(t, method) + reinterpret_cast(code); if (DebugCompile) { logCompile (static_cast(t), reinterpret_cast(methodCompiled(t, method)), methodCompiledSize(t, method), reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, method)), 0)), reinterpret_cast (&byteArrayBody(t, methodName(t, method), 0)), reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), 0))); } } } } t->m->processor->initVtable(t, c); } } MyProcessor::Thunk thunkToThunk(const BootImage::Thunk& thunk, uint8_t* base) { return MyProcessor::Thunk (base + thunk.start, thunk.frameSavedOffset, thunk.length); } void findThunks(MyThread* t, BootImage* image, uint8_t* code) { MyProcessor* p = processor(t); p->bootThunks.default_ = thunkToThunk(image->thunks.default_, code); p->bootThunks.defaultVirtual = thunkToThunk(image->thunks.defaultVirtual, code); p->bootThunks.native = thunkToThunk(image->thunks.native, code); p->bootThunks.aioob = thunkToThunk(image->thunks.aioob, code); p->bootThunks.stackOverflow = thunkToThunk(image->thunks.stackOverflow, code); p->bootThunks.table = thunkToThunk(image->thunks.table, code); } void fixupVirtualThunks(MyThread* t, uint8_t* code) { for (unsigned i = 0; i < wordArrayLength(t, root(t, VirtualThunks)); i += 2) { if (wordArrayBody(t, root(t, VirtualThunks), i)) { wordArrayBody(t, root(t, VirtualThunks), i) = wordArrayBody(t, root(t, VirtualThunks), i) + reinterpret_cast(code); } } } void boot(MyThread* t, BootImage* image, uint8_t* code) { assert(t, image->magic == BootImage::Magic); unsigned* bootClassTable = reinterpret_cast(image + 1); unsigned* appClassTable = bootClassTable + image->bootClassCount; unsigned* stringTable = appClassTable + image->appClassCount; unsigned* callTable = stringTable + image->stringCount; uintptr_t* heapMap = reinterpret_cast (padWord(reinterpret_cast(callTable + (image->callCount * 2)))); unsigned heapMapSizeInWords = ceilingDivide (heapMapSize(image->heapSize), BytesPerWord); uintptr_t* heap = heapMap + heapMapSizeInWords; MyProcessor* p = static_cast(t->m->processor); t->heapImage = p->heapImage = heap; // fprintf(stderr, "heap from %p to %p\n", // heap, heap + ceilingDivide(image->heapSize, BytesPerWord)); t->codeImage = p->codeImage = code; p->codeImageSize = image->codeSize; // fprintf(stderr, "code from %p to %p\n", // code, code + image->codeSize); if (not image->initialized) { fixupHeap(t, heapMap, heapMapSizeInWords, heap); } t->m->heap->setImmortalHeap(heap, image->heapSize / BytesPerWord); t->m->types = bootObject(heap, image->types); t->m->roots = makeArray(t, Machine::RootCount); setRoot(t, Machine::BootLoader, bootObject(heap, image->bootLoader)); setRoot(t, Machine::AppLoader, bootObject(heap, image->appLoader)); p->roots = makeArray(t, RootCount); setRoot(t, MethodTree, bootObject(heap, image->methodTree)); setRoot(t, MethodTreeSentinal, bootObject(heap, image->methodTreeSentinal)); setRoot(t, VirtualThunks, bootObject(heap, image->virtualThunks)); { object map = makeClassMap(t, bootClassTable, image->bootClassCount, heap); set(t, root(t, Machine::BootLoader), ClassLoaderMap, map); } systemClassLoaderFinder(t, root(t, Machine::BootLoader)) = t->m->bootFinder; { object map = makeClassMap(t, appClassTable, image->appClassCount, heap); set(t, root(t, Machine::AppLoader), ClassLoaderMap, map); } systemClassLoaderFinder(t, root(t, Machine::AppLoader)) = t->m->appFinder; setRoot(t, Machine::StringMap, makeStringMap (t, stringTable, image->stringCount, heap)); p->callTableSize = image->callCount; setRoot(t, CallTable, makeCallTable (t, heap, callTable, image->callCount, reinterpret_cast(code))); setRoot(t, StaticTableArray, makeStaticTableArray (t, bootClassTable, image->bootClassCount, appClassTable, image->appClassCount, heap)); findThunks(t, image, code); if (image->initialized) { resetRuntimeState (t, classLoaderMap(t, root(t, Machine::BootLoader)), heap, image->heapSize); resetRuntimeState (t, classLoaderMap(t, root(t, Machine::AppLoader)), heap, image->heapSize); for (unsigned i = 0; i < arrayLength(t, t->m->types); ++i) { resetClassRuntimeState (t, type(t, static_cast(i)), heap, image->heapSize); } } else { fixupVirtualThunks(t, code); fixupMethods (t, classLoaderMap(t, root(t, Machine::BootLoader)), image, code); fixupMethods (t, classLoaderMap(t, root(t, Machine::AppLoader)), image, code); } image->initialized = true; setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0)); } intptr_t getThunk(MyThread* t, Thunk thunk) { MyProcessor* p = processor(t); return reinterpret_cast (p->thunks.table.start + (thunk * p->thunks.table.length)); } BootImage::Thunk thunkToThunk(const MyProcessor::Thunk& thunk, uint8_t* base) { return BootImage::Thunk (thunk.start - base, thunk.frameSavedOffset, thunk.length); } using avian::codegen::OperandInfo; namespace lir = avian::codegen::lir; void compileCall(MyThread* t, Context* c, ThunkIndex index, bool call = true) { avian::codegen::Assembler* a = c->assembler; if (processor(t)->bootImage) { lir::Memory table(t->arch->thread(), TARGET_THREAD_THUNKTABLE); lir::Register scratch(t->arch->scratch()); a->apply(lir::Move, OperandInfo(TargetBytesPerWord, lir::MemoryOperand, &table), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &scratch)); lir::Memory proc(scratch.low, index * TargetBytesPerWord); a->apply(lir::Move, OperandInfo(TargetBytesPerWord, lir::MemoryOperand, &proc), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &scratch)); a->apply (call ? lir::Call : lir::Jump, OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &scratch)); } else { lir::Constant proc (new(&c->zone) avian::codegen::ResolvedPromise(reinterpret_cast(t->thunkTable[index]))); a->apply (call ? lir::LongCall : lir::LongJump, OperandInfo(TargetBytesPerWord, lir::ConstantOperand, &proc)); } } void compileThunks(MyThread* t, FixedAllocator* allocator) { MyProcessor* p = processor(t); { Context context(t); avian::codegen::Assembler* a = context.assembler; a->saveFrame(TARGET_THREAD_STACK, TARGET_THREAD_IP); p->thunks.default_.frameSavedOffset = a->length(); lir::Register thread(t->arch->thread()); a->pushFrame(1, TargetBytesPerWord, lir::RegisterOperand, &thread); compileCall(t, &context, compileMethodIndex); a->popFrame(t->arch->alignFrameSize(1)); lir::Register result(t->arch->returnLow()); a->apply(lir::Jump, OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &result)); p->thunks.default_.length = a->endBlock(false)->resolve(0, 0); p->thunks.default_.start = finish (t, allocator, a, "default", p->thunks.default_.length); } { Context context(t); avian::codegen::Assembler* a = context.assembler; lir::Register class_(t->arch->virtualCallTarget()); lir::Memory virtualCallTargetSrc (t->arch->stack(), (t->arch->frameFooterSize() + t->arch->frameReturnAddressSize()) * TargetBytesPerWord); a->apply(lir::Move, OperandInfo(TargetBytesPerWord, lir::MemoryOperand, &virtualCallTargetSrc), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &class_)); lir::Memory virtualCallTargetDst (t->arch->thread(), TARGET_THREAD_VIRTUALCALLTARGET); a->apply(lir::Move, OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &class_), OperandInfo(TargetBytesPerWord, lir::MemoryOperand, &virtualCallTargetDst)); lir::Register index(t->arch->virtualCallIndex()); lir::Memory virtualCallIndex (t->arch->thread(), TARGET_THREAD_VIRTUALCALLINDEX); a->apply(lir::Move, OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &index), OperandInfo(TargetBytesPerWord, lir::MemoryOperand, &virtualCallIndex)); a->saveFrame(TARGET_THREAD_STACK, TARGET_THREAD_IP); p->thunks.defaultVirtual.frameSavedOffset = a->length(); lir::Register thread(t->arch->thread()); a->pushFrame(1, TargetBytesPerWord, lir::RegisterOperand, &thread); compileCall(t, &context, compileVirtualMethodIndex); a->popFrame(t->arch->alignFrameSize(1)); lir::Register result(t->arch->returnLow()); a->apply(lir::Jump, OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &result)); p->thunks.defaultVirtual.length = a->endBlock(false)->resolve(0, 0); p->thunks.defaultVirtual.start = finish (t, allocator, a, "defaultVirtual", p->thunks.defaultVirtual.length); } { Context context(t); avian::codegen::Assembler* a = context.assembler; a->saveFrame(TARGET_THREAD_STACK, TARGET_THREAD_IP); p->thunks.native.frameSavedOffset = a->length(); lir::Register thread(t->arch->thread()); a->pushFrame(1, TargetBytesPerWord, lir::RegisterOperand, &thread); compileCall(t, &context, invokeNativeIndex); a->popFrameAndUpdateStackAndReturn (t->arch->alignFrameSize(1), TARGET_THREAD_NEWSTACK); p->thunks.native.length = a->endBlock(false)->resolve(0, 0); p->thunks.native.start = finish (t, allocator, a, "native", p->thunks.native.length); } { Context context(t); avian::codegen::Assembler* a = context.assembler; a->saveFrame(TARGET_THREAD_STACK, TARGET_THREAD_IP); p->thunks.aioob.frameSavedOffset = a->length(); lir::Register thread(t->arch->thread()); a->pushFrame(1, TargetBytesPerWord, lir::RegisterOperand, &thread); compileCall(t, &context, throwArrayIndexOutOfBoundsIndex); p->thunks.aioob.length = a->endBlock(false)->resolve(0, 0); p->thunks.aioob.start = finish (t, allocator, a, "aioob", p->thunks.aioob.length); } { Context context(t); avian::codegen::Assembler* a = context.assembler; a->saveFrame(TARGET_THREAD_STACK, TARGET_THREAD_IP); p->thunks.stackOverflow.frameSavedOffset = a->length(); lir::Register thread(t->arch->thread()); a->pushFrame(1, TargetBytesPerWord, lir::RegisterOperand, &thread); compileCall(t, &context, throwStackOverflowIndex); p->thunks.stackOverflow.length = a->endBlock(false)->resolve(0, 0); p->thunks.stackOverflow.start = finish (t, allocator, a, "stackOverflow", p->thunks.stackOverflow.length); } { { Context context(t); avian::codegen::Assembler* a = context.assembler; a->saveFrame(TARGET_THREAD_STACK, TARGET_THREAD_IP); p->thunks.table.frameSavedOffset = a->length(); compileCall(t, &context, dummyIndex, false); p->thunks.table.length = a->endBlock(false)->resolve(0, 0); p->thunks.table.start = static_cast (allocator->allocate (p->thunks.table.length * ThunkCount, TargetBytesPerWord)); } uint8_t* start = p->thunks.table.start; #define THUNK(s) { \ Context context(t); \ avian::codegen::Assembler* a = context.assembler; \ \ a->saveFrame(TARGET_THREAD_STACK, TARGET_THREAD_IP); \ \ p->thunks.table.frameSavedOffset = a->length(); \ \ compileCall(t, &context, s##Index, false); \ \ expect(t, a->endBlock(false)->resolve(0, 0) \ <= p->thunks.table.length); \ \ a->setDestination(start); \ a->write(); \ \ logCompile(t, start, p->thunks.table.length, 0, #s, 0); \ \ start += p->thunks.table.length; \ } #include "thunks.cpp" #undef THUNK } BootImage* image = p->bootImage; if (image) { uint8_t* imageBase = p->codeAllocator.memory.begin(); image->thunks.default_ = thunkToThunk(p->thunks.default_, imageBase); image->thunks.defaultVirtual = thunkToThunk (p->thunks.defaultVirtual, imageBase); image->thunks.native = thunkToThunk(p->thunks.native, imageBase); image->thunks.aioob = thunkToThunk(p->thunks.aioob, imageBase); image->thunks.stackOverflow = thunkToThunk (p->thunks.stackOverflow, imageBase); image->thunks.table = thunkToThunk(p->thunks.table, imageBase); } } MyProcessor* processor(MyThread* t) { return static_cast(t->m->processor); } uintptr_t defaultThunk(MyThread* t) { return reinterpret_cast(processor(t)->thunks.default_.start); } uintptr_t bootDefaultThunk(MyThread* t) { return reinterpret_cast(processor(t)->bootThunks.default_.start); } uintptr_t defaultVirtualThunk(MyThread* t) { return reinterpret_cast (processor(t)->thunks.defaultVirtual.start); } uintptr_t nativeThunk(MyThread* t) { return reinterpret_cast(processor(t)->thunks.native.start); } uintptr_t bootNativeThunk(MyThread* t) { return reinterpret_cast(processor(t)->bootThunks.native.start); } uintptr_t aioobThunk(MyThread* t) { return reinterpret_cast(processor(t)->thunks.aioob.start); } uintptr_t stackOverflowThunk(MyThread* t) { return reinterpret_cast(processor(t)->thunks.stackOverflow.start); } bool unresolved(MyThread* t, uintptr_t methodAddress) { return methodAddress == defaultThunk(t) or methodAddress == bootDefaultThunk(t); } uintptr_t compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) { Context context(t); avian::codegen::Assembler* a = context.assembler; avian::codegen::ResolvedPromise indexPromise(index); lir::Constant indexConstant(&indexPromise); lir::Register indexRegister(t->arch->virtualCallIndex()); a->apply(lir::Move, OperandInfo(TargetBytesPerWord, lir::ConstantOperand, &indexConstant), OperandInfo(TargetBytesPerWord, lir::RegisterOperand, &indexRegister)); avian::codegen::ResolvedPromise defaultVirtualThunkPromise(defaultVirtualThunk(t)); lir::Constant thunk(&defaultVirtualThunkPromise); a->apply(lir::Jump, OperandInfo(TargetBytesPerWord, lir::ConstantOperand, &thunk)); *size = a->endBlock(false)->resolve(0, 0); uint8_t* start = static_cast (codeAllocator(t)->allocate(*size, TargetBytesPerWord)); a->setDestination(start); a->write(); const char* const virtualThunkBaseName = "virtualThunk"; const size_t virtualThunkBaseNameLength = strlen(virtualThunkBaseName); const size_t maxIntStringLength = 10; THREAD_RUNTIME_ARRAY(t, char, virtualThunkName, virtualThunkBaseNameLength + maxIntStringLength); sprintf(RUNTIME_ARRAY_BODY(virtualThunkName), "%s%d", virtualThunkBaseName, index); logCompile(t, start, *size, 0, RUNTIME_ARRAY_BODY(virtualThunkName), 0); return reinterpret_cast(start); } uintptr_t virtualThunk(MyThread* t, unsigned index) { ACQUIRE(t, t->m->classLock); if (root(t, VirtualThunks) == 0 or wordArrayLength(t, root(t, VirtualThunks)) <= index * 2) { object newArray = makeWordArray(t, nextPowerOfTwo((index + 1) * 2)); if (root(t, VirtualThunks)) { memcpy(&wordArrayBody(t, newArray, 0), &wordArrayBody(t, root(t, VirtualThunks), 0), wordArrayLength(t, root(t, VirtualThunks)) * BytesPerWord); } setRoot(t, VirtualThunks, newArray); } if (wordArrayBody(t, root(t, VirtualThunks), index * 2) == 0) { unsigned size; uintptr_t thunk = compileVirtualThunk(t, index, &size); wordArrayBody(t, root(t, VirtualThunks), index * 2) = thunk; wordArrayBody(t, root(t, VirtualThunks), (index * 2) + 1) = size; } return wordArrayBody(t, root(t, VirtualThunks), index * 2); } void compile(MyThread* t, FixedAllocator* allocator, BootContext* bootContext, object method) { PROTECT(t, method); if (bootContext == 0 and methodFlags(t, method) & ACC_STATIC) { initClass(t, methodClass(t, method)); } if (methodAddress(t, method) != defaultThunk(t)) { return; } assert(t, (methodFlags(t, method) & ACC_NATIVE) == 0); // We must avoid acquiring any locks until after the first pass of // compilation, since this pass may trigger classloading operations // involving application classloaders and thus the potential for // deadlock. To make this safe, we use a private clone of the // method so that we won't be confused if another thread updates the // original while we're working. object clone = methodClone(t, method); loadMemoryBarrier(); if (methodAddress(t, method) != defaultThunk(t)) { return; } PROTECT(t, clone); Context context(t, bootContext, clone); compile(t, &context); { object ehTable = codeExceptionHandlerTable(t, methodCode(t, clone)); if (ehTable) { PROTECT(t, ehTable); // resolve all exception handler catch types before we acquire // the class lock: for (unsigned i = 0; i < exceptionHandlerTableLength(t, ehTable); ++i) { uint64_t handler = exceptionHandlerTableBody(t, ehTable, i); if (exceptionHandlerCatchType(handler)) { resolveClassInPool (t, clone, exceptionHandlerCatchType(handler) - 1); } } } } ACQUIRE(t, t->m->classLock); if (methodAddress(t, method) != defaultThunk(t)) { return; } finish(t, allocator, &context); if (DebugMethodTree) { fprintf(stderr, "insert method at %p\n", reinterpret_cast(methodCompiled(t, clone))); } // We can't update the MethodCode field on the original method // before it is placed into the method tree, since another thread // might call the method, from which stack unwinding would fail // (since there is not yet an entry in the method tree). However, // we can't insert the original method into the tree before updating // the MethodCode field on it since we rely on that field to // determine its position in the tree. Therefore, we insert the // clone in its place. Later, we'll replace the clone with the // original to save memory. setRoot (t, MethodTree, treeInsert (t, &(context.zone), root(t, MethodTree), methodCompiled(t, clone), clone, root(t, MethodTreeSentinal), compareIpToMethodBounds)); storeStoreMemoryBarrier(); set(t, method, MethodCode, methodCode(t, clone)); if (methodVirtual(t, method)) { classVtable(t, methodClass(t, method), methodOffset(t, method)) = reinterpret_cast(methodCompiled(t, clone)); } // we've compiled the method and inserted it into the tree without // error, so we ensure that the executable area not be deallocated // when we dispose of the context: context.executableAllocator = 0; treeUpdate(t, root(t, MethodTree), methodCompiled(t, clone), method, root(t, MethodTreeSentinal), compareIpToMethodBounds); } object& root(Thread* t, Root root) { return arrayBody(t, processor(static_cast(t))->roots, root); } void setRoot(Thread* t, Root root, object value) { set(t, processor(static_cast(t))->roots, ArrayBody + (root * BytesPerWord), value); } avian::util::FixedAllocator* codeAllocator(MyThread* t) { return &(processor(t)->codeAllocator); } } // namespace local } // namespace namespace vm { Processor* makeProcessor(System* system, Allocator* allocator, const char* crashDumpDirectory, bool useNativeFeatures) { return new (allocator->allocate(sizeof(local::MyProcessor))) local::MyProcessor(system, allocator, crashDumpDirectory, useNativeFeatures); } } // namespace vm ReadyTalk-avian-1e1fff5/src/continuations-x86.S000066400000000000000000000126231231440243200214170ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifdef __x86_64__ #define THREAD_CONTINUATION 2248 #define THREAD_EXCEPTION 80 #define THREAD_EXCEPTION_STACK_ADJUSTMENT 2256 #define THREAD_EXCEPTION_OFFSET 2264 #define THREAD_EXCEPTION_HANDLER 2272 #define CONTINUATION_NEXT 8 #define CONTINUATION_ADDRESS 32 #define CONTINUATION_RETURN_ADDRESS_OFFSET 40 #define CONTINUATION_FRAME_POINTER_OFFSET 48 #define CONTINUATION_LENGTH 56 #define CONTINUATION_BODY 64 // call the next continuation, if any movq THREAD_CONTINUATION(%rbx),%rcx cmpq $0,%rcx je LOCAL(vmInvoke_exit) // allocate a frame of size (continuation.length * BYTES_PER_WORD) // + CALLEE_SAVED_REGISTER_FOOTPRINT movq CONTINUATION_LENGTH(%rcx),%rsi shlq $3,%rsi subq %rsi,%rsp subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp // copy the continuation body into the frame leaq CONTINUATION_BODY(%rcx),%rdi movq $0,%r9 jmp LOCAL(vmInvoke_continuationTest) LOCAL(vmInvoke_continuationLoop): movq (%rdi,%r9,1),%r8 movq %r8,(%rsp,%r9,1) addq $8,%r9 LOCAL(vmInvoke_continuationTest): cmpq %rsi,%r9 jb LOCAL(vmInvoke_continuationLoop) // set the return address to vmInvoke_returnAddress movq CONTINUATION_RETURN_ADDRESS_OFFSET(%rcx),%rdi #if defined __MINGW32__ || defined __CYGWIN32__ leaq GLOBAL(vmInvoke_returnAddress)(%rip),%r10 #else movq GLOBAL(vmInvoke_returnAddress)@GOTPCREL(%rip),%r10 #endif movq %r10,(%rsp,%rdi,1) #ifdef AVIAN_USE_FRAME_POINTER // save the current base pointer in the frame and update it movq CONTINUATION_FRAME_POINTER_OFFSET(%rcx),%rdi movq %rbp,(%rsp,%rdi,1) addq %rsp,%rdi movq %rdi,%rbp #endif // consume the continuation movq CONTINUATION_NEXT(%rcx),%rdi movq %rdi,THREAD_CONTINUATION(%rbx) // call the continuation unless we're handling an exception movq THREAD_EXCEPTION(%rbx),%rsi cmpq $0,%rsi jne LOCAL(vmInvoke_handleException) jmp *CONTINUATION_ADDRESS(%rcx) LOCAL(vmInvoke_handleException): // we're handling an exception - call the exception handler instead movq $0,THREAD_EXCEPTION(%rbx) movq THREAD_EXCEPTION_STACK_ADJUSTMENT(%rbx),%rdi subq %rdi,%rsp movq THREAD_EXCEPTION_OFFSET(%rbx),%rdi movq %rsi,(%rsp,%rdi,1) jmp *THREAD_EXCEPTION_HANDLER(%rbx) LOCAL(vmInvoke_exit): #elif defined __i386__ #define THREAD_CONTINUATION 2160 #define THREAD_EXCEPTION 44 #define THREAD_EXCEPTION_STACK_ADJUSTMENT 2164 #define THREAD_EXCEPTION_OFFSET 2168 #define THREAD_EXCEPTION_HANDLER 2172 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 #define CONTINUATION_RETURN_ADDRESS_OFFSET 20 #define CONTINUATION_FRAME_POINTER_OFFSET 24 #define CONTINUATION_LENGTH 28 #define CONTINUATION_BODY 32 #ifdef AVIAN_USE_FRAME_POINTER # define CONTINUATION_ALIGNMENT_PADDING 8 #else # define CONTINUATION_ALIGNMENT_PADDING 12 #endif // call the next continuation, if any movl THREAD_CONTINUATION(%ebx),%ecx cmpl $0,%ecx je LOCAL(vmInvoke_exit) // allocate a frame of size (continuation.length * BYTES_PER_WORD), // plus stack alignment padding movl CONTINUATION_LENGTH(%ecx),%esi shll $2,%esi leal CONTINUATION_ALIGNMENT_PADDING(%esi),%esi subl %esi,%esp // copy the continuation body into the frame leal CONTINUATION_BODY(%ecx),%edi push %eax push %edx movl $0,%edx jmp LOCAL(vmInvoke_continuationTest) LOCAL(vmInvoke_continuationLoop): movl (%edi,%edx,1),%eax movl %eax,8(%esp,%edx,1) addl $4,%edx LOCAL(vmInvoke_continuationTest): cmpl %esi,%edx jb LOCAL(vmInvoke_continuationLoop) pop %edx pop %eax // set the return address to vmInvoke_returnAddress movl CONTINUATION_RETURN_ADDRESS_OFFSET(%ecx),%edi #if defined __MINGW32__ || defined __CYGWIN32__ movl $GLOBAL(vmInvoke_returnAddress),%esi #else call LOCAL(getPC) # if defined __APPLE__ LOCAL(vmInvoke_offset): leal GLOBAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_offset)(%esi),%esi # else addl $_GLOBAL_OFFSET_TABLE_,%esi movl GLOBAL(vmInvoke_returnAddress)@GOT(%esi),%esi # endif #endif movl %esi,(%esp,%edi,1) #ifdef AVIAN_USE_FRAME_POINTER // save the current base pointer in the frame and update it movl CONTINUATION_FRAME_POINTER_OFFSET(%ecx),%edi movl %ebp,(%esp,%edi,1) addl %esp,%edi movl %edi,%ebp #endif // consume the continuation movl CONTINUATION_NEXT(%ecx),%edi movl %edi,THREAD_CONTINUATION(%ebx) // call the continuation unless we're handling an exception movl THREAD_EXCEPTION(%ebx),%esi cmpl $0,%esi jne LOCAL(vmInvoke_handleException) jmp *CONTINUATION_ADDRESS(%ecx) LOCAL(vmInvoke_handleException): // we're handling an exception - call the exception handler instead movl $0,THREAD_EXCEPTION(%ebx) movl THREAD_EXCEPTION_STACK_ADJUSTMENT(%ebx),%edi subl %edi,%esp movl THREAD_EXCEPTION_OFFSET(%ebx),%edi movl %esi,(%esp,%edi,1) jmp *THREAD_EXCEPTION_HANDLER(%ebx) LOCAL(vmInvoke_exit): #else # error unsupported architecture #endif ReadyTalk-avian-1e1fff5/src/embed.cpp000066400000000000000000000066331231440243200175370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include #include #include #include "avian/embed.h" #ifdef __x86_64__ # define BINARY_LOADER(x) _binary_loader_##x #else # define BINARY_LOADER(x) binary_loader_##x #endif extern "C" const uint8_t BINARY_LOADER(start)[]; extern "C" const uint8_t BINARY_LOADER(end)[]; __declspec(noreturn) void printUsage(const wchar_t* executableName) { wprintf(L"Usage: %s destination.exe classes.jar package.Main\n", executableName); exit(0); } void writeDestinationFile(const wchar_t* filename) { if(FILE* file = _wfopen(filename, L"wb")) { size_t count = BINARY_LOADER(end) - BINARY_LOADER(start); if(count == fwrite(BINARY_LOADER(start), sizeof(BINARY_LOADER(start)[0]), count, file)) { fclose(file); return; } } fprintf(stderr, "Unable to write to destination file\n"); exit(EXIT_FAILURE); } void readFile(std::vector* jarFile, const wchar_t* fileName) { if(FILE* file = _wfopen(fileName, L"rb")) { fseek(file, 0, SEEK_END); jarFile->resize(ftell(file)); fseek(file, 0, SEEK_SET); fread(&jarFile->at(0), 1, jarFile->size(), file); fclose(file); } } bool mkStringSection(std::vector* stringSection, const std::vector& strings, int first, int last) { stringSection->clear(); for(int i = first; i <= last; ++i) { const std::wstring& s = strings.at(i); stringSection->push_back(s.size()); stringSection->insert(stringSection->end(), s.begin(), s.end()); } // pad to 16 entries for(int i = last - first; i < 15; ++i) stringSection->push_back(0); return stringSection->size() > 16; } void writeStringResources(HANDLE hDest, const std::vector& strings) { for(unsigned i = 0; i < strings.size(); i += 16) { std::vector stringSection; if(mkStringSection(&stringSection, strings, i, std::min(i + 15, strings.size() - 1))) UpdateResourceW(hDest, reinterpret_cast(RT_STRING), reinterpret_cast(MAKEINTRESOURCE((i >> 4) + 1)), LANG_NEUTRAL, &stringSection.at(0), sizeof(wchar_t) * stringSection.size()); } } int wmain(int argc, wchar_t* argv[]) { if(argc != 4) printUsage(argv[0]); const wchar_t* destinationName = argv[1]; const wchar_t* classesName = argv[2]; const wchar_t* mainClassName = argv[3]; writeDestinationFile(destinationName); if(HANDLE hDest = BeginUpdateResourceW(destinationName, TRUE)) { std::vector strings; strings.resize(RESID_MAIN_CLASS + 1); strings.at(RESID_MAIN_CLASS) = mainClassName; writeStringResources(hDest, strings); std::vector jarFile; readFile(&jarFile, classesName); UpdateResourceW(hDest, reinterpret_cast(RT_RCDATA), RESID_BOOT_JAR, LANG_NEUTRAL, &jarFile.at(0), jarFile.size()); EndUpdateResource(hDest, FALSE); } return 0; } #ifndef _MSC_VER extern "C" int _CRT_glob; extern "C" void __wgetmainargs(int*, wchar_t***, wchar_t***, int, int*); int main() { wchar_t **enpv, **argv; int argc, si = 0; __wgetmainargs(&argc, &argv, &enpv, _CRT_glob, &si); return wmain(argc, argv); } #endif ReadyTalk-avian-1e1fff5/src/embedded-loader.cpp000066400000000000000000000054331231440243200214550ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include "avian/embed.h" #include "jni.h" #if (defined __MINGW32__) || (defined _MSC_VER) # define EXPORT __declspec(dllexport) # ifdef _MSC_VER # define not ! # endif #else # define EXPORT __attribute__ ((visibility("default"))) \ __attribute__ ((used)) #endif extern "C" { // since we aren't linking against libstdc++, we must implement this // ourselves: void __cxa_pure_virtual(void) { abort(); } EXPORT const uint8_t* bootJar(unsigned* size) { if(HRSRC hResInfo = FindResourceW(NULL, RESID_BOOT_JAR, reinterpret_cast(RT_RCDATA))) { if(HGLOBAL hRes = LoadResource(NULL, hResInfo)) { *size = SizeofResource(NULL, hResInfo); return (const uint8_t*)LockResource(hRes); } } fprintf(stderr, "boot.jar resource not found\n"); *size = 0; return NULL; } } // extern "C" static void getMainClass(char* pName, int maxLen) { if(0 == LoadString(NULL, RESID_MAIN_CLASS, pName, maxLen)) { fprintf(stderr, "Main class not specified\n"); strcpy(pName, "Main"); } } int main(int ac, const char** av) { JavaVMInitArgs vmArgs; vmArgs.version = JNI_VERSION_1_2; vmArgs.nOptions = 1; vmArgs.ignoreUnrecognized = JNI_TRUE; JavaVMOption options[1]; vmArgs.options = options; options[0].optionString = const_cast("-Xbootclasspath:[bootJar]"); JavaVM* vm; void* env; JNI_CreateJavaVM(&vm, &env, &vmArgs); JNIEnv* e = static_cast(env); char mainClass[256]; getMainClass(mainClass, sizeof(mainClass)); jclass c = e->FindClass(mainClass); if (not e->ExceptionCheck()) { jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); if (not e->ExceptionCheck()) { jclass stringClass = e->FindClass("java/lang/String"); if (not e->ExceptionCheck()) { jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0); if (not e->ExceptionCheck()) { for (int i = 1; i < ac; ++i) { e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i])); } e->CallStaticVoidMethod(c, m, a); } else fprintf(stderr, "Couldn't create array\n"); } else fprintf(stderr, "java.lang.String not found\n"); } else fprintf(stderr, "main method not found\n"); } else fprintf(stderr, "Main class not found\n"); int exitCode = 0; if(e->ExceptionCheck()) { exitCode = -1; e->ExceptionDescribe(); e->ExceptionClear(); } vm->DestroyJavaVM(); return exitCode; } ReadyTalk-avian-1e1fff5/src/finder.cpp000066400000000000000000000613371231440243200177340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include #include "avian/zlib-custom.h" #include "avian/finder.h" #include "avian/lzma.h" #include "avian/append.h" using namespace vm; using namespace avian::util; namespace { const bool DebugFind = false; const bool DebugStat = false; class Element { public: class Iterator { public: virtual const char* next(unsigned* size) = 0; virtual void dispose() = 0; }; Element(): next(0) { } virtual Iterator* iterator() = 0; virtual System::Region* find(const char* name) = 0; virtual System::FileType stat(const char* name, unsigned* length, bool tryDirectory) = 0; virtual const char* urlPrefix() = 0; virtual const char* sourceUrl() = 0; virtual void dispose() = 0; Element* next; }; class DirectoryElement: public Element { public: class Iterator: public Element::Iterator { public: Iterator(System* s, Allocator* allocator, const char* name, unsigned skip): s(s), allocator(allocator), name(name), skip(skip), directory(0), last(0), it(0) { if (not s->success(s->open(&directory, name))) { directory = 0; } } virtual const char* next(unsigned* size) { if (it) { const char* v = it->next(size); if (v) { return v; } else { it->dispose(); it = 0; } } if (last) { allocator->free(last, strlen(last) + 1); } if (directory) { for (const char* v = directory->next(); v; v = directory->next()) { if (v[0] != '.') { last = append(allocator, name, "/", v); unsigned length; if (s->stat(last, &length) == System::TypeDirectory) { it = new (allocator->allocate(sizeof(Iterator))) Iterator(s, allocator, last, skip); it->name = last; } const char* result = last + skip; *size = strlen(result); return result; } } } return 0; } virtual void dispose() { directory->dispose(); allocator->free(this, sizeof(*this)); } System* s; Allocator* allocator; const char* name; unsigned skip; System::Directory* directory; const char* last; Iterator* it; }; DirectoryElement(System* s, Allocator* allocator, const char* name): s(s), allocator(allocator), originalName(name), name(s->toAbsolutePath(allocator, name)), urlPrefix_(append(allocator, "file:", this->name, "/")), sourceUrl_(append(allocator, "file:", this->name)) { } virtual Element::Iterator* iterator() { return new (allocator->allocate(sizeof(Iterator))) Iterator(s, allocator, name, strlen(name) + 1); } virtual System::Region* find(const char* name) { const char* file = append(allocator, this->name, "/", name); System::Region* region; System::Status status = s->map(®ion, file); allocator->free(file, strlen(file) + 1); if (s->success(status)) { if (DebugFind) { fprintf(stderr, "found %s in %s\n", name, this->name); } return region; } else { if (DebugFind) { fprintf(stderr, "%s not found in %s\n", name, this->name); } return 0; } } virtual System::FileType stat(const char* name, unsigned* length, bool) { const char* file = append(allocator, this->name, "/", name); System::FileType type = s->stat(file, length); if (DebugStat) { fprintf(stderr, "stat %s in %s: %d\n", name, this->name, type); } allocator->free(file, strlen(file) + 1); return type; } virtual const char* urlPrefix() { return urlPrefix_; } virtual const char* sourceUrl() { return sourceUrl_; } virtual void dispose() { allocator->free(originalName, strlen(originalName) + 1); allocator->free(name, strlen(name) + 1); allocator->free(urlPrefix_, strlen(urlPrefix_) + 1); allocator->free(sourceUrl_, strlen(sourceUrl_) + 1); allocator->free(this, sizeof(*this)); } System* s; Allocator* allocator; const char* originalName; const char* name; const char* urlPrefix_; const char* sourceUrl_; }; class PointerRegion: public System::Region { public: PointerRegion(System* s, Allocator* allocator, const uint8_t* start, size_t length, bool freePointer = false): s(s), allocator(allocator), start_(start), length_(length), freePointer(freePointer) { } virtual const uint8_t* start() { return start_; } virtual size_t length() { return length_; } virtual void dispose() { if (freePointer) { allocator->free(start_, length_); } allocator->free(this, sizeof(*this)); } System* s; Allocator* allocator; const uint8_t* start_; size_t length_; bool freePointer; }; class DataRegion: public System::Region { public: DataRegion(System* s, Allocator* allocator, size_t length): s(s), allocator(allocator), length_(length) { } virtual const uint8_t* start() { return data; } virtual size_t length() { return length_; } virtual void dispose() { allocator->free(this, sizeof(*this) + length_); } System* s; Allocator* allocator; size_t length_; uint8_t data[0]; }; class JarIndex { public: enum CompressionMethod { Stored = 0, Deflated = 8 }; class Entry { public: Entry(uint32_t hash, const uint8_t* entry): hash(hash), entry(entry) {} uint32_t hash; const uint8_t* entry; }; JarIndex(System* s, Allocator* allocator, unsigned capacity): s(s), allocator(allocator), capacity(capacity), position(0), nodes(static_cast*>(allocator->allocate(sizeof(List) * capacity))) { memset(table, 0, sizeof(List*) * capacity); } static JarIndex* make(System* s, Allocator* allocator, unsigned capacity) { return new (allocator->allocate(sizeof(JarIndex) + (sizeof(List*) * capacity))) JarIndex(s, allocator, capacity); } static JarIndex* open(System* s, Allocator* allocator, System::Region* region) { JarIndex* index = make(s, allocator, 32); const uint8_t* start = region->start(); const uint8_t* end = start + region->length(); const uint8_t* p = end - CentralDirectorySearchStart; // Find end of central directory record while (p > start) { if (signature(p) == CentralDirectorySignature) { p = region->start() + centralDirectoryOffset(p); while (p < end) { if (signature(p) == EntrySignature) { index = index->add(Entry(hash(fileName(p), fileNameLength(p)), p)); p = endOfEntry(p); } else { return index; } } } else { p--; } } return index; } JarIndex* add(const Entry& entry) { if (position < capacity) { unsigned i = entry.hash & (capacity - 1); table[i] = new (nodes + (position++)) List(entry, table[i]); return this; } else { JarIndex* index = make(s, allocator, capacity * 2); for (unsigned i = 0; i < capacity; ++i) { index->add(nodes[i].item); } index->add(entry); dispose(); return index; } } List* findNode(const char* name) { unsigned length = strlen(name); unsigned i = hash(name) & (capacity - 1); for (List* n = table[i]; n; n = n->next) { const uint8_t* p = n->item.entry; if (equal(name, length, fileName(p), fileNameLength(p))) { return n; } } return 0; } System::Region* find(const char* name, const uint8_t* start) { List* n = findNode(name); if (n) { const uint8_t* p = n->item.entry; switch (compressionMethod(p)) { case Stored: { return new (allocator->allocate(sizeof(PointerRegion))) PointerRegion(s, allocator, fileData(start + localHeaderOffset(p)), compressedSize(p)); } break; case Deflated: { DataRegion* region = new (allocator->allocate(sizeof(DataRegion) + uncompressedSize(p))) DataRegion(s, allocator, uncompressedSize(p)); z_stream zStream; memset(&zStream, 0, sizeof(z_stream)); zStream.next_in = const_cast(fileData(start + localHeaderOffset(p))); zStream.avail_in = compressedSize(p); zStream.next_out = region->data; zStream.avail_out = region->length(); // -15 means max window size and raw deflate (no zlib wrapper) int r = inflateInit2(&zStream, -15); expect(s, r == Z_OK); r = inflate(&zStream, Z_FINISH); expect(s, r == Z_STREAM_END); inflateEnd(&zStream); return region; } break; default: abort(s); } } return 0; } System::FileType stat(const char* name, unsigned* length, bool tryDirectory) { List* node = findNode(name); if (node) { *length = uncompressedSize(node->item.entry); return System::TypeFile; } else if (tryDirectory) { *length = 0; // try again with '/' appended unsigned length = strlen(name); RUNTIME_ARRAY(char, n, length + 2); memcpy(RUNTIME_ARRAY_BODY(n), name, length); RUNTIME_ARRAY_BODY(n)[length] = '/'; RUNTIME_ARRAY_BODY(n)[length + 1] = 0; node = findNode(RUNTIME_ARRAY_BODY(n)); if (node) { return System::TypeDirectory; } else { return System::TypeDoesNotExist; } } else { *length = 0; return System::TypeDoesNotExist; } } void dispose() { allocator->free(nodes, sizeof(List) * capacity); allocator->free(this, sizeof(*this) + (sizeof(List*) * capacity)); } System* s; Allocator* allocator; unsigned capacity; unsigned position; List* nodes; List* table[0]; }; class JarElement: public Element { public: class Iterator: public Element::Iterator { public: Iterator(System* s, Allocator* allocator, JarIndex* index): s(s), allocator(allocator), index(index), position(0) { } virtual const char* next(unsigned* size) { if (position < index->position) { List* n = index->nodes + (position++); *size = fileNameLength(n->item.entry); return reinterpret_cast(fileName(n->item.entry)); } else { return 0; } } virtual void dispose() { allocator->free(this, sizeof(*this)); } System* s; Allocator* allocator; JarIndex* index; unsigned position; }; JarElement(System* s, Allocator* allocator, const char* name, bool canonicalizePath = true): s(s), allocator(allocator), originalName(name), name(name and canonicalizePath ? s->toAbsolutePath(allocator, name) : name), urlPrefix_(this->name ? append(allocator, "jar:file:", this->name, "!/") : 0), sourceUrl_(this->name ? append(allocator, "file:", this->name) : 0), region(0), index(0) { } JarElement(System* s, Allocator* allocator, const uint8_t* jarData, unsigned jarLength): s(s), allocator(allocator), originalName(0), name(0), urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0), sourceUrl_(name ? append(allocator, "file:", name) : 0), region(new (allocator->allocate(sizeof(PointerRegion))) PointerRegion(s, allocator, jarData, jarLength)), index(JarIndex::open(s, allocator, region)) { } virtual Element::Iterator* iterator() { init(); return new (allocator->allocate(sizeof(Iterator))) Iterator(s, allocator, index); } virtual void init() { if (index == 0) { System::Region* r; if (s->success(s->map(&r, name))) { region = r; index = JarIndex::open(s, allocator, r); } } } virtual System::Region* find(const char* name) { init(); while (*name == '/') name++; System::Region* r = (index ? index->find(name, region->start()) : 0); if (DebugFind) { if (r) { fprintf(stderr, "found %s in %s\n", name, this->name); } else { fprintf(stderr, "%s not found in %s\n", name, this->name); } } return r; } virtual System::FileType stat(const char* name, unsigned* length, bool tryDirectory) { init(); while (*name == '/') name++; System::FileType type = (index ? index->stat(name, length, tryDirectory) : System::TypeDoesNotExist); if (DebugStat) { fprintf(stderr, "stat %s in %s: %d\n", name, this->name, type); } return type; } virtual const char* urlPrefix() { return urlPrefix_; } virtual const char* sourceUrl() { return sourceUrl_; } virtual void dispose() { dispose(sizeof(*this)); } virtual void dispose(unsigned size) { if (name) { if (originalName != name) { allocator->free(originalName, strlen(originalName) + 1); } allocator->free(name, strlen(name) + 1); allocator->free(urlPrefix_, strlen(urlPrefix_) + 1); allocator->free(sourceUrl_, strlen(sourceUrl_) + 1); } if (index) { index->dispose(); } if (region) { region->dispose(); } allocator->free(this, size); } System* s; Allocator* allocator; const char* originalName; const char* name; const char* urlPrefix_; const char* sourceUrl_; System::Region* region; JarIndex* index; }; class BuiltinElement: public JarElement { public: BuiltinElement(System* s, Allocator* allocator, const char* name, const char* libraryName): JarElement(s, allocator, name, false), libraryName(libraryName ? copy(allocator, libraryName) : 0) { } virtual void init() { if (index == 0) { if (s->success(s->load(&library, libraryName))) { bool lzma = strncmp("lzma.", name, 5) == 0; const char* symbolName = lzma ? name + 5 : name; void* p = library->resolve(symbolName); if (p) { uint8_t* (*function)(unsigned*); memcpy(&function, &p, BytesPerWord); unsigned size; uint8_t* data = function(&size); if (data) { bool freePointer; if (lzma) { #ifdef AVIAN_USE_LZMA unsigned outSize; data = decodeLZMA(s, allocator, data, size, &outSize); size = outSize; freePointer = true; #else abort(s); #endif } else { freePointer = false; } region = new (allocator->allocate(sizeof(PointerRegion))) PointerRegion(s, allocator, data, size, freePointer); index = JarIndex::open(s, allocator, region); } else if (DebugFind) { fprintf(stderr, "%s in %s returned null\n", symbolName, libraryName); } } else if (DebugFind) { fprintf(stderr, "unable to find %s in %s\n", symbolName, libraryName); } } } } virtual const char* urlPrefix() { return "avianvmresource:"; } virtual const char* sourceUrl() { return 0; } virtual void dispose() { library->disposeAll(); if (libraryName) { allocator->free(libraryName, strlen(libraryName) + 1); } JarElement::dispose(sizeof(*this)); } System::Library* library; const char* libraryName; }; void add(Element** first, Element** last, Element* e) { if (*last) { (*last)->next = e; } else { *first = e; } *last = e; } unsigned baseName(const char* name, char fileSeparator) { const char* p = name; const char* last = 0; while (*p) { if (*p == fileSeparator) { last = p; } ++p; } return last ? (last + 1) - name : 0; } void add(System* s, Element** first, Element** last, Allocator* allocator, const char* name, unsigned nameLength, const char* bootLibrary); void addTokens(System* s, Element** first, Element** last, Allocator* allocator, const char* jarName, unsigned jarNameBase, const char* tokens, unsigned tokensLength, const char* bootLibrary) { for (Tokenizer t(String(tokens, tokensLength), ' '); t.hasMore();) { String token(t.next()); RUNTIME_ARRAY(char, n, jarNameBase + token.length + 1); memcpy(RUNTIME_ARRAY_BODY(n), jarName, jarNameBase); memcpy(RUNTIME_ARRAY_BODY(n) + jarNameBase, token.text, token.length); RUNTIME_ARRAY_BODY(n)[jarNameBase + token.length] = 0; add(s, first, last, allocator, RUNTIME_ARRAY_BODY(n), jarNameBase + token.length, bootLibrary); } } bool continuationLine(const uint8_t* base, unsigned total, unsigned* start, unsigned* length) { return readLine(base, total, start, length) and *length > 0 and base[*start] == ' '; } void addJar(System* s, Element** first, Element** last, Allocator* allocator, const char* name, const char* bootLibrary) { if (DebugFind) { fprintf(stderr, "add jar %s\n", name); } JarElement* e = new (allocator->allocate(sizeof(JarElement))) JarElement(s, allocator, name); unsigned nameBase = baseName(name, s->fileSeparator()); add(first, last, e); System::Region* region = e->find("META-INF/MANIFEST.MF"); if (region) { unsigned start = 0; unsigned length; while (readLine(region->start(), region->length(), &start, &length)) { unsigned multilineTotal = 0; const unsigned PrefixLength = 12; if (length > PrefixLength and strncmp("Class-Path: ", reinterpret_cast (region->start() + start), PrefixLength) == 0) { { unsigned nextStart = start + length; unsigned nextLength; while (continuationLine (region->start(), region->length(), &nextStart, &nextLength)) { multilineTotal += nextLength; nextStart += nextLength; } } const char* line = reinterpret_cast (region->start() + start + PrefixLength); unsigned lineLength = length - PrefixLength; if (multilineTotal) { RUNTIME_ARRAY (char, n, (length - PrefixLength) + multilineTotal + 1); memcpy(RUNTIME_ARRAY_BODY(n), line, lineLength); unsigned offset = lineLength; { unsigned nextStart = start + length; unsigned nextLength; while (continuationLine (region->start(), region->length(), &nextStart, &nextLength)) { unsigned continuationLength = nextLength - 1; memcpy(RUNTIME_ARRAY_BODY(n) + offset, region->start() + nextStart + 1, continuationLength); offset += continuationLength; nextStart += nextLength; } } addTokens(s, first, last, allocator, name, nameBase, RUNTIME_ARRAY_BODY(n), offset, bootLibrary); } else { addTokens(s, first, last, allocator, name, nameBase, line, lineLength, bootLibrary); } } start += length + multilineTotal; } region->dispose(); } } void add(System* s, Element** first, Element** last, Allocator* allocator, const char* token, unsigned tokenLength, const char* bootLibrary) { if (*token == '[' and token[tokenLength - 1] == ']') { char* name = static_cast(allocator->allocate(tokenLength - 1)); memcpy(name, token + 1, tokenLength - 1); name[tokenLength - 2] = 0; if (DebugFind) { fprintf(stderr, "add builtin %s\n", name); } add(first, last, new (allocator->allocate(sizeof(BuiltinElement))) BuiltinElement(s, allocator, name, bootLibrary)); } else { char* name = static_cast(allocator->allocate(tokenLength + 1)); memcpy(name, token, tokenLength); name[tokenLength] = 0; unsigned length; switch (s->stat(name, &length)) { case System::TypeFile: { addJar(s, first, last, allocator, name, bootLibrary); } break; case System::TypeDirectory: { if (DebugFind) { fprintf(stderr, "add directory %s\n", name); } add(first, last, new (allocator->allocate(sizeof(DirectoryElement))) DirectoryElement(s, allocator, name)); } break; default: { if (DebugFind) { fprintf(stderr, "ignore nonexistent %s\n", name); } allocator->free(name, strlen(name) + 1); } break; } } } Element* parsePath(System* s, Allocator* allocator, const char* path, const char* bootLibrary) { Element* first = 0; Element* last = 0; for (Tokenizer t(path, s->pathSeparator()); t.hasMore();) { String token(t.next()); add(s, &first, &last, allocator, token.text, token.length, bootLibrary); } return first; } class MyIterator: public Finder::IteratorImp { public: MyIterator(System* s, Allocator* allocator, Element* path): s(s), allocator(allocator), e(path ? path->next : 0), it(path ? path->iterator() : 0) { } virtual const char* next(unsigned* size) { while (it) { const char* v = it->next(size); if (v) { return v; } else { it->dispose(); if (e) { it = e->iterator(); e = e->next; } else { it = 0; } } } return 0; } virtual void dispose() { if (it) it->dispose(); allocator->free(this, sizeof(*this)); } System* s; Allocator* allocator; Element* e; Element::Iterator* it; }; class MyFinder: public Finder { public: MyFinder(System* system, Allocator* allocator, const char* path, const char* bootLibrary): system(system), allocator(allocator), path_(parsePath(system, allocator, path, bootLibrary)), pathString(copy(allocator, path)) { } MyFinder(System* system, Allocator* allocator, const uint8_t* jarData, unsigned jarLength): system(system), allocator(allocator), path_(new (allocator->allocate(sizeof(JarElement))) JarElement(system, allocator, jarData, jarLength)), pathString(0) { } virtual IteratorImp* iterator() { return new (allocator->allocate(sizeof(MyIterator))) MyIterator(system, allocator, path_); } virtual System::Region* find(const char* name) { for (Element* e = path_; e; e = e->next) { System::Region* r = e->find(name); if (r) { return r; } } return 0; } virtual System::FileType stat(const char* name, unsigned* length, bool tryDirectory) { for (Element* e = path_; e; e = e->next) { System::FileType type = e->stat(name, length, tryDirectory); if (type != System::TypeDoesNotExist) { return type; } } return System::TypeDoesNotExist; } virtual const char* urlPrefix(const char* name) { void *finderElementPtr = NULL; return nextUrlPrefix(name, finderElementPtr); } virtual const char* nextUrlPrefix(const char* name, void *&finderElementPtr) { Element *&e = reinterpret_cast(finderElementPtr); e = e ? e->next : path_; for (; e; e = e->next) { unsigned length; System::FileType type = e->stat(name, &length, true); if (type != System::TypeDoesNotExist) { return e->urlPrefix(); } } return 0; } virtual const char* sourceUrl(const char* name) { for (Element* e = path_; e; e = e->next) { unsigned length; System::FileType type = e->stat(name, &length, true); if (type != System::TypeDoesNotExist) { return e->sourceUrl(); } } return 0; } virtual const char* path() { return pathString; } virtual void dispose() { for (Element* e = path_; e;) { Element* t = e; e = e->next; t->dispose(); } if (pathString) { allocator->free(pathString, strlen(pathString) + 1); } allocator->free(this, sizeof(*this)); } System* system; Allocator* allocator; Element* path_; const char* pathString; }; } // namespace namespace vm { AVIAN_EXPORT Finder* makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary) { return new (a->allocate(sizeof(MyFinder))) MyFinder(s, a, path, bootLibrary); } Finder* makeFinder(System* s, Allocator* a, const uint8_t* jarData, unsigned jarLength) { return new (a->allocate(sizeof(MyFinder))) MyFinder(s, a, jarData, jarLength); } } // namespace vm ReadyTalk-avian-1e1fff5/src/heap/000077500000000000000000000000001231440243200166645ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/heap/heap.cpp000066400000000000000000001347331231440243200203200ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include "avian/common.h" #include "avian/arch.h" #include using namespace vm; using namespace avian::util; namespace { namespace local { const unsigned Top = ~static_cast(0); const unsigned InitialGen2CapacityInBytes = 4 * 1024 * 1024; const unsigned InitialTenuredFixieCeilingInBytes = 4 * 1024 * 1024; const bool Verbose = false; const bool Verbose2 = false; const bool Debug = false; const bool DebugFixies = false; #ifdef NDEBUG const bool DebugAllocation = false; #else const bool DebugAllocation = true; #endif #define ACQUIRE(x) MutexLock MAKE_NAME(monitorLock_) (x) class MutexLock { public: MutexLock(System::Mutex* m): m(m) { m->acquire(); } ~MutexLock() { m->release(); } private: System::Mutex* m; }; class Context; Aborter* getAborter(Context* c); void* tryAllocate(Context* c, unsigned size); void* allocate(Context* c, unsigned size); void* allocate(Context* c, unsigned size, bool limit); void free(Context* c, const void* p, unsigned size); #ifdef USE_ATOMIC_OPERATIONS inline void markBitAtomic(uintptr_t* map, unsigned i) { uintptr_t* p = map + wordOf(i); uintptr_t v = static_cast(1) << bitOf(i); for (uintptr_t old = *p; not atomicCompareAndSwap(p, old, old | v); old = *p) { } } #endif // USE_ATOMIC_OPERATIONS inline void* get(void* o, unsigned offsetInWords) { return maskAlignedPointer(fieldAtOffset(o, offsetInWords * BytesPerWord)); } inline void** getp(void* o, unsigned offsetInWords) { return &fieldAtOffset(o, offsetInWords * BytesPerWord); } inline void set(void** o, void* value) { *o = reinterpret_cast (reinterpret_cast(value) | (reinterpret_cast(*o) & (~PointerMask))); } inline void set(void* o, unsigned offsetInWords, void* value) { set(getp(o, offsetInWords), value); } class Segment { public: class Map { public: class Iterator { public: Map* map; unsigned index; unsigned limit; Iterator(Map* map, unsigned start, unsigned end): map(map) { assert(map->segment->context, map->bitsPerRecord == 1); assert(map->segment->context, map->segment); assert(map->segment->context, start <= map->segment->position()); if (end > map->segment->position()) end = map->segment->position(); index = map->indexOf(start); limit = map->indexOf(end); if ((end - start) % map->scale) ++ limit; } bool hasMore() { unsigned word = wordOf(index); unsigned bit = bitOf(index); unsigned wordLimit = wordOf(limit); unsigned bitLimit = bitOf(limit); for (; word <= wordLimit and (word < wordLimit or bit < bitLimit); ++word) { uintptr_t w = map->data[word]; if (2) { for (; bit < BitsPerWord and (word < wordLimit or bit < bitLimit); ++bit) { if (w & (static_cast(1) << bit)) { index = ::indexOf(word, bit); // printf("hit at index %d\n", index); return true; } else { // printf("miss at index %d\n", indexOf(word, bit)); } } } bit = 0; } index = limit; return false; } unsigned next() { assert(map->segment->context, hasMore()); assert(map->segment->context, map->segment); return (index++) * map->scale; } }; Segment* segment; Map* child; uintptr_t* data; unsigned bitsPerRecord; unsigned scale; bool clearNewData; Map(Segment* segment, uintptr_t* data, unsigned bitsPerRecord, unsigned scale, Map* child, bool clearNewData): segment(segment), child(child), data(data), bitsPerRecord(bitsPerRecord), scale(scale), clearNewData(clearNewData) { } Map(Segment* segment, unsigned bitsPerRecord, unsigned scale, Map* child, bool clearNewData): segment(segment), child(child), data(0), bitsPerRecord(bitsPerRecord), scale(scale), clearNewData(clearNewData) { } void init() { assert(segment->context, bitsPerRecord); assert(segment->context, scale); assert(segment->context, powerOfTwo(scale)); if (data == 0) { data = segment->data + segment->capacity() + calculateOffset(segment->capacity()); } if (clearNewData) { memset(data, 0, size() * BytesPerWord); } if (child) { child->init(); } } unsigned calculateOffset(unsigned capacity) { unsigned n = 0; if (child) n += child->calculateFootprint(capacity); return n; } static unsigned calculateSize(Context* c UNUSED, unsigned capacity, unsigned scale, unsigned bitsPerRecord) { unsigned result = ceilingDivide(ceilingDivide(capacity, scale) * bitsPerRecord, BitsPerWord); assert(c, result); return result; } unsigned calculateSize(unsigned capacity) { return calculateSize(segment->context, capacity, scale, bitsPerRecord); } unsigned size() { return calculateSize(segment->capacity()); } unsigned calculateFootprint(unsigned capacity) { unsigned n = calculateSize(capacity); if (child) n += child->calculateFootprint(capacity); return n; } void replaceWith(Map* m) { assert(segment->context, bitsPerRecord == m->bitsPerRecord); assert(segment->context, scale == m->scale); data = m->data; m->segment = 0; m->data = 0; if (child) child->replaceWith(m->child); } unsigned indexOf(unsigned segmentIndex) { return (segmentIndex / scale) * bitsPerRecord; } unsigned indexOf(void* p) { assert(segment->context, segment->almostContains(p)); assert(segment->context, segment->capacity()); return indexOf(segment->indexOf(p)); } void clearBit(unsigned i) { assert(segment->context, wordOf(i) < size()); vm::clearBit(data, i); } void setBit(unsigned i) { assert(segment->context, wordOf(i) < size()); vm::markBit(data, i); } void clearOnlyIndex(unsigned index) { clearBits(data, bitsPerRecord, index); } void clearOnly(unsigned segmentIndex) { clearOnlyIndex(indexOf(segmentIndex)); } void clearOnly(void* p) { clearOnlyIndex(indexOf(p)); } void clear(void* p) { clearOnly(p); if (child) child->clear(p); } void setOnlyIndex(unsigned index, unsigned v = 1) { setBits(data, bitsPerRecord, index, v); } void setOnly(unsigned segmentIndex, unsigned v = 1) { setOnlyIndex(indexOf(segmentIndex), v); } void setOnly(void* p, unsigned v = 1) { setOnlyIndex(indexOf(p), v); } void set(void* p, unsigned v = 1) { setOnly(p, v); assert(segment->context, get(p) == v); if (child) child->set(p, v); } #ifdef USE_ATOMIC_OPERATIONS void markAtomic(void* p) { assert(segment->context, bitsPerRecord == 1); markBitAtomic(data, indexOf(p)); assert(segment->context, getBit(data, indexOf(p))); if (child) child->markAtomic(p); } #endif unsigned get(void* p) { return getBits(data, bitsPerRecord, indexOf(p)); } }; Context* context; uintptr_t* data; unsigned position_; unsigned capacity_; Map* map; Segment(Context* context, Map* map, unsigned desired, unsigned minimum, int64_t available = INT64_MAX): context(context), data(0), position_(0), capacity_(0), map(map) { if (desired) { if (minimum == 0) { minimum = 1; } assert(context, desired >= minimum); capacity_ = desired; if (static_cast(footprint(capacity_)) > available) { unsigned top = capacity_; unsigned bottom = minimum; unsigned target = available; while (true) { if (static_cast(footprint(capacity_)) > target) { if (bottom == capacity_) { break; } else if (static_cast(footprint(capacity_ - 1)) <= target) { -- capacity_; break; } top = capacity_; capacity_ = avg(bottom, capacity_); } else if (static_cast(footprint(capacity_)) < target) { if (top == capacity_ or static_cast(footprint(capacity_ + 1)) >= target) { break; } bottom = capacity_; capacity_ = avg(top, capacity_); } else { break; } } } while (data == 0) { data = static_cast (local::allocate (context, (footprint(capacity_)) * BytesPerWord, false)); if (data == 0) { if (capacity_ > minimum) { capacity_ = avg(minimum, capacity_); if (capacity_ == 0) { break; } } else { data = static_cast (local::allocate (context, (footprint(capacity_)) * BytesPerWord)); } } } if (map) { map->init(); } } } Segment(Context* context, Map* map, uintptr_t* data, unsigned position, unsigned capacity): context(context), data(data), position_(position), capacity_(capacity), map(map) { if (map) { map->init(); } } unsigned footprint(unsigned capacity) { return capacity + (map and capacity ? map->calculateFootprint(capacity) : 0); } unsigned capacity() { return capacity_; } unsigned position() { return position_; } unsigned remaining() { return capacity() - position(); } void replaceWith(Segment* s) { if (data) { free(context, data, (footprint(capacity())) * BytesPerWord); } data = s->data; s->data = 0; position_ = s->position_; s->position_ = 0; capacity_ = s->capacity_; s->capacity_ = 0; if (s->map) { if (map) { map->replaceWith(s->map); s->map = 0; } else { abort(context); } } else { assert(context, map == 0); } } bool contains(void* p) { return position() and p >= data and p < data + position(); } bool almostContains(void* p) { return contains(p) or p == data + position(); } void* get(unsigned offset) { assert(context, offset <= position()); return data + offset; } unsigned indexOf(void* p) { assert(context, almostContains(p)); return static_cast(p) - data; } void* allocate(unsigned size) { assert(context, size); assert(context, position() + size <= capacity()); void* p = data + position(); position_ += size; return p; } void dispose() { if (data) { free(context, data, (footprint(capacity())) * BytesPerWord); } data = 0; map = 0; } }; class Fixie { public: static const unsigned HasMask = 1 << 0; static const unsigned Marked = 1 << 1; static const unsigned Dirty = 1 << 2; static const unsigned Dead = 1 << 3; Fixie(Context* c, unsigned size, bool hasMask, Fixie** handle, bool immortal): age(immortal ? FixieTenureThreshold + 1 : 0), flags(hasMask ? HasMask : 0), size(size), next(0), handle(0) { memset(mask(), 0, maskSize(size, hasMask)); add(c, handle); if (DebugFixies) { fprintf(stderr, "make fixie %p of size %d\n", this, totalSize()); } } bool immortal() { return age == FixieTenureThreshold + 1; } void add(Context* c UNUSED, Fixie** handle) { assert(c, this->handle == 0); assert(c, next == 0); this->handle = handle; if (handle) { next = *handle; if (next) next->handle = &next; *handle = this; } else { next = 0; } } void remove(Context* c UNUSED) { if (handle) { assert(c, *handle == this); *handle = next; } if (next) { next->handle = handle; } next = 0; handle = 0; } void move(Context* c, Fixie** handle) { if (DebugFixies) { fprintf(stderr, "move fixie %p\n", this); } remove(c); add(c, handle); } void** body() { return static_cast(static_cast(body_)); } uintptr_t* mask() { return body_ + size; } static unsigned maskSize(unsigned size, bool hasMask) { return hasMask * ceilingDivide(size, BitsPerWord) * BytesPerWord; } static unsigned totalSize(unsigned size, bool hasMask) { return sizeof(Fixie) + (size * BytesPerWord) + maskSize(size, hasMask); } unsigned totalSize() { return totalSize(size, hasMask()); } bool hasMask() { return (flags & HasMask) != 0; } bool marked() { return (flags & Marked) != 0; } void marked(bool v) { if (v) { flags |= Marked; } else { flags &= ~Marked; } } bool dirty() { return (flags & Dirty) != 0; } void dirty(bool v) { if (v) { flags |= Dirty; } else { flags &= ~Dirty; } } bool dead() { return (flags & Dead) != 0; } void dead(bool v) { if (v) { flags |= Dead; } else { flags &= ~Dead; } } // be sure to update e.g. TargetFixieSizeInBytes in bootimage.cpp if // you add/remove/change fields in this class: uint16_t age; uint16_t flags; uint32_t size; Fixie* next; Fixie** handle; uintptr_t body_[0]; }; Fixie* fixie(void* body) { return static_cast(body) - 1; } void free(Context* c, Fixie** fixies, bool resetImmortal = false); class Context { public: Context(System* system, unsigned limit): system(system), client(0), count(0), limit(limit), lock(0), immortalHeapStart(0), immortalHeapEnd(0), ageMap(&gen1, max(1, log(TenureThreshold)), 1, 0, false), gen1(this, &ageMap, 0, 0), nextAgeMap(&nextGen1, max(1, log(TenureThreshold)), 1, 0, false), nextGen1(this, &nextAgeMap, 0, 0), pointerMap(&gen2, 1, 1, 0, true), pageMap(&gen2, 1, LikelyPageSizeInBytes / BytesPerWord, &pointerMap, true), heapMap(&gen2, 1, pageMap.scale * 1024, &pageMap, true), gen2(this, &heapMap, 0, 0), nextPointerMap(&nextGen2, 1, 1, 0, true), nextPageMap(&nextGen2, 1, LikelyPageSizeInBytes / BytesPerWord, &nextPointerMap, true), nextHeapMap(&nextGen2, 1, nextPageMap.scale * 1024, &nextPageMap, true), nextGen2(this, &nextHeapMap, 0, 0), gen2Base(0), incomingFootprint(0), pendingAllocation(0), tenureFootprint(0), gen1Padding(0), tenurePadding(0), gen2Padding(0), fixieTenureFootprint(0), untenuredFixieFootprint(0), tenuredFixieFootprint(0), tenuredFixieCeiling(InitialTenuredFixieCeilingInBytes), mode(Heap::MinorCollection), fixies(0), tenuredFixies(0), dirtyTenuredFixies(0), markedFixies(0), visitedFixies(0), lastCollectionTime(system->now()), totalCollectionTime(0), totalTime(0), limitWasExceeded(false) { if (not system->success(system->make(&lock))) { system->abort(); } } void dispose() { gen1.dispose(); nextGen1.dispose(); gen2.dispose(); nextGen2.dispose(); lock->dispose(); } void disposeFixies() { free(this, &tenuredFixies, true); free(this, &dirtyTenuredFixies, true); free(this, &fixies, true); } System* system; Heap::Client* client; unsigned count; unsigned limit; System::Mutex* lock; uintptr_t* immortalHeapStart; uintptr_t* immortalHeapEnd; Segment::Map ageMap; Segment gen1; Segment::Map nextAgeMap; Segment nextGen1; Segment::Map pointerMap; Segment::Map pageMap; Segment::Map heapMap; Segment gen2; Segment::Map nextPointerMap; Segment::Map nextPageMap; Segment::Map nextHeapMap; Segment nextGen2; unsigned gen2Base; unsigned incomingFootprint; int pendingAllocation; unsigned tenureFootprint; unsigned gen1Padding; unsigned tenurePadding; unsigned gen2Padding; unsigned fixieTenureFootprint; unsigned untenuredFixieFootprint; unsigned tenuredFixieFootprint; unsigned tenuredFixieCeiling; Heap::CollectionType mode; Fixie* fixies; Fixie* tenuredFixies; Fixie* dirtyTenuredFixies; Fixie* markedFixies; Fixie* visitedFixies; int64_t lastCollectionTime; int64_t totalCollectionTime; int64_t totalTime; bool limitWasExceeded; }; const char* segment(Context* c, void* p) { if (c->gen1.contains(p)) { return "gen1"; } else if (c->nextGen1.contains(p)) { return "nextGen1"; } else if (c->gen2.contains(p)) { return "gen2"; } else if (c->nextGen2.contains(p)) { return "nextGen2"; } else { return "none"; } } inline Aborter* getAborter(Context* c) { return c->system; } inline unsigned minimumNextGen1Capacity(Context* c) { return c->gen1.position() - c->tenureFootprint + c->incomingFootprint + c->gen1Padding; } inline unsigned minimumNextGen2Capacity(Context* c) { return c->gen2.position() + c->tenureFootprint + c->tenurePadding + c->gen2Padding; } inline bool oversizedGen2(Context* c) { return c->gen2.capacity() > (InitialGen2CapacityInBytes / BytesPerWord) and c->gen2.position() < (c->gen2.capacity() / 4); } inline void initNextGen1(Context* c) { new (&(c->nextAgeMap)) Segment::Map (&(c->nextGen1), max(1, log(TenureThreshold)), 1, 0, false); unsigned minimum = minimumNextGen1Capacity(c); unsigned desired = minimum; new (&(c->nextGen1)) Segment(c, &(c->nextAgeMap), desired, minimum); if (Verbose2) { fprintf(stderr, "init nextGen1 to %d bytes\n", c->nextGen1.capacity() * BytesPerWord); } } inline void initNextGen2(Context* c) { new (&(c->nextPointerMap)) Segment::Map (&(c->nextGen2), 1, 1, 0, true); new (&(c->nextPageMap)) Segment::Map (&(c->nextGen2), 1, LikelyPageSizeInBytes / BytesPerWord, &(c->nextPointerMap), true); new (&(c->nextHeapMap)) Segment::Map (&(c->nextGen2), 1, c->pageMap.scale * 1024, &(c->nextPageMap), true); unsigned minimum = minimumNextGen2Capacity(c); unsigned desired = minimum; if (not oversizedGen2(c)) { desired *= 2; } if (desired < InitialGen2CapacityInBytes / BytesPerWord) { desired = InitialGen2CapacityInBytes / BytesPerWord; } new (&(c->nextGen2)) Segment (c, &(c->nextHeapMap), desired, minimum, static_cast(c->limit / BytesPerWord) - (static_cast(c->count / BytesPerWord) - c->gen2.footprint(c->gen2.capacity()) - c->gen1.footprint(c->gen1.capacity()) + c->pendingAllocation)); if (Verbose2) { fprintf(stderr, "init nextGen2 to %d bytes\n", c->nextGen2.capacity() * BytesPerWord); } } inline bool fresh(Context* c, void* o) { return c->nextGen1.contains(o) or c->nextGen2.contains(o) or (c->gen2.contains(o) and c->gen2.indexOf(o) >= c->gen2Base); } inline bool wasCollected(Context* c, void* o) { return o and (not fresh(c, o)) and fresh(c, get(o, 0)); } inline void* follow(Context* c UNUSED, void* o) { assert(c, wasCollected(c, o)); return fieldAtOffset(o, 0); } inline void*& parent(Context* c UNUSED, void* o) { assert(c, wasCollected(c, o)); return fieldAtOffset(o, BytesPerWord); } inline uintptr_t* bitset(Context* c UNUSED, void* o) { assert(c, wasCollected(c, o)); return &fieldAtOffset(o, BytesPerWord * 2); } void free(Context* c, Fixie** fixies, bool resetImmortal) { for (Fixie** p = fixies; *p;) { Fixie* f = *p; if (f->immortal()) { if (resetImmortal) { if (DebugFixies) { fprintf(stderr, "reset immortal fixie %p\n", f); } *p = f->next; memset(f->mask(), 0, Fixie::maskSize(f->size, f->hasMask())); f->next = 0; f->handle = 0; f->marked(false); f->dirty(false); } else { p = &(f->next); } } else { *p = f->next; if (DebugFixies) { fprintf(stderr, "free fixie %p\n", f); } free(c, f, f->totalSize()); } } } void kill(Fixie* fixies) { for (Fixie* f = fixies; f; f = f->next) { if (! f->immortal()) { f->dead(true); } } } void killFixies(Context* c) { assert(c, c->markedFixies == 0); if (c->mode == Heap::MajorCollection) { kill(c->tenuredFixies); kill(c->dirtyTenuredFixies); } kill(c->fixies); } void sweepFixies(Context* c) { assert(c, c->markedFixies == 0); if (c->mode == Heap::MajorCollection) { free(c, &(c->tenuredFixies)); free(c, &(c->dirtyTenuredFixies)); c->tenuredFixieFootprint = 0; } free(c, &(c->fixies)); c->untenuredFixieFootprint = 0; while (c->visitedFixies) { Fixie* f = c->visitedFixies; f->remove(c); if (not f->immortal()) { ++ f->age; if (f->age > FixieTenureThreshold) { f->age = FixieTenureThreshold; } else if (static_cast(f->age + 1) == FixieTenureThreshold) { c->fixieTenureFootprint += f->totalSize(); } } if (f->age >= FixieTenureThreshold) { if (DebugFixies) { fprintf(stderr, "tenure fixie %p (dirty: %d)\n", f, f->dirty()); } if (not f->immortal()) { c->tenuredFixieFootprint += f->totalSize(); } if (f->dirty()) { f->add(c, &(c->dirtyTenuredFixies)); } else { f->add(c, &(c->tenuredFixies)); } } else { c->untenuredFixieFootprint += f->totalSize(); f->add(c, &(c->fixies)); } f->marked(false); } c->tenuredFixieCeiling = max (c->tenuredFixieFootprint * 2, InitialTenuredFixieCeilingInBytes); } inline void* copyTo(Context* c, Segment* s, void* o, unsigned size) { assert(c, s->remaining() >= size); void* dst = s->allocate(size); c->client->copy(o, dst); return dst; } bool immortalHeapContains(Context* c, void* p) { return p < c->immortalHeapEnd and p >= c->immortalHeapStart; } void* copy2(Context* c, void* o) { unsigned size = c->client->copiedSizeInWords(o); if (c->gen2.contains(o)) { assert(c, c->mode == Heap::MajorCollection); return copyTo(c, &(c->nextGen2), o, size); } else if (c->gen1.contains(o)) { unsigned age = c->ageMap.get(o); if (age == TenureThreshold) { if (c->mode == Heap::MinorCollection) { assert(c, c->gen2.remaining() >= size); if (c->gen2Base == Top) { c->gen2Base = c->gen2.position(); } return copyTo(c, &(c->gen2), o, size); } else { return copyTo(c, &(c->nextGen2), o, size); } } else { o = copyTo(c, &(c->nextGen1), o, size); c->nextAgeMap.setOnly(o, age + 1); if (age + 1 == TenureThreshold) { c->tenureFootprint += size; } return o; } } else { assert(c, not c->nextGen1.contains(o)); assert(c, not c->nextGen2.contains(o)); assert(c, not immortalHeapContains(c, o)); o = copyTo(c, &(c->nextGen1), o, size); c->nextAgeMap.clear(o); return o; } } void* copy(Context* c, void* o) { void* r = copy2(c, o); if (Debug) { fprintf(stderr, "copy %p (%s) to %p (%s)\n", o, segment(c, o), r, segment(c, r)); } // leave a pointer to the copy in the original fieldAtOffset(o, 0) = r; return r; } void* update3(Context* c, void* o, bool* needsVisit) { if (c->client->isFixed(o)) { Fixie* f = fixie(o); if ((not f->marked()) and (c->mode == Heap::MajorCollection or f->age < FixieTenureThreshold)) { if (DebugFixies) { fprintf(stderr, "mark fixie %p\n", f); } f->marked(true); f->dead(false); f->move(c, &(c->markedFixies)); } *needsVisit = false; return o; } else if (immortalHeapContains(c, o)) { *needsVisit = false; return o; } else if (wasCollected(c, o)) { *needsVisit = false; return follow(c, o); } else { *needsVisit = true; return copy(c, o); } } void* update2(Context* c, void* o, bool* needsVisit) { if (c->mode == Heap::MinorCollection and c->gen2.contains(o)) { *needsVisit = false; return o; } return update3(c, o, needsVisit); } void markDirty(Context* c, Fixie* f) { if (not f->dirty()) { #ifdef USE_ATOMIC_OPERATIONS ACQUIRE(c->lock); #endif if (not f->dirty()) { f->dirty(true); f->move(c, &(c->dirtyTenuredFixies)); } } } void markClean(Context* c, Fixie* f) { if (f->dirty()) { f->dirty(false); if (f->immortal()) { f->remove(c); } else { f->move(c, &(c->tenuredFixies)); } } } void updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result) { Segment* seg; Segment::Map* map; if (c->mode == Heap::MinorCollection) { seg = &(c->gen2); map = &(c->heapMap); } else { seg = &(c->nextGen2); map = &(c->nextHeapMap); } if (not (immortalHeapContains(c, result) or (c->client->isFixed(result) and fixie(result)->age >= FixieTenureThreshold) or seg->contains(result))) { if (target and c->client->isFixed(target)) { Fixie* f = fixie(target); assert(c, offset == 0 or f->hasMask()); if (static_cast(f->age + 1) >= FixieTenureThreshold) { if (DebugFixies) { fprintf(stderr, "dirty fixie %p at %d (%p): %p\n", f, offset, f->body() + offset, result); } f->dirty(true); markBit(f->mask(), offset); } } else if (seg->contains(p)) { if (Debug) { fprintf(stderr, "mark %p (%s) at %p (%s)\n", result, segment(c, result), p, segment(c, p)); } map->set(p); } } } void* update(Context* c, void** p, void* target, unsigned offset, bool* needsVisit) { if (maskAlignedPointer(*p) == 0) { *needsVisit = false; return 0; } void* result = update2(c, maskAlignedPointer(*p), needsVisit); if (result) { updateHeapMap(c, p, target, offset, result); } return result; } const uintptr_t BitsetExtensionBit = (static_cast(1) << (BitsPerWord - 1)); void bitsetInit(uintptr_t* p) { memset(p, 0, BytesPerWord); } void bitsetClear(uintptr_t* p, unsigned start, unsigned end) { if (end < BitsPerWord - 1) { // do nothing } else if (start < BitsPerWord - 1) { memset(p + 1, 0, (wordOf(end + (BitsPerWord * 2) + 1)) * BytesPerWord); } else { unsigned startWord = wordOf(start + (BitsPerWord * 2) + 1); unsigned endWord = wordOf(end + (BitsPerWord * 2) + 1); if (endWord > startWord) { memset(p + startWord + 1, 0, (endWord - startWord) * BytesPerWord); } } } void bitsetSet(uintptr_t* p, unsigned i, bool v) { if (i >= BitsPerWord - 1) { i += (BitsPerWord * 2) + 1; if (v) { p[0] |= BitsetExtensionBit; if (p[2] <= wordOf(i) - 3) p[2] = wordOf(i) - 2; } } if (v) { markBit(p, i); } else { clearBit(p, i); } } bool bitsetHasMore(uintptr_t* p) { switch (*p) { case 0: return false; case BitsetExtensionBit: { uintptr_t length = p[2]; uintptr_t word = wordOf(p[1]); for (; word < length; ++word) { if (p[word + 3]) { p[1] = indexOf(word, 0); return true; } } p[1] = indexOf(word, 0); return false; } default: return true; } } unsigned bitsetNext(Context* c, uintptr_t* p) { bool more UNUSED = bitsetHasMore(p); assert(c, more); switch (*p) { case 0: abort(c); case BitsetExtensionBit: { uintptr_t i = p[1]; uintptr_t word = wordOf(i); assert(c, word < p[2]); for (uintptr_t bit = bitOf(i); bit < BitsPerWord; ++bit) { if (p[word + 3] & (static_cast(1) << bit)) { p[1] = indexOf(word, bit) + 1; bitsetSet(p, p[1] + BitsPerWord - 2, false); return p[1] + BitsPerWord - 2; } } abort(c); } default: { for (unsigned i = 0; i < BitsPerWord - 1; ++i) { if (*p & (static_cast(1) << i)) { bitsetSet(p, i, false); return i; } } abort(c); } } } void collect(Context* c, void** p, void* target, unsigned offset) { void* original = maskAlignedPointer(*p); void* parent_ = 0; if (Debug) { fprintf(stderr, "update %p (%s) at %p (%s)\n", maskAlignedPointer(*p), segment(c, *p), p, segment(c, p)); } bool needsVisit; local::set(p, update(c, maskAlignedPointer(p), target, offset, &needsVisit)); if (Debug) { fprintf(stderr, " result: %p (%s) (visit? %d)\n", maskAlignedPointer(*p), segment(c, *p), needsVisit); } if (not needsVisit) return; visit: { void* copy = follow(c, original); class Walker : public Heap::Walker { public: Walker(Context* c, void* copy, uintptr_t* bitset): c(c), copy(copy), bitset(bitset), first(0), second(0), last(0), visits(0), total(0) { } virtual bool visit(unsigned offset) { if (Debug) { fprintf(stderr, " update %p (%s) at %p - offset %d from %p (%s)\n", get(copy, offset), segment(c, get(copy, offset)), getp(copy, offset), offset, copy, segment(c, copy)); } bool needsVisit; void* childCopy = update (c, getp(copy, offset), copy, offset, &needsVisit); if (Debug) { fprintf(stderr, " result: %p (%s) (visit? %d)\n", childCopy, segment(c, childCopy), needsVisit); } ++ total; if (total == 3) { bitsetInit(bitset); } if (needsVisit) { ++ visits; if (visits == 1) { first = offset; } else if (visits == 2) { second = offset; } } else { local::set(copy, offset, childCopy); } if (visits > 1 and total > 2 and (second or needsVisit)) { bitsetClear(bitset, last, offset); last = offset; if (second) { bitsetSet(bitset, second, true); second = 0; } if (needsVisit) { bitsetSet(bitset, offset, true); } } return true; } Context* c; void* copy; uintptr_t* bitset; unsigned first; unsigned second; unsigned last; unsigned visits; unsigned total; } walker(c, copy, bitset(c, original)); if (Debug) { fprintf(stderr, "walk %p (%s)\n", copy, segment(c, copy)); } c->client->walk(copy, &walker); if (walker.visits) { // descend if (walker.visits > 1) { parent(c, original) = parent_; parent_ = original; } original = get(copy, walker.first); local::set(copy, walker.first, follow(c, original)); goto visit; } else { // ascend original = parent_; } } if (original) { void* copy = follow(c, original); class Walker : public Heap::Walker { public: Walker(Context* c, uintptr_t* bitset): c(c), bitset(bitset), next(0), total(0) { } virtual bool visit(unsigned offset) { switch (++ total) { case 1: return true; case 2: next = offset; return true; case 3: next = bitsetNext(c, bitset); return false; default: abort(c); } } Context* c; uintptr_t* bitset; unsigned next; unsigned total; } walker(c, bitset(c, original)); if (Debug) { fprintf(stderr, "scan %p\n", copy); } c->client->walk(copy, &walker); assert(c, walker.total > 1); if (walker.total == 3 and bitsetHasMore(bitset(c, original))) { parent_ = original; } else { parent_ = parent(c, original); } if (Debug) { fprintf(stderr, " next is %p (%s) at %p - offset %d from %p (%s)\n", get(copy, walker.next), segment(c, get(copy, walker.next)), getp(copy, walker.next), walker.next, copy, segment(c, copy)); } original = get(copy, walker.next); local::set(copy, walker.next, follow(c, original)); goto visit; } else { return; } } void collect(Context* c, void** p) { collect(c, p, 0, 0); } void collect(Context* c, void* target, unsigned offset) { collect(c, getp(target, offset), target, offset); } void visitDirtyFixies(Context* c, Fixie** p) { while (*p) { Fixie* f = *p; bool wasDirty UNUSED = false; bool clean = true; uintptr_t* mask = f->mask(); unsigned word = 0; unsigned bit = 0; unsigned wordLimit = wordOf(f->size); unsigned bitLimit = bitOf(f->size); if (DebugFixies) { fprintf(stderr, "clean fixie %p\n", f); } for (; word <= wordLimit and (word < wordLimit or bit < bitLimit); ++ word) { if (mask[word]) { for (; bit < BitsPerWord and (word < wordLimit or bit < bitLimit); ++ bit) { unsigned index = indexOf(word, bit); if (getBit(mask, index)) { wasDirty = true; clearBit(mask, index); if (DebugFixies) { fprintf(stderr, "clean fixie %p at %d (%p)\n", f, index, f->body() + index); } collect(c, f->body(), index); if (getBit(mask, index)) { clean = false; } } } bit = 0; } } if (DebugFixies) { fprintf(stderr, "done cleaning fixie %p\n", f); } assert(c, wasDirty); if (clean) { markClean(c, f); } else { p = &(f->next); } } } void visitMarkedFixies(Context* c) { while (c->markedFixies) { Fixie* f = c->markedFixies; f->remove(c); if (DebugFixies) { fprintf(stderr, "visit fixie %p\n", f); } class Walker: public Heap::Walker { public: Walker(Context* c, void** p): c(c), p(p) { } virtual bool visit(unsigned offset) { local::collect(c, p, offset); return true; } Context* c; void** p; } w(c, f->body()); c->client->walk(f->body(), &w); f->move(c, &(c->visitedFixies)); } } void collect(Context* c, Segment::Map* map, unsigned start, unsigned end, bool* dirty, bool expectDirty UNUSED) { bool wasDirty UNUSED = false; for (Segment::Map::Iterator it(map, start, end); it.hasMore();) { wasDirty = true; if (map->child) { assert(c, map->scale > 1); unsigned s = it.next(); unsigned e = s + map->scale; map->clearOnly(s); bool childDirty = false; collect(c, map->child, s, e, &childDirty, true); if (childDirty) { map->setOnly(s); *dirty = true; } } else { assert(c, map->scale == 1); void** p = reinterpret_cast(map->segment->get(it.next())); map->clearOnly(p); if (c->nextGen1.contains(*p)) { map->setOnly(p); *dirty = true; } else { collect(c, p); if (not c->gen2.contains(*p)) { map->setOnly(p); *dirty = true; } } } } assert(c, wasDirty or not expectDirty); } void collect2(Context* c) { c->gen2Base = Top; c->tenureFootprint = 0; c->fixieTenureFootprint = 0; c->gen1Padding = 0; c->tenurePadding = 0; if (c->mode == Heap::MajorCollection) { c->gen2Padding = 0; } if (c->mode == Heap::MinorCollection and c->gen2.position()) { unsigned start = 0; unsigned end = start + c->gen2.position(); bool dirty; collect(c, &(c->heapMap), start, end, &dirty, false); } if (c->mode == Heap::MinorCollection) { visitDirtyFixies(c, &(c->dirtyTenuredFixies)); } class Visitor : public Heap::Visitor { public: Visitor(Context* c): c(c) { } virtual void visit(void* p) { local::collect(c, static_cast(p)); visitMarkedFixies(c); } Context* c; } v(c); c->client->visitRoots(&v); } bool limitExceeded(Context* c, int pendingAllocation) { unsigned count = c->count + pendingAllocation - (c->gen2.remaining() * BytesPerWord); if (Verbose) { if (count > c->limit) { if (not c->limitWasExceeded) { c->limitWasExceeded = true; fprintf(stderr, "heap limit %d exceeded: %d\n", c->limit, count); } } else if (c->limitWasExceeded) { c->limitWasExceeded = false; fprintf(stderr, "heap limit %d no longer exceeded: %d\n", c->limit, count); } } return count > c->limit; } void collect(Context* c) { if (limitExceeded(c, c->pendingAllocation) or oversizedGen2(c) or c->tenureFootprint + c->tenurePadding > c->gen2.remaining() or c->fixieTenureFootprint + c->tenuredFixieFootprint > c->tenuredFixieCeiling) { if (Verbose) { if (limitExceeded(c, c->pendingAllocation)) { fprintf(stderr, "low memory causes "); } else if (oversizedGen2(c)) { fprintf(stderr, "oversized gen2 causes "); } else if (c->tenureFootprint + c->tenurePadding > c->gen2.remaining()) { fprintf(stderr, "undersized gen2 causes "); } else { fprintf(stderr, "fixie ceiling causes "); } } c->mode = Heap::MajorCollection; } int64_t then; if (Verbose) { if (c->mode == Heap::MajorCollection) { fprintf(stderr, "major collection\n"); } else { fprintf(stderr, "minor collection\n"); } then = c->system->now(); } initNextGen1(c); if (c->mode == Heap::MajorCollection) { initNextGen2(c); } collect2(c); c->gen1.replaceWith(&(c->nextGen1)); if (c->mode == Heap::MajorCollection) { c->gen2.replaceWith(&(c->nextGen2)); } sweepFixies(c); if (Verbose) { int64_t now = c->system->now(); int64_t collection = now - then; int64_t run = then - c->lastCollectionTime; c->totalCollectionTime += collection; c->totalTime += collection + run; c->lastCollectionTime = now; fprintf(stderr, " - collect: %4dms; " "total: %4dms; " "run: %4dms; " "total: %4dms\n", static_cast(collection), static_cast(c->totalCollectionTime), static_cast(run), static_cast(c->totalTime - c->totalCollectionTime)); fprintf(stderr, " - gen1: %8d/%8d bytes\n", c->gen1.position() * BytesPerWord, c->gen1.capacity() * BytesPerWord); fprintf(stderr, " - gen2: %8d/%8d bytes\n", c->gen2.position() * BytesPerWord, c->gen2.capacity() * BytesPerWord); fprintf(stderr, " - untenured fixies: %8d bytes\n", c->untenuredFixieFootprint); fprintf(stderr, " - tenured fixies: %8d bytes\n", c->tenuredFixieFootprint); } } void* allocate(Context* c, unsigned size, bool limit) { ACQUIRE(c->lock); if (DebugAllocation) { size = pad(size) + 2 * BytesPerWord; } if ((not limit) or size + c->count < c->limit) { void* p = c->system->tryAllocate(size); if (p) { c->count += size; if (DebugAllocation) { static_cast(p)[0] = 0x22377322; static_cast(p)[(size / BytesPerWord) - 1] = 0x22377322; return static_cast(p) + 1; } else { return p; } } } return 0; } void* tryAllocate(Context* c, unsigned size) { return allocate(c, size, true); } void* allocate(Context* c, unsigned size) { void* p = allocate(c, size, false); expect(c->system, p); return p; } void free(Context* c, const void* p, unsigned size) { ACQUIRE(c->lock); if (DebugAllocation) { size = pad(size) + 2 * BytesPerWord; memset(const_cast(p), 0xFE, size - (2 * BytesPerWord)); p = static_cast(p) - 1; expect(c->system, static_cast(p)[0] == 0x22377322); expect(c->system, static_cast(p) [(size / BytesPerWord) - 1] == 0x22377322); } expect(c->system, c->count >= size); c->system->free(p); c->count -= size; } void free_(Context* c, const void* p, unsigned size) { free(c, p, size); } class MyHeap: public Heap { public: MyHeap(System* system, unsigned limit): c(system, limit) { } virtual void setClient(Heap::Client* client) { assert(&c, c.client == 0); c.client = client; } virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) { c.immortalHeapStart = start; c.immortalHeapEnd = start + sizeInWords; } virtual unsigned remaining() { return c.limit - c.count; } virtual unsigned limit() { return c.limit; } virtual bool limitExceeded(int pendingAllocation = 0) { return local::limitExceeded(&c, pendingAllocation); } virtual void* tryAllocate(unsigned size) { return local::tryAllocate(&c, size); } virtual void* allocate(unsigned size) { return local::allocate(&c, size); } virtual void free(const void* p, unsigned size) { free_(&c, p, size); } virtual void collect(CollectionType type, unsigned incomingFootprint, int pendingAllocation) { c.mode = type; c.incomingFootprint = incomingFootprint; c.pendingAllocation = pendingAllocation; local::collect(&c); } virtual unsigned fixedFootprint(unsigned sizeInWords, bool objectMask) { return Fixie::totalSize(sizeInWords, objectMask); } void* allocateFixed(Allocator* allocator, unsigned sizeInWords, bool objectMask, Fixie** handle, bool immortal) { expect(&c, not limitExceeded()); unsigned total = Fixie::totalSize(sizeInWords, objectMask); void* p = allocator->allocate(total); expect(&c, not limitExceeded()); return (new (p) Fixie(&c, sizeInWords, objectMask, handle, immortal)) ->body(); } virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords, bool objectMask) { return allocateFixed (allocator, sizeInWords, objectMask, &(c.fixies), false); } virtual void* allocateImmortalFixed(Allocator* allocator, unsigned sizeInWords, bool objectMask) { return allocateFixed(allocator, sizeInWords, objectMask, 0, true); } bool needsMark(void* p) { assert(&c, c.client->isFixed(p) or (not immortalHeapContains(&c, p))); if (c.client->isFixed(p)) { return fixie(p)->age >= FixieTenureThreshold; } else { return c.gen2.contains(p) or c.nextGen2.contains(p); } } bool targetNeedsMark(void* target) { return target and not c.gen2.contains(target) and not c.nextGen2.contains(target) and not immortalHeapContains(&c, target) and not (c.client->isFixed(target) and fixie(target)->age >= FixieTenureThreshold); } virtual void mark(void* p, unsigned offset, unsigned count) { if (needsMark(p)) { #ifndef USE_ATOMIC_OPERATIONS ACQUIRE(c.lock); #endif if (c.client->isFixed(p)) { Fixie* f = fixie(p); assert(&c, offset == 0 or f->hasMask()); bool dirty = false; for (unsigned i = 0; i < count; ++i) { void** target = static_cast(p) + offset + i; if (targetNeedsMark(maskAlignedPointer(*target))) { if (DebugFixies) { fprintf(stderr, "dirty fixie %p at %d (%p): %p\n", f, offset, f->body() + offset, maskAlignedPointer(*target)); } dirty = true; #ifdef USE_ATOMIC_OPERATIONS markBitAtomic(f->mask(), offset + i); #else markBit(f->mask(), offset + i); #endif assert(&c, getBit(f->mask(), offset + i)); } } if (dirty) markDirty(&c, f); } else { Segment::Map* map; if (c.gen2.contains(p)) { map = &(c.heapMap); } else { assert(&c, c.nextGen2.contains(p)); map = &(c.nextHeapMap); } for (unsigned i = 0; i < count; ++i) { void** target = static_cast(p) + offset + i; if (targetNeedsMark(maskAlignedPointer(*target))) { #ifdef USE_ATOMIC_OPERATIONS map->markAtomic(target); #else map->set(target); #endif } } } } } virtual void pad(void* p) { if (c.gen1.contains(p)) { if (c.ageMap.get(p) == TenureThreshold) { ++ c.tenurePadding; } else { ++ c.gen1Padding; } } else if (c.gen2.contains(p)) { ++ c.gen2Padding; } else { ++ c.gen1Padding; } } virtual void* follow(void* p) { if (p == 0 or c.client->isFixed(p)) { return p; } else if (wasCollected(&c, p)) { if (Debug) { fprintf(stderr, "follow %p (%s) to %p (%s)\n", p, segment(&c, p), local::follow(&c, p), segment(&c, local::follow(&c, p))); } return local::follow(&c, p); } else { return p; } } virtual void postVisit() { killFixies(&c); } virtual Status status(void* p) { p = maskAlignedPointer(p); if (p == 0) { return Null; } else if (c.client->isFixed(p)) { Fixie* f = fixie(p); return f->dead() ? Unreachable : (static_cast(f->age + 1) < FixieTenureThreshold ? Reachable : Tenured); } else if (c.nextGen1.contains(p)) { return Reachable; } else if (c.nextGen2.contains(p) or immortalHeapContains(&c, p) or (c.gen2.contains(p) and (c.mode == Heap::MinorCollection or c.gen2.indexOf(p) >= c.gen2Base))) { return Tenured; } else if (wasCollected(&c, p)) { return Reachable; } else { return Unreachable; } } virtual CollectionType collectionType() { return c.mode; } virtual void disposeFixies() { c.disposeFixies(); } virtual void dispose() { c.dispose(); assert(&c, c.count == 0); c.system->free(this); } Context c; }; } // namespace local } // namespace namespace vm { Heap* makeHeap(System* system, unsigned limit) { return new (system->tryAllocate(sizeof(local::MyHeap))) local::MyHeap(system, limit); } } // namespace vm ReadyTalk-avian-1e1fff5/src/heapdump.cpp000066400000000000000000000047131231440243200202630ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/machine.h" #include "avian/heapwalk.h" using namespace vm; namespace { namespace local { enum { Root, Size, ClassName, Push, Pop }; void write1(FILE* out, uint8_t v) { size_t n UNUSED = fwrite(&v, 1, 1, out); } void write4(FILE* out, uint32_t v) { uint8_t b[] = { static_cast( v >> 24 ), static_cast((v >> 16) & 0xFF), static_cast((v >> 8) & 0xFF), static_cast( v & 0xFF) }; size_t n UNUSED = fwrite(b, 4, 1, out); } void writeString(FILE* out, int8_t* p, unsigned size) { write4(out, size); size_t n UNUSED = fwrite(p, size, 1, out); } unsigned objectSize(Thread* t, object o) { return extendedSize(t, o, baseSize(t, o, objectClass(t, o))); } } // namespace local } // namespace namespace vm { void dumpHeap(Thread* t, FILE* out) { class Visitor: public HeapVisitor { public: Visitor(Thread* t, FILE* out): t(t), out(out), nextNumber(1) { } virtual void root() { write1(out, local::Root); } virtual unsigned visitNew(object p) { if (p) { unsigned number = nextNumber++; local::write4(out, number); local::write1(out, local::Size); local::write4(out, local::objectSize(t, p)); if (objectClass(t, p) == type(t, Machine::ClassType)) { object name = className(t, p); if (name) { local::write1(out, local::ClassName); local::writeString(out, &byteArrayBody(t, name, 0), byteArrayLength(t, name) - 1); } } return number; } else { return 0; } } virtual void visitOld(object, unsigned number) { local::write4(out, number); } virtual void push(object, unsigned, unsigned) { local::write1(out, local::Push); } virtual void pop() { local::write1(out, local::Pop); } Thread* t; FILE* out; unsigned nextNumber; } visitor(t, out); HeapWalker* w = makeHeapWalker(t, &visitor); w->visitAllRoots(); w->dispose(); } } // namespace vm ReadyTalk-avian-1e1fff5/src/heapwalk.cpp000066400000000000000000000150301231440243200202460ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/machine.h" #include "avian/heapwalk.h" using namespace vm; namespace { namespace local { const uintptr_t PointerShift = log(BytesPerWord); class Context; class Set: public HeapMap { public: class Entry { public: object value; uint32_t number; int next; }; static unsigned footprint(unsigned capacity) { return sizeof(Set) + pad(sizeof(int) * capacity) + pad(sizeof(Set::Entry) * capacity); } Set(Context* context, unsigned capacity): context(context), index(reinterpret_cast (reinterpret_cast(this) + sizeof(Set))), entries(reinterpret_cast (reinterpret_cast(index) + pad(sizeof(int) * capacity))), size(0), capacity(capacity) { } virtual int find(object value); virtual void dispose(); Context* context; int* index; Entry* entries; unsigned size; unsigned capacity; }; class Stack { public: class Entry { public: object value; int offset; }; static const unsigned Capacity = 4096; Stack(Stack* next): next(next), entryCount(0) { } Stack* next; unsigned entryCount; Entry entries[Capacity]; }; class Context { public: Context(Thread* thread): thread(thread), objects(0), stack(0) { } void dispose() { if (objects) { objects->dispose(); } while (stack) { Stack* dead = stack; stack = dead->next; thread->m->heap->free(dead, sizeof(Stack)); } } Thread* thread; Set* objects; Stack* stack; }; void push(Context* c, object p, int offset) { if (c->stack == 0 or c->stack->entryCount == Stack::Capacity) { c->stack = new (c->thread->m->heap->allocate(sizeof(Stack))) Stack(c->stack); } Stack::Entry* e = c->stack->entries + (c->stack->entryCount++); e->value = p; e->offset = offset; } bool pop(Context* c, object* p, int* offset) { if (c->stack) { if (c->stack->entryCount == 0) { if (c->stack->next) { Stack* dead = c->stack; c->stack = dead->next; c->thread->m->heap->free(dead, sizeof(Stack)); } else { return false; } } Stack::Entry* e = c->stack->entries + (--c->stack->entryCount); *p = e->value; *offset = e->offset; return true; } else { return false; } } unsigned hash(object p, unsigned capacity) { return (reinterpret_cast(p) >> PointerShift) & (capacity - 1); } Set::Entry* find(Context* c, object p) { if (c->objects == 0) return 0; for (int i = c->objects->index[hash(p, c->objects->capacity)]; i >= 0;) { Set::Entry* e = c->objects->entries + i; if (e->value == p) { return e; } i = e->next; } return 0; } int Set::find(object value) { Set::Entry* e = local::find(context, value); if (e) { return e->number; } else { return -1; } } void Set::dispose() { context->thread->m->heap->free(this, footprint(capacity)); } Set::Entry* add(Context* c UNUSED, Set* set, object p, uint32_t number) { assert(c->thread, set->size < set->capacity); unsigned index = hash(p, set->capacity); int offset = set->size++; Set::Entry* e = set->entries + offset; e->value = p; e->number = number; e->next = set->index[index]; set->index[index] = offset; return e; } Set::Entry* add(Context* c, object p) { if (c->objects == 0 or c->objects->size == c->objects->capacity) { unsigned capacity; if (c->objects) { capacity = c->objects->capacity * 2; } else { capacity = 4096; // must be power of two } Set* set = new (c->thread->m->heap->allocate(Set::footprint(capacity))) Set(c, capacity); memset(set->index, 0xFF, sizeof(int) * capacity); if (c->objects) { for (unsigned i = 0; i < c->objects->capacity; ++i) { for (int j = c->objects->index[i]; j >= 0;) { Set::Entry* e = c->objects->entries + j; add(c, set, e->value, e->number); j = e->next; } } c->thread->m->heap->free (c->objects, Set::footprint(c->objects->capacity)); } c->objects = set; } return add(c, c->objects, p, 0); } inline object get(object o, unsigned offsetInWords) { return static_cast (maskAlignedPointer (fieldAtOffset(o, offsetInWords * BytesPerWord))); } unsigned walk(Context* c, HeapVisitor* v, object p) { Thread* t = c->thread; object root = p; int nextChildOffset; v->root(); visit: { Set::Entry* e = find(c, p); if (e) { v->visitOld(p, e->number); } else { e = add(c, p); e->number = v->visitNew(p); nextChildOffset = walkNext(t, p, -1); if (nextChildOffset != -1) { goto children; } } } goto pop; children: { v->push(p, find(c, p)->number, nextChildOffset); push(c, p, nextChildOffset); p = get(p, nextChildOffset); goto visit; } pop: { if (pop(c, &p, &nextChildOffset)) { v->pop(); nextChildOffset = walkNext(t, p, nextChildOffset); if (nextChildOffset >= 0) { goto children; } else { goto pop; } } } return find(c, root)->number; } class MyHeapWalker: public HeapWalker { public: MyHeapWalker(Thread* t, HeapVisitor* v): context(t), visitor(v) { add(&context, 0)->number = v->visitNew(0); } virtual unsigned visitRoot(object root) { return walk(&context, visitor, root); } virtual void visitAllRoots() { class Visitor: public Heap::Visitor { public: Visitor(Context* c, HeapVisitor* v): c(c), v(v) { } virtual void visit(void* p) { walk(c, v, static_cast (maskAlignedPointer(*static_cast(p)))); } Context* c; HeapVisitor* v; } v(&context, visitor); visitRoots(context.thread->m, &v); } virtual HeapMap* map() { return context.objects; } virtual void dispose() { context.dispose(); context.thread->m->heap->free(this, sizeof(MyHeapWalker)); } Context context; HeapVisitor* visitor; }; } // namespace local } // namespace namespace vm { HeapWalker* makeHeapWalker(Thread* t, HeapVisitor* v) { return new (t->m->heap->allocate(sizeof(local::MyHeapWalker))) local::MyHeapWalker(t, v); } } // namespace vm ReadyTalk-avian-1e1fff5/src/interpret.cpp000066400000000000000000002266611231440243200205040ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/common.h" #include #include #include "avian/constants.h" #include "avian/machine.h" #include "avian/processor.h" #include "avian/process.h" #include "avian/arch.h" #include #include #include using namespace vm; using namespace avian::system; namespace local { const unsigned FrameBaseOffset = 0; const unsigned FrameNextOffset = 1; const unsigned FrameMethodOffset = 2; const unsigned FrameIpOffset = 3; const unsigned FrameFootprint = 4; class Thread: public vm::Thread { public: Thread(Machine* m, object javaThread, vm::Thread* parent): vm::Thread(m, javaThread, parent), ip(0), sp(0), frame(-1), code(0), stackPointers(0) { } unsigned ip; unsigned sp; int frame; object code; List* stackPointers; uintptr_t stack[0]; }; inline void pushObject(Thread* t, object o) { if (DebugStack) { fprintf(stderr, "push object %p at %d\n", o, t->sp); } assert(t, t->sp + 1 < stackSizeInWords(t) / 2); t->stack[(t->sp * 2) ] = ObjectTag; t->stack[(t->sp * 2) + 1] = reinterpret_cast(o); ++ t->sp; } inline void pushInt(Thread* t, uint32_t v) { if (DebugStack) { fprintf(stderr, "push int %d at %d\n", v, t->sp); } assert(t, t->sp + 1 < stackSizeInWords(t) / 2); t->stack[(t->sp * 2) ] = IntTag; t->stack[(t->sp * 2) + 1] = v; ++ t->sp; } inline void pushFloat(Thread* t, float v) { pushInt(t, floatToBits(v)); } inline void pushLong(Thread* t, uint64_t v) { if (DebugStack) { fprintf(stderr, "push long %" LLD " at %d\n", v, t->sp); } pushInt(t, v >> 32); pushInt(t, v & 0xFFFFFFFF); } inline void pushDouble(Thread* t, double v) { uint64_t w = doubleToBits(v); pushLong(t, w); } inline object popObject(Thread* t) { if (DebugStack) { fprintf(stderr, "pop object %p at %d\n", reinterpret_cast(t->stack[((t->sp - 1) * 2) + 1]), t->sp - 1); } assert(t, t->stack[(t->sp - 1) * 2] == ObjectTag); return reinterpret_cast(t->stack[((-- t->sp) * 2) + 1]); } inline uint32_t popInt(Thread* t) { if (DebugStack) { fprintf(stderr, "pop int %" ULD " at %d\n", t->stack[((t->sp - 1) * 2) + 1], t->sp - 1); } assert(t, t->stack[(t->sp - 1) * 2] == IntTag); return t->stack[((-- t->sp) * 2) + 1]; } inline float popFloat(Thread* t) { return bitsToFloat(popInt(t)); } inline uint64_t popLong(Thread* t) { if (DebugStack) { fprintf(stderr, "pop long %" LLD " at %d\n", (static_cast(t->stack[((t->sp - 2) * 2) + 1]) << 32) | static_cast(t->stack[((t->sp - 1) * 2) + 1]), t->sp - 2); } uint64_t a = popInt(t); uint64_t b = popInt(t); return (b << 32) | a; } inline double popDouble(Thread* t) { uint64_t v = popLong(t); return bitsToDouble(v); } inline object peekObject(Thread* t, unsigned index) { if (DebugStack) { fprintf(stderr, "peek object %p at %d\n", reinterpret_cast(t->stack[(index * 2) + 1]), index); } assert(t, index < stackSizeInWords(t) / 2); assert(t, t->stack[index * 2] == ObjectTag); return reinterpret_cast(t->stack[(index * 2) + 1]); } inline uint32_t peekInt(Thread* t, unsigned index) { if (DebugStack) { fprintf(stderr, "peek int %" ULD " at %d\n", t->stack[(index * 2) + 1], index); } assert(t, index < stackSizeInWords(t) / 2); assert(t, t->stack[index * 2] == IntTag); return t->stack[(index * 2) + 1]; } inline uint64_t peekLong(Thread* t, unsigned index) { if (DebugStack) { fprintf(stderr, "peek long %" LLD " at %d\n", (static_cast(t->stack[(index * 2) + 1]) << 32) | static_cast(t->stack[((index + 1) * 2) + 1]), index); } return (static_cast(peekInt(t, index)) << 32) | static_cast(peekInt(t, index + 1)); } inline void pokeObject(Thread* t, unsigned index, object value) { if (DebugStack) { fprintf(stderr, "poke object %p at %d\n", value, index); } t->stack[index * 2] = ObjectTag; t->stack[(index * 2) + 1] = reinterpret_cast(value); } inline void pokeInt(Thread* t, unsigned index, uint32_t value) { if (DebugStack) { fprintf(stderr, "poke int %d at %d\n", value, index); } t->stack[index * 2] = IntTag; t->stack[(index * 2) + 1] = value; } inline void pokeLong(Thread* t, unsigned index, uint64_t value) { if (DebugStack) { fprintf(stderr, "poke long %" LLD " at %d\n", value, index); } pokeInt(t, index, value >> 32); pokeInt(t, index + 1, value & 0xFFFFFFFF); } inline object* pushReference(Thread* t, object o) { if (o) { expect(t, t->sp + 1 < stackSizeInWords(t) / 2); pushObject(t, o); return reinterpret_cast(t->stack + ((t->sp - 1) * 2) + 1); } else { return 0; } } inline int frameNext(Thread* t, int frame) { return peekInt(t, frame + FrameNextOffset); } inline object frameMethod(Thread* t, int frame) { return peekObject(t, frame + FrameMethodOffset); } inline unsigned frameIp(Thread* t, int frame) { return peekInt(t, frame + FrameIpOffset); } inline unsigned frameBase(Thread* t, int frame) { return peekInt(t, frame + FrameBaseOffset); } inline object localObject(Thread* t, unsigned index) { return peekObject(t, frameBase(t, t->frame) + index); } inline uint32_t localInt(Thread* t, unsigned index) { return peekInt(t, frameBase(t, t->frame) + index); } inline uint64_t localLong(Thread* t, unsigned index) { return peekLong(t, frameBase(t, t->frame) + index); } inline void setLocalObject(Thread* t, unsigned index, object value) { pokeObject(t, frameBase(t, t->frame) + index, value); } inline void setLocalInt(Thread* t, unsigned index, uint32_t value) { pokeInt(t, frameBase(t, t->frame) + index, value); } inline void setLocalLong(Thread* t, unsigned index, uint64_t value) { pokeLong(t, frameBase(t, t->frame) + index, value); } void pushFrame(Thread* t, object method) { PROTECT(t, method); unsigned parameterFootprint = methodParameterFootprint(t, method); unsigned base = t->sp - parameterFootprint; unsigned locals = parameterFootprint; if (methodFlags(t, method) & ACC_SYNCHRONIZED) { // Try to acquire the monitor before doing anything else. // Otherwise, if we were to push the frame first, we risk trying // to release a monitor we never successfully acquired when we try // to pop the frame back off. if (methodFlags(t, method) & ACC_STATIC) { acquire(t, methodClass(t, method)); } else { acquire(t, peekObject(t, base)); } } if (t->frame >= 0) { pokeInt(t, t->frame + FrameIpOffset, t->ip); } t->ip = 0; if ((methodFlags(t, method) & ACC_NATIVE) == 0) { t->code = methodCode(t, method); locals = codeMaxLocals(t, t->code); memset(t->stack + ((base + parameterFootprint) * 2), 0, (locals - parameterFootprint) * BytesPerWord * 2); } unsigned frame = base + locals; pokeInt(t, frame + FrameNextOffset, t->frame); t->frame = frame; t->sp = frame + FrameFootprint; pokeInt(t, frame + FrameBaseOffset, base); pokeObject(t, frame + FrameMethodOffset, method); pokeInt(t, t->frame + FrameIpOffset, 0); } void popFrame(Thread* t) { object method = frameMethod(t, t->frame); if (methodFlags(t, method) & ACC_SYNCHRONIZED) { if (methodFlags(t, method) & ACC_STATIC) { release(t, methodClass(t, method)); } else { release(t, peekObject(t, frameBase(t, t->frame))); } } t->sp = frameBase(t, t->frame); t->frame = frameNext(t, t->frame); if (t->frame >= 0) { t->code = methodCode(t, frameMethod(t, t->frame)); t->ip = frameIp(t, t->frame); } else { t->code = 0; t->ip = 0; } } class MyStackWalker: public Processor::StackWalker { public: MyStackWalker(Thread* t, int frame): t(t), frame(frame) { } virtual void walk(Processor::StackVisitor* v) { for (int frame = this->frame; frame >= 0; frame = frameNext(t, frame)) { MyStackWalker walker(t, frame); if (not v->visit(&walker)) { break; } } } virtual object method() { return frameMethod(t, frame); } virtual int ip() { return frameIp(t, frame); } virtual unsigned count() { unsigned count = 0; for (int frame = this->frame; frame >= 0; frame = frameNext(t, frame)) { ++ count; } return count; } Thread* t; int frame; }; inline void checkStack(Thread* t, object method) { if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + codeMaxLocals(t, methodCode(t, method)) + FrameFootprint + codeMaxStack(t, methodCode(t, method)) > stackSizeInWords(t) / 2)) { throwNew(t, Machine::StackOverflowErrorType); } } void pushResult(Thread* t, unsigned returnCode, uint64_t result, bool indirect) { switch (returnCode) { case ByteField: case BooleanField: if (DebugRun) { fprintf(stderr, "result: %d\n", static_cast(result)); } pushInt(t, static_cast(result)); break; case CharField: if (DebugRun) { fprintf(stderr, "result: %d\n", static_cast(result)); } pushInt(t, static_cast(result)); break; case ShortField: if (DebugRun) { fprintf(stderr, "result: %d\n", static_cast(result)); } pushInt(t, static_cast(result)); break; case FloatField: case IntField: if (DebugRun) { fprintf(stderr, "result: %d\n", static_cast(result)); } pushInt(t, result); break; case DoubleField: case LongField: if (DebugRun) { fprintf(stderr, "result: %" LLD "\n", result); } pushLong(t, result); break; case ObjectField: if (indirect) { if (DebugRun) { fprintf(stderr, "result: %p at %p\n", static_cast(result) == 0 ? 0 : *reinterpret_cast(static_cast(result)), reinterpret_cast(static_cast(result))); } pushObject(t, static_cast(result) == 0 ? 0 : *reinterpret_cast(static_cast(result))); } else { if (DebugRun) { fprintf(stderr, "result: %p\n", reinterpret_cast(result)); } pushObject(t, reinterpret_cast(result)); } break; case VoidField: break; default: abort(t); } } void marshalArguments(Thread* t, uintptr_t* args, uint8_t* types, unsigned sp, object method, bool fastCallingConvention) { MethodSpecIterator it (t, reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), 0))); unsigned argOffset = 0; unsigned typeOffset = 0; while (it.hasNext()) { unsigned type = fieldType(t, fieldCode(t, *it.next())); if (types) { types[typeOffset++] = type; } switch (type) { case INT8_TYPE: case INT16_TYPE: case INT32_TYPE: case FLOAT_TYPE: args[argOffset++] = peekInt(t, sp++); break; case DOUBLE_TYPE: case INT64_TYPE: { uint64_t v = peekLong(t, sp); memcpy(args + argOffset, &v, 8); argOffset += fastCallingConvention ? 2 : (8 / BytesPerWord); sp += 2; } break; case POINTER_TYPE: { if (fastCallingConvention) { args[argOffset++] = reinterpret_cast(peekObject(t, sp++)); } else { object* v = reinterpret_cast(t->stack + ((sp++) * 2) + 1); if (*v == 0) { v = 0; } args[argOffset++] = reinterpret_cast(v); } } break; default: abort(t); } } } unsigned invokeNativeSlow(Thread* t, object method, void* function) { PROTECT(t, method); pushFrame(t, method); unsigned footprint = methodParameterFootprint(t, method) + 1; if (methodFlags(t, method) & ACC_STATIC) { ++ footprint; } unsigned count = methodParameterCount(t, method) + 2; THREAD_RUNTIME_ARRAY(t, uintptr_t, args, footprint); unsigned argOffset = 0; THREAD_RUNTIME_ARRAY(t, uint8_t, types, count); unsigned typeOffset = 0; RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(t); RUNTIME_ARRAY_BODY(types)[typeOffset++] = POINTER_TYPE; object jclass = 0; PROTECT(t, jclass); unsigned sp; if (methodFlags(t, method) & ACC_STATIC) { sp = frameBase(t, t->frame); jclass = getJClass(t, methodClass(t, method)); RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(&jclass); } else { sp = frameBase(t, t->frame); object* v = reinterpret_cast(t->stack + ((sp++) * 2) + 1); if (*v == 0) { v = 0; } RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(v); } RUNTIME_ARRAY_BODY(types)[typeOffset++] = POINTER_TYPE; marshalArguments (t, RUNTIME_ARRAY_BODY(args) + argOffset, RUNTIME_ARRAY_BODY(types) + typeOffset, sp, method, false); unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); uint64_t result; if (DebugRun) { fprintf(stderr, "invoke native method %s.%s\n", &byteArrayBody(t, className(t, methodClass(t, method)), 0), &byteArrayBody(t, methodName(t, method), 0)); } { ENTER(t, Thread::IdleState); bool noThrow = t->checkpoint->noThrow; t->checkpoint->noThrow = true; THREAD_RESOURCE(t, bool, noThrow, t->checkpoint->noThrow = noThrow); result = vm::dynamicCall(function, RUNTIME_ARRAY_BODY(args), RUNTIME_ARRAY_BODY(types), count, footprint * BytesPerWord, returnType); } if (DebugRun) { fprintf(stderr, "return from native method %s.%s\n", &byteArrayBody (t, className(t, methodClass(t, frameMethod(t, t->frame))), 0), &byteArrayBody (t, methodName(t, frameMethod(t, t->frame)), 0)); } popFrame(t); if (UNLIKELY(t->exception)) { object exception = t->exception; t->exception = 0; throw_(t, exception); } pushResult(t, returnCode, result, true); return returnCode; } unsigned invokeNative(Thread* t, object method) { PROTECT(t, method); resolveNative(t, method); object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method)); if (nativeFast(t, native)) { pushFrame(t, method); uint64_t result; { THREAD_RESOURCE0(t, popFrame(static_cast(t))); unsigned footprint = methodParameterFootprint(t, method); THREAD_RUNTIME_ARRAY(t, uintptr_t, args, footprint); unsigned sp = frameBase(t, t->frame); unsigned argOffset = 0; if ((methodFlags(t, method) & ACC_STATIC) == 0) { RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(peekObject(t, sp++)); } marshalArguments (t, RUNTIME_ARRAY_BODY(args) + argOffset, 0, sp, method, true); result = reinterpret_cast (nativeFunction(t, native))(t, method, RUNTIME_ARRAY_BODY(args)); } pushResult(t, methodReturnCode(t, method), result, false); return methodReturnCode(t, method); } else { return invokeNativeSlow(t, method, nativeFunction(t, native)); } } inline void store(Thread* t, unsigned index) { memcpy(t->stack + ((frameBase(t, t->frame) + index) * 2), t->stack + ((-- t->sp) * 2), BytesPerWord * 2); } bool isNaN(double v) { return fpclassify(v) == FP_NAN; } bool isNaN(float v) { return fpclassify(v) == FP_NAN; } uint64_t findExceptionHandler(Thread* t, object method, unsigned ip) { PROTECT(t, method); object eht = codeExceptionHandlerTable(t, methodCode(t, method)); if (eht) { for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) { uint64_t eh = exceptionHandlerTableBody(t, eht, i); if (ip - 1 >= exceptionHandlerStart(eh) and ip - 1 < exceptionHandlerEnd(eh)) { object catchType = 0; if (exceptionHandlerCatchType(eh)) { object e = t->exception; t->exception = 0; PROTECT(t, e); PROTECT(t, eht); catchType = resolveClassInPool (t, method, exceptionHandlerCatchType(eh) - 1); if (catchType) { eh = exceptionHandlerTableBody(t, eht, i); t->exception = e; } else { // can't find what we're supposed to catch - move on. continue; } } if (exceptionMatch(t, catchType, t->exception)) { return eh; } } } } return 0; } uint64_t findExceptionHandler(Thread* t, int frame) { return findExceptionHandler(t, frameMethod(t, frame), frameIp(t, frame)); } void pushField(Thread* t, object target, object field) { switch (fieldCode(t, field)) { case ByteField: case BooleanField: pushInt(t, fieldAtOffset(target, fieldOffset(t, field))); break; case CharField: case ShortField: pushInt(t, fieldAtOffset(target, fieldOffset(t, field))); break; case FloatField: case IntField: pushInt(t, fieldAtOffset(target, fieldOffset(t, field))); break; case DoubleField: case LongField: pushLong(t, fieldAtOffset(target, fieldOffset(t, field))); break; case ObjectField: pushObject(t, fieldAtOffset(target, fieldOffset(t, field))); break; default: abort(t); } } void safePoint(Thread* t) { ENTER(t, Thread::IdleState); } object interpret3(Thread* t, const int base) { unsigned instruction = nop; unsigned& ip = t->ip; unsigned& sp = t->sp; int& frame = t->frame; object& code = t->code; object& exception = t->exception; uintptr_t* stack = t->stack; code = methodCode(t, frameMethod(t, frame)); if (UNLIKELY(exception)) { goto throw_; } loop: instruction = codeBody(t, code, ip++); if (DebugRun) { fprintf(stderr, "ip: %d; instruction: 0x%x in %s.%s ", ip - 1, instruction, &byteArrayBody (t, className(t, methodClass(t, frameMethod(t, frame))), 0), &byteArrayBody (t, methodName(t, frameMethod(t, frame)), 0)); int line = findLineNumber(t, frameMethod(t, frame), ip); switch (line) { case NativeLine: fprintf(stderr, "(native)\n"); break; case UnknownLine: fprintf(stderr, "(unknown line)\n"); break; default: fprintf(stderr, "(line %d)\n", line); } } switch (instruction) { case aaload: { int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < objectArrayLength(t, array))) { pushObject(t, objectArrayBody(t, array, index)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, objectArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case aastore: { object value = popObject(t); int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < objectArrayLength(t, array))) { set(t, array, ArrayBody + (index * BytesPerWord), value); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, objectArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case aconst_null: { pushObject(t, 0); } goto loop; case aload: { pushObject(t, localObject(t, codeBody(t, code, ip++))); } goto loop; case aload_0: { pushObject(t, localObject(t, 0)); } goto loop; case aload_1: { pushObject(t, localObject(t, 1)); } goto loop; case aload_2: { pushObject(t, localObject(t, 2)); } goto loop; case aload_3: { pushObject(t, localObject(t, 3)); } goto loop; case anewarray: { int32_t count = popInt(t); if (LIKELY(count >= 0)) { uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); pushObject(t, makeObjectArray(t, class_, count)); } else { exception = makeThrowable (t, Machine::NegativeArraySizeExceptionType, "%d", count); goto throw_; } } goto loop; case areturn: { object result = popObject(t); if (frame > base) { popFrame(t); pushObject(t, result); goto loop; } else { return result; } } goto loop; case arraylength: { object array = popObject(t); if (LIKELY(array)) { pushInt(t, fieldAtOffset(array, BytesPerWord)); } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case astore: { store(t, codeBody(t, code, ip++)); } goto loop; case astore_0: { store(t, 0); } goto loop; case astore_1: { store(t, 1); } goto loop; case astore_2: { store(t, 2); } goto loop; case astore_3: { store(t, 3); } goto loop; case athrow: { exception = popObject(t); if (UNLIKELY(exception == 0)) { exception = makeThrowable(t, Machine::NullPointerExceptionType); } } goto throw_; case baload: { int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (objectClass(t, array) == type(t, Machine::BooleanArrayType)) { if (LIKELY(index >= 0 and static_cast(index) < booleanArrayLength(t, array))) { pushInt(t, booleanArrayBody(t, array, index)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, booleanArrayLength(t, array)); goto throw_; } } else { if (LIKELY(index >= 0 and static_cast(index) < byteArrayLength(t, array))) { pushInt(t, byteArrayBody(t, array, index)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, byteArrayLength(t, array)); goto throw_; } } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case bastore: { int8_t value = popInt(t); int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (objectClass(t, array) == type(t, Machine::BooleanArrayType)) { if (LIKELY(index >= 0 and static_cast(index) < booleanArrayLength(t, array))) { booleanArrayBody(t, array, index) = value; } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, booleanArrayLength(t, array)); goto throw_; } } else { if (LIKELY(index >= 0 and static_cast(index) < byteArrayLength(t, array))) { byteArrayBody(t, array, index) = value; } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, byteArrayLength(t, array)); goto throw_; } } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case bipush: { pushInt(t, static_cast(codeBody(t, code, ip++))); } goto loop; case caload: { int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < charArrayLength(t, array))) { pushInt(t, charArrayBody(t, array, index)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, charArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case castore: { uint16_t value = popInt(t); int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < charArrayLength(t, array))) { charArrayBody(t, array, index) = value; } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, charArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case checkcast: { uint16_t index = codeReadInt16(t, code, ip); if (peekObject(t, sp - 1)) { object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); if (UNLIKELY(exception)) goto throw_; if (not instanceOf(t, class_, peekObject(t, sp - 1))) { exception = makeThrowable (t, Machine::ClassCastExceptionType, "%s as %s", &byteArrayBody (t, className(t, objectClass(t, peekObject(t, sp - 1))), 0), &byteArrayBody(t, className(t, class_), 0)); goto throw_; } } } goto loop; case d2f: { pushFloat(t, static_cast(popDouble(t))); } goto loop; case d2i: { double f = popDouble(t); switch (fpclassify(f)) { case FP_NAN: pushInt(t, 0); break; case FP_INFINITE: pushInt(t, signbit(f) ? INT32_MIN : INT32_MAX); break; default: pushInt (t, f >= INT32_MAX ? INT32_MAX : (f <= INT32_MIN ? INT32_MIN : static_cast(f))); break; } } goto loop; case d2l: { double f = popDouble(t); switch (fpclassify(f)) { case FP_NAN: pushLong(t, 0); break; case FP_INFINITE: pushLong(t, signbit(f) ? INT64_MIN : INT64_MAX); break; default: pushLong (t, f >= INT64_MAX ? INT64_MAX : (f <= INT64_MIN ? INT64_MIN : static_cast(f))); break; } } goto loop; case dadd: { double b = popDouble(t); double a = popDouble(t); pushDouble(t, a + b); } goto loop; case daload: { int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < doubleArrayLength(t, array))) { pushLong(t, doubleArrayBody(t, array, index)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, doubleArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case dastore: { double value = popDouble(t); int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < doubleArrayLength(t, array))) { memcpy(&doubleArrayBody(t, array, index), &value, sizeof(uint64_t)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, doubleArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case dcmpg: { double b = popDouble(t); double a = popDouble(t); if (isNaN(a) or isNaN(b)) { pushInt(t, 1); } if (a < b) { pushInt(t, static_cast(-1)); } else if (a > b) { pushInt(t, 1); } else if (a == b) { pushInt(t, 0); } else { pushInt(t, 1); } } goto loop; case dcmpl: { double b = popDouble(t); double a = popDouble(t); if (isNaN(a) or isNaN(b)) { pushInt(t, static_cast(-1)); } if (a < b) { pushInt(t, static_cast(-1)); } else if (a > b) { pushInt(t, 1); } else if (a == b) { pushInt(t, 0); } else { pushInt(t, static_cast(-1)); } } goto loop; case dconst_0: { pushDouble(t, 0); } goto loop; case dconst_1: { pushDouble(t, 1); } goto loop; case ddiv: { double b = popDouble(t); double a = popDouble(t); pushDouble(t, a / b); } goto loop; case dmul: { double b = popDouble(t); double a = popDouble(t); pushDouble(t, a * b); } goto loop; case dneg: { double a = popDouble(t); pushDouble(t, - a); } goto loop; case vm::drem: { double b = popDouble(t); double a = popDouble(t); pushDouble(t, fmod(a, b)); } goto loop; case dsub: { double b = popDouble(t); double a = popDouble(t); pushDouble(t, a - b); } goto loop; case dup: { if (DebugStack) { fprintf(stderr, "dup\n"); } memcpy(stack + ((sp ) * 2), stack + ((sp - 1) * 2), BytesPerWord * 2); ++ sp; } goto loop; case dup_x1: { if (DebugStack) { fprintf(stderr, "dup_x1\n"); } memcpy(stack + ((sp ) * 2), stack + ((sp - 1) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 1) * 2), stack + ((sp - 2) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 2) * 2), stack + ((sp ) * 2), BytesPerWord * 2); ++ sp; } goto loop; case dup_x2: { if (DebugStack) { fprintf(stderr, "dup_x2\n"); } memcpy(stack + ((sp ) * 2), stack + ((sp - 1) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 1) * 2), stack + ((sp - 2) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 2) * 2), stack + ((sp - 3) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 3) * 2), stack + ((sp ) * 2), BytesPerWord * 2); ++ sp; } goto loop; case dup2: { if (DebugStack) { fprintf(stderr, "dup2\n"); } memcpy(stack + ((sp ) * 2), stack + ((sp - 2) * 2), BytesPerWord * 4); sp += 2; } goto loop; case dup2_x1: { if (DebugStack) { fprintf(stderr, "dup2_x1\n"); } memcpy(stack + ((sp + 1) * 2), stack + ((sp - 1) * 2), BytesPerWord * 2); memcpy(stack + ((sp ) * 2), stack + ((sp - 2) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 1) * 2), stack + ((sp - 3) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 3) * 2), stack + ((sp ) * 2), BytesPerWord * 4); sp += 2; } goto loop; case dup2_x2: { if (DebugStack) { fprintf(stderr, "dup2_x2\n"); } memcpy(stack + ((sp + 1) * 2), stack + ((sp - 1) * 2), BytesPerWord * 2); memcpy(stack + ((sp ) * 2), stack + ((sp - 2) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 1) * 2), stack + ((sp - 3) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 2) * 2), stack + ((sp - 4) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 4) * 2), stack + ((sp ) * 2), BytesPerWord * 4); sp += 2; } goto loop; case f2d: { pushDouble(t, popFloat(t)); } goto loop; case f2i: { float f = popFloat(t); switch (fpclassify(f)) { case FP_NAN: pushInt(t, 0); break; case FP_INFINITE: pushInt(t, signbit(f) ? INT32_MIN : INT32_MAX); break; default: pushInt(t, f >= INT32_MAX ? INT32_MAX : (f <= INT32_MIN ? INT32_MIN : static_cast(f))); break; } } goto loop; case f2l: { float f = popFloat(t); switch (fpclassify(f)) { case FP_NAN: pushLong(t, 0); break; case FP_INFINITE: pushLong(t, signbit(f) ? INT64_MIN : INT64_MAX); break; default: pushLong(t, static_cast(f)); break; } } goto loop; case fadd: { float b = popFloat(t); float a = popFloat(t); pushFloat(t, a + b); } goto loop; case faload: { int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < floatArrayLength(t, array))) { pushInt(t, floatArrayBody(t, array, index)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, floatArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case fastore: { float value = popFloat(t); int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < floatArrayLength(t, array))) { memcpy(&floatArrayBody(t, array, index), &value, sizeof(uint32_t)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, floatArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case fcmpg: { float b = popFloat(t); float a = popFloat(t); if (isNaN(a) or isNaN(b)) { pushInt(t, 1); } if (a < b) { pushInt(t, static_cast(-1)); } else if (a > b) { pushInt(t, 1); } else if (a == b) { pushInt(t, 0); } else { pushInt(t, 1); } } goto loop; case fcmpl: { float b = popFloat(t); float a = popFloat(t); if (isNaN(a) or isNaN(b)) { pushInt(t, static_cast(-1)); } if (a < b) { pushInt(t, static_cast(-1)); } else if (a > b) { pushInt(t, 1); } else if (a == b) { pushInt(t, 0); } else { pushInt(t, static_cast(-1)); } } goto loop; case fconst_0: { pushFloat(t, 0); } goto loop; case fconst_1: { pushFloat(t, 1); } goto loop; case fconst_2: { pushFloat(t, 2); } goto loop; case fdiv: { float b = popFloat(t); float a = popFloat(t); pushFloat(t, a / b); } goto loop; case fmul: { float b = popFloat(t); float a = popFloat(t); pushFloat(t, a * b); } goto loop; case fneg: { float a = popFloat(t); pushFloat(t, - a); } goto loop; case frem: { float b = popFloat(t); float a = popFloat(t); pushFloat(t, fmodf(a, b)); } goto loop; case fsub: { float b = popFloat(t); float a = popFloat(t); pushFloat(t, a - b); } goto loop; case getfield: { if (LIKELY(peekObject(t, sp - 1))) { uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); pushField(t, popObject(t), field); } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case getstatic: { uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); assert(t, fieldFlags(t, field) & ACC_STATIC); PROTECT(t, field); initClass(t, fieldClass(t, field)); ACQUIRE_FIELD_FOR_READ(t, field); pushField(t, classStaticTable(t, fieldClass(t, field)), field); } goto loop; case goto_: { int16_t offset = codeReadInt16(t, code, ip); ip = (ip - 3) + offset; } goto back_branch; case goto_w: { int32_t offset = codeReadInt32(t, code, ip); ip = (ip - 5) + offset; } goto back_branch; case i2b: { pushInt(t, static_cast(popInt(t))); } goto loop; case i2c: { pushInt(t, static_cast(popInt(t))); } goto loop; case i2d: { pushDouble(t, static_cast(static_cast(popInt(t)))); } goto loop; case i2f: { pushFloat(t, static_cast(static_cast(popInt(t)))); } goto loop; case i2l: { pushLong(t, static_cast(popInt(t))); } goto loop; case i2s: { pushInt(t, static_cast(popInt(t))); } goto loop; case iadd: { int32_t b = popInt(t); int32_t a = popInt(t); pushInt(t, a + b); } goto loop; case iaload: { int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < intArrayLength(t, array))) { pushInt(t, intArrayBody(t, array, index)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, intArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case iand: { int32_t b = popInt(t); int32_t a = popInt(t); pushInt(t, a & b); } goto loop; case iastore: { int32_t value = popInt(t); int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < intArrayLength(t, array))) { intArrayBody(t, array, index) = value; } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, intArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case iconst_m1: { pushInt(t, static_cast(-1)); } goto loop; case iconst_0: { pushInt(t, 0); } goto loop; case iconst_1: { pushInt(t, 1); } goto loop; case iconst_2: { pushInt(t, 2); } goto loop; case iconst_3: { pushInt(t, 3); } goto loop; case iconst_4: { pushInt(t, 4); } goto loop; case iconst_5: { pushInt(t, 5); } goto loop; case idiv: { int32_t b = popInt(t); int32_t a = popInt(t); if (UNLIKELY(b == 0)) { exception = makeThrowable(t, Machine::ArithmeticExceptionType); goto throw_; } pushInt(t, a / b); } goto loop; case if_acmpeq: { int16_t offset = codeReadInt16(t, code, ip); object b = popObject(t); object a = popObject(t); if (a == b) { ip = (ip - 3) + offset; } } goto back_branch; case if_acmpne: { int16_t offset = codeReadInt16(t, code, ip); object b = popObject(t); object a = popObject(t); if (a != b) { ip = (ip - 3) + offset; } } goto back_branch; case if_icmpeq: { int16_t offset = codeReadInt16(t, code, ip); int32_t b = popInt(t); int32_t a = popInt(t); if (a == b) { ip = (ip - 3) + offset; } } goto back_branch; case if_icmpne: { int16_t offset = codeReadInt16(t, code, ip); int32_t b = popInt(t); int32_t a = popInt(t); if (a != b) { ip = (ip - 3) + offset; } } goto back_branch; case if_icmpgt: { int16_t offset = codeReadInt16(t, code, ip); int32_t b = popInt(t); int32_t a = popInt(t); if (a > b) { ip = (ip - 3) + offset; } } goto back_branch; case if_icmpge: { int16_t offset = codeReadInt16(t, code, ip); int32_t b = popInt(t); int32_t a = popInt(t); if (a >= b) { ip = (ip - 3) + offset; } } goto back_branch; case if_icmplt: { int16_t offset = codeReadInt16(t, code, ip); int32_t b = popInt(t); int32_t a = popInt(t); if (a < b) { ip = (ip - 3) + offset; } } goto back_branch; case if_icmple: { int16_t offset = codeReadInt16(t, code, ip); int32_t b = popInt(t); int32_t a = popInt(t); if (a <= b) { ip = (ip - 3) + offset; } } goto back_branch; case ifeq: { int16_t offset = codeReadInt16(t, code, ip); if (popInt(t) == 0) { ip = (ip - 3) + offset; } } goto back_branch; case ifne: { int16_t offset = codeReadInt16(t, code, ip); if (popInt(t)) { ip = (ip - 3) + offset; } } goto back_branch; case ifgt: { int16_t offset = codeReadInt16(t, code, ip); if (static_cast(popInt(t)) > 0) { ip = (ip - 3) + offset; } } goto back_branch; case ifge: { int16_t offset = codeReadInt16(t, code, ip); if (static_cast(popInt(t)) >= 0) { ip = (ip - 3) + offset; } } goto back_branch; case iflt: { int16_t offset = codeReadInt16(t, code, ip); if (static_cast(popInt(t)) < 0) { ip = (ip - 3) + offset; } } goto back_branch; case ifle: { int16_t offset = codeReadInt16(t, code, ip); if (static_cast(popInt(t)) <= 0) { ip = (ip - 3) + offset; } } goto back_branch; case ifnonnull: { int16_t offset = codeReadInt16(t, code, ip); if (popObject(t)) { ip = (ip - 3) + offset; } } goto back_branch; case ifnull: { int16_t offset = codeReadInt16(t, code, ip); if (popObject(t) == 0) { ip = (ip - 3) + offset; } } goto back_branch; case iinc: { uint8_t index = codeBody(t, code, ip++); int8_t c = codeBody(t, code, ip++); setLocalInt(t, index, localInt(t, index) + c); } goto loop; case iload: case fload: { pushInt(t, localInt(t, codeBody(t, code, ip++))); } goto loop; case iload_0: case fload_0: { pushInt(t, localInt(t, 0)); } goto loop; case iload_1: case fload_1: { pushInt(t, localInt(t, 1)); } goto loop; case iload_2: case fload_2: { pushInt(t, localInt(t, 2)); } goto loop; case iload_3: case fload_3: { pushInt(t, localInt(t, 3)); } goto loop; case imul: { int32_t b = popInt(t); int32_t a = popInt(t); pushInt(t, a * b); } goto loop; case ineg: { pushInt(t, - popInt(t)); } goto loop; case instanceof: { uint16_t index = codeReadInt16(t, code, ip); if (peekObject(t, sp - 1)) { object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); if (instanceOf(t, class_, popObject(t))) { pushInt(t, 1); } else { pushInt(t, 0); } } else { popObject(t); pushInt(t, 0); } } goto loop; case invokeinterface: { uint16_t index = codeReadInt16(t, code, ip); ip += 2; object method = resolveMethod(t, frameMethod(t, frame), index - 1); unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { code = findInterfaceMethod (t, method, objectClass(t, peekObject(t, sp - parameterFootprint))); goto invoke; } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case invokespecial: { uint16_t index = codeReadInt16(t, code, ip); object method = resolveMethod(t, frameMethod(t, frame), index - 1); unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { object class_ = methodClass(t, frameMethod(t, frame)); if (isSpecialMethod(t, method, class_)) { class_ = classSuper(t, class_); PROTECT(t, method); PROTECT(t, class_); initClass(t, class_); code = findVirtualMethod(t, method, class_); } else { code = method; } goto invoke; } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case invokestatic: { uint16_t index = codeReadInt16(t, code, ip); object method = resolveMethod(t, frameMethod(t, frame), index - 1); PROTECT(t, method); initClass(t, methodClass(t, method)); code = method; } goto invoke; case invokevirtual: { uint16_t index = codeReadInt16(t, code, ip); object method = resolveMethod(t, frameMethod(t, frame), index - 1); unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { object class_ = objectClass(t, peekObject(t, sp - parameterFootprint)); PROTECT(t, method); PROTECT(t, class_); code = findVirtualMethod(t, method, class_); goto invoke; } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case ior: { int32_t b = popInt(t); int32_t a = popInt(t); pushInt(t, a | b); } goto loop; case irem: { int32_t b = popInt(t); int32_t a = popInt(t); if (UNLIKELY(b == 0)) { exception = makeThrowable(t, Machine::ArithmeticExceptionType); goto throw_; } pushInt(t, a % b); } goto loop; case ireturn: case freturn: { int32_t result = popInt(t); if (frame > base) { popFrame(t); pushInt(t, result); goto loop; } else { return makeInt(t, result); } } goto loop; case ishl: { int32_t b = popInt(t); int32_t a = popInt(t); pushInt(t, a << (b & 0x1F)); } goto loop; case ishr: { int32_t b = popInt(t); int32_t a = popInt(t); pushInt(t, a >> (b & 0x1F)); } goto loop; case istore: case fstore: { setLocalInt(t, codeBody(t, code, ip++), popInt(t)); } goto loop; case istore_0: case fstore_0: { setLocalInt(t, 0, popInt(t)); } goto loop; case istore_1: case fstore_1: { setLocalInt(t, 1, popInt(t)); } goto loop; case istore_2: case fstore_2: { setLocalInt(t, 2, popInt(t)); } goto loop; case istore_3: case fstore_3: { setLocalInt(t, 3, popInt(t)); } goto loop; case isub: { int32_t b = popInt(t); int32_t a = popInt(t); pushInt(t, a - b); } goto loop; case iushr: { int32_t b = popInt(t); uint32_t a = popInt(t); pushInt(t, a >> (b & 0x1F)); } goto loop; case ixor: { int32_t b = popInt(t); int32_t a = popInt(t); pushInt(t, a ^ b); } goto loop; case jsr: { uint16_t offset = codeReadInt16(t, code, ip); pushInt(t, ip); ip = (ip - 3) + static_cast(offset); } goto loop; case jsr_w: { uint32_t offset = codeReadInt32(t, code, ip); pushInt(t, ip); ip = (ip - 5) + static_cast(offset); } goto loop; case l2d: { pushDouble(t, static_cast(static_cast(popLong(t)))); } goto loop; case l2f: { pushFloat(t, static_cast(static_cast(popLong(t)))); } goto loop; case l2i: { pushInt(t, static_cast(popLong(t))); } goto loop; case ladd: { int64_t b = popLong(t); int64_t a = popLong(t); pushLong(t, a + b); } goto loop; case laload: { int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < longArrayLength(t, array))) { pushLong(t, longArrayBody(t, array, index)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, longArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case land: { int64_t b = popLong(t); int64_t a = popLong(t); pushLong(t, a & b); } goto loop; case lastore: { int64_t value = popLong(t); int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < longArrayLength(t, array))) { longArrayBody(t, array, index) = value; } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, longArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case lcmp: { int64_t b = popLong(t); int64_t a = popLong(t); pushInt(t, a > b ? 1 : a == b ? 0 : -1); } goto loop; case lconst_0: { pushLong(t, 0); } goto loop; case lconst_1: { pushLong(t, 1); } goto loop; case ldc: case ldc_w: { uint16_t index; if (instruction == ldc) { index = codeBody(t, code, ip++); } else { index = codeReadInt16(t, code, ip); } object pool = codePool(t, code); if (singletonIsObject(t, pool, index - 1)) { object v = singletonObject(t, pool, index - 1); if (objectClass(t, v) == type(t, Machine::ReferenceType)) { object class_ = resolveClassInPool (t, frameMethod(t, frame), index - 1); pushObject(t, getJClass(t, class_)); } else if (objectClass(t, v) == type(t, Machine::ClassType)) { pushObject(t, getJClass(t, v)); } else { pushObject(t, v); } } else { pushInt(t, singletonValue(t, pool, index - 1)); } } goto loop; case ldc2_w: { uint16_t index = codeReadInt16(t, code, ip); object pool = codePool(t, code); uint64_t v; memcpy(&v, &singletonValue(t, pool, index - 1), 8); pushLong(t, v); } goto loop; case ldiv_: { int64_t b = popLong(t); int64_t a = popLong(t); if (UNLIKELY(b == 0)) { exception = makeThrowable(t, Machine::ArithmeticExceptionType); goto throw_; } pushLong(t, a / b); } goto loop; case lload: case dload: { pushLong(t, localLong(t, codeBody(t, code, ip++))); } goto loop; case lload_0: case dload_0: { pushLong(t, localLong(t, 0)); } goto loop; case lload_1: case dload_1: { pushLong(t, localLong(t, 1)); } goto loop; case lload_2: case dload_2: { pushLong(t, localLong(t, 2)); } goto loop; case lload_3: case dload_3: { pushLong(t, localLong(t, 3)); } goto loop; case lmul: { int64_t b = popLong(t); int64_t a = popLong(t); pushLong(t, a * b); } goto loop; case lneg: { pushLong(t, - popLong(t)); } goto loop; case lookupswitch: { int32_t base = ip - 1; ip += 3; ip -= (ip % 4); int32_t default_ = codeReadInt32(t, code, ip); int32_t pairCount = codeReadInt32(t, code, ip); int32_t key = popInt(t); int32_t bottom = 0; int32_t top = pairCount; for (int32_t span = top - bottom; span; span = top - bottom) { int32_t middle = bottom + (span / 2); unsigned index = ip + (middle * 8); int32_t k = codeReadInt32(t, code, index); if (key < k) { top = middle; } else if (key > k) { bottom = middle + 1; } else { ip = base + codeReadInt32(t, code, index); goto loop; } } ip = base + default_; } goto loop; case lor: { int64_t b = popLong(t); int64_t a = popLong(t); pushLong(t, a | b); } goto loop; case lrem: { int64_t b = popLong(t); int64_t a = popLong(t); if (UNLIKELY(b == 0)) { exception = makeThrowable(t, Machine::ArithmeticExceptionType); goto throw_; } pushLong(t, a % b); } goto loop; case lreturn: case dreturn: { int64_t result = popLong(t); if (frame > base) { popFrame(t); pushLong(t, result); goto loop; } else { return makeLong(t, result); } } goto loop; case lshl: { int32_t b = popInt(t); int64_t a = popLong(t); pushLong(t, a << (b & 0x3F)); } goto loop; case lshr: { int32_t b = popInt(t); int64_t a = popLong(t); pushLong(t, a >> (b & 0x3F)); } goto loop; case lstore: case dstore: { setLocalLong(t, codeBody(t, code, ip++), popLong(t)); } goto loop; case lstore_0: case dstore_0:{ setLocalLong(t, 0, popLong(t)); } goto loop; case lstore_1: case dstore_1: { setLocalLong(t, 1, popLong(t)); } goto loop; case lstore_2: case dstore_2: { setLocalLong(t, 2, popLong(t)); } goto loop; case lstore_3: case dstore_3: { setLocalLong(t, 3, popLong(t)); } goto loop; case lsub: { int64_t b = popLong(t); int64_t a = popLong(t); pushLong(t, a - b); } goto loop; case lushr: { int64_t b = popInt(t); uint64_t a = popLong(t); pushLong(t, a >> (b & 0x3F)); } goto loop; case lxor: { int64_t b = popLong(t); int64_t a = popLong(t); pushLong(t, a ^ b); } goto loop; case monitorenter: { object o = popObject(t); if (LIKELY(o)) { acquire(t, o); } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case monitorexit: { object o = popObject(t); if (LIKELY(o)) { release(t, o); } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case multianewarray: { uint16_t index = codeReadInt16(t, code, ip); uint8_t dimensions = codeBody(t, code, ip++); object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); PROTECT(t, class_); THREAD_RUNTIME_ARRAY(t, int32_t, counts, dimensions); for (int i = dimensions - 1; i >= 0; --i) { RUNTIME_ARRAY_BODY(counts)[i] = popInt(t); if (UNLIKELY(RUNTIME_ARRAY_BODY(counts)[i] < 0)) { exception = makeThrowable (t, Machine::NegativeArraySizeExceptionType, "%d", RUNTIME_ARRAY_BODY(counts)[i]); goto throw_; } } object array = makeArray(t, RUNTIME_ARRAY_BODY(counts)[0]); setObjectClass(t, array, class_); PROTECT(t, array); populateMultiArray(t, array, RUNTIME_ARRAY_BODY(counts), 0, dimensions); pushObject(t, array); } goto loop; case new_: { uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); PROTECT(t, class_); initClass(t, class_); pushObject(t, make(t, class_)); } goto loop; case newarray: { int32_t count = popInt(t); if (LIKELY(count >= 0)) { uint8_t type = codeBody(t, code, ip++); object array; switch (type) { case T_BOOLEAN: array = makeBooleanArray(t, count); break; case T_CHAR: array = makeCharArray(t, count); break; case T_FLOAT: array = makeFloatArray(t, count); break; case T_DOUBLE: array = makeDoubleArray(t, count); break; case T_BYTE: array = makeByteArray(t, count); break; case T_SHORT: array = makeShortArray(t, count); break; case T_INT: array = makeIntArray(t, count); break; case T_LONG: array = makeLongArray(t, count); break; default: abort(t); } pushObject(t, array); } else { exception = makeThrowable (t, Machine::NegativeArraySizeExceptionType, "%d", count); goto throw_; } } goto loop; case nop: goto loop; case pop_: { -- sp; } goto loop; case pop2: { sp -= 2; } goto loop; case putfield: { uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); PROTECT(t, field); { ACQUIRE_FIELD_FOR_WRITE(t, field); switch (fieldCode(t, field)) { case ByteField: case BooleanField: case CharField: case ShortField: case FloatField: case IntField: { int32_t value = popInt(t); object o = popObject(t); if (LIKELY(o)) { switch (fieldCode(t, field)) { case ByteField: case BooleanField: fieldAtOffset(o, fieldOffset(t, field)) = value; break; case CharField: case ShortField: fieldAtOffset(o, fieldOffset(t, field)) = value; break; case FloatField: case IntField: fieldAtOffset(o, fieldOffset(t, field)) = value; break; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); } } break; case DoubleField: case LongField: { int64_t value = popLong(t); object o = popObject(t); if (LIKELY(o)) { fieldAtOffset(o, fieldOffset(t, field)) = value; } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); } } break; case ObjectField: { object value = popObject(t); object o = popObject(t); if (LIKELY(o)) { set(t, o, fieldOffset(t, field), value); } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); } } break; default: abort(t); } } if (UNLIKELY(exception)) { goto throw_; } } goto loop; case putstatic: { uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); assert(t, fieldFlags(t, field) & ACC_STATIC); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); initClass(t, fieldClass(t, field)); object table = classStaticTable(t, fieldClass(t, field)); switch (fieldCode(t, field)) { case ByteField: case BooleanField: case CharField: case ShortField: case FloatField: case IntField: { int32_t value = popInt(t); switch (fieldCode(t, field)) { case ByteField: case BooleanField: fieldAtOffset(table, fieldOffset(t, field)) = value; break; case CharField: case ShortField: fieldAtOffset(table, fieldOffset(t, field)) = value; break; case FloatField: case IntField: fieldAtOffset(table, fieldOffset(t, field)) = value; break; } } break; case DoubleField: case LongField: { fieldAtOffset(table, fieldOffset(t, field)) = popLong(t); } break; case ObjectField: { set(t, table, fieldOffset(t, field), popObject(t)); } break; default: abort(t); } } goto loop; case ret: { ip = localInt(t, codeBody(t, code, ip)); } goto loop; case return_: { object method = frameMethod(t, frame); if ((methodFlags(t, method) & ConstructorFlag) and (classVmFlags(t, methodClass(t, method)) & HasFinalMemberFlag)) { storeStoreMemoryBarrier(); } if (frame > base) { popFrame(t); goto loop; } else { return 0; } } goto loop; case saload: { int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < shortArrayLength(t, array))) { pushInt(t, shortArrayBody(t, array, index)); } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, shortArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case sastore: { int16_t value = popInt(t); int32_t index = popInt(t); object array = popObject(t); if (LIKELY(array)) { if (LIKELY(index >= 0 and static_cast(index) < shortArrayLength(t, array))) { shortArrayBody(t, array, index) = value; } else { exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", index, shortArrayLength(t, array)); goto throw_; } } else { exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; case sipush: { pushInt(t, static_cast(codeReadInt16(t, code, ip))); } goto loop; case swap: { uintptr_t tmp[2]; memcpy(tmp , stack + ((sp - 1) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 1) * 2), stack + ((sp - 2) * 2), BytesPerWord * 2); memcpy(stack + ((sp - 2) * 2), tmp , BytesPerWord * 2); } goto loop; case tableswitch: { int32_t base = ip - 1; ip += 3; ip -= (ip % 4); int32_t default_ = codeReadInt32(t, code, ip); int32_t bottom = codeReadInt32(t, code, ip); int32_t top = codeReadInt32(t, code, ip); int32_t key = popInt(t); if (key >= bottom and key <= top) { unsigned index = ip + ((key - bottom) * 4); ip = base + codeReadInt32(t, code, index); } else { ip = base + default_; } } goto loop; case wide: goto wide; case impdep1: { // this means we're invoking a virtual method on an instance of a // bootstrap class, so we need to load the real class to get the // real method and call it. assert(t, frameNext(t, frame) >= base); popFrame(t); assert(t, codeBody(t, code, ip - 3) == invokevirtual); ip -= 2; uint16_t index = codeReadInt16(t, code, ip); object method = resolveMethod(t, frameMethod(t, frame), index - 1); unsigned parameterFootprint = methodParameterFootprint(t, method); object class_ = objectClass(t, peekObject(t, sp - parameterFootprint)); assert(t, classVmFlags(t, class_) & BootstrapFlag); resolveClass(t, classLoader(t, methodClass(t, frameMethod(t, frame))), className(t, class_)); ip -= 3; } goto loop; default: abort(t); } wide: switch (codeBody(t, code, ip++)) { case aload: { pushObject(t, localObject(t, codeReadInt16(t, code, ip))); } goto loop; case astore: { setLocalObject(t, codeReadInt16(t, code, ip), popObject(t)); } goto loop; case iinc: { uint16_t index = codeReadInt16(t, code, ip); int16_t count = codeReadInt16(t, code, ip); setLocalInt(t, index, localInt(t, index) + count); } goto loop; case iload: { pushInt(t, localInt(t, codeReadInt16(t, code, ip))); } goto loop; case istore: { setLocalInt(t, codeReadInt16(t, code, ip), popInt(t)); } goto loop; case lload: { pushLong(t, localLong(t, codeReadInt16(t, code, ip))); } goto loop; case lstore: { setLocalLong(t, codeReadInt16(t, code, ip), popLong(t)); } goto loop; case ret: { ip = localInt(t, codeReadInt16(t, code, ip)); } goto loop; default: abort(t); } back_branch: safePoint(t); goto loop; invoke: { if (methodFlags(t, code) & ACC_NATIVE) { invokeNative(t, code); } else { checkStack(t, code); pushFrame(t, code); } } goto loop; throw_: if (DebugRun) { fprintf(stderr, "throw\n"); } pokeInt(t, t->frame + FrameIpOffset, t->ip); for (; frame >= base; popFrame(t)) { uint64_t eh = findExceptionHandler(t, frame); if (eh) { sp = frame + FrameFootprint; ip = exceptionHandlerIp(eh); pushObject(t, exception); exception = 0; goto loop; } } return 0; } uint64_t interpret2(vm::Thread* t, uintptr_t* arguments) { int base = arguments[0]; bool* success = reinterpret_cast(arguments[1]); object r = interpret3(static_cast(t), base); *success = true; return reinterpret_cast(r); } object interpret(Thread* t) { const int base = t->frame; while (true) { bool success = false; uintptr_t arguments[] = { static_cast(base), reinterpret_cast(&success) }; uint64_t r = run(t, interpret2, arguments); if (success) { if (t->exception) { object exception = t->exception; t->exception = 0; throw_(t, exception); } else { return reinterpret_cast(r); } } } } void pushArguments(Thread* t, object this_, const char* spec, bool indirectObjects, va_list a) { if (this_) { pushObject(t, this_); } for (MethodSpecIterator it(t, spec); it.hasNext();) { switch (*it.next()) { case 'L': case '[': if (indirectObjects) { object* v = va_arg(a, object*); pushObject(t, v ? *v : 0); } else { pushObject(t, va_arg(a, object)); } break; case 'J': case 'D': pushLong(t, va_arg(a, uint64_t)); break; case 'F': { pushFloat(t, va_arg(a, double)); } break; default: pushInt(t, va_arg(a, uint32_t)); break; } } } void pushArguments(Thread* t, object this_, const char* spec, const jvalue* arguments) { if (this_) { pushObject(t, this_); } unsigned index = 0; for (MethodSpecIterator it(t, spec); it.hasNext();) { switch (*it.next()) { case 'L': case '[': { jobject v = arguments[index++].l; pushObject(t, v ? *v : 0); } break; case 'J': case 'D': pushLong(t, arguments[index++].j); break; case 'F': { pushFloat(t, arguments[index++].f); } break; default: pushInt(t, arguments[index++].i); break; } } } void pushArguments(Thread* t, object this_, const char* spec, object a) { if (this_) { pushObject(t, this_); } unsigned index = 0; for (MethodSpecIterator it(t, spec); it.hasNext();) { switch (*it.next()) { case 'L': case '[': pushObject(t, objectArrayBody(t, a, index++)); break; case 'J': case 'D': pushLong(t, fieldAtOffset(objectArrayBody(t, a, index++), 8)); break; default: pushInt(t, fieldAtOffset(objectArrayBody(t, a, index++), BytesPerWord)); break; } } } object invoke(Thread* t, object method) { PROTECT(t, method); object class_; PROTECT(t, class_); if (methodVirtual(t, method)) { unsigned parameterFootprint = methodParameterFootprint(t, method); class_ = objectClass(t, peekObject(t, t->sp - parameterFootprint)); if (classVmFlags(t, class_) & BootstrapFlag) { resolveClass(t, root(t, Machine::BootLoader), className(t, class_)); } if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { method = findInterfaceMethod(t, method, class_); } else { method = findVirtualMethod(t, method, class_); } } else { class_ = methodClass(t, method); } if (methodFlags(t, method) & ACC_STATIC) { initClass(t, class_); } object result = 0; if (methodFlags(t, method) & ACC_NATIVE) { unsigned returnCode = invokeNative(t, method); switch (returnCode) { case ByteField: case BooleanField: case CharField: case ShortField: case FloatField: case IntField: result = makeInt(t, popInt(t)); break; case LongField: case DoubleField: result = makeLong(t, popLong(t)); break; case ObjectField: result = popObject(t); break; case VoidField: result = 0; break; default: abort(t); }; } else { checkStack(t, method); pushFrame(t, method); result = interpret(t); if (LIKELY(t->exception == 0)) { popFrame(t); } else { object exception = t->exception; t->exception = 0; throw_(t, exception); } } return result; } class MyProcessor: public Processor { public: MyProcessor(System* s, Allocator* allocator, const char* crashDumpDirectory) : s(s), allocator(allocator) { signals.setCrashDumpDirectory(crashDumpDirectory); } virtual vm::Thread* makeThread(Machine* m, object javaThread, vm::Thread* parent) { Thread* t = new (m->heap->allocate(sizeof(Thread) + m->stackSizeInBytes)) Thread(m, javaThread, parent); t->init(); return t; } virtual object makeMethod(vm::Thread* t, uint8_t vmFlags, uint8_t returnCode, uint8_t parameterCount, uint8_t parameterFootprint, uint16_t flags, uint16_t offset, object name, object spec, object addendum, object class_, object code) { return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, offset, 0, 0, name, spec, addendum, class_, code); } virtual object makeClass(vm::Thread* t, uint16_t flags, uint16_t vmFlags, uint16_t fixedSize, uint8_t arrayElementSize, uint8_t arrayDimensions, object objectMask, object name, object sourceFile, object super, object interfaceTable, object virtualTable, object fieldTable, object methodTable, object addendum, object staticTable, object loader, unsigned vtableLength UNUSED) { return vm::makeClass (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, 0, objectMask, name, sourceFile, super, interfaceTable, virtualTable, fieldTable, methodTable, addendum, staticTable, loader, 0, 0); } virtual void initVtable(vm::Thread*, object) { // ignore } virtual void visitObjects(vm::Thread* vmt, Heap::Visitor* v) { Thread* t = static_cast(vmt); v->visit(&(t->code)); for (unsigned i = 0; i < t->sp; ++i) { if (t->stack[i * 2] == ObjectTag) { v->visit(reinterpret_cast(t->stack + (i * 2) + 1)); } } } virtual void walkStack(vm::Thread* vmt, StackVisitor* v) { Thread* t = static_cast(vmt); if (t->frame >= 0) { pokeInt(t, t->frame + FrameIpOffset, t->ip); } MyStackWalker walker(t, t->frame); walker.walk(v); } virtual int lineNumber(vm::Thread* t, object method, int ip) { return findLineNumber(static_cast(t), method, ip); } virtual object* makeLocalReference(vm::Thread* vmt, object o) { Thread* t = static_cast(vmt); return pushReference(t, o); } virtual void disposeLocalReference(vm::Thread*, object* r) { if (r) { *r = 0; } } virtual bool pushLocalFrame(vm::Thread* vmt, unsigned capacity) { Thread* t = static_cast(vmt); if (t->sp + capacity < stackSizeInWords(t) / 2) { t->stackPointers = new(t->m->heap) List(t->sp, t->stackPointers); return true; } else { return false; } } virtual void popLocalFrame(vm::Thread* vmt) { Thread* t = static_cast(vmt); List* f = t->stackPointers; t->stackPointers = f->next; t->sp = f->item; t->m->heap->free(f, sizeof(List)); } virtual object invokeArray(vm::Thread* vmt, object method, object this_, object arguments) { Thread* t = static_cast(vmt); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > stackSizeInWords(t) / 2)) { throwNew(t, Machine::StackOverflowErrorType); } const char* spec = reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), 0)); pushArguments(t, this_, spec, arguments); return local::invoke(t, method); } virtual object invokeArray(vm::Thread* vmt, object method, object this_, const jvalue* arguments) { Thread* t = static_cast(vmt); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > stackSizeInWords(t) / 2)) { throwNew(t, Machine::StackOverflowErrorType); } const char* spec = reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), 0)); pushArguments(t, this_, spec, arguments); return local::invoke(t, method); } virtual object invokeList(vm::Thread* vmt, object method, object this_, bool indirectObjects, va_list arguments) { Thread* t = static_cast(vmt); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > stackSizeInWords(t) / 2)) { throwNew(t, Machine::StackOverflowErrorType); } const char* spec = reinterpret_cast (&byteArrayBody(t, methodSpec(t, method), 0)); pushArguments(t, this_, spec, indirectObjects, arguments); return local::invoke(t, method); } virtual object invokeList(vm::Thread* vmt, object loader, const char* className, const char* methodName, const char* methodSpec, object this_, va_list arguments) { Thread* t = static_cast(vmt); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false) > stackSizeInWords(t) / 2)) { throwNew(t, Machine::StackOverflowErrorType); } pushArguments(t, this_, methodSpec, false, arguments); object method = resolveMethod (t, loader, className, methodName, methodSpec); assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); return local::invoke(t, method); } virtual object getStackTrace(vm::Thread* t, vm::Thread*) { // not implemented return makeObjectArray(t, 0); } virtual void initialize(BootImage*, avian::util::Slice) { abort(s); } virtual void addCompilationHandler(CompilationHandler*) { abort(s); } virtual void compileMethod(vm::Thread*, Zone*, object*, object*, avian::codegen::DelayedPromise**, object, OffsetResolver*) { abort(s); } virtual void visitRoots(vm::Thread*, HeapWalker*) { abort(s); } virtual void normalizeVirtualThunks(vm::Thread*) { abort(s); } virtual unsigned* makeCallTable(vm::Thread*, HeapWalker*) { abort(s); } virtual void boot(vm::Thread*, BootImage* image, uint8_t* code) { expect(s, image == 0 and code == 0); } virtual void callWithCurrentContinuation(vm::Thread*, object) { abort(s); } virtual void dynamicWind(vm::Thread*, object, object, object) { abort(s); } virtual void feedResultToContinuation(vm::Thread*, object, object){ abort(s); } virtual void feedExceptionToContinuation(vm::Thread*, object, object) { abort(s); } virtual void walkContinuationBody(vm::Thread*, Heap::Walker*, object, unsigned) { abort(s); } virtual void dispose(vm::Thread* t) { t->m->heap->free(t, sizeof(Thread) + t->m->stackSizeInBytes); } virtual void dispose() { allocator->free(this, sizeof(*this)); signals.setCrashDumpDirectory(0); } System* s; Allocator* allocator; SignalRegistrar signals; }; } // namespace namespace vm { Processor* makeProcessor(System* system, Allocator* allocator, const char* crashDumpDirectory, bool) { return new (allocator->allocate(sizeof(local::MyProcessor))) local::MyProcessor(system, allocator, crashDumpDirectory); } } // namespace vm ReadyTalk-avian-1e1fff5/src/jnienv.cpp000066400000000000000000003042321231440243200177500ustar00rootroot00000000000000/* Copyright (c) 2008-2011 Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/jnienv.h" #include "avian/machine.h" #include "avian/util.h" #include "avian/processor.h" #include "avian/constants.h" #include using namespace vm; namespace { namespace local { jint JNICALL AttachCurrentThread(Machine* m, Thread** t, void*) { *t = static_cast(m->localThread->get()); if (*t == 0) { *t = attachThread(m, false); } return 0; } jint JNICALL AttachCurrentThreadAsDaemon(Machine* m, Thread** t, void*) { *t = static_cast(m->localThread->get()); if (*t == 0) { *t = attachThread(m, true); } return 0; } jint JNICALL DetachCurrentThread(Machine* m) { Thread* t = static_cast(m->localThread->get()); if (t) { // todo: detaching the root thread seems to cause stability // problems which I haven't yet had a chance to investigate // thoroughly. Meanwhile, we just ignore requests to detach it, // which leaks a bit of memory but should be harmless otherwise. if (m->rootThread != t) { m->localThread->set(0); ACQUIRE_RAW(t, t->m->stateLock); enter(t, Thread::ActiveState); threadPeer(t, t->javaThread) = 0; enter(t, Thread::ZombieState); t->state = Thread::JoinedState; } return 0; } else { return -1; } } uint64_t destroyJavaVM(Thread* t, uintptr_t*) { // wait for other non-daemon threads to exit { ACQUIRE(t, t->m->stateLock); while (t->m->liveCount - t->m->daemonCount > 1) { t->m->stateLock->wait(t->systemThread, 0); } } { ENTER(t, Thread::ActiveState); t->m->classpath->shutDown(t); } // wait again in case the Classpath::shutDown process started new // threads: { ACQUIRE(t, t->m->stateLock); while (t->m->liveCount - t->m->daemonCount > 1) { t->m->stateLock->wait(t->systemThread, 0); } enter(t, Thread::ExclusiveState); } shutDown(t); return 1; } jint JNICALL DestroyJavaVM(Machine* m) { Thread* t; AttachCurrentThread(m, &t, 0); if (runRaw(t, destroyJavaVM, 0)) { t->exit(); return 0; } else { return -1; } } jint JNICALL GetEnv(Machine* m, Thread** t, jint version) { *t = static_cast(m->localThread->get()); if (*t) { if (version <= JNI_VERSION_1_6) { return AVIAN_JNI_OK; } else { return AVIAN_JNI_EVERSION; } } else { return AVIAN_JNI_EDETACHED; } } jint JNICALL GetVersion(Thread* t) { ENTER(t, Thread::ActiveState); return JNI_VERSION_1_6; } jsize JNICALL GetStringLength(Thread* t, jstring s) { ENTER(t, Thread::ActiveState); return stringLength(t, *s); } const jchar* JNICALL GetStringChars(Thread* t, jstring s, jboolean* isCopy) { ENTER(t, Thread::ActiveState); jchar* chars = static_cast (t->m->heap->allocate((stringLength(t, *s) + 1) * sizeof(jchar))); stringChars(t, *s, chars); if (isCopy) *isCopy = true; return chars; } void JNICALL ReleaseStringChars(Thread* t, jstring s, const jchar* chars) { ENTER(t, Thread::ActiveState); t->m->heap->free(chars, (stringLength(t, *s) + 1) * sizeof(jchar)); } void JNICALL GetStringRegion(Thread* t, jstring s, jsize start, jsize length, jchar* dst) { ENTER(t, Thread::ActiveState); stringChars(t, *s, start, length, dst); } const jchar* JNICALL GetStringCritical(Thread* t, jstring s, jboolean* isCopy) { if (t->criticalLevel == 0) { enter(t, Thread::ActiveState); } ++ t->criticalLevel; if (isCopy) { *isCopy = true; } object data = stringData(t, *s); if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { return GetStringChars(t, s, isCopy); } else { return &charArrayBody(t, data, stringOffset(t, *s)); } } void JNICALL ReleaseStringCritical(Thread* t, jstring s, const jchar* chars) { if (objectClass(t, stringData(t, *s)) == type(t, Machine::ByteArrayType)) { ReleaseStringChars(t, s, chars); } if ((-- t->criticalLevel) == 0) { enter(t, Thread::IdleState); } } jsize JNICALL GetStringUTFLength(Thread* t, jstring s) { ENTER(t, Thread::ActiveState); return stringUTFLength(t, *s); } const char* JNICALL GetStringUTFChars(Thread* t, jstring s, jboolean* isCopy) { ENTER(t, Thread::ActiveState); int length = stringUTFLength(t, *s); char* chars = static_cast (t->m->heap->allocate(length + 1)); stringUTFChars(t, *s, chars, length); if (isCopy) *isCopy = true; return chars; } void JNICALL ReleaseStringUTFChars(Thread* t, jstring s, const char* chars) { ENTER(t, Thread::ActiveState); t->m->heap->free(chars, stringUTFLength(t, *s) + 1); } void JNICALL GetStringUTFRegion(Thread* t, jstring s, jsize start, jsize length, char* dst) { ENTER(t, Thread::ActiveState); stringUTFChars (t, *s, start, length, dst, stringUTFLength(t, *s, start, length)); } jsize JNICALL GetArrayLength(Thread* t, jarray array) { ENTER(t, Thread::ActiveState); return fieldAtOffset(*array, BytesPerWord); } uint64_t newString(Thread* t, uintptr_t* arguments) { const jchar* chars = reinterpret_cast(arguments[0]); jsize size = arguments[1]; object a = makeCharArray(t, size); if (size) { memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar)); } return reinterpret_cast (makeLocalReference(t, t->m->classpath->makeString(t, a, 0, size))); } jstring JNICALL NewString(Thread* t, const jchar* chars, jsize size) { if (chars == 0) return 0; uintptr_t arguments[] = { reinterpret_cast(chars), static_cast(size) }; return reinterpret_cast(run(t, newString, arguments)); } uint64_t newStringUTF(Thread* t, uintptr_t* arguments) { const char* chars = reinterpret_cast(arguments[0]); object array = parseUtf8(t, chars, strlen(chars)); return reinterpret_cast (makeLocalReference (t, t->m->classpath->makeString (t, array, 0, fieldAtOffset(array, BytesPerWord) - 1))); } jstring JNICALL NewStringUTF(Thread* t, const char* chars) { if (chars == 0) return 0; uintptr_t arguments[] = { reinterpret_cast(chars) }; return reinterpret_cast(run(t, newStringUTF, arguments)); } void replace(int a, int b, const char* in, int8_t* out) { while (*in) { *out = (*in == a ? b : *in); ++ in; ++ out; } *out = 0; } uint64_t defineClass(Thread* t, uintptr_t* arguments) { jobject loader = reinterpret_cast(arguments[0]); const uint8_t* buffer = reinterpret_cast(arguments[1]); jsize length = arguments[2]; return reinterpret_cast (makeLocalReference (t, getJClass (t, defineClass (t, loader ? *loader : root(t, Machine::BootLoader), buffer, length)))); } jclass JNICALL DefineClass(Thread* t, const char*, jobject loader, const jbyte* buffer, jsize length) { uintptr_t arguments[] = { reinterpret_cast(loader), reinterpret_cast(buffer), static_cast(length) }; return reinterpret_cast(run(t, defineClass, arguments)); } uint64_t findClass(Thread* t, uintptr_t* arguments) { const char* name = reinterpret_cast(arguments[0]); object n = makeByteArray(t, strlen(name) + 1); replace('.', '/', name, &byteArrayBody(t, n, 0)); object caller = getCaller(t, 0); return reinterpret_cast (makeLocalReference (t, getJClass (t, resolveClass (t, caller ? classLoader(t, methodClass(t, caller)) : root(t, Machine::AppLoader), n)))); } jclass JNICALL FindClass(Thread* t, const char* name) { uintptr_t arguments[] = { reinterpret_cast(name) }; return reinterpret_cast(run(t, findClass, arguments)); } uint64_t throwNew(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); const char* message = reinterpret_cast(arguments[1]); object m = 0; PROTECT(t, m); if (message) { m = makeString(t, "%s", message); } object trace = makeTrace(t); PROTECT(t, trace); t->exception = make(t, jclassVmClass(t, *c)); set(t, t->exception, ThrowableMessage, m); set(t, t->exception, ThrowableTrace, trace); return 1; } jint JNICALL ThrowNew(Thread* t, jclass c, const char* message) { if (t->exception) { return -1; } uintptr_t arguments[] = { reinterpret_cast(c), reinterpret_cast(message) }; return run(t, throwNew, arguments) ? 0 : -1; } jint JNICALL Throw(Thread* t, jthrowable throwable) { if (t->exception) { return -1; } ENTER(t, Thread::ActiveState); t->exception = *throwable; return 0; } jobject JNICALL NewLocalRef(Thread* t, jobject o) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, *o); } void JNICALL DeleteLocalRef(Thread* t, jobject r) { ENTER(t, Thread::ActiveState); disposeLocalReference(t, r); } jboolean JNICALL ExceptionCheck(Thread* t) { return t->exception != 0; } uint64_t getObjectClass(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); return reinterpret_cast (makeLocalReference(t, getJClass(t, objectClass(t, *o)))); } jclass JNICALL GetObjectClass(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(o) }; return reinterpret_cast(run(t, getObjectClass, arguments)); } uint64_t getSuperclass(Thread* t, uintptr_t* arguments) { object class_ = jclassVmClass(t, *reinterpret_cast(arguments[0])); if (classFlags(t, class_) & ACC_INTERFACE) { return 0; } else { object super = classSuper(t, class_); return super ? reinterpret_cast (makeLocalReference(t, getJClass(t, super))) : 0; } } jclass JNICALL GetSuperclass(Thread* t, jclass c) { uintptr_t arguments[] = { reinterpret_cast(c) }; return reinterpret_cast(run(t, getSuperclass, arguments)); } uint64_t isInstanceOf(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jclass c = reinterpret_cast(arguments[1]); return instanceOf(t, jclassVmClass(t, *c), *o); } jboolean JNICALL IsInstanceOf(Thread* t, jobject o, jclass c) { uintptr_t arguments[] = { reinterpret_cast(o), reinterpret_cast(c) }; return run(t, isInstanceOf, arguments); } uint64_t isAssignableFrom(Thread* t, uintptr_t* arguments) { jclass b = reinterpret_cast(arguments[0]); jclass a = reinterpret_cast(arguments[1]); return isAssignableFrom(t, jclassVmClass(t, *a), jclassVmClass(t, *b)); } jboolean JNICALL IsAssignableFrom(Thread* t, jclass b, jclass a) { uintptr_t arguments[] = { reinterpret_cast(b), reinterpret_cast(a) }; return run(t, isAssignableFrom, arguments); } object findMethod(Thread* t, jclass c, const char* name, const char* spec) { object n = makeByteArray(t, "%s", name); PROTECT(t, n); object s = makeByteArray(t, "%s", spec); return vm::findMethod(t, jclassVmClass(t, *c), n, s); } jint methodID(Thread* t, object method) { int id = methodNativeID(t, method); loadMemoryBarrier(); if (id == 0) { PROTECT(t, method); ACQUIRE(t, t->m->referenceLock); if (methodNativeID(t, method) == 0) { setRoot(t, Machine::JNIMethodTable, vectorAppend (t, root(t, Machine::JNIMethodTable), method)); storeStoreMemoryBarrier(); methodNativeID(t, method) = vectorSize (t, root(t, Machine::JNIMethodTable)); } } return methodNativeID(t, method); } uint64_t getMethodID(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); const char* name = reinterpret_cast(arguments[1]); const char* spec = reinterpret_cast(arguments[2]); object method = findMethod(t, c, name, spec); assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); return methodID(t, method); } jmethodID JNICALL GetMethodID(Thread* t, jclass c, const char* name, const char* spec) { uintptr_t arguments[] = { reinterpret_cast(c), reinterpret_cast(name), reinterpret_cast(spec) }; return run(t, getMethodID, arguments); } uint64_t getStaticMethodID(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); const char* name = reinterpret_cast(arguments[1]); const char* spec = reinterpret_cast(arguments[2]); object method = findMethod(t, c, name, spec); assert(t, methodFlags(t, method) & ACC_STATIC); return methodID(t, method); } jmethodID JNICALL GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec) { uintptr_t arguments[] = { reinterpret_cast(c), reinterpret_cast(name), reinterpret_cast(spec) }; return run(t, getStaticMethodID, arguments); } object getMethod(Thread* t, jmethodID m) { assert(t, m); object method = vectorBody(t, root(t, Machine::JNIMethodTable), m - 1); assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); return method; } uint64_t newObjectV(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; va_list* a = reinterpret_cast(arguments[2]); object o = make(t, jclassVmClass(t, *c)); PROTECT(t, o); t->m->processor->invokeList(t, getMethod(t, m), o, true, *a); return reinterpret_cast(makeLocalReference(t, o)); } jobject JNICALL NewObjectV(Thread* t, jclass c, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(c), m, reinterpret_cast(VA_LIST(a)) }; return reinterpret_cast(run(t, newObjectV, arguments)); } jobject JNICALL NewObject(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); jobject r = NewObjectV(t, c, m, a); va_end(a); return r; } uint64_t newObjectA(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; const jvalue* a = reinterpret_cast(arguments[2]); object o = make(t, jclassVmClass(t, *c)); PROTECT(t, o); t->m->processor->invokeArray(t, getMethod(t, m), o, a); return reinterpret_cast(makeLocalReference(t, o)); } jobject JNICALL NewObjectA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return reinterpret_cast(run(t, newObjectA, arguments)); } uint64_t callObjectMethodV(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; va_list* a = reinterpret_cast(arguments[2]); return reinterpret_cast (makeLocalReference (t, t->m->processor->invokeList(t, getMethod(t, m), *o, true, *a))); } jobject JNICALL CallObjectMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(VA_LIST(a)) }; return reinterpret_cast(run(t, callObjectMethodV, arguments)); } jobject JNICALL CallObjectMethod(Thread* t, jobject o, jmethodID m, ...) { va_list a; va_start(a, m); jobject r = CallObjectMethodV(t, o, m, a); va_end(a); return r; } uint64_t callObjectMethodA(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; const jvalue* a = reinterpret_cast(arguments[2]); return reinterpret_cast (makeLocalReference (t, t->m->processor->invokeArray(t, getMethod(t, m), *o, a))); } jobject JNICALL CallObjectMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return reinterpret_cast(run(t, callObjectMethodA, arguments)); } uint64_t callIntMethodV(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; va_list* a = reinterpret_cast(arguments[2]); return intValue (t, t->m->processor->invokeList(t, getMethod(t, m), *o, true, *a)); } jboolean JNICALL CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(VA_LIST(a)) }; return run(t, callIntMethodV, arguments) != 0; } jboolean JNICALL CallBooleanMethod(Thread* t, jobject o, jmethodID m, ...) { va_list a; va_start(a, m); jboolean r = CallBooleanMethodV(t, o, m, a); va_end(a); return r; } uint64_t callIntMethodA(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; const jvalue* a = reinterpret_cast(arguments[2]); return intValue (t, t->m->processor->invokeArray(t, getMethod(t, m), *o, a)); } jboolean JNICALL CallBooleanMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return run(t, callIntMethodA, arguments) != 0; } jbyte JNICALL CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(VA_LIST(a)) }; return run(t, callIntMethodV, arguments); } jbyte JNICALL CallByteMethod(Thread* t, jobject o, jmethodID m, ...) { va_list a; va_start(a, m); jbyte r = CallByteMethodV(t, o, m, a); va_end(a); return r; } jbyte JNICALL CallByteMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return run(t, callIntMethodA, arguments); } jchar JNICALL CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(VA_LIST(a)) }; return run(t, callIntMethodV, arguments); } jchar JNICALL CallCharMethod(Thread* t, jobject o, jmethodID m, ...) { va_list a; va_start(a, m); jchar r = CallCharMethodV(t, o, m, a); va_end(a); return r; } jchar JNICALL CallCharMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return run(t, callIntMethodA, arguments); } jshort JNICALL CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(VA_LIST(a)) }; return run(t, callIntMethodV, arguments); } jshort JNICALL CallShortMethod(Thread* t, jobject o, jmethodID m, ...) { va_list a; va_start(a, m); jshort r = CallShortMethodV(t, o, m, a); va_end(a); return r; } jshort JNICALL CallShortMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return run(t, callIntMethodA, arguments); } jint JNICALL CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(VA_LIST(a)) }; return run(t, callIntMethodV, arguments); } jint JNICALL CallIntMethod(Thread* t, jobject o, jmethodID m, ...) { va_list a; va_start(a, m); jint r = CallIntMethodV(t, o, m, a); va_end(a); return r; } jint JNICALL CallIntMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return run(t, callIntMethodA, arguments); } uint64_t callLongMethodV(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; va_list* a = reinterpret_cast(arguments[2]); return longValue (t, t->m->processor->invokeList(t, getMethod(t, m), *o, true, *a)); } jlong JNICALL CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(VA_LIST(a)) }; return run(t, callLongMethodV, arguments); } jlong JNICALL CallLongMethod(Thread* t, jobject o, jmethodID m, ...) { va_list a; va_start(a, m); jlong r = CallLongMethodV(t, o, m, a); va_end(a); return r; } uint64_t callLongMethodA(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; const jvalue* a = reinterpret_cast(arguments[2]); return longValue (t, t->m->processor->invokeArray(t, getMethod(t, m), *o, a)); } jlong JNICALL CallLongMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return run(t, callLongMethodA, arguments); } jfloat JNICALL CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(VA_LIST(a)) }; return bitsToFloat(run(t, callIntMethodV, arguments)); } jfloat JNICALL CallFloatMethod(Thread* t, jobject o, jmethodID m, ...) { va_list a; va_start(a, m); jfloat r = CallFloatMethodV(t, o, m, a); va_end(a); return r; } jfloat JNICALL CallFloatMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return bitsToFloat(run(t, callIntMethodA, arguments)); } jdouble JNICALL CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(VA_LIST(a)) }; return bitsToDouble(run(t, callLongMethodV, arguments)); } jdouble JNICALL CallDoubleMethod(Thread* t, jobject o, jmethodID m, ...) { va_list a; va_start(a, m); jdouble r = CallDoubleMethodV(t, o, m, a); va_end(a); return r; } jdouble JNICALL CallDoubleMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; return bitsToDouble(run(t, callLongMethodA, arguments)); } uint64_t callVoidMethodV(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; va_list* a = reinterpret_cast(arguments[2]); t->m->processor->invokeList(t, getMethod(t, m), *o, true, *a); return 0; } void JNICALL CallVoidMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(VA_LIST(a)) }; run(t, callVoidMethodV, arguments); } void JNICALL CallVoidMethod(Thread* t, jobject o, jmethodID m, ...) { va_list a; va_start(a, m); CallVoidMethodV(t, o, m, a); va_end(a); } uint64_t callVoidMethodA(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); jmethodID m = arguments[1]; const jvalue* a = reinterpret_cast(arguments[2]); t->m->processor->invokeArray(t, getMethod(t, m), *o, a); return 0; } void JNICALL CallVoidMethodA(Thread* t, jobject o, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { reinterpret_cast(o), m, reinterpret_cast(a) }; run(t, callVoidMethodA, arguments); } object getStaticMethod(Thread* t, jmethodID m) { assert(t, m); object method = vectorBody(t, root(t, Machine::JNIMethodTable), m - 1); assert(t, methodFlags(t, method) & ACC_STATIC); return method; } uint64_t callStaticObjectMethodV(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; va_list* a = reinterpret_cast(arguments[1]); return reinterpret_cast (makeLocalReference (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a))); } jobject JNICALL CallStaticObjectMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return reinterpret_cast(run(t, callStaticObjectMethodV, arguments)); } jobject JNICALL CallStaticObjectMethod(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); jobject r = CallStaticObjectMethodV(t, c, m, a); va_end(a); return r; } uint64_t callStaticObjectMethodA(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; const jvalue* a = reinterpret_cast(arguments[1]); return reinterpret_cast (makeLocalReference (t, t->m->processor->invokeArray(t, getStaticMethod(t, m), 0, a))); } jobject JNICALL CallStaticObjectMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return reinterpret_cast(run(t, callStaticObjectMethodA, arguments)); } uint64_t callStaticIntMethodV(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; va_list* a = reinterpret_cast(arguments[1]); return intValue (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a)); } jboolean JNICALL CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticIntMethodV, arguments) != 0; } jboolean JNICALL CallStaticBooleanMethod(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); jboolean r = CallStaticBooleanMethodV(t, c, m, a); va_end(a); return r; } uint64_t callStaticIntMethodA(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; const jvalue* a = reinterpret_cast(arguments[1]); return intValue (t, t->m->processor->invokeArray(t, getStaticMethod(t, m), 0, a)); } jboolean JNICALL CallStaticBooleanMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return run(t, callStaticIntMethodA, arguments) != 0; } jbyte JNICALL CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticIntMethodV, arguments); } jbyte JNICALL CallStaticByteMethod(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); jbyte r = CallStaticByteMethodV(t, c, m, a); va_end(a); return r; } jbyte JNICALL CallStaticByteMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return run(t, callStaticIntMethodA, arguments); } jchar JNICALL CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticIntMethodV, arguments); } jchar JNICALL CallStaticCharMethod(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); jchar r = CallStaticCharMethodV(t, c, m, a); va_end(a); return r; } jchar JNICALL CallStaticCharMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return run(t, callStaticIntMethodA, arguments); } jshort JNICALL CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticIntMethodV, arguments); } jshort JNICALL CallStaticShortMethod(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); jshort r = CallStaticShortMethodV(t, c, m, a); va_end(a); return r; } jshort JNICALL CallStaticShortMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return run(t, callStaticIntMethodA, arguments); } jint JNICALL CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticIntMethodV, arguments); } jint JNICALL CallStaticIntMethod(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); jint r = CallStaticIntMethodV(t, c, m, a); va_end(a); return r; } jint JNICALL CallStaticIntMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return run(t, callStaticIntMethodA, arguments); } uint64_t callStaticLongMethodV(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; va_list* a = reinterpret_cast(arguments[1]); return longValue (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a)); } jlong JNICALL CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticLongMethodV, arguments); } jlong JNICALL CallStaticLongMethod(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); jlong r = CallStaticLongMethodV(t, c, m, a); va_end(a); return r; } uint64_t callStaticLongMethodA(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; const jvalue* a = reinterpret_cast(arguments[1]); return longValue (t, t->m->processor->invokeArray(t, getStaticMethod(t, m), 0, a)); } jlong JNICALL CallStaticLongMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return run(t, callStaticLongMethodA, arguments); } jfloat JNICALL CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return bitsToFloat(run(t, callStaticIntMethodV, arguments)); } jfloat JNICALL CallStaticFloatMethod(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); jfloat r = CallStaticFloatMethodV(t, c, m, a); va_end(a); return r; } jfloat JNICALL CallStaticFloatMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return bitsToFloat(run(t, callStaticIntMethodA, arguments)); } jdouble JNICALL CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return bitsToDouble(run(t, callStaticLongMethodV, arguments)); } jdouble JNICALL CallStaticDoubleMethod(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); jdouble r = CallStaticDoubleMethodV(t, c, m, a); va_end(a); return r; } jdouble JNICALL CallStaticDoubleMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; return bitsToDouble(run(t, callStaticLongMethodA, arguments)); } uint64_t callStaticVoidMethodV(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; va_list* a = reinterpret_cast(arguments[1]); t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a); return 0; } void JNICALL CallStaticVoidMethodV(Thread* t, jclass, jmethodID m, va_list a) { uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; run(t, callStaticVoidMethodV, arguments); } void JNICALL CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...) { va_list a; va_start(a, m); CallStaticVoidMethodV(t, c, m, a); va_end(a); } uint64_t callStaticVoidMethodA(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[0]; const jvalue* a = reinterpret_cast(arguments[1]); t->m->processor->invokeArray(t, getStaticMethod(t, m), 0, a); return 0; } void JNICALL CallStaticVoidMethodA(Thread* t, jclass, jmethodID m, const jvalue* a) { uintptr_t arguments[] = { m, reinterpret_cast(a) }; run(t, callStaticVoidMethodA, arguments); } jint fieldID(Thread* t, object field) { int id = fieldNativeID(t, field); loadMemoryBarrier(); if (id == 0) { PROTECT(t, field); ACQUIRE(t, t->m->referenceLock); if (fieldNativeID(t, field) == 0) { setRoot(t, Machine::JNIFieldTable, vectorAppend (t, root(t, Machine::JNIFieldTable), field)); storeStoreMemoryBarrier(); fieldNativeID(t, field) = vectorSize(t, root(t, Machine::JNIFieldTable)); } } return fieldNativeID(t, field); } uint64_t getFieldID(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); const char* name = reinterpret_cast(arguments[1]); const char* spec = reinterpret_cast(arguments[2]); return fieldID(t, resolveField(t, jclassVmClass(t, *c), name, spec)); } jfieldID JNICALL GetFieldID(Thread* t, jclass c, const char* name, const char* spec) { uintptr_t arguments[] = { reinterpret_cast(c), reinterpret_cast(name), reinterpret_cast(spec) }; return run(t, getFieldID, arguments); } jfieldID JNICALL GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec) { uintptr_t arguments[] = { reinterpret_cast(c), reinterpret_cast(name), reinterpret_cast(spec) }; return run(t, getFieldID, arguments); } object getField(Thread* t, jfieldID f) { assert(t, f); object field = vectorBody(t, root(t, Machine::JNIFieldTable), f - 1); assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); return field; } uint64_t getObjectField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return reinterpret_cast (makeLocalReference(t, fieldAtOffset(*o, fieldOffset(t, field)))); } jobject JNICALL GetObjectField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return reinterpret_cast(run(t, getObjectField, arguments)); } uint64_t getBooleanField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jboolean JNICALL GetBooleanField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getBooleanField, arguments); } uint64_t getByteField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jbyte JNICALL GetByteField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getByteField, arguments); } uint64_t getCharField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jchar JNICALL GetCharField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getCharField, arguments); } uint64_t getShortField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jshort JNICALL GetShortField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getShortField, arguments); } uint64_t getIntField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jint JNICALL GetIntField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getIntField, arguments); } uint64_t getLongField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset(*o, fieldOffset(t, field)); } jlong JNICALL GetLongField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return run(t, getLongField, arguments); } uint64_t getFloatField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return floatToBits(fieldAtOffset(*o, fieldOffset(t, field))); } jfloat JNICALL GetFloatField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return bitsToFloat(run(t, getFloatField, arguments)); } uint64_t getDoubleField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return doubleToBits(fieldAtOffset(*o, fieldOffset(t, field))); } jdouble JNICALL GetDoubleField(Thread* t, jobject o, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(o), field }; return bitsToDouble(run(t, getDoubleField, arguments)); } uint64_t setObjectField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jobject v = reinterpret_cast(arguments[2]); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); set(t, *o, fieldOffset(t, field), (v ? *v : 0)); return 1; } void JNICALL SetObjectField(Thread* t, jobject o, jfieldID field, jobject v) { uintptr_t arguments[] = { reinterpret_cast(o), field, reinterpret_cast(v) }; run(t, setObjectField, arguments); } uint64_t setBooleanField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jboolean v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetBooleanField(Thread* t, jobject o, jfieldID field, jboolean v) { uintptr_t arguments[] = { reinterpret_cast(o), field, v }; run(t, setBooleanField, arguments); } uint64_t setByteField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jbyte v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetByteField(Thread* t, jobject o, jfieldID field, jbyte v) { uintptr_t arguments[] = { reinterpret_cast(o), field, static_cast(v) }; run(t, setByteField, arguments); } uint64_t setCharField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jchar v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetCharField(Thread* t, jobject o, jfieldID field, jchar v) { uintptr_t arguments[] = { reinterpret_cast(o), field, v }; run(t, setCharField, arguments); } uint64_t setShortField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jshort v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetShortField(Thread* t, jobject o, jfieldID field, jshort v) { uintptr_t arguments[] = { reinterpret_cast(o), field, static_cast(v) }; run(t, setShortField, arguments); } uint64_t setIntField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jint v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetIntField(Thread* t, jobject o, jfieldID field, jint v) { uintptr_t arguments[] = { reinterpret_cast(o), field, static_cast(v) }; run(t, setIntField, arguments); } uint64_t setLongField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jlong v; memcpy(&v, arguments + 2, sizeof(jlong)); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetLongField(Thread* t, jobject o, jfieldID field, jlong v) { uintptr_t arguments[2 + (sizeof(jlong) / BytesPerWord)]; arguments[0] = reinterpret_cast(o); arguments[1] = field; memcpy(arguments + 2, &v, sizeof(jlong)); run(t, setLongField, arguments); } uint64_t setFloatField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jfloat v = bitsToFloat(arguments[2]); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetFloatField(Thread* t, jobject o, jfieldID field, jfloat v) { uintptr_t arguments[] = { reinterpret_cast(o), field, floatToBits(v) }; run(t, setFloatField, arguments); } uint64_t setDoubleField(Thread* t, uintptr_t* arguments) { jobject o = reinterpret_cast(arguments[0]); object field = getField(t, arguments[1]); jdouble v; memcpy(&v, arguments + 2, sizeof(jdouble)); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset(*o, fieldOffset(t, field)) = v; return 1; } void JNICALL SetDoubleField(Thread* t, jobject o, jfieldID field, jdouble v) { uintptr_t arguments[2 + (sizeof(jdouble) / BytesPerWord)]; arguments[0] = reinterpret_cast(o); arguments[1] = field; memcpy(arguments + 2, &v, sizeof(jdouble)); run(t, setDoubleField, arguments); } object getStaticField(Thread* t, jfieldID f) { assert(t, f); object field = vectorBody(t, root(t, Machine::JNIFieldTable), f - 1); assert(t, fieldFlags(t, field) & ACC_STATIC); return field; } uint64_t getStaticObjectField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return reinterpret_cast (makeLocalReference (t, fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)))); } jobject JNICALL GetStaticObjectField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return reinterpret_cast(run(t, getStaticObjectField, arguments)); } uint64_t getStaticBooleanField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jboolean JNICALL GetStaticBooleanField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticBooleanField, arguments); } uint64_t getStaticByteField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jbyte JNICALL GetStaticByteField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticByteField, arguments); } uint64_t getStaticCharField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jchar JNICALL GetStaticCharField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticCharField, arguments); } uint64_t getStaticShortField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jshort JNICALL GetStaticShortField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticShortField, arguments); } uint64_t getStaticIntField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jint JNICALL GetStaticIntField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticIntField, arguments); } uint64_t getStaticLongField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)); } jlong JNICALL GetStaticLongField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return run(t, getStaticLongField, arguments); } uint64_t getStaticFloatField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return floatToBits (fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field))); } jfloat JNICALL GetStaticFloatField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return bitsToFloat(run(t, getStaticFloatField, arguments)); } uint64_t getStaticDoubleField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); PROTECT(t, field); ACQUIRE_FIELD_FOR_READ(t, field); return doubleToBits (fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field))); } jdouble JNICALL GetStaticDoubleField(Thread* t, jobject c, jfieldID field) { uintptr_t arguments[] = { reinterpret_cast(c), field }; return bitsToDouble(run(t, getStaticDoubleField, arguments)); } uint64_t setStaticObjectField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jobject v = reinterpret_cast(arguments[2]); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); set(t, classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field), (v ? *v : 0)); return 1; } void JNICALL SetStaticObjectField(Thread* t, jobject c, jfieldID field, jobject v) { uintptr_t arguments[] = { reinterpret_cast(c), field, reinterpret_cast(v) }; run(t, setStaticObjectField, arguments); } uint64_t setStaticBooleanField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jboolean v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticBooleanField(Thread* t, jobject c, jfieldID field, jboolean v) { uintptr_t arguments[] = { reinterpret_cast(c), field, v }; run(t, setStaticBooleanField, arguments); } uint64_t setStaticByteField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jbyte v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticByteField(Thread* t, jobject c, jfieldID field, jbyte v) { uintptr_t arguments[] = { reinterpret_cast(c), field, static_cast(v) }; run(t, setStaticByteField, arguments); } uint64_t setStaticCharField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jchar v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticCharField(Thread* t, jobject c, jfieldID field, jchar v) { uintptr_t arguments[] = { reinterpret_cast(c), field, v }; run(t, setStaticCharField, arguments); } uint64_t setStaticShortField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jshort v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticShortField(Thread* t, jobject c, jfieldID field, jshort v) { uintptr_t arguments[] = { reinterpret_cast(c), field, static_cast(v) }; run(t, setStaticShortField, arguments); } uint64_t setStaticIntField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jint v = arguments[2]; PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticIntField(Thread* t, jobject c, jfieldID field, jint v) { uintptr_t arguments[] = { reinterpret_cast(c), field, static_cast(v) }; run(t, setStaticIntField, arguments); } uint64_t setStaticLongField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jlong v; memcpy(&v, arguments + 2, sizeof(jlong)); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticLongField(Thread* t, jobject c, jfieldID field, jlong v) { uintptr_t arguments[2 + (sizeof(jlong) / BytesPerWord)]; arguments[0] = reinterpret_cast(c); arguments[1] = field; memcpy(arguments + 2, &v, sizeof(jlong)); run(t, setStaticLongField, arguments); } uint64_t setStaticFloatField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jfloat v = bitsToFloat(arguments[2]); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticFloatField(Thread* t, jobject c, jfieldID field, jfloat v) { uintptr_t arguments[] = { reinterpret_cast(c), field, floatToBits(v) }; run(t, setStaticFloatField, arguments); } uint64_t setStaticDoubleField(Thread* t, uintptr_t* arguments) { jobject c = reinterpret_cast(arguments[0]); initClass(t, jclassVmClass(t, *c)); object field = getStaticField(t, arguments[1]); jdouble v; memcpy(&v, arguments + 2, sizeof(jdouble)); PROTECT(t, field); ACQUIRE_FIELD_FOR_WRITE(t, field); fieldAtOffset (classStaticTable(t, jclassVmClass(t, *c)), fieldOffset(t, field)) = v; return 1; } void JNICALL SetStaticDoubleField(Thread* t, jobject c, jfieldID field, jdouble v) { uintptr_t arguments[2 + (sizeof(jdouble) / BytesPerWord)]; arguments[0] = reinterpret_cast(c); arguments[1] = field; memcpy(arguments + 2, &v, sizeof(jdouble)); run(t, setStaticDoubleField, arguments); } jobject JNICALL newGlobalRef(Thread* t, jobject o, bool weak) { ENTER(t, Thread::ActiveState); ACQUIRE(t, t->m->referenceLock); if (o) { for (Reference* r = t->m->jniReferences; r; r = r->next) { if (r->target == *o and r->weak == weak) { acquire(t, r); return &(r->target); } } Reference* r = new (t->m->heap->allocate(sizeof(Reference))) Reference(*o, &(t->m->jniReferences), weak); acquire(t, r); return &(r->target); } else { return 0; } } jobject JNICALL NewGlobalRef(Thread* t, jobject o) { return newGlobalRef(t, o, false); } void JNICALL DeleteGlobalRef(Thread* t, jobject r) { ENTER(t, Thread::ActiveState); ACQUIRE(t, t->m->referenceLock); if (r) { release(t, reinterpret_cast(r)); } } jobject JNICALL NewWeakGlobalRef(Thread* t, jobject o) { return newGlobalRef(t, o, true); } void JNICALL DeleteWeakGlobalRef(Thread* t, jobject r) { DeleteGlobalRef(t, r); } jint JNICALL EnsureLocalCapacity(Thread*, jint) { return 0; } jthrowable JNICALL ExceptionOccurred(Thread* t) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, t->exception); } void JNICALL ExceptionDescribe(Thread* t) { ENTER(t, Thread::ActiveState); return printTrace(t, t->exception); } void JNICALL ExceptionClear(Thread* t) { ENTER(t, Thread::ActiveState); t->exception = 0; } uint64_t newObjectArray(Thread* t, uintptr_t* arguments) { jsize length = arguments[0]; jclass class_ = reinterpret_cast(arguments[1]); jobject init = reinterpret_cast(arguments[2]); object a = makeObjectArray(t, jclassVmClass(t, *class_), length); object value = (init ? *init : 0); for (jsize i = 0; i < length; ++i) { set(t, a, ArrayBody + (i * BytesPerWord), value); } return reinterpret_cast(makeLocalReference(t, a)); } jobjectArray JNICALL NewObjectArray(Thread* t, jsize length, jclass class_, jobject init) { uintptr_t arguments[] = { static_cast(length), reinterpret_cast(class_), reinterpret_cast(init) }; return reinterpret_cast(run(t, newObjectArray, arguments)); } jobject JNICALL GetObjectArrayElement(Thread* t, jobjectArray array, jsize index) { ENTER(t, Thread::ActiveState); return makeLocalReference(t, objectArrayBody(t, *array, index)); } void JNICALL SetObjectArrayElement(Thread* t, jobjectArray array, jsize index, jobject value) { ENTER(t, Thread::ActiveState); set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0)); } uint64_t newArray(Thread* t, uintptr_t* arguments) { object (*constructor)(Thread*, unsigned) = reinterpret_cast(arguments[0]); jsize length = arguments[1]; return reinterpret_cast (makeLocalReference(t, constructor(t, length))); } jbooleanArray JNICALL NewBooleanArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeBooleanArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } object makeByteArray0(Thread* t, unsigned length) { return makeByteArray(t, length); } jbyteArray JNICALL NewByteArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeByteArray0)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jcharArray JNICALL NewCharArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeCharArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jshortArray JNICALL NewShortArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeShortArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jintArray JNICALL NewIntArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeIntArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jlongArray JNICALL NewLongArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeLongArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jfloatArray JNICALL NewFloatArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeFloatArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jdoubleArray JNICALL NewDoubleArray(Thread* t, jsize length) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(makeDoubleArray)), static_cast(length) }; return reinterpret_cast(run(t, newArray, arguments)); } jboolean* JNICALL GetBooleanArrayElements(Thread* t, jbooleanArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = booleanArrayLength(t, *array) * sizeof(jboolean); jboolean* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &booleanArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jbyte* JNICALL GetByteArrayElements(Thread* t, jbyteArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = byteArrayLength(t, *array) * sizeof(jbyte); jbyte* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &byteArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jchar* JNICALL GetCharArrayElements(Thread* t, jcharArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = charArrayLength(t, *array) * sizeof(jchar); jchar* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &charArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jshort* JNICALL GetShortArrayElements(Thread* t, jshortArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = shortArrayLength(t, *array) * sizeof(jshort); jshort* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &shortArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jint* JNICALL GetIntArrayElements(Thread* t, jintArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = intArrayLength(t, *array) * sizeof(jint); jint* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &intArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jlong* JNICALL GetLongArrayElements(Thread* t, jlongArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = longArrayLength(t, *array) * sizeof(jlong); jlong* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &longArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jfloat* JNICALL GetFloatArrayElements(Thread* t, jfloatArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = floatArrayLength(t, *array) * sizeof(jfloat); jfloat* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &floatArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } jdouble* JNICALL GetDoubleArrayElements(Thread* t, jdoubleArray array, jboolean* isCopy) { ENTER(t, Thread::ActiveState); unsigned size = doubleArrayLength(t, *array) * sizeof(jdouble); jdouble* p = static_cast(t->m->heap->allocate(size)); if (size) { memcpy(p, &doubleArrayBody(t, *array, 0), size); } if (isCopy) { *isCopy = true; } return p; } void JNICALL ReleaseBooleanArrayElements(Thread* t, jbooleanArray array, jboolean* p, jint mode) { ENTER(t, Thread::ActiveState); unsigned size = booleanArrayLength(t, *array) * sizeof(jboolean); if (mode == 0 or mode == AVIAN_JNI_COMMIT) { if (size) { memcpy(&booleanArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == AVIAN_JNI_ABORT) { t->m->heap->free(p, size); } } void JNICALL ReleaseByteArrayElements(Thread* t, jbyteArray array, jbyte* p, jint mode) { ENTER(t, Thread::ActiveState); unsigned size = byteArrayLength(t, *array) * sizeof(jbyte); if (mode == 0 or mode == AVIAN_JNI_COMMIT) { if (size) { memcpy(&byteArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == AVIAN_JNI_ABORT) { t->m->heap->free(p, size); } } void JNICALL ReleaseCharArrayElements(Thread* t, jcharArray array, jchar* p, jint mode) { ENTER(t, Thread::ActiveState); unsigned size = charArrayLength(t, *array) * sizeof(jchar); if (mode == 0 or mode == AVIAN_JNI_COMMIT) { if (size) { memcpy(&charArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == AVIAN_JNI_ABORT) { t->m->heap->free(p, size); } } void JNICALL ReleaseShortArrayElements(Thread* t, jshortArray array, jshort* p, jint mode) { ENTER(t, Thread::ActiveState); unsigned size = shortArrayLength(t, *array) * sizeof(jshort); if (mode == 0 or mode == AVIAN_JNI_COMMIT) { if (size) { memcpy(&shortArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == AVIAN_JNI_ABORT) { t->m->heap->free(p, size); } } void JNICALL ReleaseIntArrayElements(Thread* t, jintArray array, jint* p, jint mode) { ENTER(t, Thread::ActiveState); unsigned size = intArrayLength(t, *array) * sizeof(jint); if (mode == 0 or mode == AVIAN_JNI_COMMIT) { if (size) { memcpy(&intArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == AVIAN_JNI_ABORT) { t->m->heap->free(p, size); } } void JNICALL ReleaseLongArrayElements(Thread* t, jlongArray array, jlong* p, jint mode) { ENTER(t, Thread::ActiveState); unsigned size = longArrayLength(t, *array) * sizeof(jlong); if (mode == 0 or mode == AVIAN_JNI_COMMIT) { if (size) { memcpy(&longArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == AVIAN_JNI_ABORT) { t->m->heap->free(p, size); } } void JNICALL ReleaseFloatArrayElements(Thread* t, jfloatArray array, jfloat* p, jint mode) { ENTER(t, Thread::ActiveState); unsigned size = floatArrayLength(t, *array) * sizeof(jfloat); if (mode == 0 or mode == AVIAN_JNI_COMMIT) { if (size) { memcpy(&floatArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == AVIAN_JNI_ABORT) { t->m->heap->free(p, size); } } void JNICALL ReleaseDoubleArrayElements(Thread* t, jdoubleArray array, jdouble* p, jint mode) { ENTER(t, Thread::ActiveState); unsigned size = doubleArrayLength(t, *array) * sizeof(jdouble); if (mode == 0 or mode == AVIAN_JNI_COMMIT) { if (size) { memcpy(&doubleArrayBody(t, *array, 0), p, size); } } if (mode == 0 or mode == AVIAN_JNI_ABORT) { t->m->heap->free(p, size); } } void JNICALL GetBooleanArrayRegion(Thread* t, jbooleanArray array, jint offset, jint length, jboolean* dst) { ENTER(t, Thread::ActiveState); if (length) { memcpy(dst, &booleanArrayBody(t, *array, offset), length * sizeof(jboolean)); } } void JNICALL GetByteArrayRegion(Thread* t, jbyteArray array, jint offset, jint length, jbyte* dst) { ENTER(t, Thread::ActiveState); if (length) { memcpy(dst, &byteArrayBody(t, *array, offset), length * sizeof(jbyte)); } } void JNICALL GetCharArrayRegion(Thread* t, jcharArray array, jint offset, jint length, jchar* dst) { ENTER(t, Thread::ActiveState); if (length) { memcpy(dst, &charArrayBody(t, *array, offset), length * sizeof(jchar)); } } void JNICALL GetShortArrayRegion(Thread* t, jshortArray array, jint offset, jint length, jshort* dst) { ENTER(t, Thread::ActiveState); if (length) { memcpy(dst, &shortArrayBody(t, *array, offset), length * sizeof(jshort)); } } void JNICALL GetIntArrayRegion(Thread* t, jintArray array, jint offset, jint length, jint* dst) { ENTER(t, Thread::ActiveState); if (length) { memcpy(dst, &intArrayBody(t, *array, offset), length * sizeof(jint)); } } void JNICALL GetLongArrayRegion(Thread* t, jlongArray array, jint offset, jint length, jlong* dst) { ENTER(t, Thread::ActiveState); if (length) { memcpy(dst, &longArrayBody(t, *array, offset), length * sizeof(jlong)); } } void JNICALL GetFloatArrayRegion(Thread* t, jfloatArray array, jint offset, jint length, jfloat* dst) { ENTER(t, Thread::ActiveState); if (length) { memcpy(dst, &floatArrayBody(t, *array, offset), length * sizeof(jfloat)); } } void JNICALL GetDoubleArrayRegion(Thread* t, jdoubleArray array, jint offset, jint length, jdouble* dst) { ENTER(t, Thread::ActiveState); if (length) { memcpy(dst, &doubleArrayBody(t, *array, offset), length * sizeof(jdouble)); } } void JNICALL SetBooleanArrayRegion(Thread* t, jbooleanArray array, jint offset, jint length, const jboolean* src) { ENTER(t, Thread::ActiveState); if (length) { memcpy(&booleanArrayBody(t, *array, offset), src, length * sizeof(jboolean)); } } void JNICALL SetByteArrayRegion(Thread* t, jbyteArray array, jint offset, jint length, const jbyte* src) { ENTER(t, Thread::ActiveState); if (length) { memcpy(&byteArrayBody(t, *array, offset), src, length * sizeof(jbyte)); } } void JNICALL SetCharArrayRegion(Thread* t, jcharArray array, jint offset, jint length, const jchar* src) { ENTER(t, Thread::ActiveState); if (length) { memcpy(&charArrayBody(t, *array, offset), src, length * sizeof(jchar)); } } void JNICALL SetShortArrayRegion(Thread* t, jshortArray array, jint offset, jint length, const jshort* src) { ENTER(t, Thread::ActiveState); if (length) { memcpy(&shortArrayBody(t, *array, offset), src, length * sizeof(jshort)); } } void JNICALL SetIntArrayRegion(Thread* t, jintArray array, jint offset, jint length, const jint* src) { ENTER(t, Thread::ActiveState); if (length) { memcpy(&intArrayBody(t, *array, offset), src, length * sizeof(jint)); } } void JNICALL SetLongArrayRegion(Thread* t, jlongArray array, jint offset, jint length, const jlong* src) { ENTER(t, Thread::ActiveState); if (length) { memcpy(&longArrayBody(t, *array, offset), src, length * sizeof(jlong)); } } void JNICALL SetFloatArrayRegion(Thread* t, jfloatArray array, jint offset, jint length, const jfloat* src) { ENTER(t, Thread::ActiveState); if (length) { memcpy(&floatArrayBody(t, *array, offset), src, length * sizeof(jfloat)); } } void JNICALL SetDoubleArrayRegion(Thread* t, jdoubleArray array, jint offset, jint length, const jdouble* src) { ENTER(t, Thread::ActiveState); if (length) { memcpy(&doubleArrayBody(t, *array, offset), src, length * sizeof(jdouble)); } } void* JNICALL GetPrimitiveArrayCritical(Thread* t, jarray array, jboolean* isCopy) { if (t->criticalLevel == 0) { enter(t, Thread::ActiveState); } ++ t->criticalLevel; if (isCopy) { *isCopy = true; } expect(t, *array); return reinterpret_cast(*array) + 2; } void JNICALL ReleasePrimitiveArrayCritical(Thread* t, jarray, void*, jint) { if ((-- t->criticalLevel) == 0) { enter(t, Thread::IdleState); } } uint64_t fromReflectedMethod(Thread* t, uintptr_t* arguments) { jobject m = reinterpret_cast(arguments[0]); return methodID(t, t->m->classpath->getVMMethod(t, *m)); } jmethodID JNICALL FromReflectedMethod(Thread* t, jobject method) { uintptr_t arguments[] = { reinterpret_cast(method) }; return static_cast(run(t, fromReflectedMethod, arguments)); } uint64_t toReflectedMethod(Thread* t, uintptr_t* arguments) { jmethodID m = arguments[1]; jboolean isStatic = arguments[2]; return reinterpret_cast (makeLocalReference (t, t->m->classpath->makeJMethod (t, isStatic ? getStaticMethod(t, m) : getMethod(t, m)))); } jobject JNICALL ToReflectedMethod(Thread* t, jclass c, jmethodID method, jboolean isStatic) { uintptr_t arguments[] = { reinterpret_cast(c), static_cast(method), static_cast(isStatic) }; return reinterpret_cast(run(t, toReflectedMethod, arguments)); } uint64_t fromReflectedField(Thread* t, uintptr_t* arguments) { jobject f = reinterpret_cast(arguments[0]); return fieldID(t, t->m->classpath->getVMField(t, *f)); } jfieldID JNICALL FromReflectedField(Thread* t, jobject field) { uintptr_t arguments[] = { reinterpret_cast(field) }; return static_cast(run(t, fromReflectedField, arguments)); } uint64_t toReflectedField(Thread* t, uintptr_t* arguments) { jfieldID f = arguments[1]; jboolean isStatic = arguments[2]; return reinterpret_cast (makeLocalReference (t, t->m->classpath->makeJField (t, isStatic ? getStaticField(t, f) : getField(t, f)))); } jobject JNICALL ToReflectedField(Thread* t, jclass c, jfieldID field, jboolean isStatic) { uintptr_t arguments[] = { reinterpret_cast(c), static_cast(field), static_cast(isStatic) }; return reinterpret_cast(run(t, toReflectedField, arguments)); } uint64_t registerNatives(Thread* t, uintptr_t* arguments) { jclass c = reinterpret_cast(arguments[0]); const JNINativeMethod* methods = reinterpret_cast(arguments[1]); jint methodCount = arguments[2]; for (int i = 0; i < methodCount; ++i) { if (methods[i].function) { // Android's class library sometimes prepends a mysterious "!" // to the method signature, which we happily ignore: const char* sig = methods[i].signature; if (*sig == '!') ++ sig; object method = findMethodOrNull (t, jclassVmClass(t, *c), methods[i].name, sig); if (method == 0 or (methodFlags(t, method) & ACC_NATIVE) == 0) { // The JNI spec says we must throw a NoSuchMethodError in this // case, but that would prevent using a code shrinker like // ProGuard effectively. Instead, we just ignore it. // fprintf(stderr, "not found: %s.%s%s\n", &byteArrayBody(t, className(t, jclassVmClass(t, *c)), 0), methods[i].name, sig); // abort(t); } else { registerNative(t, method, methods[i].function); } } } return 1; } jint JNICALL RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods, jint methodCount) { uintptr_t arguments[] = { reinterpret_cast(c), reinterpret_cast(methods), static_cast(methodCount) }; return run(t, registerNatives, arguments) ? 0 : -1; } jint JNICALL UnregisterNatives(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); unregisterNatives(t, *c); return 0; } uint64_t monitorOp(Thread* t, uintptr_t* arguments) { void (*op)(Thread*, object) = reinterpret_cast(arguments[0]); jobject o = reinterpret_cast(arguments[1]); op(t, *o); return 1; } void acquire0(Thread* t, object o) { return acquire(t, o); } jint JNICALL MonitorEnter(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(acquire0)), reinterpret_cast(o) }; return run(t, monitorOp, arguments) ? 0 : -1; } void release0(Thread* t, object o) { return release(t, o); } jint JNICALL MonitorExit(Thread* t, jobject o) { uintptr_t arguments[] = { reinterpret_cast(voidPointer(release0)), reinterpret_cast(o) }; return run(t, monitorOp, arguments) ? 0 : -1; } jint JNICALL GetJavaVM(Thread* t, Machine** m) { *m = t->m; return 0; } jboolean JNICALL IsSameObject(Thread* t, jobject a, jobject b) { if (a and b) { ENTER(t, Thread::ActiveState); return *a == *b; } else { return a == b; } } uint64_t pushLocalFrame(Thread* t, uintptr_t* arguments) { if (t->m->processor->pushLocalFrame(t, arguments[0])) { return 1; } else { throw_(t, root(t, Machine::OutOfMemoryError)); } } jint JNICALL PushLocalFrame(Thread* t, jint capacity) { uintptr_t arguments[] = { static_cast(capacity) }; return run(t, pushLocalFrame, arguments) ? 0 : -1; } uint64_t popLocalFrame(Thread* t, uintptr_t* arguments) { uint64_t r; jobject presult = reinterpret_cast(arguments[0]); if(presult != NULL) { object result = *presult; PROTECT(t, result); t->m->processor->popLocalFrame(t); r = reinterpret_cast(makeLocalReference(t, result)); } else { t->m->processor->popLocalFrame(t); r = 0; } return r; } jobject JNICALL PopLocalFrame(Thread* t, jobject result) { uintptr_t arguments[] = { reinterpret_cast(result) }; return reinterpret_cast(run(t, popLocalFrame, arguments)); } uint64_t newDirectByteBuffer(Thread* t, uintptr_t* arguments) { jlong capacity; memcpy(&capacity, arguments + 1, sizeof(jlong)); return reinterpret_cast (makeLocalReference (t, t->m->classpath->makeDirectByteBuffer (t, reinterpret_cast(arguments[0]), capacity))); } jobject JNICALL NewDirectByteBuffer(Thread* t, void* p, jlong capacity) { uintptr_t arguments[1 + (sizeof(jlong) / BytesPerWord)]; arguments[0] = reinterpret_cast(p); memcpy(arguments + 1, &capacity, sizeof(jlong)); return reinterpret_cast(run(t, newDirectByteBuffer, arguments)); } uint64_t getDirectBufferAddress(Thread* t, uintptr_t* arguments) { return reinterpret_cast (t->m->classpath->getDirectBufferAddress (t, *reinterpret_cast(arguments[0]))); } void* JNICALL GetDirectBufferAddress(Thread* t, jobject b) { uintptr_t arguments[] = { reinterpret_cast(b) }; return reinterpret_cast(run(t, getDirectBufferAddress, arguments)); } uint64_t getDirectBufferCapacity(Thread* t, uintptr_t* arguments) { return t->m->classpath->getDirectBufferCapacity (t, *reinterpret_cast(arguments[0])); } jlong JNICALL GetDirectBufferCapacity(Thread* t, jobject b) { uintptr_t arguments[] = { reinterpret_cast(b) }; return run(t, getDirectBufferCapacity, arguments); } struct JavaVMOption { char* optionString; void* extraInfo; }; struct JavaVMInitArgs { jint version; jint nOptions; JavaVMOption* options; jboolean ignoreUnrecognized; }; int parseSize(const char* s) { unsigned length = strlen(s); RUNTIME_ARRAY(char, buffer, length + 1); if (length == 0) { return 0; } else if (s[length - 1] == 'k' or s[length - 1] == 'K') { memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1); RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0; return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024; } else if (s[length - 1] == 'm' or s[length - 1] == 'M') { memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1); RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0; return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024 * 1024; } else { return atoi(s); } } void append(char** p, const char* value, unsigned length, char tail) { if (length) { memcpy(*p, value, length); *p += length; *((*p)++) = tail; } } uint64_t boot(Thread* t, uintptr_t*) { setRoot(t, Machine::NullPointerException, makeThrowable (t, Machine::NullPointerExceptionType)); setRoot(t, Machine::ArithmeticException, makeThrowable(t, Machine::ArithmeticExceptionType)); setRoot(t, Machine::ArrayIndexOutOfBoundsException, makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType)); setRoot(t, Machine::OutOfMemoryError, makeThrowable(t, Machine::OutOfMemoryErrorType)); setRoot(t, Machine::Shutdown, makeThrowable(t, Machine::ThrowableType)); t->m->classpath->preBoot(t); t->javaThread = t->m->classpath->makeThread(t, 0); threadPeer(t, t->javaThread) = reinterpret_cast(t); setRoot(t, Machine::FinalizerThread, t->m->classpath->makeThread(t, t)); threadDaemon(t, root(t, Machine::FinalizerThread)) = true; t->m->classpath->boot(t); const char* port = findProperty(t, "avian.trace.port"); if (port) { object host = makeString(t, "0.0.0.0"); PROTECT(t, host); object method = resolveMethod (t, root(t, Machine::BootLoader), "avian/Traces", "startTraceListener", "(Ljava/lang/String;I)V"); t->m->processor->invoke(t, method, 0, host, atoi(port)); } enter(t, Thread::IdleState); return 1; } } // namespace local } // namespace namespace vm { void populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) { memset(vmTable, 0, sizeof(JavaVMVTable)); vmTable->DestroyJavaVM = local::DestroyJavaVM; vmTable->AttachCurrentThread = local::AttachCurrentThread; vmTable->AttachCurrentThreadAsDaemon = local::AttachCurrentThreadAsDaemon; vmTable->DetachCurrentThread = local::DetachCurrentThread; vmTable->GetEnv = local::GetEnv; memset(envTable, 0, sizeof(JNIEnvVTable)); envTable->GetVersion = local::GetVersion; envTable->GetStringLength = local::GetStringLength; envTable->GetStringChars = local::GetStringChars; envTable->ReleaseStringChars = local::ReleaseStringChars; envTable->GetStringRegion = local::GetStringRegion; envTable->GetStringCritical = local::GetStringCritical; envTable->ReleaseStringCritical = local::ReleaseStringCritical; envTable->GetStringUTFLength = local::GetStringUTFLength; envTable->GetStringUTFChars = local::GetStringUTFChars; envTable->ReleaseStringUTFChars = local::ReleaseStringUTFChars; envTable->GetStringUTFRegion = local::GetStringUTFRegion; envTable->GetArrayLength = local::GetArrayLength; envTable->NewString = local::NewString; envTable->NewStringUTF = local::NewStringUTF; envTable->DefineClass = local::DefineClass; envTable->FindClass = local::FindClass; envTable->ThrowNew = local::ThrowNew; envTable->Throw = local::Throw; envTable->ExceptionCheck = local::ExceptionCheck; envTable->NewDirectByteBuffer = local::NewDirectByteBuffer; envTable->GetDirectBufferAddress = local::GetDirectBufferAddress; envTable->GetDirectBufferCapacity = local::GetDirectBufferCapacity; envTable->NewLocalRef = local::NewLocalRef; envTable->DeleteLocalRef = local::DeleteLocalRef; envTable->GetObjectClass = local::GetObjectClass; envTable->GetSuperclass = local::GetSuperclass; envTable->IsInstanceOf = local::IsInstanceOf; envTable->IsAssignableFrom = local::IsAssignableFrom; envTable->GetFieldID = local::GetFieldID; envTable->GetMethodID = local::GetMethodID; envTable->GetStaticMethodID = local::GetStaticMethodID; envTable->NewObjectV = local::NewObjectV; envTable->NewObjectA = local::NewObjectA; envTable->NewObject = local::NewObject; envTable->CallObjectMethodV = local::CallObjectMethodV; envTable->CallObjectMethodA = local::CallObjectMethodA; envTable->CallObjectMethod = local::CallObjectMethod; envTable->CallBooleanMethodV = local::CallBooleanMethodV; envTable->CallBooleanMethodA = local::CallBooleanMethodA; envTable->CallBooleanMethod = local::CallBooleanMethod; envTable->CallByteMethodV = local::CallByteMethodV; envTable->CallByteMethodA = local::CallByteMethodA; envTable->CallByteMethod = local::CallByteMethod; envTable->CallCharMethodV = local::CallCharMethodV; envTable->CallCharMethodA = local::CallCharMethodA; envTable->CallCharMethod = local::CallCharMethod; envTable->CallShortMethodV = local::CallShortMethodV; envTable->CallShortMethodA = local::CallShortMethodA; envTable->CallShortMethod = local::CallShortMethod; envTable->CallIntMethodV = local::CallIntMethodV; envTable->CallIntMethodA = local::CallIntMethodA; envTable->CallIntMethod = local::CallIntMethod; envTable->CallLongMethodV = local::CallLongMethodV; envTable->CallLongMethodA = local::CallLongMethodA; envTable->CallLongMethod = local::CallLongMethod; envTable->CallFloatMethodV = local::CallFloatMethodV; envTable->CallFloatMethodA = local::CallFloatMethodA; envTable->CallFloatMethod = local::CallFloatMethod; envTable->CallDoubleMethodV = local::CallDoubleMethodV; envTable->CallDoubleMethodA = local::CallDoubleMethodA; envTable->CallDoubleMethod = local::CallDoubleMethod; envTable->CallVoidMethodV = local::CallVoidMethodV; envTable->CallVoidMethodA = local::CallVoidMethodA; envTable->CallVoidMethod = local::CallVoidMethod; envTable->CallStaticObjectMethodV = local::CallStaticObjectMethodV; envTable->CallStaticObjectMethodA = local::CallStaticObjectMethodA; envTable->CallStaticObjectMethod = local::CallStaticObjectMethod; envTable->CallStaticBooleanMethodV = local::CallStaticBooleanMethodV; envTable->CallStaticBooleanMethodA = local::CallStaticBooleanMethodA; envTable->CallStaticBooleanMethod = local::CallStaticBooleanMethod; envTable->CallStaticByteMethodV = local::CallStaticByteMethodV; envTable->CallStaticByteMethodA = local::CallStaticByteMethodA; envTable->CallStaticByteMethod = local::CallStaticByteMethod; envTable->CallStaticCharMethodV = local::CallStaticCharMethodV; envTable->CallStaticCharMethodA = local::CallStaticCharMethodA; envTable->CallStaticCharMethod = local::CallStaticCharMethod; envTable->CallStaticShortMethodV = local::CallStaticShortMethodV; envTable->CallStaticShortMethodA = local::CallStaticShortMethodA; envTable->CallStaticShortMethod = local::CallStaticShortMethod; envTable->CallStaticIntMethodV = local::CallStaticIntMethodV; envTable->CallStaticIntMethodA = local::CallStaticIntMethodA; envTable->CallStaticIntMethod = local::CallStaticIntMethod; envTable->CallStaticLongMethodV = local::CallStaticLongMethodV; envTable->CallStaticLongMethodA = local::CallStaticLongMethodA; envTable->CallStaticLongMethod = local::CallStaticLongMethod; envTable->CallStaticFloatMethodV = local::CallStaticFloatMethodV; envTable->CallStaticFloatMethodA = local::CallStaticFloatMethodA; envTable->CallStaticFloatMethod = local::CallStaticFloatMethod; envTable->CallStaticDoubleMethodV = local::CallStaticDoubleMethodV; envTable->CallStaticDoubleMethodA = local::CallStaticDoubleMethodA; envTable->CallStaticDoubleMethod = local::CallStaticDoubleMethod; envTable->CallStaticVoidMethodV = local::CallStaticVoidMethodV; envTable->CallStaticVoidMethodA = local::CallStaticVoidMethodA; envTable->CallStaticVoidMethod = local::CallStaticVoidMethod; envTable->GetStaticFieldID = local::GetStaticFieldID; envTable->GetObjectField = local::GetObjectField; envTable->GetBooleanField = local::GetBooleanField; envTable->GetByteField = local::GetByteField; envTable->GetCharField = local::GetCharField; envTable->GetShortField = local::GetShortField; envTable->GetIntField = local::GetIntField; envTable->GetLongField = local::GetLongField; envTable->GetFloatField = local::GetFloatField; envTable->GetDoubleField = local::GetDoubleField; envTable->SetObjectField = local::SetObjectField; envTable->SetBooleanField = local::SetBooleanField; envTable->SetByteField = local::SetByteField; envTable->SetCharField = local::SetCharField; envTable->SetShortField = local::SetShortField; envTable->SetIntField = local::SetIntField; envTable->SetLongField = local::SetLongField; envTable->SetFloatField = local::SetFloatField; envTable->SetDoubleField = local::SetDoubleField; envTable->GetStaticObjectField = local::GetStaticObjectField; envTable->GetStaticBooleanField = local::GetStaticBooleanField; envTable->GetStaticByteField = local::GetStaticByteField; envTable->GetStaticCharField = local::GetStaticCharField; envTable->GetStaticShortField = local::GetStaticShortField; envTable->GetStaticIntField = local::GetStaticIntField; envTable->GetStaticLongField = local::GetStaticLongField; envTable->GetStaticFloatField = local::GetStaticFloatField; envTable->GetStaticDoubleField = local::GetStaticDoubleField; envTable->SetStaticObjectField = local::SetStaticObjectField; envTable->SetStaticBooleanField = local::SetStaticBooleanField; envTable->SetStaticByteField = local::SetStaticByteField; envTable->SetStaticCharField = local::SetStaticCharField; envTable->SetStaticShortField = local::SetStaticShortField; envTable->SetStaticIntField = local::SetStaticIntField; envTable->SetStaticLongField = local::SetStaticLongField; envTable->SetStaticFloatField = local::SetStaticFloatField; envTable->SetStaticDoubleField = local::SetStaticDoubleField; envTable->NewGlobalRef = local::NewGlobalRef; envTable->NewWeakGlobalRef = local::NewWeakGlobalRef; envTable->DeleteGlobalRef = local::DeleteGlobalRef; envTable->DeleteWeakGlobalRef = local::DeleteWeakGlobalRef; envTable->EnsureLocalCapacity = local::EnsureLocalCapacity; envTable->ExceptionOccurred = local::ExceptionOccurred; envTable->ExceptionDescribe = local::ExceptionDescribe; envTable->ExceptionClear = local::ExceptionClear; envTable->NewObjectArray = local::NewObjectArray; envTable->GetObjectArrayElement = local::GetObjectArrayElement; envTable->SetObjectArrayElement = local::SetObjectArrayElement; envTable->NewBooleanArray = local::NewBooleanArray; envTable->NewByteArray = local::NewByteArray; envTable->NewCharArray = local::NewCharArray; envTable->NewShortArray = local::NewShortArray; envTable->NewIntArray = local::NewIntArray; envTable->NewLongArray = local::NewLongArray; envTable->NewFloatArray = local::NewFloatArray; envTable->NewDoubleArray = local::NewDoubleArray; envTable->GetBooleanArrayElements = local::GetBooleanArrayElements; envTable->GetByteArrayElements = local::GetByteArrayElements; envTable->GetCharArrayElements = local::GetCharArrayElements; envTable->GetShortArrayElements = local::GetShortArrayElements; envTable->GetIntArrayElements = local::GetIntArrayElements; envTable->GetLongArrayElements = local::GetLongArrayElements; envTable->GetFloatArrayElements = local::GetFloatArrayElements; envTable->GetDoubleArrayElements = local::GetDoubleArrayElements; envTable->ReleaseBooleanArrayElements = local::ReleaseBooleanArrayElements; envTable->ReleaseByteArrayElements = local::ReleaseByteArrayElements; envTable->ReleaseCharArrayElements = local::ReleaseCharArrayElements; envTable->ReleaseShortArrayElements = local::ReleaseShortArrayElements; envTable->ReleaseIntArrayElements = local::ReleaseIntArrayElements; envTable->ReleaseLongArrayElements = local::ReleaseLongArrayElements; envTable->ReleaseFloatArrayElements = local::ReleaseFloatArrayElements; envTable->ReleaseDoubleArrayElements = local::ReleaseDoubleArrayElements; envTable->GetBooleanArrayRegion = local::GetBooleanArrayRegion; envTable->GetByteArrayRegion = local::GetByteArrayRegion; envTable->GetCharArrayRegion = local::GetCharArrayRegion; envTable->GetShortArrayRegion = local::GetShortArrayRegion; envTable->GetIntArrayRegion = local::GetIntArrayRegion; envTable->GetLongArrayRegion = local::GetLongArrayRegion; envTable->GetFloatArrayRegion = local::GetFloatArrayRegion; envTable->GetDoubleArrayRegion = local::GetDoubleArrayRegion; envTable->SetBooleanArrayRegion = local::SetBooleanArrayRegion; envTable->SetByteArrayRegion = local::SetByteArrayRegion; envTable->SetCharArrayRegion = local::SetCharArrayRegion; envTable->SetShortArrayRegion = local::SetShortArrayRegion; envTable->SetIntArrayRegion = local::SetIntArrayRegion; envTable->SetLongArrayRegion = local::SetLongArrayRegion; envTable->SetFloatArrayRegion = local::SetFloatArrayRegion; envTable->SetDoubleArrayRegion = local::SetDoubleArrayRegion; envTable->GetPrimitiveArrayCritical = local::GetPrimitiveArrayCritical; envTable->ReleasePrimitiveArrayCritical = local::ReleasePrimitiveArrayCritical; envTable->RegisterNatives = local::RegisterNatives; envTable->UnregisterNatives = local::UnregisterNatives; envTable->MonitorEnter = local::MonitorEnter; envTable->MonitorExit = local::MonitorExit; envTable->GetJavaVM = local::GetJavaVM; envTable->IsSameObject = local::IsSameObject; envTable->PushLocalFrame = local::PushLocalFrame; envTable->PopLocalFrame = local::PopLocalFrame; envTable->FromReflectedMethod = local::FromReflectedMethod; envTable->ToReflectedMethod = local::ToReflectedMethod; envTable->FromReflectedField = local::FromReflectedField; envTable->ToReflectedField = local::ToReflectedField; } } // namespace vm extern "C" AVIAN_EXPORT jint JNICALL JNI_GetDefaultJavaVMInitArgs(void*) { return 0; } extern "C" AVIAN_EXPORT jint JNICALL JNI_GetCreatedJavaVMs(Machine**, jsize, jsize*) { // todo return -1; } extern "C" AVIAN_EXPORT jint JNICALL JNI_CreateJavaVM(Machine** m, Thread** t, void* args) { local::JavaVMInitArgs* a = static_cast(args); unsigned heapLimit = 0; unsigned stackLimit = 0; const char* bootLibraries = 0; const char* classpath = 0; const char* javaHome = AVIAN_JAVA_HOME; const char* embedPrefix = AVIAN_EMBED_PREFIX; const char* bootClasspathPrepend = ""; const char* bootClasspath = 0; const char* bootClasspathAppend = ""; const char* crashDumpDirectory = 0; unsigned propertyCount = 0; for (int i = 0; i < a->nOptions; ++i) { if (strncmp(a->options[i].optionString, "-X", 2) == 0) { const char* p = a->options[i].optionString + 2; if (strncmp(p, "mx", 2) == 0) { heapLimit = local::parseSize(p + 2); } else if (strncmp(p, "ss", 2) == 0) { stackLimit = local::parseSize(p + 2); } else if (strncmp(p, BOOTCLASSPATH_PREPEND_OPTION ":", sizeof(BOOTCLASSPATH_PREPEND_OPTION)) == 0) { bootClasspathPrepend = p + sizeof(BOOTCLASSPATH_PREPEND_OPTION); } else if (strncmp(p, BOOTCLASSPATH_OPTION ":", sizeof(BOOTCLASSPATH_OPTION)) == 0) { bootClasspath = p + sizeof(BOOTCLASSPATH_OPTION); } else if (strncmp(p, BOOTCLASSPATH_APPEND_OPTION ":", sizeof(BOOTCLASSPATH_APPEND_OPTION)) == 0) { bootClasspathAppend = p + sizeof(BOOTCLASSPATH_APPEND_OPTION); } } else if (strncmp(a->options[i].optionString, "-D", 2) == 0) { const char* p = a->options[i].optionString + 2; if (strncmp(p, BOOTSTRAP_PROPERTY "=", sizeof(BOOTSTRAP_PROPERTY)) == 0) { bootLibraries = p + sizeof(BOOTSTRAP_PROPERTY); } else if (strncmp(p, JAVA_COMMAND_PROPERTY "=", sizeof(JAVA_COMMAND_PROPERTY)) == 0 or strncmp(p, JAVA_LAUNCHER_PROPERTY "=", sizeof(JAVA_LAUNCHER_PROPERTY)) == 0) { // this means we're being invoked via the javac or java // command, so the bootstrap library should be e.g. libjvm.so bootLibraries = SO_PREFIX "jvm" SO_SUFFIX; } else if (strncmp(p, CRASHDIR_PROPERTY "=", sizeof(CRASHDIR_PROPERTY)) == 0) { crashDumpDirectory = p + sizeof(CRASHDIR_PROPERTY); } else if (strncmp(p, CLASSPATH_PROPERTY "=", sizeof(CLASSPATH_PROPERTY)) == 0) { classpath = p + sizeof(CLASSPATH_PROPERTY); } else if (strncmp(p, JAVA_HOME_PROPERTY "=", sizeof(JAVA_HOME_PROPERTY)) == 0) { javaHome = p + sizeof(JAVA_HOME_PROPERTY); } else if (strncmp(p, EMBED_PREFIX_PROPERTY "=", sizeof(EMBED_PREFIX_PROPERTY)) == 0) { embedPrefix = p + sizeof(EMBED_PREFIX_PROPERTY); } ++ propertyCount; } } if (heapLimit == 0) heapLimit = 128 * 1024 * 1024; if (stackLimit == 0) stackLimit = 128 * 1024; if (classpath == 0) classpath = "."; System* s = makeSystem(); Heap* h = makeHeap(s, heapLimit); Classpath* c = makeClasspath(s, h, javaHome, embedPrefix); if (bootClasspath == 0) { bootClasspath = c->bootClasspath(); } unsigned bcppl = strlen(bootClasspathPrepend); unsigned bcpl = strlen(bootClasspath); unsigned bcpal = strlen(bootClasspathAppend); unsigned bootClasspathBufferSize = bcppl + bcpl + bcpal + 3; RUNTIME_ARRAY(char, bootClasspathBuffer, bootClasspathBufferSize); char* bootClasspathPointer = RUNTIME_ARRAY_BODY(bootClasspathBuffer); if (bootClasspathBufferSize > 3) { local::append(&bootClasspathPointer, bootClasspathPrepend, bcppl, bcpl + bcpal ? PATH_SEPARATOR : 0); local::append(&bootClasspathPointer, bootClasspath, bcpl, bcpal ? PATH_SEPARATOR : 0); local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0); } else { *RUNTIME_ARRAY_BODY(bootClasspathBuffer) = 0; } char* bootLibrary = bootLibraries ? strdup(bootLibraries) : 0; char* bootLibraryEnd = bootLibrary ? strchr(bootLibrary, PATH_SEPARATOR) : 0; if(bootLibraryEnd) *bootLibraryEnd = 0; Finder* bf = makeFinder (s, h, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary); Finder* af = makeFinder(s, h, classpath, bootLibrary); if(bootLibrary) free(bootLibrary); Processor* p = makeProcessor(s, h, crashDumpDirectory, true); const char** properties = static_cast (h->allocate(sizeof(const char*) * propertyCount)); const char** propertyPointer = properties; const char** arguments = static_cast (h->allocate(sizeof(const char*) * a->nOptions)); const char** argumentPointer = arguments; for (int i = 0; i < a->nOptions; ++i) { if (strncmp(a->options[i].optionString, "-D", 2) == 0) { *(propertyPointer++) = a->options[i].optionString + 2; } *(argumentPointer++) = a->options[i].optionString; } *m = new (h->allocate(sizeof(Machine))) Machine (s, h, bf, af, p, c, properties, propertyCount, arguments, a->nOptions, stackLimit); *t = p->makeThread(*m, 0, 0); enter(*t, Thread::ActiveState); enter(*t, Thread::IdleState); return run(*t, local::boot, 0) ? 0 : -1; } ReadyTalk-avian-1e1fff5/src/lzma-decode.cpp000066400000000000000000000026311231440243200206410ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/lzma-util.h" #include "C/LzmaDec.h" using namespace vm; namespace { int32_t read4(const uint8_t* in) { return (static_cast(in[3]) << 24) | (static_cast(in[2]) << 16) | (static_cast(in[1]) << 8) | (static_cast(in[0]) ); } } // namespace namespace vm { uint8_t* decodeLZMA(System* s, avian::util::Allocator* a, uint8_t* in, unsigned inSize, unsigned* outSize) { const unsigned PropHeaderSize = 5; const unsigned HeaderSize = 13; int32_t outSize32 = read4(in + PropHeaderSize); expect(s, outSize32 >= 0); SizeT outSizeT = outSize32; uint8_t* out = static_cast(a->allocate(outSize32)); SizeT inSizeT = inSize; LzmaAllocator allocator(a); ELzmaStatus status; int result = LzmaDecode (out, &outSizeT, in + HeaderSize, &inSizeT, in, PropHeaderSize, LZMA_FINISH_END, &status, &(allocator.allocator)); expect(s, result == SZ_OK); expect(s, status == LZMA_STATUS_FINISHED_WITH_MARK); *outSize = outSize32; return out; } } // namespace vm ReadyTalk-avian-1e1fff5/src/lzma-encode.cpp000066400000000000000000000030221231440243200206460ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/lzma-util.h" #include "C/LzmaEnc.h" using namespace vm; namespace { SRes myProgress(void*, UInt64, UInt64) { return SZ_OK; } } // namespace namespace vm { uint8_t* encodeLZMA(System* s, Allocator* a, uint8_t* in, unsigned inSize, unsigned* outSize) { const unsigned PropHeaderSize = 5; const unsigned HeaderSize = 13; unsigned bufferSize = inSize * 2; uint8_t* buffer = static_cast(a->allocate(bufferSize)); LzmaAllocator allocator(a); CLzmaEncProps props; LzmaEncProps_Init(&props); props.level = 9; props.writeEndMark = 1; ICompressProgress progress = { myProgress }; SizeT propsSize = PropHeaderSize; int32_t inSize32 = inSize; memcpy(buffer + PropHeaderSize, &inSize32, 4); SizeT outSizeT = bufferSize; int result = LzmaEncode (buffer + HeaderSize, &outSizeT, in, inSize, &props, buffer, &propsSize, 1, &progress, &(allocator.allocator), &(allocator.allocator)); expect(s, result == SZ_OK); *outSize = outSizeT + HeaderSize; uint8_t* out = static_cast(a->allocate(*outSize)); memcpy(out, buffer, *outSize); a->free(buffer, bufferSize); return out; } } // namespace vm ReadyTalk-avian-1e1fff5/src/lzma/000077500000000000000000000000001231440243200167125ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/lzma/load.cpp000066400000000000000000000105041231440243200203350ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "C/LzmaDec.h" #if (defined __MINGW32__) || (defined _MSC_VER) # define EXPORT __declspec(dllexport) # include # define open _open # define write _write # define close _close # ifdef _MSC_VER # define S_IRWXU (_S_IREAD | _S_IWRITE) # define and && # endif #else # define EXPORT __attribute__ ((visibility("default"))) # include # include # include # define O_BINARY 0 #endif #if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) # define SYMBOL(x) binary_exe_##x #else # define SYMBOL(x) _binary_exe_##x #endif extern "C" { extern const uint8_t SYMBOL(start)[]; extern const uint8_t SYMBOL(end)[]; } // extern "C" namespace { int32_t read4(const uint8_t* in) { return (static_cast(in[3]) << 24) | (static_cast(in[2]) << 16) | (static_cast(in[1]) << 8) | (static_cast(in[0]) ); } void* myAllocate(void*, size_t size) { return malloc(size); } void myFree(void*, void* address) { free(address); } #if (defined __MINGW32__) || (defined _MSC_VER) void* openLibrary(const char* name) { return LoadLibrary(name); } void* librarySymbol(void* library, const char* name) { void* address; FARPROC p = GetProcAddress(static_cast(library), name); memcpy(&address, &p, sizeof(void*)); return address; } const char* libraryError(void*) { return "unknown error"; } const char* temporaryFileName(char* buffer, unsigned size) { unsigned c = GetTempPathA(size, buffer); if (c) { if (GetTempFileNameA(buffer, "223", 0, buffer + c)) { DeleteFileA(buffer + c); return buffer + c; } } return 0; } #else void* openLibrary(const char* name) { return dlopen(name, RTLD_LAZY | RTLD_LOCAL); } void* librarySymbol(void* library, const char* name) { return dlsym(library, name); } const char* libraryError(void*) { return dlerror(); } const char* temporaryFileName(char* buffer, unsigned) { return tmpnam(buffer); } #endif } // namespace int main(int ac, const char** av) { const unsigned PropHeaderSize = 5; const unsigned HeaderSize = 13; SizeT inSize = SYMBOL(end) - SYMBOL(start); int32_t outSize32 = read4(SYMBOL(start) + PropHeaderSize); SizeT outSize = outSize32; uint8_t* out = static_cast(malloc(outSize)); if (out) { ISzAlloc allocator = { myAllocate, myFree }; ELzmaStatus status = LZMA_STATUS_NOT_SPECIFIED; if (SZ_OK == LzmaDecode (out, &outSize, SYMBOL(start) + HeaderSize, &inSize, SYMBOL(start), PropHeaderSize, LZMA_FINISH_END, &status, &allocator)) { const unsigned BufferSize = 1024; char buffer[BufferSize]; const char* name = temporaryFileName(buffer, BufferSize); if (name) { int file = open(name, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, S_IRWXU); if (file != -1) { SizeT result = write(file, out, outSize); free(out); if (close(file) == 0 and outSize == result) { void* library = openLibrary(name); unlink(name); if (library) { void* main = librarySymbol(library, "avianMain"); if (main) { int (*mainFunction)(const char*, int, const char**); memcpy(&mainFunction, &main, sizeof(void*)); return mainFunction(name, ac, av); } else { fprintf(stderr, "unable to find main in %s", name); } } else { fprintf(stderr, "unable to load %s: %s\n", name, libraryError(library)); } } else { unlink(name); fprintf(stderr, "close or write failed; tried %d, got %d; %s\n", static_cast(outSize), static_cast(result), strerror(errno)); } } else { fprintf(stderr, "unable to open %s\n", name); } } else { fprintf(stderr, "unable to make temporary file name\n"); } } else { fprintf(stderr, "unable to decode LZMA data\n"); } } else { fprintf(stderr, "unable to allocate buffer of size %d\n", static_cast(outSize)); } return -1; } ReadyTalk-avian-1e1fff5/src/lzma/main.cpp000066400000000000000000000100251231440243200203400ustar00rootroot00000000000000#include #include #include #include #include #include #ifdef WIN32 #include #else #include #include #endif #include #include "LzmaEnc.h" #include "LzmaDec.h" namespace { int32_t read4(const uint8_t* in) { return (static_cast(in[3]) << 24) | (static_cast(in[2]) << 16) | (static_cast(in[1]) << 8) | (static_cast(in[0]) ); } void* myAllocate(void*, size_t size) { return malloc(size); } void myFree(void*, void* address) { free(address); } SRes myProgress(void*, UInt64, UInt64) { return SZ_OK; } void usageAndExit(const char* program) { fprintf(stderr, "usage: %s {encode|decode} " "[]", program); exit(-1); } } // namespace int main(int argc, const char** argv) { if (argc < 4 or argc > 5) { usageAndExit(argv[0]); } bool encode = strcmp(argv[1], "encode") == 0; uint8_t* data = 0; unsigned size; int fd = open(argv[2], O_RDONLY); if (fd != -1) { struct stat s; int r = fstat(fd, &s); if (r != -1) { #ifdef WIN32 HANDLE fm; HANDLE h = (HANDLE) _get_osfhandle (fd); fm = CreateFileMapping( h, NULL, PAGE_READONLY, 0, 0, NULL); data = static_cast(MapViewOfFile( fm, FILE_MAP_READ, 0, 0, s.st_size)); CloseHandle(fm); #else data = static_cast (mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0)); #endif size = s.st_size; } close(fd); } bool success = false; if (data) { const unsigned PropHeaderSize = 5; const unsigned HeaderSize = 13; SizeT outSize; if (encode) { outSize = size * 2; } else { int32_t outSize32 = read4(data + PropHeaderSize); if (outSize32 >= 0) { outSize = outSize32; } else if (argc == 5) { outSize = atoi(argv[4]); } else { outSize = -1; } } if (outSize >= 0) { uint8_t* out = static_cast(malloc(outSize)); if (out) { SizeT inSize = size; ISzAlloc allocator = { myAllocate, myFree }; ELzmaStatus status = LZMA_STATUS_NOT_SPECIFIED; int result; if (encode) { CLzmaEncProps props; LzmaEncProps_Init(&props); props.level = 9; props.writeEndMark = 1; ICompressProgress progress = { myProgress }; SizeT propsSize = PropHeaderSize; int32_t inSize32 = inSize; memcpy(out + PropHeaderSize, &inSize32, 4); result = LzmaEncode (out + HeaderSize, &outSize, data, inSize, &props, out, &propsSize, 1, &progress, &allocator, &allocator); outSize += HeaderSize; } else { result = LzmaDecode (out, &outSize, data + HeaderSize, &inSize, data, PropHeaderSize, LZMA_FINISH_END, &status, &allocator); } if (result == SZ_OK) { FILE* outFile = fopen(argv[3], "wb"); if (outFile) { if (fwrite(out, outSize, 1, outFile) == 1) { success = true; } else { fprintf(stderr, "unable to write to %s\n", argv[3]); } fclose(outFile); } else { fprintf(stderr, "unable to open %s\n", argv[3]); } } else { fprintf(stderr, "unable to %s data: result %d status %d\n", encode ? "encode" : "decode", result, status); } free(out); } else { fprintf(stderr, "unable to allocate output buffer\n"); } } else { fprintf(stderr, "unable to determine uncompressed size\n"); } #ifdef WIN32 UnmapViewOfFile(data); #else munmap(data, size); #endif } else { perror(argv[0]); } return (success ? 0 : -1); } ReadyTalk-avian-1e1fff5/src/machine.cpp000066400000000000000000004367051231440243200200760ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/jnienv.h" #include "avian/machine.h" #include "avian/util.h" #include #include "avian/constants.h" #include "avian/processor.h" #include "avian/arch.h" #include "avian/lzma.h" #include #include #if defined(PLATFORM_WINDOWS) # define WIN32_LEAN_AND_MEAN # include #endif using namespace vm; using namespace avian::util; namespace { const bool DebugClassReader = false; const unsigned NoByte = 0xFFFF; #ifdef USE_ATOMIC_OPERATIONS void atomicIncrement(uint32_t* p, int v) { for (uint32_t old = *p; not atomicCompareAndSwap32(p, old, old + v); old = *p) { } } #endif void join(Thread* t, Thread* o) { if (t != o) { assert(t, o->state != Thread::JoinedState); assert(t, (o->flags & Thread::SystemFlag) == 0); if (o->flags & Thread::JoinFlag) { o->systemThread->join(); } o->state = Thread::JoinedState; } } #ifndef NDEBUG bool find(Thread* t, Thread* o) { return (t == o) or (t->peer and find(t->peer, o)) or (t->child and find(t->child, o)); } unsigned count(Thread* t, Thread* o) { unsigned c = 0; if (t != o) ++ c; if (t->peer) c += count(t->peer, o); if (t->child) c += count(t->child, o); return c; } Thread** fill(Thread* t, Thread* o, Thread** array) { if (t != o) *(array++) = t; if (t->peer) array = fill(t->peer, o, array); if (t->child) array = fill(t->child, o, array); return array; } #endif // not NDEBUG void dispose(Thread* t, Thread* o, bool remove) { if (remove) { #ifndef NDEBUG expect(t, find(t->m->rootThread, o)); unsigned c = count(t->m->rootThread, o); THREAD_RUNTIME_ARRAY(t, Thread*, threads, c); fill(t->m->rootThread, o, RUNTIME_ARRAY_BODY(threads)); #endif if (o->parent) { Thread* previous = 0; for (Thread* p = o->parent->child; p;) { if (p == o) { if (p == o->parent->child) { o->parent->child = p->peer; } else { previous->peer = p->peer; } break; } else { previous = p; p = p->peer; } } for (Thread* p = o->child; p;) { Thread* next = p->peer; p->peer = o->parent->child; o->parent->child = p; p->parent = o->parent; p = next; } } else if (o->child) { t->m->rootThread = o->child; for (Thread* p = o->peer; p;) { Thread* next = p->peer; p->peer = t->m->rootThread; t->m->rootThread = p; p = next; } } else if (o->peer) { t->m->rootThread = o->peer; } else { abort(t); } #ifndef NDEBUG expect(t, not find(t->m->rootThread, o)); for (unsigned i = 0; i < c; ++i) { expect(t, find(t->m->rootThread, RUNTIME_ARRAY_BODY(threads)[i])); } #endif } o->dispose(); } void visitAll(Thread* m, Thread* o, void (*visit)(Thread*, Thread*)) { for (Thread* p = o->child; p;) { Thread* child = p; p = p->peer; visitAll(m, child, visit); } visit(m, o); } void disposeNoRemove(Thread* m, Thread* o) { dispose(m, o, false); } void interruptDaemon(Thread* m, Thread* o) { if (o->flags & Thread::DaemonFlag) { interrupt(m, o); } } void turnOffTheLights(Thread* t) { expect(t, t->m->liveCount == 1); visitAll(t, t->m->rootThread, join); enter(t, Thread::ExitState); { object p = 0; PROTECT(t, p); for (p = t->m->finalizers; p;) { object f = p; p = finalizerNext(t, p); void (*function)(Thread*, object); memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); if (function) { function(t, finalizerTarget(t, f)); } } for (p = t->m->tenuredFinalizers; p;) { object f = p; p = finalizerNext(t, p); void (*function)(Thread*, object); memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); if (function) { function(t, finalizerTarget(t, f)); } } } if (root(t, Machine::VirtualFiles)) { for (unsigned i = 0; i < arrayLength(t, root(t, Machine::VirtualFiles)); ++i) { object region = arrayBody(t, root(t, Machine::VirtualFiles), i); if (region) { static_cast(regionRegion(t, region))->dispose(); } } } for (object p = root(t, Machine::VirtualFileFinders); p; p = finderNext(t, p)) { static_cast(finderFinder(t, p))->dispose(); } Machine* m = t->m; visitAll(t, t->m->rootThread, disposeNoRemove); System* s = m->system; expect(s, m->threadCount == 0); Heap* h = m->heap; Processor* p = m->processor; Classpath* c = m->classpath; Finder* bf = m->bootFinder; Finder* af = m->appFinder; c->dispose(); h->disposeFixies(); m->dispose(); p->dispose(); bf->dispose(); af->dispose(); h->dispose(); s->dispose(); } void killZombies(Thread* t, Thread* o) { for (Thread* p = o->child; p;) { Thread* child = p; p = p->peer; killZombies(t, child); } if ((o->flags & Thread::SystemFlag) == 0) { switch (o->state) { case Thread::ZombieState: join(t, o); // fall through case Thread::JoinedState: dispose(t, o, true); default: break; } } } unsigned footprint(Thread* t) { expect(t, t->criticalLevel == 0); unsigned n = t->heapOffset + t->heapIndex + t->backupHeapIndex; for (Thread* c = t->child; c; c = c->peer) { n += footprint(c); } return n; } void visitRoots(Thread* t, Heap::Visitor* v) { if (t->state != Thread::ZombieState) { v->visit(&(t->javaThread)); v->visit(&(t->exception)); t->m->processor->visitObjects(t, v); for (Thread::Protector* p = t->protector; p; p = p->next) { p->visit(v); } } for (Thread* c = t->child; c; c = c->peer) { visitRoots(c, v); } } bool walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize, unsigned arrayElementSize, unsigned arrayLength, unsigned start) { unsigned fixedSizeInWords = ceilingDivide(fixedSize, BytesPerWord); unsigned arrayElementSizeInWords = ceilingDivide(arrayElementSize, BytesPerWord); for (unsigned i = start; i < fixedSizeInWords; ++i) { if (mask[i / 32] & (static_cast(1) << (i % 32))) { if (not w->visit(i)) { return false; } } } bool arrayObjectElements = false; for (unsigned j = 0; j < arrayElementSizeInWords; ++j) { unsigned k = fixedSizeInWords + j; if (mask[k / 32] & (static_cast(1) << (k % 32))) { arrayObjectElements = true; break; } } if (arrayObjectElements) { unsigned arrayStart; unsigned elementStart; if (start > fixedSizeInWords) { unsigned s = start - fixedSizeInWords; arrayStart = s / arrayElementSizeInWords; elementStart = s % arrayElementSizeInWords; } else { arrayStart = 0; elementStart = 0; } for (unsigned i = arrayStart; i < arrayLength; ++i) { for (unsigned j = elementStart; j < arrayElementSizeInWords; ++j) { unsigned k = fixedSizeInWords + j; if (mask[k / 32] & (static_cast(1) << (k % 32))) { if (not w->visit (fixedSizeInWords + (i * arrayElementSizeInWords) + j)) { return false; } } } } } return true; } object findInInterfaces(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object)) { object result = 0; if (classInterfaceTable(t, class_)) { for (unsigned i = 0; i < arrayLength(t, classInterfaceTable(t, class_)) and result == 0; i += 2) { result = find (t, arrayBody(t, classInterfaceTable(t, class_), i), name, spec); } } return result; } void finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p) { v->visit(&finalizerTarget(t, *p)); object finalizer = *p; *p = finalizerNext(t, finalizer); void (*function)(Thread*, object); memcpy(&function, &finalizerFinalize(t, finalizer), BytesPerWord); if (function) { finalizerNext(t, finalizer) = t->m->finalizeQueue; t->m->finalizeQueue = finalizer; } else { set(t, finalizer, FinalizerQueueTarget, finalizerTarget(t, finalizer)); set(t, finalizer, FinalizerQueueNext, root(t, Machine::ObjectsToFinalize)); setRoot(t, Machine::ObjectsToFinalize, finalizer); } } void referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p) { if (DebugReferences) { fprintf(stderr, "target %p unreachable for reference %p\n", jreferenceTarget(t, *p), *p); } v->visit(p); jreferenceTarget(t, *p) = 0; if (objectClass(t, *p) == type(t, Machine::CleanerType)) { object reference = *p; *p = jreferenceVmNext(t, reference); set(t, reference, CleanerQueueNext, root(t, Machine::ObjectsToClean)); setRoot(t, Machine::ObjectsToClean, reference); } else { if (jreferenceQueue(t, *p) and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable) { // queue is reachable - add the reference v->visit(&jreferenceQueue(t, *p)); object q = jreferenceQueue(t, *p); if (referenceQueueFront(t, q)) { set(t, *p, JreferenceJNext, referenceQueueFront(t, q)); } else { set(t, *p, JreferenceJNext, *p); } set(t, q, ReferenceQueueFront, *p); jreferenceQueue(t, *p) = 0; } *p = jreferenceVmNext(t, *p); } } void referenceUnreachable(Thread* t, Heap::Visitor* v, object* p) { object r = static_cast(t->m->heap->follow(*p)); if (DebugReferences) { fprintf(stderr, "reference %p unreachable (target %p)\n", *p, jreferenceTarget(t, r)); } if (jreferenceQueue(t, r) and t->m->heap->status(jreferenceQueue(t, r)) != Heap::Unreachable) { // queue is reachable - add the reference referenceTargetUnreachable(t, v, p); } else { *p = jreferenceVmNext(t, *p); } } void referenceTargetReachable(Thread* t, Heap::Visitor* v, object* p) { if (DebugReferences) { fprintf(stderr, "target %p reachable for reference %p\n", jreferenceTarget(t, *p), *p); } v->visit(p); v->visit(&jreferenceTarget(t, *p)); if (t->m->heap->status(jreferenceQueue(t, *p)) == Heap::Unreachable) { jreferenceQueue(t, *p) = 0; } else { v->visit(&jreferenceQueue(t, *p)); } } bool isFinalizable(Thread* t, object o) { return t->m->heap->status(o) == Heap::Unreachable and (classVmFlags (t, static_cast(t->m->heap->follow(objectClass(t, o)))) & HasFinalizerFlag); } void clearTargetIfFinalizable(Thread* t, object r) { if (isFinalizable (t, static_cast(t->m->heap->follow(jreferenceTarget(t, r))))) { jreferenceTarget(t, r) = 0; } } void postVisit(Thread* t, Heap::Visitor* v) { Machine* m = t->m; bool major = m->heap->collectionType() == Heap::MajorCollection; assert(t, m->finalizeQueue == 0); m->heap->postVisit(); for (object p = m->weakReferences; p;) { object r = static_cast(m->heap->follow(p)); p = jreferenceVmNext(t, r); clearTargetIfFinalizable(t, r); } if (major) { for (object p = m->tenuredWeakReferences; p;) { object r = static_cast(m->heap->follow(p)); p = jreferenceVmNext(t, r); clearTargetIfFinalizable(t, r); } } for (Reference* r = m->jniReferences; r; r = r->next) { if (r->weak and isFinalizable (t, static_cast(t->m->heap->follow(r->target)))) { r->target = 0; } } object firstNewTenuredFinalizer = 0; object lastNewTenuredFinalizer = 0; { object unreachable = 0; for (object* p = &(m->finalizers); *p;) { v->visit(p); if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) { object finalizer = *p; *p = finalizerNext(t, finalizer); finalizerNext(t, finalizer) = unreachable; unreachable = finalizer; } else { p = &finalizerNext(t, *p); } } for (object* p = &(m->finalizers); *p;) { // target is reachable v->visit(&finalizerTarget(t, *p)); if (m->heap->status(*p) == Heap::Tenured) { // the finalizer is tenured, so we remove it from // m->finalizers and later add it to m->tenuredFinalizers if (lastNewTenuredFinalizer == 0) { lastNewTenuredFinalizer = *p; } object finalizer = *p; *p = finalizerNext(t, finalizer); finalizerNext(t, finalizer) = firstNewTenuredFinalizer; firstNewTenuredFinalizer = finalizer; } else { p = &finalizerNext(t, *p); } } for (object* p = &unreachable; *p;) { // target is unreachable - queue it up for finalization finalizerTargetUnreachable(t, v, p); } } object firstNewTenuredWeakReference = 0; object lastNewTenuredWeakReference = 0; for (object* p = &(m->weakReferences); *p;) { if (m->heap->status(*p) == Heap::Unreachable) { // reference is unreachable referenceUnreachable(t, v, p); } else if (m->heap->status (jreferenceTarget (t, static_cast(m->heap->follow(*p)))) == Heap::Unreachable) { // target is unreachable referenceTargetUnreachable(t, v, p); } else { // both reference and target are reachable referenceTargetReachable(t, v, p); if (m->heap->status(*p) == Heap::Tenured) { // the reference is tenured, so we remove it from // m->weakReferences and later add it to // m->tenuredWeakReferences if (lastNewTenuredWeakReference == 0) { lastNewTenuredWeakReference = *p; } object reference = *p; *p = jreferenceVmNext(t, reference); jreferenceVmNext(t, reference) = firstNewTenuredWeakReference; firstNewTenuredWeakReference = reference; } else { p = &jreferenceVmNext(t, *p); } } } if (major) { { object unreachable = 0; for (object* p = &(m->tenuredFinalizers); *p;) { v->visit(p); if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) { object finalizer = *p; *p = finalizerNext(t, finalizer); finalizerNext(t, finalizer) = unreachable; unreachable = finalizer; } else { p = &finalizerNext(t, *p); } } for (object* p = &(m->tenuredFinalizers); *p;) { // target is reachable v->visit(&finalizerTarget(t, *p)); p = &finalizerNext(t, *p); } for (object* p = &unreachable; *p;) { // target is unreachable - queue it up for finalization finalizerTargetUnreachable(t, v, p); } } for (object* p = &(m->tenuredWeakReferences); *p;) { if (m->heap->status(*p) == Heap::Unreachable) { // reference is unreachable referenceUnreachable(t, v, p); } else if (m->heap->status (jreferenceTarget (t, static_cast(m->heap->follow(*p)))) == Heap::Unreachable) { // target is unreachable referenceTargetUnreachable(t, v, p); } else { // both reference and target are reachable referenceTargetReachable(t, v, p); p = &jreferenceVmNext(t, *p); } } } if (lastNewTenuredFinalizer) { finalizerNext(t, lastNewTenuredFinalizer) = m->tenuredFinalizers; m->tenuredFinalizers = firstNewTenuredFinalizer; } if (lastNewTenuredWeakReference) { jreferenceVmNext(t, lastNewTenuredWeakReference) = m->tenuredWeakReferences; m->tenuredWeakReferences = firstNewTenuredWeakReference; } for (Reference* r = m->jniReferences; r; r = r->next) { if (r->weak) { if (m->heap->status(r->target) == Heap::Unreachable) { r->target = 0; } else { v->visit(&(r->target)); } } } } void postCollect(Thread* t) { #ifdef VM_STRESS t->m->heap->free(t->defaultHeap, ThreadHeapSizeInBytes); t->defaultHeap = static_cast (t->m->heap->allocate(ThreadHeapSizeInBytes)); memset(t->defaultHeap, 0, ThreadHeapSizeInBytes); #endif if (t->heap == t->defaultHeap) { memset(t->defaultHeap, 0, t->heapIndex * BytesPerWord); } else { memset(t->defaultHeap, 0, ThreadHeapSizeInBytes); t->heap = t->defaultHeap; } t->heapOffset = 0; if (t->m->heap->limitExceeded()) { // if we're out of memory, pretend the thread-local heap is // already full so we don't make things worse: t->heapIndex = ThreadHeapSizeInWords; } else { t->heapIndex = 0; } if (t->flags & Thread::UseBackupHeapFlag) { memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes); t->flags &= ~Thread::UseBackupHeapFlag; t->backupHeapIndex = 0; } for (Thread* c = t->child; c; c = c->peer) { postCollect(c); } } uint64_t invoke(Thread* t, uintptr_t* arguments) { object m = *reinterpret_cast(arguments[0]); object o = *reinterpret_cast(arguments[1]); t->m->processor->invoke(t, m, o); return 1; } void finalizeObject(Thread* t, object o, const char* name) { for (object c = objectClass(t, o); c; c = classSuper(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object m = arrayBody(t, classMethodTable(t, c), i); if (vm::strcmp(reinterpret_cast(name), &byteArrayBody(t, methodName(t, m), 0)) == 0 and vm::strcmp(reinterpret_cast("()V"), &byteArrayBody(t, methodSpec(t, m), 0)) == 0) { PROTECT(t, m); PROTECT(t, o); uintptr_t arguments[] = { reinterpret_cast(&m), reinterpret_cast(&o) }; run(t, invoke, arguments); t->exception = 0; return; } } } abort(t); } unsigned readByte(AbstractStream& s, unsigned* value) { if (*value == NoByte) { return s.read1(); } else { unsigned r = *value; *value = NoByte; return r; } } object parseUtf8NonAscii(Thread* t, AbstractStream& s, object bytesSoFar, unsigned byteCount, unsigned sourceIndex, unsigned byteA, unsigned byteB) { PROTECT(t, bytesSoFar); unsigned length = byteArrayLength(t, bytesSoFar) - 1; object value = makeCharArray(t, length + 1); unsigned vi = 0; for (; vi < byteCount; ++vi) { charArrayBody(t, value, vi) = byteArrayBody(t, bytesSoFar, vi); } for (unsigned si = sourceIndex; si < length; ++si) { unsigned a = readByte(s, &byteA); if (a & 0x80) { if (a & 0x20) { // 3 bytes si += 2; assert(t, si < length); unsigned b = readByte(s, &byteB); unsigned c = s.read1(); charArrayBody(t, value, vi++) = ((a & 0xf) << 12) | ((b & 0x3f) << 6) | (c & 0x3f); } else { // 2 bytes ++ si; assert(t, si < length); unsigned b = readByte(s, &byteB); if (a == 0xC0 and b == 0x80) { charArrayBody(t, value, vi++) = 0; } else { charArrayBody(t, value, vi++) = ((a & 0x1f) << 6) | (b & 0x3f); } } } else { charArrayBody(t, value, vi++) = a; } } if (vi < length) { PROTECT(t, value); object v = makeCharArray(t, vi + 1); memcpy(&charArrayBody(t, v, 0), &charArrayBody(t, value, 0), vi * 2); value = v; } return value; } object parseUtf8(Thread* t, AbstractStream& s, unsigned length) { object value = makeByteArray(t, length + 1); unsigned vi = 0; for (unsigned si = 0; si < length; ++si) { unsigned a = s.read1(); if (a & 0x80) { if (a & 0x20) { // 3 bytes return parseUtf8NonAscii(t, s, value, vi, si, a, NoByte); } else { // 2 bytes unsigned b = s.read1(); if (a == 0xC0 and b == 0x80) { ++ si; assert(t, si < length); byteArrayBody(t, value, vi++) = 0; } else { return parseUtf8NonAscii(t, s, value, vi, si, a, b); } } } else { byteArrayBody(t, value, vi++) = a; } } if (vi < length) { PROTECT(t, value); object v = makeByteArray(t, vi + 1); memcpy(&byteArrayBody(t, v, 0), &byteArrayBody(t, value, 0), vi); value = v; } return value; } object makeByteArray(Thread* t, Stream& s, unsigned length) { object value = makeByteArray(t, length + 1); s.read(reinterpret_cast(&byteArrayBody(t, value, 0)), length); return value; } void removeByteArray(Thread* t, object o) { hashMapRemove (t, root(t, Machine::ByteArrayMap), o, byteArrayHash, objectEqual); } object internByteArray(Thread* t, object array) { PROTECT(t, array); ACQUIRE(t, t->m->referenceLock); object n = hashMapFindNode (t, root(t, Machine::ByteArrayMap), array, byteArrayHash, byteArrayEqual); if (n) { return jreferenceTarget(t, tripleFirst(t, n)); } else { hashMapInsert(t, root(t, Machine::ByteArrayMap), array, 0, byteArrayHash); addFinalizer(t, array, removeByteArray); return array; } } unsigned parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i) { PROTECT(t, pool); s.setPosition(index[i]); switch (s.read1()) { case CONSTANT_Integer: case CONSTANT_Float: { uint32_t v = s.read4(); singletonValue(t, pool, i) = v; if(DebugClassReader) { fprintf(stderr, " consts[%d] = int/float 0x%x\n", i, v); } } return 1; case CONSTANT_Long: case CONSTANT_Double: { uint64_t v = s.read8(); memcpy(&singletonValue(t, pool, i), &v, 8); if(DebugClassReader) { fprintf(stderr, " consts[%d] = long/double \n", i); } } return 2; case CONSTANT_Utf8: { if (singletonObject(t, pool, i) == 0) { object value = internByteArray(t, makeByteArray(t, s, s.read2())); set(t, pool, SingletonBody + (i * BytesPerWord), value); if(DebugClassReader) { fprintf(stderr, " consts[%d] = utf8 %s\n", i, &byteArrayBody(t, value, 0)); } } } return 1; case CONSTANT_Class: { if (singletonObject(t, pool, i) == 0) { unsigned si = s.read2() - 1; parsePoolEntry(t, s, index, pool, si); object value = makeReference(t, 0, singletonObject(t, pool, si), 0); set(t, pool, SingletonBody + (i * BytesPerWord), value); if(DebugClassReader) { fprintf(stderr, " consts[%d] = class \n", i); } } } return 1; case CONSTANT_String: { if (singletonObject(t, pool, i) == 0) { unsigned si = s.read2() - 1; parsePoolEntry(t, s, index, pool, si); object value = parseUtf8(t, singletonObject(t, pool, si)); value = t->m->classpath->makeString (t, value, 0, fieldAtOffset(value, BytesPerWord) - 1); value = intern(t, value); set(t, pool, SingletonBody + (i * BytesPerWord), value); if(DebugClassReader) { fprintf(stderr, " consts[%d] = string \n", i); } } } return 1; case CONSTANT_NameAndType: { if (singletonObject(t, pool, i) == 0) { unsigned ni = s.read2() - 1; unsigned ti = s.read2() - 1; parsePoolEntry(t, s, index, pool, ni); parsePoolEntry(t, s, index, pool, ti); object name = singletonObject(t, pool, ni); object type = singletonObject(t, pool, ti); object value = makePair(t, name, type); set(t, pool, SingletonBody + (i * BytesPerWord), value); if(DebugClassReader) { fprintf(stderr, " consts[%d] = nameAndType %s%s\n", i, &byteArrayBody(t, name, 0), &byteArrayBody(t, type, 0)); } } } return 1; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: { if (singletonObject(t, pool, i) == 0) { unsigned ci = s.read2() - 1; unsigned nti = s.read2() - 1; parsePoolEntry(t, s, index, pool, ci); parsePoolEntry(t, s, index, pool, nti); object class_ = referenceName(t, singletonObject(t, pool, ci)); object nameAndType = singletonObject(t, pool, nti); object value = makeReference (t, class_, pairFirst(t, nameAndType), pairSecond(t, nameAndType)); set(t, pool, SingletonBody + (i * BytesPerWord), value); if(DebugClassReader) { fprintf(stderr, " consts[%d] = method %s.%s%s\n", i, &byteArrayBody(t, class_, 0), &byteArrayBody(t, pairFirst(t, nameAndType), 0), &byteArrayBody(t, pairSecond(t, nameAndType), 0)); } } } return 1; default: abort(t); } } object parsePool(Thread* t, Stream& s) { unsigned count = s.read2() - 1; object pool = makeSingletonOfSize(t, count + poolMaskSize(count)); PROTECT(t, pool); if(DebugClassReader) { fprintf(stderr, " const pool entries %d\n", count); } if (count) { uint32_t* index = static_cast(t->m->heap->allocate(count * 4)); THREAD_RESOURCE2(t, uint32_t*, index, unsigned, count, t->m->heap->free(index, count * 4)); for (unsigned i = 0; i < count; ++i) { index[i] = s.position(); switch (s.read1()) { case CONSTANT_Class: case CONSTANT_String: singletonMarkObject(t, pool, i); s.skip(2); break; case CONSTANT_Integer: s.skip(4); break; case CONSTANT_Float: singletonSetBit(t, pool, count, i); s.skip(4); break; case CONSTANT_NameAndType: case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: singletonMarkObject(t, pool, i); s.skip(4); break; case CONSTANT_Long: s.skip(8); ++ i; break; case CONSTANT_Double: singletonSetBit(t, pool, count, i); singletonSetBit(t, pool, count, i + 1); s.skip(8); ++ i; break; case CONSTANT_Utf8: singletonMarkObject(t, pool, i); s.skip(s.read2()); break; default: abort(t); } } unsigned end = s.position(); for (unsigned i = 0; i < count;) { i += parsePoolEntry(t, s, index, pool, i); } s.setPosition(end); } return pool; } void addInterfaces(Thread* t, object class_, object map) { object table = classInterfaceTable(t, class_); if (table) { unsigned increment = 2; if (classFlags(t, class_) & ACC_INTERFACE) { increment = 1; } PROTECT(t, map); PROTECT(t, table); for (unsigned i = 0; i < arrayLength(t, table); i += increment) { object interface = arrayBody(t, table, i); object name = className(t, interface); hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual); } } } object getClassAddendum(Thread* t, object class_, object pool) { object addendum = classAddendum(t, class_); if (addendum == 0) { PROTECT(t, class_); addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, -1, 0, 0); set(t, class_, ClassAddendum, addendum); } return addendum; } void parseInterfaceTable(Thread* t, Stream& s, object class_, object pool, Machine::Type throwType) { PROTECT(t, class_); PROTECT(t, pool); object map = makeHashMap(t, 0, 0); PROTECT(t, map); if (classSuper(t, class_)) { addInterfaces(t, classSuper(t, class_), map); } unsigned count = s.read2(); object table = 0; PROTECT(t, table); if (count) { table = makeArray(t, count); object addendum = getClassAddendum(t, class_, pool); set(t, addendum, ClassAddendumInterfaceTable, table); } for (unsigned i = 0; i < count; ++i) { object name = referenceName(t, singletonObject(t, pool, s.read2() - 1)); PROTECT(t, name); object interface = resolveClass (t, classLoader(t, class_), name, true, throwType); PROTECT(t, interface); set(t, table, ArrayBody + (i * BytesPerWord), interface); hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual); addInterfaces(t, interface, map); } object interfaceTable = 0; if (hashMapSize(t, map)) { unsigned length = hashMapSize(t, map); if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { length *= 2; } interfaceTable = makeArray(t, length); PROTECT(t, interfaceTable); unsigned i = 0; for (HashMapIterator it(t, map); it.hasMore();) { object interface = tripleSecond(t, it.next()); set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface); ++ i; if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { if (classVirtualTable(t, interface)) { // we'll fill in this table in parseMethodTable(): object vtable = makeArray (t, arrayLength(t, classVirtualTable(t, interface))); set(t, interfaceTable, ArrayBody + (i * BytesPerWord), vtable); } ++i; } } } set(t, class_, ClassInterfaceTable, interfaceTable); } void parseFieldTable(Thread* t, Stream& s, object class_, object pool) { PROTECT(t, class_); PROTECT(t, pool); unsigned memberOffset = BytesPerWord; if (classSuper(t, class_)) { memberOffset = classFixedSize(t, classSuper(t, class_)); } unsigned count = s.read2(); if (count) { unsigned staticOffset = BytesPerWord * 3; unsigned staticCount = 0; object fieldTable = makeArray(t, count); PROTECT(t, fieldTable); object staticValueTable = makeIntArray(t, count); PROTECT(t, staticValueTable); object addendum = 0; PROTECT(t, addendum); THREAD_RUNTIME_ARRAY(t, uint8_t, staticTypes, count); for (unsigned i = 0; i < count; ++i) { unsigned flags = s.read2(); unsigned name = s.read2(); unsigned spec = s.read2(); unsigned value = 0; addendum = 0; unsigned code = fieldCode (t, byteArrayBody(t, singletonObject(t, pool, spec - 1), 0)); unsigned attributeCount = s.read2(); for (unsigned j = 0; j < attributeCount; ++j) { object name = singletonObject(t, pool, s.read2() - 1); unsigned length = s.read4(); if (vm::strcmp(reinterpret_cast("ConstantValue"), &byteArrayBody(t, name, 0)) == 0) { value = s.read2(); } else if (vm::strcmp(reinterpret_cast("Signature"), &byteArrayBody(t, name, 0)) == 0) { if (addendum == 0) { addendum = makeFieldAddendum(t, pool, 0, 0); } set(t, addendum, AddendumSignature, singletonObject(t, pool, s.read2() - 1)); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { if (addendum == 0) { addendum = makeFieldAddendum(t, pool, 0, 0); } object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); set(t, addendum, AddendumAnnotationTable, body); } else { s.skip(length); } } object field = makeField (t, 0, // vm flags code, flags, 0, // offset 0, // native ID singletonObject(t, pool, name - 1), singletonObject(t, pool, spec - 1), addendum, class_); unsigned size = fieldSize(t, code); if (flags & ACC_STATIC) { staticOffset = pad(staticOffset, size); fieldOffset(t, field) = staticOffset; staticOffset += size; intArrayBody(t, staticValueTable, staticCount) = value; RUNTIME_ARRAY_BODY(staticTypes)[staticCount++] = code; } else { if (flags & ACC_FINAL) { classVmFlags(t, class_) |= HasFinalMemberFlag; } memberOffset = pad(memberOffset, size); fieldOffset(t, field) = memberOffset; memberOffset += size; } set(t, fieldTable, ArrayBody + (i * BytesPerWord), field); } set(t, class_, ClassFieldTable, fieldTable); if (staticCount) { unsigned footprint = ceilingDivide(staticOffset - (BytesPerWord * 2), BytesPerWord); object staticTable = makeSingletonOfSize(t, footprint); uint8_t* body = reinterpret_cast (&singletonBody(t, staticTable, 0)); memcpy(body, &class_, BytesPerWord); singletonMarkObject(t, staticTable, 0); for (unsigned i = 0, offset = BytesPerWord; i < staticCount; ++i) { unsigned size = fieldSize(t, RUNTIME_ARRAY_BODY(staticTypes)[i]); offset = pad(offset, size); unsigned value = intArrayBody(t, staticValueTable, i); if (value) { switch (RUNTIME_ARRAY_BODY(staticTypes)[i]) { case ByteField: case BooleanField: body[offset] = singletonValue(t, pool, value - 1); break; case CharField: case ShortField: *reinterpret_cast(body + offset) = singletonValue(t, pool, value - 1); break; case IntField: case FloatField: *reinterpret_cast(body + offset) = singletonValue(t, pool, value - 1); break; case LongField: case DoubleField: memcpy(body + offset, &singletonValue(t, pool, value - 1), 8); break; case ObjectField: memcpy(body + offset, &singletonObject(t, pool, value - 1), BytesPerWord); break; default: abort(t); } } if (RUNTIME_ARRAY_BODY(staticTypes)[i] == ObjectField) { singletonMarkObject(t, staticTable, offset / BytesPerWord); } offset += size; } set(t, class_, ClassStaticTable, staticTable); } } classFixedSize(t, class_) = pad(memberOffset); if (classSuper(t, class_) and memberOffset == classFixedSize(t, classSuper(t, class_))) { set(t, class_, ClassObjectMask, classObjectMask(t, classSuper(t, class_))); } else { object mask = makeIntArray (t, ceilingDivide(classFixedSize(t, class_), 32 * BytesPerWord)); intArrayBody(t, mask, 0) = 1; object superMask = 0; if (classSuper(t, class_)) { superMask = classObjectMask(t, classSuper(t, class_)); if (superMask) { memcpy(&intArrayBody(t, mask, 0), &intArrayBody(t, superMask, 0), ceilingDivide(classFixedSize(t, classSuper(t, class_)), 32 * BytesPerWord) * 4); } } bool sawReferenceField = false; object fieldTable = classFieldTable(t, class_); if (fieldTable) { for (int i = arrayLength(t, fieldTable) - 1; i >= 0; --i) { object field = arrayBody(t, fieldTable, i); if ((fieldFlags(t, field) & ACC_STATIC) == 0 and fieldCode(t, field) == ObjectField) { unsigned index = fieldOffset(t, field) / BytesPerWord; intArrayBody(t, mask, (index / 32)) |= 1 << (index % 32); sawReferenceField = true; } } } if (superMask or sawReferenceField) { set(t, class_, ClassObjectMask, mask); } } } uint16_t read16(uint8_t* code, unsigned& ip) { uint16_t a = code[ip++]; uint16_t b = code[ip++]; return (a << 8) | b; } uint32_t read32(uint8_t* code, unsigned& ip) { uint32_t b = code[ip++]; uint32_t a = code[ip++]; uint32_t c = code[ip++]; uint32_t d = code[ip++]; return (a << 24) | (b << 16) | (c << 8) | d; } void disassembleCode(const char* prefix, uint8_t* code, unsigned length) { unsigned ip = 0; while(ip < length) { unsigned instr; fprintf(stderr, "%s%x:\t", prefix, ip); switch (instr = code[ip++]) { case aaload: fprintf(stderr, "aaload\n"); break; case aastore: fprintf(stderr, "aastore\n"); break; case aconst_null: fprintf(stderr, "aconst_null\n"); break; case aload: fprintf(stderr, "aload %02x\n", code[ip++]); break; case aload_0: fprintf(stderr, "aload_0\n"); break; case aload_1: fprintf(stderr, "aload_1\n"); break; case aload_2: fprintf(stderr, "aload_2\n"); break; case aload_3: fprintf(stderr, "aload_3\n"); break; case anewarray: fprintf(stderr, "anewarray %04x\n", read16(code, ip)); break; case areturn: fprintf(stderr, "areturn\n"); break; case arraylength: fprintf(stderr, "arraylength\n"); break; case astore: fprintf(stderr, "astore %02x\n", code[ip++]); break; case astore_0: fprintf(stderr, "astore_0\n"); break; case astore_1: fprintf(stderr, "astore_1\n"); break; case astore_2: fprintf(stderr, "astore_2\n"); break; case astore_3: fprintf(stderr, "astore_3\n"); break; case athrow: fprintf(stderr, "athrow\n"); break; case baload: fprintf(stderr, "baload\n"); break; case bastore: fprintf(stderr, "bastore\n"); break; case bipush: fprintf(stderr, "bipush %02x\n", code[ip++]); break; case caload: fprintf(stderr, "caload\n"); break; case castore: fprintf(stderr, "castore\n"); break; case checkcast: fprintf(stderr, "checkcast %04x\n", read16(code, ip)); break; case d2f: fprintf(stderr, "d2f\n"); break; case d2i: fprintf(stderr, "d2i\n"); break; case d2l: fprintf(stderr, "d2l\n"); break; case dadd: fprintf(stderr, "dadd\n"); break; case daload: fprintf(stderr, "daload\n"); break; case dastore: fprintf(stderr, "dastore\n"); break; case dcmpg: fprintf(stderr, "dcmpg\n"); break; case dcmpl: fprintf(stderr, "dcmpl\n"); break; case dconst_0: fprintf(stderr, "dconst_0\n"); break; case dconst_1: fprintf(stderr, "dconst_1\n"); break; case ddiv: fprintf(stderr, "ddiv\n"); break; case dmul: fprintf(stderr, "dmul\n"); break; case dneg: fprintf(stderr, "dneg\n"); break; case vm::drem: fprintf(stderr, "drem\n"); break; case dsub: fprintf(stderr, "dsub\n"); break; case dup: fprintf(stderr, "dup\n"); break; case dup_x1: fprintf(stderr, "dup_x1\n"); break; case dup_x2: fprintf(stderr, "dup_x2\n"); break; case dup2: fprintf(stderr, "dup2\n"); break; case dup2_x1: fprintf(stderr, "dup2_x1\n"); break; case dup2_x2: fprintf(stderr, "dup2_x2\n"); break; case f2d: fprintf(stderr, "f2d\n"); break; case f2i: fprintf(stderr, "f2i\n"); break; case f2l: fprintf(stderr, "f2l\n"); break; case fadd: fprintf(stderr, "fadd\n"); break; case faload: fprintf(stderr, "faload\n"); break; case fastore: fprintf(stderr, "fastore\n"); break; case fcmpg: fprintf(stderr, "fcmpg\n"); break; case fcmpl: fprintf(stderr, "fcmpl\n"); break; case fconst_0: fprintf(stderr, "fconst_0\n"); break; case fconst_1: fprintf(stderr, "fconst_1\n"); break; case fconst_2: fprintf(stderr, "fconst_2\n"); break; case fdiv: fprintf(stderr, "fdiv\n"); break; case fmul: fprintf(stderr, "fmul\n"); break; case fneg: fprintf(stderr, "fneg\n"); break; case frem: fprintf(stderr, "frem\n"); break; case fsub: fprintf(stderr, "fsub\n"); break; case getfield: fprintf(stderr, "getfield %04x\n", read16(code, ip)); break; case getstatic: fprintf(stderr, "getstatic %04x\n", read16(code, ip)); break; case goto_: { int16_t offset = read16(code, ip); fprintf(stderr, "goto %04x\n", offset + ip - 3); } break; case goto_w: { int32_t offset = read32(code, ip); fprintf(stderr, "goto_w %08x\n", offset + ip - 5); } break; case i2b: fprintf(stderr, "i2b\n"); break; case i2c: fprintf(stderr, "i2c\n"); break; case i2d: fprintf(stderr, "i2d\n"); break; case i2f: fprintf(stderr, "i2f\n"); break; case i2l: fprintf(stderr, "i2l\n"); break; case i2s: fprintf(stderr, "i2s\n"); break; case iadd: fprintf(stderr, "iadd\n"); break; case iaload: fprintf(stderr, "iaload\n"); break; case iand: fprintf(stderr, "iand\n"); break; case iastore: fprintf(stderr, "iastore\n"); break; case iconst_m1: fprintf(stderr, "iconst_m1\n"); break; case iconst_0: fprintf(stderr, "iconst_0\n"); break; case iconst_1: fprintf(stderr, "iconst_1\n"); break; case iconst_2: fprintf(stderr, "iconst_2\n"); break; case iconst_3: fprintf(stderr, "iconst_3\n"); break; case iconst_4: fprintf(stderr, "iconst_4\n"); break; case iconst_5: fprintf(stderr, "iconst_5\n"); break; case idiv: fprintf(stderr, "idiv\n"); break; case if_acmpeq: { int16_t offset = read16(code, ip); fprintf(stderr, "if_acmpeq %04x\n", offset + ip - 3); } break; case if_acmpne: { int16_t offset = read16(code, ip); fprintf(stderr, "if_acmpne %04x\n", offset + ip - 3); } break; case if_icmpeq: { int16_t offset = read16(code, ip); fprintf(stderr, "if_icmpeq %04x\n", offset + ip - 3); } break; case if_icmpne: { int16_t offset = read16(code, ip); fprintf(stderr, "if_icmpne %04x\n", offset + ip - 3); } break; case if_icmpgt: { int16_t offset = read16(code, ip); fprintf(stderr, "if_icmpgt %04x\n", offset + ip - 3); } break; case if_icmpge: { int16_t offset = read16(code, ip); fprintf(stderr, "if_icmpge %04x\n", offset + ip - 3); } break; case if_icmplt: { int16_t offset = read16(code, ip); fprintf(stderr, "if_icmplt %04x\n", offset + ip - 3); } break; case if_icmple: { int16_t offset = read16(code, ip); fprintf(stderr, "if_icmple %04x\n", offset + ip - 3); } break; case ifeq: { int16_t offset = read16(code, ip); fprintf(stderr, "ifeq %04x\n", offset + ip - 3); } break; case ifne: { int16_t offset = read16(code, ip); fprintf(stderr, "ifne %04x\n", offset + ip - 3); } break; case ifgt: { int16_t offset = read16(code, ip); fprintf(stderr, "ifgt %04x\n", offset + ip - 3); } break; case ifge: { int16_t offset = read16(code, ip); fprintf(stderr, "ifge %04x\n", offset + ip - 3); } break; case iflt: { int16_t offset = read16(code, ip); fprintf(stderr, "iflt %04x\n", offset + ip - 3); } break; case ifle: { int16_t offset = read16(code, ip); fprintf(stderr, "ifle %04x\n", offset + ip - 3); } break; case ifnonnull: { int16_t offset = read16(code, ip); fprintf(stderr, "ifnonnull %04x\n", offset + ip - 3); } break; case ifnull: { int16_t offset = read16(code, ip); fprintf(stderr, "ifnull %04x\n", offset + ip - 3); } break; case iinc: { uint8_t a = code[ip++]; uint8_t b = code[ip++]; fprintf(stderr, "iinc %02x %02x\n", a, b); } break; case iload: fprintf(stderr, "iload %02x\n", code[ip++]); break; case fload: fprintf(stderr, "fload %02x\n", code[ip++]); break; case iload_0: fprintf(stderr, "iload_0\n"); break; case fload_0: fprintf(stderr, "fload_0\n"); break; case iload_1: fprintf(stderr, "iload_1\n"); break; case fload_1: fprintf(stderr, "fload_1\n"); break; case iload_2: fprintf(stderr, "iload_2\n"); break; case fload_2: fprintf(stderr, "fload_2\n"); break; case iload_3: fprintf(stderr, "iload_3\n"); break; case fload_3: fprintf(stderr, "fload_3\n"); break; case imul: fprintf(stderr, "imul\n"); break; case ineg: fprintf(stderr, "ineg\n"); break; case instanceof: fprintf(stderr, "instanceof %04x\n", read16(code, ip)); break; case invokeinterface: fprintf(stderr, "invokeinterface %04x\n", read16(code, ip)); break; case invokespecial: fprintf(stderr, "invokespecial %04x\n", read16(code, ip)); break; case invokestatic: fprintf(stderr, "invokestatic %04x\n", read16(code, ip)); break; case invokevirtual: fprintf(stderr, "invokevirtual %04x\n", read16(code, ip)); break; case ior: fprintf(stderr, "ior\n"); break; case irem: fprintf(stderr, "irem\n"); break; case ireturn: fprintf(stderr, "ireturn\n"); break; case freturn: fprintf(stderr, "freturn\n"); break; case ishl: fprintf(stderr, "ishl\n"); break; case ishr: fprintf(stderr, "ishr\n"); break; case istore: fprintf(stderr, "istore %02x\n", code[ip++]); break; case fstore: fprintf(stderr, "fstore %02x\n", code[ip++]); break; case istore_0: fprintf(stderr, "istore_0\n"); break; case fstore_0: fprintf(stderr, "fstore_0\n"); break; case istore_1: fprintf(stderr, "istore_1\n"); break; case fstore_1: fprintf(stderr, "fstore_1\n"); break; case istore_2: fprintf(stderr, "istore_2\n"); break; case fstore_2: fprintf(stderr, "fstore_2\n"); break; case istore_3: fprintf(stderr, "istore_3\n"); break; case fstore_3: fprintf(stderr, "fstore_3\n"); break; case isub: fprintf(stderr, "isub\n"); break; case iushr: fprintf(stderr, "iushr\n"); break; case ixor: fprintf(stderr, "ixor\n"); break; case jsr: fprintf(stderr, "jsr %04x\n", read16(code, ip)); break; case jsr_w: fprintf(stderr, "jsr_w %08x\n", read32(code, ip)); break; case l2d: fprintf(stderr, "l2d\n"); break; case l2f: fprintf(stderr, "l2f\n"); break; case l2i: fprintf(stderr, "l2i\n"); break; case ladd: fprintf(stderr, "ladd\n"); break; case laload: fprintf(stderr, "laload\n"); break; case land: fprintf(stderr, "land\n"); break; case lastore: fprintf(stderr, "lastore\n"); break; case lcmp: fprintf(stderr, "lcmp\n"); break; case lconst_0: fprintf(stderr, "lconst_0\n"); break; case lconst_1: fprintf(stderr, "lconst_1\n"); break; case ldc: fprintf(stderr, "ldc %04x\n", read16(code, ip)); break; case ldc_w: fprintf(stderr, "ldc_w %08x\n", read32(code, ip)); break; case ldc2_w: fprintf(stderr, "ldc2_w %04x\n", read16(code, ip)); break; case ldiv_: fprintf(stderr, "ldiv_\n"); break; case lload: fprintf(stderr, "lload %02x\n", code[ip++]); break; case dload: fprintf(stderr, "dload %02x\n", code[ip++]); break; case lload_0: fprintf(stderr, "lload_0\n"); break; case dload_0: fprintf(stderr, "dload_0\n"); break; case lload_1: fprintf(stderr, "lload_1\n"); break; case dload_1: fprintf(stderr, "dload_1\n"); break; case lload_2: fprintf(stderr, "lload_2\n"); break; case dload_2: fprintf(stderr, "dload_2\n"); break; case lload_3: fprintf(stderr, "lload_3\n"); break; case dload_3: fprintf(stderr, "dload_3\n"); break; case lmul: fprintf(stderr, "lmul\n"); break; case lneg: fprintf(stderr, "lneg\n"); break; case lookupswitch: { int32_t default_ = read32(code, ip); int32_t pairCount = read32(code, ip); fprintf(stderr, "lookupswitch default: %d pairCount: %d\n", default_, pairCount); for (int i = 0; i < pairCount; i++) { int32_t k = read32(code, ip); int32_t d = read32(code, ip); fprintf(stderr, "%s key: %02x dest: %2x\n", prefix, k, d); } } break; case lor: fprintf(stderr, "lor\n"); break; case lrem: fprintf(stderr, "lrem\n"); break; case lreturn: fprintf(stderr, "lreturn\n"); break; case dreturn: fprintf(stderr, "dreturn\n"); break; case lshl: fprintf(stderr, "lshl\n"); break; case lshr: fprintf(stderr, "lshr\n"); break; case lstore: fprintf(stderr, "lstore %02x\n", code[ip++]); break; case dstore: fprintf(stderr, "dstore %02x\n", code[ip++]); break; case lstore_0: fprintf(stderr, "lstore_0\n"); break; case dstore_0: fprintf(stderr, "dstore_0\n"); break; case lstore_1: fprintf(stderr, "lstore_1\n"); break; case dstore_1: fprintf(stderr, "dstore_1\n"); break; case lstore_2: fprintf(stderr, "lstore_2\n"); break; case dstore_2: fprintf(stderr, "dstore_2\n"); break; case lstore_3: fprintf(stderr, "lstore_3\n"); break; case dstore_3: fprintf(stderr, "dstore_3\n"); break; case lsub: fprintf(stderr, "lsub\n"); break; case lushr: fprintf(stderr, "lushr\n"); break; case lxor: fprintf(stderr, "lxor\n"); break; case monitorenter: fprintf(stderr, "monitorenter\n"); break; case monitorexit: fprintf(stderr, "monitorexit\n"); break; case multianewarray: { unsigned type = read16(code, ip); fprintf(stderr, "multianewarray %04x %02x\n", type, code[ip++]); } break; case new_: fprintf(stderr, "new %04x\n", read16(code, ip)); break; case newarray: fprintf(stderr, "newarray %02x\n", code[ip++]); break; case nop: fprintf(stderr, "nop\n"); break; case pop_: fprintf(stderr, "pop\n"); break; case pop2: fprintf(stderr, "pop2\n"); break; case putfield: fprintf(stderr, "putfield %04x\n", read16(code, ip)); break; case putstatic: fprintf(stderr, "putstatic %04x\n", read16(code, ip)); break; case ret: fprintf(stderr, "ret %02x\n", code[ip++]); break; case return_: fprintf(stderr, "return_\n"); break; case saload: fprintf(stderr, "saload\n"); break; case sastore: fprintf(stderr, "sastore\n"); break; case sipush: fprintf(stderr, "sipush %04x\n", read16(code, ip)); break; case swap: fprintf(stderr, "swap\n"); break; case tableswitch: { int32_t default_ = read32(code, ip); int32_t bottom = read32(code, ip); int32_t top = read32(code, ip); fprintf(stderr, "tableswitch default: %d bottom: %d top: %d\n", default_, bottom, top); for (int i = 0; i < top - bottom + 1; i++) { int32_t d = read32(code, ip); fprintf(stderr, "%s key: %d dest: %2x\n", prefix, i + bottom, d); } } break; case wide: { switch (code[ip++]) { case aload: fprintf(stderr, "wide aload %04x\n", read16(code, ip)); break; case astore: fprintf(stderr, "wide astore %04x\n", read16(code, ip)); break; case iinc: fprintf(stderr, "wide iinc %04x %04x\n", read16(code, ip), read16(code, ip)); break; case iload: fprintf(stderr, "wide iload %04x\n", read16(code, ip)); break; case istore: fprintf(stderr, "wide istore %04x\n", read16(code, ip)); break; case lload: fprintf(stderr, "wide lload %04x\n", read16(code, ip)); break; case lstore: fprintf(stderr, "wide lstore %04x\n", read16(code, ip)); break; case ret: fprintf(stderr, "wide ret %04x\n", read16(code, ip)); break; default: { fprintf(stderr, "unknown wide instruction %02x %04x\n", instr, read16(code, ip)); } } } break; default: { fprintf(stderr, "unknown instruction %02x\n", instr); } } } } object parseCode(Thread* t, Stream& s, object pool) { PROTECT(t, pool); unsigned maxStack = s.read2(); unsigned maxLocals = s.read2(); unsigned length = s.read4(); if(DebugClassReader) { fprintf(stderr, " code: maxStack %d maxLocals %d length %d\n", maxStack, maxLocals, length); } object code = makeCode(t, pool, 0, 0, 0, 0, maxStack, maxLocals, length); s.read(&codeBody(t, code, 0), length); PROTECT(t, code); if(DebugClassReader) { disassembleCode(" ", &codeBody(t, code, 0), length); } unsigned ehtLength = s.read2(); if (ehtLength) { object eht = makeExceptionHandlerTable(t, ehtLength); for (unsigned i = 0; i < ehtLength; ++i) { unsigned start = s.read2(); unsigned end = s.read2(); unsigned ip = s.read2(); unsigned catchType = s.read2(); exceptionHandlerTableBody(t, eht, i) = exceptionHandler (start, end, ip, catchType); } set(t, code, CodeExceptionHandlerTable, eht); } unsigned attributeCount = s.read2(); for (unsigned j = 0; j < attributeCount; ++j) { object name = singletonObject(t, pool, s.read2() - 1); unsigned length = s.read4(); if (vm::strcmp(reinterpret_cast("LineNumberTable"), &byteArrayBody(t, name, 0)) == 0) { unsigned lntLength = s.read2(); object lnt = makeLineNumberTable(t, lntLength); for (unsigned i = 0; i < lntLength; ++i) { unsigned ip = s.read2(); unsigned line = s.read2(); lineNumberTableBody(t, lnt, i) = lineNumber(ip, line); } set(t, code, CodeLineNumberTable, lnt); } else { s.skip(length); } } return code; } object addInterfaceMethods(Thread* t, object class_, object virtualMap, unsigned* virtualCount, bool makeList) { object itable = classInterfaceTable(t, class_); if (itable) { PROTECT(t, class_); PROTECT(t, virtualMap); PROTECT(t, itable); object list = 0; PROTECT(t, list); object method = 0; PROTECT(t, method); object vtable = 0; PROTECT(t, vtable); unsigned stride = (classFlags(t, class_) & ACC_INTERFACE) ? 1 : 2; for (unsigned i = 0; i < arrayLength(t, itable); i += stride) { vtable = classVirtualTable(t, arrayBody(t, itable, i)); if (vtable) { for (unsigned j = 0; j < arrayLength(t, vtable); ++j) { method = arrayBody(t, vtable, j); object n = hashMapFindNode (t, virtualMap, method, methodHash, methodEqual); if (n == 0) { method = makeMethod (t, methodVmFlags(t, method), methodReturnCode(t, method), methodParameterCount(t, method), methodParameterFootprint(t, method), methodFlags(t, method), (*virtualCount)++, 0, 0, methodName(t, method), methodSpec(t, method), 0, class_, 0); hashMapInsert(t, virtualMap, method, method, methodHash); if (makeList) { if (list == 0) { list = vm::makeList(t, 0, 0, 0); } listAppend(t, list, method); } } } } } return list; } return 0; } void parseMethodTable(Thread* t, Stream& s, object class_, object pool) { PROTECT(t, class_); PROTECT(t, pool); object virtualMap = makeHashMap(t, 0, 0); PROTECT(t, virtualMap); unsigned virtualCount = 0; unsigned declaredVirtualCount = 0; object superVirtualTable = 0; PROTECT(t, superVirtualTable); if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { if (classSuper(t, class_)) { superVirtualTable = classVirtualTable(t, classSuper(t, class_)); } if (superVirtualTable) { virtualCount = arrayLength(t, superVirtualTable); for (unsigned i = 0; i < virtualCount; ++i) { object method = arrayBody(t, superVirtualTable, i); hashMapInsert(t, virtualMap, method, method, methodHash); } } } object newVirtuals = makeList(t, 0, 0, 0); PROTECT(t, newVirtuals); unsigned count = s.read2(); if(DebugClassReader) { fprintf(stderr, " method count %d\n", count); } if (count) { object methodTable = makeArray(t, count); PROTECT(t, methodTable); object addendum = 0; PROTECT(t, addendum); object code = 0; PROTECT(t, code); for (unsigned i = 0; i < count; ++i) { unsigned flags = s.read2(); unsigned name = s.read2(); unsigned spec = s.read2(); if(DebugClassReader) { fprintf(stderr, " method flags %d name %d spec %d '%s%s'\n", flags, name, spec, &byteArrayBody(t, singletonObject(t, pool, name - 1), 0), &byteArrayBody(t, singletonObject(t, pool, spec - 1), 0)); } addendum = 0; code = 0; unsigned attributeCount = s.read2(); for (unsigned j = 0; j < attributeCount; ++j) { object attributeName = singletonObject(t, pool, s.read2() - 1); unsigned length = s.read4(); if (vm::strcmp(reinterpret_cast("Code"), &byteArrayBody(t, attributeName, 0)) == 0) { code = parseCode(t, s, pool); } else if (vm::strcmp(reinterpret_cast("Exceptions"), &byteArrayBody(t, attributeName, 0)) == 0) { if (addendum == 0) { addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0, 0); } unsigned exceptionCount = s.read2(); object body = makeShortArray(t, exceptionCount); for (unsigned i = 0; i < exceptionCount; ++i) { shortArrayBody(t, body, i) = s.read2(); } set(t, addendum, MethodAddendumExceptionTable, body); } else if (vm::strcmp(reinterpret_cast ("AnnotationDefault"), &byteArrayBody(t, attributeName, 0)) == 0) { if (addendum == 0) { addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0, 0); } object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); set(t, addendum, MethodAddendumAnnotationDefault, body); } else if (vm::strcmp(reinterpret_cast("Signature"), &byteArrayBody(t, attributeName, 0)) == 0) { if (addendum == 0) { addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0, 0); } set(t, addendum, AddendumSignature, singletonObject(t, pool, s.read2() - 1)); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleAnnotations"), &byteArrayBody(t, attributeName, 0)) == 0) { if (addendum == 0) { addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0, 0); } object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); set(t, addendum, AddendumAnnotationTable, body); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleParameterAnnotations"), &byteArrayBody(t, attributeName, 0)) == 0) { if (addendum == 0) { addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0, 0); } object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); set(t, addendum, MethodAddendumParameterAnnotationTable, body); } else { s.skip(length); } } const char* specString = reinterpret_cast (&byteArrayBody(t, singletonObject(t, pool, spec - 1), 0)); unsigned parameterCount; unsigned returnCode; scanMethodSpec(t, specString, ¶meterCount, &returnCode); object method = t->m->processor->makeMethod (t, 0, // vm flags returnCode, parameterCount, parameterFootprint(t, specString, flags & ACC_STATIC), flags, 0, // offset singletonObject(t, pool, name - 1), singletonObject(t, pool, spec - 1), addendum, class_, code); PROTECT(t, method); if (methodVirtual(t, method)) { ++ declaredVirtualCount; object p = hashMapFindNode (t, virtualMap, method, methodHash, methodEqual); if (p) { methodOffset(t, method) = methodOffset(t, tripleFirst(t, p)); set(t, p, TripleSecond, method); } else { methodOffset(t, method) = virtualCount++; listAppend(t, newVirtuals, method); hashMapInsert(t, virtualMap, method, method, methodHash); } if (UNLIKELY((classFlags(t, class_) & ACC_INTERFACE) == 0 and vm::strcmp (reinterpret_cast("finalize"), &byteArrayBody(t, methodName(t, method), 0)) == 0 and vm::strcmp (reinterpret_cast("()V"), &byteArrayBody(t, methodSpec(t, method), 0)) == 0 and (not emptyMethod(t, method)))) { classVmFlags(t, class_) |= HasFinalizerFlag; } } else { methodOffset(t, method) = i; if (vm::strcmp(reinterpret_cast(""), &byteArrayBody(t, methodName(t, method), 0)) == 0) { methodVmFlags(t, method) |= ClassInitFlag; classVmFlags(t, class_) |= NeedInitFlag; } else if (vm::strcmp (reinterpret_cast(""), &byteArrayBody(t, methodName(t, method), 0)) == 0) { methodVmFlags(t, method) |= ConstructorFlag; } } set(t, methodTable, ArrayBody + (i * BytesPerWord), method); } set(t, class_, ClassMethodTable, methodTable); } object abstractVirtuals = addInterfaceMethods (t, class_, virtualMap, &virtualCount, true); PROTECT(t, abstractVirtuals); bool populateInterfaceVtables = false; if (declaredVirtualCount == 0 and abstractVirtuals == 0 and (classFlags(t, class_) & ACC_INTERFACE) == 0) { if (classSuper(t, class_)) { // inherit virtual table from superclass set(t, class_, ClassVirtualTable, superVirtualTable); if (classInterfaceTable(t, classSuper(t, class_)) and arrayLength(t, classInterfaceTable(t, class_)) == arrayLength (t, classInterfaceTable(t, classSuper(t, class_)))) { // inherit interface table from superclass set(t, class_, ClassInterfaceTable, classInterfaceTable(t, classSuper(t, class_))); } else { populateInterfaceVtables = true; } } else { // apparently, Object does not have any virtual methods. We // give it a vtable anyway so code doesn't break elsewhere. object vtable = makeArray(t, 0); set(t, class_, ClassVirtualTable, vtable); } } else if (virtualCount) { // generate class vtable object vtable = makeArray(t, virtualCount); unsigned i = 0; if (classFlags(t, class_) & ACC_INTERFACE) { PROTECT(t, vtable); for (HashMapIterator it(t, virtualMap); it.hasMore();) { object method = tripleFirst(t, it.next()); assert(t, arrayBody(t, vtable, methodOffset(t, method)) == 0); set(t, vtable, ArrayBody + (methodOffset(t, method) * BytesPerWord), method); ++ i; } } else { populateInterfaceVtables = true; if (superVirtualTable) { for (; i < arrayLength(t, superVirtualTable); ++i) { object method = arrayBody(t, superVirtualTable, i); method = hashMapFind(t, virtualMap, method, methodHash, methodEqual); set(t, vtable, ArrayBody + (i * BytesPerWord), method); } } for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) { set(t, vtable, ArrayBody + (i * BytesPerWord), pairFirst(t, p)); ++ i; } } if (abstractVirtuals) { PROTECT(t, vtable); object originalMethodTable = classMethodTable(t, class_); PROTECT(t, originalMethodTable); unsigned oldLength = classMethodTable(t, class_) ? arrayLength(t, classMethodTable(t, class_)) : 0; object addendum = getClassAddendum(t, class_, pool); classAddendumDeclaredMethodCount(t, addendum) = oldLength; object newMethodTable = makeArray (t, oldLength + listSize(t, abstractVirtuals)); if (oldLength) { memcpy(&arrayBody(t, newMethodTable, 0), &arrayBody(t, classMethodTable(t, class_), 0), oldLength * sizeof(object)); } mark(t, newMethodTable, ArrayBody, oldLength); unsigned mti = oldLength; for (object p = listFront(t, abstractVirtuals); p; p = pairSecond(t, p)) { set(t, newMethodTable, ArrayBody + ((mti++) * BytesPerWord), pairFirst(t, p)); if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { set(t, vtable, ArrayBody + ((i++) * BytesPerWord), pairFirst(t, p)); } } assert(t, arrayLength(t, newMethodTable) == mti); set(t, class_, ClassMethodTable, newMethodTable); } assert(t, arrayLength(t, vtable) == i); set(t, class_, ClassVirtualTable, vtable); } if (populateInterfaceVtables) { // generate interface vtables object itable = classInterfaceTable(t, class_); if (itable) { PROTECT(t, itable); for (unsigned i = 0; i < arrayLength(t, itable); i += 2) { object ivtable = classVirtualTable(t, arrayBody(t, itable, i)); if (ivtable) { object vtable = arrayBody(t, itable, i + 1); for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) { object method = arrayBody(t, ivtable, j); method = hashMapFind (t, virtualMap, method, methodHash, methodEqual); assert(t, method); set(t, vtable, ArrayBody + (j * BytesPerWord), method); } } } } } } void parseAttributeTable(Thread* t, Stream& s, object class_, object pool) { PROTECT(t, class_); PROTECT(t, pool); unsigned attributeCount = s.read2(); for (unsigned j = 0; j < attributeCount; ++j) { object name = singletonObject(t, pool, s.read2() - 1); unsigned length = s.read4(); if (vm::strcmp(reinterpret_cast("SourceFile"), &byteArrayBody(t, name, 0)) == 0) { set(t, class_, ClassSourceFile, singletonObject(t, pool, s.read2() - 1)); } else if (vm::strcmp(reinterpret_cast("Signature"), &byteArrayBody(t, name, 0)) == 0) { object addendum = getClassAddendum(t, class_, pool); set(t, addendum, AddendumSignature, singletonObject(t, pool, s.read2() - 1)); } else if (vm::strcmp(reinterpret_cast("InnerClasses"), &byteArrayBody(t, name, 0)) == 0) { unsigned innerClassCount = s.read2(); object table = makeArray(t, innerClassCount); PROTECT(t, table); for (unsigned i = 0; i < innerClassCount; ++i) { int16_t inner = s.read2(); int16_t outer = s.read2(); int16_t name = s.read2(); int16_t flags = s.read2(); object reference = makeInnerClassReference (t, inner ? referenceName(t, singletonObject(t, pool, inner - 1)) : 0, outer ? referenceName(t, singletonObject(t, pool, outer - 1)) : 0, name ? singletonObject(t, pool, name - 1) : 0, flags); set(t, table, ArrayBody + (i * BytesPerWord), reference); } object addendum = getClassAddendum(t, class_, pool); set(t, addendum, ClassAddendumInnerClassTable, table); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { object body = makeByteArray(t, length); PROTECT(t, body); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); object addendum = getClassAddendum(t, class_, pool); set(t, addendum, AddendumAnnotationTable, body); } else if (vm::strcmp(reinterpret_cast ("EnclosingMethod"), &byteArrayBody(t, name, 0)) == 0) { int16_t enclosingClass = s.read2(); int16_t enclosingMethod = s.read2(); object addendum = getClassAddendum(t, class_, pool); set(t, addendum, ClassAddendumEnclosingClass, referenceName(t, singletonObject(t, pool, enclosingClass - 1))); set(t, addendum, ClassAddendumEnclosingMethod, enclosingMethod ? singletonObject(t, pool, enclosingMethod - 1) : 0); } else { s.skip(length); } } } void updateClassTables(Thread* t, object newClass, object oldClass) { object fieldTable = classFieldTable(t, newClass); if (fieldTable) { for (unsigned i = 0; i < arrayLength(t, fieldTable); ++i) { set(t, arrayBody(t, fieldTable, i), FieldClass, newClass); } } object staticTable = classStaticTable(t, newClass); if (staticTable) { set(t, staticTable, SingletonBody, newClass); } if (classFlags(t, newClass) & ACC_INTERFACE) { object virtualTable = classVirtualTable(t, newClass); if (virtualTable) { for (unsigned i = 0; i < arrayLength(t, virtualTable); ++i) { if (methodClass(t, arrayBody(t, virtualTable, i)) == oldClass) { set(t, arrayBody(t, virtualTable, i), MethodClass, newClass); } } } } object methodTable = classMethodTable(t, newClass); if (methodTable) { for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) { set(t, arrayBody(t, methodTable, i), MethodClass, newClass); } } } void updateBootstrapClass(Thread* t, object bootstrapClass, object class_) { expect(t, bootstrapClass != class_); // verify that the classes have the same layout expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_)); expect(t, classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_)); expect(t, (classVmFlags(t, class_) & HasFinalizerFlag) == 0); PROTECT(t, bootstrapClass); PROTECT(t, class_); ENTER(t, Thread::ExclusiveState); classVmFlags(t, bootstrapClass) &= ~BootstrapFlag; classVmFlags(t, bootstrapClass) |= classVmFlags(t, class_); classFlags(t, bootstrapClass) |= classFlags(t, class_); set(t, bootstrapClass, ClassSuper, classSuper(t, class_)); set(t, bootstrapClass, ClassInterfaceTable, classInterfaceTable(t, class_)); set(t, bootstrapClass, ClassVirtualTable, classVirtualTable(t, class_)); set(t, bootstrapClass, ClassFieldTable, classFieldTable(t, class_)); set(t, bootstrapClass, ClassMethodTable, classMethodTable(t, class_)); set(t, bootstrapClass, ClassStaticTable, classStaticTable(t, class_)); set(t, bootstrapClass, ClassAddendum, classAddendum(t, class_)); updateClassTables(t, bootstrapClass, class_); } object makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, object elementClass) { if (classVmFlags(t, type(t, Machine::JobjectType)) & BootstrapFlag) { PROTECT(t, loader); PROTECT(t, spec); PROTECT(t, elementClass); // Load java.lang.Object if present so we can use its vtable, but // don't throw an exception if we can't find it. This way, we // avoid infinite recursion due to trying to create an array to // make a stack trace for a ClassNotFoundException. resolveSystemClass (t, root(t, Machine::BootLoader), className(t, type(t, Machine::JobjectType)), false); } object vtable = classVirtualTable(t, type(t, Machine::JobjectType)); object c = t->m->processor->makeClass (t, 0, 0, 2 * BytesPerWord, BytesPerWord, dimensions, classObjectMask(t, type(t, Machine::ArrayType)), spec, 0, type(t, Machine::JobjectType), root(t, Machine::ArrayInterfaceTable), vtable, 0, 0, 0, elementClass, loader, arrayLength(t, vtable)); PROTECT(t, c); t->m->processor->initVtable(t, c); return c; } void saveLoadedClass(Thread* t, object loader, object c) { PROTECT(t, loader); PROTECT(t, c); ACQUIRE(t, t->m->classLock); if (classLoaderMap(t, loader) == 0) { object map = makeHashMap(t, 0, 0); set(t, loader, ClassLoaderMap, map); } hashMapInsert (t, classLoaderMap(t, loader), className(t, c), c, byteArrayHash); } object makeArrayClass(Thread* t, object loader, object spec, bool throw_, Machine::Type throwType) { PROTECT(t, loader); PROTECT(t, spec); const char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); const char* start = s; unsigned dimensions = 0; for (; *s == '['; ++s) ++ dimensions; object elementSpec; switch (*s) { case 'L': { ++ s; const char* elementSpecStart = s; while (*s and *s != ';') ++ s; if (dimensions > 1) { elementSpecStart -= dimensions; ++ s; } elementSpec = makeByteArray(t, s - elementSpecStart + 1); memcpy(&byteArrayBody(t, elementSpec, 0), &byteArrayBody(t, spec, elementSpecStart - start), s - elementSpecStart); byteArrayBody(t, elementSpec, s - elementSpecStart) = 0; } break; default: if (dimensions > 1) { char c = *s; elementSpec = makeByteArray(t, dimensions + 1); unsigned i; for (i = 0; i < dimensions - 1; ++i) { byteArrayBody(t, elementSpec, i) = '['; } byteArrayBody(t, elementSpec, i++) = c; byteArrayBody(t, elementSpec, i) = 0; -- dimensions; } else { abort(t); } } object elementClass = hashMapFind (t, root(t, Machine::BootstrapClassMap), elementSpec, byteArrayHash, byteArrayEqual); if (elementClass == 0) { elementClass = resolveClass(t, loader, elementSpec, throw_, throwType); if (elementClass == 0) return 0; } PROTECT(t, elementClass); ACQUIRE(t, t->m->classLock); object class_ = findLoadedClass(t, classLoader(t, elementClass), spec); if (class_) { return class_; } class_ = makeArrayClass (t, classLoader(t, elementClass), dimensions, spec, elementClass); PROTECT(t, class_); saveLoadedClass(t, classLoader(t, elementClass), class_); return class_; } object resolveArrayClass(Thread* t, object loader, object spec, bool throw_, Machine::Type throwType) { object c = hashMapFind (t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash, byteArrayEqual); if (c) { set(t, c, ClassVirtualTable, classVirtualTable(t, type(t, Machine::JobjectType))); return c; } else { PROTECT(t, loader); PROTECT(t, spec); c = findLoadedClass(t, root(t, Machine::BootLoader), spec); if (c) { return c; } else { return makeArrayClass(t, loader, spec, throw_, throwType); } } } void removeMonitor(Thread* t, object o) { unsigned hash; if (DebugMonitors) { hash = objectHash(t, o); } object m = hashMapRemove (t, root(t, Machine::MonitorMap), o, objectHash, objectEqual); if (DebugMonitors) { fprintf(stderr, "dispose monitor %p for object %x\n", m, hash); } } void removeString(Thread* t, object o) { hashMapRemove(t, root(t, Machine::StringMap), o, stringHash, objectEqual); } void bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask, unsigned fixedSize, unsigned arrayElementSize, unsigned vtableLength) { object super = (superType >= 0 ? vm::type(t, static_cast(superType)) : 0); object mask; if (objectMask) { if (super and classObjectMask(t, super) and intArrayBody(t, classObjectMask(t, super), 0) == static_cast(objectMask)) { mask = classObjectMask (t, vm::type(t, static_cast(superType))); } else { mask = makeIntArray(t, 1); intArrayBody(t, mask, 0) = objectMask; } } else { mask = 0; } super = (superType >= 0 ? vm::type(t, static_cast(superType)) : 0); object class_ = t->m->processor->makeClass (t, 0, BootstrapFlag, fixedSize, arrayElementSize, arrayElementSize ? 1 : 0, mask, 0, 0, super, 0, 0, 0, 0, 0, 0, root(t, Machine::BootLoader), vtableLength); setType(t, type, class_); } void bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name, int vtableLength, object bootMethod) { PROTECT(t, bootMethod); object n = makeByteArray(t, name); PROTECT(t, n); object class_ = vm::type(t, type); PROTECT(t, class_); set(t, class_, ClassName, n); object vtable; if (vtableLength >= 0) { vtable = makeArray(t, vtableLength); for (int i = 0; i < vtableLength; ++ i) { arrayBody(t, vtable, i) = bootMethod; } } else { vtable = classVirtualTable (t, vm::type(t, static_cast(superType))); } set(t, class_, ClassVirtualTable, vtable); t->m->processor->initVtable(t, class_); hashMapInsert (t, root(t, Machine::BootstrapClassMap), n, class_, byteArrayHash); } void nameClass(Thread* t, Machine::Type type, const char* name) { object n = makeByteArray(t, name); set(t, arrayBody(t, t->m->types, type), ClassName, n); } void makeArrayInterfaceTable(Thread* t) { object interfaceTable = makeArray(t, 4); set(t, interfaceTable, ArrayBody, type (t, Machine::SerializableType)); set(t, interfaceTable, ArrayBody + (2 * BytesPerWord), type(t, Machine::CloneableType)); setRoot(t, Machine::ArrayInterfaceTable, interfaceTable); } void boot(Thread* t) { Machine* m = t->m; m->unsafe = true; m->roots = allocate(t, pad((Machine::RootCount + 2) * BytesPerWord), true); arrayLength(t, m->roots) = Machine::RootCount; setRoot(t, Machine::BootLoader, allocate(t, FixedSizeOfSystemClassLoader, true)); setRoot(t, Machine::AppLoader, allocate(t, FixedSizeOfSystemClassLoader, true)); m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true); arrayLength(t, m->types) = TypeCount; #include "type-initializations.cpp" object arrayClass = type(t, Machine::ArrayType); set(t, m->types, 0, arrayClass); set(t, m->roots, 0, arrayClass); object loaderClass = type(t, Machine::SystemClassLoaderType); set(t, root(t, Machine::BootLoader), 0, loaderClass); set(t, root(t, Machine::AppLoader), 0, loaderClass); object objectClass = type(t, Machine::JobjectType); object classClass = type(t, Machine::ClassType); set(t, classClass, 0, classClass); set(t, classClass, ClassSuper, objectClass); object intArrayClass = type(t, Machine::IntArrayType); set(t, intArrayClass, 0, classClass); set(t, intArrayClass, ClassSuper, objectClass); m->unsafe = false; classVmFlags(t, type(t, Machine::SingletonType)) |= SingletonFlag; classVmFlags(t, type(t, Machine::ContinuationType)) |= ContinuationFlag; classVmFlags(t, type(t, Machine::JreferenceType)) |= ReferenceFlag; classVmFlags(t, type(t, Machine::WeakReferenceType)) |= ReferenceFlag | WeakReferenceFlag; classVmFlags(t, type(t, Machine::SoftReferenceType)) |= ReferenceFlag | WeakReferenceFlag; classVmFlags(t, type(t, Machine::PhantomReferenceType)) |= ReferenceFlag | WeakReferenceFlag; classVmFlags(t, type(t, Machine::JbooleanType)) |= PrimitiveFlag; classVmFlags(t, type(t, Machine::JbyteType)) |= PrimitiveFlag; classVmFlags(t, type(t, Machine::JcharType)) |= PrimitiveFlag; classVmFlags(t, type(t, Machine::JshortType)) |= PrimitiveFlag; classVmFlags(t, type(t, Machine::JintType)) |= PrimitiveFlag; classVmFlags(t, type(t, Machine::JlongType)) |= PrimitiveFlag; classVmFlags(t, type(t, Machine::JfloatType)) |= PrimitiveFlag; classVmFlags(t, type(t, Machine::JdoubleType)) |= PrimitiveFlag; classVmFlags(t, type(t, Machine::JvoidType)) |= PrimitiveFlag; set(t, type(t, Machine::BooleanArrayType), ClassStaticTable, type(t, Machine::JbooleanType)); set(t, type(t, Machine::ByteArrayType), ClassStaticTable, type(t, Machine::JbyteType)); set(t, type(t, Machine::CharArrayType), ClassStaticTable, type(t, Machine::JcharType)); set(t, type(t, Machine::ShortArrayType), ClassStaticTable, type(t, Machine::JshortType)); set(t, type(t, Machine::IntArrayType), ClassStaticTable, type(t, Machine::JintType)); set(t, type(t, Machine::LongArrayType), ClassStaticTable, type(t, Machine::JlongType)); set(t, type(t, Machine::FloatArrayType), ClassStaticTable, type(t, Machine::JfloatType)); set(t, type(t, Machine::DoubleArrayType), ClassStaticTable, type(t, Machine::JdoubleType)); { object map = makeHashMap(t, 0, 0); set(t, root(t, Machine::BootLoader), ClassLoaderMap, map); } systemClassLoaderFinder(t, root(t, Machine::BootLoader)) = m->bootFinder; { object map = makeHashMap(t, 0, 0); set(t, root(t, Machine::AppLoader), ClassLoaderMap, map); } systemClassLoaderFinder(t, root(t, Machine::AppLoader)) = m->appFinder; set(t, root(t, Machine::AppLoader), ClassLoaderParent, root(t, Machine::BootLoader)); setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0)); setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0)); makeArrayInterfaceTable(t); set(t, type(t, Machine::BooleanArrayType), ClassInterfaceTable, root(t, Machine::ArrayInterfaceTable)); set(t, type(t, Machine::ByteArrayType), ClassInterfaceTable, root(t, Machine::ArrayInterfaceTable)); set(t, type(t, Machine::CharArrayType), ClassInterfaceTable, root(t, Machine::ArrayInterfaceTable)); set(t, type(t, Machine::ShortArrayType), ClassInterfaceTable, root(t, Machine::ArrayInterfaceTable)); set(t, type(t, Machine::IntArrayType), ClassInterfaceTable, root(t, Machine::ArrayInterfaceTable)); set(t, type(t, Machine::LongArrayType), ClassInterfaceTable, root(t, Machine::ArrayInterfaceTable)); set(t, type(t, Machine::FloatArrayType), ClassInterfaceTable, root(t, Machine::ArrayInterfaceTable)); set(t, type(t, Machine::DoubleArrayType), ClassInterfaceTable, root(t, Machine::ArrayInterfaceTable)); m->processor->boot(t, 0, 0); { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 0, 1); codeBody(t, bootCode, 0) = impdep1; object bootMethod = makeMethod (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); PROTECT(t, bootMethod); #include "type-java-initializations.cpp" //#ifdef AVIAN_HEAPDUMP # include "type-name-initializations.cpp" //#endif } } class HeapClient: public Heap::Client { public: HeapClient(Machine* m): m(m) { } virtual void visitRoots(Heap::Visitor* v) { ::visitRoots(m, v); postVisit(m->rootThread, v); } virtual void collect(void* context, Heap::CollectionType type) { collect(static_cast(context), type); } virtual bool isFixed(void* p) { return objectFixed(m->rootThread, static_cast(p)); } virtual unsigned sizeInWords(void* p) { Thread* t = m->rootThread; object o = static_cast(m->heap->follow(maskAlignedPointer(p))); unsigned n = baseSize(t, o, static_cast (m->heap->follow(objectClass(t, o)))); if (objectExtended(t, o)) { ++ n; } return n; } virtual unsigned copiedSizeInWords(void* p) { Thread* t = m->rootThread; object o = static_cast(m->heap->follow(maskAlignedPointer(p))); assert(t, not objectFixed(t, o)); unsigned n = baseSize(t, o, static_cast (m->heap->follow(objectClass(t, o)))); if (objectExtended(t, o) or hashTaken(t, o)) { ++ n; } return n; } virtual void copy(void* srcp, void* dstp) { Thread* t = m->rootThread; object src = static_cast(m->heap->follow(maskAlignedPointer(srcp))); assert(t, not objectFixed(t, src)); object class_ = static_cast (m->heap->follow(objectClass(t, src))); unsigned base = baseSize(t, src, class_); unsigned n = extendedSize(t, src, base); object dst = static_cast(dstp); memcpy(dst, src, n * BytesPerWord); if (hashTaken(t, src)) { alias(dst, 0) &= PointerMask; alias(dst, 0) |= ExtendedMark; extendedWord(t, dst, base) = takeHash(t, src); } } virtual void walk(void* p, Heap::Walker* w) { object o = static_cast(m->heap->follow(maskAlignedPointer(p))); ::walk(m->rootThread, w, o, 0); } void dispose() { m->heap->free(this, sizeof(*this)); } private: Machine* m; }; void doCollect(Thread* t, Heap::CollectionType type, int pendingAllocation) { expect(t, not t->m->collecting); t->m->collecting = true; THREAD_RESOURCE0(t, t->m->collecting = false); #ifdef VM_STRESS bool stress = (t->flags & Thread::StressFlag) != 0; if (not stress) atomicOr(&(t->flags), Thread::StressFlag); #endif Machine* m = t->m; m->unsafe = true; m->heap->collect(type, footprint(m->rootThread), pendingAllocation - (t->m->heapPoolIndex * ThreadHeapSizeInWords)); m->unsafe = false; postCollect(m->rootThread); killZombies(t, m->rootThread); for (unsigned i = 0; i < m->heapPoolIndex; ++i) { m->heap->free(m->heapPool[i], ThreadHeapSizeInBytes); } m->heapPoolIndex = 0; if (m->heap->limitExceeded()) { // if we're out of memory, disallow further allocations of fixed // objects: m->fixedFootprint = FixedFootprintThresholdInBytes; } else { m->fixedFootprint = 0; } #ifdef VM_STRESS if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag); #endif object finalizeQueue = t->m->finalizeQueue; t->m->finalizeQueue = 0; for (; finalizeQueue; finalizeQueue = finalizerNext(t, finalizeQueue)) { void (*function)(Thread*, object); memcpy(&function, &finalizerFinalize(t, finalizeQueue), BytesPerWord); function(t, finalizerTarget(t, finalizeQueue)); } if ((root(t, Machine::ObjectsToFinalize) or root(t, Machine::ObjectsToClean)) and m->finalizeThread == 0 and t->state != Thread::ExitState) { m->finalizeThread = m->processor->makeThread (m, root(t, Machine::FinalizerThread), m->rootThread); addThread(t, m->finalizeThread); if (not startThread(t, m->finalizeThread)) { removeThread(t, m->finalizeThread); m->finalizeThread = 0; } } } uint64_t invokeLoadClass(Thread* t, uintptr_t* arguments) { object method = reinterpret_cast(arguments[0]); object loader = reinterpret_cast(arguments[1]); object specString = reinterpret_cast(arguments[2]); return reinterpret_cast (t->m->processor->invoke(t, method, loader, specString)); } bool isInitializing(Thread* t, object c) { for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) { if (s->class_ == c) { return true; } } return false; } object findInTable(Thread* t, object table, object name, object spec, object& (*getName)(Thread*, object), object& (*getSpec)(Thread*, object)) { if (table) { for (unsigned i = 0; i < arrayLength(t, table); ++i) { object o = arrayBody(t, table, i); if (vm::strcmp(&byteArrayBody(t, getName(t, o), 0), &byteArrayBody(t, name, 0)) == 0 and vm::strcmp(&byteArrayBody(t, getSpec(t, o), 0), &byteArrayBody(t, spec, 0)) == 0) { return o; } } // fprintf(stderr, "%s %s not in\n", // &byteArrayBody(t, name, 0), // &byteArrayBody(t, spec, 0)); // for (unsigned i = 0; i < arrayLength(t, table); ++i) { // object o = arrayBody(t, table, i); // fprintf(stderr, "\t%s %s\n", // &byteArrayBody(t, getName(t, o), 0), // &byteArrayBody(t, getSpec(t, o), 0)); // } } return 0; } void updatePackageMap(Thread* t, object class_) { PROTECT(t, class_); if (root(t, Machine::PackageMap) == 0) { setRoot(t, Machine::PackageMap, makeHashMap(t, 0, 0)); } object className = vm::className(t, class_); if ('[' != byteArrayBody(t, className, 0)) { THREAD_RUNTIME_ARRAY (t, char, packageName, byteArrayLength(t, className)); char* s = reinterpret_cast(&byteArrayBody(t, className, 0)); char* p = strrchr(s, '/'); if (p) { int length = (p - s) + 1; memcpy(RUNTIME_ARRAY_BODY(packageName), &byteArrayBody(t, className, 0), length); RUNTIME_ARRAY_BODY(packageName)[length] = 0; object key = vm::makeByteArray (t, "%s", RUNTIME_ARRAY_BODY(packageName)); PROTECT(t, key); hashMapRemove (t, root(t, Machine::PackageMap), key, byteArrayHash, byteArrayEqual); object source = classSource(t, class_); if (source) { // note that we strip the "file:" prefix, since OpenJDK's // Package.defineSystemPackage expects an unadorned filename: const unsigned PrefixLength = 5; unsigned sourceNameLength = byteArrayLength(t, source) - PrefixLength; THREAD_RUNTIME_ARRAY(t, char, sourceName, sourceNameLength); memcpy(RUNTIME_ARRAY_BODY(sourceName), &byteArrayBody(t, source, PrefixLength), sourceNameLength); source = vm::makeByteArray(t, "%s", RUNTIME_ARRAY_BODY(sourceName)); } else { source = vm::makeByteArray(t, "avian-dummy-package-source"); } hashMapInsert (t, root(t, Machine::PackageMap), key, source, byteArrayHash); } } } } // namespace namespace vm { Machine::Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder, Processor* processor, Classpath* classpath, const char** properties, unsigned propertyCount, const char** arguments, unsigned argumentCount, unsigned stackSizeInBytes): vtable(&javaVMVTable), system(system), heapClient(new (heap->allocate(sizeof(HeapClient))) HeapClient(this)), heap(heap), bootFinder(bootFinder), appFinder(appFinder), processor(processor), classpath(classpath), rootThread(0), exclusive(0), finalizeThread(0), jniReferences(0), properties(properties), propertyCount(propertyCount), arguments(arguments), argumentCount(argumentCount), threadCount(0), activeCount(0), liveCount(0), daemonCount(0), fixedFootprint(0), stackSizeInBytes(stackSizeInBytes), localThread(0), stateLock(0), heapLock(0), classLock(0), referenceLock(0), shutdownLock(0), libraries(0), errorLog(0), bootimage(0), types(0), roots(0), finalizers(0), tenuredFinalizers(0), finalizeQueue(0), weakReferences(0), tenuredWeakReferences(0), unsafe(false), collecting(false), triedBuiltinOnLoad(false), dumpedHeapOnOOM(false), alive(true), heapPoolIndex(0) { heap->setClient(heapClient); populateJNITables(&javaVMVTable, &jniEnvVTable); const char* bootstrapProperty = findProperty(this, BOOTSTRAP_PROPERTY); const char* bootstrapPropertyDup = bootstrapProperty ? strdup(bootstrapProperty) : 0; const char* bootstrapPropertyEnd = bootstrapPropertyDup + (bootstrapPropertyDup ? strlen(bootstrapPropertyDup) : 0); char* codeLibraryName = (char*)bootstrapPropertyDup; char* codeLibraryNameEnd = 0; if (codeLibraryName && (codeLibraryNameEnd = strchr(codeLibraryName, system->pathSeparator()))) *codeLibraryNameEnd = 0; if (not system->success(system->make(&localThread)) or not system->success(system->make(&stateLock)) or not system->success(system->make(&heapLock)) or not system->success(system->make(&classLock)) or not system->success(system->make(&referenceLock)) or not system->success(system->make(&shutdownLock)) or not system->success (system->load(&libraries, bootstrapPropertyDup))) { system->abort(); } System::Library* additionalLibrary = 0; while (codeLibraryNameEnd && codeLibraryNameEnd + 1 < bootstrapPropertyEnd) { codeLibraryName = codeLibraryNameEnd + 1; codeLibraryNameEnd = strchr(codeLibraryName, system->pathSeparator()); if (codeLibraryNameEnd) *codeLibraryNameEnd = 0; if (!system->success(system->load(&additionalLibrary, codeLibraryName))) system->abort(); libraries->setNext(additionalLibrary); } if(bootstrapPropertyDup) free((void*)bootstrapPropertyDup); } void Machine::dispose() { localThread->dispose(); stateLock->dispose(); heapLock->dispose(); classLock->dispose(); referenceLock->dispose(); shutdownLock->dispose(); if (libraries) { libraries->disposeAll(); } for (Reference* r = jniReferences; r;) { Reference* tmp = r; r = r->next; heap->free(tmp, sizeof(*tmp)); } for (unsigned i = 0; i < heapPoolIndex; ++i) { heap->free(heapPool[i], ThreadHeapSizeInBytes); } if (bootimage) { heap->free(bootimage, bootimageSize); } heap->free(arguments, sizeof(const char*) * argumentCount); heap->free(properties, sizeof(const char*) * propertyCount); static_cast(heapClient)->dispose(); heap->free(this, sizeof(*this)); } Thread::Thread(Machine* m, object javaThread, Thread* parent): vtable(&(m->jniEnvVTable)), m(m), parent(parent), peer(0), child(0), waitNext(0), state(NoState), criticalLevel(0), systemThread(0), lock(0), javaThread(javaThread), exception(0), heapIndex(0), heapOffset(0), protector(0), classInitStack(0), runnable(this), defaultHeap(static_cast (m->heap->allocate(ThreadHeapSizeInBytes))), heap(defaultHeap), backupHeapIndex(0), flags(ActiveFlag) { } void Thread::init() { memset(defaultHeap, 0, ThreadHeapSizeInBytes); memset(backupHeap, 0, ThreadBackupHeapSizeInBytes); if (parent == 0) { assert(this, m->rootThread == 0); assert(this, javaThread == 0); m->rootThread = this; m->unsafe = true; if (not m->system->success(m->system->attach(&runnable))) { abort(this); } BootImage* image = 0; uint8_t* code = 0; const char* imageFunctionName = findProperty(m, "avian.bootimage"); if (imageFunctionName) { bool lzma = strncmp("lzma:", imageFunctionName, 5) == 0; const char* symbolName = lzma ? imageFunctionName + 5 : imageFunctionName; void* imagep = m->libraries->resolve(symbolName); if (imagep) { uint8_t* (*imageFunction)(unsigned*); memcpy(&imageFunction, &imagep, BytesPerWord); unsigned size; uint8_t* imageBytes = imageFunction(&size); if (lzma) { #ifdef AVIAN_USE_LZMA m->bootimage = image = reinterpret_cast (decodeLZMA (m->system, m->heap, imageBytes, size, &(m->bootimageSize))); #else abort(this); #endif } else { image = reinterpret_cast(imageBytes); } const char* codeFunctionName = findProperty(m, "avian.codeimage"); if (codeFunctionName) { void* codep = m->libraries->resolve(codeFunctionName); if (codep) { uint8_t* (*codeFunction)(unsigned*); memcpy(&codeFunction, &codep, BytesPerWord); code = codeFunction(&size); } } } } m->unsafe = false; enter(this, ActiveState); if (image and code) { m->processor->boot(this, image, code); makeArrayInterfaceTable(this); } else { boot(this); } setRoot(this, Machine::ByteArrayMap, makeWeakHashMap(this, 0, 0)); setRoot(this, Machine::MonitorMap, makeWeakHashMap(this, 0, 0)); setRoot(this, Machine::ClassRuntimeDataTable, makeVector(this, 0, 0)); setRoot(this, Machine::MethodRuntimeDataTable, makeVector(this, 0, 0)); setRoot(this, Machine::JNIMethodTable, makeVector(this, 0, 0)); setRoot(this, Machine::JNIFieldTable, makeVector(this, 0, 0)); m->localThread->set(this); } expect(this, m->system->success(m->system->make(&lock))); } void Thread::exit() { if (state != Thread::ExitState and state != Thread::ZombieState) { enter(this, Thread::ExclusiveState); if (m->liveCount == 1) { turnOffTheLights(this); } else { threadPeer(this, javaThread) = 0; enter(this, Thread::ZombieState); } } } void Thread::dispose() { if (lock) { lock->dispose(); } if (systemThread) { systemThread->dispose(); } -- m->threadCount; m->heap->free(defaultHeap, ThreadHeapSizeInBytes); m->processor->dispose(this); } void shutDown(Thread* t) { ACQUIRE(t, t->m->shutdownLock); object hooks = root(t, Machine::ShutdownHooks); PROTECT(t, hooks); setRoot(t, Machine::ShutdownHooks, 0); object h = hooks; PROTECT(t, h); for (; h; h = pairSecond(t, h)) { startThread(t, pairFirst(t, h)); } // wait for hooks to exit h = hooks; for (; h; h = pairSecond(t, h)) { while (true) { Thread* ht = reinterpret_cast(threadPeer(t, pairFirst(t, h))); { ACQUIRE(t, t->m->stateLock); if (ht == 0 or ht->state == Thread::ZombieState or ht->state == Thread::JoinedState) { break; } else { ENTER(t, Thread::IdleState); t->m->stateLock->wait(t->systemThread, 0); } } } } // tell finalize thread to exit and wait for it to do so { ACQUIRE(t, t->m->stateLock); Thread* finalizeThread = t->m->finalizeThread; if (finalizeThread) { t->m->finalizeThread = 0; t->m->stateLock->notifyAll(t->systemThread); while (finalizeThread->state != Thread::ZombieState and finalizeThread->state != Thread::JoinedState) { ENTER(t, Thread::IdleState); t->m->stateLock->wait(t->systemThread, 0); } } } // interrupt daemon threads and tell them to die // todo: be more aggressive about killing daemon threads, e.g. at // any GC point, not just at waits/sleeps { ACQUIRE(t, t->m->stateLock); t->m->alive = false; visitAll(t, t->m->rootThread, interruptDaemon); } } void enter(Thread* t, Thread::State s) { stress(t); if (s == t->state) return; if (t->state == Thread::ExitState) { // once in exit state, we stay that way return; } #ifdef USE_ATOMIC_OPERATIONS # define INCREMENT atomicIncrement # define ACQUIRE_LOCK ACQUIRE_RAW(t, t->m->stateLock) # define STORE_LOAD_MEMORY_BARRIER storeLoadMemoryBarrier() #else # define INCREMENT(pointer, value) *(pointer) += value; # define ACQUIRE_LOCK # define STORE_LOAD_MEMORY_BARRIER ACQUIRE_RAW(t, t->m->stateLock); #endif // not USE_ATOMIC_OPERATIONS switch (s) { case Thread::ExclusiveState: { ACQUIRE_LOCK; while (t->m->exclusive) { // another thread got here first. ENTER(t, Thread::IdleState); t->m->stateLock->wait(t->systemThread, 0); } switch (t->state) { case Thread::ActiveState: break; case Thread::IdleState: { INCREMENT(&(t->m->activeCount), 1); } break; default: abort(t); } t->state = Thread::ExclusiveState; t->m->exclusive = t; STORE_LOAD_MEMORY_BARRIER; while (t->m->activeCount > 1) { t->m->stateLock->wait(t->systemThread, 0); } } break; case Thread::IdleState: if (LIKELY(t->state == Thread::ActiveState)) { // fast path assert(t, t->m->activeCount > 0); INCREMENT(&(t->m->activeCount), -1); t->state = s; if (t->m->exclusive) { ACQUIRE_LOCK; t->m->stateLock->notifyAll(t->systemThread); } break; } else { // fall through to slow path } case Thread::ZombieState: { ACQUIRE_LOCK; switch (t->state) { case Thread::ExclusiveState: { assert(t, t->m->exclusive == t); t->m->exclusive = 0; } break; case Thread::ActiveState: break; default: abort(t); } assert(t, t->m->activeCount > 0); INCREMENT(&(t->m->activeCount), -1); if (s == Thread::ZombieState) { assert(t, t->m->liveCount > 0); -- t->m->liveCount; if (t->flags & Thread::DaemonFlag) { -- t->m->daemonCount; } } t->state = s; t->m->stateLock->notifyAll(t->systemThread); } break; case Thread::ActiveState: if (LIKELY(t->state == Thread::IdleState and t->m->exclusive == 0)) { // fast path INCREMENT(&(t->m->activeCount), 1); t->state = s; if (t->m->exclusive) { // another thread has entered the exclusive state, so we // return to idle and use the slow path to become active enter(t, Thread::IdleState); } else { break; } } { ACQUIRE_LOCK; switch (t->state) { case Thread::ExclusiveState: { assert(t, t->m->exclusive == t); t->state = s; t->m->exclusive = 0; t->m->stateLock->notifyAll(t->systemThread); } break; case Thread::NoState: case Thread::IdleState: { while (t->m->exclusive) { t->m->stateLock->wait(t->systemThread, 0); } INCREMENT(&(t->m->activeCount), 1); if (t->state == Thread::NoState) { ++ t->m->liveCount; ++ t->m->threadCount; } t->state = s; } break; default: abort(t); } } break; case Thread::ExitState: { ACQUIRE_LOCK; switch (t->state) { case Thread::ExclusiveState: { assert(t, t->m->exclusive == t); // exit state should also be exclusive, so don't set exclusive = 0 t->m->stateLock->notifyAll(t->systemThread); } break; case Thread::ActiveState: break; default: abort(t); } assert(t, t->m->activeCount > 0); INCREMENT(&(t->m->activeCount), -1); t->state = s; while (t->m->liveCount - t->m->daemonCount > 1) { t->m->stateLock->wait(t->systemThread, 0); } } break; default: abort(t); } } object allocate2(Thread* t, unsigned sizeInBytes, bool objectMask) { return allocate3 (t, t->m->heap, ceilingDivide(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords ? Machine::FixedAllocation : Machine::MovableAllocation, sizeInBytes, objectMask); } object allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, unsigned sizeInBytes, bool objectMask) { expect(t, t->criticalLevel == 0); if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { expect(t, t->backupHeapIndex + ceilingDivide(sizeInBytes, BytesPerWord) <= ThreadBackupHeapSizeInWords); object o = reinterpret_cast(t->backupHeap + t->backupHeapIndex); t->backupHeapIndex += ceilingDivide(sizeInBytes, BytesPerWord); fieldAtOffset(o, 0) = 0; return o; } else if (UNLIKELY(t->flags & Thread::TracingFlag)) { expect(t, t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord) <= ThreadHeapSizeInWords); return allocateSmall(t, sizeInBytes); } ACQUIRE_RAW(t, t->m->stateLock); while (t->m->exclusive and t->m->exclusive != t) { // another thread wants to enter the exclusive state, either for a // collection or some other reason. We give it a chance here. ENTER(t, Thread::IdleState); while (t->m->exclusive) { t->m->stateLock->wait(t->systemThread, 0); } } do { switch (type) { case Machine::MovableAllocation: if (t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords) { t->heap = 0; if ((not t->m->heap->limitExceeded()) and t->m->heapPoolIndex < ThreadHeapPoolSize) { t->heap = static_cast (t->m->heap->tryAllocate(ThreadHeapSizeInBytes)); if (t->heap) { memset(t->heap, 0, ThreadHeapSizeInBytes); t->m->heapPool[t->m->heapPoolIndex++] = t->heap; t->heapOffset += t->heapIndex; t->heapIndex = 0; } } } break; case Machine::FixedAllocation: if (t->m->fixedFootprint + sizeInBytes > FixedFootprintThresholdInBytes) { t->heap = 0; } break; case Machine::ImmortalAllocation: break; } int pendingAllocation = t->m->heap->fixedFootprint (ceilingDivide(sizeInBytes, BytesPerWord), objectMask); if (t->heap == 0 or t->m->heap->limitExceeded(pendingAllocation)) { // fprintf(stderr, "gc"); // vmPrintTrace(t); collect(t, Heap::MinorCollection, pendingAllocation); } if (t->m->heap->limitExceeded(pendingAllocation)) { throw_(t, root(t, Machine::OutOfMemoryError)); } } while (type == Machine::MovableAllocation and t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords); switch (type) { case Machine::MovableAllocation: { return allocateSmall(t, sizeInBytes); } case Machine::FixedAllocation: { object o = static_cast (t->m->heap->allocateFixed (allocator, ceilingDivide(sizeInBytes, BytesPerWord), objectMask)); memset(o, 0, sizeInBytes); alias(o, 0) = FixedMark; t->m->fixedFootprint += t->m->heap->fixedFootprint (ceilingDivide(sizeInBytes, BytesPerWord), objectMask); return o; } case Machine::ImmortalAllocation: { object o = static_cast (t->m->heap->allocateImmortalFixed (allocator, ceilingDivide(sizeInBytes, BytesPerWord), objectMask)); memset(o, 0, sizeInBytes); alias(o, 0) = FixedMark; return o; } default: abort(t); } } void collect(Thread* t, Heap::CollectionType type, int pendingAllocation) { ENTER(t, Thread::ExclusiveState); unsigned pending = pendingAllocation - (t->m->heapPoolIndex * ThreadHeapSizeInWords); if (t->m->heap->limitExceeded(pending)) { type = Heap::MajorCollection; } doCollect(t, type, pendingAllocation); if (t->m->heap->limitExceeded(pending)) { // try once more, giving the heap a chance to squeeze everything // into the smallest possible space: doCollect(t, Heap::MajorCollection, pendingAllocation); } } object makeNewGeneral(Thread* t, object class_) { assert(t, t->state == Thread::ActiveState); PROTECT(t, class_); object instance = makeNew(t, class_); PROTECT(t, instance); if (classVmFlags(t, class_) & WeakReferenceFlag) { ACQUIRE(t, t->m->referenceLock); jreferenceVmNext(t, instance) = t->m->weakReferences; t->m->weakReferences = instance; } if (classVmFlags(t, class_) & HasFinalizerFlag) { addFinalizer(t, instance, 0); } return instance; } void popResources(Thread* t) { while (t->resource != t->checkpoint->resource) { Thread::Resource* r = t->resource; t->resource = r->next; r->release(); } t->protector = t->checkpoint->protector; } object makeByteArrayV(Thread* t, const char* format, va_list a, int size) { THREAD_RUNTIME_ARRAY(t, char, buffer, size); int r = vm::vsnprintf(RUNTIME_ARRAY_BODY(buffer), size - 1, format, a); if (r >= 0 and r < size - 1) { object s = makeByteArray(t, strlen(RUNTIME_ARRAY_BODY(buffer)) + 1); memcpy(&byteArrayBody(t, s, 0), RUNTIME_ARRAY_BODY(buffer), byteArrayLength(t, s)); return s; } else { return 0; } } object makeByteArray(Thread* t, const char* format, ...) { int size = 256; while (true) { va_list a; va_start(a, format); object s = makeByteArrayV(t, format, a, size); va_end(a); if (s) { return s; } else { size *= 2; } } } object makeString(Thread* t, const char* format, ...) { int size = 256; while (true) { va_list a; va_start(a, format); object s = makeByteArrayV(t, format, a, size); va_end(a); if (s) { return t->m->classpath->makeString(t, s, 0, byteArrayLength(t, s) - 1); } else { size *= 2; } } } int stringUTFLength(Thread* t, object string, unsigned start, unsigned length) { unsigned result = 0; if (length) { object data = stringData(t, string); if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { result = length; } else { for (unsigned i = 0; i < length; ++i) { uint16_t c = charArrayBody (t, data, stringOffset(t, string) + start + i); if (c == 0) result += 1; // null char (was 2 bytes in Java) else if (c < 0x80) result += 1; // ASCII char else if (c < 0x800) result += 2; // two-byte char else result += 3; // three-byte char } } } return result; } void stringChars(Thread* t, object string, unsigned start, unsigned length, char* chars) { if (length) { object data = stringData(t, string); if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { memcpy(chars, &byteArrayBody(t, data, stringOffset(t, string) + start), length); } else { for (unsigned i = 0; i < length; ++i) { chars[i] = charArrayBody(t, data, stringOffset(t, string) + start + i); } } } chars[length] = 0; } void stringChars(Thread* t, object string, unsigned start, unsigned length, uint16_t* chars) { if (length) { object data = stringData(t, string); if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { for (unsigned i = 0; i < length; ++i) { chars[i] = byteArrayBody(t, data, stringOffset(t, string) + start + i); } } else { memcpy(chars, &charArrayBody(t, data, stringOffset(t, string) + start), length * sizeof(uint16_t)); } } chars[length] = 0; } void stringUTFChars(Thread* t, object string, unsigned start, unsigned length, char* chars, unsigned charsLength UNUSED) { assert(t, static_cast (stringUTFLength(t, string, start, length)) == charsLength); object data = stringData(t, string); if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { memcpy(chars, &byteArrayBody(t, data, stringOffset(t, string) + start), length); chars[length] = 0; } else { int j = 0; for (unsigned i = 0; i < length; ++i) { uint16_t c = charArrayBody (t, data, stringOffset(t, string) + start + i); if(!c) { // null char chars[j++] = 0; } else if (c < 0x80) { // ASCII char chars[j++] = static_cast(c); } else if (c < 0x800) { // two-byte char chars[j++] = static_cast(0x0c0 | (c >> 6)); chars[j++] = static_cast(0x080 | (c & 0x03f)); } else { // three-byte char chars[j++] = static_cast(0x0e0 | ((c >> 12) & 0x0f)); chars[j++] = static_cast(0x080 | ((c >> 6) & 0x03f)); chars[j++] = static_cast(0x080 | (c & 0x03f)); } } chars[j] = 0; } } uint64_t resolveBootstrap(Thread* t, uintptr_t* arguments) { object name = reinterpret_cast(arguments[0]); resolveSystemClass(t, root(t, Machine::BootLoader), name); return 1; } bool isAssignableFrom(Thread* t, object a, object b) { assert(t, a); assert(t, b); if (a == b) return true; if (classFlags(t, a) & ACC_INTERFACE) { if (classVmFlags(t, b) & BootstrapFlag) { uintptr_t arguments[] = { reinterpret_cast(className(t, b)) }; if (run(t, resolveBootstrap, arguments) == 0) { t->exception = 0; return false; } } object itable = classInterfaceTable(t, b); if (itable) { unsigned stride = (classFlags(t, b) & ACC_INTERFACE) ? 1 : 2; for (unsigned i = 0; i < arrayLength(t, itable); i += stride) { if (arrayBody(t, itable, i) == a) { return true; } } } } else if (classArrayDimensions(t, a)) { if (classArrayDimensions(t, b)) { return isAssignableFrom (t, classStaticTable(t, a), classStaticTable(t, b)); } } else if ((classVmFlags(t, a) & PrimitiveFlag) == (classVmFlags(t, b) & PrimitiveFlag)) { for (; b; b = classSuper(t, b)) { if (b == a) { return true; } } } return false; } bool instanceOf(Thread* t, object class_, object o) { if (o == 0) { return false; } else { return isAssignableFrom(t, class_, objectClass(t, o)); } } object classInitializer(Thread* t, object class_) { if (classMethodTable(t, class_)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, class_)); ++i) { object o = arrayBody(t, classMethodTable(t, class_), i); if (methodVmFlags(t, o) & ClassInitFlag) { return o; } } } return 0; } unsigned fieldCode(Thread* t, unsigned javaCode) { switch (javaCode) { case 'B': return ByteField; case 'C': return CharField; case 'D': return DoubleField; case 'F': return FloatField; case 'I': return IntField; case 'J': return LongField; case 'S': return ShortField; case 'V': return VoidField; case 'Z': return BooleanField; case 'L': case '[': return ObjectField; default: abort(t); } } unsigned fieldType(Thread* t, unsigned code) { switch (code) { case VoidField: return VOID_TYPE; case ByteField: case BooleanField: return INT8_TYPE; case CharField: case ShortField: return INT16_TYPE; case DoubleField: return DOUBLE_TYPE; case FloatField: return FLOAT_TYPE; case IntField: return INT32_TYPE; case LongField: return INT64_TYPE; case ObjectField: return POINTER_TYPE; default: abort(t); } } unsigned primitiveSize(Thread* t, unsigned code) { switch (code) { case VoidField: return 0; case ByteField: case BooleanField: return 1; case CharField: case ShortField: return 2; case FloatField: case IntField: return 4; case DoubleField: case LongField: return 8; default: abort(t); } } object parseClass(Thread* t, object loader, const uint8_t* data, unsigned size, Machine::Type throwType) { PROTECT(t, loader); class Client: public Stream::Client { public: Client(Thread* t): t(t) { } virtual void NO_RETURN handleError() { abort(t); } private: Thread* t; } client(t); Stream s(&client, data, size); uint32_t magic = s.read4(); expect(t, magic == 0xCAFEBABE); unsigned minorVer = s.read2(); // minor version unsigned majorVer = s.read2(); // major version if(DebugClassReader) { fprintf(stderr, "read class (minor %d major %d)\n", minorVer, majorVer); } object pool = parsePool(t, s); PROTECT(t, pool); unsigned flags = s.read2(); unsigned name = s.read2(); object class_ = makeClass(t, flags, 0, // VM flags 0, // fixed size 0, // array size 0, // array dimensions 0, // runtime data index 0, // object mask referenceName (t, singletonObject(t, pool, name - 1)), 0, // source file 0, // super 0, // interfaces 0, // vtable 0, // fields 0, // methods 0, // addendum 0, // static table loader, 0, // source 0);// vtable length PROTECT(t, class_); unsigned super = s.read2(); if (super) { object sc = resolveClass (t, loader, referenceName(t, singletonObject(t, pool, super - 1)), true, throwType); set(t, class_, ClassSuper, sc); classVmFlags(t, class_) |= (classVmFlags(t, sc) & (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag | NeedInitFlag)); } if(DebugClassReader) { fprintf(stderr, " flags %d name %d super %d\n", flags, name, super); } parseInterfaceTable(t, s, class_, pool, throwType); parseFieldTable(t, s, class_, pool); parseMethodTable(t, s, class_, pool); parseAttributeTable(t, s, class_, pool); object vtable = classVirtualTable(t, class_); unsigned vtableLength = (vtable ? arrayLength(t, vtable) : 0); object real = t->m->processor->makeClass (t, classFlags(t, class_), classVmFlags(t, class_), classFixedSize(t, class_), classArrayElementSize(t, class_), classArrayDimensions(t, class_), classObjectMask(t, class_), className(t, class_), classSourceFile(t, class_), classSuper(t, class_), classInterfaceTable(t, class_), classVirtualTable(t, class_), classFieldTable(t, class_), classMethodTable(t, class_), classAddendum(t, class_), classStaticTable(t, class_), classLoader(t, class_), vtableLength); PROTECT(t, real); t->m->processor->initVtable(t, real); updateClassTables(t, real, class_); if (root(t, Machine::PoolMap)) { object bootstrapClass = hashMapFind (t, root(t, Machine::BootstrapClassMap), className(t, class_), byteArrayHash, byteArrayEqual); hashMapInsert (t, root(t, Machine::PoolMap), bootstrapClass ? bootstrapClass : real, pool, objectHash); } return real; } uint64_t runParseClass(Thread* t, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); System::Region* region = reinterpret_cast(arguments[1]); Machine::Type throwType = static_cast(arguments[2]); return reinterpret_cast (parseClass(t, loader, region->start(), region->length(), throwType)); } object resolveSystemClass(Thread* t, object loader, object spec, bool throw_, Machine::Type throwType) { PROTECT(t, loader); PROTECT(t, spec); ACQUIRE(t, t->m->classLock); object class_ = hashMapFind (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); if (class_ == 0) { PROTECT(t, class_); if (classLoaderParent(t, loader)) { class_ = resolveSystemClass (t, classLoaderParent(t, loader), spec, false); if (class_) { return class_; } } if (byteArrayBody(t, spec, 0) == '[') { class_ = resolveArrayClass(t, loader, spec, throw_, throwType); } else { THREAD_RUNTIME_ARRAY(t, char, file, byteArrayLength(t, spec) + 6); memcpy(RUNTIME_ARRAY_BODY(file), &byteArrayBody(t, spec, 0), byteArrayLength(t, spec) - 1); memcpy(RUNTIME_ARRAY_BODY(file) + byteArrayLength(t, spec) - 1, ".class", 7); System::Region* region = static_cast (systemClassLoaderFinder(t, loader))->find (RUNTIME_ARRAY_BODY(file)); if (region) { if (Verbose) { fprintf(stderr, "parsing %s\n", &byteArrayBody(t, spec, 0)); } { THREAD_RESOURCE(t, System::Region*, region, region->dispose()); uintptr_t arguments[] = { reinterpret_cast(loader), reinterpret_cast(region), static_cast(throwType) }; // parse class file class_ = reinterpret_cast (runRaw(t, runParseClass, arguments)); if (UNLIKELY(t->exception)) { if (throw_) { object e = t->exception; t->exception = 0; vm::throw_(t, e); } else { t->exception = 0; return 0; } } } if (Verbose) { fprintf(stderr, "done parsing %s: %p\n", &byteArrayBody(t, spec, 0), class_); } { const char* source = static_cast (systemClassLoaderFinder(t, loader))->sourceUrl (RUNTIME_ARRAY_BODY(file)); if (source) { unsigned length = strlen(source); object array = makeByteArray(t, length + 1); memcpy(&byteArrayBody(t, array, 0), source, length); array = internByteArray(t, array); set(t, class_, ClassSource, array); } } object bootstrapClass = hashMapFind (t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash, byteArrayEqual); if (bootstrapClass) { PROTECT(t, bootstrapClass); updateBootstrapClass(t, bootstrapClass, class_); class_ = bootstrapClass; } } } if (class_) { hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); updatePackageMap(t, class_); } else if (throw_) { throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0)); } } return class_; } object findLoadedClass(Thread* t, object loader, object spec) { PROTECT(t, loader); PROTECT(t, spec); ACQUIRE(t, t->m->classLock); return classLoaderMap(t, loader) ? hashMapFind (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual) : 0; } object resolveClass(Thread* t, object loader, object spec, bool throw_, Machine::Type throwType) { if (objectClass(t, loader) == type(t, Machine::SystemClassLoaderType)) { return resolveSystemClass(t, loader, spec, throw_, throwType); } else { PROTECT(t, loader); PROTECT(t, spec); object c = findLoadedClass(t, loader, spec); if (c) { return c; } if (byteArrayBody(t, spec, 0) == '[') { c = resolveArrayClass(t, loader, spec, throw_, throwType); } else { if (root(t, Machine::LoadClassMethod) == 0) { object m = resolveMethod (t, root(t, Machine::BootLoader), "java/lang/ClassLoader", "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); if (m) { setRoot(t, Machine::LoadClassMethod, m); object classLoaderClass = type(t, Machine::ClassLoaderType); if (classVmFlags(t, classLoaderClass) & BootstrapFlag) { resolveSystemClass (t, root(t, Machine::BootLoader), vm::className(t, classLoaderClass)); } } } object method = findVirtualMethod (t, root(t, Machine::LoadClassMethod), objectClass(t, loader)); PROTECT(t, method); THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, spec)); replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast (&byteArrayBody(t, spec, 0))); object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); PROTECT(t, specString); uintptr_t arguments[] = { reinterpret_cast(method), reinterpret_cast(loader), reinterpret_cast(specString) }; object jc = reinterpret_cast (runRaw(t, invokeLoadClass, arguments)); if (LIKELY(jc)) { c = jclassVmClass(t, jc); } else if (t->exception) { if (throw_) { object e = type(t, throwType) == objectClass(t, t->exception) ? t->exception : makeThrowable(t, throwType, specString, 0, t->exception); t->exception = 0; vm::throw_(t, e); } else { t->exception = 0; } } } if (LIKELY(c)) { PROTECT(t, c); saveLoadedClass(t, loader, c); } else if (throw_) { throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0)); } return c; } } object resolveMethod(Thread* t, object class_, const char* methodName, const char* methodSpec) { PROTECT(t, class_); object name = makeByteArray(t, methodName); PROTECT(t, name); object spec = makeByteArray(t, methodSpec); object method = findMethodInClass(t, class_, name, spec); if (method == 0) { throwNew(t, Machine::NoSuchMethodErrorType, "%s %s not found in %s", methodName, methodSpec, &byteArrayBody (t, className(t, class_), 0)); } else { return method; } } object resolveField(Thread* t, object class_, const char* fieldName, const char* fieldSpec) { PROTECT(t, class_); object name = makeByteArray(t, fieldName); PROTECT(t, name); object spec = makeByteArray(t, fieldSpec); PROTECT(t, spec); object field = findInInterfaces(t, class_, name, spec, findFieldInClass); object c = class_; PROTECT(t, c); for (; c != 0 and field == 0; c = classSuper(t, c)) { field = findFieldInClass(t, c, name, spec); } if (field == 0) { throwNew(t, Machine::NoSuchFieldErrorType, "%s %s not found in %s", fieldName, fieldSpec, &byteArrayBody(t, className(t, class_), 0)); } else { return field; } } bool classNeedsInit(Thread* t, object c) { if (classVmFlags(t, c) & NeedInitFlag) { if (classVmFlags(t, c) & InitFlag) { // the class is currently being initialized. If this the thread // which is initializing it, we should not try to initialize it // recursively. Otherwise, we must wait for the responsible // thread to finish. for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) { if (s->class_ == c) { return false; } } } return true; } else { return false; } } bool preInitClass(Thread* t, object c) { int flags = classVmFlags(t, c); loadMemoryBarrier(); if (flags & NeedInitFlag) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); if (classVmFlags(t, c) & NeedInitFlag) { if (classVmFlags(t, c) & InitFlag) { // If the class is currently being initialized and this the thread // which is initializing it, we should not try to initialize it // recursively. if (isInitializing(t, c)) { return false; } // some other thread is on the job - wait for it to finish. while (classVmFlags(t, c) & InitFlag) { ENTER(t, Thread::IdleState); t->m->classLock->wait(t->systemThread, 0); } } else if (classVmFlags(t, c) & InitErrorFlag) { throwNew(t, Machine::NoClassDefFoundErrorType, "%s", &byteArrayBody(t, className(t, c), 0)); } else { classVmFlags(t, c) |= InitFlag; return true; } } } return false; } void postInitClass(Thread* t, object c) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); if (t->exception) { classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag; classVmFlags(t, c) &= ~InitFlag; object exception = t->exception; t->exception = 0; exception = makeThrowable (t, Machine::ExceptionInInitializerErrorType, 0, 0, exception); set(t, exception, ExceptionInInitializerErrorException, throwableCause(t, exception)); throw_(t, exception); } else { classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag); } t->m->classLock->notifyAll(t->systemThread); } void initClass(Thread* t, object c) { PROTECT(t, c); object super = classSuper(t, c); if (super) { initClass(t, super); } if (preInitClass(t, c)) { OBJECT_RESOURCE(t, c, postInitClass(t, c)); object initializer = classInitializer(t, c); if (initializer) { Thread::ClassInitStack stack(t, c); t->m->processor->invoke(t, initializer, 0); } } } object resolveObjectArrayClass(Thread* t, object loader, object elementClass) { PROTECT(t, loader); PROTECT(t, elementClass); { object arrayClass = classRuntimeDataArrayClass (t, getClassRuntimeData(t, elementClass)); if (arrayClass) { return arrayClass; } } object elementSpec = className(t, elementClass); PROTECT(t, elementSpec); object spec; if (byteArrayBody(t, elementSpec, 0) == '[') { spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1); byteArrayBody(t, spec, 0) = '['; memcpy(&byteArrayBody(t, spec, 1), &byteArrayBody(t, elementSpec, 0), byteArrayLength(t, elementSpec)); } else { spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 3); byteArrayBody(t, spec, 0) = '['; byteArrayBody(t, spec, 1) = 'L'; memcpy(&byteArrayBody(t, spec, 2), &byteArrayBody(t, elementSpec, 0), byteArrayLength(t, elementSpec) - 1); byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 1) = ';'; byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 2) = 0; } object arrayClass = resolveClass(t, loader, spec); set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass, arrayClass); return arrayClass; } object makeObjectArray(Thread* t, object elementClass, unsigned count) { object arrayClass = resolveObjectArrayClass (t, classLoader(t, elementClass), elementClass); PROTECT(t, arrayClass); object array = makeArray(t, count); setObjectClass(t, array, arrayClass); return array; } object findFieldInClass(Thread* t, object class_, object name, object spec) { return findInTable (t, classFieldTable(t, class_), name, spec, fieldName, fieldSpec); } object findMethodInClass(Thread* t, object class_, object name, object spec) { return findInTable (t, classMethodTable(t, class_), name, spec, methodName, methodSpec); } object findInHierarchyOrNull(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object)) { object originalClass = class_; object o = 0; if ((classFlags(t, class_) & ACC_INTERFACE) and classVirtualTable(t, class_)) { o = findInTable (t, classVirtualTable(t, class_), name, spec, methodName, methodSpec); } if (o == 0) { for (; o == 0 and class_; class_ = classSuper(t, class_)) { o = find(t, class_, name, spec); } if (o == 0 and find == findFieldInClass) { o = findInInterfaces(t, originalClass, name, spec, find); } } return o; } unsigned parameterFootprint(Thread* t, const char* s, bool static_) { unsigned footprint = 0; for (MethodSpecIterator it(t, s); it.hasNext();) { switch (*it.next()) { case 'J': case 'D': footprint += 2; break; default: ++ footprint; break; } } if (not static_) { ++ footprint; } return footprint; } void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)) { PROTECT(t, target); ACQUIRE(t, t->m->referenceLock); void* function; memcpy(&function, &finalize, BytesPerWord); object f = makeFinalizer(t, 0, function, 0, 0, 0); finalizerTarget(t, f) = target; finalizerNext(t, f) = t->m->finalizers; t->m->finalizers = f; } object objectMonitor(Thread* t, object o, bool createNew) { assert(t, t->state == Thread::ActiveState); object m = hashMapFind (t, root(t, Machine::MonitorMap), o, objectHash, objectEqual); if (m) { if (DebugMonitors) { fprintf(stderr, "found monitor %p for object %x\n", m, objectHash(t, o)); } return m; } else if (createNew) { PROTECT(t, o); PROTECT(t, m); { ENTER(t, Thread::ExclusiveState); m = hashMapFind (t, root(t, Machine::MonitorMap), o, objectHash, objectEqual); if (m) { if (DebugMonitors) { fprintf(stderr, "found monitor %p for object %x\n", m, objectHash(t, o)); } return m; } object head = makeMonitorNode(t, 0, 0); m = makeMonitor(t, 0, 0, 0, head, head, 0); if (DebugMonitors) { fprintf(stderr, "made monitor %p for object %x\n", m, objectHash(t, o)); } hashMapInsert(t, root(t, Machine::MonitorMap), o, m, objectHash); addFinalizer(t, o, removeMonitor); } return m; } else { return 0; } } object intern(Thread* t, object s) { PROTECT(t, s); ACQUIRE(t, t->m->referenceLock); object n = hashMapFindNode (t, root(t, Machine::StringMap), s, stringHash, stringEqual); if (n) { return jreferenceTarget(t, tripleFirst(t, n)); } else { hashMapInsert(t, root(t, Machine::StringMap), s, 0, stringHash); addFinalizer(t, s, removeString); return s; } } void walk(Thread* t, Heap::Walker* w, object o, unsigned start) { object class_ = static_cast(t->m->heap->follow(objectClass(t, o))); object objectMask = static_cast (t->m->heap->follow(classObjectMask(t, class_))); bool more = true; if (objectMask) { unsigned fixedSize = classFixedSize(t, class_); unsigned arrayElementSize = classArrayElementSize(t, class_); unsigned arrayLength = (arrayElementSize ? fieldAtOffset(o, fixedSize - BytesPerWord) : 0); THREAD_RUNTIME_ARRAY(t, uint32_t, mask, intArrayLength(t, objectMask)); memcpy(RUNTIME_ARRAY_BODY(mask), &intArrayBody(t, objectMask, 0), intArrayLength(t, objectMask) * 4); more = ::walk(t, w, RUNTIME_ARRAY_BODY(mask), fixedSize, arrayElementSize, arrayLength, start); } else if (classVmFlags(t, class_) & SingletonFlag) { unsigned length = singletonLength(t, o); if (length) { more = ::walk(t, w, singletonMask(t, o), (singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start); } else if (start == 0) { more = w->visit(0); } } else if (start == 0) { more = w->visit(0); } if (more and classVmFlags(t, class_) & ContinuationFlag) { t->m->processor->walkContinuationBody(t, w, o, start); } } int walkNext(Thread* t, object o, int previous) { class Walker: public Heap::Walker { public: Walker(): value(-1) { } bool visit(unsigned offset) { value = offset; return false; } int value; } walker; walk(t, &walker, o, previous + 1); return walker.value; } void visitRoots(Machine* m, Heap::Visitor* v) { v->visit(&(m->types)); v->visit(&(m->roots)); for (Thread* t = m->rootThread; t; t = t->peer) { ::visitRoots(t, v); } for (Reference* r = m->jniReferences; r; r = r->next) { if (not r->weak) { v->visit(&(r->target)); } } } void logTrace(FILE* f, const char* fmt, ...) { va_list a; va_start(a, fmt); #ifdef PLATFORM_WINDOWS const unsigned length = _vscprintf(fmt, a); #else const unsigned length = vsnprintf(0, 0, fmt, a); #endif va_end(a); RUNTIME_ARRAY(char, buffer, length + 1); va_start(a, fmt); vsnprintf(RUNTIME_ARRAY_BODY(buffer), length + 1, fmt, a); va_end(a); RUNTIME_ARRAY_BODY(buffer)[length] = 0; ::fprintf(f, "%s", RUNTIME_ARRAY_BODY(buffer)); #ifdef PLATFORM_WINDOWS ::OutputDebugStringA(RUNTIME_ARRAY_BODY(buffer)); #endif } void printTrace(Thread* t, object exception) { if (exception == 0) { exception = makeThrowable(t, Machine::NullPointerExceptionType); } for (object e = exception; e; e = throwableCause(t, e)) { if (e != exception) { logTrace(errorLog(t), "caused by: "); } logTrace(errorLog(t), "%s", &byteArrayBody (t, className(t, objectClass(t, e)), 0)); if (throwableMessage(t, e)) { object m = throwableMessage(t, e); THREAD_RUNTIME_ARRAY(t, char, message, stringLength(t, m) + 1); stringChars(t, m, RUNTIME_ARRAY_BODY(message)); logTrace(errorLog(t), ": %s\n", RUNTIME_ARRAY_BODY(message)); } else { logTrace(errorLog(t), "\n"); } object trace = throwableTrace(t, e); if (trace) { for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { object e = objectArrayBody(t, trace, i); const int8_t* class_ = &byteArrayBody (t, className(t, methodClass(t, traceElementMethod(t, e))), 0); const int8_t* method = &byteArrayBody (t, methodName(t, traceElementMethod(t, e)), 0); int line = t->m->processor->lineNumber (t, traceElementMethod(t, e), traceElementIp(t, e)); logTrace(errorLog(t), " at %s.%s ", class_, method); switch (line) { case NativeLine: logTrace(errorLog(t), "(native)\n"); break; case UnknownLine: logTrace(errorLog(t), "(unknown line)\n"); break; default: logTrace(errorLog(t), "(line %d)\n", line); } } } if (e == throwableCause(t, e)) { break; } } ::fflush(errorLog(t)); } object makeTrace(Thread* t, Processor::StackWalker* walker) { class Visitor: public Processor::StackVisitor { public: Visitor(Thread* t): t(t), trace(0), index(0), protector(t, &trace) { } virtual bool visit(Processor::StackWalker* walker) { if (trace == 0) { trace = makeObjectArray(t, walker->count()); assert(t, trace); } object e = makeTraceElement(t, walker->method(), walker->ip()); assert(t, index < objectArrayLength(t, trace)); set(t, trace, ArrayBody + (index * BytesPerWord), e); ++ index; return true; } Thread* t; object trace; unsigned index; Thread::SingleProtector protector; } v(t); walker->walk(&v); return v.trace ? v.trace : makeObjectArray(t, 0); } object makeTrace(Thread* t, Thread* target) { class Visitor: public Processor::StackVisitor { public: Visitor(Thread* t): t(t), trace(0) { } virtual bool visit(Processor::StackWalker* walker) { trace = vm::makeTrace(t, walker); return false; } Thread* t; object trace; } v(t); t->m->processor->walkStack(target, &v); return v.trace ? v.trace : makeObjectArray(t, 0); } void runFinalizeThread(Thread* t) { object finalizeList = 0; PROTECT(t, finalizeList); object cleanList = 0; PROTECT(t, cleanList); while (true) { { ACQUIRE(t, t->m->stateLock); while (t->m->finalizeThread and root(t, Machine::ObjectsToFinalize) == 0 and root(t, Machine::ObjectsToClean) == 0) { ENTER(t, Thread::IdleState); t->m->stateLock->wait(t->systemThread, 0); } if (t->m->finalizeThread == 0) { return; } else { finalizeList = root(t, Machine::ObjectsToFinalize); setRoot(t, Machine::ObjectsToFinalize, 0); cleanList = root(t, Machine::ObjectsToClean); setRoot(t, Machine::ObjectsToClean, 0); } } for (; finalizeList; finalizeList = finalizerQueueNext(t, finalizeList)) { finalizeObject(t, finalizerQueueTarget(t, finalizeList), "finalize"); } for (; cleanList; cleanList = cleanerQueueNext(t, cleanList)) { finalizeObject(t, cleanList, "clean"); } } } object parseUtf8(Thread* t, const char* data, unsigned length) { class Client: public Stream::Client { public: Client(Thread* t): t(t) { } virtual void handleError() { if (false) abort(t); } private: Thread* t; } client(t); Stream s(&client, reinterpret_cast(data), length); return ::parseUtf8(t, s, length); } object parseUtf8(Thread* t, object array) { for (unsigned i = 0; i < byteArrayLength(t, array) - 1; ++i) { if (byteArrayBody(t, array, i) & 0x80) { goto slow_path; } } return array; slow_path: class Client: public Stream::Client { public: Client(Thread* t): t(t) { } virtual void handleError() { if (false) abort(t); } private: Thread* t; } client(t); class MyStream: public AbstractStream { public: class MyProtector: public Thread::Protector { public: MyProtector(Thread* t, MyStream* s): Protector(t), s(s) { } virtual void visit(Heap::Visitor* v) { v->visit(&(s->array)); } MyStream* s; }; MyStream(Thread* t, Client* client, object array): AbstractStream(client, byteArrayLength(t, array) - 1), array(array), protector(t, this) { } virtual void copy(uint8_t* dst, unsigned offset, unsigned size) { memcpy(dst, &byteArrayBody(protector.t, array, offset), size); } object array; MyProtector protector; } s(t, &client, array); return ::parseUtf8(t, s, byteArrayLength(t, array) - 1); } object getCaller(Thread* t, unsigned target, bool skipMethodInvoke) { class Visitor: public Processor::StackVisitor { public: Visitor(Thread* t, unsigned target, bool skipMethodInvoke): t(t), method(0), count(0), target(target), skipMethodInvoke(skipMethodInvoke) { } virtual bool visit(Processor::StackWalker* walker) { if (skipMethodInvoke and methodClass (t, walker->method()) == type(t, Machine::JmethodType) and strcmp (&byteArrayBody(t, methodName(t, walker->method()), 0), reinterpret_cast("invoke")) == 0) { return true; } if (count == target) { method = walker->method(); return false; } else { ++ count; return true; } } Thread* t; object method; unsigned count; unsigned target; bool skipMethodInvoke; } v(t, target, skipMethodInvoke); t->m->processor->walkStack(t, &v); return v.method; } object defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length) { PROTECT(t, loader); object c = parseClass(t, loader, buffer, length); // char name[byteArrayLength(t, className(t, c))]; // memcpy(name, &byteArrayBody(t, className(t, c), 0), // byteArrayLength(t, className(t, c))); // replace('/', '-', name); // const unsigned BufferSize = 1024; // char path[BufferSize]; // snprintf(path, BufferSize, "/tmp/avian-define-class/%s.class", name); // FILE* file = fopen(path, "wb"); // if (file) { // fwrite(buffer, length, 1, file); // fclose(file); // } PROTECT(t, c); saveLoadedClass(t, loader, c); return c; } void populateMultiArray(Thread* t, object array, int32_t* counts, unsigned index, unsigned dimensions) { if (index + 1 == dimensions or counts[index] == 0) { return; } PROTECT(t, array); object spec = className(t, objectClass(t, array)); PROTECT(t, spec); object elementSpec = makeByteArray(t, byteArrayLength(t, spec) - 1); memcpy(&byteArrayBody(t, elementSpec, 0), &byteArrayBody(t, spec, 1), byteArrayLength(t, spec) - 1); object class_ = resolveClass (t, classLoader(t, objectClass(t, array)), elementSpec); PROTECT(t, class_); for (int32_t i = 0; i < counts[index]; ++i) { object a = makeArray (t, ceilingDivide (counts[index + 1] * classArrayElementSize(t, class_), BytesPerWord)); arrayLength(t, a) = counts[index + 1]; setObjectClass(t, a, class_); set(t, array, ArrayBody + (i * BytesPerWord), a); populateMultiArray(t, a, counts, index + 1, dimensions); } } object interruptLock(Thread* t, object thread) { object lock = threadInterruptLock(t, thread); loadMemoryBarrier(); if (lock == 0) { PROTECT(t, thread); ACQUIRE(t, t->m->referenceLock); if (threadInterruptLock(t, thread) == 0) { object head = makeMonitorNode(t, 0, 0); object lock = makeMonitor(t, 0, 0, 0, head, head, 0); storeStoreMemoryBarrier(); set(t, thread, ThreadInterruptLock, lock); } } return threadInterruptLock(t, thread); } void clearInterrupted(Thread* t) { monitorAcquire(t, interruptLock(t, t->javaThread)); threadInterrupted(t, t->javaThread) = false; monitorRelease(t, interruptLock(t, t->javaThread)); } void threadInterrupt(Thread* t, object thread) { PROTECT(t, thread); monitorAcquire(t, interruptLock(t, thread)); Thread* p = reinterpret_cast(threadPeer(t, thread)); if (p) { interrupt(t, p); } threadInterrupted(t, thread) = true; monitorRelease(t, interruptLock(t, thread)); } bool threadIsInterrupted(Thread* t, object thread, bool clear) { PROTECT(t, thread); monitorAcquire(t, interruptLock(t, thread)); bool v = threadInterrupted(t, thread); if (clear) { threadInterrupted(t, thread) = false; } monitorRelease(t, interruptLock(t, thread)); return v; } void noop() { } #include "type-constructors.cpp" } // namespace vm // for debugging AVIAN_EXPORT void vmfPrintTrace(Thread* t, FILE* out) { class Visitor: public Processor::StackVisitor { public: Visitor(Thread* t, FILE* out): t(t), out(out) { } virtual bool visit(Processor::StackWalker* walker) { const int8_t* class_ = &byteArrayBody (t, className(t, methodClass(t, walker->method())), 0); const int8_t* method = &byteArrayBody (t, methodName(t, walker->method()), 0); int line = t->m->processor->lineNumber (t, walker->method(), walker->ip()); fprintf(out, " at %s.%s ", class_, method); switch (line) { case NativeLine: fprintf(out, "(native)\n"); break; case UnknownLine: fprintf(out, "(unknown line)\n"); break; default: fprintf(out, "(line %d)\n", line); } return true; } Thread* t; FILE* out; } v(t, out); fprintf(out, "debug trace for thread %p\n", t); t->m->processor->walkStack(t, &v); fflush(out); } AVIAN_EXPORT void vmPrintTrace(Thread* t) { vmfPrintTrace(t, stderr); } // also for debugging AVIAN_EXPORT void* vmAddressFromLine(Thread* t, object m, unsigned line) { object code = methodCode(t, m); printf("code: %p\n", code); object lnt = codeLineNumberTable(t, code); printf("lnt: %p\n", lnt); if (lnt) { unsigned last = 0; unsigned bottom = 0; unsigned top = lineNumberTableLength(t, lnt); for(unsigned i = bottom; i < top; i++) { uint64_t ln = lineNumberTableBody(t, lnt, i); if(lineNumberLine(ln) == line) return reinterpret_cast(lineNumberIp(ln)); else if(lineNumberLine(ln) > line) return reinterpret_cast(last); last = lineNumberIp(ln); } } return 0; } ReadyTalk-avian-1e1fff5/src/main.cpp000066400000000000000000000155701231440243200174070ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "stdlib.h" #include "stdio.h" #include "string.h" #include "jni.h" #include #include "avian/finder.h" #include #if (defined __MINGW32__) || (defined _MSC_VER) # define PATH_SEPARATOR ';' #else # define PATH_SEPARATOR ':' #endif #ifdef _MSC_VER # define not ! # define or || # define and && # define xor ^ #endif // not _MSC_VER #ifdef BOOT_LIBRARY // since we aren't linking against libstdc++, we must implement this // ourselves: extern "C" void __cxa_pure_virtual(void) { abort(); } // we link against a System implmentation, which requires this at link // time, but it should not be used at runtime: extern "C" uint64_t vmNativeCall(void*, void*, unsigned, unsigned) { abort(); // abort is not declared __declspec(noreturn) on MSVC, so we have to // pretend it might return to make the compiler happy: return 0; } #endif // BOOT_LIBRARY namespace { const char* mainClass(const char* jar) { using namespace vm; System* system = makeSystem(); class MyAllocator : public avian::util::Allocator { public: MyAllocator(System* s): s(s) { } virtual void* tryAllocate(unsigned size) { return s->tryAllocate(size); } virtual void* allocate(unsigned size) { void* p = tryAllocate(size); if (p == 0) { abort(s); } return p; } virtual void free(const void* p, unsigned) { s->free(p); } System* s; } allocator(system); Finder* finder = makeFinder(system, &allocator, jar, 0); char* result = 0; System::Region* region = finder->find("META-INF/MANIFEST.MF"); if (region) { unsigned start = 0; unsigned length; while (readLine(region->start(), region->length(), &start, &length)) { const unsigned PrefixLength = 12; if (strncasecmp("Main-Class: ", reinterpret_cast (region->start() + start), PrefixLength) == 0) { result = static_cast(malloc(length + 1 - PrefixLength)); memcpy(result, region->start() + start + PrefixLength, length - PrefixLength); result[length - PrefixLength] = 0; break; } start += length; } region->dispose(); } finder->dispose(); system->dispose(); return result; } void usageAndExit(const char* name) { fprintf (stderr, "usage: %s\n" "\t[{-cp|-classpath} ]\n" "\t[-Xmx]\n" "\t[-Xss]\n" "\t[-Xbootclasspath/p:]\n" "\t[-Xbootclasspath:]\n" "\t[-Xbootclasspath/a:]\n" "\t[-D= ...]\n" "\t{|-jar } [ ...]\n", name); exit(-1); } } // namespace int main(int ac, const char** av) { JavaVMInitArgs vmArgs; vmArgs.version = JNI_VERSION_1_2; vmArgs.nOptions = 1; vmArgs.ignoreUnrecognized = JNI_TRUE; const char* class_ = 0; const char* jar = 0; int argc = 0; const char** argv = 0; const char* classpath = "."; for (int i = 1; i < ac; ++i) { if (strcmp(av[i], "-cp") == 0 or strcmp(av[i], "-classpath") == 0) { if (i + 1 == ac) usageAndExit(av[0]); classpath = av[++i]; } else if (strcmp(av[i], "-jar") == 0) { if (i + 1 == ac) usageAndExit(av[0]); jar = av[++i]; } else if (strncmp(av[i], "-X", 2) == 0 or strncmp(av[i], "-D", 2) == 0) { ++ vmArgs.nOptions; } else if (strcmp(av[i], "-client") == 0 or strcmp(av[i], "-server") == 0) { // ignore } else { if (jar == 0) { class_ = av[i++]; } if (i < ac) { argc = ac - i; argv = av + i; i = ac; } } } if (jar) { classpath = jar; class_ = mainClass(jar); if (class_ == 0) { fprintf(stderr, "Main-Class manifest header not found in %s\n", jar); exit(-1); } } #ifdef BOOT_LIBRARY ++ vmArgs.nOptions; #endif #ifdef BOOT_IMAGE vmArgs.nOptions += 2; #endif #ifdef BOOT_BUILTINS ++ vmArgs.nOptions; #endif RUNTIME_ARRAY(JavaVMOption, options, vmArgs.nOptions); vmArgs.options = RUNTIME_ARRAY_BODY(options); unsigned optionIndex = 0; #ifdef BOOT_IMAGE vmArgs.options[optionIndex++].optionString = const_cast("-Davian.bootimage=bootimageBin"); vmArgs.options[optionIndex++].optionString = const_cast("-Davian.codeimage=codeimageBin"); #endif #ifdef BOOT_LIBRARY vmArgs.options[optionIndex++].optionString = const_cast("-Davian.bootstrap=" BOOT_LIBRARY); #endif #ifdef BOOT_BUILTINS vmArgs.options[optionIndex++].optionString = const_cast("-Davian.builtins=" BOOT_BUILTINS); #endif #define CLASSPATH_PROPERTY "-Djava.class.path=" unsigned classpathSize = strlen(classpath); unsigned classpathPropertyBufferSize = sizeof(CLASSPATH_PROPERTY) + classpathSize; RUNTIME_ARRAY(char, classpathPropertyBuffer, classpathPropertyBufferSize); memcpy(RUNTIME_ARRAY_BODY(classpathPropertyBuffer), CLASSPATH_PROPERTY, sizeof(CLASSPATH_PROPERTY) - 1); memcpy(RUNTIME_ARRAY_BODY(classpathPropertyBuffer) + sizeof(CLASSPATH_PROPERTY) - 1, classpath, classpathSize + 1); vmArgs.options[optionIndex++].optionString = RUNTIME_ARRAY_BODY(classpathPropertyBuffer); for (int i = 1; i < ac; ++i) { if (strncmp(av[i], "-X", 2) == 0 or strncmp(av[i], "-D", 2) == 0) { vmArgs.options[optionIndex++].optionString = const_cast(av[i]); } } if (class_ == 0) { usageAndExit(av[0]); } JavaVM* vm; void* env; JNI_CreateJavaVM(&vm, &env, &vmArgs); JNIEnv* e = static_cast(env); jclass c = 0; if (not e->ExceptionCheck()) { c = e->FindClass(class_); } if (jar) { free(const_cast(class_)); } if (not e->ExceptionCheck()) { jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); if (not e->ExceptionCheck()) { jclass stringClass = e->FindClass("java/lang/String"); if (not e->ExceptionCheck()) { jobjectArray a = e->NewObjectArray(argc, stringClass, 0); if (not e->ExceptionCheck()) { for (int i = 0; i < argc; ++i) { e->SetObjectArrayElement(a, i, e->NewStringUTF(argv[i])); } e->CallStaticVoidMethod(c, m, a); } } } } int exitCode = 0; if (e->ExceptionCheck()) { exitCode = -1; e->ExceptionDescribe(); } vm->DestroyJavaVM(); return exitCode; } ReadyTalk-avian-1e1fff5/src/openjdk/000077500000000000000000000000001231440243200174015ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/openjdk/caseSensitive/000077500000000000000000000000001231440243200222065ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/openjdk/caseSensitive/WS2tcpip.h000066400000000000000000000000261231440243200240300ustar00rootroot00000000000000#include "ws2tcpip.h" ReadyTalk-avian-1e1fff5/src/openjdk/caseSensitive/Wincon.h000066400000000000000000000002201231440243200236060ustar00rootroot00000000000000// Console_md.c #includes "Wincon.h", which only matches "wincon.h" on // a case insensive filesystem, so we redirect here. #include "wincon.h" ReadyTalk-avian-1e1fff5/src/openjdk/jni_md.h000066400000000000000000000015221231440243200210120ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef JNI_MD_H #define JNI_MD_H #include "stdint.h" #if (defined __MINGW32__) || (defined _MSC_VER) # define JNIEXPORT __declspec(dllexport) # define JNICALL __stdcall #else // not (defined __MINGW32__) || (defined _MSC_VER) # define JNIEXPORT __attribute__ ((visibility("default"))) \ __attribute__ ((used)) # define JNICALL #endif // not (defined __MINGW32__) || (defined _MSC_VER) #define JNIIMPORT typedef int32_t jint; typedef int64_t jlong; typedef int8_t jbyte; #endif//JNI_MD_H ReadyTalk-avian-1e1fff5/src/openjdk/my_java_props_macosx.c000066400000000000000000000005371231440243200237750ustar00rootroot00000000000000#include "java_props_macosx.h" PreferredToolkit getPreferredToolkit() { return XToolkit; } void setOSNameAndVersion(java_props_t* props) { props->os_name = strdup("iOS"); props->os_version = strdup("Unknown"); } void setProxyProperties(java_props_t* props) { // ignore } char* setupMacOSXLocale(int cat) { return 0; } char* environ[0]; ReadyTalk-avian-1e1fff5/src/openjdk/my_management.c000066400000000000000000000001011231440243200223560ustar00rootroot00000000000000#define JNI_OnLoad management_JNI_OnLoad #include "management.c" ReadyTalk-avian-1e1fff5/src/openjdk/my_net_util.c000066400000000000000000000006061231440243200220770ustar00rootroot00000000000000#define JNI_OnLoad net_JNI_OnLoad #include "net_util.c" #ifdef _WIN32 #undef IN6_SET_ADDR_UNSPECIFIED #define IN6_SET_ADDR_UNSPECIFIED(a) \ memset((a)->s6_bytes,0,sizeof(struct in6_addr)) void IN6ADDR_SETANY(struct sockaddr_in6 *a) { a->sin6_family = AF_INET6; a->sin6_port = 0; a->sin6_flowinfo = 0; IN6_SET_ADDR_UNSPECIFIED(&a->sin6_addr); a->sin6_scope_id = 0; } #endif ReadyTalk-avian-1e1fff5/src/openjdk/stubs.cpp000066400000000000000000000004531231440243200212470ustar00rootroot00000000000000#include "avian/machine.h" using namespace vm; extern "C" AVIAN_EXPORT jint JNICALL net_JNI_OnLoad(JavaVM*, void*) { return 0; } extern "C" AVIAN_EXPORT jint JNICALL management_JNI_OnLoad(JavaVM*, void*) { return 0; } extern "C" char* findJavaTZ_md(const char*, const char*) { return 0; } ReadyTalk-avian-1e1fff5/src/powerpc-regs.S000066400000000000000000000016301231440243200205100ustar00rootroot00000000000000#define r0 0 #define r1 1 #define r2 2 #define r3 3 #define r4 4 #define r5 5 #define r6 6 #define r7 7 #define r8 8 #define r9 9 #define r10 10 #define r11 11 #define r12 12 #define r13 13 #define r14 14 #define r15 15 #define r16 16 #define r17 17 #define r18 18 #define r19 19 #define r20 20 #define r21 21 #define r22 22 #define r23 23 #define r24 24 #define r25 25 #define r26 26 #define r27 27 #define r28 28 #define r29 29 #define r30 30 #define r31 31 #define f0 0 #define f1 1 #define f2 2 #define f3 3 #define f4 4 #define f5 5 #define f6 6 #define f7 7 #define f8 8 #define f9 9 #define f10 10 #define f11 11 #define f12 12 #define f13 13 #define f14 14 #define f15 15 #define f16 16 #define f17 17 #define f18 18 #define f19 19 #define f20 20 #define f21 21 #define f22 22 #define f23 23 #define f24 24 #define f25 25 #define f26 26 #define f27 27 #define f28 28 #define f29 29 #define f30 30 #define f31 31 ReadyTalk-avian-1e1fff5/src/powerpc.S000066400000000000000000000126771231440243200175670ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/types.h" .text #define BYTES_PER_WORD 4 #define GPR_COUNT 8 #ifdef __APPLE__ # define GLOBAL(x) _##x # define LOCAL(x) L##x # define LINKAGE_AREA 6 # define MEMORY_BASE BYTES_PER_WORD * (LINKAGE_AREA + GPR_COUNT) # define RETURN_ADDRESS_OFFSET 8 #else # define GLOBAL(x) x # define LOCAL(x) .L##x # define LINKAGE_AREA 2 # define MEMORY_BASE BYTES_PER_WORD * LINKAGE_AREA # define RETURN_ADDRESS_OFFSET 4 # include "powerpc-regs.S" #endif .globl GLOBAL(vmNativeCall) GLOBAL(vmNativeCall): // save return address mflr r0 stw r0,RETURN_ADDRESS_OFFSET(r1) // r3 aka r13: function // r4 : stackTotal // r5 : memoryTable // r6 : memoryCount // r7 : memoryBase // r8 : gprTable // r9 : fprTable // r10 aka r14: returnType // r15 : stack frame size // r16 : temporary // r17 : temporary // r18 : temporary // allocate stack space, adding room for callee-saved registers and // scratch space for copying a FP return value into GPRs subfic r11,r4,-48 stwux r1,r1,r11 // save callee-saved registers used for local variables add r11,r4,r1 // save registers used for local variables stw r13,0(r11) stw r14,4(r11) stw r15,8(r11) stw r16,12(r11) stw r17,16(r11) stw r18,20(r11) stw r19,24(r11) // remember where we saved the local variables mr r19,r11 // save our argument registers so we can clobber them mr r13,r3 mr r14,r10 li r16,0 b LOCAL(test) LOCAL(loop): lwzx r17,r16,r5 add r18,r16,r7 stwx r17,r18,r1 addi r16,r16,BYTES_PER_WORD LOCAL(test): cmplw r16,r6 blt LOCAL(loop) // do we need to load the floating point registers? cmpwi r9,0 beq LOCAL(gpr) // yes, we do lfd f1,0(r9) lfd f2,8(r9) lfd f3,16(r9) lfd f4,24(r9) lfd f5,32(r9) lfd f6,40(r9) lfd f7,48(r9) lfd f8,56(r9) #ifdef __APPLE__ lfd f9,64(r9) lfd f10,72(r9) lfd f11,80(r9) lfd f12,88(r9) lfd f13,96(r9) #endif LOCAL(gpr): // do we need to load the general-purpose registers? cmpwi r8,0 beq LOCAL(call) // yes, we do mr r16,r8 lwz r3,0(r16) lwz r4,4(r16) lwz r5,8(r16) lwz r6,12(r16) lwz r7,16(r16) lwz r8,20(r16) lwz r9,24(r16) lwz r10,28(r16) LOCAL(call): // load and call function address mtctr r13 bctrl // handle return value based on expected type cmpwi r14,VOID_TYPE bne LOCAL(float) b LOCAL(exit) LOCAL(float): cmpwi r14,FLOAT_TYPE bne LOCAL(double) stfs f1,32(r19) lwz r4,32(r19) b LOCAL(exit) LOCAL(double): cmpwi r14,DOUBLE_TYPE bne LOCAL(int64) stfd f1,32(r19) lwz r3,32(r19) lwz r4,36(r19) b LOCAL(exit) LOCAL(int64): cmpwi r14,INT64_TYPE beq LOCAL(exit) mr r4,r3 b LOCAL(exit) LOCAL(copy): // move floating point return value to GPRs via memory stfd f1,32(r19) lwz r3,32(r19) lwz r4,36(r19) b LOCAL(exit) LOCAL(exit): // restore callee-saved registers used for local variables lwz r13,0(r19) lwz r14,4(r19) lwz r15,8(r19) lwz r16,12(r19) lwz r17,16(r19) lwz r18,20(r19) lwz r19,24(r19) // restore stack pointer lwz r1,0(r1) // load return address lwz r0,RETURN_ADDRESS_OFFSET(r1) mtlr r0 // return blr .globl GLOBAL(vmJump) GLOBAL(vmJump): mtlr r3 mr r1,r5 mr r13,r6 mr r4,r7 mr r3,r8 blr #define CHECKPOINT_THREAD 4 #define CHECKPOINT_STACK 24 .globl GLOBAL(vmRun) GLOBAL(vmRun): // r3: function // r4: arguments // r5: checkpoint mflr r0 stw r0,RETURN_ADDRESS_OFFSET(r1) stwu r1,-(MEMORY_BASE+88)(r1) stw r13,MEMORY_BASE+0(r1) stw r14,MEMORY_BASE+4(r1) stw r15,MEMORY_BASE+8(r1) stw r16,MEMORY_BASE+12(r1) stw r17,MEMORY_BASE+16(r1) stw r18,MEMORY_BASE+20(r1) stw r19,MEMORY_BASE+24(r1) stw r20,MEMORY_BASE+28(r1) stw r21,MEMORY_BASE+32(r1) stw r22,MEMORY_BASE+36(r1) stw r23,MEMORY_BASE+40(r1) stw r24,MEMORY_BASE+44(r1) stw r25,MEMORY_BASE+48(r1) stw r26,MEMORY_BASE+52(r1) stw r27,MEMORY_BASE+56(r1) stw r28,MEMORY_BASE+60(r1) stw r29,MEMORY_BASE+64(r1) stw r30,MEMORY_BASE+68(r1) stw r31,MEMORY_BASE+72(r1) stw r1,CHECKPOINT_STACK(r5) mr r6,r3 lwz r3,CHECKPOINT_THREAD(r5) mtctr r6 bctrl .globl GLOBAL(vmRun_returnAddress) GLOBAL(vmRun_returnAddress): lwz r13,MEMORY_BASE+0(r1) lwz r14,MEMORY_BASE+4(r1) lwz r15,MEMORY_BASE+8(r1) lwz r16,MEMORY_BASE+12(r1) lwz r17,MEMORY_BASE+16(r1) lwz r18,MEMORY_BASE+20(r1) lwz r19,MEMORY_BASE+24(r1) lwz r20,MEMORY_BASE+28(r1) lwz r21,MEMORY_BASE+32(r1) lwz r22,MEMORY_BASE+36(r1) lwz r23,MEMORY_BASE+40(r1) lwz r24,MEMORY_BASE+44(r1) lwz r25,MEMORY_BASE+48(r1) lwz r26,MEMORY_BASE+52(r1) lwz r27,MEMORY_BASE+56(r1) lwz r28,MEMORY_BASE+60(r1) lwz r29,MEMORY_BASE+64(r1) lwz r30,MEMORY_BASE+68(r1) lwz r31,MEMORY_BASE+72(r1) lwz r1,0(r1) lwz r0,RETURN_ADDRESS_OFFSET(r1) mtlr r0 blr ReadyTalk-avian-1e1fff5/src/process.cpp000066400000000000000000000161321231440243200201340ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/process.h" #include using namespace vm; namespace { unsigned mangledSize(int8_t c) { switch (c) { case '_': case ';': case '[': return 2; case '$': return 6; default: return 1; } } unsigned mangle(int8_t c, char* dst) { switch (c) { case '/': dst[0] = '_'; return 1; case '_': dst[0] = '_'; dst[1] = '1'; return 2; case ';': dst[0] = '_'; dst[1] = '2'; return 2; case '[': dst[0] = '_'; dst[1] = '3'; return 2; case '$': memcpy(dst, "_00024", 6); return 6; default: dst[0] = c; return 1; } } unsigned jniNameLength(Thread* t, object method, bool decorate) { unsigned size = 0; object className = ::className(t, methodClass(t, method)); for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) { size += mangledSize(byteArrayBody(t, className, i)); } ++ size; object methodName = ::methodName(t, method); for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) { size += mangledSize(byteArrayBody(t, methodName, i)); } if (decorate) { size += 2; object methodSpec = ::methodSpec(t, method); for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1 and byteArrayBody(t, methodSpec, i) != ')'; ++i) { size += mangledSize(byteArrayBody(t, methodSpec, i)); } } return size; } void makeJNIName(Thread* t, const char* prefix, unsigned prefixLength, char* name, object method, bool decorate) { memcpy(name, prefix, prefixLength); name += prefixLength; object className = ::className(t, methodClass(t, method)); for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) { name += mangle(byteArrayBody(t, className, i), name); } *(name++) = '_'; object methodName = ::methodName(t, method); for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) { name += mangle(byteArrayBody(t, methodName, i), name); } if (decorate) { *(name++) = '_'; *(name++) = '_'; object methodSpec = ::methodSpec(t, method); for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1 and byteArrayBody(t, methodSpec, i) != ')'; ++i) { name += mangle(byteArrayBody(t, methodSpec, i), name); } } *(name++) = 0; } void* resolveNativeMethod(Thread* t, const char* undecorated, const char* decorated) { for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) { void* p = lib->resolve(undecorated); if (p) { return p; } else { p = lib->resolve(decorated); if (p) { return p; } } } return 0; } void* resolveNativeMethod(Thread* t, object method, const char* prefix, unsigned prefixLength, int footprint UNUSED) { unsigned undecoratedSize = prefixLength + jniNameLength(t, method, false); // extra 6 is for code below: THREAD_RUNTIME_ARRAY(t, char, undecorated, undecoratedSize + 1 + 6); makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(undecorated) + 1, method, false); unsigned decoratedSize = prefixLength + jniNameLength(t, method, true); // extra 6 is for code below: THREAD_RUNTIME_ARRAY(t, char, decorated, decoratedSize + 1 + 6); makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(decorated) + 1, method, true); void* p = resolveNativeMethod(t, RUNTIME_ARRAY_BODY(undecorated) + 1, RUNTIME_ARRAY_BODY(decorated) + 1); if (p) { return p; } #ifdef PLATFORM_WINDOWS // on windows, we also try the _%s@%d and %s@%d variants if (footprint == -1) { footprint = methodParameterFootprint(t, method) + 1; if (methodFlags(t, method) & ACC_STATIC) { ++ footprint; } } *RUNTIME_ARRAY_BODY(undecorated) = '_'; vm::snprintf(RUNTIME_ARRAY_BODY(undecorated) + undecoratedSize + 1, 5, "@%d", footprint * BytesPerWord); *RUNTIME_ARRAY_BODY(decorated) = '_'; vm::snprintf(RUNTIME_ARRAY_BODY(decorated) + decoratedSize + 1, 5, "@%d", footprint * BytesPerWord); p = resolveNativeMethod(t, RUNTIME_ARRAY_BODY(undecorated), RUNTIME_ARRAY_BODY(decorated)); if (p) { return p; } // one more try without the leading underscore p = resolveNativeMethod(t, RUNTIME_ARRAY_BODY(undecorated) + 1, RUNTIME_ARRAY_BODY(decorated) + 1); if (p) { return p; } #endif return 0; } object resolveNativeMethod(Thread* t, object method) { void* p = resolveNativeMethod(t, method, "Avian_", 6, 3); if (p) { return makeNative(t, p, true); } p = resolveNativeMethod(t, method, "Java_", 5, -1); if (p) { return makeNative(t, p, false); } return 0; } } // namespace namespace vm { void resolveNative(Thread* t, object method) { PROTECT(t, method); assert(t, methodFlags(t, method) & ACC_NATIVE); initClass(t, methodClass(t, method)); if (methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0) { object native = resolveNativeMethod(t, method); if (UNLIKELY(native == 0)) { throwNew(t, Machine::UnsatisfiedLinkErrorType, "%s.%s%s", &byteArrayBody(t, className(t, methodClass(t, method)), 0), &byteArrayBody(t, methodName(t, method), 0), &byteArrayBody(t, methodSpec(t, method), 0)); } PROTECT(t, native); object runtimeData = getMethodRuntimeData(t, method); // ensure other threads only see the methodRuntimeDataNative field // populated once the object it points to has been populated: storeStoreMemoryBarrier(); set(t, runtimeData, MethodRuntimeDataNative, native); } } int findLineNumber(Thread* t, object method, unsigned ip) { if (methodFlags(t, method) & ACC_NATIVE) { return NativeLine; } // our parameter indicates the instruction following the one we care // about, so we back up first: -- ip; object code = methodCode(t, method); object lnt = codeLineNumberTable(t, code); if (lnt) { unsigned bottom = 0; unsigned top = lineNumberTableLength(t, lnt); for (unsigned span = top - bottom; span; span = top - bottom) { unsigned middle = bottom + (span / 2); uint64_t ln = lineNumberTableBody(t, lnt, middle); if (ip >= lineNumberIp(ln) and (middle + 1 == lineNumberTableLength(t, lnt) or ip < lineNumberIp(lineNumberTableBody(t, lnt, middle + 1)))) { return lineNumberLine(ln); } else if (ip < lineNumberIp(ln)) { top = middle; } else if (ip > lineNumberIp(ln)) { bottom = middle + 1; } } if (top < lineNumberTableLength(t, lnt)) { return lineNumberLine(lineNumberTableBody(t, lnt, top)); } else { return UnknownLine; } } else { return UnknownLine; } } } // namespace vm ReadyTalk-avian-1e1fff5/src/system/000077500000000000000000000000001231440243200172735ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/system/posix.cpp000066400000000000000000000524441231440243200211520ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef __STDC_CONSTANT_MACROS # define __STDC_CONSTANT_MACROS #endif #include "sys/types.h" #ifdef __APPLE__ # include "CoreFoundation/CoreFoundation.h" # include "sys/ucontext.h" # undef assert #elif defined(__ANDROID__) # include /* for sigcontext */ # include /* for stack_t */ typedef struct ucontext { unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; struct sigcontext uc_mcontext; unsigned long uc_sigmask; } ucontext_t; #else # if defined __FreeBSD__ # include "limits.h" # endif # include "ucontext.h" #endif #include "sys/mman.h" #include "sys/stat.h" #include "sys/time.h" #include "time.h" #include "fcntl.h" #include "dlfcn.h" #include "errno.h" #include "unistd.h" #include "pthread.h" #include "signal.h" #include "stdint.h" #include "dirent.h" #include "sched.h" #include #include #include #include #include #define ACQUIRE(x) MutexResource MAKE_NAME(mutexResource_) (x) using namespace vm; using namespace avian::util; namespace { class MutexResource { public: MutexResource(pthread_mutex_t& m): m(&m) { pthread_mutex_lock(&m); } ~MutexResource() { pthread_mutex_unlock(m); } private: pthread_mutex_t* m; }; const int VisitSignal = SIGUSR1; const unsigned VisitSignalIndex = 0; const int InterruptSignal = SIGUSR2; const unsigned InterruptSignalIndex = 1; const int PipeSignal = SIGPIPE; const unsigned PipeSignalIndex = 2; const int signals[] = {VisitSignal, InterruptSignal, PipeSignal}; const unsigned SignalCount = 3; class MySystem; MySystem* system; void handleSignal(int signal, siginfo_t* info, void* context); void* run(void* r) { static_cast(r)->run(); return 0; } void pathOfExecutable(System* s, const char** retBuf, unsigned* size) { #ifdef __APPLE__ CFBundleRef bundle = CFBundleGetMainBundle(); CFURLRef url = CFBundleCopyExecutableURL(bundle); CFStringRef path = CFURLCopyPath(url); path = CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, path, CFSTR("")); CFIndex pathSize = CFStringGetMaximumSizeOfFileSystemRepresentation(path); char* buffer = reinterpret_cast(allocate(s, pathSize)); if (CFStringGetFileSystemRepresentation(path, buffer, pathSize)) { *size = pathSize; *retBuf = buffer; } else { abort(); } #else if (s) *size = 0; *retBuf = NULL; #endif } const bool Verbose = false; const unsigned Notified = 1 << 0; class MySystem: public System { public: class Thread: public System::Thread { public: Thread(System* s, System::Runnable* r): s(s), r(r), next(0), flags(0) { pthread_mutex_init(&mutex, 0); pthread_cond_init(&condition, 0); } virtual void interrupt() { ACQUIRE(mutex); r->setInterrupted(true); pthread_kill(thread, InterruptSignal); // pthread_kill won't necessarily wake a thread blocked in // pthread_cond_{timed}wait (it does on Linux but not Mac OS), // so we signal the condition as well: int rv UNUSED = pthread_cond_signal(&condition); expect(s, rv == 0); } virtual bool getAndClearInterrupted() { ACQUIRE(mutex); bool interrupted = r->interrupted(); r->setInterrupted(false); return interrupted; } virtual void join() { int rv UNUSED = pthread_join(thread, 0); expect(s, rv == 0); } virtual void dispose() { pthread_mutex_destroy(&mutex); pthread_cond_destroy(&condition); ::free(this); } pthread_t thread; pthread_mutex_t mutex; pthread_cond_t condition; System* s; System::Runnable* r; Thread* next; unsigned flags; }; class Mutex: public System::Mutex { public: Mutex(System* s): s(s) { pthread_mutex_init(&mutex, 0); } virtual void acquire() { pthread_mutex_lock(&mutex); } virtual void release() { pthread_mutex_unlock(&mutex); } virtual void dispose() { pthread_mutex_destroy(&mutex); ::free(this); } System* s; pthread_mutex_t mutex; }; class Monitor: public System::Monitor { public: Monitor(System* s): s(s), owner_(0), first(0), last(0), depth(0) { pthread_mutex_init(&mutex, 0); } virtual bool tryAcquire(System::Thread* context) { Thread* t = static_cast(context); if (owner_ == t) { ++ depth; return true; } else { switch (pthread_mutex_trylock(&mutex)) { case EBUSY: return false; case 0: owner_ = t; ++ depth; return true; default: sysAbort(s); } } } virtual void acquire(System::Thread* context) { Thread* t = static_cast(context); if (owner_ != t) { pthread_mutex_lock(&mutex); owner_ = t; } ++ depth; } virtual void release(System::Thread* context) { Thread* t = static_cast(context); if (owner_ == t) { if (-- depth == 0) { owner_ = 0; pthread_mutex_unlock(&mutex); } } else { sysAbort(s); } } void append(Thread* t) { #ifndef NDEBUG for (Thread* x = first; x; x = x->next) { expect(s, t != x); } #endif if (last) { expect(s, t != last); last->next = t; last = t; } else { first = last = t; } } void remove(Thread* t) { Thread* previous = 0; for (Thread* current = first; current;) { if (t == current) { if (current == first) { first = t->next; } else { expect(s, previous != t->next); previous->next = t->next; } if (current == last) { last = previous; } t->next = 0; break; } else { previous = current; current = current->next; } } #ifndef NDEBUG for (Thread* x = first; x; x = x->next) { expect(s, t != x); } #endif } virtual void wait(System::Thread* context, int64_t time) { wait(context, time, false); } virtual bool waitAndClearInterrupted(System::Thread* context, int64_t time) { return wait(context, time, true); } bool wait(System::Thread* context, int64_t time, bool clearInterrupted) { Thread* t = static_cast(context); if (owner_ == t) { // Initialized here to make gcc 4.2 a happy compiler bool interrupted = false; bool notified = false; unsigned depth = 0; { ACQUIRE(t->mutex); expect(s, (t->flags & Notified) == 0); interrupted = t->r->interrupted(); if (interrupted and clearInterrupted) { t->r->setInterrupted(false); } append(t); depth = this->depth; this->depth = 0; owner_ = 0; pthread_mutex_unlock(&mutex); if (not interrupted) { // pretend anything greater than one million years (in // milliseconds) is infinity so as to avoid overflow: if (time and time < INT64_C(31536000000000000)) { int64_t then = s->now() + time; timespec ts = { static_cast(then / 1000), static_cast((then % 1000) * 1000 * 1000) }; int rv UNUSED = pthread_cond_timedwait (&(t->condition), &(t->mutex), &ts); expect(s, rv == 0 or rv == ETIMEDOUT or rv == EINTR); } else { int rv UNUSED = pthread_cond_wait(&(t->condition), &(t->mutex)); expect(s, rv == 0 or rv == EINTR); } interrupted = t->r->interrupted(); if (interrupted and clearInterrupted) { t->r->setInterrupted(false); } } notified = ((t->flags & Notified) != 0); } pthread_mutex_lock(&mutex); { ACQUIRE(t->mutex); t->flags = 0; } if (not notified) { remove(t); } else { #ifndef NDEBUG for (Thread* x = first; x; x = x->next) { expect(s, t != x); } #endif } t->next = 0; owner_ = t; this->depth = depth; return interrupted; } else { sysAbort(s); } } void doNotify(Thread* t) { ACQUIRE(t->mutex); t->flags |= Notified; int rv UNUSED = pthread_cond_signal(&(t->condition)); expect(s, rv == 0); } virtual void notify(System::Thread* context) { Thread* t = static_cast(context); if (owner_ == t) { if (first) { Thread* t = first; first = first->next; if (t == last) { expect(s, first == 0); last = 0; } doNotify(t); } } else { sysAbort(s); } } virtual void notifyAll(System::Thread* context) { Thread* t = static_cast(context); if (owner_ == t) { for (Thread* t = first; t; t = t->next) { doNotify(t); } first = last = 0; } else { sysAbort(s); } } virtual System::Thread* owner() { return owner_; } virtual void dispose() { expect(s, owner_ == 0); pthread_mutex_destroy(&mutex); ::free(this); } System* s; pthread_mutex_t mutex; Thread* owner_; Thread* first; Thread* last; unsigned depth; }; class Local: public System::Local { public: Local(System* s): s(s) { int r UNUSED = pthread_key_create(&key, 0); expect(s, r == 0); } virtual void* get() { return pthread_getspecific(key); } virtual void set(void* p) { int r UNUSED = pthread_setspecific(key, p); expect(s, r == 0); } virtual void dispose() { int r UNUSED = pthread_key_delete(key); expect(s, r == 0); ::free(this); } System* s; pthread_key_t key; }; class Region: public System::Region { public: Region(System* s, uint8_t* start, size_t length): s(s), start_(start), length_(length) { } virtual const uint8_t* start() { return start_; } virtual size_t length() { return length_; } virtual void dispose() { if (start_) { munmap(start_, length_); } ::free(this); } System* s; uint8_t* start_; size_t length_; }; class Directory: public System::Directory { public: Directory(System* s, DIR* directory): s(s), directory(directory) { } virtual const char* next() { if (directory) { dirent* e = readdir(directory); if (e) { return e->d_name; } } return 0; } virtual void dispose() { if (directory) { closedir(directory); } ::free(this); } System* s; DIR* directory; }; class Library: public System::Library { public: Library(System* s, void* p, const char* name, unsigned nameLength, bool isMain): s(s), p(p), mainExecutable(isMain), name_(name), nameLength(nameLength), next_(0) { } virtual void* resolve(const char* function) { return dlsym(p, function); } virtual const char* name() { return name_; } virtual System::Library* next() { return next_; } virtual void setNext(System::Library* lib) { next_ = lib; } virtual void disposeAll() { if (Verbose) { fprintf(stderr, "close %p\n", p); } if (not mainExecutable) dlclose(p); if (next_) { next_->disposeAll(); } if (name_) { ::free(const_cast(name_)); } ::free(this); } System* s; void* p; bool mainExecutable; const char* name_; unsigned nameLength; System::Library* next_; }; MySystem(): threadVisitor(0), visitTarget(0) { expect(this, system == 0); system = this; expect(this, registerHandler(InterruptSignalIndex)); expect(this, registerHandler(VisitSignalIndex)); expect(this, registerHandler(PipeSignalIndex)); expect(this, make(&visitLock) == 0); } // Returns true on success, false on failure bool unregisterHandler(int index) { return sigaction(signals[index], oldHandlers + index, 0) == 0; } // Returns true on success, false on failure bool registerHandler(int index) { struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); sigemptyset(&(sa.sa_mask)); sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = handleSignal; return sigaction(signals[index], &sa, oldHandlers + index) == 0; } virtual void* tryAllocate(unsigned sizeInBytes) { return malloc(sizeInBytes); } virtual void free(const void* p) { if (p) ::free(const_cast(p)); } virtual void* tryAllocateExecutable(unsigned sizeInBytes) { #ifdef MAP_32BIT // map to the lower 32 bits of memory when possible so as to avoid // expensive relative jumps const unsigned Extra = MAP_32BIT; #else const unsigned Extra = 0; #endif void* p = mmap(0, sizeInBytes, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | Extra, -1, 0); if (p == MAP_FAILED) { return 0; } else { // fprintf(stderr, "executable from %p to %p\n", p, // static_cast(p) + sizeInBytes); return static_cast(p); } } virtual void freeExecutable(const void* p, unsigned sizeInBytes) { munmap(const_cast(p), sizeInBytes); } virtual bool success(Status s) { return s == 0; } virtual Status attach(Runnable* r) { Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r); t->thread = pthread_self(); r->attach(t); return 0; } virtual Status start(Runnable* r) { Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r); r->attach(t); int rv UNUSED = pthread_create(&(t->thread), 0, run, r); expect(this, rv == 0); return 0; } virtual Status make(System::Mutex** m) { *m = new (allocate(this, sizeof(Mutex))) Mutex(this); return 0; } virtual Status make(System::Monitor** m) { *m = new (allocate(this, sizeof(Monitor))) Monitor(this); return 0; } virtual Status make(System::Local** l) { *l = new (allocate(this, sizeof(Local))) Local(this); return 0; } virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, ThreadVisitor* visitor) { assert(this, st != sTarget); Thread* target = static_cast(sTarget); #ifdef __APPLE__ // On Mac OS, signals sent using pthread_kill are never delivered // if the target thread is blocked (e.g. acquiring a lock or // waiting on a condition), so we can't rely on it and must use // the Mach-specific thread execution API instead. mach_port_t port = pthread_mach_thread_np(target->thread); if (thread_suspend(port)) return -1; THREAD_STATE_TYPE state; mach_msg_type_number_t stateCount = THREAD_STATE_COUNT; kern_return_t rv = thread_get_state (port, THREAD_STATE, reinterpret_cast(&state), &stateCount); if (rv == 0) { visitor->visit(reinterpret_cast(THREAD_STATE_IP(state)), reinterpret_cast(THREAD_STATE_STACK(state)), reinterpret_cast(THREAD_STATE_LINK(state))); } thread_resume(port); return rv ? -1 : 0; #else // not __APPLE__ Thread* t = static_cast(st); ACQUIRE_MONITOR(t, visitLock); while (threadVisitor) visitLock->wait(t, 0); threadVisitor = visitor; visitTarget = target; int rv = pthread_kill(target->thread, VisitSignal); int result; if (rv == 0) { while (visitTarget) visitLock->wait(t, 0); result = 0; } else { visitTarget = 0; result = -1; } threadVisitor = 0; system->visitLock->notifyAll(t); return result; #endif // not __APPLE__ } virtual Status map(System::Region** region, const char* name) { Status status = 1; int fd = ::open(name, O_RDONLY); if (fd != -1) { struct stat s; int r = fstat(fd, &s); if (r != -1) { void* data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (data) { *region = new (allocate(this, sizeof(Region))) Region(this, static_cast(data), s.st_size); status = 0; } } close(fd); } return status; } virtual Status open(System::Directory** directory, const char* name) { Status status = 1; DIR* d = opendir(name); if (d) { *directory = new (allocate(this, sizeof(Directory))) Directory(this, d); status = 0; } return status; } virtual FileType stat(const char* name, unsigned* length) { #ifdef __FreeBSD__ // Now the hack below causes the error "Dereferencing type-punned // pointer will break strict aliasing rules", so another workaround // is needed... struct stat ss; struct stat* s = &ss; #else // Ugly Hack Alert: It seems that the Apple iOS Simulator's stat // implementation writes beyond the end of the struct stat we pass // it, which can clobber unrelated parts of the stack. Perhaps // this is due to some kind of header/library mismatch, but I've // been unable to track it down so far. The workaround is to give // it 8 words more than it should need, where 8 is a number I just // made up and seems to work. void* array[ceilingDivide(sizeof(struct stat), sizeof(void*)) + 8]; struct stat* s = reinterpret_cast(array); #endif int r = ::stat(name, s); if (r == 0) { if (S_ISREG(s->st_mode)) { *length = s->st_size; return TypeFile; } else if (S_ISDIR(s->st_mode)) { *length = 0; return TypeDirectory; } else { *length = 0; return TypeUnknown; } } else { *length = 0; return TypeDoesNotExist; } } virtual const char* libraryPrefix() { return SO_PREFIX; } virtual const char* librarySuffix() { return SO_SUFFIX; } virtual const char* toAbsolutePath(Allocator* allocator, const char* name) { if (name[0] == '/') { return copy(allocator, name); } else { char buffer[PATH_MAX]; return append(allocator, getcwd(buffer, PATH_MAX), "/", name); } } virtual Status load(System::Library** lib, const char* name) { unsigned nameLength = (name ? strlen(name) : 0); bool isMain = name == 0; if (isMain) { pathOfExecutable(this, &name, &nameLength); } void* p = dlopen(name, RTLD_LAZY | RTLD_LOCAL); if (p) { if (Verbose) { fprintf(stderr, "open %s as %p\n", name, p); } char* n; if (name) { n = static_cast(allocate(this, nameLength + 1)); memcpy(n, name, nameLength + 1); if (isMain) { free(name); } } else { n = 0; } *lib = new (allocate(this, sizeof(Library))) Library(this, p, n, nameLength, isMain); return 0; } else { if (Verbose) { fprintf(stderr, "dlerror opening %s: %s\n", name, dlerror()); } return 1; } } virtual char pathSeparator() { return ':'; } virtual char fileSeparator() { return '/'; } virtual int64_t now() { timeval tv = { 0, 0 }; gettimeofday(&tv, 0); return (static_cast(tv.tv_sec) * 1000) + (static_cast(tv.tv_usec) / 1000); } virtual void yield() { sched_yield(); } virtual void exit(int code) { ::exit(code); } virtual void abort() { avian::system::crash(); } virtual void dispose() { visitLock->dispose(); expect(this, unregisterHandler(InterruptSignalIndex)); expect(this, unregisterHandler(VisitSignalIndex)); expect(this, unregisterHandler(PipeSignalIndex)); system = 0; ::free(this); } struct sigaction oldHandlers[SignalCount]; ThreadVisitor* threadVisitor; Thread* visitTarget; System::Monitor* visitLock; }; void handleSignal(int signal, siginfo_t*, void* context) { ucontext_t* c = static_cast(context); void* ip = reinterpret_cast(IP_REGISTER(c)); void* stack = reinterpret_cast(STACK_REGISTER(c)); void* link = reinterpret_cast(LINK_REGISTER(c)); switch (signal) { case VisitSignal: { system->threadVisitor->visit(ip, stack, link); System::Thread* t = system->visitTarget; system->visitTarget = 0; ACQUIRE_MONITOR(t, system->visitLock); system->visitLock->notifyAll(t); } break; case InterruptSignal: case PipeSignal: break; default: abort(); } } } // namespace namespace vm { AVIAN_EXPORT System* makeSystem() { return new (malloc(sizeof(MySystem))) MySystem(); } } // namespace vm ReadyTalk-avian-1e1fff5/src/system/posix/000077500000000000000000000000001231440243200204355ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/system/posix/signal.cpp000066400000000000000000000122041231440243200224150ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "signal.h" #include "sys/types.h" #ifdef __APPLE__ #include "CoreFoundation/CoreFoundation.h" #include "sys/ucontext.h" #undef assert #elif defined(__ANDROID__) #include /* for sigcontext */ #include /* for stack_t */ typedef struct ucontext { unsigned long uc_flags; struct ucontext* uc_link; stack_t uc_stack; struct sigcontext uc_mcontext; unsigned long uc_sigmask; } ucontext_t; #else #if defined __FreeBSD__ #include "limits.h" #endif #include "ucontext.h" #endif #include "avian/arch.h" #include #include namespace avian { namespace system { namespace posix { const int InvalidSignal = -1; const int SegFaultSignal = SIGSEGV; const unsigned SegFaultSignalIndex = 0; #ifdef __APPLE__ const int AltSegFaultSignal = SIGBUS; #else const int AltSegFaultSignal = InvalidSignal; #endif const unsigned AltSegFaultSignalIndex = 1; const int DivideByZeroSignal = SIGFPE; const unsigned DivideByZeroSignalIndex = 2; const int signals[] = {SegFaultSignal, AltSegFaultSignal, DivideByZeroSignal}; const unsigned SignalCount = 3; } struct SignalRegistrar::Data { Handler* handlers[posix::SignalCount]; struct sigaction oldHandlers[posix::SignalCount]; bool registerHandler(Handler* handler, int index); Data() { if(instance) { crash(); } instance = this; } ~Data() { instance = 0; } static SignalRegistrar::Data* instance; }; SignalRegistrar::Data* SignalRegistrar::Data::instance = 0; namespace posix { using namespace vm; void handleSignal(int signal, siginfo_t*, void* context) { ucontext_t* c = static_cast(context); void* ip = reinterpret_cast(IP_REGISTER(c)); void* stack = reinterpret_cast(STACK_REGISTER(c)); void* thread = reinterpret_cast(THREAD_REGISTER(c)); #ifdef FRAME_REGISTER void* frame = reinterpret_cast(FRAME_REGISTER(c)); #else void* frame = 0; #endif unsigned index; switch (signal) { case SegFaultSignal: case AltSegFaultSignal: case DivideByZeroSignal: { switch (signal) { case SegFaultSignal: index = SegFaultSignalIndex; break; case AltSegFaultSignal: index = AltSegFaultSignalIndex; break; case DivideByZeroSignal: index = DivideByZeroSignalIndex; break; default: crash(); } bool jump = SignalRegistrar::Data::instance->handlers[index]->handleSignal(&ip, &frame, &stack, &thread); if (jump) { // I'd like to use setcontext here (and get rid of the // sigprocmask call), but it doesn't work on my Linux x86_64 // system, and I can't tell from the documentation if it's even // supposed to work. sigset_t set; sigemptyset(&set); sigaddset(&set, signal); pthread_sigmask(SIG_UNBLOCK, &set, 0); vmJump(ip, frame, stack, thread, 0, 0); } else { crash(); } } break; default: crash(); } } } // namespace posix NO_RETURN void crash() { abort(); } SignalRegistrar::SignalRegistrar() { data = new (malloc(sizeof(Data))) Data(); } SignalRegistrar::~SignalRegistrar() { data->~Data(); free(data); } bool SignalRegistrar::Data::registerHandler(Handler* handler, int index) { if (handler) { handlers[index] = handler; struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); sigemptyset(&(sa.sa_mask)); sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = posix::handleSignal; return sigaction(posix::signals[index], &sa, oldHandlers + index) == 0; } else if (handlers[index]) { handlers[index] = 0; return sigaction(posix::signals[index], oldHandlers + index, 0) == 0; } else { return false; } } bool SignalRegistrar::registerHandler(Signal signal, Handler* handler) { switch(signal) { case SegFault: if(!data->registerHandler(handler, posix::SegFaultSignalIndex)) { return false; } if (posix::AltSegFaultSignal != posix::InvalidSignal) { return data->registerHandler(handler, posix::AltSegFaultSignalIndex); } else { return true; } case DivideByZero: return data->registerHandler(handler, posix::DivideByZeroSignalIndex); default: crash(); } } bool SignalRegistrar::unregisterHandler(Signal signal) { switch(signal) { case SegFault: if(!data->registerHandler(0, posix::SegFaultSignalIndex)) { return false; } if (posix::AltSegFaultSignal != posix::InvalidSignal) { return data->registerHandler(0, posix::AltSegFaultSignalIndex); } else { return true; } case DivideByZero: return data->registerHandler(0, posix::DivideByZeroSignalIndex); default: crash(); } } void SignalRegistrar::setCrashDumpDirectory(const char*) { // Do nothing, not currently supported on posix } } // namespace system } // namespace avian ReadyTalk-avian-1e1fff5/src/system/windows.cpp000066400000000000000000000547221231440243200215030ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "sys/stat.h" #include "windows.h" #ifdef _MSC_VER # define S_ISREG(x) ((x) & _S_IFREG) # define S_ISDIR(x) ((x) & _S_IFDIR) # define FTIME _ftime_s #else # define FTIME _ftime #endif #undef max #undef min #include "avian/arch.h" #include #include #include #include #if defined(WINAPI_FAMILY) #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define WaitForSingleObject(hHandle, dwMilliseconds) \ WaitForSingleObjectEx((hHandle), (dwMilliseconds), FALSE) #define CreateEvent(lpEventAttributes, bManualReset, bInitialState, lpName) \ CreateEventEx((lpEventAttributes), (lpName), ((bManualReset)?CREATE_EVENT_MANUAL_RESET:0)|((bInitialState)?CREATE_EVENT_INITIAL_SET:0), EVENT_ALL_ACCESS) #define CreateMutex(lpEventAttributes, bInitialOwner, lpName) \ CreateMutexEx((lpEventAttributes), (lpName), (bInitialOwner)?CREATE_MUTEX_INITIAL_OWNER:0, MUTEX_ALL_ACCESS) #include "thread-emulation.h" #endif #if defined(WINAPI_PARTITION_PHONE) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE) // Headers in Windows Phone 8 DevKit contain severe error, so let's define needed functions on our own extern "C" { WINBASEAPI _Ret_maybenull_ HANDLE WINAPI CreateFileMappingFromApp( _In_ HANDLE hFile, _In_opt_ PSECURITY_ATTRIBUTES SecurityAttributes, _In_ ULONG PageProtection, _In_ ULONG64 MaximumSize, _In_opt_ PCWSTR Name ); WINBASEAPI _Ret_maybenull_ __out_data_source(FILE) PVOID WINAPI MapViewOfFileFromApp( _In_ HANDLE hFileMappingObject, _In_ ULONG DesiredAccess, _In_ ULONG64 FileOffset, _In_ SIZE_T NumberOfBytesToMap ); WINBASEAPI BOOL WINAPI UnmapViewOfFile( _In_ LPCVOID lpBaseAddress ); } #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE) #else #ifndef WINAPI_PARTITION_DESKTOP #define WINAPI_PARTITION_DESKTOP 1 #endif #ifndef WINAPI_FAMILY_PARTITION #define WINAPI_FAMILY_PARTITION(x) (x) #endif #endif #define ACQUIRE(s, x) MutexResource MAKE_NAME(mutexResource_) (s, x) using namespace vm; namespace { class MutexResource { public: MutexResource(System* s, HANDLE m): s(s), m(m) { int r UNUSED = WaitForSingleObject(m, INFINITE); assert(s, r == WAIT_OBJECT_0); } ~MutexResource() { bool success UNUSED = ReleaseMutex(m); assert(s, success); } private: System* s; HANDLE m; }; class MySystem; MySystem* system; #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) LONG CALLBACK handleException(LPEXCEPTION_POINTERS e); #endif DWORD WINAPI run(void* r) { static_cast(r)->run(); return 0; } const bool Verbose = false; const unsigned Waiting = 1 << 0; const unsigned Notified = 1 << 1; class MySystem: public System { public: class Thread: public System::Thread { public: Thread(System* s, System::Runnable* r): s(s), r(r), next(0), flags(0) { mutex = CreateMutex(0, false, 0); assert(s, mutex); event = CreateEvent(0, true, false, 0); assert(s, event); } virtual void interrupt() { ACQUIRE(s, mutex); r->setInterrupted(true); if (flags & Waiting) { int r UNUSED = SetEvent(event); assert(s, r != 0); } } virtual bool getAndClearInterrupted() { ACQUIRE(s, mutex); bool interrupted = r->interrupted(); r->setInterrupted(false); return interrupted; } virtual void join() { int r UNUSED = WaitForSingleObject(thread, INFINITE); assert(s, r == WAIT_OBJECT_0); } virtual void dispose() { CloseHandle(event); CloseHandle(mutex); CloseHandle(thread); ::free(this); } HANDLE thread; HANDLE mutex; HANDLE event; System* s; System::Runnable* r; Thread* next; unsigned flags; }; class Mutex: public System::Mutex { public: Mutex(System* s): s(s) { mutex = CreateMutex(0, false, 0); assert(s, mutex); } virtual void acquire() { int r UNUSED = WaitForSingleObject(mutex, INFINITE); assert(s, r == WAIT_OBJECT_0); } virtual void release() { bool success UNUSED = ReleaseMutex(mutex); assert(s, success); } virtual void dispose() { CloseHandle(mutex); ::free(this); } System* s; HANDLE mutex; }; class Monitor: public System::Monitor { public: Monitor(System* s): s(s), owner_(0), first(0), last(0), depth(0) { mutex = CreateMutex(0, false, 0); assert(s, mutex); } virtual bool tryAcquire(System::Thread* context) { Thread* t = static_cast(context); assert(s, t); if (owner_ == t) { ++ depth; return true; } else { switch (WaitForSingleObject(mutex, 0)) { case WAIT_TIMEOUT: return false; case WAIT_OBJECT_0: owner_ = t; ++ depth; return true; default: sysAbort(s); } } } virtual void acquire(System::Thread* context) { Thread* t = static_cast(context); assert(s, t); if (owner_ != t) { int r UNUSED = WaitForSingleObject(mutex, INFINITE); assert(s, r == WAIT_OBJECT_0); owner_ = t; } ++ depth; } virtual void release(System::Thread* context) { Thread* t = static_cast(context); assert(s, t); if (owner_ == t) { if (-- depth == 0) { owner_ = 0; bool success UNUSED = ReleaseMutex(mutex); assert(s, success); } } else { sysAbort(s); } } void append(Thread* t) { #ifndef NDEBUG for (Thread* x = first; x; x = x->next) { expect(s, t != x); } #endif if (last) { last->next = t; last = t; } else { first = last = t; } } void remove(Thread* t) { Thread* previous = 0; for (Thread* current = first; current;) { if (t == current) { if (current == first) { first = t->next; } else { previous->next = t->next; } if (current == last) { last = previous; } t->next = 0; break; } else { previous = current; current = current->next; } } #ifndef NDEBUG for (Thread* x = first; x; x = x->next) { expect(s, t != x); } #endif } virtual void wait(System::Thread* context, int64_t time) { wait(context, time, false); } virtual bool waitAndClearInterrupted(System::Thread* context, int64_t time) { return wait(context, time, true); } bool wait(System::Thread* context, int64_t time, bool clearInterrupted) { Thread* t = static_cast(context); assert(s, t); if (owner_ == t) { // Initialized here to make gcc 4.2 a happy compiler bool interrupted = false; bool notified = false; unsigned depth = 0; int r UNUSED; { ACQUIRE(s, t->mutex); expect(s, (t->flags & Notified) == 0); interrupted = t->r->interrupted(); if (interrupted and clearInterrupted) { t->r->setInterrupted(false); } t->flags |= Waiting; append(t); depth = this->depth; this->depth = 0; owner_ = 0; bool success UNUSED = ReleaseMutex(mutex); assert(s, success); if (not interrupted) { success = ResetEvent(t->event); assert(s, success); success = ReleaseMutex(t->mutex); assert(s, success); r = WaitForSingleObject(t->event, (time ? time : INFINITE)); assert(s, r == WAIT_OBJECT_0 or r == WAIT_TIMEOUT); r = WaitForSingleObject(t->mutex, INFINITE); assert(s, r == WAIT_OBJECT_0); interrupted = t->r->interrupted(); if (interrupted and clearInterrupted) { t->r->setInterrupted(false); } } notified = ((t->flags & Notified) != 0); } r = WaitForSingleObject(mutex, INFINITE); assert(s, r == WAIT_OBJECT_0); { ACQUIRE(s, t->mutex); t->flags = 0; } if (not notified) { remove(t); } else { #ifndef NDEBUG for (Thread* x = first; x; x = x->next) { expect(s, t != x); } #endif } t->next = 0; owner_ = t; this->depth = depth; return interrupted; } else { sysAbort(s); } } void doNotify(Thread* t) { ACQUIRE(s, t->mutex); t->flags |= Notified; bool success UNUSED = SetEvent(t->event); assert(s, success); } virtual void notify(System::Thread* context) { Thread* t = static_cast(context); assert(s, t); if (owner_ == t) { if (first) { Thread* t = first; first = first->next; if (t == last) { expect(s, first == 0); last = 0; } doNotify(t); } } else { sysAbort(s); } } virtual void notifyAll(System::Thread* context) { Thread* t = static_cast(context); assert(s, t); if (owner_ == t) { for (Thread* t = first; t; t = t->next) { doNotify(t); } first = last = 0; } else { sysAbort(s); } } virtual System::Thread* owner() { return owner_; } virtual void dispose() { assert(s, owner_ == 0); CloseHandle(mutex); ::free(this); } System* s; HANDLE mutex; Thread* owner_; Thread* first; Thread* last; unsigned depth; }; class Local: public System::Local { public: Local(System* s): s(s) { key = TlsAlloc(); assert(s, key != TLS_OUT_OF_INDEXES); } virtual void* get() { return TlsGetValue(key); } virtual void set(void* p) { bool r UNUSED = TlsSetValue(key, p); assert(s, r); } virtual void dispose() { bool r UNUSED = TlsFree(key); assert(s, r); ::free(this); } System* s; unsigned key; }; class Region: public System::Region { public: Region(System* system, uint8_t* start, size_t length, HANDLE mapping, HANDLE file): system(system), start_(start), length_(length), mapping(mapping), file(file) { } virtual const uint8_t* start() { return start_; } virtual size_t length() { return length_; } virtual void dispose() { if (start_) { if (start_) UnmapViewOfFile(start_); if (mapping) CloseHandle(mapping); if (file) CloseHandle(file); } system->free(this); } System* system; uint8_t* start_; size_t length_; HANDLE mapping; HANDLE file; }; class Directory: public System::Directory { public: Directory(System* s): s(s), handle(0), findNext(false) { } virtual const char* next() { if (handle and handle != INVALID_HANDLE_VALUE) { if (findNext) { if (FindNextFile(handle, &data)) { return data.cFileName; } } else { findNext = true; return data.cFileName; } } return 0; } virtual void dispose() { if (handle and handle != INVALID_HANDLE_VALUE) { FindClose(handle); } ::free(this); } System* s; HANDLE handle; WIN32_FIND_DATA data; bool findNext; }; class Library: public System::Library { public: Library(System* s, HMODULE handle, const char* name): s(s), handle(handle), name_(name), next_(0) { } virtual void* resolve(const char* function) { void* address; FARPROC p = GetProcAddress(handle, function); memcpy(&address, &p, BytesPerWord); return address; } virtual const char* name() { return name_; } virtual System::Library* next() { return next_; } virtual void setNext(System::Library* lib) { next_ = lib; } virtual void disposeAll() { if (Verbose) { fprintf(stderr, "close %p\n", handle); fflush(stderr); } if (name_) { FreeLibrary(handle); } if (next_) { next_->disposeAll(); } if (name_) { ::free(const_cast(name_)); } ::free(this); } System* s; HMODULE handle; const char* name_; System::Library* next_; }; MySystem() { expect(this, system == 0); system = this; mutex = CreateMutex(0, false, 0); assert(this, mutex); } virtual void* tryAllocate(unsigned sizeInBytes) { return malloc(sizeInBytes); } virtual void free(const void* p) { if (p) ::free(const_cast(p)); } #if !defined(AVIAN_AOT_ONLY) virtual void* tryAllocateExecutable(unsigned sizeInBytes) { return VirtualAlloc (0, sizeInBytes, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); } virtual void freeExecutable(const void* p, unsigned) { int r UNUSED = VirtualFree(const_cast(p), 0, MEM_RELEASE); assert(this, r); } #endif virtual bool success(Status s) { return s == 0; } virtual Status attach(Runnable* r) { Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r); bool success UNUSED = DuplicateHandle (GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &(t->thread), 0, false, DUPLICATE_SAME_ACCESS); assert(this, success); r->attach(t); return 0; } virtual Status start(Runnable* r) { Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r); r->attach(t); DWORD id; t->thread = CreateThread(0, 0, run, r, 0, &id); assert(this, t->thread); return 0; } virtual Status make(System::Mutex** m) { *m = new (allocate(this, sizeof(Mutex))) Mutex(this); return 0; } virtual Status make(System::Monitor** m) { *m = new (allocate(this, sizeof(Monitor))) Monitor(this); return 0; } virtual Status make(System::Local** l) { *l = new (allocate(this, sizeof(Local))) Local(this); return 0; } virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, ThreadVisitor* visitor) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) assert(this, st != sTarget); Thread* target = static_cast(sTarget); ACQUIRE(this, mutex); bool success = false; int rv = SuspendThread(target->thread); if (rv != -1) { CONTEXT context; memset(&context, 0, sizeof(CONTEXT)); context.ContextFlags = CONTEXT_CONTROL; rv = GetThreadContext(target->thread, &context); if (rv) { # ifdef ARCH_x86_32 visitor->visit(reinterpret_cast(context.Eip), reinterpret_cast(context.Esp), reinterpret_cast(context.Ebp)); # elif defined ARCH_x86_64 visitor->visit(reinterpret_cast(context.Rip), reinterpret_cast(context.Rsp), reinterpret_cast(context.Rbp)); # endif success = true; } rv = ResumeThread(target->thread); expect(this, rv != -1); } return (success ? 0 : 1); #else #pragma message("TODO: http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.application.unhandledexception(v=vs.105).aspx") return false; #endif } virtual Status map(System::Region** region, const char* name) { Status status = 1; size_t nameLen = strlen(name) * 2; RUNTIME_ARRAY(wchar_t, wideName, nameLen + 1); MultiByteToWideChar(CP_UTF8, 0, name, -1, RUNTIME_ARRAY_BODY(wideName), nameLen + 1); #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) HANDLE file = CreateFileW(RUNTIME_ARRAY_BODY(wideName), FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); #else HANDLE file = CreateFile2(RUNTIME_ARRAY_BODY(wideName), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0); #endif if (file != INVALID_HANDLE_VALUE) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) unsigned size = GetFileSize(file, 0); #else FILE_STANDARD_INFO info; unsigned size = INVALID_FILE_SIZE; if(GetFileInformationByHandleEx(file, FileStandardInfo, &info, sizeof(info))) size = info.EndOfFile.QuadPart; #endif if (size != INVALID_FILE_SIZE) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, size, 0); #else HANDLE mapping = CreateFileMappingFromApp(file, 0, PAGE_READONLY, size, 0); #endif if (mapping) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) void* data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); #else void* data = MapViewOfFileFromApp(mapping, FILE_MAP_READ, 0, 0); #endif if (data) { *region = new (allocate(this, sizeof(Region))) Region(this, static_cast(data), size, file, mapping); status = 0; } if (status) { CloseHandle(mapping); } } } if (status) { CloseHandle(file); } } return status; } virtual Status open(System::Directory** directory, const char* name) { Status status = 1; unsigned length = strlen(name); RUNTIME_ARRAY(char, buffer, length + 3); memcpy(RUNTIME_ARRAY_BODY(buffer), name, length); memcpy(RUNTIME_ARRAY_BODY(buffer) + length, "\\*", 3); Directory* d = new (allocate(this, sizeof(Directory))) Directory(this); #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) d->handle = FindFirstFile(RUNTIME_ARRAY_BODY(buffer), &(d->data)); #else d->handle = FindFirstFileEx(RUNTIME_ARRAY_BODY(buffer), FindExInfoStandard, &(d->data), FindExSearchNameMatch, 0, 0); #endif if (d->handle == INVALID_HANDLE_VALUE) { d->dispose(); } else { *directory = d; status = 0; } return status; } virtual FileType stat(const char* name, unsigned* length) { size_t nameLen = strlen(name) * 2; RUNTIME_ARRAY(wchar_t, wideName, nameLen + 1); MultiByteToWideChar(CP_UTF8, 0, name, -1, RUNTIME_ARRAY_BODY(wideName), nameLen + 1); WIN32_FILE_ATTRIBUTE_DATA data; if (GetFileAttributesExW (RUNTIME_ARRAY_BODY(wideName), GetFileExInfoStandard, &data)) { if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { return TypeDirectory; } else { *length = (data.nFileSizeHigh * static_cast(MAXDWORD + 1)) + data.nFileSizeLow; return TypeFile; } } else { return TypeDoesNotExist; } } virtual const char* libraryPrefix() { return SO_PREFIX; } virtual const char* librarySuffix() { return SO_SUFFIX; } virtual const char* toAbsolutePath(avian::util::Allocator* allocator, const char* name) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) if (strncmp(name, "//", 2) == 0 or strncmp(name, "\\\\", 2) == 0 or strncmp(name + 1, ":/", 2) == 0 or strncmp(name + 1, ":\\", 2) == 0) { return copy(allocator, name); } else { TCHAR buffer[MAX_PATH]; GetCurrentDirectory(MAX_PATH, buffer); return append(allocator, buffer, "\\", name); } #else #pragma message("TODO:http://lunarfrog.com/blog/2012/05/21/winrt-folders-access/ Windows.ApplicationModel.Package.Current.InstalledLocation") return copy(allocator, name); #endif } virtual Status load(System::Library** lib, const char* name) { HMODULE handle; unsigned nameLength = (name ? strlen(name) : 0); if (name) { size_t nameLen = nameLength * 2; RUNTIME_ARRAY(wchar_t, wideName, nameLen + 1); MultiByteToWideChar(CP_UTF8, 0, name, -1, RUNTIME_ARRAY_BODY(wideName), nameLen + 1); #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) handle = LoadLibraryW(RUNTIME_ARRAY_BODY(wideName)); #else handle = LoadPackagedLibrary(RUNTIME_ARRAY_BODY(wideName), 0); #endif } else { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) handle = GetModuleHandle(0); #else // Most of WinRT/WP8 applications can not host native object files inside main executable assert(this, false); #endif } if (handle) { if (Verbose) { fprintf(stderr, "open %s as %p\n", name, handle); fflush(stderr); } char* n; if (name) { n = static_cast(allocate(this, nameLength + 1)); memcpy(n, name, nameLength + 1); } else { n = 0; } *lib = new (allocate(this, sizeof(Library))) Library(this, handle, n); return 0; } else { if (Verbose) { fprintf(stderr, "unable to open %s: %ld\n", name, GetLastError()); fflush(stderr); } return 1; } } virtual char pathSeparator() { return ';'; } virtual char fileSeparator() { return '\\'; } virtual int64_t now() { // We used to use _ftime here, but that only gives us 1-second // resolution on Windows 7. _ftime_s might work better, but MinGW // doesn't have it as of this writing. So we use this mess instead: FILETIME time; GetSystemTimeAsFileTime(&time); return (((static_cast(time.dwHighDateTime) << 32) | time.dwLowDateTime) / 10000) - 11644473600000LL; } virtual void yield() { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) SwitchToThread(); #else YieldProcessor(); #endif } virtual void exit(int code) { ::exit(code); } virtual void abort() { avian::system::crash(); } virtual void dispose() { system = 0; CloseHandle(mutex); ::free(this); } HANDLE mutex; }; } // namespace namespace vm { AVIAN_EXPORT System* makeSystem() { return new (malloc(sizeof(MySystem))) MySystem(); } } // namespace vm ReadyTalk-avian-1e1fff5/src/system/windows/000077500000000000000000000000001231440243200207655ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/system/windows/signal.cpp000066400000000000000000000174601231440243200227560ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "windows.h" #include "sys/timeb.h" #ifdef _MSC_VER #define FTIME _ftime_s #else #define FTIME _ftime #endif #ifndef WINAPI_FAMILY #ifndef WINAPI_PARTITION_DESKTOP #define WINAPI_PARTITION_DESKTOP 1 #endif #ifndef WINAPI_FAMILY_PARTITION #define WINAPI_FAMILY_PARTITION(x) (x) #endif #endif #include #include namespace avian { namespace system { namespace windows { const unsigned HandlerCount = 2; } // namespace windows struct SignalRegistrar::Data { Handler* handlers[windows::HandlerCount]; const char* crashDumpDirectory; #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) LPTOP_LEVEL_EXCEPTION_FILTER oldHandler; #endif Data() : crashDumpDirectory(0), #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) oldHandler(0) #endif { if (instance) { crash(); } instance = this; memset(handlers, 0, sizeof(handlers)); } ~Data() { instance = 0; } bool registerHandler(Handler* handler, int index); bool findHandler() { for (unsigned i = 0; i < windows::HandlerCount; ++i) { if (handlers[i]) return true; } return false; } static SignalRegistrar::Data* instance; }; SignalRegistrar::Data* SignalRegistrar::Data::instance = 0; namespace windows { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #pragma pack(push, 4) struct MINIDUMP_EXCEPTION_INFORMATION { DWORD thread; LPEXCEPTION_POINTERS exception; BOOL exceptionInCurrentAddressSpace; }; #pragma pack(pop) struct MINIDUMP_USER_STREAM_INFORMATION; struct MINIDUMP_CALLBACK_INFORMATION; enum MINIDUMP_TYPE { MiniDumpNormal = 0, MiniDumpWithFullMemory = 2 }; typedef BOOL (*MiniDumpWriteDumpType)(HANDLE processHandle, DWORD processId, HANDLE file, MINIDUMP_TYPE type, const MINIDUMP_EXCEPTION_INFORMATION * exception, const MINIDUMP_USER_STREAM_INFORMATION * userStream, const MINIDUMP_CALLBACK_INFORMATION * callback); #endif void dump(LPEXCEPTION_POINTERS e, const char* directory) { HINSTANCE dbghelp = LoadLibrary("dbghelp.dll"); if (dbghelp) { MiniDumpWriteDumpType MiniDumpWriteDump = reinterpret_cast (GetProcAddress(dbghelp, "MiniDumpWriteDump")); if (MiniDumpWriteDump) { char name[MAX_PATH]; _timeb tb; FTIME(&tb); vm::snprintf(name, MAX_PATH, "%s\\crash-%" LLD ".mdmp", directory, (static_cast(tb.time) * 1000) + static_cast (tb.millitm)); HANDLE file = CreateFile(name, FILE_WRITE_DATA, 0, 0, CREATE_ALWAYS, 0, 0); if (file != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION exception = {GetCurrentThreadId(), e, true}; MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file, MiniDumpWithFullMemory, &exception, 0, 0); CloseHandle(file); } } FreeLibrary(dbghelp); } } LONG CALLBACK handleException(LPEXCEPTION_POINTERS e) { SignalRegistrar::Handler* handler = 0; if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { handler = SignalRegistrar::Data::instance->handlers[SignalRegistrar::SegFault]; } else if (e->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) { handler = SignalRegistrar::Data::instance->handlers[SignalRegistrar::DivideByZero]; } if (handler) { #ifdef ARCH_x86_32 void* ip = reinterpret_cast(e->ContextRecord->Eip); void* base = reinterpret_cast(e->ContextRecord->Ebp); void* stack = reinterpret_cast(e->ContextRecord->Esp); void* thread = reinterpret_cast(e->ContextRecord->Ebx); #elif defined ARCH_x86_64 void* ip = reinterpret_cast(e->ContextRecord->Rip); void* base = reinterpret_cast(e->ContextRecord->Rbp); void* stack = reinterpret_cast(e->ContextRecord->Rsp); void* thread = reinterpret_cast(e->ContextRecord->Rbx); #endif bool jump = handler->handleSignal(&ip, &base, &stack, &thread); #ifdef ARCH_x86_32 e->ContextRecord->Eip = reinterpret_cast(ip); e->ContextRecord->Ebp = reinterpret_cast(base); e->ContextRecord->Esp = reinterpret_cast(stack); e->ContextRecord->Ebx = reinterpret_cast(thread); #elif defined ARCH_x86_64 e->ContextRecord->Rip = reinterpret_cast(ip); e->ContextRecord->Rbp = reinterpret_cast(base); e->ContextRecord->Rsp = reinterpret_cast(stack); e->ContextRecord->Rbx = reinterpret_cast(thread); #endif if (jump) { return EXCEPTION_CONTINUE_EXECUTION; } else if (SignalRegistrar::Data::instance->crashDumpDirectory) { dump(e, SignalRegistrar::Data::instance->crashDumpDirectory); } } return EXCEPTION_CONTINUE_SEARCH; } } // namespace windows SignalRegistrar::SignalRegistrar() { data = new (malloc(sizeof(Data))) Data(); } SignalRegistrar::~SignalRegistrar() { data->~Data(); free(data); } bool SignalRegistrar::Data::registerHandler(Handler* handler, int index) { if(index != SegFault && index != DivideByZero) { crash(); } if (handler) { handlers[index] = handler; #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) if (oldHandler == 0) { #ifdef ARCH_x86_32 oldHandler = SetUnhandledExceptionFilter(windows::handleException); #elif defined ARCH_x86_64 AddVectoredExceptionHandler(1, windows::handleException); oldHandler = reinterpret_cast(1); #endif } #else #pragma message( \ "TODO: http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.application.unhandledexception(v=vs.105).aspx") #endif return true; } else if (handlers[index]) { handlers[index] = 0; if (not findHandler()) { #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #ifdef ARCH_x86_32 SetUnhandledExceptionFilter(oldHandler); oldHandler = 0; #elif defined ARCH_x86_64 // do nothing, handlers are never "unregistered" anyway #endif #else #pragma message( \ "TODO: http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.windows.application.unhandledexception(v=vs.105).aspx") #endif } return true; } else { return false; } } NO_RETURN void crash() { // trigger an EXCEPTION_ACCESS_VIOLATION, which we will catch and // generate a debug dump for *static_cast(0) = 0; // Some (all?) compilers don't realize that we can't possibly continue past // the above statement. abort(); } bool SignalRegistrar::registerHandler(Signal signal, Handler* handler) { return data->registerHandler(handler, signal); } bool SignalRegistrar::unregisterHandler(Signal signal) { return data->registerHandler(0, signal); } void SignalRegistrar::setCrashDumpDirectory(const char* crashDumpDirectory) { data->crashDumpDirectory = crashDumpDirectory; } } // namespace system } // namespace avian ReadyTalk-avian-1e1fff5/src/thunks.cpp000066400000000000000000000035001231440243200177650ustar00rootroot00000000000000THUNK(tryInitClass) THUNK(findInterfaceMethodFromInstance) THUNK(findInterfaceMethodFromInstanceAndReference) THUNK(findSpecialMethodFromReference) THUNK(findStaticMethodFromReference) THUNK(findVirtualMethodFromReference) THUNK(getMethodAddress) THUNK(compareDoublesG) THUNK(compareDoublesL) THUNK(compareFloatsG) THUNK(compareFloatsL) THUNK(compareLongs) THUNK(addDouble) THUNK(subtractDouble) THUNK(multiplyDouble) THUNK(divideDouble) THUNK(moduloDouble) THUNK(negateDouble) THUNK(squareRootDouble) THUNK(doubleToFloat) THUNK(doubleToInt) THUNK(doubleToLong) THUNK(addFloat) THUNK(subtractFloat) THUNK(multiplyFloat) THUNK(divideFloat) THUNK(moduloFloat) THUNK(negateFloat) THUNK(absoluteFloat) THUNK(absoluteLong) THUNK(absoluteInt) THUNK(divideLong) THUNK(divideInt) THUNK(moduloLong) THUNK(moduloInt) THUNK(floatToDouble) THUNK(floatToInt) THUNK(floatToLong) THUNK(intToDouble) THUNK(intToFloat) THUNK(longToDouble) THUNK(longToFloat) THUNK(makeBlankObjectArray) THUNK(makeBlankObjectArrayFromReference) THUNK(makeBlankArray) THUNK(lookUpAddress) THUNK(setMaybeNull) THUNK(acquireMonitorForObject) THUNK(acquireMonitorForObjectOnEntrance) THUNK(releaseMonitorForObject) THUNK(makeMultidimensionalArray) THUNK(makeMultidimensionalArrayFromReference) THUNK(throw_) THUNK(checkCast) THUNK(checkCastFromReference) THUNK(getStaticFieldValueFromReference) THUNK(getFieldValueFromReference) THUNK(setStaticFieldValueFromReference) THUNK(setFieldValueFromReference) THUNK(setStaticLongFieldValueFromReference) THUNK(setLongFieldValueFromReference) THUNK(setStaticObjectFieldValueFromReference) THUNK(setObjectFieldValueFromReference) THUNK(instanceOf64) THUNK(instanceOfFromReference) THUNK(makeNewGeneral64) THUNK(makeNew64) THUNK(makeNewFromReference) THUNK(set) THUNK(getJClass64) THUNK(getJClassFromReference) THUNK(gcIfNecessary) THUNK(idleIfNecessary) ReadyTalk-avian-1e1fff5/src/tools/000077500000000000000000000000001231440243200171075ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/tools/binary-to-object/000077500000000000000000000000001231440243200222575ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/tools/binary-to-object/main.cpp000066400000000000000000000070301231440243200237070ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include #include #ifdef WIN32 #include #else #include #include #endif #include #include extern "C" void __cxa_pure_virtual() { abort(); } void* operator new(size_t size) { return malloc(size); } void operator delete(void*) { abort(); } namespace { using namespace avian::tools; using namespace avian::util; bool writeObject(uint8_t* data, size_t size, OutputStream* out, const char* startName, const char* endName, const char* format, const char* architecture, unsigned alignment, bool writable, bool executable) { Platform* platform = Platform::getPlatform(PlatformInfo(PlatformInfo::formatFromString(format), PlatformInfo::archFromString(architecture))); if(!platform) { fprintf(stderr, "unsupported platform: %s/%s\n", format, architecture); return false; } SymbolInfo symbols[] = { SymbolInfo(0, startName), SymbolInfo(size, endName) }; unsigned accessFlags = (writable ? Platform::Writable : 0) | (executable ? Platform::Executable : 0); return platform->writeObject(out, Slice(symbols, 2), Slice(data, size), accessFlags, alignment); } void usageAndExit(const char* name) { fprintf(stderr, "usage: %s " " " "[ [{writable|executable}...]]\n", name); exit(-1); } } // namespace int main(int argc, const char** argv) { if (argc < 7 or argc > 10) { usageAndExit(argv[0]); } unsigned alignment = 1; if (argc > 7) { alignment = atoi(argv[7]); } bool writable = false; bool executable = false; for (int i = 8; i < argc; ++i) { if (strcmp("writable", argv[i]) == 0) { writable = true; } else if (strcmp("executable", argv[i]) == 0) { executable = true; } else { usageAndExit(argv[0]); } } uint8_t* data = 0; unsigned size; int fd = open(argv[1], O_RDONLY); if (fd != -1) { struct stat s; int r = fstat(fd, &s); if (r != -1) { #ifdef WIN32 HANDLE fm; HANDLE h = (HANDLE) _get_osfhandle (fd); fm = CreateFileMapping( h, NULL, PAGE_READONLY, 0, 0, NULL); data = static_cast(MapViewOfFile( fm, FILE_MAP_READ, 0, 0, s.st_size)); CloseHandle(fm); #else data = static_cast (mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0)); #endif size = s.st_size; } close(fd); } bool success = false; if (data) { FileOutputStream out(argv[2]); if (out.isValid()) { success = writeObject (data, size, &out, argv[3], argv[4], argv[5], argv[6], alignment, writable, executable); } else { fprintf(stderr, "unable to open %s\n", argv[2]); } #ifdef WIN32 UnmapViewOfFile(data); #else munmap(data, size); #endif } else { perror(argv[0]); } return (success ? 0 : -1); } ReadyTalk-avian-1e1fff5/src/tools/bootimage-generator/000077500000000000000000000000001231440243200230415ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/tools/bootimage-generator/main.cpp000066400000000000000000001634721231440243200245060ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include "avian/heapwalk.h" #include "avian/common.h" #include "avian/machine.h" #include "avian/util.h" #include #include #include #include "avian/target.h" #include #include #include "avian/lzma.h" #include #include // since we aren't linking against libstdc++, we must implement this // ourselves: extern "C" void __cxa_pure_virtual(void) { abort(); } using namespace vm; using namespace avian::tools; using namespace avian::util; using namespace avian::codegen; namespace { const unsigned HeapCapacity = 512 * 1024 * 1024; const unsigned TargetFixieSizeInBytes = 8 + (TargetBytesPerWord * 2); const unsigned TargetFixieSizeInWords = ceilingDivide (TargetFixieSizeInBytes, TargetBytesPerWord); const unsigned TargetFixieAge = 0; const unsigned TargetFixieFlags = 2; const unsigned TargetFixieSize = 4; const bool DebugNativeTarget = false; enum Type { Type_none, Type_pad, Type_object, Type_object_nogc, Type_int8_t, Type_uint8_t, Type_int16_t, Type_uint16_t, Type_int32_t, Type_uint32_t, Type_intptr_t, Type_uintptr_t, Type_int64_t, Type_int64_t_pad, Type_uint64_t, Type_float, Type_double, Type_double_pad, Type_word, Type_array }; class Field { public: Type type; unsigned buildOffset; unsigned buildSize; unsigned targetOffset; unsigned targetSize; }; void init(Field* f, Type type, unsigned buildOffset, unsigned buildSize, unsigned targetOffset, unsigned targetSize) { f->type = type; f->buildOffset = buildOffset; f->buildSize = buildSize; f->targetOffset = targetOffset; f->targetSize = targetSize; } class TypeMap { public: enum Kind { NormalKind, SingletonKind, PoolKind }; TypeMap(unsigned buildFixedSizeInWords, unsigned targetFixedSizeInWords, unsigned fixedFieldCount, Kind kind = NormalKind, unsigned buildArrayElementSizeInBytes = 0, unsigned targetArrayElementSizeInBytes = 0, Type arrayElementType = Type_none): buildFixedSizeInWords(buildFixedSizeInWords), targetFixedSizeInWords(targetFixedSizeInWords), fixedFieldCount(fixedFieldCount), buildArrayElementSizeInBytes(buildArrayElementSizeInBytes), targetArrayElementSizeInBytes(targetArrayElementSizeInBytes), arrayElementType(arrayElementType), kind(kind) { } uintptr_t* targetFixedOffsets() { return reinterpret_cast(this + 1); } Field* fixedFields() { return reinterpret_cast (targetFixedOffsets() + (buildFixedSizeInWords * BytesPerWord)); } static unsigned sizeInBytes(unsigned buildFixedSizeInWords, unsigned fixedFieldCount) { return sizeof(TypeMap) + (buildFixedSizeInWords * BytesPerWord * BytesPerWord) + (sizeof(Field) * fixedFieldCount); } unsigned buildFixedSizeInWords; unsigned targetFixedSizeInWords; unsigned fixedFieldCount; unsigned buildArrayElementSizeInBytes; unsigned targetArrayElementSizeInBytes; Type arrayElementType; Kind kind; }; // Notes on immutable references in the heap image: // // One of the advantages of a bootimage-based build is that reduces // the overhead of major GCs at runtime since we can avoid scanning // the pre-built heap image entirely. However, this only works if we // can ensure that no part of the heap image (with exceptions noted // below) ever points to runtime-allocated objects. Therefore (most) // references in the heap image are considered immutable, and any // attempt to update them at runtime will cause the process to abort. // // However, some references in the heap image really must be updated // at runtime: e.g. the static field table for each class. Therefore, // we allocate these as "fixed" objects, subject to mark-and-sweep // collection, instead of as "copyable" objects subject to copying // collection. This strategy avoids the necessity of maintaining // "dirty reference" bitsets at runtime for the entire heap image; // each fixed object has its own bitset specific to that object. // // In addition to the "fixed" object solution, there are other // strategies available to avoid attempts to update immutable // references at runtime: // // * Table-based: use a lazily-updated array or vector to associate // runtime data with heap image objects (see // e.g. getClassRuntimeData in machine.cpp). // // * Update references at build time: for example, we set the names // of primitive classes before generating the heap image so that we // need not populate them lazily at runtime. bool endsWith(const char* suffix, const char* s, unsigned length) { unsigned suffixLength = strlen(suffix); return length >= suffixLength and memcmp(suffix, s + (length - suffixLength), suffixLength) == 0; } object getNonStaticFields(Thread* t, object typeMaps, object c, object fields, unsigned* count, object* array) { PROTECT(t, typeMaps); PROTECT(t, c); PROTECT(t, fields); *array = hashMapFind(t, typeMaps, c, objectHash, objectEqual); if (*array) { *count += reinterpret_cast(&byteArrayBody(t, *array, 0)) ->fixedFieldCount; } else { if (classSuper(t, c)) { fields = getNonStaticFields (t, typeMaps, classSuper(t, c), fields, count, array); } if (classFieldTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classFieldTable(t, c)); ++i) { object field = arrayBody(t, classFieldTable(t, c), i); if ((fieldFlags(t, field) & ACC_STATIC) == 0) { ++ (*count); fields = vectorAppend(t, fields, field); } } } } return vectorAppend(t, fields, 0); } object allFields(Thread* t, object typeMaps, object c, unsigned* count, object* array) { PROTECT(t, typeMaps); PROTECT(t, c); object fields = makeVector(t, 0, 0); PROTECT(t, fields); *array = hashMapFind(t, typeMaps, c, objectHash, objectEqual); bool includeMembers; if (*array) { includeMembers = false; *count += reinterpret_cast(&byteArrayBody(t, *array, 0)) ->fixedFieldCount; } else { includeMembers = true; if (classSuper(t, c)) { fields = getNonStaticFields (t, typeMaps, classSuper(t, c), fields, count, array); } } if (classFieldTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classFieldTable(t, c)); ++i) { object field = arrayBody(t, classFieldTable(t, c), i); if (includeMembers or (fieldFlags(t, field) & ACC_STATIC)) { ++ (*count); fields = vectorAppend(t, fields, field); } } } return fields; } TypeMap* classTypeMap(Thread* t, object typeMaps, object p) { return reinterpret_cast (&byteArrayBody (t, hashMapFind(t, typeMaps, p, objectHash, objectEqual), 0)); } TypeMap* typeMap(Thread* t, object typeMaps, object p) { return reinterpret_cast (&byteArrayBody (t, objectClass(t, p) == type(t, Machine::SingletonType) ? hashMapFind(t, typeMaps, p, objectHash, objectEqual) : hashMapFind(t, typeMaps, objectClass(t, p), objectHash, objectEqual), 0)); } unsigned targetFieldOffset(Thread* t, object typeMaps, object field) { // if (strcmp(reinterpret_cast // (&byteArrayBody(t, className(t, fieldClass(t, field)), 0)), // "java/lang/Throwable") == 0) trap(); return ((fieldFlags(t, field) & ACC_STATIC) ? typeMap(t, typeMaps, classStaticTable(t, fieldClass(t, field))) : classTypeMap(t, typeMaps, fieldClass(t, field))) ->targetFixedOffsets()[fieldOffset(t, field)]; } object makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, const char* className, const char* methodName, const char* methodSpec, object typeMaps) { PROTECT(t, typeMaps); t->m->classpath->interceptMethods(t); object constants = 0; PROTECT(t, constants); object calls = 0; PROTECT(t, calls); object methods = 0; PROTECT(t, methods); DelayedPromise* addresses = 0; class MyOffsetResolver: public OffsetResolver { public: MyOffsetResolver(object* typeMaps): typeMaps(typeMaps) { } virtual unsigned fieldOffset(Thread* t, object field) { return targetFieldOffset(t, *typeMaps, field); } object* typeMaps; } resolver(&typeMaps); Finder* finder = static_cast (systemClassLoaderFinder(t, root(t, Machine::BootLoader))); for (Finder::Iterator it(finder); it.hasMore();) { unsigned nameSize = 0; const char* name = it.next(&nameSize); if (endsWith(".class", name, nameSize) and (className == 0 or strncmp(name, className, nameSize - 6) == 0)) { // fprintf(stderr, "pass 1 %.*s\n", nameSize - 6, name); object c = resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "%.*s", nameSize - 6, name), true); PROTECT(t, c); System::Region* region = finder->find(name); { THREAD_RESOURCE(t, System::Region*, region, region->dispose()); class Client: public Stream::Client { public: Client(Thread* t): t(t) { } virtual void NO_RETURN handleError() { abort(t); } private: Thread* t; } client(t); Stream s(&client, region->start(), region->length()); uint32_t magic = s.read4(); expect(t, magic == 0xCAFEBABE); s.read2(); // minor version s.read2(); // major version unsigned count = s.read2() - 1; if (count) { THREAD_RUNTIME_ARRAY(t, Type, types, count + 2); RUNTIME_ARRAY_BODY(types)[0] = Type_object; RUNTIME_ARRAY_BODY(types)[1] = Type_intptr_t; for (unsigned i = 2; i < count + 2; ++i) { switch (s.read1()) { case CONSTANT_Class: case CONSTANT_String: RUNTIME_ARRAY_BODY(types)[i] = Type_object; s.skip(2); break; case CONSTANT_Integer: case CONSTANT_Float: RUNTIME_ARRAY_BODY(types)[i] = Type_int32_t; s.skip(4); break; case CONSTANT_NameAndType: case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: RUNTIME_ARRAY_BODY(types)[i] = Type_object; s.skip(4); break; case CONSTANT_Long: RUNTIME_ARRAY_BODY(types)[i++] = Type_int64_t; RUNTIME_ARRAY_BODY(types)[i] = Type_int64_t_pad; s.skip(8); break; case CONSTANT_Double: RUNTIME_ARRAY_BODY(types)[i++] = Type_double; RUNTIME_ARRAY_BODY(types)[i] = Type_double_pad; s.skip(8); break; case CONSTANT_Utf8: RUNTIME_ARRAY_BODY(types)[i] = Type_object; s.skip(s.read2()); break; default: abort(t); } } object array = makeByteArray (t, TypeMap::sizeInBytes(count + 2, count + 2)); TypeMap* map = new (&byteArrayBody(t, array, 0)) TypeMap (count + 2, count + 2, count + 2, TypeMap::PoolKind); for (unsigned i = 0; i < count + 2; ++i) { expect(t, i < map->buildFixedSizeInWords); map->targetFixedOffsets()[i * BytesPerWord] = i * TargetBytesPerWord; init(new (map->fixedFields() + i) Field, RUNTIME_ARRAY_BODY(types)[i], i * BytesPerWord, BytesPerWord, i * TargetBytesPerWord, TargetBytesPerWord); } hashMapInsert (t, typeMaps, hashMapFind (t, root(t, Machine::PoolMap), c, objectHash, objectEqual), array, objectHash); } } { object array = 0; PROTECT(t, array); unsigned count = 0; object fields = allFields(t, typeMaps, c, &count, &array); PROTECT(t, fields); THREAD_RUNTIME_ARRAY(t, Field, memberFields, count + 1); unsigned memberIndex; unsigned buildMemberOffset; unsigned targetMemberOffset; if (array) { memberIndex = 0; buildMemberOffset = 0; targetMemberOffset = 0; TypeMap* map = reinterpret_cast (&byteArrayBody(t, array, 0)); for (unsigned j = 0; j < map->fixedFieldCount; ++j) { Field* f = map->fixedFields() + j; RUNTIME_ARRAY_BODY(memberFields)[memberIndex] = *f; targetMemberOffset = f->targetOffset + f->targetSize; ++ memberIndex; } } else { init(new (RUNTIME_ARRAY_BODY(memberFields)) Field, Type_object, 0, BytesPerWord, 0, TargetBytesPerWord); memberIndex = 1; buildMemberOffset = BytesPerWord; targetMemberOffset = TargetBytesPerWord; } const unsigned StaticHeader = 3; THREAD_RUNTIME_ARRAY(t, Field, staticFields, count + StaticHeader); init(new (RUNTIME_ARRAY_BODY(staticFields)) Field, Type_object, 0, BytesPerWord, 0, TargetBytesPerWord); init(new (RUNTIME_ARRAY_BODY(staticFields) + 1) Field, Type_intptr_t, BytesPerWord, BytesPerWord, TargetBytesPerWord, TargetBytesPerWord); init(new (RUNTIME_ARRAY_BODY(staticFields) + 2) Field, Type_object, BytesPerWord * 2, BytesPerWord, TargetBytesPerWord * 2, TargetBytesPerWord); unsigned staticIndex = StaticHeader; unsigned buildStaticOffset = BytesPerWord * StaticHeader; unsigned targetStaticOffset = TargetBytesPerWord * StaticHeader; for (unsigned i = 0; i < vectorSize(t, fields); ++i) { object field = vectorBody(t, fields, i); if (field) { unsigned buildSize = fieldSize(t, fieldCode(t, field)); unsigned targetSize = buildSize; Type type; switch (fieldCode(t, field)) { case ObjectField: type = Type_object; targetSize = TargetBytesPerWord; break; case ByteField: case BooleanField: type = Type_int8_t; break; case CharField: case ShortField: type = Type_int8_t; break; case FloatField: case IntField: type = Type_int32_t; break; case LongField: case DoubleField: type = Type_int64_t; break; default: abort(t); } if (fieldFlags(t, field) & ACC_STATIC) { targetStaticOffset = pad(targetStaticOffset, targetSize); buildStaticOffset = fieldOffset(t, field); init(new (RUNTIME_ARRAY_BODY(staticFields) + staticIndex) Field, type, buildStaticOffset, buildSize, targetStaticOffset, targetSize); targetStaticOffset += targetSize; ++ staticIndex; } else { targetMemberOffset = pad(targetMemberOffset, targetSize); buildMemberOffset = fieldOffset(t, field); init(new (RUNTIME_ARRAY_BODY(memberFields) + memberIndex) Field, type, buildMemberOffset, buildSize, targetMemberOffset, targetSize); targetMemberOffset += targetSize; ++ memberIndex; } } else { targetMemberOffset = pad(targetMemberOffset, TargetBytesPerWord); } } if (hashMapFind(t, typeMaps, c, objectHash, objectEqual) == 0) { object array = makeByteArray (t, TypeMap::sizeInBytes (ceilingDivide(classFixedSize(t, c), BytesPerWord), memberIndex)); TypeMap* map = new (&byteArrayBody(t, array, 0)) TypeMap (ceilingDivide(classFixedSize(t, c), BytesPerWord), ceilingDivide(targetMemberOffset, TargetBytesPerWord), memberIndex); for (unsigned i = 0; i < memberIndex; ++i) { Field* f = RUNTIME_ARRAY_BODY(memberFields) + i; expect(t, f->buildOffset < map->buildFixedSizeInWords * BytesPerWord); map->targetFixedOffsets()[f->buildOffset] = f->targetOffset; map->fixedFields()[i] = *f; } hashMapInsert(t, typeMaps, c, array, objectHash); } if (classStaticTable(t, c)) { object array = makeByteArray (t, TypeMap::sizeInBytes (singletonCount(t, classStaticTable(t, c)) + 2, staticIndex)); TypeMap* map = new (&byteArrayBody(t, array, 0)) TypeMap (singletonCount(t, classStaticTable(t, c)) + 2, ceilingDivide(targetStaticOffset, TargetBytesPerWord), staticIndex, TypeMap::SingletonKind); for (unsigned i = 0; i < staticIndex; ++i) { Field* f = RUNTIME_ARRAY_BODY(staticFields) + i; expect(t, f->buildOffset < map->buildFixedSizeInWords * BytesPerWord); map->targetFixedOffsets()[f->buildOffset] = f->targetOffset; map->fixedFields()[i] = *f; } hashMapInsert (t, typeMaps, classStaticTable(t, c), array, objectHash); } } } } for (Finder::Iterator it(finder); it.hasMore();) { unsigned nameSize = 0; const char* name = it.next(&nameSize); if (endsWith(".class", name, nameSize) and (className == 0 or strncmp(name, className, nameSize - 6) == 0)) { // fprintf(stderr, "pass 2 %.*s\n", nameSize - 6, name); object c = resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "%.*s", nameSize - 6, name), true); PROTECT(t, c); if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); if (((methodName == 0 or ::strcmp (reinterpret_cast (&byteArrayBody (t, vm::methodName(t, method), 0)), methodName) == 0) and (methodSpec == 0 or ::strcmp (reinterpret_cast (&byteArrayBody (t, vm::methodSpec(t, method), 0)), methodSpec) == 0))) { if (methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) { PROTECT(t, method); t->m->processor->compileMethod (t, zone, &constants, &calls, &addresses, method, &resolver); if (methodCode(t, method)) { methods = makePair(t, method, methods); } } object addendum = methodAddendum(t, method); if (addendum and methodAddendumExceptionTable(t, addendum)) { PROTECT(t, addendum); // resolve exception types now to avoid trying to update // immutable references at runtime for (unsigned i = 0; i < shortArrayLength (t, methodAddendumExceptionTable(t, addendum)); ++i) { uint16_t index = shortArrayBody (t, methodAddendumExceptionTable(t, addendum), i) - 1; object o = singletonObject (t, addendumPool(t, addendum), index); if (objectClass(t, o) == type(t, Machine::ReferenceType)) { o = resolveClass (t, root(t, Machine::BootLoader), referenceName(t, o)); set(t, addendumPool(t, addendum), SingletonBody + (index * BytesPerWord), o); } } } } } } } } for (; calls; calls = tripleThird(t, calls)) { object method = tripleFirst(t, calls); uintptr_t address; if (methodFlags(t, method) & ACC_NATIVE) { address = reinterpret_cast(code + image->thunks.native.start); } else { address = codeCompiled(t, methodCode(t, method)); } static_cast(pointerValue(t, tripleSecond(t, calls))) ->listener->resolve(address, 0); } for (; addresses; addresses = addresses->next) { uint8_t* value = reinterpret_cast(addresses->basis->value()); expect(t, value >= code); addresses->listener->resolve (static_cast(value - code), 0); } for (; methods; methods = pairSecond(t, methods)) { codeCompiled(t, methodCode(t, pairFirst(t, methods))) -= reinterpret_cast(code); } t->m->processor->normalizeVirtualThunks(t); return constants; } void visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants) { Machine* m = t->m; for (HashMapIterator it(t, classLoaderMap(t, root(t, Machine::BootLoader))); it.hasMore();) { w->visitRoot(tripleSecond(t, it.next())); } image->bootLoader = w->visitRoot(root(t, Machine::BootLoader)); image->appLoader = w->visitRoot(root(t, Machine::AppLoader)); image->types = w->visitRoot(m->types); m->processor->visitRoots(t, w); for (; constants; constants = tripleThird(t, constants)) { w->visitRoot(tripleFirst(t, constants)); } } unsigned targetOffset(Thread* t, object typeMaps, object p, unsigned offset) { TypeMap* map = typeMap(t, typeMaps, p); if (map->targetArrayElementSizeInBytes and offset >= map->buildFixedSizeInWords * BytesPerWord) { return (map->targetFixedSizeInWords * TargetBytesPerWord) + (((offset - (map->buildFixedSizeInWords * BytesPerWord)) / map->buildArrayElementSizeInBytes) * map->targetArrayElementSizeInBytes); } else { return map->targetFixedOffsets()[offset]; } } unsigned targetSize(Thread* t, object typeMaps, object p) { TypeMap* map = typeMap(t, typeMaps, p); if (map->targetArrayElementSizeInBytes) { return map->targetFixedSizeInWords + ceilingDivide(map->targetArrayElementSizeInBytes * fieldAtOffset (p, (map->buildFixedSizeInWords - 1) * BytesPerWord), TargetBytesPerWord); } else { switch (map->kind) { case TypeMap::NormalKind: return map->targetFixedSizeInWords; case TypeMap::SingletonKind: return map->targetFixedSizeInWords + singletonMaskSize (map->targetFixedSizeInWords - 2, TargetBitsPerWord); case TypeMap::PoolKind: { unsigned maskSize = poolMaskSize (map->targetFixedSizeInWords - 2, TargetBitsPerWord); return map->targetFixedSizeInWords + maskSize + singletonMaskSize (map->targetFixedSizeInWords - 2 + maskSize, TargetBitsPerWord); } default: abort(t); } } } unsigned objectMaskCount(TypeMap* map) { unsigned count = map->targetFixedSizeInWords; if (map->targetArrayElementSizeInBytes) { ++ count; } return count; } unsigned targetSize(Thread* t, object typeMaps, object referer, unsigned refererOffset, object p) { if (referer and objectClass(t, referer) == type(t, Machine::ClassType) and (refererOffset * BytesPerWord) == ClassObjectMask) { return (TargetBytesPerWord * 2) + pad (ceilingDivide (objectMaskCount (classTypeMap(t, typeMaps, referer)), 32) * 4, TargetBytesPerWord); } else { return targetSize(t, typeMaps, p); } } void copy(Thread* t, uint8_t* src, uint8_t* dst, Type type) { switch (type) { case Type_int8_t: memcpy(dst, src, 1); break; case Type_int16_t: { int16_t s; memcpy(&s, src, 2); int16_t d = targetV2(s); memcpy(dst, &d, 2); } break; case Type_int32_t: case Type_float: { int32_t s; memcpy(&s, src, 4); int32_t d = targetV4(s); memcpy(dst, &d, 4); } break; case Type_int64_t: case Type_double: { int64_t s; memcpy(&s, src, 8); int64_t d = targetV8(s); memcpy(dst, &d, 8); } break; case Type_int64_t_pad: case Type_double_pad: break; case Type_intptr_t: { intptr_t s; memcpy(&s, src, BytesPerWord); target_intptr_t d = targetVW(s); memcpy(dst, &d, TargetBytesPerWord); } break; case Type_object: { memset(dst, 0, TargetBytesPerWord); } break; default: abort(t); } } bool nonObjectsEqual(uint8_t* src, uint8_t* dst, Type type) { switch (type) { case Type_int8_t: return memcmp(dst, src, 1) == 0; case Type_int16_t: return memcmp(dst, src, 2) == 0; case Type_int32_t: case Type_float: return memcmp(dst, src, 4) == 0; case Type_int64_t: case Type_double: return memcmp(dst, src, 8) == 0; case Type_int64_t_pad: case Type_double_pad: return true; case Type_intptr_t: return memcmp(dst, src, BytesPerWord) == 0; case Type_object: case Type_object_nogc: return true; default: abort(); } } bool nonObjectsEqual(TypeMap* map, uint8_t* src, uint8_t* dst) { for (unsigned i = 0; i < map->fixedFieldCount; ++i) { Field* field = map->fixedFields() + i; if (not nonObjectsEqual (src + field->buildOffset, dst + field->targetOffset, field->type)) { return false; } } if (map->targetArrayElementSizeInBytes) { unsigned fixedSize = map->buildFixedSizeInWords * BytesPerWord; unsigned count = fieldAtOffset(src, fixedSize - BytesPerWord); for (unsigned i = 0; i < count; ++i) { if (not nonObjectsEqual (src + fixedSize + (i * map->buildArrayElementSizeInBytes), dst + (map->targetFixedSizeInWords * TargetBytesPerWord) + (i * map->targetArrayElementSizeInBytes), map->arrayElementType)) { return false; } } } return true; } void copy(Thread* t, object typeMaps, object p, uint8_t* dst) { TypeMap* map = typeMap(t, typeMaps, p); uint8_t* src = reinterpret_cast(p); for (unsigned i = 0; i < map->fixedFieldCount; ++i) { Field* field = map->fixedFields() + i; if (field->type > Type_array) abort(t); copy(t, src + field->buildOffset, dst + field->targetOffset, field->type); } if (map->targetArrayElementSizeInBytes) { unsigned fixedSize = map->buildFixedSizeInWords * BytesPerWord; unsigned count = fieldAtOffset(p, fixedSize - BytesPerWord); for (unsigned i = 0; i < count; ++i) { copy(t, src + fixedSize + (i * map->buildArrayElementSizeInBytes), dst + (map->targetFixedSizeInWords * TargetBytesPerWord) + (i * map->targetArrayElementSizeInBytes), map->arrayElementType); } if (objectClass(t, p) == type(t, Machine::ClassType)) { uint16_t fixedSize; uint8_t arrayElementSize; object array = hashMapFind(t, typeMaps, p, objectHash, objectEqual); if (array) { TypeMap* classMap = reinterpret_cast (&byteArrayBody(t, array, 0)); fixedSize = targetV2 (classMap->targetFixedSizeInWords * TargetBytesPerWord); arrayElementSize = classMap->targetArrayElementSizeInBytes; } else if (classFixedSize(t, p) == BytesPerWord * 2 and classArrayElementSize(t, p) == BytesPerWord) { fixedSize = targetV2(TargetBytesPerWord * 2); arrayElementSize = TargetBytesPerWord; } else { fixedSize = 0; arrayElementSize = 0; } if (fixedSize) { memcpy(dst + TargetClassFixedSize, &fixedSize, 2); memcpy(dst + TargetClassArrayElementSize, &arrayElementSize, 1); } // if (strcmp("vm::lineNumberTable", // reinterpret_cast(&byteArrayBody(t, className(t, p), 0))) == 0) trap(); } } else { switch (map->kind) { case TypeMap::NormalKind: if (objectClass(t, p) == type(t, Machine::FieldType)) { uint16_t offset = targetV2(targetFieldOffset(t, typeMaps, p)); memcpy(dst + TargetFieldOffset, &offset, 2); } break; case TypeMap::SingletonKind: { unsigned maskSize = singletonMaskSize (map->targetFixedSizeInWords - 2, TargetBitsPerWord); target_uintptr_t targetLength = targetVW (map->targetFixedSizeInWords - 2 + maskSize); memcpy(dst + TargetBytesPerWord, &targetLength, TargetBytesPerWord); uint8_t* mask = dst + (map->targetFixedSizeInWords * TargetBytesPerWord); memset(mask, 0, maskSize * TargetBytesPerWord); for (unsigned i = 0; i < map->fixedFieldCount; ++i) { Field* field = map->fixedFields() + i; if (field->type == Type_object) { unsigned offset = field->targetOffset / TargetBytesPerWord; reinterpret_cast(mask)[offset / 32] |= targetV4(static_cast(1) << (offset % 32)); } } if (DebugNativeTarget) { expect (t, memcmp (src + (map->targetFixedSizeInWords * TargetBytesPerWord), mask, singletonMaskSize (map->targetFixedSizeInWords - 2, TargetBitsPerWord) * TargetBytesPerWord) == 0); } } break; case TypeMap::PoolKind: { unsigned poolMaskSize = vm::poolMaskSize (map->targetFixedSizeInWords - 2, TargetBitsPerWord); unsigned objectMaskSize = singletonMaskSize (map->targetFixedSizeInWords - 2 + poolMaskSize, TargetBitsPerWord); target_uintptr_t targetLength = targetVW (map->targetFixedSizeInWords - 2 + poolMaskSize + objectMaskSize); memcpy(dst + TargetBytesPerWord, &targetLength, TargetBytesPerWord); uint8_t* poolMask = dst + (map->targetFixedSizeInWords * TargetBytesPerWord); memset(poolMask, 0, poolMaskSize * TargetBytesPerWord); uint8_t* objectMask = dst + ((map->targetFixedSizeInWords + poolMaskSize) * TargetBytesPerWord); memset(objectMask, 0, objectMaskSize * TargetBytesPerWord); for (unsigned i = 0; i < map->fixedFieldCount; ++i) { Field* field = map->fixedFields() + i; switch (field->type) { case Type_object: reinterpret_cast(objectMask)[i / 32] |= targetV4(static_cast(1) << (i % 32)); break; case Type_float: case Type_double: reinterpret_cast(poolMask) [i / TargetBitsPerWord] |= targetVW (static_cast(1) << (i % TargetBitsPerWord)); break; default: break; } } if (DebugNativeTarget) { expect (t, memcmp (src + (map->targetFixedSizeInWords * TargetBytesPerWord), poolMask, (poolMaskSize + singletonMaskSize (map->targetFixedSizeInWords - 2 + poolMaskSize, TargetBitsPerWord)) * TargetBytesPerWord) == 0); } } break; default: abort(t); } } } void copy(Thread* t, object typeMaps, object referer, unsigned refererOffset, object p, uint8_t* dst) { if (referer and objectClass(t, referer) == type(t, Machine::ClassType) and (refererOffset * BytesPerWord) == ClassObjectMask) { TypeMap* map = classTypeMap(t, typeMaps, referer); memset(dst, 0, TargetBytesPerWord); unsigned length = ceilingDivide(objectMaskCount(map), 32); target_uintptr_t targetLength = targetVW(length); memcpy(dst + TargetBytesPerWord, &targetLength, TargetBytesPerWord); memset(dst + (TargetBytesPerWord * 2), 0, length * 4); for (unsigned i = 0; i < map->fixedFieldCount; ++i) { Field* field = map->fixedFields() + i; if (field->type == Type_object) { unsigned offset = field->targetOffset / TargetBytesPerWord; reinterpret_cast(dst + (TargetBytesPerWord * 2)) [offset / 32] |= targetV4(static_cast(1) << (offset % 32)); } } if (map->targetArrayElementSizeInBytes and map->arrayElementType == Type_object) { unsigned offset = map->targetFixedSizeInWords; reinterpret_cast(dst + (TargetBytesPerWord * 2)) [offset / 32] |= targetV4(static_cast(1) << (offset % 32)); } } else { copy(t, typeMaps, p, dst); } if (DebugNativeTarget) { expect(t, targetSize(t, typeMaps, p) == baseSize(t, p, objectClass(t, p))); expect(t, nonObjectsEqual (typeMap(t, typeMaps, p), reinterpret_cast(p), dst)); } } HeapWalker* makeHeapImage(Thread* t, BootImage* image, target_uintptr_t* heap, target_uintptr_t* map, unsigned capacity, object constants, object typeMaps) { class Visitor: public HeapVisitor { public: Visitor(Thread* t, object typeMaps, target_uintptr_t* heap, target_uintptr_t* map, unsigned capacity): t(t), typeMaps(typeMaps), currentObject(0), currentNumber(0), currentOffset(0), heap(heap), map(map), position(0), capacity(capacity) { } void visit(unsigned number) { if (currentObject) { if (DebugNativeTarget) { expect (t, targetOffset (t, typeMaps, currentObject, currentOffset * BytesPerWord) == currentOffset * BytesPerWord); } unsigned offset = currentNumber - 1 + (targetOffset (t, typeMaps, currentObject, currentOffset * BytesPerWord) / TargetBytesPerWord); unsigned mark = heap[offset] & (~TargetPointerMask); unsigned value = number | (mark << TargetBootShift); if (value) targetMarkBit(map, offset); heap[offset] = targetVW(value); } } virtual void root() { currentObject = 0; } virtual unsigned visitNew(object p) { if (p) { unsigned size = targetSize (t, typeMaps, currentObject, currentOffset, p); unsigned number; if ((currentObject and objectClass(t, currentObject) == type(t, Machine::ClassType) and (currentOffset * BytesPerWord) == ClassStaticTable) or instanceOf(t, type(t, Machine::SystemClassLoaderType), p)) { // Static tables and system classloaders must be allocated // as fixed objects in the heap image so that they can be // marked as dirty and visited during GC. Otherwise, // attempts to update references in these objects to point // to runtime-allocated memory would fail because we don't // scan non-fixed objects in the heap image during GC. target_uintptr_t* dst = heap + position + TargetFixieSizeInWords; unsigned maskSize = ceilingDivide(size, TargetBitsPerWord); unsigned total = TargetFixieSizeInWords + size + maskSize; expect(t, position + total < capacity); memset(heap + position, 0, TargetFixieSizeInBytes); uint16_t age = targetV2(FixieTenureThreshold + 1); memcpy(reinterpret_cast(heap + position) + TargetFixieAge, &age, 2); uint16_t flags = targetV2(1); memcpy(reinterpret_cast(heap + position) + TargetFixieFlags, &flags, 2); uint32_t targetSize = targetV4(size); memcpy(reinterpret_cast(heap + position) + TargetFixieSize, &targetSize, 4); copy(t, typeMaps, currentObject, currentOffset, p, reinterpret_cast(dst)); dst[0] |= FixedMark; memset(heap + position + TargetFixieSizeInWords + size, 0, maskSize * TargetBytesPerWord); number = (dst - heap) + 1; position += total; } else { expect(t, position + size < capacity); copy(t, typeMaps, currentObject, currentOffset, p, reinterpret_cast(heap + position)); number = position + 1; position += size; } visit(number); return number; } else { return 0; } } virtual void visitOld(object, unsigned number) { visit(number); } virtual void push(object object, unsigned number, unsigned offset) { currentObject = object; currentNumber = number; currentOffset = offset; } virtual void pop() { currentObject = 0; } Thread* t; object typeMaps; object currentObject; unsigned currentNumber; unsigned currentOffset; target_uintptr_t* heap; target_uintptr_t* map; unsigned position; unsigned capacity; } visitor(t, typeMaps, heap, map, capacity / TargetBytesPerWord); HeapWalker* w = makeHeapWalker(t, &visitor); visitRoots(t, image, w, constants); image->heapSize = visitor.position * TargetBytesPerWord; return w; } void updateConstants(Thread* t, object constants, HeapMap* heapTable) { for (; constants; constants = tripleThird(t, constants)) { unsigned target = heapTable->find(tripleFirst(t, constants)); expect(t, target > 0); for (Promise::Listener* pl = static_cast (pointerValue(t, tripleSecond(t, constants)))->listener; pl; pl = pl->next) { pl->resolve((target - 1) * TargetBytesPerWord, 0); } } } BootImage::Thunk targetThunk(BootImage::Thunk t) { return BootImage::Thunk (targetV4(t.start), targetV4(t.frameSavedOffset), targetV4(t.length)); } void writeBootImage2(Thread* t, OutputStream* bootimageOutput, OutputStream* codeOutput, BootImage* image, uint8_t* code, const char* className, const char* methodName, const char* methodSpec, const char* bootimageStart, const char* bootimageEnd, const char* codeimageStart, const char* codeimageEnd, bool useLZMA) { setRoot(t, Machine::OutOfMemoryError, make(t, type(t, Machine::OutOfMemoryErrorType))); Zone zone(t->m->system, t->m->heap, 64 * 1024); class MyCompilationHandler : public Processor::CompilationHandler { public: String heapDup(const char* name) { String ret(name); char* n = (char*)heap->allocate(ret.length + 1); memcpy(n, ret.text, ret.length + 1); ret.text = n; return ret; } virtual void compiled(const void* code, unsigned size UNUSED, unsigned frameSize UNUSED, const char* name) { uint64_t offset = reinterpret_cast(code) - codeOffset; symbols.add(SymbolInfo(offset, heapDup(name))); // printf("%ld %ld %s.%s%s\n", offset, offset + size, class_, name, spec); } virtual void dispose() {} DynamicArray symbols; uint64_t codeOffset; Heap* heap; MyCompilationHandler(uint64_t codeOffset, Heap* heap): codeOffset(codeOffset), heap(heap) {} } compilationHandler(reinterpret_cast(code), t->m->heap); t->m->processor->addCompilationHandler(&compilationHandler); object classPoolMap; object typeMaps; object constants; { classPoolMap = makeHashMap(t, 0, 0); PROTECT(t, classPoolMap); setRoot(t, Machine::PoolMap, classPoolMap); typeMaps = makeHashMap(t, 0, 0); PROTECT(t, typeMaps); #include "type-maps.cpp" for (unsigned i = 0; i < arrayLength(t, t->m->types); ++i) { Type* source = types[i]; unsigned typeCount = 0; unsigned fieldCount = 1; while (source[typeCount] != Type_none) { ++ typeCount; if (source[typeCount] != Type_pad) { ++ fieldCount; } } THREAD_RUNTIME_ARRAY(t, Field, fields, fieldCount); init(new (RUNTIME_ARRAY_BODY(fields)) Field, Type_object, 0, BytesPerWord, 0, TargetBytesPerWord); unsigned buildOffset = BytesPerWord; unsigned targetOffset = TargetBytesPerWord; bool sawArray = false; Type type = Type_none; unsigned buildSize = 0; unsigned targetSize = 0; unsigned fieldOffset = 1; for (unsigned j = 0; j < typeCount; ++j) { switch (source[j]) { case Type_pad: type = Type_pad; buildSize = 0; targetSize = 0; break; case Type_object: type = Type_object; buildSize = BytesPerWord; targetSize = TargetBytesPerWord; break; case Type_object_nogc: type = Type_object_nogc; buildSize = BytesPerWord; targetSize = TargetBytesPerWord; break; case Type_word: case Type_intptr_t: case Type_uintptr_t: type = Type_intptr_t; buildSize = BytesPerWord; targetSize = TargetBytesPerWord; break; case Type_int8_t: case Type_uint8_t: type = Type_int8_t; buildSize = targetSize = 1; break; case Type_int16_t: case Type_uint16_t: type = Type_int16_t; buildSize = targetSize = 2; break; case Type_int32_t: case Type_uint32_t: case Type_float: type = Type_int32_t; buildSize = targetSize = 4; break; case Type_int64_t: case Type_uint64_t: case Type_double: type = Type_int64_t; buildSize = targetSize = 8; break; case Type_array: type = Type_none; buildSize = targetSize = 0; break; default: abort(t); } if (source[j] == Type_array) { sawArray = true; } if (type == Type_pad) { buildOffset = pad(buildOffset, BytesPerWord); targetOffset = pad(targetOffset, TargetBytesPerWord); } else if (not sawArray) { buildOffset = pad(buildOffset, buildSize); targetOffset = pad(targetOffset, targetSize); init(new (RUNTIME_ARRAY_BODY(fields) + (fieldOffset++)) Field, type, buildOffset, buildSize, targetOffset, targetSize); buildOffset += buildSize; targetOffset += targetSize; } } unsigned fixedFieldCount; Type arrayElementType; unsigned buildArrayElementSize; unsigned targetArrayElementSize; if (sawArray) { fixedFieldCount = fieldCount - 2; arrayElementType = type; buildArrayElementSize = buildSize; targetArrayElementSize = targetSize; } else { fixedFieldCount = fieldCount; arrayElementType = Type_none; buildArrayElementSize = 0; targetArrayElementSize = 0; } object array = makeByteArray (t, TypeMap::sizeInBytes (ceilingDivide(buildOffset, BytesPerWord), fixedFieldCount)); TypeMap* map = new (&byteArrayBody(t, array, 0)) TypeMap (ceilingDivide(buildOffset, BytesPerWord), ceilingDivide(targetOffset, TargetBytesPerWord), fixedFieldCount, TypeMap::NormalKind, buildArrayElementSize, targetArrayElementSize, arrayElementType); for (unsigned j = 0; j < fixedFieldCount; ++j) { Field* f = RUNTIME_ARRAY_BODY(fields) + j; expect(t, f->buildOffset < map->buildFixedSizeInWords * BytesPerWord); map->targetFixedOffsets()[f->buildOffset] = f->targetOffset; map->fixedFields()[j] = *f; } hashMapInsert (t, typeMaps, vm::type(t, static_cast(i)), array, objectHash); } constants = makeCodeImage (t, &zone, image, code, className, methodName, methodSpec, typeMaps); PROTECT(t, constants); // these roots will not be used when the bootimage is loaded, so // there's no need to preserve them: setRoot(t, Machine::PoolMap, 0); setRoot(t, Machine::ByteArrayMap, makeWeakHashMap(t, 0, 0)); // name all primitive classes so we don't try to update immutable // references at runtime: { object name = makeByteArray(t, "void"); set(t, type(t, Machine::JvoidType), ClassName, name); name = makeByteArray(t, "boolean"); set(t, type(t, Machine::JbooleanType), ClassName, name); name = makeByteArray(t, "byte"); set(t, type(t, Machine::JbyteType), ClassName, name); name = makeByteArray(t, "short"); set(t, type(t, Machine::JshortType), ClassName, name); name = makeByteArray(t, "char"); set(t, type(t, Machine::JcharType), ClassName, name); name = makeByteArray(t, "int"); set(t, type(t, Machine::JintType), ClassName, name); name = makeByteArray(t, "float"); set(t, type(t, Machine::JfloatType), ClassName, name); name = makeByteArray(t, "long"); set(t, type(t, Machine::JlongType), ClassName, name); name = makeByteArray(t, "double"); set(t, type(t, Machine::JdoubleType), ClassName, name); } // resolve primitive array classes in case they are needed at // runtime: { object name = makeByteArray(t, "[B"); resolveSystemClass(t, root(t, Machine::BootLoader), name, true); name = makeByteArray(t, "[Z"); resolveSystemClass(t, root(t, Machine::BootLoader), name, true); name = makeByteArray(t, "[S"); resolveSystemClass(t, root(t, Machine::BootLoader), name, true); name = makeByteArray(t, "[C"); resolveSystemClass(t, root(t, Machine::BootLoader), name, true); name = makeByteArray(t, "[I"); resolveSystemClass(t, root(t, Machine::BootLoader), name, true); name = makeByteArray(t, "[J"); resolveSystemClass(t, root(t, Machine::BootLoader), name, true); name = makeByteArray(t, "[F"); resolveSystemClass(t, root(t, Machine::BootLoader), name, true); name = makeByteArray(t, "[D"); resolveSystemClass(t, root(t, Machine::BootLoader), name, true); } } target_uintptr_t* heap = static_cast (t->m->heap->allocate(HeapCapacity)); target_uintptr_t* heapMap = static_cast (t->m->heap->allocate(heapMapSize(HeapCapacity))); memset(heapMap, 0, heapMapSize(HeapCapacity)); HeapWalker* heapWalker = makeHeapImage (t, image, heap, heapMap, HeapCapacity, constants, typeMaps); updateConstants(t, constants, heapWalker->map()); image->bootClassCount = hashMapSize (t, classLoaderMap(t, root(t, Machine::BootLoader))); unsigned* bootClassTable = static_cast (t->m->heap->allocate(image->bootClassCount * sizeof(unsigned))); { unsigned i = 0; for (HashMapIterator it (t, classLoaderMap(t, root(t, Machine::BootLoader))); it.hasMore();) { bootClassTable[i++] = targetVW (heapWalker->map()->find(tripleSecond(t, it.next()))); } } image->appClassCount = hashMapSize (t, classLoaderMap(t, root(t, Machine::AppLoader))); unsigned* appClassTable = static_cast (t->m->heap->allocate(image->appClassCount * sizeof(unsigned))); { unsigned i = 0; for (HashMapIterator it (t, classLoaderMap(t, root(t, Machine::AppLoader))); it.hasMore();) { appClassTable[i++] = targetVW (heapWalker->map()->find(tripleSecond(t, it.next()))); } } image->stringCount = hashMapSize(t, root(t, Machine::StringMap)); unsigned* stringTable = static_cast (t->m->heap->allocate(image->stringCount * sizeof(unsigned))); { unsigned i = 0; for (HashMapIterator it(t, root(t, Machine::StringMap)); it.hasMore();) { stringTable[i++] = targetVW (heapWalker->map()->find (jreferenceTarget(t, tripleFirst(t, it.next())))); } } unsigned* callTable = t->m->processor->makeCallTable(t, heapWalker); heapWalker->dispose(); image->magic = BootImage::Magic; image->initialized = 0; fprintf(stderr, "class count %d string count %d call count %d\n" "heap size %d code size %d\n", image->bootClassCount, image->stringCount, image->callCount, image->heapSize, image->codeSize); Buffer bootimageData; if (true) { { BootImage targetImage; #ifdef FIELD # undef FIELD #endif #define FIELD(name) targetImage.name = targetV4(image->name); #include "bootimage-fields.cpp" #undef FIELD #define THUNK_FIELD(name) \ targetImage.thunks.name = targetThunk(image->thunks.name); #include "bootimage-fields.cpp" #undef THUNK_FIELD bootimageData.write(&targetImage, sizeof(BootImage)); } bootimageData.write(bootClassTable, image->bootClassCount * sizeof(unsigned)); bootimageData.write(appClassTable, image->appClassCount * sizeof(unsigned)); bootimageData.write(stringTable, image->stringCount * sizeof(unsigned)); bootimageData.write(callTable, image->callCount * sizeof(unsigned) * 2); unsigned offset = sizeof(BootImage) + (image->bootClassCount * sizeof(unsigned)) + (image->appClassCount * sizeof(unsigned)) + (image->stringCount * sizeof(unsigned)) + (image->callCount * sizeof(unsigned) * 2); while (offset % TargetBytesPerWord) { uint8_t c = 0; bootimageData.write(&c, 1); ++ offset; } bootimageData.write(heapMap, pad(heapMapSize(image->heapSize), TargetBytesPerWord)); bootimageData.write(heap, pad(image->heapSize, TargetBytesPerWord)); // fwrite(code, pad(image->codeSize, TargetBytesPerWord), 1, codeOutput); Platform* platform = Platform::getPlatform(PlatformInfo((PlatformInfo::Format)AVIAN_TARGET_FORMAT, (PlatformInfo::Architecture)AVIAN_TARGET_ARCH)); if(!platform) { fprintf(stderr, "unsupported platform: target-format = %d / target-arch = %d\n", AVIAN_TARGET_FORMAT, AVIAN_TARGET_ARCH); abort(); } SymbolInfo bootimageSymbols[] = { SymbolInfo(0, bootimageStart), SymbolInfo(bootimageData.length, bootimageEnd) }; uint8_t* bootimage; unsigned bootimageLength; if (useLZMA) { #ifdef AVIAN_USE_LZMA bootimage = encodeLZMA(t->m->system, t->m->heap, bootimageData.data, bootimageData.length, &bootimageLength); fprintf(stderr, "compressed heap size %d\n", bootimageLength); #else abort(t); #endif } else { bootimage = bootimageData.data; bootimageLength = bootimageData.length; } platform->writeObject(bootimageOutput, Slice(bootimageSymbols, 2), Slice(bootimage, bootimageLength), Platform::Writable, TargetBytesPerWord); if (useLZMA) { t->m->heap->free(bootimage, bootimageLength); } compilationHandler.symbols.add(SymbolInfo(0, codeimageStart)); compilationHandler.symbols.add(SymbolInfo(image->codeSize, codeimageEnd)); platform->writeObject(codeOutput, Slice(compilationHandler.symbols), Slice(code, image->codeSize), Platform::Executable, TargetBytesPerWord); for(SymbolInfo* sym = compilationHandler.symbols.begin(); sym != compilationHandler.symbols.end() - 2; sym++) { t->m->heap->free(const_cast((const void*)sym->name.text), sym->name.length + 1); } } } uint64_t writeBootImage(Thread* t, uintptr_t* arguments) { OutputStream* bootimageOutput = reinterpret_cast(arguments[0]); OutputStream* codeOutput = reinterpret_cast(arguments[1]); BootImage* image = reinterpret_cast(arguments[2]); uint8_t* code = reinterpret_cast(arguments[3]); const char* className = reinterpret_cast(arguments[4]); const char* methodName = reinterpret_cast(arguments[5]); const char* methodSpec = reinterpret_cast(arguments[6]); const char* bootimageStart = reinterpret_cast(arguments[7]); const char* bootimageEnd = reinterpret_cast(arguments[8]); const char* codeimageStart = reinterpret_cast(arguments[9]); const char* codeimageEnd = reinterpret_cast(arguments[10]); bool useLZMA = arguments[11]; writeBootImage2 (t, bootimageOutput, codeOutput, image, code, className, methodName, methodSpec, bootimageStart, bootimageEnd, codeimageStart, codeimageEnd, useLZMA); return 1; } char* myStrndup(const char* src, unsigned length) { char* s = static_cast(malloc(length + 1)); memcpy(s, src, length); s[length] = 0; return s; } class Arguments { public: const char* classpath; const char* bootimage; const char* codeimage; char* entryClass; char* entryMethod; char* entrySpec; char* bootimageStart; char* bootimageEnd; char* codeimageStart; char* codeimageEnd; bool useLZMA; bool maybeSplit(const char* src, char*& destA, char*& destB) { if(src) { const char* split = strchr(src, ':'); if(!split) { return false; } destA = myStrndup(src, split - src); destB = strdup(split + 1); } return true; } Arguments(int ac, const char** av): entryClass(0), entryMethod(0), entrySpec(0), bootimageStart(0), bootimageEnd(0), codeimageStart(0), codeimageEnd(0) { ArgParser parser; Arg classpath(parser, true, "cp", ""); Arg bootimage(parser, true, "bootimage", ""); Arg codeimage(parser, true, "codeimage", ""); Arg entry(parser, false, "entry", "[.[]]"); Arg bootimageSymbols(parser, false, "bootimage-symbols", ":"); Arg codeimageSymbols(parser, false, "codeimage-symbols", ":"); Arg useLZMA(parser, false, "use-lzma", 0); if(!parser.parse(ac, av)) { parser.printUsage(av[0]); exit(1); } this->classpath = classpath.value; this->bootimage = bootimage.value; this->codeimage = codeimage.value; this->useLZMA = useLZMA.value != 0; if(entry.value) { if(const char* entryClassEnd = strchr(entry.value, '.')) { entryClass = myStrndup(entry.value, entryClassEnd - entry.value); if(const char* entryMethodEnd = strchr(entryClassEnd, '(')) { entryMethod = myStrndup(entryClassEnd + 1, entryMethodEnd - entryClassEnd - 1); entrySpec = strdup(entryMethodEnd); } else { entryMethod = strdup(entryClassEnd + 1); } } else { entryClass = strdup(entry.value); } } if(!maybeSplit(bootimageSymbols.value, bootimageStart, bootimageEnd) || !maybeSplit(codeimageSymbols.value, codeimageStart, codeimageEnd)) { fprintf(stderr, "wrong format for symbols\n"); parser.printUsage(av[0]); exit(1); } if(!bootimageStart) { bootimageStart = strdup("_binary_bootimage_bin_start"); } if(!bootimageEnd) { bootimageEnd = strdup("_binary_bootimage_bin_end"); } if(!codeimageStart) { codeimageStart = strdup("_binary_codeimage_bin_start"); } if(!codeimageEnd) { codeimageEnd = strdup("_binary_codeimage_bin_end"); } } ~Arguments() { if(entryClass) { free(entryClass); } if(entryMethod) { free(entryMethod); } if(entrySpec) { free(entrySpec); } if(bootimageStart) { free(bootimageStart); } if(bootimageEnd) { free(bootimageEnd); } if(codeimageStart) { free(codeimageStart); } if(codeimageEnd) { free(codeimageEnd); } } void dump() { printf( "classpath = %s\n" "bootimage = %s\n" "codeimage = %s\n" "entryClass = %s\n" "entryMethod = %s\n" "entrySpec = %s\n" "bootimageStart = %s\n" "bootimageEnd = %s\n" "codeimageStart = %s\n" "codeimageEnd = %s\n", classpath, bootimage, codeimage, entryClass, entryMethod, entrySpec, bootimageStart, bootimageEnd, codeimageStart, codeimageEnd); } }; } // namespace int main(int ac, const char** av) { Arguments args(ac, av); // args.dump(); System* s = makeSystem(); Heap* h = makeHeap(s, HeapCapacity * 2); Classpath* c = makeClasspath(s, h, AVIAN_JAVA_HOME, AVIAN_EMBED_PREFIX); Finder* f = makeFinder(s, h, args.classpath, 0); Processor* p = makeProcessor(s, h, 0, false); // todo: currently, the compiler cannot compile code with jumps or // calls spanning more than the maximum size of an immediate value // in a branch instruction for the target architecture (~32MB on // PowerPC and ARM). When that limitation is removed, we'll be able // to specify a capacity as large as we like here: #if (AVIAN_TARGET_ARCH == AVIAN_ARCH_X86_64) \ || (AVIAN_TARGET_ARCH == AVIAN_ARCH_X86) const unsigned CodeCapacity = 128 * 1024 * 1024; #else const unsigned CodeCapacity = 30 * 1024 * 1024; #endif Slice code = Slice::alloc(h, CodeCapacity); BootImage image; p->initialize(&image, code); Machine* m = new (h->allocate(sizeof(Machine))) Machine (s, h, f, 0, p, c, 0, 0, 0, 0, 128 * 1024); Thread* t = p->makeThread(m, 0, 0); enter(t, Thread::ActiveState); enter(t, Thread::IdleState); FileOutputStream bootimageOutput(args.bootimage); if (!bootimageOutput.isValid()) { fprintf(stderr, "unable to open %s\n", args.bootimage); return -1; } FileOutputStream codeOutput(args.codeimage); if (!codeOutput.isValid()) { fprintf(stderr, "unable to open %s\n", args.codeimage); return -1; } uintptr_t arguments[] = {reinterpret_cast(&bootimageOutput), reinterpret_cast(&codeOutput), reinterpret_cast(&image), reinterpret_cast(code.begin()), reinterpret_cast(args.entryClass), reinterpret_cast(args.entryMethod), reinterpret_cast(args.entrySpec), reinterpret_cast(args.bootimageStart), reinterpret_cast(args.bootimageEnd), reinterpret_cast(args.codeimageStart), reinterpret_cast(args.codeimageEnd), static_cast(args.useLZMA)}; run(t, writeBootImage, arguments); if (t->exception) { printTrace(t, t->exception); return -1; } else { return 0; } } ReadyTalk-avian-1e1fff5/src/tools/object-writer/000077500000000000000000000000001231440243200216675ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/tools/object-writer/elf.cpp000066400000000000000000000236551231440243200231540ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include #include "endianness.h" #include #define EI_NIDENT 16 #define EI_MAG0 0 #define EI_MAG1 1 #define EI_MAG2 2 #define EI_MAG3 3 #define EI_CLASS 4 #define EI_DATA 5 #define EI_VERSION 6 #define EI_OSABI 7 #define EI_ABIVERSION 8 #define ELFMAG0 0x7f #define ELFMAG1 'E' #define ELFMAG2 'L' #define ELFMAG3 'F' #define ELFCLASS64 2 #define ELFCLASS32 1 #define EV_CURRENT 1 #define ELFDATA2LSB 1 #define ELFDATA2MSB 2 #define ELFOSABI_SYSV 0 #define ET_REL 1 #define EM_386 3 #define EM_X86_64 62 #define EM_ARM 40 #define EM_PPC 20 #define SHT_PROGBITS 1 #define SHT_SYMTAB 2 #define SHT_STRTAB 3 #define SHF_WRITE (1 << 0) #define SHF_ALLOC (1 << 1) #define SHF_EXECINSTR (1 << 2) #define STB_GLOBAL 1 #define STT_NOTYPE 0 #define STV_DEFAULT 0 #define SYMBOL_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) #define OSABI ELFOSABI_SYSV namespace { using namespace avian::tools; using namespace avian::util; template struct ElfTypes { typedef uint16_t Half; typedef uint32_t Word; typedef AddrTy Addr; typedef uint64_t Xword; typedef uint16_t Section; typedef AddrTy Off; typedef AddrTy XFlags; static const unsigned BytesPerWord = sizeof(AddrTy); }; template struct Symbol_Ty; template<> struct Symbol_Ty { typedef ElfTypes Elf; Elf::Word st_name; unsigned char st_info; unsigned char st_other; Elf::Section st_shndx; Elf::Addr st_value; Elf::Xword st_size; }; template<> struct Symbol_Ty { typedef ElfTypes Elf; Elf::Word st_name; Elf::Addr st_value; Elf::Word st_size; unsigned char st_info; unsigned char st_other; Elf::Section st_shndx; }; using avian::endian::Endianness; #define V1 Endianness::v1 #define V2 Endianness::v2 #define V3 Endianness::v3 #define V4 Endianness::v4 #define VANY Endianness::vAny unsigned getElfPlatform(PlatformInfo::Architecture arch) { switch(arch) { case PlatformInfo::x86_64: return EM_X86_64; case PlatformInfo::x86: return EM_386; case PlatformInfo::Arm: return EM_ARM; case PlatformInfo::PowerPC: return EM_PPC; default: return ~0; } } const char* getSectionName(unsigned accessFlags, unsigned& sectionFlags) { sectionFlags = SHF_ALLOC; if (accessFlags & Platform::Writable) { if (accessFlags & Platform::Executable) { sectionFlags |= SHF_WRITE | SHF_EXECINSTR; return ".rwx"; } else { sectionFlags |= SHF_WRITE; return ".data"; } } else if (accessFlags & Platform::Executable) { sectionFlags |= SHF_EXECINSTR; return ".text"; } else { return ".rodata"; } } template class ElfPlatform : public Platform { public: typedef ElfTypes Elf; static const unsigned Class = Elf::BytesPerWord / 4; struct FileHeader { unsigned char e_ident[EI_NIDENT]; typename Elf::Half e_type; typename Elf::Half e_machine; typename Elf::Word e_version; typename Elf::Addr e_entry; typename Elf::Off e_phoff; typename Elf::Off e_shoff; typename Elf::Word e_flags; typename Elf::Half e_ehsize; typename Elf::Half e_phentsize; typename Elf::Half e_phnum; typename Elf::Half e_shentsize; typename Elf::Half e_shnum; typename Elf::Half e_shstrndx; }; struct SectionHeader { typename Elf::Word sh_name; typename Elf::Word sh_type; typename Elf::XFlags sh_flags; typename Elf::Addr sh_addr; typename Elf::Off sh_offset; typename Elf::Off sh_size; typename Elf::Word sh_link; typename Elf::Word sh_info; typename Elf::Addr sh_addralign; typename Elf::Off sh_entsize; }; typedef Symbol_Ty Symbol; static const unsigned Encoding = TargetLittleEndian ? ELFDATA2LSB : ELFDATA2MSB; const unsigned machine; ElfPlatform(PlatformInfo::Architecture arch): Platform(PlatformInfo(PlatformInfo::Elf, arch)), machine(getElfPlatform(arch)) {} class FileWriter { public: unsigned sectionCount; unsigned sectionStringTableSectionNumber; AddrTy dataOffset; FileHeader header; StringTable strings; FileWriter(unsigned machine): sectionCount(0), dataOffset(sizeof(FileHeader)) { memset(&header, 0, sizeof(FileHeader)); header.e_ident[EI_MAG0] = V1(ELFMAG0); header.e_ident[EI_MAG1] = V1(ELFMAG1); header.e_ident[EI_MAG2] = V1(ELFMAG2); header.e_ident[EI_MAG3] = V1(ELFMAG3); header.e_ident[EI_CLASS] = V1(Class); header.e_ident[EI_DATA] = V1(Encoding); header.e_ident[EI_VERSION] = V1(EV_CURRENT); header.e_ident[EI_OSABI] = V1(OSABI); header.e_ident[EI_ABIVERSION] = V1(0); header.e_type = V2(ET_REL); header.e_machine = V2(machine); header.e_version = V4(EV_CURRENT); header.e_entry = VANY(static_cast(0)); header.e_phoff = VANY(static_cast(0)); header.e_shoff = VANY(static_cast(sizeof(FileHeader))); header.e_flags = V4(machine == EM_ARM ? 0x04000000 : 0); header.e_ehsize = V2(sizeof(FileHeader)); header.e_phentsize = V2(0); header.e_phnum = V2(0); header.e_shentsize = V2(sizeof(SectionHeader)); } void writeHeader(OutputStream* out) { header.e_shnum = V2(sectionCount); header.e_shstrndx = V2(sectionStringTableSectionNumber); out->writeChunk(&header, sizeof(FileHeader)); } }; class SectionWriter { public: FileWriter& file; String name; SectionHeader header; const size_t* dataSize; const uint8_t* const* data; SectionWriter(FileWriter& file): file(file), name(""), dataSize(0), data(0) { memset(&header, 0, sizeof(SectionHeader)); file.sectionCount++; file.dataOffset += sizeof(SectionHeader); size_t nameOffset = file.strings.add(name); header.sh_name = V4(nameOffset); } SectionWriter( FileWriter& file, const char* chname, unsigned type, AddrTy flags, unsigned alignment, AddrTy addr, const uint8_t* const* data, size_t* dataSize, size_t entsize = 0, unsigned link = 0): file(file), name(chname), dataSize(dataSize), data(data) { if(strcmp(chname, ".shstrtab") == 0) { file.sectionStringTableSectionNumber = file.sectionCount; } file.sectionCount++; file.dataOffset += sizeof(SectionHeader); size_t nameOffset = file.strings.add(name); header.sh_name = V4(nameOffset); header.sh_type = V4(type); header.sh_flags = VANY(flags); header.sh_addr = VANY(addr); // header.sh_offset = VANY(static_cast(bodySectionOffset)); // header.sh_size = VANY(static_cast(*dataSize)); header.sh_link = V4(link); header.sh_info = V4(0); header.sh_addralign = VANY(static_cast(alignment)); header.sh_entsize = VANY(static_cast(entsize)); } void writeHeader(OutputStream* out) { if(dataSize) { header.sh_offset = VANY(file.dataOffset); header.sh_size = VANY(static_cast(*dataSize)); file.dataOffset += *dataSize; } out->writeChunk(&header, sizeof(SectionHeader)); } void writeData(OutputStream* out) { if(data) { out->writeChunk(*data, *dataSize); } } }; virtual bool writeObject(OutputStream* out, Slice symbols, Slice data, unsigned accessFlags, unsigned alignment) { unsigned sectionFlags; const char* sectionName = getSectionName(accessFlags, sectionFlags); StringTable symbolStringTable; Buffer symbolTable; FileWriter file(machine); const int bodySectionNumber = 1; const int stringTableSectionNumber = 3; SectionWriter sections[] = { SectionWriter(file), // null section SectionWriter(file, sectionName, SHT_PROGBITS, sectionFlags, alignment, 0, &data.items, &data.count), // body section SectionWriter(file, ".shstrtab", SHT_STRTAB, 0, 1, 0, &file.strings.data, &file.strings.length), SectionWriter(file, ".strtab", SHT_STRTAB, 0, 1, 0, &symbolStringTable.data, &symbolStringTable.length), SectionWriter(file, ".symtab", SHT_SYMTAB, 0, 8, 0, &symbolTable.data, &symbolTable.length, sizeof(Symbol), stringTableSectionNumber) }; // for some reason, string tables require a null first element... symbolStringTable.add(""); for(SymbolInfo* sym = symbols.begin(); sym != symbols.end(); sym++) { size_t nameOffset = symbolStringTable.add(sym->name); Symbol symbolStruct; symbolStruct.st_name = V4(nameOffset); symbolStruct.st_value = VANY(static_cast(sym->addr)); symbolStruct.st_size = VANY(static_cast(0)); symbolStruct.st_info = V1(SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE)); symbolStruct.st_other = V1(STV_DEFAULT); symbolStruct.st_shndx = V2(bodySectionNumber); symbolTable.write(&symbolStruct, sizeof(Symbol)); } file.writeHeader(out); for(unsigned i = 0; i < file.sectionCount; i++) { sections[i].writeHeader(out); } for(unsigned i = 0; i < file.sectionCount; i++) { sections[i].writeData(out); } return true; } }; ElfPlatform elfX86Platform(PlatformInfo::x86); ElfPlatform elfArmPlatform(PlatformInfo::Arm); ElfPlatform elfPowerPCPlatform(PlatformInfo::PowerPC); ElfPlatform elfX86_64Platform(PlatformInfo::x86_64); } // namespace ReadyTalk-avian-1e1fff5/src/tools/object-writer/endianness.h000066400000000000000000000040701231440243200241700ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_ENDIANNESS_H #define AVIAN_ENDIANNESS_H namespace avian { namespace endian { static union { uint32_t i; char c[4]; } _DetectEndianness = {1}; const bool LittleEndian = _DetectEndianness.c[0] == 1; template class Endianness { public: static inline uint8_t v1(uint8_t v) { return v; } static inline uint16_t v2(uint16_t v) { if(LittleEndian == TargetLittleEndian) { return v; } else { return ((v >> 8) & 0xFF) | (v << 8); } } static inline uint32_t v4(uint32_t v) { if(LittleEndian == TargetLittleEndian) { return v; } else { return ((v >> 24) & 0x000000FF) | ((v >> 8) & 0x0000FF00) | ((v << 8) & 0x00FF0000) | ((v << 24)); } } static inline uint32_t vAny(uint32_t v) { return v4(v); } static inline uint64_t v8(uint64_t v) { if(LittleEndian == TargetLittleEndian) { return v; } else { return ((static_cast(v) >> 56) & (static_cast(0xff) << 0)) | ((static_cast(v) >> 40) & (static_cast(0xff) << 8)) | ((static_cast(v) >> 24) & (static_cast(0xff) << 16)) | ((static_cast(v) >> 8) & (static_cast(0xff) << 24)) | ((static_cast(v) << 8) & (static_cast(0xff) << 32)) | ((static_cast(v) << 24) & (static_cast(0xff) << 40)) | ((static_cast(v) << 40) & (static_cast(0xff) << 48)) | ((static_cast(v) << 56)); } } static inline uint64_t vAny(uint64_t v) { return v8(v); } }; } // namespace endian } // namespace avian #endif // AVIAN_ENDIANNESS_H ReadyTalk-avian-1e1fff5/src/tools/object-writer/mach-o.cpp000066400000000000000000000170541231440243200235460ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include "endianness.h" #include #define MH_MAGIC_64 0xfeedfacf #define MH_MAGIC 0xfeedface #define MH_OBJECT 1 #define LC_SYMTAB 2 #define S_REGULAR 0 #define N_SECT 0xe #define N_EXT 0x1 #define CPU_ARCH_ABI64 0x01000000 #define CPU_TYPE_I386 7 #define CPU_TYPE_X86_64 (CPU_TYPE_I386 | CPU_ARCH_ABI64) #define CPU_TYPE_POWERPC 18 #define CPU_TYPE_ARM 12 #define CPU_SUBTYPE_I386_ALL 3 #define CPU_SUBTYPE_X86_64_ALL CPU_SUBTYPE_I386_ALL #define CPU_SUBTYPE_POWERPC_ALL 0 #define CPU_SUBTYPE_ARM_V7 9 namespace { using namespace avian::tools; using namespace avian::util; typedef int cpu_type_t; typedef int cpu_subtype_t; typedef int vm_prot_t; using avian::endian::Endianness; #define V1 Endianness::v1 #define V2 Endianness::v2 #define V3 Endianness::v3 #define V4 Endianness::v4 #define VANY Endianness::vAny inline unsigned log(unsigned n) { unsigned r = 0; for (unsigned i = 1; i < n; ++r) i <<= 1; return r; } template class MachOPlatform : public Platform { public: struct FileHeader { uint32_t magic; cpu_type_t cputype; cpu_subtype_t cpusubtype; uint32_t filetype; uint32_t ncmds; uint32_t sizeofcmds; union { uint32_t flags; AddrTy flagsAndMaybeReserved; }; }; struct SegmentCommand { uint32_t cmd; uint32_t cmdsize; char segname[16]; AddrTy vmaddr; AddrTy vmsize; AddrTy fileoff; AddrTy filesize; vm_prot_t maxprot; vm_prot_t initprot; uint32_t nsects; uint32_t flags; }; struct Section { char sectname[16]; char segname[16]; AddrTy addr; AddrTy size; uint32_t offset; uint32_t align; uint32_t reloff; uint32_t nreloc; uint32_t flags; uint32_t reserved1; AddrTy reserved2AndMaybe3; }; struct NList { union { uint32_t n_strx; } n_un; uint8_t n_type; uint8_t n_sect; uint16_t n_desc; AddrTy n_value; }; struct SymtabCommand { uint32_t cmd; uint32_t cmdsize; uint32_t symoff; uint32_t nsyms; uint32_t stroff; uint32_t strsize; }; static const unsigned BytesPerWord = sizeof(AddrTy); static const unsigned Segment = BytesPerWord == 8 ? 0x19 : 1; static const unsigned Magic = BytesPerWord == 8 ? 0xfeedfacf : 0xfeedface; static inline unsigned pad(unsigned n) { return (n + (BytesPerWord - 1)) & ~(BytesPerWord - 1); } virtual bool writeObject(OutputStream* out, Slice symbols, Slice data, unsigned accessFlags, unsigned alignment) { cpu_type_t cpuType; cpu_subtype_t cpuSubType; switch(info.arch) { case PlatformInfo::x86_64: cpuType = CPU_TYPE_X86_64; cpuSubType = CPU_SUBTYPE_X86_64_ALL; break; case PlatformInfo::x86: cpuType = CPU_TYPE_I386; cpuSubType = CPU_SUBTYPE_I386_ALL; break; case PlatformInfo::PowerPC: cpuType = CPU_TYPE_POWERPC; cpuSubType = CPU_SUBTYPE_POWERPC_ALL; break; case PlatformInfo::Arm: cpuType = CPU_TYPE_ARM; cpuSubType = CPU_SUBTYPE_ARM_V7; break; default: // should never happen (see MachOPlatform declarations at bottom) fprintf(stderr, "unsupported architecture: %d\n", info.arch); return false; } const char* segmentName; const char* sectionName; if (accessFlags & Writable) { if (accessFlags & Executable) { segmentName = "__RWX"; sectionName = "__rwx"; } else { segmentName = "__DATA"; sectionName = "__data"; } } else { segmentName = "__TEXT"; sectionName = "__text"; } FileHeader header = { V4(Magic), // magic static_cast(V4(cpuType)), static_cast(V4(cpuSubType)), V4(MH_OBJECT), // filetype, V4(2), // ncmds V4(sizeof(SegmentCommand) + sizeof(Section) + sizeof(SymtabCommand)), // sizeofcmds { V4(0) } // flags }; AddrTy finalSize = pad(data.count); SegmentCommand segment = { V4(Segment), // cmd V4(sizeof(SegmentCommand) + sizeof(Section)), // cmdsize "", // segname VANY(static_cast(0)), // vmaddr VANY(static_cast(finalSize)), // vmsize VANY(static_cast(sizeof(FileHeader) + sizeof(SegmentCommand) + sizeof(Section) + sizeof(SymtabCommand))), // fileoff VANY(static_cast(finalSize)), // filesize static_cast(V4(7)), // maxprot static_cast(V4(7)), // initprot V4(1), // nsects V4(0) // flags }; strncpy(segment.segname, segmentName, sizeof(segment.segname)); Section sect = { "", // sectname "", // segname VANY(static_cast(0)), // addr VANY(static_cast(finalSize)), // size V4(sizeof(FileHeader) + sizeof(SegmentCommand) + sizeof(Section) + sizeof(SymtabCommand)), // offset V4(log(alignment)), // align V4(0), // reloff V4(0), // nreloc V4(S_REGULAR), // flags V4(0), // reserved1 V4(0), // reserved2 }; strncpy(sect.segname, segmentName, sizeof(sect.segname)); strncpy(sect.sectname, sectionName, sizeof(sect.sectname)); StringTable strings; strings.add(""); Buffer symbolList; for(SymbolInfo* sym = symbols.begin(); sym != symbols.end(); sym++) { unsigned offset = strings.length; strings.write("_", 1); strings.add(sym->name); NList symbol = { { V4(offset) }, // n_un V1(N_SECT | N_EXT), // n_type V1(1), // n_sect V2(0), // n_desc VANY(static_cast(sym->addr)) // n_value }; symbolList.write(&symbol, sizeof(NList)); } SymtabCommand symbolTable = { V4(LC_SYMTAB), // cmd V4(sizeof(SymtabCommand)), // cmdsize V4(sizeof(FileHeader) + sizeof(SegmentCommand) + sizeof(Section) + sizeof(SymtabCommand) + finalSize), // symoff V4(symbols.count), // nsyms V4(sizeof(FileHeader) + sizeof(SegmentCommand) + sizeof(Section) + sizeof(SymtabCommand) + finalSize + (sizeof(NList) * symbols.count)), // stroff V4(strings.length), // strsize }; out->writeChunk(&header, sizeof(header)); out->writeChunk(&segment, sizeof(segment)); out->writeChunk(§, sizeof(sect)); out->writeChunk(&symbolTable, sizeof(symbolTable)); out->writeChunk(data.items, data.count); out->writeRepeat(0, finalSize - data.count); out->writeChunk(symbolList.data, symbolList.length); out->writeChunk(strings.data, strings.length); return true; } MachOPlatform(PlatformInfo::Architecture arch): Platform(PlatformInfo(PlatformInfo::MachO, arch)) {} }; MachOPlatform darwinx86Platform(PlatformInfo::x86); MachOPlatform darwinArmPlatform(PlatformInfo::Arm); MachOPlatform darwinPowerPCPlatform(PlatformInfo::PowerPC); MachOPlatform darwinx86_64Platform(PlatformInfo::x86_64); } // namespace ReadyTalk-avian-1e1fff5/src/tools/object-writer/pe.cpp000066400000000000000000000200601231440243200227750ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include #include namespace { // --- winnt.h ---- #define IMAGE_SIZEOF_SHORT_NAME 8 #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) #define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386. #define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian #define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian #define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian #define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. #define IMAGE_SCN_ALIGN_1BYTES 0x100000 #define IMAGE_SCN_ALIGN_2BYTES 0x200000 #define IMAGE_SCN_ALIGN_4BYTES 0x300000 #define IMAGE_SCN_ALIGN_8BYTES 0x400000 #define IMAGE_SCN_MEM_EXECUTE 0x20000000 #define IMAGE_SCN_MEM_READ 0x40000000 #define IMAGE_SCN_MEM_WRITE 0x80000000 #define IMAGE_SCN_CNT_CODE 32 struct IMAGE_FILE_HEADER { uint16_t Machine; uint16_t NumberOfSections; uint32_t TimeDateStamp; uint32_t PointerToSymbolTable; uint32_t NumberOfSymbols; uint16_t SizeOfOptionalHeader; uint16_t Characteristics; } __attribute__((packed)); struct IMAGE_SECTION_HEADER { uint8_t Name[IMAGE_SIZEOF_SHORT_NAME]; union { uint32_t PhysicalAddress; uint32_t VirtualSize; } Misc; uint32_t VirtualAddress; uint32_t SizeOfRawData; uint32_t PointerToRawData; uint32_t PointerToRelocations; uint32_t PointerToLinenumbers; uint16_t NumberOfRelocations; uint16_t NumberOfLinenumbers; uint32_t Characteristics; } __attribute__((packed)); struct IMAGE_SYMBOL { union { struct { uint32_t Short; uint32_t Long; } Name; } N; uint32_t Value; int16_t SectionNumber; uint16_t Type; uint8_t StorageClass; uint8_t NumberOfAuxSymbols; } __attribute__((packed)); // --- winnt.h ---- inline unsigned pad(unsigned n) { return (n + (4 - 1)) & ~(4 - 1); } using namespace avian::tools; using namespace avian::util; template class WindowsPlatform : public Platform { public: class FileWriter { public: unsigned sectionCount; unsigned symbolCount; unsigned dataStart; unsigned dataOffset; IMAGE_FILE_HEADER header; StringTable strings; Buffer symbols; FileWriter(unsigned machine, unsigned machineMask, unsigned symbolCount): sectionCount(0), symbolCount(symbolCount), dataStart(sizeof(IMAGE_FILE_HEADER)), dataOffset(0) { header.Machine = machine; // header.NumberOfSections = sectionCount; header.TimeDateStamp = 0; // header.PointerToSymbolTable = sizeof(IMAGE_FILE_HEADER) // + sizeof(IMAGE_SECTION_HEADER) // + pad(size); // header.NumberOfSymbols = symbolCount; header.SizeOfOptionalHeader = 0; header.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_LINE_NUMS_STRIPPED | machineMask; } void writeHeader(OutputStream* out) { header.NumberOfSections = sectionCount; header.PointerToSymbolTable = dataStart + dataOffset; dataOffset = pad(dataOffset + symbolCount * sizeof(IMAGE_SYMBOL)); header.NumberOfSymbols = symbolCount; out->writeChunk(&header, sizeof(IMAGE_FILE_HEADER)); } void addSymbol(String name, unsigned addr, unsigned sectionNumber, unsigned type, unsigned storageClass) { unsigned nameOffset = strings.add(name); IMAGE_SYMBOL symbol = { { { 0, 0 } }, // Name addr, // Value static_cast(sectionNumber), // SectionNumber static_cast(type), // Type static_cast(storageClass), // StorageClass 0, // NumberOfAuxSymbols }; symbol.N.Name.Long = nameOffset+4; symbols.write(&symbol, sizeof(IMAGE_SYMBOL)); } void writeData(OutputStream* out) { out->writeChunk(symbols.data, symbols.length); uint32_t size = strings.length + 4; out->writeChunk(&size, 4); out->writeChunk(strings.data, strings.length); } }; class SectionWriter { public: FileWriter& file; IMAGE_SECTION_HEADER header; size_t dataSize; size_t finalSize; const uint8_t* data; unsigned dataOffset; SectionWriter( FileWriter& file, const char* name, unsigned sectionMask, const uint8_t* data, size_t dataSize): file(file), dataSize(dataSize), finalSize(pad(dataSize)), data(data) { file.sectionCount++; file.dataStart += sizeof(IMAGE_SECTION_HEADER); strcpy(reinterpret_cast(header.Name), name); header.Misc.VirtualSize = 0; header.SizeOfRawData = finalSize; // header.PointerToRawData = file.dataOffset; dataOffset = file.dataOffset; file.dataOffset += finalSize; header.PointerToRelocations = 0; header.PointerToLinenumbers = 0; header.NumberOfRelocations = 0; header.NumberOfLinenumbers = 0; header.Characteristics = sectionMask; } void writeHeader(OutputStream* out) { header.PointerToRawData = dataOffset + file.dataStart; out->writeChunk(&header, sizeof(IMAGE_SECTION_HEADER)); } void writeData(OutputStream* out) { out->writeChunk(data, dataSize); out->writeRepeat(0, finalSize - dataSize); } }; virtual bool writeObject(OutputStream* out, Slice symbols, Slice data, unsigned accessFlags, unsigned alignment) { int machine; int machineMask; if (Architecture == PlatformInfo::x86_64) { machine = IMAGE_FILE_MACHINE_AMD64; machineMask = 0; } else if (Architecture == PlatformInfo::x86) { machine = IMAGE_FILE_MACHINE_I386; machineMask = IMAGE_FILE_32BIT_MACHINE; } else if (Architecture == PlatformInfo::Arm) { machine = IMAGE_FILE_MACHINE_ARMNT; machineMask = IMAGE_FILE_32BIT_MACHINE; } int sectionMask; switch (alignment) { case 0: case 1: sectionMask = IMAGE_SCN_ALIGN_1BYTES; break; case 2: sectionMask = IMAGE_SCN_ALIGN_2BYTES; break; case 4: sectionMask = IMAGE_SCN_ALIGN_4BYTES; break; case 8: sectionMask = IMAGE_SCN_ALIGN_8BYTES; break; default: fprintf(stderr, "unsupported alignment: %d\n", alignment); return false; } sectionMask |= IMAGE_SCN_MEM_READ; const char* sectionName; if (accessFlags & Platform::Writable) { if (accessFlags & Platform::Executable) { sectionName = ".rwx"; sectionMask |= IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE; } else { sectionName = ".data"; sectionMask |= IMAGE_SCN_MEM_WRITE; } } else { sectionName = ".text"; sectionMask |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE; } FileWriter file(machine, machineMask, symbols.count); SectionWriter section(file, sectionName, sectionMask, data.items, data.count); file.writeHeader(out); for(SymbolInfo* sym = symbols.begin(); sym != symbols.end(); sym++) { file.addSymbol(sym->name, sym->addr, 1, 0, 2); } section.writeHeader(out); section.writeData(out); file.writeData(out); return true; } WindowsPlatform(): Platform(PlatformInfo(PlatformInfo::Pe, Architecture)) {} }; WindowsPlatform<4, PlatformInfo::x86> windows32Platform; WindowsPlatform<8, PlatformInfo::x86_64> windows64Platform; WindowsPlatform<4, PlatformInfo::Arm> windowsRtPlatform; // Windows Phone 8 and Windows RT } // namespace ReadyTalk-avian-1e1fff5/src/tools/object-writer/tools.cpp000066400000000000000000000053021231440243200235330ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include #include using namespace avian::util; namespace avian { namespace tools { Buffer::Buffer(): capacity(100), length(0), data((uint8_t*)malloc(capacity)) {} Buffer::~Buffer() { free(data); } void Buffer::ensure(size_t more) { if(length + more > capacity) { capacity = capacity * 2 + more; data = (uint8_t*)realloc(data, capacity); } } void Buffer::write(const void* d, size_t size) { ensure(size); memcpy(data + length, d, size); length += size; } unsigned StringTable::add(String str) { unsigned offset = Buffer::length; Buffer::write(str.text, str.length + 1); return offset; } void OutputStream::write(uint8_t byte) { writeChunk(&byte, 1); } void OutputStream::writeRepeat(uint8_t byte, size_t size) { for(size_t i = 0; i < size; i++) { write(byte); } } FileOutputStream::FileOutputStream(const char* name): file(fopen(name, "wb")) {} FileOutputStream::~FileOutputStream() { if(file) { fclose(file); } } bool FileOutputStream::isValid() { return file; } void FileOutputStream::writeChunk(const void* data, size_t size) { fwrite(data, size, 1, file); } void FileOutputStream::write(uint8_t byte) { fputc(byte, file); } Platform* Platform::first = 0; PlatformInfo::Format PlatformInfo::formatFromString(const char* format) { if (strcmp(format, "elf") == 0 or strcmp(format, "linux") == 0 or strcmp(format, "freebsd") == 0 or strcmp(format, "qnx") == 0) { return Elf; } else if (strcmp(format, "pe") == 0 or strcmp(format, "windows") == 0) { return Pe; } else if (strcmp(format, "macho") == 0 or strcmp(format, "darwin") == 0) { return MachO; } else { return UnknownFormat; } } PlatformInfo::Architecture PlatformInfo::archFromString(const char* arch) { if(strcmp(arch, "i386") == 0) { return x86; } else if(strcmp(arch, "x86_64") == 0) { return x86_64; } else if(strcmp(arch, "powerpc") == 0) { return PowerPC; } else if(strcmp(arch, "arm") == 0) { return Arm; } else { return UnknownArch; } } Platform* Platform::getPlatform(PlatformInfo info) { for(Platform* p = first; p; p = p->next) { if(p->info == info) { return p; } } return 0; } } // namespace tools } // namespace avian ReadyTalk-avian-1e1fff5/src/tools/type-generator/000077500000000000000000000000001231440243200220545ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/tools/type-generator/io.h000066400000000000000000000051061231440243200226360ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "assert.h" #ifndef AVIAN_TOOLS_TYPE_GENERATOR_IO_H #define AVIAN_TOOLS_TYPE_GENERATOR_IO_H namespace avian { namespace tools { namespace typegenerator { class Input { public: virtual ~Input() { } virtual void dispose() = 0; virtual int peek() = 0; virtual int read() = 0; virtual unsigned line() = 0; virtual unsigned column() = 0; void skipSpace() { bool quit = false; while (not quit) { int c = peek(); switch (c) { case ' ': case '\t': case '\n': read(); break; default: quit = true; } } } }; class FileInput : public Input { public: const char* file; FILE* stream; unsigned line_; unsigned column_; bool close; FileInput(const char* file, FILE* stream = 0, bool close = true): file(file), stream(stream), line_(1), column_(1), close(close) { } virtual ~FileInput() { dispose(); } virtual void dispose() { if (stream and close) { fclose(stream); stream = 0; } } virtual int peek() { int c = getc(stream); ungetc(c, stream); return c; } virtual int read() { int c = getc(stream); if (c == '\n') { ++ line_; column_ = 1; } else { ++ column_; } return c; } virtual unsigned line() { return line_; } virtual unsigned column() { return column_; } }; class Output { public: virtual ~Output() { } virtual void dispose() = 0; virtual void write(const char* s) = 0; void write(int i) { static const int Size = 32; char s[Size]; int c UNUSED = ::snprintf(s, Size, "%d", i); assert(c > 0 and c < Size); write(s); } }; class FileOutput : public Output { public: const char* file; FILE* stream; bool close; FileOutput(const char* file, FILE* stream = 0, bool close = true): file(file), stream(stream), close(close) { } virtual ~FileOutput() { dispose(); } virtual void dispose() { if (stream and close) { fclose(stream); stream = 0; } } virtual void write(const char* s) { fputs(s, stream); } const char* filename() { return file; } }; } // namespace typegenerator } // namespace tools } // namespace avian #endif // AVIAN_TOOLS_TYPE_GENERATOR_IO_H ReadyTalk-avian-1e1fff5/src/tools/type-generator/main.cpp000066400000000000000000001226211231440243200235100ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "stdlib.h" #include "stdio.h" #include "stdint.h" #include "string.h" #include "errno.h" #include "avian/constants.h" #include "avian/finder.h" #include #include "io.h" #include "sexpr.h" #include "assert.h" #define UNREACHABLE abort() #define UNUSED __attribute__((unused)) void operator delete(void*) { abort(); } extern "C" void __cxa_pure_virtual(void) { abort(); } using namespace vm; using namespace avian::tools::typegenerator; namespace { namespace local { #ifndef POINTER_SIZE # define POINTER_SIZE sizeof(void*) #endif const unsigned BytesPerWord = POINTER_SIZE; inline unsigned pad(unsigned size, unsigned alignment) { unsigned n = alignment; while (size and n % size) ++ n; return n - alignment; } inline unsigned pad(unsigned n) { unsigned extra = n % BytesPerWord; return (extra ? n + BytesPerWord - extra : n); } inline bool equal(const char* a, const char* b) { return strcmp(a, b) == 0; } inline bool endsWith(const char* a, const char* b) { unsigned al = strlen(a); unsigned bl = strlen(b); return (bl >= al) and strncmp(a, b + (bl - al), al) == 0; } inline const char* take(unsigned n, const char* c) { char* r = static_cast(malloc(n + 1)); assert(r); memcpy(r, c, n); r[n] = 0; return r; } class Scalar : public Object { public: Object* owner; const char* typeName; const char* name; unsigned elementSize; bool noassert; bool nogc; static Scalar* make(Object* owner, const char* typeName, const char* name, unsigned size) { Scalar* o = allocate(); o->type = Object::Scalar; o->owner = owner; o->typeName = typeName; o->name = name; o->elementSize = size; o->noassert = false; o->nogc = false; return o; } }; class Array : public Scalar { public: static Array* make(Object* owner, const char* typeName, const char* name, unsigned elementSize) { Array* o = allocate(); o->type = Object::Array; o->owner = owner; o->typeName = typeName; o->name = name; o->elementSize = elementSize; o->noassert = false; o->nogc = false; return o; } }; unsigned arrayElementSize(Object* o) { switch (o->type) { case Object::Array: return static_cast(o)->elementSize; default: UNREACHABLE; } } Object* memberOwner(Object* o) { switch (o->type) { case Object::Scalar: case Object::Array: return static_cast(o)->owner; default: UNREACHABLE; } } const char* memberTypeName(Object* o) { switch (o->type) { case Object::Scalar: case Object::Array: return static_cast(o)->typeName; default: UNREACHABLE; } } const char* memberTypeEnumName(Object* o) { const char* n = memberTypeName(o); if (strcmp("void*", n) == 0) { return "word"; } else { return n; } } const char*& memberName(Object* o) { switch (o->type) { case Object::Scalar: case Object::Array: return static_cast(o)->name; default: UNREACHABLE; } } unsigned memberSize(Object* o) { switch (o->type) { case Object::Scalar: return static_cast(o)->elementSize; default: UNREACHABLE; } } unsigned memberElementSize(Object* o) { switch (o->type) { case Object::Scalar: case Object::Array: return static_cast(o)->elementSize; default: UNREACHABLE; } } bool& memberNoAssert(Object* o) { switch (o->type) { case Object::Scalar: case Object::Array: return static_cast(o)->noassert; default: UNREACHABLE; } } bool& memberNoGC(Object* o) { switch (o->type) { case Object::Scalar: case Object::Array: return static_cast(o)->nogc; default: UNREACHABLE; } } bool memberGC(Object* o) { return not memberNoGC(o) and equal(memberTypeName(o), "object"); } class Method : public Object { public: Object* owner; const char* name; const char* spec; static Method* make(Object* owner, const char* name, const char* spec) { Method* o = allocate(); o->type = Object::Method; o->owner = owner; o->name = name; o->spec = spec; return o; } }; const char* methodName(Object* o) { switch (o->type) { case Object::Method: return static_cast(o)->name; default: UNREACHABLE; } } const char* methodSpec(Object* o) { switch (o->type) { case Object::Method: return static_cast(o)->spec; default: UNREACHABLE; } } class Type : public Object { public: const char* name; const char* javaName; Object* super; List members; List methods; bool overridesMethods; static Type* make(Object::ObjectType type, const char* name, const char* javaName) { Type* o = allocate(); o->type = type; o->name = name; o->javaName = javaName; o->super = 0; o->members.first = o->members.last = 0; o->methods.first = o->methods.last = 0; o->overridesMethods = false; return o; } }; const char* typeName(Object* o) { switch (o->type) { case Object::Type: return static_cast(o)->name; default: UNREACHABLE; } } const char* typeJavaName(Object* o) { switch (o->type) { case Object::Type: return static_cast(o)->javaName; default: UNREACHABLE; } } Object* typeMembers(Object* o) { switch (o->type) { case Object::Type: return static_cast(o)->members.first; default: UNREACHABLE; } } Object* typeMethods(Object* o) { switch (o->type) { case Object::Type: return static_cast(o)->methods.first; default: UNREACHABLE; } } bool& typeOverridesMethods(Object* o) { switch (o->type) { case Object::Type: return static_cast(o)->overridesMethods; default: UNREACHABLE; } } void addMember(Object* o, Object* member) { switch (o->type) { case Object::Type: if (member->type == Object::Array) { static_cast(o)->members.append (Scalar::make(o, "uintptr_t", "length", BytesPerWord)); } static_cast(o)->members.append(member); break; default: UNREACHABLE; } } void addMethod(Object* o, Object* method) { switch (o->type) { case Object::Type: for (Object* p = typeMethods(o); p; p = cdr(p)) { Object* m = car(p); if (equal(methodName(m), methodName(method)) and equal(methodSpec(m), methodSpec(method))) { setCar(p, method); return; } } static_cast(o)->methods.append(method); break; default: UNREACHABLE; } } Object*& typeSuper(Object* o) { switch (o->type) { case Object::Type: return static_cast(o)->super; default: UNREACHABLE; } } class Number : public Object { public: unsigned value; static Number* make(unsigned value) { Number* o = allocate(); o->type = Object::Number; o->value = value; return o; } }; unsigned number(Object* o) { assert(o->type == Object::Number); return static_cast(o)->value; } class Character : public Object { public: char value; static Character* make(char value) { Character* o = allocate(); o->type = Object::Character; o->value = value; return o; } }; char character(Object* o) { assert(o->type == Object::Character); return static_cast(o)->value; } class String : public Object { public: const char* value; static String* make(Object* s) { assert(s); String* o = allocate(); o->type = Object::String; unsigned length = 0; for (Object* p = s; p; p = cdr(p)) ++ length; char* value = static_cast(malloc(length + 1)); assert(value); unsigned i = 0; for (Object* p = s; p; p = cdr(p)) value[i++] = character(car(p)); value[i] = 0; o->value = value; return o; } }; const char* string(Object* o) { assert(o->type == Object::String); return static_cast(o)->value; } class Singleton : public Object { public: static Singleton* make(Object::ObjectType type) { Singleton* o = allocate(); o->type = type; return o; } }; bool endsWith(char c, const char* s) { assert(s); if (*s == 0) return false; while (*s) ++ s; return (*(s - 1) == c); } const char* capitalize(const char* s) { assert(s); unsigned length = strlen(s); assert(length); char* r = static_cast(malloc(length + 1)); assert(r); memcpy(r, s, length + 1); if (r[0] >= 'a' and r[0] <= 'z') r[0] = (r[0] - 'a') + 'A'; return r; } Object* read(Input* in, Object* eos, int level) { List s; int c; while ((c = in->peek()) >= 0) { switch (c) { case '(': { if (s.first) { return String::make(s.first); } else { List list; Object* o; in->read(); while ((o = read(in, eos, level + 1)) != eos) { list.append(o); } return list.first; } } break; case ')': { if (s.first) { return String::make(s.first); } else { if (level == 0) { fprintf(stderr, "unexpected ')'\n"); abort(); } in->read(); return eos; } } break; case ' ': case '\t': case '\n': case '\r': { if (s.first) { return String::make(s.first); } } break; default: { s.append(Character::make(c)); } break; } in->read(); } if (level == 0) { if (s.first) { return String::make(s.first); } else { return eos; } } else { fprintf(stderr, "unexpected end of stream\n"); abort(); } } Object* declaration(const char* name, Object* declarations) { for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); switch (o->type) { case Object::Type: if (equal(name, typeName(o))) return o; break; default: UNREACHABLE; } } return 0; } Object* javaDeclaration(const char* name, Object* declarations) { for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); switch (o->type) { case Object::Type: if (typeJavaName(o) and equal(name, typeJavaName(o))) return o; break; default: UNREACHABLE; } } return 0; } Object* derivationChain(Object* o) { Object* chain = 0; for (Object* p = o; p; p = typeSuper(p)) { chain = cons(p, chain); } return chain; } class MemberIterator { public: Object* types; Object* type; Object* members; Object* member; int index_; unsigned offset_; unsigned size_; unsigned padding_; unsigned alignment_; unsigned sawSuperclassBoundary; MemberIterator(Object* type, bool skipSupers = false): types(derivationChain(type)), type(car(types)), members(0), member(0), index_(-1), offset_(BytesPerWord), size_(0), padding_(0), alignment_(BytesPerWord), sawSuperclassBoundary(true) { while (skipSupers and hasMore() and this->type != type) next(); padding_ = 0; alignment_ = BytesPerWord; } bool hasMore() { if (members) { return true; } else { while (types) { if (member) { assert(member->type == Object::Scalar); offset_ = ((offset_ + size_) + (BytesPerWord - 1)) & ~(BytesPerWord - 1); alignment_ = BytesPerWord; sawSuperclassBoundary = true; member = 0; } else { sawSuperclassBoundary = false; } type = car(types); members = typeMembers(type); types = cdr(types); if (members) return true; } return false; } } Object* next() { assert(hasMore()); if (member) { assert(member->type == Object::Scalar); offset_ += size_; } member = car(members); members = cdr(members); ++ index_; switch (member->type) { case Object::Scalar: { size_ = memberSize(member); padding_ = pad(size_, alignment_); alignment_ = (alignment_ + size_ + padding_) % 8; } break; case Object::Array: { size_ = 0x7FFFFFFF; padding_ = pad(memberElementSize(member), alignment_); alignment_ = 0; } break; default: UNREACHABLE; } offset_ += padding_; // fprintf(stderr, // "type: %s; member: %s; size: %d; padding: %d; alignment: %d;" // " offset: %d;\n", // typeName(type), memberName(member), size_, padding_, alignment_, // offset_); return member; } unsigned offset() { return offset_; } unsigned size() { return size_; } unsigned padding() { return padding_; } unsigned space() { return size_ + padding_; } unsigned index() { return index_; } unsigned alignment() { return alignment_; } }; bool namesPointer(const char* s) { return equal(s, "Collector") or equal(s, "Disposer") or endsWith('*', s); } unsigned sizeOf(const char* type) { if (equal(type, "object") or equal(type, "intptr_t") or equal(type, "uintptr_t")) { return BytesPerWord; } else if (equal(type, "unsigned") or equal(type, "int")) { return sizeof(int); } else if (equal(type, "bool")) { return sizeof(bool); } else if (equal(type, "int8_t") or equal(type, "uint8_t")) { return sizeof(uint8_t); } else if (equal(type, "int16_t") or equal(type, "uint16_t")) { return sizeof(uint16_t); } else if (equal(type, "int32_t") or equal(type, "uint32_t")) { return sizeof(uint32_t); } else if (equal(type, "int64_t") or equal(type, "uint64_t")) { return sizeof(uint64_t); } else if (equal(type, "char")) { return sizeof(char); } else if (endsWith("[0]", type)) { return 0; } else if (namesPointer(type)) { return BytesPerWord; } else { fprintf(stderr, "unexpected type: %s\n", type); abort(); } } Object* parseArray(Object* t, Object* p) { const char* typeName = string(car(p)); p = cdr(p); const char* name = string(car(p)); return Array::make(t, typeName, name, sizeOf(typeName)); } Object* parseMember(Object* t, Object* p); Object* parseMember(Object* t, Object* p, bool* isNew) { Object* member = parseMember(t, p); for (MemberIterator it(t); it.hasMore();) { Object* m = it.next(); if (equal(memberName(m), memberName(member))) { if (not equal(memberTypeName(m), memberTypeName(member))) { abort(); } *isNew = false; return m; } } *isNew = true; return member; } Object* parseMember(Object* t, Object* p) { const char* spec = string(car(p)); if (equal(spec, "array")) { return parseArray(t, cdr(p)); } else if (equal(spec, "noassert")) { bool isNew; Object* member = parseMember(t, cdr(p), &isNew); memberNoAssert(member) = true; return isNew ? member : 0; } else if (equal(spec, "nogc")) { bool isNew; Object* member = parseMember(t, cdr(p), &isNew); memberNoGC(member) = true; return isNew ? member : 0; } else if (equal(spec, "require")) { bool isNew; Object* member = parseMember(t, cdr(p), &isNew); return isNew ? member : 0; } else if (equal(spec, "alias")) { bool isNew; Object* member = parseMember(t, cdr(cdr(p)), &isNew); memberName(member) = string(car(cdr(p))); return 0; } else { return Scalar::make(t, spec, string(car(cdr(p))), sizeOf(spec)); } } void parseSubdeclaration(Object* t, Object* p, Object* declarations) { const char* front = string(car(p)); if (equal(front, "extends")) { assert(t->type == Object::Type); assert(typeSuper(t) == 0); typeSuper(t) = declaration(string(car(cdr(p))), declarations); assert(typeSuper(t)); assert(typeSuper(t)->type == Object::Type); } else { Object* member = parseMember(t, p); if (member) { addMember(t, member); } } } const char* append(const char* a, const char* b, const char* c, const char* d) { unsigned al = strlen(a); unsigned bl = strlen(b); unsigned cl = strlen(c); unsigned dl = strlen(d); char* p = static_cast(malloc(al + bl + cl + dl + 1)); memcpy(p, a, al); memcpy(p + al, b, bl); memcpy(p + al + bl, c, cl); memcpy(p + al + bl + cl, d, dl + 1); return p; } const char* append(const char* a, const char* b) { return append(a, b, "", ""); } const char* fieldType(const char* spec) { switch (*spec) { case 'B': case 'Z': return "uint8_t"; case 'C': case 'S': return "uint16_t"; case 'D': case 'J': return "uint64_t"; case 'F': case 'I': return "uint32_t"; case 'L': case '[': return "object"; default: abort(); } } void parseJavaClass(Object* type, Stream* s, Object* declarations) { uint32_t magic = s->read4(); assert(magic == 0xCAFEBABE); s->read2(); // minor version s->read2(); // major version unsigned poolCount = s->read2() - 1; uintptr_t pool[poolCount]; for (unsigned i = 0; i < poolCount; ++i) { unsigned c = s->read1(); switch (c) { case CONSTANT_Integer: case CONSTANT_Float: pool[i] = s->read4(); break; case CONSTANT_Long: case CONSTANT_Double: pool[i++] = s->read4(); pool[i] = s->read4(); break; case CONSTANT_Utf8: { unsigned length = s->read2(); uint8_t* p = static_cast(malloc(length + 1)); s->read(p, length); p[length] = 0; pool[i] = reinterpret_cast(p); } break; case CONSTANT_Class: case CONSTANT_String: pool[i] = s->read2(); break; case CONSTANT_NameAndType: pool[i] = s->read4(); break; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: pool[i] = s->read4(); break; default: abort(); } } s->read2(); // flags s->read2(); // name unsigned superIndex = s->read2(); if (superIndex) { const char* name = reinterpret_cast (pool[pool[superIndex - 1] - 1]); typeSuper(type) = javaDeclaration(name, declarations); assert(typeSuper(type)); } unsigned interfaceCount = s->read2(); s->skip(interfaceCount * 2); // for (unsigned i = 0; i < interfaceCount; ++i) { // const char* name = reinterpret_cast // (pool[pool[s->read2() - 1] - 1]); // } unsigned fieldCount = s->read2(); for (unsigned i = 0; i < fieldCount; ++i) { unsigned flags = s->read2(); unsigned nameIndex = s->read2(); unsigned specIndex = s->read2(); unsigned attributeCount = s->read2(); for (unsigned j = 0; j < attributeCount; ++j) { s->read2(); s->skip(s->read4()); } if ((flags & ACC_STATIC) == 0) { char* name = reinterpret_cast(pool[nameIndex - 1]); unsigned nameLength = strlen(name); if (nameLength > 0 and name[nameLength - 1] == '_') { name[nameLength - 1] = 0; } const char* spec = reinterpret_cast(pool[specIndex - 1]); const char* memberType = fieldType(spec); Object* member = Scalar::make (type, memberType, name, sizeOf(memberType)); addMember(type, member); } } if (typeSuper(type)) { for (Object* p = typeMethods(typeSuper(type)); p; p = cdr(p)) { addMethod(type, car(p)); } } unsigned methodCount = s->read2(); for (unsigned i = 0; i < methodCount; ++i) { unsigned flags = s->read2(); unsigned nameIndex = s->read2(); unsigned specIndex = s->read2(); unsigned attributeCount = s->read2(); for (unsigned j = 0; j < attributeCount; ++j) { s->read2(); s->skip(s->read4()); } const char* name = reinterpret_cast(pool[nameIndex - 1]); const char* spec = reinterpret_cast(pool[specIndex - 1]); if ((flags & (ACC_STATIC | ACC_PRIVATE)) == 0 and *name != '<') { Object* method = Method::make(type, name, spec); addMethod(type, method); typeOverridesMethods(type) = true; } } } Object* parseType(Finder* finder, Object::ObjectType type, Object* p, Object* declarations) { const char* name = string(car(p)); const char* javaName = 0; if (cdr(p) and car(cdr(p))->type == Object::String) { p = cdr(p); javaName = string(car(p)); } Type* t = Type::make(type, name, javaName); bool isJavaType = javaName and *javaName != '['; if (isJavaType) { class Client: public Stream::Client { public: virtual void NO_RETURN handleError() { abort(); } } client; System::Region* region = finder->find(append(javaName, ".class")); Stream s(&client, region->start(), region->length()); parseJavaClass(t, &s, declarations); region->dispose(); } for (p = cdr(p); p; p = cdr(p)) { if (type == Object::Type) { parseSubdeclaration(t, car(p), declarations); } else { Object* member = parseMember(t, car(p)); if (member) { assert(member->type == Object::Scalar); addMember(t, member); } } } if (not isJavaType) { if (type == Object::Type and typeSuper(t)) { for (Object* p = typeMethods(typeSuper(t)); p; p = cdr(p)) { addMethod(t, car(p)); } } } return t; } Object* parseDeclaration(Finder* finder, Object* p, Object* declarations) { const char* spec = string(car(p)); if (equal(spec, "type")) { return parseType(finder, Object::Type, cdr(p), declarations); } else { fprintf(stderr, "unexpected declaration spec: %s\n", spec); abort(); } } Object* parse(Finder* finder, Input* in) { Object* eos = Singleton::make(Object::Eos); List declarations; Object* o; while ((o = read(in, eos, 0)) != eos) { declarations.append (parseDeclaration(finder, o, declarations.first)); } return declarations.first; } void writeAccessorName(Output* out, Object* member, bool unsafe = false) { const char* owner = typeName(memberOwner(member)); out->write(owner); out->write(capitalize(memberName(member))); if (unsafe) { out->write("Unsafe"); } } void writeOffset(Output* out, Object* offset, bool allocationStyle = false) { if (offset) { bool wrote = false; unsigned padLevel = 0; for (Object* p = offset; p; p = cdr(p)) { Object* o = car(p); if (wrote) { out->write(" + "); } switch (o->type) { case Object::Number: { if (number(o)) { out->write(number(o)); wrote = true; } } break; case Object::Array: { out->write("pad(("); if (allocationStyle) { out->write("length"); } else { out->write(typeName(memberOwner(o))); out->write("Length"); out->write("(o)"); } out->write(" * "); out->write(arrayElementSize(o)); out->write(")"); ++ padLevel; wrote = true; } break; default: UNREACHABLE; } } for (unsigned i = 0; i < padLevel; ++i) out->write(")"); } else { out->write("0"); } } void writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) { const char* typeName = memberTypeName(member); if (not unsafe) { out->write("const unsigned "); out->write(capitalize(local::typeName(memberOwner(member)))); out->write(capitalize(memberName(member))); out->write(" = "); writeOffset(out, offset); out->write(";\n\n"); out->write("#define HAVE_"); out->write(capitalize(local::typeName(memberOwner(member)))); out->write(capitalize(memberName(member))); out->write(" 1\n\n"); } out->write("inline "); if (endsWith("[0]", typeName)) { out->write(take(strlen(typeName) - 3, typeName)); out->write("*"); } else { out->write(typeName); out->write("&"); } out->write("\n"); writeAccessorName(out, member, unsafe); out->write("(Thread* t UNUSED, object"); out->write(" o"); if (member->type != Object::Scalar) { out->write(", unsigned i"); } out->write(") {\n"); if (memberOwner(member)->type == Object::Type) { if (not unsafe) { out->write(" assert(t, t->m->unsafe or "); out->write("instanceOf(t, arrayBodyUnsafe"); out->write("(t, t->m->types, Machine::"); out->write(capitalize(local::typeName(memberOwner(member)))); out->write("Type)"); out->write(", o));\n"); if (member->type != Object::Scalar) { out->write(" assert(t, i < "); out->write(local::typeName(memberOwner(member))); out->write("Length(t, o));\n"); } } } out->write(" return reinterpret_cast<"); if (endsWith("[0]", typeName)) { out->write(take(strlen(typeName) - 3, typeName)); out->write("*"); } else { out->write(typeName); out->write("&"); } out->write(">(reinterpret_cast(o)"); out->write("["); out->write(capitalize(local::typeName(memberOwner(member)))); out->write(capitalize(memberName(member))); if (member->type != Object::Scalar) { out->write(" + (i * "); unsigned elementSize = sizeOf(memberTypeName(member)); out->write(elementSize); out->write(")"); } out->write("]);\n}\n\n"); } Object* typeBodyOffset(Object* type, Object* offset) { MemberIterator it(type, true); while (it.hasMore()) { Object* m = it.next(); switch (m->type) { case Object::Scalar: { offset = cons(Number::make(it.space()), offset); } break; case Object::Array: { if (it.padding()) offset = cons(Number::make(it.padding()), offset); offset = cons(m, offset); } break; default: UNREACHABLE; } } unsigned padding = pad(BytesPerWord, it.alignment()); if (padding) offset = cons(Number::make(padding), offset); return offset; } Object* typeOffset(Object* type, Object* super) { if (super) { return typeBodyOffset(super, typeOffset(super, typeSuper(super))); } else { return (type->type == Object::Type ? cons(Number::make(BytesPerWord), 0) : 0); } } Object* typeOffset(Object* type) { return typeOffset(0, type); } void writeAccessors(Output* out, Object* declarations) { for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); switch (o->type) { case Object::Type: { Object* offset = typeOffset (o, o->type == Object::Type ? typeSuper(o) : 0); for (MemberIterator it(o, true); it.hasMore();) { Object* m = it.next(); switch (m->type) { case Object::Scalar: { if (it.padding()) offset = cons(Number::make(it.padding()), offset); writeAccessor(out, m, offset); if (memberNoAssert(m)) { writeAccessor(out, m, offset, true); } offset = cons(Number::make(it.size()), offset); } break; case Object::Array: { if (it.padding()) offset = cons(Number::make(it.padding()), offset); writeAccessor(out, m, offset); if (memberNoAssert(m)) { writeAccessor(out, m, offset, true); } offset = cons(m, offset); } break; default: UNREACHABLE; } } } break; default: break; } } } unsigned typeFixedSize(Object* type) { unsigned length = BytesPerWord; for (MemberIterator it(type); it.hasMore();) { Object* m = it.next(); switch (m->type) { case Object::Scalar: { length = pad(it.offset() + it.size()); } break; case Object::Array: break; default: UNREACHABLE; } } return length; } unsigned typeArrayElementSize(Object* type) { for (MemberIterator it(type); it.hasMore();) { Object* m = it.next(); switch (m->type) { case Object::Scalar: break; case Object::Array: { return memberElementSize(m); } break; default: UNREACHABLE; } } return 0; } void writeSizes(Output* out, Object* declarations) { for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); switch (o->type) { case Object::Type: { out->write("const unsigned FixedSizeOf"); out->write(capitalize(typeName(o))); out->write(" = "); out->write(typeFixedSize(o)); out->write(";\n\n"); int aes = typeArrayElementSize(o); if (aes) { out->write("const unsigned ArrayElementSizeOf"); out->write(capitalize(typeName(o))); out->write(" = "); out->write(aes); out->write(";\n\n"); } } break; default: break; } } } const char* obfuscate(const char* s) { if (equal(s, "default")) { return "default_"; } else if (equal(s, "template")) { return "template_"; } else if (equal(s, "class")) { return "class_"; } else if (equal(s, "register")) { return "register_"; } else if (equal(s, "this")) { return "this_"; } else { return s; } } void writeConstructorParameters(Output* out, Object* t) { for (MemberIterator it(t); it.hasMore();) { Object* m = it.next(); switch (m->type) { case Object::Scalar: { out->write(", "); out->write(memberTypeName(m)); out->write(" "); out->write(obfuscate(memberName(m))); } break; default: break; } } } void writeConstructorArguments(Output* out, Object* t) { for (MemberIterator it(t); it.hasMore();) { Object* m = it.next(); switch (m->type) { case Object::Scalar: { out->write(", "); out->write(obfuscate(memberName(m))); } break; default: break; } } } void writeConstructorInitializations(Output* out, Object* t) { for (MemberIterator it(t); it.hasMore();) { Object* m = it.next(); switch (m->type) { case Object::Scalar: { out->write(" "); writeAccessorName(out, m); out->write("(t, o) = "); out->write(obfuscate(memberName(m))); out->write(";\n"); } break; default: break; } } } void writeInitializerDeclarations(Output* out, Object* declarations) { for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); switch (o->type) { case Object::Type: { out->write("void init"); out->write(capitalize(typeName(o))); out->write("(Thread* t, object o"); writeConstructorParameters(out, o); out->write(");\n\n"); } break; default: break; } } } void writeConstructorDeclarations(Output* out, Object* declarations) { for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); switch (o->type) { case Object::Type: { out->write("object make"); out->write(capitalize(typeName(o))); out->write("(Thread* t"); writeConstructorParameters(out, o); out->write(");\n\n"); } break; default: break; } } } void writeInitializers(Output* out, Object* declarations) { for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); switch (o->type) { case Object::Type: { out->write("void\ninit"); out->write(capitalize(typeName(o))); out->write("(Thread* t, object o"); writeConstructorParameters(out, o); out->write(")\n{\n"); out->write(" setObjectClass(t, o, "); out->write("arrayBody(t, t->m->types, Machine::"); out->write(capitalize(typeName(o))); out->write("Type));\n"); writeConstructorInitializations(out, o); out->write("}\n\n"); } break; default: break; } } } void writeConstructors(Output* out, Object* declarations) { for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); switch (o->type) { case Object::Type: { out->write("object make"); out->write(capitalize(typeName(o))); out->write("(Thread* t"); writeConstructorParameters(out, o); out->write(")\n{\n"); bool hasObjectMask = strcmp(typeName(o), "singleton") == 0; for (MemberIterator it(o); it.hasMore();) { Object* m = it.next(); if (m->type == Object::Scalar and equal(memberTypeName(m), "object") and not memberNoGC(m)) { out->write(" PROTECT(t, "); out->write(obfuscate(memberName(m))); out->write(");\n"); hasObjectMask = true; } else if (m->type == Object::Array and equal(memberTypeName(m), "object") and not memberNoGC(m)) { hasObjectMask = true; } } out->write(" object o = allocate(t, "); writeOffset(out, typeOffset(o), true); if (hasObjectMask) { out->write(", true"); } else { out->write(", false"); } out->write(");\n"); out->write(" init"); out->write(capitalize(typeName(o))); out->write("(t, o"); writeConstructorArguments(out, o); out->write(");\n"); out->write(" return o;\n}\n\n"); } break; default: break; } } } void writeEnums(Output* out, Object* declarations) { bool wrote = false; for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); switch (o->type) { case Object::Type: { if (wrote) { out->write(",\n"); } else { wrote = true; } out->write(capitalize(typeName(o))); out->write("Type"); } break; default: break; } } if (wrote) { out->write("\n"); } } unsigned methodCount(Object* o) { unsigned c = 0; for (Object* p = typeMethods(o); p; p = cdr(p)) ++c; return c; } void set(uint32_t* mask, unsigned index) { if (index < 32) { *mask |= 1 << index; } else { UNREACHABLE; } } uint32_t typeObjectMask(Object* type) { assert(typeFixedSize(type) + typeArrayElementSize(type) < 32 * BytesPerWord); uint32_t mask = 1; for (MemberIterator it(type); it.hasMore();) { Object* m = it.next(); unsigned offset = it.offset() / BytesPerWord; switch (m->type) { case Object::Scalar: { if (memberGC(m)) { set(&mask, offset); } } break; case Object::Array: { if (memberGC(m)) { set(&mask, offset); } } break; default: UNREACHABLE; } } return mask; } void writeInitialization(Output* out, Object* type) { out->write("bootClass(t, Machine::"); out->write(capitalize(typeName(type))); out->write("Type, "); if (typeSuper(type)) { out->write("Machine::"); out->write(capitalize(typeName(typeSuper(type)))); out->write("Type"); } else { out->write("-1"); } out->write(", "); if (typeObjectMask(type) != 1) { out->write(typeObjectMask(type)); } else { out->write("0"); } out->write(", "); out->write(typeFixedSize(type)); out->write(", "); out->write(typeArrayElementSize(type)); out->write(", "); out->write(methodCount(type)); out->write(");\n"); } unsigned typeCount(Object* declarations) { unsigned count = 0; for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); switch (o->type) { case Object::Type: { ++ count; } break; default: break; } } return count; } Object* reorder(Object* declarations) { Object* intArrayType = 0; Object* classType = 0; for (Object** p = &declarations; *p;) { Object* o = car(*p); if (o->type == Object::Type and equal(typeName(o), "intArray")) { intArrayType = o; *p = cdr(*p); } else if (o->type == Object::Type and equal(typeName(o), "class")) { classType = o; *p = cdr(*p); } else { p = &cdr(*p); } } return cons(intArrayType, cons(classType, declarations)); } void writeInitializations(Output* out, Object* declarations) { declarations = reorder(declarations); for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); if (o->type == Object::Type) { writeInitialization(out, o); } } } void writeJavaInitialization(Output* out, Object* type) { out->write("bootJavaClass(t, Machine::"); out->write(capitalize(typeName(type))); out->write("Type, "); if (typeSuper(type)) { out->write("Machine::"); out->write(capitalize(typeName(typeSuper(type)))); out->write("Type"); } else { out->write("-1"); } out->write(", \""); out->write(typeJavaName(type)); out->write("\", "); if (typeOverridesMethods(type)) { out->write(methodCount(type)); } else { out->write("-1"); } out->write(", bootMethod);\n"); } void writeJavaInitializations(Output* out, Object* declarations) { for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); if (o->type == Object::Type and typeJavaName(o)) { writeJavaInitialization(out, o); } } } void writeNameInitialization(Output* out, Object* type) { out->write("nameClass(t, Machine::"); out->write(capitalize(typeName(type))); out->write("Type, \""); if (equal(typeName(type), "jbyte") or equal(typeName(type), "jboolean") or equal(typeName(type), "jshort") or equal(typeName(type), "jchar") or equal(typeName(type), "jint") or equal(typeName(type), "jlong") or equal(typeName(type), "jfloat") or equal(typeName(type), "jdouble") or equal(typeName(type), "jvoid")) { out->write(typeName(type) + 1); } else { out->write("vm::"); out->write(typeName(type)); } out->write("\");\n"); } void writeNameInitializations(Output* out, Object* declarations) { for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); if (o->type == Object::Type and typeJavaName(o) == 0) { writeNameInitialization(out, o); } } } void writeMap(Output* out, Object* type) { for (MemberIterator it(type); it.hasMore();) { Object* m = it.next(); if (it.sawSuperclassBoundary) { out->write("Type_pad, "); } switch (m->type) { case Object::Scalar: { out->write("Type_"); out->write(memberTypeEnumName(m)); if (memberNoGC(m)) { out->write("_nogc"); } } break; case Object::Array: { out->write("Type_array, "); out->write("Type_"); out->write(memberTypeEnumName(m)); } break; default: UNREACHABLE; } out->write(", "); } out->write("Type_none"); } void writeMaps(Output* out, Object* declarations) { unsigned count = 0; for (Object* p = declarations; p; p = cdr(p)) { if (car(p)->type == Object::Type) { ++ count; } } out->write("Type types[]["); out->write(count); out->write("] = {\n"); bool wrote = false; for (Object* p = declarations; p; p = cdr(p)) { Object* o = car(p); if (o->type == Object::Type) { if (wrote) { out->write(",\n"); } else { wrote = true; } out->write("// "); out->write(typeName(o)); out->write("\n{ "); writeMap(out, o); out->write(" }"); } } out->write("\n};"); } void usageAndExit(const char* command) { fprintf(stderr, "usage: %s " "{enums,declarations,constructors,initializations," "java-initializations,name-initializations,maps}\n", command); exit(-1); } } // namespace local } // namespace extern "C" uint64_t vmNativeCall(void*, void*, unsigned, unsigned) { abort(); } extern "C" void vmJump(void*, void*, void*, void*, uintptr_t, uintptr_t) { abort(); } int main(int ac, char** av) { if (ac != 5 or not (local::equal(av[4], "enums") or local::equal(av[4], "declarations") or local::equal(av[4], "constructors") or local::equal(av[4], "initializations") or local::equal(av[4], "java-initializations") or local::equal(av[4], "name-initializations") or local::equal(av[4], "maps"))) { local::usageAndExit(av[0]); } System* system = makeSystem(); class MyAllocator : public avian::util::Allocator { public: MyAllocator(System* s): s(s) { } virtual void* tryAllocate(unsigned size) { return s->tryAllocate(size); } virtual void* allocate(unsigned size) { void* p = tryAllocate(size); if (p == 0) { abort(s); } return p; } virtual void free(const void* p, unsigned) { s->free(p); } System* s; } allocator(system); Finder* finder = makeFinder(system, &allocator, av[1], 0); FILE* inStream = ::fopen(av[2], "rb"); if (inStream == 0) { fprintf(stderr, "unable to open %s: %s\n", av[2], strerror(errno)); return -1; } FileInput in(0, inStream, false); Object* declarations = local::parse(finder, &in); finder->dispose(); system->dispose(); FILE* outStream = ::fopen(av[3], "wb"); if (outStream == 0) { fprintf(stderr, "unable to open %s: %s\n", av[3], strerror(errno)); return -1; } FileOutput out(0, outStream, false); if (local::equal(av[4], "enums")) { local::writeEnums(&out, declarations); } else if (local::equal(av[4], "declarations")) { out.write("const unsigned TypeCount = "); out.Output::write(local::typeCount(declarations)); out.write(";\n\n"); local::writeAccessors(&out, declarations); local::writeSizes(&out, declarations); local::writeInitializerDeclarations(&out, declarations); local::writeConstructorDeclarations(&out, declarations); } else if (local::equal(av[4], "constructors")) { local::writeInitializers(&out, declarations); local::writeConstructors(&out, declarations); } else if (local::equal(av[4], "initializations")) { local::writeInitializations(&out, declarations); } else if (local::equal(av[4], "java-initializations")) { local::writeJavaInitializations(&out, declarations); } else if (local::equal(av[4], "name-initializations")) { local::writeNameInitializations(&out, declarations); } else if (local::equal(av[4], "maps")) { local::writeMaps(&out, declarations); } out.write("\n"); return 0; } ReadyTalk-avian-1e1fff5/src/tools/type-generator/sexpr.h000066400000000000000000000036141231440243200233720ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef AVIAN_TOOLS_TYPE_GENERATOR_SEXPR_H #define AVIAN_TOOLS_TYPE_GENERATOR_SEXPR_H namespace avian { namespace tools { namespace typegenerator { template inline T* allocate() { T* t = static_cast(malloc(sizeof(T))); assert(t); return t; } class Object { public: typedef enum { Scalar, Array, Method, Type, Pair, Number, Character, String, Eos } ObjectType; ObjectType type; }; class Pair : public Object { public: Object* car; Object* cdr; static Pair* make(Object* car, Object* cdr) { Pair* o = allocate(); o->type = Object::Pair; o->car = car; o->cdr = cdr; return o; } }; inline Object* cons(Object* car, Object* cdr) { return Pair::make(car, cdr); } inline Object*& car(Object* o) { assert(o->type == Object::Pair); return static_cast(o)->car; } inline void setCar(Object* o, Object* v) { assert(o->type == Object::Pair); static_cast(o)->car = v; } inline Object*& cdr(Object* o) { assert(o->type == Object::Pair); return static_cast(o)->cdr; } inline void setCdr(Object* o, Object* v) { assert(o->type == Object::Pair); static_cast(o)->cdr = v; } class List { public: Object* first; Object* last; List(): first(0), last(0) { } void append(Object* o) { Object* p = cons(o, 0); if (last) { setCdr(last, p); last = p; } else { first = last = p; } } }; } // namespace typegenerator } // namespace tools } // namespace avian #endif // AVIAN_TOOLS_TYPE_GENERATOR_SEXPR_H ReadyTalk-avian-1e1fff5/src/types.def000066400000000000000000000161201231440243200175730ustar00rootroot00000000000000(type jobject java/lang/Object) (type class avian/VMClass (array void* vtable)) (type jclass java/lang/Class (require object vmClass)) (type jaccessibleObject java/lang/reflect/AccessibleObject) (type jfield java/lang/reflect/Field) (type jmethod java/lang/reflect/Method) (type jconstructor java/lang/reflect/Constructor) (type constantPool sun/reflect/ConstantPool) (type serializable java/io/Serializable) (type cloneable java/lang/Cloneable) (type singleton (array uintptr_t body)) (type classLoader java/lang/ClassLoader (object map)) (type systemClassLoader avian/SystemClassLoader (void* finder)) (type field avian/VMField) (type method avian/VMMethod) (type addendum avian/Addendum) (type classAddendum avian/ClassAddendum) (type methodAddendum avian/MethodAddendum) (type fieldAddendum avian/FieldAddendum) (type classRuntimeData (object arrayClass) (object jclass) (object pool) (object signers)) (type methodRuntimeData (object native)) (type pointer (void* value)) (type native (void* function) (uint8_t fast)) (type nativeIntercept (extends native) (object original)) (type finder (void* finder) (object name) (object next)) (type region (void* region) (uint32_t position)) (type exceptionHandlerTable (array uint64_t body)) (type lineNumberTable (array uint64_t body)) (type code (object pool) (object exceptionHandlerTable) (object lineNumberTable) (intptr_t compiled) (uint32_t compiledSize) (uint16_t maxStack) (uint16_t maxLocals) (array uint8_t body)) (type reference (object class) (object name) (object spec)) (type triple (object first) (object second) (object third)) (type finalizer (nogc object target) (void* finalize) (nogc object next) (object queueTarget) (object queueNext)) (type hashMap (uint32_t size) (object array)) (type weakHashMap (extends hashMap)) (type list (uint32_t size) (object front) (object rear)) (type vector (uint32_t size) (array object body)) (type traceElement (object method) (int32_t ip)) (type treeNode (object value) (object left) (object right)) (type callNode (intptr_t address) (object target) (uintptr_t flags) (object next)) (type wordArray (array uintptr_t body)) (type array (noassert array object body)) (type pair (object first) (object second)) (type monitor (void* owner) (void* waitHead) (void* waitTail) (object acquireHead) (object acquireTail) (uint32_t depth)) (type monitorNode (void* value) (object next)) (type innerClassReference avian/InnerClassReference) (type continuationContext (object next) (object before) (object after) (object continuation) (object method)) (type continuation avian/Continuations$Continuation (object next) (object context) (object method) (void* address) (uintptr_t returnAddressOffset) (uintptr_t framePointerOffset) (array uintptr_t body)) (type unwindResult avian/Continuations$UnwindResult) (type string java/lang/String (alias data object value) (alias length uint32_t count) (alias hashCode uint32_t hash)) (type thread java/lang/Thread (require object sleepLock) (require object interruptLock) (require uint8_t interrupted) (require uint8_t unparked) (alias peer uint64_t eetop) (require uint64_t peer)) (type threadGroup java/lang/ThreadGroup) (type stackTraceElement java/lang/StackTraceElement) (type throwable java/lang/Throwable (alias message object detailMessage) (alias trace object backtrace) (alias trace object stackState)) (type exception java/lang/Exception) (type runtimeException java/lang/RuntimeException) (type nullPointerException java/lang/NullPointerException) (type arithmeticException java/lang/ArithmeticException) (type illegalStateException java/lang/IllegalStateException) (type illegalArgumentException java/lang/IllegalArgumentException) (type illegalMonitorStateException java/lang/IllegalMonitorStateException) (type indexOutOfBoundsException java/lang/IndexOutOfBoundsException) (type arrayIndexOutOfBoundsException java/lang/ArrayIndexOutOfBoundsException) (type arrayStoreException java/lang/ArrayStoreException) (type negativeArraySizeException java/lang/NegativeArraySizeException) (type cloneNotSupportedException java/lang/CloneNotSupportedException) (type reflectiveOperationException java/lang/ReflectiveOperationException) (type classCastException java/lang/ClassCastException) (type classNotFoundException java/lang/ClassNotFoundException) (type invocationTargetException java/lang/reflect/InvocationTargetException) (type interruptedException java/lang/InterruptedException) (type error java/lang/Error) (type virtualMachineError java/lang/VirtualMachineError) (type outOfMemoryError java/lang/OutOfMemoryError) (type stackOverflowError java/lang/StackOverflowError) (type linkageError java/lang/LinkageError) (type incompatibleClassChangeError java/lang/IncompatibleClassChangeError) (type abstractMethodError java/lang/AbstractMethodError) (type noSuchFieldError java/lang/NoSuchFieldError) (type noSuchMethodError java/lang/NoSuchMethodError) (type noClassDefFoundError java/lang/NoClassDefFoundError) (type unsatisfiedLinkError java/lang/UnsatisfiedLinkError) (type exceptionInInitializerError java/lang/ExceptionInInitializerError) (type ioException java/io/IOException) (type fileNotFoundException java/io/FileNotFoundException) (type incompatibleContinuationException avian/IncompatibleContinuationException) (type number java/lang/Number) (type byte java/lang/Byte) (type boolean java/lang/Boolean) (type short java/lang/Short) (type char java/lang/Character) (type int java/lang/Integer) (type long java/lang/Long) (type float java/lang/Float) (type double java/lang/Double) (type referenceQueue java/lang/ref/ReferenceQueue (alias front object head)) (type jreference java/lang/ref/Reference (alias target object referent) (alias queue object queue) (alias jNext object next) (alias jNext object queueNext) (alias vmNext object discovered) (alias vmNext object pendingNext) (nogc object target) (nogc object queue) (nogc object vmNext)) (type weakReference java/lang/ref/WeakReference) (type softReference java/lang/ref/SoftReference) (type phantomReference java/lang/ref/PhantomReference) (type cleaner sun/misc/Cleaner (object queueNext)) (type byteArray [B (extends jobject) (array int8_t body)) (type booleanArray [Z (extends jobject) (array uint8_t body)) (type shortArray [S (extends jobject) (array int16_t body)) (type charArray [C (extends jobject) (array uint16_t body)) (type intArray [I (extends jobject) (array int32_t body)) (type longArray [J (extends jobject) (array int64_t body)) (type floatArray [F (extends jobject) (array uint32_t body)) (type doubleArray [D (extends jobject) (array uint64_t body)) (type jbyte (extends jobject)) (type jboolean (extends jobject)) (type jshort (extends jobject)) (type jchar (extends jobject)) (type jint (extends jobject)) (type jlong (extends jobject)) (type jfloat (extends jobject)) (type jdouble (extends jobject)) (type jvoid (extends jobject)) ReadyTalk-avian-1e1fff5/src/util.cpp000066400000000000000000000351121231440243200174320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/util.h" #include using namespace vm; namespace { class TreeContext { public: class MyProtector: public Thread::Protector { public: MyProtector(Thread* thread, TreeContext* context): Protector(thread), context(context) { } virtual void visit(Heap::Visitor* v) { v->visit(&(context->root)); v->visit(&(context->node)); for (List* p = context->ancestors; p; p = p->next) { v->visit(&(p->item)); } } TreeContext* context; }; TreeContext(Thread* thread, Zone* zone): zone(zone), root(0), node(0), ancestors(0), protector(thread, this), fresh(false) { } Zone* zone; object root; object node; List* ancestors; MyProtector protector; bool fresh; }; List* path(TreeContext* c, object node, List* next) { return new(c->zone) List(node, next); } inline object getTreeNodeValue(Thread*, object n) { return reinterpret_cast (alias(n, TreeNodeValue) & PointerMask); } inline void setTreeNodeValue(Thread* t, object n, object value) { intptr_t red = alias(n, TreeNodeValue) & (~PointerMask); set(t, n, TreeNodeValue, value); alias(n, TreeNodeValue) |= red; } inline bool treeNodeRed(Thread*, object n) { return (alias(n, TreeNodeValue) & (~PointerMask)) == 1; } inline void setTreeNodeRed(Thread*, object n, bool red) { if (red) { alias(n, TreeNodeValue) |= 1; } else { alias(n, TreeNodeValue) &= PointerMask; } } inline object cloneTreeNode(Thread* t, object n) { PROTECT(t, n); object newNode = makeTreeNode (t, getTreeNodeValue(t, n), treeNodeLeft(t, n), treeNodeRight(t, n)); setTreeNodeRed(t, newNode, treeNodeRed(t, n)); return newNode; } object treeFind(Thread* t, object tree, intptr_t key, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)) { object node = tree; while (node != sentinal) { intptr_t difference = compare(t, key, getTreeNodeValue(t, node)); if (difference < 0) { node = treeNodeLeft(t, node); } else if (difference > 0) { node = treeNodeRight(t, node); } else { return node; } } return 0; } void treeFind(Thread* t, TreeContext* c, object old, intptr_t key, object node, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)) { PROTECT(t, old); PROTECT(t, node); PROTECT(t, sentinal); object newRoot = cloneTreeNode(t, old); PROTECT(t, newRoot); object new_ = newRoot; PROTECT(t, new_); int count = 0; while (old != sentinal) { c->ancestors = path(c, new_, c->ancestors); intptr_t difference = compare(t, key, getTreeNodeValue(t, old)); if (difference < 0) { old = treeNodeLeft(t, old); object n = cloneTreeNode(t, old); set(t, new_, TreeNodeLeft, n); new_ = n; } else if (difference > 0) { old = treeNodeRight(t, old); object n = cloneTreeNode(t, old); set(t, new_, TreeNodeRight, n); new_ = n; } else { c->fresh = false; c->root = newRoot; c->node = new_; c->ancestors = c->ancestors->next; return; } if (++ count > 100) { // if we've gone this deep, we probably have an unbalanced tree, // which should only happen if there's a serious bug somewhere // in our insertion process abort(t); } } setTreeNodeValue(t, new_, getTreeNodeValue(t, node)); c->fresh = true; c->root = newRoot; c->node = new_; c->ancestors = c->ancestors; } object leftRotate(Thread* t, object n) { PROTECT(t, n); object child = cloneTreeNode(t, treeNodeRight(t, n)); set(t, n, TreeNodeRight, treeNodeLeft(t, child)); set(t, child, TreeNodeLeft, n); return child; } object rightRotate(Thread* t, object n) { PROTECT(t, n); object child = cloneTreeNode(t, treeNodeLeft(t, n)); set(t, n, TreeNodeLeft, treeNodeRight(t, child)); set(t, child, TreeNodeRight, n); return child; } object treeAdd(Thread* t, TreeContext* c) { object new_ = c->node; PROTECT(t, new_); object newRoot = c->root; PROTECT(t, newRoot); // rebalance setTreeNodeRed(t, new_, true); while (c->ancestors != 0 and treeNodeRed(t, c->ancestors->item)) { if (c->ancestors->item == treeNodeLeft(t, c->ancestors->next->item)) { if (treeNodeRed (t, treeNodeRight(t, c->ancestors->next->item))) { setTreeNodeRed(t, c->ancestors->item, false); object n = cloneTreeNode (t, treeNodeRight(t, c->ancestors->next->item)); set(t, c->ancestors->next->item, TreeNodeRight, n); setTreeNodeRed(t, treeNodeRight(t, c->ancestors->next->item), false); setTreeNodeRed(t, c->ancestors->next->item, true); new_ = c->ancestors->next->item; c->ancestors = c->ancestors->next->next; } else { if (new_ == treeNodeRight(t, c->ancestors->item)) { new_ = c->ancestors->item; c->ancestors = c->ancestors->next; object n = leftRotate(t, new_); if (new_ == treeNodeRight(t, c->ancestors->item)) { set(t, c->ancestors->item, TreeNodeRight, n); } else { set(t, c->ancestors->item, TreeNodeLeft, n); } c->ancestors = path(c, n, c->ancestors); } setTreeNodeRed(t, c->ancestors->item, false); setTreeNodeRed(t, c->ancestors->next->item, true); object n = rightRotate(t, c->ancestors->next->item); if (c->ancestors->next->next == 0) { newRoot = n; } else if (treeNodeRight(t, c->ancestors->next->next->item) == c->ancestors->next->item) { set(t, c->ancestors->next->next->item, TreeNodeRight, n); } else { set(t, c->ancestors->next->next->item, TreeNodeLeft, n); } // done } } else { // this is just the reverse of the code above (right and // left swapped): if (treeNodeRed (t, treeNodeLeft(t, c->ancestors->next->item))) { setTreeNodeRed(t, c->ancestors->item, false); object n = cloneTreeNode (t, treeNodeLeft(t, c->ancestors->next->item)); set(t, c->ancestors->next->item, TreeNodeLeft, n); setTreeNodeRed(t, treeNodeLeft(t, c->ancestors->next->item), false); setTreeNodeRed(t, c->ancestors->next->item, true); new_ = c->ancestors->next->item; c->ancestors = c->ancestors->next->next; } else { if (new_ == treeNodeLeft(t, c->ancestors->item)) { new_ = c->ancestors->item; c->ancestors = c->ancestors->next; object n = rightRotate(t, new_); if (new_ == treeNodeLeft(t, c->ancestors->item)) { set(t, c->ancestors->item, TreeNodeLeft, n); } else { set(t, c->ancestors->item, TreeNodeRight, n); } c->ancestors = path(c, n, c->ancestors); } setTreeNodeRed(t, c->ancestors->item, false); setTreeNodeRed(t, c->ancestors->next->item, true); object n = leftRotate(t, c->ancestors->next->item); if (c->ancestors->next->next == 0) { newRoot = n; } else if (treeNodeLeft(t, c->ancestors->next->next->item) == c->ancestors->next->item) { set(t, c->ancestors->next->next->item, TreeNodeLeft, n); } else { set(t, c->ancestors->next->next->item, TreeNodeRight, n); } // done } } } setTreeNodeRed(t, newRoot, false); return newRoot; } } // namespace namespace vm { object hashMapFindNode(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); if (array) { unsigned index = hash(t, key) & (arrayLength(t, array) - 1); for (object n = arrayBody(t, array, index); n; n = tripleThird(t, n)) { object k = tripleFirst(t, n); if (weak) { k = jreferenceTarget(t, k); if (k == 0) { continue; } } if (equal(t, key, k)) { return n; } } } return 0; } void hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object), unsigned size) { PROTECT(t, map); object newArray = 0; if (size) { object oldArray = hashMapArray(t, map); PROTECT(t, oldArray); unsigned newLength = nextPowerOfTwo(size); if (oldArray and arrayLength(t, oldArray) == newLength) { return; } newArray = makeArray(t, newLength); if (oldArray != hashMapArray(t, map)) { // a resize was performed during a GC via the makeArray call // above; nothing left to do return; } if (oldArray) { bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); for (unsigned i = 0; i < arrayLength(t, oldArray); ++i) { object next; for (object p = arrayBody(t, oldArray, i); p; p = next) { next = tripleThird(t, p); object k = tripleFirst(t, p); if (weak) { k = jreferenceTarget(t, k); if (k == 0) { continue; } } unsigned index = hash(t, k) & (newLength - 1); set(t, p, TripleThird, arrayBody(t, newArray, index)); set(t, newArray, ArrayBody + (index * BytesPerWord), p); } } } } set(t, map, HashMapArray, newArray); } void hashMapInsert(Thread* t, object map, object key, object value, uint32_t (*hash)(Thread*, object)) { // note that we reinitialize the array variable whenever an // allocation (and thus possibly a collection) occurs, in case the // array changes due to a table resize. PROTECT(t, map); uint32_t h = hash(t, key); bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); ++ hashMapSize(t, map); if (array == 0 or hashMapSize(t, map) >= arrayLength(t, array) * 2) { PROTECT(t, key); PROTECT(t, value); hashMapResize(t, map, hash, array ? arrayLength(t, array) * 2 : 16); array = hashMapArray(t, map); } object k = key; if (weak) { PROTECT(t, key); PROTECT(t, value); object r = makeWeakReference(t, 0, 0, 0, 0); jreferenceTarget(t, r) = key; jreferenceVmNext(t, r) = t->m->weakReferences; t->m->weakReferences = r; k = r; array = hashMapArray(t, map); } object n = makeTriple(t, k, value, 0); array = hashMapArray(t, map); unsigned index = h & (arrayLength(t, array) - 1); set(t, n, TripleThird, arrayBody(t, array, index)); set(t, array, ArrayBody + (index * BytesPerWord), n); if (hashMapSize(t, map) <= arrayLength(t, array) / 3) { // this might happen if nodes were removed during GC in which case // we weren't able to resize at the time hashMapResize(t, map, hash, arrayLength(t, array) / 2); } } object hashMapRemoveNode(Thread* t, object map, unsigned index, object p, object n) { if (p) { set(t, p, TripleThird, tripleThird(t, n)); } else { set(t, hashMapArray(t, map), ArrayBody + (index * BytesPerWord), tripleThird(t, n)); } -- hashMapSize(t, map); return n; } object hashMapRemove(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); object o = 0; if (array) { unsigned index = hash(t, key) & (arrayLength(t, array) - 1); object p = 0; for (object n = arrayBody(t, array, index); n;) { object k = tripleFirst(t, n); if (weak) { k = jreferenceTarget(t, k); if (k == 0) { n = tripleThird(t, hashMapRemoveNode(t, map, index, p, n)); continue; } } if (equal(t, key, k)) { o = tripleSecond(t, hashMapRemoveNode(t, map, index, p, n)); break; } else { p = n; n = tripleThird(t, n); } } if ((not t->m->collecting) and hashMapSize(t, map) <= arrayLength(t, array) / 3) { PROTECT(t, o); hashMapResize(t, map, hash, arrayLength(t, array) / 2); } } return o; } void listAppend(Thread* t, object list, object value) { PROTECT(t, list); ++ listSize(t, list); object p = makePair(t, value, 0); if (listFront(t, list)) { set(t, listRear(t, list), PairSecond, p); } else { set(t, list, ListFront, p); } set(t, list, ListRear, p); } object vectorAppend(Thread* t, object vector, object value) { if (vectorLength(t, vector) == vectorSize(t, vector)) { PROTECT(t, vector); PROTECT(t, value); object newVector = makeVector (t, vectorSize(t, vector), max(16, vectorSize(t, vector) * 2)); if (vectorSize(t, vector)) { memcpy(&vectorBody(t, newVector, 0), &vectorBody(t, vector, 0), vectorSize(t, vector) * BytesPerWord); } vector = newVector; } set(t, vector, VectorBody + (vectorSize(t, vector) * BytesPerWord), value); ++ vectorSize(t, vector); return vector; } object growArray(Thread* t, object array) { PROTECT(t, array); object newArray = makeArray (t, array == 0 ? 16 : (arrayLength(t, array) * 2)); if (array) { memcpy(&arrayBody(t, newArray, 0), &arrayBody(t, array, 0), arrayLength(t, array)); } return newArray; } object treeQuery(Thread* t, object tree, intptr_t key, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)) { object node = treeFind(t, tree, key, sentinal, compare); return (node ? getTreeNodeValue(t, node) : 0); } object treeInsert(Thread* t, Zone* zone, object tree, intptr_t key, object value, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)) { PROTECT(t, tree); PROTECT(t, sentinal); object node = makeTreeNode(t, value, sentinal, sentinal); TreeContext c(t, zone); treeFind(t, &c, tree, key, node, sentinal, compare); expect(t, c.fresh); return treeAdd(t, &c); } void treeUpdate(Thread* t, object tree, intptr_t key, object value, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)) { setTreeNodeValue(t, treeFind(t, tree, key, sentinal, compare), value); } } // namespace vm ReadyTalk-avian-1e1fff5/src/util/000077500000000000000000000000001231440243200167245ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/src/util/arg-parser.cpp000066400000000000000000000045611231440243200215010ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include #include namespace avian { namespace util { Arg::Arg(ArgParser& parser, bool required, const char* name, const char* desc): next(0), required(required), name(name), desc(desc), value(0) { *parser.last = this; parser.last = &next; } ArgParser::ArgParser(): first(0), last(&first) {} bool ArgParser::parse(int ac, const char* const* av) { Arg* state = 0; for(int i = 1; i < ac; i++) { if(state) { if(state->value) { fprintf(stderr, "duplicate parameter %s: '%s' and '%s'\n", state->name, state->value, av[i]); return false; } state->value = av[i]; state = 0; } else { if(av[i][0] != '-') { fprintf(stderr, "expected -parameter\n"); return false; } bool found = false; for(Arg* arg = first; arg; arg = arg->next) { if(strcmp(arg->name, &av[i][1]) == 0) { found = true; if (arg->desc == 0) { arg->value = "true"; } else { state = arg; } } } if (not found) { fprintf(stderr, "unrecognized parameter %s\n", av[i]); return false; } } } if(state) { fprintf(stderr, "expected argument after -%s\n", state->name); return false; } for(Arg* arg = first; arg; arg = arg->next) { if(arg->required && !arg->value) { fprintf(stderr, "expected value for %s\n", arg->name); return false; } } return true; } void ArgParser::printUsage(const char* exe) { fprintf(stderr, "usage:\n%s \\\n", exe); for(Arg* arg = first; arg; arg = arg->next) { const char* lineEnd = arg->next ? " \\" : ""; if(arg->required) { fprintf(stderr, " -%s\t%s%s\n", arg->name, arg->desc, lineEnd); } else if (arg->desc) { fprintf(stderr, " [-%s\t%s]%s\n", arg->name, arg->desc, lineEnd); } else { fprintf(stderr, " [-%s]%s\n", arg->name, lineEnd); } } } } // namespace util } // namespace avian ReadyTalk-avian-1e1fff5/src/util/fixed-allocator.cpp000066400000000000000000000023341231440243200225070ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include namespace avian { namespace util { FixedAllocator::FixedAllocator(Aborter* a, Slice memory) : a(a), memory(memory), offset(0) { } void* FixedAllocator::tryAllocate(unsigned size) { return allocate(size); } void* FixedAllocator::allocate(unsigned size, unsigned padAlignment) { unsigned paddedSize = vm::pad(size, padAlignment); expect(a, offset + paddedSize < memory.count); void* p = memory.begin() + offset; offset += paddedSize; return p; } void* FixedAllocator::allocate(unsigned size) { return allocate(size, vm::BytesPerWord); } void FixedAllocator::free(const void* p, unsigned size) { if (p >= memory.begin() and static_cast(p) + size == memory.begin() + offset) { offset -= size; } else { abort(a); } } } // namespace util } // namespace avian ReadyTalk-avian-1e1fff5/src/x86.S000066400000000000000000000237501231440243200165270ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include "avian/types.h" #define LOCAL(x) .L##x #if defined __APPLE__ \ || ((defined __MINGW32__ || defined __CYGWIN32__) && ! defined __x86_64__) # define GLOBAL(x) _##x #else # define GLOBAL(x) x #endif .text #ifdef __x86_64__ #define CHECKPOINT_THREAD 8 #define CHECKPOINT_STACK 48 #ifdef __MINGW32__ .globl GLOBAL(detectFeature) GLOBAL(detectFeature): pushq %rbp movq %rsp, %rbp pushq %rdx pushq %rcx pushq %rbx pushq %rsi pushq %rdi movl %ecx, %edi movl %edx, %esi movl $1, %eax cpuid andl %esi, %edx andl %edi, %ecx orl %edx, %ecx test %ecx, %ecx je LOCAL(NOSSE) movl $1, %eax jmp LOCAL(SSEEND) LOCAL(NOSSE): movl $0, %eax LOCAL(SSEEND): popq %rdi popq %rsi popq %rbx popq %rcx popq %rdx movq %rbp,%rsp popq %rbp ret .globl GLOBAL(vmNativeCall) GLOBAL(vmNativeCall): pushq %rbp //save nonvolatile registers pushq %r12 pushq %r13 pushq %r14 pushq %r15 movq %rsp, %rbp // %rcx: function // %rdx: arguments // %r8: arguments count // %r9: return type movq %rcx, %r10 movq %rdx, %r11 movq %r8, %r12 movq %r9, %r13 // %r10: function // %r11: arguments // %r12: arguments count // %r13: return type //allocate initial stack space subq $32, %rsp //first arg cmp $0, %r12 je LOCAL(call) movq 0(%r11),%rcx movq 0(%r11),%xmm0 subq $1, %r12 //second arg cmp $0, %r12 je LOCAL(call) movq 8(%r11),%rdx movq 8(%r11),%xmm1 subq $1, %r12 //third arg cmp $0, %r12 je LOCAL(call) movq 16(%r11),%r8 movq 16(%r11),%xmm2 subq $1, %r12 //fourth arg cmp $0, %r12 je LOCAL(call) movq 24(%r11),%r9 movq 24(%r11),%xmm3 subq $1, %r12 //calculate stack space for arguments, aligned movq $8, %r15 leaq (%r15, %r12, 8), %r15 andq $0xFFFFFFFFFFFFFFF0, %r15 //reserve stack space for arguments subq %r15, %rsp //reset the counter addq $3, %r12 jmp LOCAL(loopend) LOCAL(loop): movq (%r11, %r12, 8), %r14 movq %r14, (%rsp, %r12, 8); subq $1, %r12 LOCAL(loopend): //we don't need to move arg 3 and lower cmpq $3, %r12 jne LOCAL(loop) LOCAL(call): call *%r10 LOCAL(void): cmpq $VOID_TYPE,%r13 jne LOCAL(float) jmp LOCAL(exit) LOCAL(float): cmpq $FLOAT_TYPE,%r13 je LOCAL(copy) cmpq $DOUBLE_TYPE,%r13 jne LOCAL(exit) LOCAL(copy): movq %xmm0,%rax LOCAL(exit): movq %rbp, %rsp //return nonvolatile registers to their former state popq %r15 popq %r14 popq %r13 popq %r12 popq %rbp ret .globl GLOBAL(vmJump) GLOBAL(vmJump): movq %rdx,%rbp movq 40(%rsp),%rax movq 48(%rsp),%rdx movq %r8,%rsp movq %r9,%rbx jmp *%rcx #define VMRUN_FRAME_SIZE 80 .globl GLOBAL(vmRun) GLOBAL(vmRun): // %rcx: function // %rdx: arguments // %r8 : checkpoint pushq %rbp movq %rsp,%rbp subq $VMRUN_FRAME_SIZE,%rsp movq %rbx,16(%rsp) movq %r12,24(%rsp) movq %r13,32(%rsp) movq %r14,40(%rsp) movq %r15,48(%rsp) movq %rsi,56(%rsp) movq %rdi,64(%rsp) movq %rsp,CHECKPOINT_STACK(%r8) movq %rcx,%r11 movq CHECKPOINT_THREAD(%r8),%rcx call *%r11 .globl GLOBAL(vmRun_returnAddress) GLOBAL(vmRun_returnAddress): movq 16(%rsp),%rbx movq 24(%rsp),%r12 movq 32(%rsp),%r13 movq 40(%rsp),%r14 movq 48(%rsp),%r15 movq 56(%rsp),%rsi movq 64(%rsp),%rdi addq $VMRUN_FRAME_SIZE,%rsp popq %rbp ret #else // not __MINGW32__ .globl GLOBAL(detectFeature) GLOBAL(detectFeature): pushq %rbp movq %rsp, %rbp pushq %rdx pushq %rcx pushq %rbx movl $1, %eax cpuid andl %esi, %edx andl %edi, %ecx orl %edx, %ecx test %ecx, %ecx je LOCAL(NOSSE) movl $1, %eax jmp LOCAL(SSEEND) LOCAL(NOSSE): movl $0, %eax LOCAL(SSEEND): popq %rbx popq %rcx popq %rdx movq %rbp,%rsp popq %rbp ret .globl GLOBAL(vmNativeCall) GLOBAL(vmNativeCall): pushq %rbp movq %rsp,%rbp // %rdi aka -48(%rbp): function // %rsi aka -40(%rbp): stack // %rdx aka -32(%rbp): stackSize // %rcx aka -24(%rbp): gprTable // %r8 aka -16(%rbp): sseTable // %r9 aka -8(%rbp): returnType // save our argument registers so we can clobber them pushq %r9 pushq %r8 pushq %rcx pushq %rdx pushq %rsi pushq %rdi // reserve space for arguments passed via memory subq %rdx,%rsp // align to a 16 byte boundary andq $0xFFFFFFFFFFFFFFF0,%rsp // copy memory arguments into place movq $0,%rcx jmp LOCAL(test) LOCAL(loop): movq %rcx,%rax movq %rcx,%rdx addq %rsp,%rdx addq -40(%rbp),%rax movq (%rax),%rax movq %rax,(%rdx) addq $8,%rcx LOCAL(test): cmpq -32(%rbp),%rcx jb LOCAL(loop) // do we need to load the general-purpose registers? cmpq $0,-24(%rbp) je LOCAL(sse) // yes, we do movq -24(%rbp),%rax movq 0(%rax),%rdi movq 8(%rax),%rsi movq 16(%rax),%rdx movq 24(%rax),%rcx movq 32(%rax),%r8 movq 40(%rax),%r9 LOCAL(sse): // do we need to load the SSE registers? cmpq $0,-16(%rbp) je LOCAL(call) // yes, we do movq -16(%rbp),%rax movq 0(%rax),%xmm0 movq 8(%rax),%xmm1 movq 16(%rax),%xmm2 movq 24(%rax),%xmm3 movq 32(%rax),%xmm4 movq 40(%rax),%xmm5 movq 48(%rax),%xmm6 movq 56(%rax),%xmm7 LOCAL(call): call *-48(%rbp) // handle return value based on expected type movq -8(%rbp),%rcx LOCAL(void): cmpq $VOID_TYPE,%rcx jne LOCAL(float) jmp LOCAL(exit) LOCAL(float): cmpq $FLOAT_TYPE,%rcx je LOCAL(copy) cmpq $DOUBLE_TYPE,%rcx jne LOCAL(exit) LOCAL(copy): #ifdef __APPLE__ // as of OS X 10.6, Apple is still using an assembler that doesn't // understand movq SSE,GPR, but movd does the same thing, despite // the name movd %xmm0,%rax #else movq %xmm0,%rax #endif LOCAL(exit): movq %rbp,%rsp popq %rbp ret .globl GLOBAL(vmJump) GLOBAL(vmJump): movq %rsi,%rbp movq %rdx,%rsp movq %rcx,%rbx movq %r8,%rax movq %r9,%rdx jmp *%rdi #define VMRUN_FRAME_SIZE 64 .globl GLOBAL(vmRun) GLOBAL(vmRun): // %rdi: function // %rsi: arguments // %rdx: checkpoint pushq %rbp movq %rsp,%rbp subq $VMRUN_FRAME_SIZE,%rsp movq %rbx,16(%rsp) movq %r12,24(%rsp) movq %r13,32(%rsp) movq %r14,40(%rsp) movq %r15,48(%rsp) movq %rsp,CHECKPOINT_STACK(%rdx) movq %rdi,%r11 movq CHECKPOINT_THREAD(%rdx),%rdi call *%r11 .globl GLOBAL(vmRun_returnAddress) GLOBAL(vmRun_returnAddress): movq 16(%rsp),%rbx movq 24(%rsp),%r12 movq 32(%rsp),%r13 movq 40(%rsp),%r14 movq 48(%rsp),%r15 addq $VMRUN_FRAME_SIZE,%rsp popq %rbp ret #endif // not __MINGW32__ #elif defined __i386__ #define CHECKPOINT_THREAD 4 #define CHECKPOINT_STACK 24 #define CHECKPOINT_BASE 28 .globl GLOBAL(detectFeature) GLOBAL(detectFeature): pushl %ebp movl %esp, %ebp pushl %edx pushl %ecx pushl %ebx pushl %esi pushl %edi movl 12(%ebp), %esi movl 8(%ebp), %edi movl $1, %eax cpuid andl %esi, %edx andl %edi, %ecx orl %edx, %ecx test %ecx, %ecx je LOCAL(NOSSE) movl $1, %eax jmp LOCAL(SSEEND) LOCAL(NOSSE): movl $0, %eax LOCAL(SSEEND): popl %edi popl %esi popl %ebx popl %ecx popl %edx movl %ebp,%esp popl %ebp ret .globl GLOBAL(vmNativeCall) GLOBAL(vmNativeCall): pushl %ebp movl %esp,%ebp // 8(%ebp): function // 12(%ebp): stack // 16(%ebp): stackSize // 20(%ebp): returnType // reserve space for arguments movl 16(%ebp),%ecx subl %ecx,%esp //# ifdef __APPLE__ // align to a 16 byte boundary andl $0xFFFFFFF0,%esp //# endif // copy arguments into place movl $0,%ecx jmp LOCAL(test) LOCAL(loop): movl %ecx,%eax movl %ecx,%edx addl %esp,%edx addl 12(%ebp),%eax movl (%eax),%eax movl %eax,(%edx) addl $4,%ecx LOCAL(test): cmpl 16(%ebp),%ecx jb LOCAL(loop) // call function call *8(%ebp) // handle return value based on expected type movl 20(%ebp),%ecx LOCAL(void): cmpl $VOID_TYPE,%ecx jne LOCAL(int64) jmp LOCAL(exit) LOCAL(int64): cmpl $INT64_TYPE,%ecx jne LOCAL(float) jmp LOCAL(exit) LOCAL(float): cmpl $FLOAT_TYPE,%ecx jne LOCAL(double) fstps 8(%ebp) movl 8(%ebp),%eax jmp LOCAL(exit) LOCAL(double): cmpl $DOUBLE_TYPE,%ecx jne LOCAL(exit) fstpl 8(%ebp) movl 8(%ebp),%eax movl 12(%ebp),%edx LOCAL(exit): movl %ebp,%esp popl %ebp ret .globl GLOBAL(vmJump) GLOBAL(vmJump): movl 4(%esp),%esi movl 8(%esp),%ebp movl 16(%esp),%ebx movl 20(%esp),%eax movl 24(%esp),%edx movl 12(%esp),%esp jmp *%esi #define VMRUN_FRAME_SIZE 24 .globl GLOBAL(vmRun) GLOBAL(vmRun): // 8(%ebp): function // 12(%ebp): arguments // 16(%ebp): checkpoint pushl %ebp movl %esp,%ebp subl $VMRUN_FRAME_SIZE,%esp movl %ebx,8(%esp) movl %esi,12(%esp) movl %edi,16(%esp) movl 12(%ebp),%eax movl %eax,4(%esp) movl 16(%ebp),%ecx movl CHECKPOINT_THREAD(%ecx),%eax movl %eax,0(%esp) movl %esp,CHECKPOINT_STACK(%ecx) call *8(%ebp) .globl GLOBAL(vmRun_returnAddress) GLOBAL(vmRun_returnAddress): movl 8(%esp),%ebx movl 12(%esp),%esi movl 16(%esp),%edi addl $VMRUN_FRAME_SIZE,%esp popl %ebp ret #endif // __i386__ ReadyTalk-avian-1e1fff5/src/x86.masm000066400000000000000000000052451231440243200172610ustar00rootroot00000000000000comment # Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. ORIGIN: https://github.com/gkvas/avian/tree/wince # .586 .MODEL FLAT, C VOID_TYPE equ 0 INT8_TYPE equ 1 INT16_TYPE equ 2 INT32_TYPE equ 3 INT64_TYPE equ 4 FLOAT_TYPE equ 5 DOUBLE_TYPE equ 6 POINTER_TYPE equ 7 CHECKPOINT_THREAD equ 4 CHECKPOINT_STACK equ 24 CHECKPOINT_BASE equ 28 _TEXT SEGMENT public C detectFeature detectFeature: push ebp mov ebp,esp push edx push ecx push ebx push esi push edi mov esi,ds:dword ptr[12+ebp] mov edi,ds:dword ptr[8+ebp] mov eax,1 cpuid and edx,esi and ecx,edi or ecx,edx test ecx,ecx je LNOSSE mov eax,1 jmp LSSEEND LNOSSE: mov eax,0 LSSEEND: pop edi pop esi pop ebx pop ecx pop edx mov esp,ebp pop ebp ret public C vmNativeCall vmNativeCall: push ebp mov ebp,esp mov ecx,ds:dword ptr[16+ebp] sub esp,ecx mov ecx,0 jmp Ltest Lloop: mov eax,ecx mov edx,ecx add edx,esp add eax,ds:dword ptr[12+ebp] mov eax,ds:dword ptr[eax] mov ds:dword ptr[edx],eax add ecx,4 Ltest: cmp ecx,ds:dword ptr[16+ebp] jb Lloop call dword ptr[8+ebp] mov ecx,ds:dword ptr[20+ebp] Lvoid: cmp ecx,offset VOID_TYPE jne Lint64 jmp Lexit Lint64: cmp ecx,offset INT64_TYPE jne Lfloat jmp Lexit Lfloat: cmp ecx,offset FLOAT_TYPE jne Ldouble fstp ds:dword ptr[8+ebp] mov eax,ds:dword ptr[8+ebp] jmp Lexit Ldouble: cmp ecx,offset DOUBLE_TYPE jne Lexit fstp ds:qword ptr[8+ebp] mov eax,ds:dword ptr[8+ebp] mov edx,ds:dword ptr[12+ebp] Lexit: mov esp,ebp pop ebp ret public C vmJump vmJump: mov esi,ds:dword ptr[4+esp] mov ebp,ds:dword ptr[8+esp] mov ebx,ds:dword ptr[16+esp] mov eax,ds:dword ptr[20+esp] mov edx,ds:dword ptr[24+esp] mov esp,ds:dword ptr[12+esp] jmp esi VMRUN_FRAME_SIZE equ 24 public C vmRun_ vmRun_: ; 8(%ebp): function ; 12(%ebp): arguments ; 16(%ebp): checkpoint push ebp mov ebp,esp sub esp,offset VMRUN_FRAME_SIZE mov ds:dword ptr[8+esp],ebx mov ds:dword ptr[12+esp],esi mov ds:dword ptr[16+esp],edi mov eax,ds:dword ptr[12+ebp] mov ds:dword ptr[4+esp],eax mov ecx,ds:dword ptr[16+ebp] mov eax,ds:dword ptr[CHECKPOINT_THREAD+ecx] mov ds:dword ptr[0+esp],eax mov ds:dword ptr[CHECKPOINT_STACK+ecx],esp call dword ptr[8+ebp] public C vmRun_returnAddress vmRun_returnAddress: mov ebx,ds:dword ptr[8+esp] mov esi,ds:dword ptr[12+esp] mov edi,ds:dword ptr[16+esp] add esp,offset VMRUN_FRAME_SIZE pop ebp ret _TEXT ENDS ENDReadyTalk-avian-1e1fff5/test/000077500000000000000000000000001231440243200161375ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/test/AllFloats.java000066400000000000000000000072421231440243200206700ustar00rootroot00000000000000public class AllFloats { private static float multiplyByFive(float a) {return 5f * a;} private static double multiplyByFive(double a) {return 5d * a;} private static float multiply(float a, float b) {return a * b;} private static double multiply(double a, double b) {return a * b;} private static double multiply(float a, double b) {return a * b;} private static float divide(float a, float b) {return a / b;} private static double divide(double a, double b) {return a / b;} private static double divide(float a, double b) {return a / b;} private static float remainder(float a, float b) {return a % b;} private static double remainder(double a, double b) {return a % b;} private static double remainder(float a, double b) {return a % b;} private static float add(float a, float b) {return a + b;} private static double add(double a, double b) {return a + b;} private static double add(float a, double b) {return a + b;} private static float subtract(float a, float b) {return a - b;} private static double subtract(double a, double b) {return a - b;} private static double subtract(float a, double b) {return a - b;} private static float complex(float a, float b) {return (a - b) / (a * b) + (float)Math.sqrt(a);} private static double complex(double a, double b) {return (a - b) / (a * b) + Math.sqrt(a);} private static double complex(float a, double b) {return (a - b) / (a * b) + Math.sqrt(a);} private static double sqrt(double a) {return Math.sqrt(a);} private static float complexNoIntrinsic(float a, float b) {return (a - b) / (a * b) + (float)sqrt(a);} private static int f2i(float a) {return (int)a;} private static long f2l(float a) {return (long)a;} private static float i2f(int a) {return (float)a;} private static double i2d(int a) {return (double)a;} private static int d2i(double a) {return (int)a;} private static long d2l(double a) {return (long)a;} private static float l2f(long a) {return (float)a;} private static double l2d(long a) {return (double)a;} private static float negate(float a) {return -a;} private static double negate(double a) {return -a;} private static int abs(int a) {return Math.abs(a);} private static float abs(float a) {return Math.abs(a);} private static void expect(boolean v) { if(!v)throw new RuntimeException(); } private static int last(){return 0;} public static void main(String[] args) { expect(multiplyByFive(36f) == 5f * 36f); expect(multiplyByFive(36d) == 5d * 36d); expect(multiply(5f, 4f) == 5f*4f); expect(multiply(5d, 4d) == 5d*4d); expect(multiply(5f, 4d) == 5f*4d); expect(divide(5f, 2f) == 5f/2f); expect(divide(5d, 2d) == 5d/2d); expect(divide(5f, 2d) == 5f/2d); expect(remainder(5f, 2f) == 5f%2f); expect(remainder(5d, 2d) == 5d%2d); expect(remainder(5f, 2d) == 5f%2d); expect(add(5f, 4f) == 5f+4f); expect(add(5d, 4d) == 5f+4d); expect(add(5f, 4d) == 5f+4d); expect(subtract(5f, 4f) == 5f-4f); expect(subtract(5d, 4d) == 5f-4d); expect(subtract(5f, 4d) == 5f-4d); expect(complex(4f, 3f) == (4f-3f)/(4f*3f) + 2f); expect(complex(4d, 3d) == (4d-3d)/(4d*3d) + 2d); expect(complex(4f, 3d) == (4f-3d)/(4f*3d) + 2f); expect(complexNoIntrinsic(4f, 3f) == (4f-3f)/(4f*3f) + 2f); expect(f2i(4f) == 4); expect(f2l(4f) == 4); expect(i2f(4) == 4f); expect(i2d(4) == 4d); expect(d2i(4d) == 4); expect(d2l(4d) == 4); expect(l2f(4) == 4f); expect(l2d(4) == 4d); expect(negate(4f) == -4f); expect(negate(4d) == -4d); expect(abs(-4) == 4); expect(abs(12) == 12); expect(abs(-4f) == 4f); expect(abs(12f) == 12f); int unused = last(); } } ReadyTalk-avian-1e1fff5/test/Annotations.java000066400000000000000000000056101231440243200213010ustar00rootroot00000000000000import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import avian.testing.annotations.Color; import avian.testing.annotations.Test; import avian.testing.annotations.TestComplex; import avian.testing.annotations.TestEnum; import avian.testing.annotations.TestInteger; public class Annotations { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } public static void main(String[] args) throws Exception { Method m = Annotations.class.getMethod("foo"); expect(m.isAnnotationPresent(Test.class)); expect(((Test) m.getAnnotation(Test.class)).value().equals("couscous")); expect(((TestEnum) m.getAnnotation(TestEnum.class)).value() .equals(Color.Red)); expect(((TestInteger) m.getAnnotation(TestInteger.class)).value() == 42); expect(m.getAnnotations().length == 3); Method noAnno = Annotations.class.getMethod("noAnnotation"); expect(noAnno.getAnnotation(Test.class) == null); expect(noAnno.getAnnotations().length == 0); testProxyDefaultValue(); testComplexAnnotation(); } @Test("couscous") @TestEnum(Color.Red) @TestInteger(42) public static void foo() { } public static void noAnnotation() { } private static void testProxyDefaultValue() { ClassLoader loader = Annotations.class.getClassLoader(); InvocationHandler handler = new InvocationHandler() { public Object invoke(Object proxy, Method method, Object... args) { return method.getDefaultValue(); } }; Test test = (Test) Proxy.newProxyInstance(loader, new Class[] { Test.class }, handler); expect("Hello, world!".equals(test.value())); } private interface World { @TestComplex(arrayValue = { @Test, @Test(value = "7/9") }, stringValue = "adjunct element", charValue = '7', doubleValue = 0.7778, classValue = TestInteger.class) int hello(); } private static void testComplexAnnotation(TestComplex annotation) throws Exception { expect(2 == annotation.arrayValue().length); expect("Hello, world!".equals(annotation.arrayValue()[0].value())); expect("7/9".equals(annotation.arrayValue()[1].value())); expect("adjunct element".equals(annotation.stringValue())); expect('7' == annotation.charValue()); expect(0.7778 == annotation.doubleValue()); expect(TestInteger.class == annotation.classValue()); } public static void testComplexAnnotation() throws Exception { ClassLoader loader = Annotations.class.getClassLoader(); TestComplex annotation = (TestComplex) World.class.getMethod("hello").getAnnotation(TestComplex.class); testComplexAnnotation(annotation); Class clazz = Proxy.getProxyClass(loader, new Class[] { World.class }); annotation = (TestComplex) clazz.getMethod("hello").getAnnotation(TestComplex.class); expect(annotation == null); } } ReadyTalk-avian-1e1fff5/test/ArrayDequeTest.java000066400000000000000000000106751231440243200217150ustar00rootroot00000000000000import java.util.ArrayDeque; import java.util.Iterator; import java.util.LinkedList; import java.util.NoSuchElementException; public class ArrayDequeTest { private static void verify(boolean val) { if (! val) { throw new RuntimeException(); } } public static void main(String[] args) throws InterruptedException { QueueHelper.sizeTest(new ArrayDeque()); QueueHelper.isEmptyTest(new ArrayDeque()); QueueHelper.addTest(new ArrayDeque()); QueueHelper.addAllTest(new ArrayDeque()); QueueHelper.elementTest(new ArrayDeque()); QueueHelper.elementFail(new ArrayDeque()); QueueHelper.removeEmptyFail(new ArrayDeque()); QueueHelper.removeTest(new ArrayDeque()); QueueHelper.containsTest(new ArrayDeque()); QueueHelper.containsAllTest(new ArrayDeque()); QueueHelper.removeObjectTest(new ArrayDeque()); QueueHelper.removeAllTest(new ArrayDeque()); QueueHelper.clearTest(new ArrayDeque()); QueueHelper.toArrayTest(new ArrayDeque()); DequeHelper.addFirstTest(new ArrayDeque()); DequeHelper.addLastTest(new ArrayDeque()); DequeHelper.removeFirstTest(new ArrayDeque()); DequeHelper.removeLastTest(new ArrayDeque()); iterateTest(false); iterateTest(true); iteratorRemoveTest(false); iteratorRemoveTest(true); iteratorNoElementFail(false); iteratorNoElementFail(true); } private static void iterateTest(boolean desc) { int testQty = 10; LinkedList compareList = new LinkedList(); ArrayDeque ad = new ArrayDeque(); for (int i = 0; i < testQty; i++) { Object o = new Object(); compareList.add(o); ad.add(o); } Iterator compIt; Iterator testIt; if (desc) { compIt = compareList.descendingIterator(); testIt = ad.descendingIterator(); } else { compIt = compareList.iterator(); testIt = ad.iterator(); } while (testIt.hasNext()) { verify(testIt.next() == compIt.next()); } // remove from the front compareList.removeFirst(); ad.removeFirst(); if (desc) { compIt = compareList.descendingIterator(); testIt = ad.descendingIterator(); } else { compIt = compareList.iterator(); testIt = ad.iterator(); } while (testIt.hasNext()) { verify(testIt.next() == compIt.next()); } // remove from the end compareList.removeLast(); ad.removeLast(); if (desc) { compIt = compareList.descendingIterator(); testIt = ad.descendingIterator(); } else { compIt = compareList.iterator(); testIt = ad.iterator(); } while (testIt.hasNext()) { verify(testIt.next() == compIt.next()); } } private static void iteratorRemoveTest(boolean desc) { int testQty = 20; LinkedList compareList = new LinkedList(); ArrayDeque ad = new ArrayDeque(); for (int i = 0; i < testQty; i++) { Object o = new Object(); compareList.add(o); ad.add(o); } Iterator compIt; Iterator testIt; if (desc) { compIt = compareList.descendingIterator(); testIt = ad.descendingIterator(); } else { compIt = compareList.iterator(); testIt = ad.iterator(); } boolean flip = true; // start with true to ensure first is removed while (testIt.hasNext()) { // advance iterators testIt.next(); compIt.next(); if (flip || ! testIt.hasNext()) { compIt.remove(); testIt.remove(); flip = false; } else { flip = true; } } if (desc) { compIt = compareList.descendingIterator(); testIt = ad.descendingIterator(); } else { compIt = compareList.iterator(); testIt = ad.iterator(); } while (testIt.hasNext()) { verify(testIt.next() == compIt.next()); } } private static void iteratorNoElementFail(boolean desc) { ArrayDeque ad = new ArrayDeque(); Iterator testIt; if (desc) { testIt = ad.descendingIterator(); } else { testIt = ad.iterator(); } try { testIt.next(); throw new RuntimeException("Exception should have thrown"); } catch (NoSuchElementException e) { // expected } } } ReadyTalk-avian-1e1fff5/test/ArraysTest.java000066400000000000000000000107351231440243200211110ustar00rootroot00000000000000import java.util.Arrays; public class ArraysTest { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static > void expectSorted(T[] array) { for (int i = 1; i < array.length; ++i) { expect(array[i - 1].compareTo(array[i]) <= 0); } } private static int pseudoRandom(int seed) { return 3170425 * seed + 132102; } private static > int shuffle(T[] array, int seed) { for (int i = array.length; i > 1; --i) { int i2 = (seed < 0 ? -seed : seed) % i; T value = array[i - 1]; array[i - 1] = array[i2]; array[i2] = value; seed = pseudoRandom(seed); } return seed; } public static void testSort() { Integer[] array = new Integer[64]; for (int i = 0; i < array.length; ++i) { array[i] = Integer.valueOf(i + 1); } ; int random = 12345; for (int i = 0; i < 32; ++i) { random = shuffle(array, random); Arrays.sort(array); expectSorted(array); } } public static void main(String[] args) { { int[] array = new int[0]; Exception exception = null; try { int x = array[0]; } catch (ArrayIndexOutOfBoundsException e) { exception = e; } expect(exception != null); } { int[] array = new int[0]; Exception exception = null; try { int x = array[-1]; } catch (ArrayIndexOutOfBoundsException e) { exception = e; } expect(exception != null); } { int[] array = new int[3]; int i = 0; array[i++] = 1; array[i++] = 2; array[i++] = 3; expect(array[--i] == 3); expect(array[--i] == 2); expect(array[--i] == 1); } { Object[][] array = new Object[1][1]; expect(array.length == 1); expect(array[0].length == 1); } { Object[][] array = new Object[2][3]; expect(array.length == 2); expect(array[0].length == 3); } { int j = 0; byte[] decodeTable = new byte[256]; for (int i = 'A'; i <= 'Z'; ++i) decodeTable[i] = (byte) j++; for (int i = 'a'; i <= 'z'; ++i) decodeTable[i] = (byte) j++; for (int i = '0'; i <= '9'; ++i) decodeTable[i] = (byte) j++; decodeTable['+'] = (byte) j++; decodeTable['/'] = (byte) j++; decodeTable['='] = 0; expect(decodeTable['a'] != 0); } { boolean p = true; int[] array = new int[] { 1, 2 }; expect(array[0] == array[p ? 0 : 1]); p = false; expect(array[1] == array[p ? 0 : 1]); } { int[] array = new int[1024]; array[1023] = -1; expect(array[1023] == -1); expect(array[1022] == 0); } { Integer[] array = (Integer[]) java.lang.reflect.Array.newInstance(Integer.class, 1); array[0] = Integer.valueOf(42); expect(array[0].intValue() == 42); } { Object[] a = new Object[3]; Object[] b = new Object[3]; expect(Arrays.equals(a, b)); a[0] = new Object(); expect(! Arrays.equals(a, b)); expect(! Arrays.equals(b, new Object[4])); expect(! Arrays.equals(a, null)); expect(! Arrays.equals(null, b)); expect(Arrays.equals((Object[])null, (Object[])null)); b[0] = a[0]; expect(Arrays.equals(a, b)); Arrays.hashCode(a); Arrays.hashCode((Object[])null); } { String[] list = new String[] { "Hello", "World", "!" }; Object[] result = Arrays.copyOf(list, 2, Object[].class); expect(list[1] == result[1]); expect(result.length == 2); expect(result.getClass().getComponentType() == Object.class); } { Object[] a = new Object[3]; Object[] b = new Object[3]; expect(Arrays.deepEquals(a, b)); a[0] = new Object(); expect(! Arrays.deepEquals(a, b)); expect(! Arrays.deepEquals(b, new Object[4])); expect(! Arrays.deepEquals(a, null)); expect(! Arrays.deepEquals(null, b)); expect(Arrays.deepEquals((Object[])null, (Object[])null)); b[0] = a[0]; expect(Arrays.deepEquals(a, b)); a[0] = new Object[] {1}; expect(! Arrays.deepEquals(a, b)); b[0] = new Object[] {1}; expect(Arrays.deepEquals(a, b)); ((Object[])a[0])[0] = (Long)1L; expect(! Arrays.deepEquals(a, b)); a[0] = new Integer[] {1}; expect(Arrays.deepEquals(a, b)); a[0] = new int[] {1}; expect(! Arrays.deepEquals(a, b)); b[0] = new int[] {1}; expect(Arrays.deepEquals(a, b)); } testSort(); } } ReadyTalk-avian-1e1fff5/test/AtomicTests.java000066400000000000000000000152141231440243200212440ustar00rootroot00000000000000import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; public class AtomicTests { private static final int threadCount = 10; private static final int iterationsPerThread = 100; public static void main(String[] args) { runAtomicIntegerTest(true); runAtomicIntegerTest(false); runAtomicLongTest(true); runAtomicLongTest(false); runAtomicReferenceTest(); } private static void blockTillThreadsDone(AtomicInteger threadDoneCount) throws InterruptedException { synchronized (threadDoneCount) { while (threadDoneCount.get() < threadCount) { threadDoneCount.wait(); } } } private static void runAtomicIntegerTest(final boolean increment) { final AtomicInteger result = new AtomicInteger(); final AtomicInteger threadDoneCount = new AtomicInteger(); // only using an AtomicBoolean here so I don't need two variables to do the synchronize/wait/notify final AtomicBoolean threadsStart = new AtomicBoolean(false); Runnable operationRunnable = new Runnable() { @Override public void run() { boolean flip = true; for (int i = 0; i < iterationsPerThread; i++) { if (flip) { if (increment) { result.incrementAndGet(); } else { result.decrementAndGet(); } flip = false; } else { if (increment) { result.getAndIncrement(); } else { result.getAndDecrement(); } flip = true; } } } }; for (int i = 0; i < threadCount; i++) { new Thread(new DelayedRunnable(threadsStart, operationRunnable, threadDoneCount)).start(); } synchronized (threadsStart) { threadsStart.set(true); threadsStart.notifyAll(); } try { blockTillThreadsDone(threadDoneCount); } catch (InterruptedException e) { // let thread exit return; } int expectedResult = threadCount * iterationsPerThread; if (! increment) { expectedResult *= -1; } int resultValue = result.get(); if (resultValue != expectedResult) { throw new IllegalStateException(resultValue + " != " + expectedResult); } } private static void runAtomicLongTest(final boolean increment) { final AtomicLong result = new AtomicLong(); final AtomicInteger threadDoneCount = new AtomicInteger(); // only using an AtomicBoolean here so I don't need two variables to do the synchronize/wait/notify final AtomicBoolean threadsStart = new AtomicBoolean(false); Runnable operationRunnable = new Runnable() { @Override public void run() { boolean flip = true; for (int i = 0; i < iterationsPerThread; i++) { if (flip) { if (increment) { result.incrementAndGet(); } else { result.decrementAndGet(); } flip = false; } else { if (increment) { result.getAndIncrement(); } else { result.getAndDecrement(); } flip = true; } } } }; for (int i = 0; i < threadCount; i++) { new Thread(new DelayedRunnable(threadsStart, operationRunnable, threadDoneCount)).start(); } synchronized (threadsStart) { threadsStart.set(true); threadsStart.notifyAll(); } try { blockTillThreadsDone(threadDoneCount); } catch (InterruptedException e) { // let thread exit return; } long expectedResult = threadCount * iterationsPerThread; if (! increment) { expectedResult *= -1; } long resultValue = result.get(); if (resultValue != expectedResult) { throw new IllegalStateException(resultValue + " != " + expectedResult); } } private static void runAtomicReferenceTest() { final AtomicReference result = new AtomicReference(0); final AtomicInteger threadDoneCount = new AtomicInteger(0); // only using an AtomicBoolean here so I don't need two variables to do the synchronize/wait/notify final AtomicBoolean threadsStart = new AtomicBoolean(false); Runnable operationRunnable = new Runnable() { @Override public void run() { for (int i = 0; i < iterationsPerThread; i++) { Integer current = result.get(); while (! result.compareAndSet(current, current + 1)) { current = result.get(); } } } }; for (int i = 0; i < threadCount; i++) { new Thread(new DelayedRunnable(threadsStart, operationRunnable, threadDoneCount)).start(); } synchronized (threadsStart) { threadsStart.set(true); threadsStart.notifyAll(); } try { blockTillThreadsDone(threadDoneCount); } catch (InterruptedException e) { // let thread exit return; } long expectedResult = threadCount * iterationsPerThread; Integer resultValue = result.get(); if (resultValue != expectedResult) { throw new IllegalStateException(resultValue + " != " + expectedResult); } } private static class DelayedRunnable implements Runnable { private final AtomicBoolean threadsStart; private final Runnable operationRunnable; private final AtomicInteger threadDoneCount; private DelayedRunnable(AtomicBoolean threadsStart, Runnable operationRunnable, AtomicInteger threadDoneCount) { this.threadsStart = threadsStart; this.operationRunnable = operationRunnable; this.threadDoneCount = threadDoneCount; } @Override public void run() { try { try { waitTillReady(); } catch (InterruptedException e) { // let thread exit return; } operationRunnable.run(); } finally { synchronized (threadDoneCount) { threadDoneCount.incrementAndGet(); threadDoneCount.notifyAll(); } } } private void waitTillReady() throws InterruptedException { synchronized (threadsStart) { while (! threadsStart.get()) { threadsStart.wait(); } } } } } ReadyTalk-avian-1e1fff5/test/BitsetTest.java000066400000000000000000000075721231440243200211070ustar00rootroot00000000000000import java.util.BitSet; public class BitsetTest { public static void main(String[] args) { BitSet bits = new BitSet(16); bits.set(5); bits.set(1); BitSet other = new BitSet(16); other.set(5); assertTrue("bit 1 is set", bits.get(1)); assertTrue("bit 5 is set", bits.get(5)); assertTrue("bit 0 is not set", !bits.get(0)); assertTrue("bit 16 is not set", !bits.get(16)); assertCardinality(bits, 2); bits.and(other); assertTrue("bit 5 is set", bits.get(5)); assertTrue("bit 1 is not set", !bits.get(1)); assertCardinality(bits, 1); bits.set(100); assertTrue("bit 100 is set", bits.get(100)); assertTrue("bit 101 is not set", !bits.get(101)); assertCardinality(bits, 2); other.set(101); bits.or(other); assertTrue("bit 101 is set", bits.get(101)); assertEquals("first bit is 5", 5, bits.nextSetBit(0)); assertEquals("first bit is 5 from 3", 5, bits.nextSetBit(4)); assertEquals("first bit is 5 from 5", 5, bits.nextSetBit(5)); assertEquals("second bit is 100", 100, bits.nextSetBit(6)); assertEquals("second bit is 100 from 100", 100, bits.nextSetBit(100)); assertEquals("third bit is 101", 101, bits.nextSetBit(101)); assertEquals("there is no 4th bit", -1, bits.nextSetBit(102)); assertCardinality(bits, 3); assertEquals("first empty bit is 0", 0, bits.nextClearBit(0)); assertEquals("after 5, 6 is empty", 6, bits.nextClearBit(5)); assertEquals("after 100, 102 is empty", 102, bits.nextClearBit(100)); testFlip(); testClear(); BitSet expandingSet = new BitSet(); //should force us to have 3 partitions. expandingSet.set(128); } private static void testFlip() { /* simple case */ BitSet bitset = new BitSet(); bitset.set(0); bitset.flip(0, 0); assertTrue("Should not be flipped with 0 length range", bitset.get(0)); bitset.flip(0, 1); assertTrue("Should be false with range of one", !bitset.get(0)); bitset.flip(0); assertTrue("Should be true again", bitset.get(0)); /* need to grow */ bitset.flip(1000); assertTrue("1000 should be true", bitset.get(1000)); assertTrue("1001 should be false", !bitset.get(1001)); assertTrue("999 should be false", !bitset.get(999)); /* Range over 2 segments */ bitset.flip(60, 70); assertTrue("59 should be false", !bitset.get(59)); for (int i=60; i < 70; ++i) { assertTrue(i + " should be true", bitset.get(i)); } assertTrue("70 should be false", !bitset.get(70)); } private static void testClear() { BitSet bitset = new BitSet(); bitset.set(0, 20); assertCardinality(bitset, 20); bitset.clear(1); assertTrue("bit 1 should be 0", !bitset.get(1)); assertCardinality(bitset, 19); bitset.clear(0, 3); assertTrue("bit 0 should be 0", !bitset.get(0)); assertTrue("bit 1 should be 0", !bitset.get(1)); assertTrue("bit 2 should be 0", !bitset.get(2)); assertTrue("bit 3 should be 1", bitset.get(3)); assertCardinality(bitset, 17); bitset = new BitSet(70); bitset.flip(0, 65); for (int i=0; i < 65; ++i) { assertTrue("bit " + i + " should be set", bitset.get(i)); } assertTrue("bit 65 should not be set", !bitset.get(65)); } static void assertTrue(String msg, boolean flag) { if (flag) { System.out.println(msg + " : OK."); } else { throw new RuntimeException("Error:"+msg); } } static void assertEquals(String msg, int expected, int actual) { if (expected==actual) { System.out.println(msg + " : OK. ["+actual+']'); } else { throw new RuntimeException("Error:"+msg+" expected:"+expected+", actual:"+actual); } } static void assertCardinality(BitSet set, int expectedCardinality) { assertEquals("Checking cardinality", expectedCardinality, set.cardinality()); } } ReadyTalk-avian-1e1fff5/test/Buffers.java000066400000000000000000000050461231440243200204030ustar00rootroot00000000000000import java.nio.ByteBuffer; public class Buffers { static { System.loadLibrary("test"); } private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static void test(Factory factory1, Factory factory2) { { final int size = 64; ByteBuffer b1 = factory1.allocate(size); try { for (int i = 0; i < size; ++i) b1.put(i, (byte) 42); for (int i = 0; i < size; ++i) expect(b1.get(i) == 42); for (int i = 0; i < size / 2; ++i) b1.putShort(i * 2, (short) -12345); for (int i = 0; i < size / 2; ++i) expect(b1.getShort(i * 2) == -12345); for (int i = 0; i < size / 4; ++i) b1.putInt(i * 4, 0x12345678); for (int i = 0; i < size / 4; ++i) expect(b1.getInt(i * 4) == 0x12345678); for (int i = 0; i < size / 8; ++i) b1.putLong(i * 8, 0x1234567890ABCDEFL); for (int i = 0; i < size / 8; ++i) expect(b1.getLong(i * 8) == 0x1234567890ABCDEFL); ByteBuffer b2 = factory2.allocate(size); try { b2.put(b1); for (int i = 0; i < size / 8; ++i) expect(b2.getLong(i * 8) == 0x1234567890ABCDEFL); } finally { factory2.dispose(b2); } } finally { factory1.dispose(b1); } } } private static native ByteBuffer allocateNative(int capacity); private static native void freeNative(ByteBuffer b); public static void main(String[] args) { Factory array = new Factory() { public ByteBuffer allocate(int capacity) { return ByteBuffer.allocate(capacity); } public void dispose(ByteBuffer b) { // ignore } }; Factory direct = new Factory() { public ByteBuffer allocate(int capacity) { return ByteBuffer.allocateDirect(capacity); } public void dispose(ByteBuffer b) { // ignore } }; Factory native_ = new Factory() { public ByteBuffer allocate(int capacity) { return allocateNative(capacity); } public void dispose(ByteBuffer b) { freeNative(b); } }; test(array, array); test(array, direct); test(array, native_); test(direct, array); test(direct, direct); test(direct, native_); test(native_, array); test(native_, direct); test(native_, native_); } private interface Factory { public ByteBuffer allocate(int capacity); public void dispose(ByteBuffer b); } } ReadyTalk-avian-1e1fff5/test/Busy.java000066400000000000000000000007631231440243200177320ustar00rootroot00000000000000public class Busy { private static volatile int foo = 0; private static volatile boolean go; public static void main(String[] args) { final Object lock = new Object(); synchronized (lock) { new Thread() { public void run() { while (foo < 100) { go = true; } } }.start(); while (foo < 100) { while (! go) { } go = false; byte[] array = new byte[256 * 1024]; ++ foo; } } } }ReadyTalk-avian-1e1fff5/test/Collections.java000066400000000000000000000033111231440243200212560ustar00rootroot00000000000000import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; public class Collections { public static void main(String[] args) { testValues(); testSort(); } @SuppressWarnings("rawtypes") private static void testValues() { Map testMap = java.util.Collections.unmodifiableMap(java.util.Collections.emptyMap()); Collection values = testMap.values(); if (values == null) { throw new NullPointerException(); } try { values.clear(); throw new IllegalStateException("Object should be immutable, exception should have thrown"); } catch (Exception e) { // expected } } private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static > void expectSorted(List list) { for (int i = 1; i < list.size(); ++i) { expect(list.get(i - 1).compareTo(list.get(i)) <= 0); } } private static int pseudoRandom(int seed) { return 3170425 * seed + 132102; } private static > int shuffle(List list, int seed) { for (int i = list.size(); i > 1; --i) { int i2 = (seed < 0 ? -seed : seed) % i; T value = list.get(i - 1); list.set(i - 1, list.get(i2)); list.set(i2, value); seed = pseudoRandom(seed); } return seed; } public static void testSort() { List list = new ArrayList(); for (int i = 0; i < 64; ++i) { list.add(Integer.valueOf(i + 1)); } ; int random = 12345; for (int i = 0; i < 32; ++i) { random = shuffle(list, random); java.util.Collections.sort(list); expectSorted(list); } } } ReadyTalk-avian-1e1fff5/test/CompletionServiceTest.java000066400000000000000000000033301231440243200232730ustar00rootroot00000000000000import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.TimeUnit; public class CompletionServiceTest { public static void main(String args[]) throws InterruptedException, ExecutionException { Executor dumbExecutor = new Executor() { @Override public void execute(Runnable task) { new Thread(task).start(); } }; pollNoResultTest(dumbExecutor); pollTimeoutNoResultTest(dumbExecutor); takeTest(dumbExecutor); } private static void verify(boolean val) { if (! val) { throw new RuntimeException(); } } private static void pollNoResultTest(Executor executor) { ExecutorCompletionService ecs = new ExecutorCompletionService(executor); verify(ecs.poll() == null); } private static void pollTimeoutNoResultTest(Executor executor) throws InterruptedException { long delayTime = 0; ExecutorCompletionService ecs = new ExecutorCompletionService(executor); long startTime = System.currentTimeMillis(); verify(ecs.poll(delayTime, TimeUnit.MILLISECONDS) == null); verify(System.currentTimeMillis() - startTime >= delayTime); } private static void takeTest(Executor executor) throws InterruptedException, ExecutionException { ExecutorCompletionService ecs = new ExecutorCompletionService(executor); final Object result = new Object(); ecs.submit(new Callable() { @Override public Object call() throws Exception { return result; } }); verify(ecs.take().get() == result); } } ReadyTalk-avian-1e1fff5/test/ConcurrentHashMapTest.java000066400000000000000000000113221231440243200232250ustar00rootroot00000000000000import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; public class ConcurrentHashMapTest { private static final int ThreadCount = 4; private static final int IterationCount = 100; private static final int Range = 10; private static final int CommonBase = -Range; private static void expect(boolean v) { if (! v) throw new RuntimeException(); } public static void main(String[] args) throws Throwable { final ConcurrentMap map = new ConcurrentHashMap(); final int[] counter = new int[1]; final int[] step = new int[1]; final Throwable[] exception = new Throwable[1]; synchronized (map) { for (int i = 0; i < ThreadCount; ++i) { final int index = i; new Thread() { public void run() { try { synchronized (map) { ++ counter[0]; map.notifyAll(); while (exception[0] == null && step[0] == 0) { map.wait(); } } for (int i = 0; i < IterationCount; ++i) { populateCommon(map); populate(map, index * Range); } synchronized (map) { -- counter[0]; map.notifyAll(); while (exception[0] == null && step[0] == 1) { map.wait(); } } for (int i = 0; i < IterationCount; ++i) { populate(map, index * Range); depopulate(map, index * Range); } synchronized (map) { ++ counter[0]; map.notifyAll(); } } catch (Throwable e) { synchronized (map) { exception[0] = e; map.notifyAll(); } e.printStackTrace(); } } }.start(); } try { while (exception[0] == null && counter[0] < ThreadCount) { map.wait(); } step[0] = 1; map.notifyAll(); while (exception[0] == null && counter[0] > 0) { map.wait(); } if (map.size() != ThreadCount * Range) { System.err.println ("expected " + (ThreadCount * Range) + " got " + map.size()); } expect(map.size() == ThreadCount * Range); for (int i = CommonBase, j = CommonBase + Range; i < j; ++i) { expect(! map.containsKey(i)); } step[0] = 2; map.notifyAll(); while (exception[0] == null && counter[0] < ThreadCount) { map.wait(); } expect(map.isEmpty()); expect(exception[0] == null); } catch (Throwable e) { exception[0] = e; throw e; } finally { map.notifyAll(); } } } private static void populateCommon(ConcurrentMap map) { Object value = new Object(); for (int i = CommonBase, j = CommonBase + Range; i < j; ++i) { map.remove(i); map.put(i, value); map.remove(i); } } private static void populate(ConcurrentMap map, int base) { for (int i = base, j = base + Range; i < j; ++i) { map.remove(i); Object value = new Object(); expect(map.put(i, value) == null); expect(map.containsKey(i)); expect(map.get(i).equals(value)); expect(map.putIfAbsent(i, new Object()) == value); expect(map.get(i).equals(value)); expect(! map.remove(i, new Object())); expect(map.remove(i, value)); expect(map.replace(i, value) == null); expect(! map.containsKey(i)); expect(map.get(i) == null); expect(map.putIfAbsent(i, value) == null); expect(map.containsKey(i)); expect(map.get(i) == value); Object newValue = new Object(); expect(map.replace(i, newValue) == value); expect(map.get(i) == newValue); boolean found = false; for (Iterator> it = map.entrySet().iterator(); it.hasNext();) { Map.Entry e = it.next(); if (e.getKey() == i) { expect(! found); expect(e.getValue() == newValue); found = true; it.remove(); } } expect(found); expect(! map.containsKey(i)); expect(map.putIfAbsent(i, value) == null); expect(map.containsKey(i)); expect(map.get(i) == value); } } private static void depopulate(ConcurrentMap map, int base) { for (int i = base, j = base + Range; i < j; ++i) { expect(map.containsKey(i)); expect(map.remove(i) != null); } } } ReadyTalk-avian-1e1fff5/test/Datagrams.java000066400000000000000000000046611231440243200207140ustar00rootroot00000000000000import java.net.SocketAddress; import java.net.InetSocketAddress; import java.net.ProtocolFamily; import java.net.StandardProtocolFamily; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.channels.Selector; import java.nio.channels.SelectionKey; public class Datagrams { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static boolean equal(byte[] a, int aOffset, byte[] b, int bOffset, int length) { for (int i = 0; i < length; ++i) { if (a[aOffset + i] != b[bOffset + i]) return false; } return true; } public static void main(String[] args) throws Exception { final String Hostname = "localhost"; final int Port = 22043; final SocketAddress Address = new InetSocketAddress(Hostname, Port); final byte[] Message = "hello, world!".getBytes(); DatagramChannel out = DatagramChannel.open(); try { out.configureBlocking(false); out.connect(Address); DatagramChannel in = DatagramChannel.open(); try { in.configureBlocking(false); in.socket().bind(Address); Selector selector = Selector.open(); try { SelectionKey outKey = out.register (selector, SelectionKey.OP_WRITE, null); SelectionKey inKey = in.register (selector, SelectionKey.OP_READ, null); int state = 0; ByteBuffer inBuffer = ByteBuffer.allocate(Message.length); loop: while (true) { selector.select(); switch (state) { case 0: { if (outKey.isWritable()) { out.write(ByteBuffer.wrap(Message)); state = 1; } } break; case 1: { if (inKey.isReadable()) { in.receive(inBuffer); if (! inBuffer.hasRemaining()) { expect(equal(inBuffer.array(), inBuffer.arrayOffset(), Message, 0, Message.length)); break loop; } } } break; default: throw new RuntimeException(); } } } finally { selector.close(); } } finally { in.close(); } } finally { out.close(); } } } ReadyTalk-avian-1e1fff5/test/Dates.java000066400000000000000000000015351231440243200200460ustar00rootroot00000000000000import java.text.FieldPosition; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; public class Dates { private final static long EPOCH = 1234567890; private final static String TEXT = "2009-02-13T23:31:30"; private static void expect(boolean v) { if (! v) throw new RuntimeException(); } public static void main(String[] args) throws Exception { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); format.setTimeZone(TimeZone.getTimeZone("GMT")); Date date = format.parse("1970-01-01T00:00:00"); expect(0 == date.getTime()); date = new Date(EPOCH * 1000l); String actual = format.format(date, new StringBuffer(), new FieldPosition(0)).toString(); expect(TEXT.equals(actual)); date = format.parse(TEXT); expect(EPOCH == date.getTime() / 1000l); } } ReadyTalk-avian-1e1fff5/test/DefineClass.java000066400000000000000000000041651231440243200211700ustar00rootroot00000000000000import java.io.IOException; import java.io.File; import java.io.FileInputStream; public class DefineClass { private static File findClass(String name, File directory) { for (File file: directory.listFiles()) { if (file.isFile()) { if (file.getName().equals(name + ".class")) { return file; } } else if (file.isDirectory()) { File result = findClass(name, file); if (result != null) { return result; } } } return null; } private static byte[] read(File file) throws IOException { byte[] bytes = new byte[(int) file.length()]; FileInputStream in = new FileInputStream(file); try { if (in.read(bytes) != (int) file.length()) { throw new RuntimeException(); } return bytes; } finally { in.close(); } } private static Class loadClass(String name) throws Exception { return new MyClassLoader(DefineClass.class.getClassLoader()).defineClass (name, read(findClass(name, new File(System.getProperty("user.dir"))))); } private static void testStatic() throws Exception { loadClass("DefineClass$Hello") .getMethod("main", String[].class).invoke(null, (Object) new String[0]); } private static void testDerived() throws Exception { System.out.println (String.valueOf (((Base) loadClass("DefineClass$Derived").newInstance()).zip())); } public static void main(String[] args) throws Exception { testStatic(); testDerived(); } private static class MyClassLoader extends ClassLoader { public MyClassLoader(ClassLoader parent) { super(parent); } public Class defineClass(String name, byte[] bytes) { return defineClass(name, bytes, 0, bytes.length); } } public static class Hello { public static void main(String[] args) { System.out.println("hello, world!"); } } public abstract static class Base { public int foo; public int[] array; public void bar() { } public abstract int zip(); } public static class Derived extends Base { public int zip() { return 42; } } } ReadyTalk-avian-1e1fff5/test/DequeHelper.java000066400000000000000000000026211231440243200212060ustar00rootroot00000000000000import java.util.Deque; public class DequeHelper { private static void verify(boolean val) { if (! val) { throw new RuntimeException(); } } public static void main(String args[]) { // prevents unit test failure } public static void addFirstTest(Deque q) { Object firstObject = new Object(); Object lastObject = new Object(); q.addFirst(lastObject); q.addFirst(firstObject); verify(q.size() == 2); verify(q.peekFirst() == firstObject); verify(q.peekLast() == lastObject); } public static void addLastTest(Deque q) { Object firstObject = new Object(); Object lastObject = new Object(); q.addLast(firstObject); q.addLast(lastObject); verify(q.size() == 2); verify(q.peekFirst() == firstObject); verify(q.peekLast() == lastObject); } public static void removeFirstTest(Deque q) { Object firstObject = new Object(); Object lastObject = new Object(); q.addLast(firstObject); q.addLast(lastObject); verify(q.removeFirst() == firstObject); verify(q.removeFirst() == lastObject); } public static void removeLastTest(Deque q) { Object firstObject = new Object(); Object lastObject = new Object(); q.addLast(firstObject); q.addLast(lastObject); verify(q.removeLast() == lastObject); verify(q.removeLast() == firstObject); } } ReadyTalk-avian-1e1fff5/test/DivideByZero.java000066400000000000000000000050161231440243200213430ustar00rootroot00000000000000public class DivideByZero { private static int divide(int n, int d) { return n / d; } private static int modulo(int n, int d) { return n % d; } private static long divide(long n, long d) { return n / d; } private static long modulo(long n, long d) { return n % d; } private static float divide(float n, float d) { return n / d; } private static float modulo(float n, float d) { return n % d; } private static double divide(double n, double d) { return n / d; } private static double modulo(double n, double d) { return n % d; } public static void main(String[] args) { try { int x = 1 / 0; throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { int x = 1 % 0; throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { int y = 2; int x = y / 0; throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { int y = 2; int x = y % 0; throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { int z = 0; int y = 2; int x = y / z; throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { int z = 0; int y = 2; int x = y % z; throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { long z = 0; long y = 2; long x = y / z; throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { long z = 0; long y = 2; long x = y % z; throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { divide(5, 0); throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { modulo(6, 0); throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { divide(5L, 0L); throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } try { modulo(6L, 0L); throw new RuntimeException(); } catch (ArithmeticException e) { e.printStackTrace(); } divide(5F, 0F); modulo(6F, 0F); divide(5D, 0D); modulo(6D, 0D); } } ReadyTalk-avian-1e1fff5/test/EnumSetTest.java000066400000000000000000000055701231440243200212310ustar00rootroot00000000000000import java.util.EnumSet; import java.util.Iterator; import java.util.NoSuchElementException; public class EnumSetTest { private enum SmallEnum { ONE, TWO, THREE } private enum LargerEnum { LARGEONE, LARGETWO, LARGETHREE, LARGEFOUR, LARGEFIVE, LARGESIX } public static void main(String[] args) { testAllOf(); testNoneOf(); testIterators(); testOf(); testCopyOf(); testComplimentOf(); } private static void testComplimentOf() { EnumSet one = EnumSet.of(SmallEnum.ONE, SmallEnum.THREE); EnumSet two = EnumSet.complementOf(one); assertElementInSet(SmallEnum.TWO, two); assertSize(1, two); } private static void testCopyOf() { EnumSet one = EnumSet.of(SmallEnum.ONE, SmallEnum.THREE); EnumSet two = EnumSet.copyOf(one); assertElementInSet(SmallEnum.ONE, two); assertElementInSet(SmallEnum.THREE, two); assertSize(2, two); } private static void testOf() { EnumSet set = EnumSet.of(LargerEnum.LARGEONE, LargerEnum.LARGEFIVE, LargerEnum.LARGETWO); assertElementInSet(LargerEnum.LARGEONE, set); assertElementInSet(LargerEnum.LARGEFIVE, set); assertElementInSet(LargerEnum.LARGETWO, set); assertSize(3, set); } private static void testAllOf() { EnumSet set = EnumSet.allOf(SmallEnum.class); for (SmallEnum current : SmallEnum.values()) { assertElementInSet(current, set); } assertSize(3, set); } private static void testNoneOf() { EnumSet set = EnumSet.noneOf(SmallEnum.class); assertSize(0, set); } private static void testIterators() { EnumSet set = EnumSet.allOf(SmallEnum.class); Iterator iterator = set.iterator(); boolean exceptionCaught = false; try { iterator.remove(); } catch (IllegalStateException e) { exceptionCaught = true; } if (!exceptionCaught) { throw new RuntimeException("Calling remove() before next() should throw IllegalStateException"); } while (iterator.hasNext()) { iterator.next(); iterator.remove(); } assertSize(0, set); exceptionCaught = false; try { iterator.next(); } catch (NoSuchElementException e) { exceptionCaught = true; } if (!exceptionCaught) { throw new RuntimeException("Calling next() when hasNext() == false should throw NoSuchElementException"); } } private static void assertElementInSet(Enum element, EnumSet set) { if (!set.contains(element)) { throw new RuntimeException("expected " + element + " in the set!"); } } private static void assertSize(int expectedSize, EnumSet set) { if (set.size() != expectedSize) { throw new RuntimeException("expected the set to be size=" + expectedSize + ", actual=" + set.size()); } } } ReadyTalk-avian-1e1fff5/test/Enums.java000066400000000000000000000021541231440243200200730ustar00rootroot00000000000000public class Enums { private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }; private enum Rank { ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING }; private enum Person { Joe(4), Mike(5) ; private final int age; private Person(int age) { this.age = age; } public int getAge() { return age; } }; private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static boolean checkFaceCard(Rank r) { switch (r) { case ACE: case JACK: case QUEEN: case KING: return true; } return false; } public static void main(String[] args) { expect(Suit.CLUBS.ordinal() == 0); expect(Suit.valueOf("DIAMONDS") == Suit.DIAMONDS); System.out.println(Suit.SPADES); expect(Suit.values()[1] == Suit.HEARTS); expect(!checkFaceCard(Rank.FIVE)); expect(checkFaceCard(Rank.KING)); expect(Person.Mike.getAge() == 5); } } ReadyTalk-avian-1e1fff5/test/Exceptions.java000066400000000000000000000006431231440243200211260ustar00rootroot00000000000000public class Exceptions { private static void evenMoreDangerous() { throw new RuntimeException("chaos! panic! overwhelming anxiety!"); } private static void moreDangerous() { evenMoreDangerous(); } private static void dangerous() { moreDangerous(); } public static void main(String[] args) { try { dangerous(); } catch (Exception e) { e.printStackTrace(); } } } ReadyTalk-avian-1e1fff5/test/FileOutput.java000066400000000000000000000023201231440243200210770ustar00rootroot00000000000000import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.File; import java.io.IOException; public class FileOutput { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static void test(boolean appendFirst) throws IOException { try { FileOutputStream f = new FileOutputStream("test.txt", appendFirst); f.write("Hello world!\n".getBytes()); f.close(); FileOutputStream f2 = new FileOutputStream("test.txt", true); f2.write("Hello world again!".getBytes()); f2.close(); FileInputStream in = new FileInputStream("test.txt"); byte[] buffer = new byte[256]; int c; int offset = 0; while ((c = in.read(buffer, offset, buffer.length - offset)) != -1) { offset += c; } in.close(); if (! "Hello world!\nHello world again!".equals (new String(buffer, 0, offset))) { throw new RuntimeException(); } } finally { expect(new File("test.txt").delete()); } } public static void main(String[] args) throws IOException { expect(new File("nonexistent-file").length() == 0); test(false); test(true); } } ReadyTalk-avian-1e1fff5/test/Files.java000066400000000000000000000045301231440243200200460ustar00rootroot00000000000000import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; public class Files { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static void isAbsoluteTest(boolean absolutePath) { File file = new File("test.txt"); if (absolutePath) { file = file.getAbsoluteFile(); } boolean isAbsolute = file.isAbsolute(); if (absolutePath) { expect(isAbsolute); } else { expect(!isAbsolute); } } private static void setExecutableTestWithPermissions(boolean executable) throws Exception { File file = File.createTempFile("avian.", null); try { file.setExecutable(executable); if (executable) { expect(file.canExecute()); } else { // Commented out because this will fail on Windows - both on Avian and on OpenJDK // The implementation for Windows considers canExecute() to be the same as canRead() // expect(!file.canExecute()); } } finally { expect(file.delete()); } } public static void main(String[] args) throws Exception { isAbsoluteTest(true); isAbsoluteTest(false); setExecutableTestWithPermissions(true); setExecutableTestWithPermissions(false); { File f = new File("test.txt"); f.createNewFile(); expect(! f.createNewFile()); f.delete(); } { File f = new File("test.txt"); FileOutputStream out = new FileOutputStream(f); try { byte[] message = "hello, world!\n".getBytes(); out.write(message); out.close(); expect(f.lastModified() > 0); FileInputStream in = new FileInputStream(f); try { expect(in.available() == message.length); for (int i = 0; i < message.length; ++i) { in.read(); expect(in.available() == message.length - i - 1); } expect(in.read() == -1); expect(in.available() == 0); } finally { in.close(); } } finally { f.delete(); } } expect(new File("foo/bar").getParent().equals("foo")); expect(new File("foo/bar/").getParent().equals("foo")); expect(new File("foo/bar//").getParent().equals("foo")); expect(new File("foo/nonexistent-directory").listFiles() == null); } } ReadyTalk-avian-1e1fff5/test/Finalizers.java000066400000000000000000000014211231440243200211060ustar00rootroot00000000000000public class Finalizers { private static final Object lock = new Object(); private static boolean finalized = false; private static void expect(boolean v) { if (! v) throw new RuntimeException(); } protected void finalize() { synchronized (lock) { finalized = true; lock.notifyAll(); } } public static void main(String[] args) throws Exception { new Finalizers(); expect(! finalized); synchronized (lock) { System.gc(); lock.wait(5000); } expect(finalized); new Finalizers2(); finalized = false; expect(! finalized); synchronized (lock) { System.gc(); lock.wait(5000); } expect(finalized); } private static class Finalizers2 extends Finalizers { } } ReadyTalk-avian-1e1fff5/test/Floats.java000066400000000000000000000206461231440243200202420ustar00rootroot00000000000000public class Floats { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static double multiply(double a, double b) { return a * b; } private static float multiply(float a, float b) { return a * b; } private static double divide(double a, double b) { return a / b; } private static double subtract(double a, double b) { return a - b; } private double field = 100d; private static int doubleToInt(Floats f) { return (int) f.field; } private static void multiplyAndStore(double a, double b, Floats f) { f.field = a * b; } private static double loadAndMultiply(double a, Floats f) { return f.field * a; } private static void subdivide(double src[], int srcoff, double left[], int leftoff, double right[], int rightoff) { double x1 = src[srcoff + 0]; double y1 = src[srcoff + 1]; double ctrlx1 = src[srcoff + 2]; double ctrly1 = src[srcoff + 3]; double ctrlx2 = src[srcoff + 4]; double ctrly2 = src[srcoff + 5]; double x2 = src[srcoff + 6]; double y2 = src[srcoff + 7]; if (left != null) { left[leftoff + 0] = x1; left[leftoff + 1] = y1; } if (right != null) { right[rightoff + 6] = x2; right[rightoff + 7] = y2; } x1 = (x1 + ctrlx1) / 2.0; y1 = (y1 + ctrly1) / 2.0; x2 = (x2 + ctrlx2) / 2.0; y2 = (y2 + ctrly2) / 2.0; double centerx = (ctrlx1 + ctrlx2) / 2.0; double centery = (ctrly1 + ctrly2) / 2.0; ctrlx1 = (x1 + centerx) / 2.0; ctrly1 = (y1 + centery) / 2.0; ctrlx2 = (x2 + centerx) / 2.0; ctrly2 = (y2 + centery) / 2.0; centerx = (ctrlx1 + ctrlx2) / 2.0; centery = (ctrly1 + ctrly2) / 2.0; if (left != null) { left[leftoff + 2] = x1; left[leftoff + 3] = y1; left[leftoff + 4] = ctrlx1; left[leftoff + 5] = ctrly1; left[leftoff + 6] = centerx; left[leftoff + 7] = centery; } if (right != null) { right[rightoff + 0] = centerx; right[rightoff + 1] = centery; right[rightoff + 2] = ctrlx2; right[rightoff + 3] = ctrly2; right[rightoff + 4] = x2; right[rightoff + 5] = y2; } } public static class Rectangle { public double x; public double y; public double width; public double height; public void setX(double x) { this.x = x; } } public static void main(String[] args) throws Exception { expect(new Double(42.0) == 42.0); { Rectangle r = new Rectangle(); Rectangle.class.getMethod("setX", double.class).invoke(r, 42.0); expect(r.x == 42.0); } { double input[] = new double[8]; double left[] = new double[8]; double right[] = new double[8]; input[0] = 732.0; input[1] = 952.0; input[2] = 761.0; input[3] = 942.0; input[4] = 786.0; input[5] = 944.0; input[6] = 813.0; input[7] = 939.0; subdivide(input, 0, left, 0, right, 0); expect(left[0] == 732.0); expect(left[1] == 952.0); expect(left[2] == 746.5); expect(left[3] == 947.0); expect(left[4] == 760.0); expect(left[5] == 945.0); expect(left[6] == 773.25); expect(left[7] == 943.625); expect(right[0] == 773.25); expect(right[1] == 943.625); expect(right[2] == 786.5); expect(right[3] == 942.25); expect(right[4] == 799.5); expect(right[5] == 941.5); expect(right[6] == 813.0); expect(right[7] == 939.0); } expect(multiply(0.5d, 0.5d) == 0.25d); expect(multiply(0.5f, 0.5f) == 0.25f); expect(multiply(0.5d, 0.1d) == 0.05d); expect(multiply(0.5f, 0.1f) == 0.05f); expect(multiply(0.5d, 0.5d) < 0.5d); expect(multiply(0.5f, 0.5f) < 0.5f); expect(multiply(0.5d, 0.1d) < 0.5d); expect(multiply(0.5f, 0.1f) < 0.5f); expect(multiply(0.5d, 0.5d) > 0.1d); expect(multiply(0.5f, 0.5f) > 0.1f); expect(multiply(0.5d, 0.1d) > 0.01d); expect(multiply(0.5f, 0.1f) > 0.01f); expect(divide(0.5d, 0.5d) == 1.0d); expect(divide(0.5d, 0.1d) == 5.0d); expect(subtract(0.5d, 0.5d) == 0.0d); expect(subtract(0.5d, 0.1d) == 0.4d); { double d = 1d; expect(((int) d) == 1); } { double d = 12345d; expect(((int) d) == 12345); } expect(doubleToInt(new Floats()) == 100); { Floats f = new Floats(); f.field = 32.0d; expect(loadAndMultiply(2.0d, f) == 64.0d); } { Floats f = new Floats(); f.field = 32.0d; expect(multiply(2.0d, f.field) == 64.0d); } { Floats f = new Floats(); multiplyAndStore(32.0d, 0.5d, f); expect(f.field == 16.0d); } { float f = 1f; expect(((int) f) == 1); } { float f = 1f; expect(((long) f) == 1); } expect(Math.round(0.4f) == 0); expect(Math.round(0.5f) == 1); expect(Math.round(1.0f) == 1); expect(Math.round(1.9f) == 2); expect(Math.round(0.4d) == 0); expect(Math.round(0.5d) == 1); expect(Math.round(1.0d) == 1); expect(Math.round(1.9d) == 2); { float b = 1.0f; int blue = (int)(b * 255 + 0.5); expect(blue == 255); } { long z = 6553311036568663L; double d = (double) z; expect(d == 6553311036568663.0); } { long z = 12345L; float f = (float) z; expect(f == 12345.0); } { int z = 12345; float f = (float) z; expect(f == 12345.0); } { int z = 12345; double d = (double) z; expect(d == 12345.0); } // Test floatToIntBits { int orig = 0x7f800001; float NaN = Float.intBitsToFloat(orig); int result = Float.floatToIntBits(NaN); int expected = 0x7fc00000; expect(result == expected); } { int orig = 0x7f801001; float NaN = Float.intBitsToFloat(orig); int result = Float.floatToIntBits(NaN); int expected = 0x7fc00000; expect(result == expected); } { int orig = 0x00800001; float number = Float.intBitsToFloat(orig); int result = Float.floatToIntBits(number); expect(result == orig); } { int orig = 0x80800003; float number = Float.intBitsToFloat(orig); int result = Float.floatToIntBits(number); expect(result == orig); } for (int x = 0; x < 1000; ++x) { int m = 100; int n = 200; double array[][] = new double[m][n]; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { array[i][j] = 1234567890.0; } } } { double v = Double.NaN; expect(0 == (int) v); } { double v = Double.NEGATIVE_INFINITY; expect(Integer.MIN_VALUE == (int) v); } { double v = Long.MIN_VALUE; expect(Integer.MIN_VALUE == (int) v); } { double v = Double.POSITIVE_INFINITY; expect(Integer.MAX_VALUE == (int) v); } { double v = Long.MAX_VALUE; expect(Integer.MAX_VALUE == (int) v); } { float v = Float.NaN; expect(0 == (int) v); } { float v = Float.NEGATIVE_INFINITY; expect(Integer.MIN_VALUE == (int) v); } { float v = Integer.MIN_VALUE; expect(Integer.MIN_VALUE == (int) v); } { float v = Float.POSITIVE_INFINITY; expect(Integer.MAX_VALUE == (int) v); } { float v = Integer.MAX_VALUE; expect(Integer.MAX_VALUE == (int) v); } { double v = Double.NaN; expect(0 == (long) v); } { double v = Double.NEGATIVE_INFINITY; expect(Long.MIN_VALUE == (long) v); } { double v = Long.MIN_VALUE; expect(Long.MIN_VALUE == (long) v); } { double v = Double.POSITIVE_INFINITY; expect(Long.MAX_VALUE == (long) v); } { double v = Long.MAX_VALUE; expect(Long.MAX_VALUE == (long) v); } { float v = Float.NaN; expect(0 == (long) v); } { float v = Float.NEGATIVE_INFINITY; expect(Long.MIN_VALUE == (long) v); } { float v = Integer.MIN_VALUE; expect(Integer.MIN_VALUE == (long) v); } { float v = Float.POSITIVE_INFINITY; expect(Long.MAX_VALUE == (long) v); } expect(Double.NaN != Double.NaN); expect(! (Double.NaN == Double.NaN)); { double d = Double.NaN; expect(Double.NaN != d); expect(! (Double.NaN == d)); expect(d != d); expect(! (d == d)); } expect(Float.NaN != Float.NaN); expect(! (Float.NaN == Float.NaN)); { float d = Float.NaN; expect(Float.NaN != d); expect(! (Float.NaN == d)); expect(d != d); expect(! (d == d)); } } } ReadyTalk-avian-1e1fff5/test/FutureTaskTest.java000066400000000000000000000060421231440243200217410ustar00rootroot00000000000000import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.RunnableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class FutureTaskTest { private static final int DELAY_TIME = 10; public static void main(String[] args) throws InterruptedException, ExecutionException { isDoneTest(false); isDoneTest(true); getCallableResultTest(); getRunnableResultTest(); getTimeoutFail(); getExecutionExceptionTest(); } private static void isDoneTest(final boolean throwException) { RunnableFuture future = new FutureTask(new Runnable() { @Override public void run() { if (throwException) { throw new RuntimeException(); } } }, null); // should finish the future future.run(); if (! future.isDone()) { throw new RuntimeException("Future should be done"); } } private static void getCallableResultTest() throws InterruptedException, ExecutionException { final Object result = new Object(); FutureTask future = new FutureTask(new Callable() { @Override public Object call() throws Exception { return result; } }); future.run(); if (future.get() != result) { throw new RuntimeException("Bad result returned: " + future.get()); } } private static void getRunnableResultTest() throws InterruptedException, ExecutionException { final Object result = new Object(); FutureTask future = new FutureTask(new Runnable() { @Override public void run() { // nothing here } }, result); future.run(); if (future.get() != result) { throw new RuntimeException("Bad result returned: " + future.get()); } } private static void getTimeoutFail() throws InterruptedException, ExecutionException { RunnableFuture future = new FutureTask(new Runnable() { @Override public void run() { // wont run } }, null); long startTime = System.currentTimeMillis(); try { future.get(DELAY_TIME, TimeUnit.MILLISECONDS); throw new RuntimeException("Exception should have been thrown"); } catch (TimeoutException e) { long catchTime = System.currentTimeMillis(); if (catchTime - startTime < DELAY_TIME) { throw new RuntimeException("get with timeout did not block long enough"); } } } private static void getExecutionExceptionTest() throws InterruptedException, ExecutionException { FutureTask future = new FutureTask(new Runnable() { @Override public void run() { throw new RuntimeException(); } }, null); future.run(); try { future.get(); throw new RuntimeException("Exception should have thrown"); } catch (ExecutionException e) { // expected } } } ReadyTalk-avian-1e1fff5/test/GC.java000066400000000000000000000070221231440243200172740ustar00rootroot00000000000000public class GC { private static final Integer cache[] = new Integer[100]; private static final Integer MAX_INT_OBJ = new Integer(Integer.MAX_VALUE); private static Integer valueOf(int i) { try { return cache[i]; } catch (ArrayIndexOutOfBoundsException e) { return (i == Integer.MAX_VALUE) ? MAX_INT_OBJ : new Integer(i); } } private static void small() { for (int i = 0; i < 1024; ++i) { byte[] a = new byte[4 * 1024]; } } private static void medium() { for (int i = 0; i < 8; ++i) { Object[] array = new Object[32]; for (int j = 0; j < 32; ++j) { array[j] = new byte[32 * 1024]; } } } private static void large() { for (int i = 0; i < 8; ++i) { byte[] a = new byte[16 * 1024 * 1024]; } for (int i = 0; i < 8; ++i) { byte[] a = new byte[16 * 1024 * 1024]; for (int j = 0; j < 32; ++j) { byte[] b = new byte[32 * 1024]; } } } private static void stackMap1(boolean predicate) { if (predicate) { Object a = null; } System.gc(); } private static void stackMap2(boolean predicate) { if (predicate) { int a = 42; } else { Object a = null; } System.gc(); } private static void stackMap3(boolean predicate) { if (predicate) { Object a = null; } else { int a = 42; } System.gc(); } private static void stackMap4(boolean predicate) { int i = 2; if (predicate) { Object a = null; } else { Object a = null; } do { System.gc(); int a = 42; -- i; } while (i >= 0); } private static void noop() { } private static void stackMap5(boolean predicate) { if (predicate) { noop(); } if (predicate) { noop(); } else { Object a = null; } System.gc(); } private static void stackMap6(boolean predicate) { if (predicate) { int a = 42; } else { Object a = null; } if (predicate) { noop(); } else { Object a = null; } noop(); System.gc(); } private static void stackMap7(boolean predicate) { try { if (predicate) { Object a = null; } else { Object a = null; } try { int a = 42; throw new DummyException(); } finally { System.gc(); } } catch (DummyException e) { e.toString(); } } private static void stackMap8(boolean predicate) { try { Object x = new Object(); if (predicate) { Object a = null; } else { Object a = null; } try { int a = 42; throw new DummyException(); } finally { System.gc(); x.toString(); } } catch (DummyException e) { e.toString(); } } public static void main(String[] args) { valueOf(1000); Object[] array = new Object[1024 * 1024]; array[0] = new Object(); small(); array[1] = new Object(); medium(); array[2] = new Object(); large(); array[0].toString(); array[1].toString(); array[2].toString(); stackMap1(true); stackMap1(false); stackMap2(true); stackMap2(false); stackMap3(true); stackMap3(false); stackMap4(true); stackMap4(false); stackMap5(true); stackMap5(false); stackMap6(true); stackMap6(false); stackMap7(true); stackMap7(false); stackMap8(true); stackMap8(false); } private static class DummyException extends RuntimeException { } } ReadyTalk-avian-1e1fff5/test/Hello.java000066400000000000000000000001571231440243200200500ustar00rootroot00000000000000public class Hello { public static void main(String[] args) { System.out.println("hello, world!"); } } ReadyTalk-avian-1e1fff5/test/Initializers.java000066400000000000000000000007241231440243200214530ustar00rootroot00000000000000public class Initializers { private static class Static2 { public static String foo = "Static2.foo"; static { System.gc(); new Exception().printStackTrace(); } } private static class Static1 { public static String foo = "Static1.foo"; static { System.out.println(Static2.foo); } } public static void main(String[] args) { Object x = new Object(); System.out.println(Static1.foo); x.toString(); } } ReadyTalk-avian-1e1fff5/test/Integers.java000066400000000000000000000216731231440243200205730ustar00rootroot00000000000000public class Integers { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static int gcd(int m, int n) { int temp; m = Math.abs(m); n = Math.abs(n); if (m < n) { temp = m; m = n; n = temp; } while (n != 0) { temp = m; m = n; n = temp % n; } return m; } public static void main(String[] args) throws Exception { { int foo = 1028; foo -= 1023; expect(foo == 5); } expect(gcd(12, 4) == 4); { int a = 2; int b = 2; int c = a + b; } { int a = 2; int c = a + a; } { int a = -5; int b = 2; expect(a >> b == -5 >> 2); expect(a >>> b == -5 >>> 2); expect(a << b == -5 << 2); expect(a + b == -5 + 2); expect(a - b == -5 - 2); expect(a * b == -5 * 2); expect(a / b == -5 / 2); expect(a % b == -5 % 2); expect((a & b) == (-5 & 2)); expect((a | b) == (-5 | 2)); expect((a ^ b) == (-5 ^ 2)); expect(-a == 5); expect(~a == ~-5); a = 5; b = 2; expect(a >> b == 5 >> 2); expect(a >>> b == 5 >>> 2); expect(a << b == 5 << 2); expect(a + b == 5 + 2); expect(a - b == 5 - 2); expect(a * b == 5 * 2); expect(a / b == 5 / 2); expect(a % b == 5 % 2); expect((a & b) == (5 & 2)); expect((a | b) == (5 | 2)); expect((a ^ b) == (5 ^ 2)); expect(-a == -5); expect(~a == ~5); } { int a = -5; expect(a >> 2 == -5 >> 2); expect(a >>> 2 == -5 >>> 2); expect(a << 2 == -5 << 2); expect(a + 2 == -5 + 2); expect(a - 2 == -5 - 2); expect(a * 2 == -5 * 2); expect(a / 2 == -5 / 2); expect(a % 2 == -5 % 2); expect((a & 2) == (-5 & 2)); expect((a | 2) == (-5 | 2)); expect((a ^ 2) == (-5 ^ 2)); a = 5; expect(a >> 2 == 5 >> 2); expect(a >>> 2 == 5 >>> 2); expect(a << 2 == 5 << 2); expect(a + 2 == 5 + 2); expect(a - 2 == 5 - 2); expect(a * 2 == 5 * 2); expect(a / 2 == 5 / 2); expect(a % 2 == 5 % 2); expect((a & 2) == (5 & 2)); expect((a | 2) == (5 | 2)); expect((a ^ 2) == (5 ^ 2)); } { int a = -5; int b = 1234567; expect(a + b == -5 + 1234567); expect(a - b == -5 - 1234567); expect(a * b == -5 * 1234567); expect(a / b == -5 / 1234567); expect(a % b == -5 % 1234567); expect((a & b) == (-5 & 1234567)); expect((a | b) == (-5 | 1234567)); expect((a ^ b) == (-5 ^ 1234567)); a = 5; b = 1234567; expect(a + b == 5 + 1234567); expect(a - b == 5 - 1234567); expect(a * b == 5 * 1234567); expect(a / b == 5 / 1234567); expect(a % b == 5 % 1234567); expect((a & b) == (5 & 1234567)); expect((a | b) == (5 | 1234567)); expect((a ^ b) == (5 ^ 1234567)); } { int a = -5; expect(a + 1234567 == -5 + 1234567); expect(a - 1234567 == -5 - 1234567); expect(a * 1234567 == -5 * 1234567); expect(a / 1234567 == -5 / 1234567); expect(a % 1234567 == -5 % 1234567); expect((a & 1234567) == (-5 & 1234567)); expect((a | 1234567) == (-5 | 1234567)); expect((a ^ 1234567) == (-5 ^ 1234567)); a = 5; expect(a + 1234567 == 5 + 1234567); expect(a - 1234567 == 5 - 1234567); expect(a * 1234567 == 5 * 1234567); expect(a / 1234567 == 5 / 1234567); expect(a % 1234567 == 5 % 1234567); expect((a & 1234567) == (5 & 1234567)); expect((a | 1234567) == (5 | 1234567)); expect((a ^ 1234567) == (5 ^ 1234567)); } { int a = -1234567; int b = 2; expect(a >> b == -1234567 >> 2); expect(a >>> b == -1234567 >>> 2); expect(a << b == -1234567 << 2); expect(a + b == -1234567 + 2); expect(a - b == -1234567 - 2); expect(a * b == -1234567 * 2); expect(a / b == -1234567 / 2); expect(a % b == -1234567 % 2); expect((a & b) == (-1234567 & 2)); expect((a | b) == (-1234567 | 2)); expect((a ^ b) == (-1234567 ^ 2)); expect(-a == 1234567); expect(~a == ~-1234567); a = 1234567; b = 2; expect(a >> b == 1234567 >> 2); expect(a >>> b == 1234567 >>> 2); expect(a << b == 1234567 << 2); expect(a + b == 1234567 + 2); expect(a - b == 1234567 - 2); expect(a * b == 1234567 * 2); expect(a / b == 1234567 / 2); expect(a % b == 1234567 % 2); expect((a & b) == (1234567 & 2)); expect((a | b) == (1234567 | 2)); expect((a ^ b) == (1234567 ^ 2)); expect(-a == -1234567); expect(~a == ~1234567); } { int a = -1234567; expect(a >> 2 == -1234567 >> 2); expect(a >>> 2 == -1234567 >>> 2); expect(a << 2 == -1234567 << 2); expect(a + 2 == -1234567 + 2); expect(a - 2 == -1234567 - 2); expect(a * 2 == -1234567 * 2); expect(a / 2 == -1234567 / 2); expect(a % 2 == -1234567 % 2); expect((a & 2) == (-1234567 & 2)); expect((a | 2) == (-1234567 | 2)); expect((a ^ 2) == (-1234567 ^ 2)); a = 1234567; expect(a >> 2 == 1234567 >> 2); expect(a >>> 2 == 1234567 >>> 2); expect(a << 2 == 1234567 << 2); expect(a + 2 == 1234567 + 2); expect(a - 2 == 1234567 - 2); expect(a * 2 == 1234567 * 2); expect(a / 2 == 1234567 / 2); expect(a % 2 == 1234567 % 2); expect((a & 2) == (1234567 & 2)); expect((a | 2) == (1234567 | 2)); expect((a ^ 2) == (1234567 ^ 2)); } { int a = -1234567; int b = 1234567; expect(a + b == -1234567 + 1234567); expect(a - b == -1234567 - 1234567); expect(a * b == -1234567 * 1234567); expect(a / b == -1234567 / 1234567); expect(a % b == -1234567 % 1234567); expect((a & b) == (-1234567 & 1234567)); expect((a | b) == (-1234567 | 1234567)); expect((a ^ b) == (-1234567 ^ 1234567)); a = 1234567; b = 1234567; expect(a + b == 1234567 + 1234567); expect(a - b == 1234567 - 1234567); expect(a * b == 1234567 * 1234567); expect(a / b == 1234567 / 1234567); expect(a % b == 1234567 % 1234567); expect((a & b) == (1234567 & 1234567)); expect((a | b) == (1234567 | 1234567)); expect((a ^ b) == (1234567 ^ 1234567)); } { int a = -1234567; expect(a + 1234567 == -1234567 + 1234567); expect(a - 1234567 == -1234567 - 1234567); expect(a * 1234567 == -1234567 * 1234567); expect(a / 1234567 == -1234567 / 1234567); expect(a % 1234567 == -1234567 % 1234567); expect((a & 1234567) == (-1234567 & 1234567)); expect((a | 1234567) == (-1234567 | 1234567)); expect((a ^ 1234567) == (-1234567 ^ 1234567)); a = 1234567; expect(a + 1234567 == 1234567 + 1234567); expect(a - 1234567 == 1234567 - 1234567); expect(a * 1234567 == 1234567 * 1234567); expect(a / 1234567 == 1234567 / 1234567); expect(a % 1234567 == 1234567 % 1234567); expect((a & 1234567) == (1234567 & 1234567)); expect((a | 1234567) == (1234567 | 1234567)); expect((a ^ 1234567) == (1234567 ^ 1234567)); } { int get_buffer = 2144642881; int bits_left = 30; int l = 9; int code = (((get_buffer >> (bits_left -= (l)))) & ((1<<(l))-1)); expect(code == 510); } { int width = 8; int height = 8; int depth = 24; int scanlinePad = 4; int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1)) / scanlinePad * scanlinePad; expect(bytesPerLine == 24); } { int y = -11760768; expect((y + 0x8000) == (-11760768 + 0x8000)); } expect(Math.min(796, 1069) == 796); { int b = 1; expect((b << 32) == 1); } { int b = 0xFFFFFFFF; expect((b >>> -1) == 1); } { int b = 0x10000000; expect((b >> -31) == 0x8000000); } { int b = 1; int s = 32; expect((b << s) == 1); } { int b = 0xFFFFFFFF; int s = -1; expect((b >>> s) == 1); } { int b = 0x10000000; int s = -31; expect((b >> s) == 0x8000000); } { int b = 0xBE; expect((b & 0xFF) == 0xBE); } { int b = 0xBE; expect((b >>> 0) == 0xBE); } { int b = 0xBE; expect((b >> 0) == 0xBE); } { int b = 0xBE; expect((b << 0) == 0xBE); } { int b = 0xBE; expect(((b >>> 0) & 0xFF) == 0xBE); } { int b = 0xBE; int x = 0xFF; expect((b & x) == 0xBE); } { int b = 0xBE; int x = 0; expect((b >>> x) == 0xBE); } { int b = 0xBE; int x = 0; expect((b >> x) == 0xBE); } { int b = 0xBE; int x = 0; expect((b << x) == 0xBE); } { int b = 0xBE; int x = 0; int y = 0xFF; expect(((b >>> x) & y) == 0xBE); } expect(123 == Integer.decode("123").intValue()); expect(-123 == Integer.decode("-123").intValue()); expect(-83 == Integer.decode("-0123").intValue()); expect(-291 == Integer.decode("-0x123").intValue()); expect(291 == Integer.decode("#123").intValue()); } } ReadyTalk-avian-1e1fff5/test/JNI.java000066400000000000000000000073131231440243200174260ustar00rootroot00000000000000import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Field; public class JNI { static { System.loadLibrary("test"); } private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static float echo(float f) { return f; } private static native float doEcho(float f); private static double echo(double f) { return f; } private static native double doEcho(double f); private static native double addDoubles (double a1, double a2, double a3, double a4, double a5, double a6, double a7, double a8, double a9, double a10, double a11, double a12, double a13, double a14, double a15, double a16, double a17, double a18, double a19, double a20); private static native float addFloats (float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8, float a9, float a10, float a11, float a12, float a13, float a14, float a15, float a16, float a17, float a18, float a19, float a20); private static native double addMix (float a1, double a2, float a3, double a4, float a5, float a6, float a7, float a8, float a9, float a10, float a11, float a12, float a13, float a14, float a15, double a16, float a17, float a18, float a19, float a20); private static native long fromReflectedMethod(Object m); private static native Object toReflectedMethod(Class c, long id, boolean isStatic); private static native int callStaticIntMethod(Class c, long id); private static native Object newObject(Class c, long id); private static native long fromReflectedField(Field f); private static native Field toReflectedField(Class c, long id, boolean isStatic); private static native int getStaticIntField(Class c, long id); private static native Object testLocalRef(Object o); public static int method242() { return 242; } public static final int field950 = 950; public static void main(String[] args) throws Exception { expect(addDoubles (1.0d, 2.0d, 3.0d, 4.0d, 5.0d, 6.0d, 7.0d, 8.0d, 9.0d, 10.0d, 11.0d, 12.0d, 13.0d, 14.0d, 15.0d, 16.0d, 17.0d, 18.0d, 19.0d, 20.0d) == 210.0d); expect(addFloats (1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f) == 210.0f); expect(addMix (1.0f, 2.0d, 3.0f, 4.0d, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0d, 17.0f, 18.0f, 19.0f, 20.0f) == 210.0d); expect(doEcho(42.0f) == 42.0f); expect(doEcho(42.0d) == 42.0d); expect(callStaticIntMethod (JNI.class, fromReflectedMethod (JNI.class.getMethod("method242"))) == 242); expect(((Method) toReflectedMethod (JNI.class, fromReflectedMethod (JNI.class.getMethod("method242")), true)) .getName().equals("method242")); expect(newObject (JNI.class, fromReflectedMethod (JNI.class.getConstructor())) instanceof JNI); expect(((Constructor) toReflectedMethod (JNI.class, fromReflectedMethod (JNI.class.getConstructor()), false)) .getDeclaringClass().equals(JNI.class)); expect(getStaticIntField (JNI.class, fromReflectedField (JNI.class.getField("field950"))) == 950); expect(toReflectedField (JNI.class, fromReflectedField (JNI.class.getField("field950")), true) .getName().equals("field950")); { Object o = new Object(); expect(testLocalRef(o) == o); } } } ReadyTalk-avian-1e1fff5/test/LazyLoading.java000066400000000000000000000106111231440243200212160ustar00rootroot00000000000000import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class LazyLoading { public static boolean loadLazy; public static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static File findClass(String name, File directory) { for (File file: directory.listFiles()) { if (file.isFile()) { if (file.getName().equals(name + ".class")) { return file; } } else if (file.isDirectory()) { File result = findClass(name, file); if (result != null) { return result; } } } return null; } private static byte[] read(File file) throws IOException { byte[] bytes = new byte[(int) file.length()]; FileInputStream in = new FileInputStream(file); try { if (in.read(bytes) != (int) file.length()) { throw new RuntimeException(); } return bytes; } finally { in.close(); } } public static void main(String[] args) throws Exception { Class c = new MyClassLoader(LazyLoading.class.getClassLoader()).loadClass ("LazyLoading$Test"); c.getMethod("test").invoke(null); } private static class MyClassLoader extends ClassLoader { public MyClassLoader(ClassLoader parent) { super(parent); } protected Class findClass(String name) throws ClassNotFoundException { try { return defineClass (name, read (LazyLoading.findClass (name, new File(System.getProperty("user.dir"))))); } catch (IOException e) { throw new RuntimeException(e); } } public Class loadClass(String name) throws ClassNotFoundException { if ("LazyLoading$Test".equals(name)) { return findClass(name); } else if ("LazyLoading$Lazy".equals(name) || "LazyLoading$Interface".equals(name)) { if (loadLazy) { return findClass(name); } else { throw new ClassNotFoundException(name); } } else { return super.loadClass(name); } } private Class defineClass(String name, byte[] bytes) { return defineClass(name, bytes, 0, bytes.length); } } public static class Test { public static void test() { doTest(); loadLazy = true; doTest(); } private static void doTest() { if (loadLazy) { // anewarray Lazy[] array = new Lazy[1]; // new and invokespecial Object lazy = new Lazy(); // checkcast array[0] = (Lazy) lazy; // instanceof expect(lazy instanceof Lazy); // invokeinterface expect(array[0].interfaceMethod() == 42); // invokestatic expect(Lazy.staticMethod() == 43); // invokevirtual expect(array[0].virtualMethod() == 44); // ldc expect(Lazy.class == lazy.getClass()); // multianewarray Lazy[][] multiarray = new Lazy[5][6]; multiarray[2][3] = array[0]; expect(multiarray[2][3] == array[0]); // getfield expect(array[0].intField == 45); // getstatic expect(Lazy.intStaticField == 46); // putfield int array[0].intField = 47; expect(array[0].intField == 47); // putfield long array[0].longField = 48; expect(array[0].longField == 48); // putfield object Object x = new Object(); array[0].objectField = x; expect(array[0].objectField == x); // putstatic int array[0].intStaticField = 49; expect(array[0].intStaticField == 49); // putstatic long array[0].longStaticField = 50; expect(array[0].longStaticField == 50); // putstatic object Object y = new Object(); array[0].objectStaticField = y; expect(array[0].objectStaticField == y); } } } private interface Interface { public int interfaceMethod(); } private static class Lazy implements Interface { public static int intStaticField = 46; public static long longStaticField; public static Object objectStaticField; public int intField = 45; public long longField; public Object objectField; public int interfaceMethod() { return 42; } public static int staticMethod() { return 43; } public int virtualMethod() { return 44; } } } ReadyTalk-avian-1e1fff5/test/LinkedBlockingQueueTest.java000066400000000000000000000144171231440243200235350ustar00rootroot00000000000000import java.util.LinkedList; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class LinkedBlockingQueueTest { private static final int DELAY_TILL_ACTION = 10; public static void main(String[] args) throws InterruptedException { remainingCapacityTest(); QueueHelper.sizeTest(new LinkedBlockingQueue()); QueueHelper.isEmptyTest(new LinkedBlockingQueue()); QueueHelper.addTest(new LinkedBlockingQueue()); addCapacityFail(); offerTest(); offerWithTimeoutTest(); offerTimeoutTest(); putTest(); QueueHelper.addAllTest(new LinkedBlockingQueue()); addAllFail(); QueueHelper.elementTest(new LinkedBlockingQueue()); QueueHelper.elementFail(new LinkedBlockingQueue()); pollEmptyTest(); pollTest(); pollTimeoutTest(); takeTest(); QueueHelper.removeEmptyFail(new LinkedBlockingQueue()); QueueHelper.removeTest(new LinkedBlockingQueue()); drainToTest(); drainToLimitTest(); QueueHelper.containsTest(new LinkedBlockingQueue()); QueueHelper.containsAllTest(new LinkedBlockingQueue()); QueueHelper.removeObjectTest(new LinkedBlockingQueue()); QueueHelper.removeAllTest(new LinkedBlockingQueue()); QueueHelper.clearTest(new LinkedBlockingQueue()); QueueHelper.toArrayTest(new LinkedBlockingQueue()); } private static void verify(boolean val) { if (! val) { throw new RuntimeException(); } } private static void remainingCapacityTest() { LinkedBlockingQueue lbq = new LinkedBlockingQueue(2); verify(lbq.remainingCapacity() == 2); lbq.add(new Object()); verify(lbq.remainingCapacity() == 1); } private static void addCapacityFail() { LinkedBlockingQueue lbq = new LinkedBlockingQueue(1); Object testObject = new Object(); lbq.add(testObject); try { lbq.add(new Object()); throw new RuntimeException("Exception should have thrown"); } catch (IllegalStateException e) { // expected } verify(lbq.size() == 1); verify(lbq.peek() == testObject); } private static void offerTest() { LinkedBlockingQueue lbq = new LinkedBlockingQueue(1); Object testObject = new Object(); verify(lbq.offer(testObject)); verify(! lbq.offer(new Object())); verify(lbq.size() == 1); verify(lbq.peek() == testObject); } private static void offerWithTimeoutTest() throws InterruptedException { final LinkedBlockingQueue lbq = new LinkedBlockingQueue(1); lbq.add(new Object()); new Thread(new Runnable() { @Override public void run() { try { // sleep to make sure offer call starts first Thread.sleep(DELAY_TILL_ACTION); lbq.take(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }).start(); // should accept once thread starts verify(lbq.offer(new Object(), 10, TimeUnit.SECONDS)); } private static void offerTimeoutTest() throws InterruptedException { LinkedBlockingQueue lbq = new LinkedBlockingQueue(1); lbq.add(new Object()); verify(! lbq.offer(new Object(), 10, TimeUnit.MILLISECONDS)); } private static void putTest() throws InterruptedException { LinkedBlockingQueue lbq = new LinkedBlockingQueue(); Object testObject = new Object(); lbq.put(testObject); verify(lbq.size() == 1); verify(lbq.peek() == testObject); } private static void addAllFail() { LinkedBlockingQueue lbq = new LinkedBlockingQueue(1); LinkedList toAdd = new LinkedList(); toAdd.add(new Object()); toAdd.add(new Object()); try { lbq.addAll(toAdd); throw new RuntimeException("Exception should have thrown"); } catch (IllegalStateException e) { // expected } } private static void pollEmptyTest() { LinkedBlockingQueue lbq = new LinkedBlockingQueue(); verify(lbq.poll() == null); } private static void pollTest() { LinkedBlockingQueue lbq = new LinkedBlockingQueue(); Object testObject = new Object(); lbq.add(testObject); verify(lbq.poll() == testObject); } private static void pollTimeoutTest() throws InterruptedException { final LinkedBlockingQueue lbq = new LinkedBlockingQueue(); final Object testObject = new Object(); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(DELAY_TILL_ACTION); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } lbq.add(testObject); } }).start(); verify(lbq.poll(DELAY_TILL_ACTION * 2, TimeUnit.MILLISECONDS) == testObject); } private static void takeTest() throws InterruptedException { final LinkedBlockingQueue lbq = new LinkedBlockingQueue(); final Object testObject = new Object(); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(DELAY_TILL_ACTION); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } lbq.add(testObject); } }).start(); verify(lbq.take() == testObject); } private static void drainToTest() { int objQty = 2; LinkedBlockingQueue lbq = new LinkedBlockingQueue(); for (int i = 0; i < objQty; i++) { lbq.add(new Object()); } LinkedList drainToResult = new LinkedList(); verify(lbq.drainTo(drainToResult) == objQty); verify(drainToResult.size() == objQty); } private static void drainToLimitTest() { int objQty = 4; int limit = 2; LinkedBlockingQueue lbq = new LinkedBlockingQueue(); for (int i = 0; i < objQty; i++) { lbq.add(new Object()); } LinkedList drainToResult = new LinkedList(); verify(lbq.drainTo(drainToResult, limit) == limit); verify(drainToResult.size() == limit); verify(lbq.size() == objQty - limit); } } ReadyTalk-avian-1e1fff5/test/List.java000066400000000000000000000114051231440243200177160ustar00rootroot00000000000000import java.util.ArrayList; import java.util.LinkedList; import java.util.ListIterator; public class List { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static String printList(ArrayList list) { StringBuilder sb = new StringBuilder(); for (Integer i : list) { sb.append(i); sb.append(", "); } sb.setLength(sb.length()-2); return sb.toString(); } private static void isEqual(String s1, String s2) { System.out.println(s1); expect(s1.equals(s2)); } private static void testIterators(java.util.List l) { l.add(1); l.add(2); l.add(3); ListIterator it = l.listIterator(); expect(it.next().equals(Integer.valueOf(1))); expect(it.next().equals(Integer.valueOf(2))); expect(it.next().equals(Integer.valueOf(3))); expect(! it.hasNext()); it = l.listIterator(1); expect(it.next().equals(Integer.valueOf(2))); expect(it.next().equals(Integer.valueOf(3))); expect(! it.hasNext()); it = l.listIterator(2); expect(it.next().equals(Integer.valueOf(3))); expect(! it.hasNext()); it = l.listIterator(3); expect(it.previous().equals(Integer.valueOf(3))); expect(it.previous().equals(Integer.valueOf(2))); expect(it.previous().equals(Integer.valueOf(1))); expect(! it.hasPrevious()); it = l.listIterator(2); expect(it.previous().equals(Integer.valueOf(2))); expect(it.previous().equals(Integer.valueOf(1))); expect(! it.hasPrevious()); it = l.listIterator(1); expect(it.previous().equals(Integer.valueOf(1))); expect(! it.hasPrevious()); } private static void testIterators2(java.util.List l) { l.add(1); l.add(2); l.add(3); ListIterator it = l.listIterator(); expect(it.next().equals(Integer.valueOf(1))); it.remove(); expect(it.next().equals(Integer.valueOf(2))); it.remove(); expect(it.next().equals(Integer.valueOf(3))); it.remove(); expect(! it.hasNext()); expect(l.isEmpty()); l.add(1); l.add(2); l.add(3); it = l.listIterator(1); expect(it.next().equals(Integer.valueOf(2))); it.remove(); expect(it.next().equals(Integer.valueOf(3))); it.remove(); expect(! it.hasNext()); expect(l.size() == 1); l.add(2); l.add(3); it = l.listIterator(2); expect(it.next().equals(Integer.valueOf(3))); it.remove(); expect(! it.hasNext()); expect(l.size() == 2); l.add(3); it = l.listIterator(3); expect(it.previous().equals(Integer.valueOf(3))); it.remove(); expect(it.previous().equals(Integer.valueOf(2))); it.remove(); expect(it.previous().equals(Integer.valueOf(1))); it.remove(); expect(! it.hasPrevious()); expect(l.isEmpty()); l.add(1); l.add(2); l.add(3); it = l.listIterator(2); expect(it.previous().equals(Integer.valueOf(2))); it.remove(); expect(it.previous().equals(Integer.valueOf(1))); it.remove(); expect(! it.hasPrevious()); expect(l.size() == 1); l.clear(); l.add(1); l.add(2); l.add(3); it = l.listIterator(1); expect(it.previous().equals(Integer.valueOf(1))); it.remove(); expect(! it.hasPrevious()); expect(l.size() == 2); } private static void testGrow() { ArrayList foo = new ArrayList(2); foo.add(0); foo.add(1); foo.add(2); // first grow foo.add(3); foo.add(4); // second grow foo.add(5); for (int i = 0; i < foo.size(); i++) { expect(i == foo.get(i)); } } private static void testRemove() { ArrayList foo = new ArrayList(2); foo.add("Uno"); foo.add("Dos"); foo.add("Tres"); foo.add("Cuatro"); ArrayList fooToRemove = new ArrayList(2); fooToRemove.add(foo.get(0)); fooToRemove.add(foo.get(1)); for (String s : fooToRemove) { foo.remove(s); } expect(foo.size() == 2); } public static void main(String args[]) { ArrayList l = new ArrayList(); l.add(1); l.add(2); l.add(3); l.add(4); l.add(5); isEqual(printList(l), "1, 2, 3, 4, 5"); l.add(0, 6); isEqual(printList(l), "6, 1, 2, 3, 4, 5"); l.add(2, 7); isEqual(printList(l), "6, 1, 7, 2, 3, 4, 5"); l.remove(1); isEqual(printList(l), "6, 7, 2, 3, 4, 5"); l.add(6, 8); isEqual(printList(l), "6, 7, 2, 3, 4, 5, 8"); Integer[] ints = new Integer[15]; Integer[] z = l.toArray(ints); expect(z == ints); for (int i=0; i < z.length; i++) { System.out.println(z[i]); } testIterators(new ArrayList()); testIterators(new LinkedList()); testIterators2(new ArrayList()); testIterators2(new LinkedList()); testGrow(); testRemove(); } } ReadyTalk-avian-1e1fff5/test/Logging.java000066400000000000000000000055061231440243200203760ustar00rootroot00000000000000import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; public class Logging { private static final Logger log = Logger.getLogger("Logging"); private static class MyHandler extends Handler { private static final int NAME_WIDTH = 18; private static final int METHOD_WIDTH = 20; private static final int LEVEL_WIDTH = 8; public Object clone() { return this; } public void close() { } public void flush() { } private void maybeLogThrown(StringBuilder sb, Throwable t) { if (t != null) { sb.append("\nCaused by: "); sb.append(t.getClass().getName()); sb.append(": "); sb.append(t.getMessage()); sb.append('\n'); for (StackTraceElement elt : t.getStackTrace()) { sb.append('\t'); sb.append(elt.getClassName()); sb.append('.'); sb.append(elt.getMethodName()); sb.append('('); sb.append(elt.getFileName()); sb.append(':'); sb.append(elt.getLineNumber()); sb.append(')'); sb.append('\n'); } maybeLogThrown(sb, t.getCause()); } } private void indent(StringBuilder sb, int amount) { do { sb.append(' '); } while (--amount > 0); } public void publish(LogRecord r) { StringBuilder sb = new StringBuilder(); sb.append(r.getLoggerName()); indent(sb, NAME_WIDTH - r.getLoggerName().length()); String methodName = r.getSourceMethodName(); if (methodName == null) { methodName = ""; } sb.append(methodName); indent(sb, METHOD_WIDTH - methodName.length()); sb.append(r.getLevel().getName()); indent(sb, LEVEL_WIDTH - r.getLevel().getName().length()); sb.append(r.getMessage()); maybeLogThrown(sb, r.getThrown()); System.out.println(sb.toString()); } } public void run() { log.info("Started run"); a(); log.log(Level.INFO, "Ended {}!", "run"); } private void a() { log.fine("Started a()"); b(); } private void b() { log.info("Started b()"); c(); } private void c() { log.warning("Started c()"); try { d(); } catch (Exception ex) { log.log(Level.SEVERE, "Exception caught in c", ex); } } private void d() throws Exception { e(); } private void e() throws Exception { throw new Exception("Started here"); } private static final boolean useCustomHandler = true; public static void main(String args[]) { if (useCustomHandler) { Logger root = Logger.getLogger(""); root.addHandler(new MyHandler()); for (Handler h : root.getHandlers()) root.removeHandler(h); root.addHandler(new MyHandler()); } Logging me = new Logging(); me.run(); } } ReadyTalk-avian-1e1fff5/test/Longs.java000066400000000000000000000307251231440243200200730ustar00rootroot00000000000000public class Longs { private static volatile long volatileLong = getConstant(); private static long getConstant() { return 0x123456789ABCDEFL; } private static void expect(boolean v) { if (! v) throw new RuntimeException(); } public static long readLongFrom(java.io.InputStream in) throws java.io.IOException { long b1 = in.read(); long b2 = in.read(); long b3 = in.read(); long b4 = in.read(); long b5 = in.read(); long b6 = in.read(); long b7 = in.read(); long b8 = in.read(); if (b8 == -1) throw new java.io.EOFException(); return (long) ((b1 << 56) | (b2 << 48) | (b3 << 40) | (b4 << 32) | (b5 << 24) | (b6 << 16) | (b7 << 8) | (b8)); } public static void putInt(int val, byte[] dst, int offset) { System.out.println("put " + val); dst[offset] = (byte)((val >> 24) & 0xff); dst[offset+1] = (byte)((val >> 16) & 0xff); dst[offset+2] = (byte)((val >> 8) & 0xff); dst[offset+3] = (byte)((val ) & 0xff); } public static void putLong(long val, byte[] dst, int offset) { putInt((int)(val >> 32), dst, offset); putInt((int)val, dst, offset + 4); } public static int getInt(byte[] src, int offset) { int r = ((src[offset] & 0xFF) << 24) | ((src[offset + 1] & 0xFF) << 16) | ((src[offset + 2] & 0xFF) << 8) | ((src[offset + 3] & 0xFF)); System.out.println("get " + r); return r; } public static long getLong(byte[] src, int offset) { return ((long) getInt(src, offset) << 32) | ((long) getInt(src, offset + 4) & 0xffffffffL); } private static long roundUp(long a, long b) { a += b - 1L; return a - (a % b); } private static int negativeOne() { return -1; } private static long unsignedShiftRight32(long x) { return x >>> 32; } public static class Rectangle { public long x; public long y; public long width; public long height; public void setX(long x) { this.x = x; } } public static void main(String[] args) throws Exception { expect(volatileLong == getConstant()); { Rectangle r = new Rectangle(); Rectangle.class.getMethod("setX", long.class).invoke(r, 42L); expect(r.x == 42L); } { long a = 0x1FFFFFFFFL; long b = -1; expect(a != b); } expect(Math.abs(-123L) == 123L); expect(readLongFrom(new java.io.InputStream() { int step; public int read() { return ++step; } }) == 0x0102030405060708L); expect(((long) negativeOne()) == -1); { long foo = 25214903884L; int radix = 10; expect(foo > 0); foo /= radix; expect(foo > 0); } expect(roundUp(156, 2) == 156); expect(((int) roundUp(156, 2)) == 156); expect(Long.parseLong("25214903884") == 25214903884L); expect(Long.parseLong("-9223372036854775808") == -9223372036854775808L); expect(String.valueOf(25214903884L).equals("25214903884")); expect(String.valueOf(-9223372036854775808L).equals ("-9223372036854775808")); { long a = -5; long b = 2; expect(a >> b == -5L >> 2); expect(a >>> b == -5L >>> 2); expect(a << b == -5L << 2); expect(a + b == -5L + 2L); expect(a - b == -5L - 2L); expect(a * b == -5L * 2L); expect(a / b == -5L / 2L); expect(a % b == -5L % 2L); expect((a & b) == (-5L & 2L)); expect((a | b) == (-5L | 2L)); expect((a ^ b) == (-5L ^ 2L)); expect(-a == 5L); expect(~a == ~-5L); a = 5; b = 2; expect(a >> b == 5L >> 2); expect(a >>> b == 5L >>> 2); expect(a << b == 5L << 2); expect(a + b == 5L + 2L); expect(a - b == 5L - 2L); expect(a * b == 5L * 2L); expect(a / b == 5L / 2L); expect(a % b == 5L % 2L); expect((a & b) == (5L & 2L)); expect((a | b) == (5L | 2L)); expect((a ^ b) == (5L ^ 2L)); expect(-a == -5L); expect(~a == ~5L); } { long a = -25214903884L; long b = 2; expect(a >> b == -25214903884L >> 2); expect(a >>> b == -25214903884L >>> 2); expect(a << b == -25214903884L << 2); expect(a + b == -25214903884L + 2L); expect(a - b == -25214903884L - 2L); expect(a * b == -25214903884L * 2L); expect(a / b == -25214903884L / 2L); expect(a % b == -25214903884L % 2L); expect((a & b) == (-25214903884L & 2L)); expect((a | b) == (-25214903884L | 2L)); expect((a ^ b) == (-25214903884L ^ 2L)); expect(-a == 25214903884L); expect(~a == ~-25214903884L); a = 25214903884L; b = 2; expect(a >> b == 25214903884L >> 2); expect(a >>> b == 25214903884L >>> 2); expect(a << b == 25214903884L << 2); expect(a + b == 25214903884L + 2L); expect(a - b == 25214903884L - 2L); expect(a * b == 25214903884L * 2L); expect(a / b == 25214903884L / 2L); expect(a % b == 25214903884L % 2L); expect((a & b) == (25214903884L & 2L)); expect((a | b) == (25214903884L | 2L)); expect((a ^ b) == (25214903884L ^ 2L)); expect(-a == -25214903884L); expect(~a == ~25214903884L); } { long b = 2; expect((-25214903884L) >> b == -25214903884L >> 2); expect((-25214903884L) >>> b == -25214903884L >>> 2); expect((-25214903884L) << b == -25214903884L << 2); expect((-25214903884L) + b == -25214903884L + 2L); expect((-25214903884L) - b == -25214903884L - 2L); expect((-25214903884L) * b == -25214903884L * 2L); expect((-25214903884L) / b == -25214903884L / 2L); expect((-25214903884L) % b == -25214903884L % 2L); expect(((-25214903884L) & b) == (-25214903884L & 2L)); expect(((-25214903884L) | b) == (-25214903884L | 2L)); expect(((-25214903884L) ^ b) == (-25214903884L ^ 2L)); b = 2; expect(25214903884L >> b == 25214903884L >> 2); expect(25214903884L >>> b == 25214903884L >>> 2); expect(25214903884L << b == 25214903884L << 2); expect(25214903884L + b == 25214903884L + 2L); expect(25214903884L - b == 25214903884L - 2L); expect(25214903884L * b == 25214903884L * 2L); expect(25214903884L / b == 25214903884L / 2L); expect(25214903884L % b == 25214903884L % 2L); expect((25214903884L & b) == (25214903884L & 2L)); expect((25214903884L | b) == (25214903884L | 2L)); expect((25214903884L ^ b) == (25214903884L ^ 2L)); } { long a = 2L; expect(a + (-25214903884L) == 2L + (-25214903884L)); expect(a - (-25214903884L) == 2L - (-25214903884L)); expect(a * (-25214903884L) == 2L * (-25214903884L)); expect(a / (-25214903884L) == 2L / (-25214903884L)); expect(a % (-25214903884L) == 2L % (-25214903884L)); expect((a & (-25214903884L)) == (2L & (-25214903884L))); expect((a | (-25214903884L)) == (2L | (-25214903884L))); expect((a ^ (-25214903884L)) == (2L ^ (-25214903884L))); a = 2L; expect(a + 25214903884L == 2L + 25214903884L); expect(a - 25214903884L == 2L - 25214903884L); expect(a * 25214903884L == 2L * 25214903884L); expect(a / 25214903884L == 2L / 25214903884L); expect(a % 25214903884L == 2L % 25214903884L); expect((a & 25214903884L) == (2L & 25214903884L)); expect((a | 25214903884L) == (2L | 25214903884L)); expect((a ^ 25214903884L) == (2L ^ 25214903884L)); } { long b = 2; expect((-281474976710656L) >> b == -281474976710656L >> 2); expect((-281474976710656L) >>> b == -281474976710656L >>> 2); expect((-281474976710656L) << b == -281474976710656L << 2); expect((-281474976710656L) + b == -281474976710656L + 2L); expect((-281474976710656L) - b == -281474976710656L - 2L); expect((-281474976710656L) * b == -281474976710656L * 2L); expect((-281474976710656L) / b == -281474976710656L / 2L); expect((-281474976710656L) % b == -281474976710656L % 2L); expect(((-281474976710656L) & b) == (-281474976710656L & 2L)); expect(((-281474976710656L) | b) == (-281474976710656L | 2L)); expect(((-281474976710656L) ^ b) == (-281474976710656L ^ 2L)); b = 2; expect(281474976710656L >> b == 281474976710656L >> 2); expect(281474976710656L >>> b == 281474976710656L >>> 2); expect(281474976710656L << b == 281474976710656L << 2); expect(281474976710656L + b == 281474976710656L + 2L); expect(281474976710656L - b == 281474976710656L - 2L); expect(281474976710656L * b == 281474976710656L * 2L); expect(281474976710656L / b == 281474976710656L / 2L); expect(281474976710656L % b == 281474976710656L % 2L); expect((281474976710656L & b) == (281474976710656L & 2L)); expect((281474976710656L | b) == (281474976710656L | 2L)); expect((281474976710656L ^ b) == (281474976710656L ^ 2L)); } { long a = 2L; expect(a + (-281474976710656L) == 2L + (-281474976710656L)); expect(a - (-281474976710656L) == 2L - (-281474976710656L)); expect(a * (-281474976710656L) == 2L * (-281474976710656L)); expect(a / (-281474976710656L) == 2L / (-281474976710656L)); expect(a % (-281474976710656L) == 2L % (-281474976710656L)); expect((a & (-281474976710656L)) == (2L & (-281474976710656L))); expect((a | (-281474976710656L)) == (2L | (-281474976710656L))); expect((a ^ (-281474976710656L)) == (2L ^ (-281474976710656L))); a = 2L; expect(a + 281474976710656L == 2L + 281474976710656L); expect(a - 281474976710656L == 2L - 281474976710656L); expect(a * 281474976710656L == 2L * 281474976710656L); expect(a / 281474976710656L == 2L / 281474976710656L); expect(a % 281474976710656L == 2L % 281474976710656L); expect((a & 281474976710656L) == (2L & 281474976710656L)); expect((a | 281474976710656L) == (2L | 281474976710656L)); expect((a ^ 281474976710656L) == (2L ^ 281474976710656L)); } { long x = 231; expect((x >> 32) == 0); expect((x >>> 32) == 0); expect((x << 32) == 992137445376L); int shift = 32; expect((x >> shift) == 0); expect((x >>> shift) == 0); expect((x << shift) == 992137445376L); long y = -231; expect((y >> 32) == 0xffffffffffffffffL); expect((y >>> 32) == 0xffffffffL); } expect(Long.valueOf(231L) == 231L); { byte[] array = new byte[8]; putLong(231, array, 0); expect((array[0] & 0xff) == 0); expect((array[1] & 0xff) == 0); expect((array[2] & 0xff) == 0); expect((array[3] & 0xff) == 0); expect((array[4] & 0xff) == 0); expect((array[5] & 0xff) == 0); expect((array[6] & 0xff) == 0); expect((array[7] & 0xff) == 231); expect(getLong(array, 0) == 231); } java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(8); buffer.putLong(231); buffer.flip(); expect(buffer.getLong() == 231); expect(unsignedShiftRight32(231) == 0); { int[] x = new int[] { 1701899151 }; int[] z = new int[x.length * 2]; final long LONG_MASK = 0xffffffffL; int lastProductLowWord = 0; for (int j=0, i=0; j>> 33); z[i++] = (int) (product >>> 1); lastProductLowWord = (int) product; } expect(z[0] == 337192406); expect(z[1] == -437261072); } { long b = 1; expect((b << 64) == 1); } { long b = 0xFFFFFFFFFFFFFFFFL; expect((b >>> -1) == 1); } { long b = 0x10000000000L; expect((b >> -63) == 0x8000000000L); } { long b = 1; int s = 64; expect((b << s) == 1); } { long b = 0xFFFFFFFFFFFFFFFFL; int s = -1; expect((b >>> s) == 1); } { long b = 0x10000000000L; int s = -63; expect((b >> s) == 0x8000000000L); } { long b = 0xBEL; expect((b & 0xFF) == 0xBEL); } { long b = 0xBEL; expect((b >>> 0) == 0xBEL); } { long b = 0xBEL; expect((b >> 0) == 0xBEL); } { long b = 0xBEL; expect((b << 0) == 0xBEL); } { long b = 0xBEL; expect(((b >>> 0) & 0xFF) == 0xBEL); } { long b = 0xBEL; int x = 0xFF; expect((b & x) == 0xBEL); } { long b = 0xBEL; int x = 0; expect((b >>> x) == 0xBEL); } { long b = 0xBEL; int x = 0; expect((b >> x) == 0xBEL); } { long b = 0xBEL; int x = 0; expect((b << x) == 0xBEL); } { long b = 0xBEL; int x = 0; int y = 0xFF; expect(((b >>> x) & y) == 0xBEL); } { long b = 0xFFFFFFFFFFFFFFFFL; int s = 20; expect((b >>> -s) == 0xFFFFF); } } } ReadyTalk-avian-1e1fff5/test/MessageFormatTest.java000066400000000000000000000021651231440243200224030ustar00rootroot00000000000000import java.text.MessageFormat; public class MessageFormatTest { private static void assertEquals(Object a, Object b) { if(!a.equals(b)) { throw new RuntimeException("[" + a + "] != [" + b + "]"); } } public static void main(String[] args) { assertEquals("Hi there", MessageFormat.format("Hi there", "a")); assertEquals("Hi there", MessageFormat.format("Hi {0}here", "t")); assertEquals("Hi a!a!a", MessageFormat.format("Hi {0}!{0}!{0}", "a")); assertEquals("Hi There", MessageFormat.format("{1} {0}", "There", "Hi")); assertEquals("6 There 4", MessageFormat.format("{1} {2} {0}", 4, 6, "There")); assertEquals("Zero and {0} aren't the same", MessageFormat.format("{0} and '{0}' aren''t the same","Zero")); assertEquals("There are six grapes", MessageFormat.format("There are {0} grapes", "six")); assertEquals("3 + 2 = 5", MessageFormat.format("{2} + {1} = {0}", 5, 2, 3)); assertEquals("again and again and again", MessageFormat.format("{0} and {0} and {0}", "again")); assertEquals("Joe's age is 30, not {0}", MessageFormat.format("Joe''s age is {0}, not '{0}'", 30)); } }ReadyTalk-avian-1e1fff5/test/Misc.java000066400000000000000000000145621231440243200177050ustar00rootroot00000000000000import java.io.IOException; import java.net.URL; import java.util.Enumeration; public class Misc { private static class μClass { public int μField; public void μMethod(int i) { μField = i; } } private interface Bar { public int baz(); } private static abstract class Bim implements Bar { } private static class Baz extends Bim { public int baz() { return 42; } } private static class Static { static { staticRan = true; } public static void run() { } } private static boolean staticRan; private static int alpha; private static int beta; private static byte byte1, byte2, byte3; private static volatile int volatileStatic; private static volatile long volatileStaticLong; private final int NonStaticConstant = 42; private int gamma; private int pajama; private boolean boolean1; private boolean boolean2; private long time; private volatile int volatileMember; public Misc() { expect(! boolean1); expect(! boolean2); time = 0xffffffffffffffffL; expect(! boolean1); expect(! boolean2); } private String foo(String s) { return s; } public String bar(String s) { return s; } private static String baz(String s) { return s; } private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private synchronized byte sync() { byte[] array = new byte[123]; return array[42]; } private static synchronized byte syncStatic(boolean throw_) { byte[] array = new byte[123]; if (throw_) { throw new RuntimeException(); } else { return array[42]; } } public String toString() { return super.toString(); } private static int zap() { return 42; } private static int zip() { return 5 + zap(); } private static int zup() { return zap() + 5; } private static class Foo { public int a; public int b; public int c; public int[] array; } private static int bar(int a, int b, int c) { return a + b + c; } private static Object gimmeNull() { return null; } private static Object queryDefault(Object default_) { Object o = gimmeNull(); return (o == null ? default_ : o); } private static class Zam { public void bim() { } } private static class Zim { public Object zum() { return null; } } private static Zim zim = new Zim(); private static void zam() { Zam z; while ((z = (Zam) zim.zum()) != null) { z.bim(); } } public static void main(String[] args) throws Exception { zam(); Bim bim = new Baz(); expect(bim.baz() == 42); expect(queryDefault(new Object()) != null); { Foo foo = new Foo(); int x = foo.a + foo.b + foo.c; bar(foo.a, foo.b, foo.c); } byte2 = 0; expect(byte2 == 0); boolean v = Boolean.valueOf("true"); ClassLoader.getSystemClassLoader().toString(); { Misc m = new Misc(); m.toString(); expect(m.NonStaticConstant == 42); expect(m.time == 0xffffffffffffffffL); long t = m.time; expect(t == 0xffffffffffffffffL); String s = "hello"; m.foo(s); m.bar(s); baz(s); m.sync(); syncStatic(false); try { syncStatic(true); } catch (RuntimeException e) { e.printStackTrace(); } int d = alpha; beta = 42; alpha = 43; volatileStatic = 55; volatileStaticLong = 9L; int e = beta; int f = alpha; m.volatileMember = 23; m.gamma = 44; m.volatileMember = 27; expect(beta == 42); expect(alpha == 43); expect(m.gamma == 44); expect(volatileStatic == 55); expect(volatileStaticLong == 9L); expect(m.volatileMember == 27); } expect(zip() == 47); expect(zup() == 47); { Object a = new Object(); Object b = new Object(); expect(a != b); Object c = a; Object d = b; expect(c != d); c = (c == a) ? b : a; d = (d == a) ? b : a; expect(c != d); } { Foo foo = new Foo(); foo.array = new int[3]; foo.a = (foo.a + 1) % foo.array.length; } { boolean foo = false; boolean iconic = false; do { zap(); iconic = foo ? true : false; } while (foo); zap(); } { int x = 0; if (x == 0) { x = 1; do { int y = x; x = 1; } while (x != 1); } } System.out.println(new java.util.Date().toString()); System.out.println('x'); System.out.println(true); System.out.println(42); System.out.println(123456789012345L); System.out.println(75.62); System.out.println(75.62d); System.out.println(new char[] { 'h', 'i' }); expect(! (((Object) new int[0]) instanceof Object[])); { μClass μInstance = new μClass(); μInstance.μMethod(8933); expect(μInstance.μField == 8933); } expect(new int[0] instanceof Cloneable); expect(new int[0] instanceof java.io.Serializable); expect(new Object[0] instanceof Cloneable); expect(new Object[0] instanceof java.io.Serializable); expect((Baz.class.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0); expect((Protected.class.getModifiers() & java.lang.reflect.Modifier.PUBLIC) == 0); try { int count = 0; boolean test = false, extraDir = false; ClassLoader loader = Misc.class.getClassLoader(); Enumeration resources = loader.getResources("multi-classpath-test.txt"); while (resources.hasMoreElements()) { ++count; String url = resources.nextElement().toString(); if (url.contains("extra-dir")) { extraDir = true; } else if (url.contains("test")) { test = true; } } expect(count == 2); expect(test); expect(extraDir); } catch (IOException e) { throw new RuntimeException(e); } expect(java.util.Arrays.equals (new byte[] { 0, 0, 0, 0 }, java.net.InetAddress.getByName("0.0.0.0").getAddress())); try { java.net.InetAddress.getByName ("bs.thisdomaindoesntexistseriouslynoway"); throw new AssertionError(); } catch (java.net.UnknownHostException e) { // cool } expect(! staticRan); Static.run(); expect(staticRan); } protected class Protected { } } ReadyTalk-avian-1e1fff5/test/NullPointer.java000066400000000000000000000051421231440243200212570ustar00rootroot00000000000000public class NullPointer { private int x; private Object y; private static void throw_(Object o) { o.toString(); } private static void throwAndCatch(Object o) { try { o.toString(); throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } } public static void main(String[] args) { try { throw_(null); throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } throwAndCatch(null); // invokeinterface try { ((Runnable) null).run(); throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // invokevirtual try { ((Object) null).toString(); throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // arraylength try { int a = ((byte[]) null).length; throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // iaload try { int a = ((byte[]) null)[42]; throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // aaload try { Object a = ((Object[]) null)[42]; throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // getfield (int) try { int a = ((NullPointer) null).x; throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // getfield (Object) try { Object a = ((NullPointer) null).y; throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // iastore try { ((byte[]) null)[42] = 42; throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // aastore try { ((Object[]) null)[42] = null; throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // putfield (int) try { ((NullPointer) null).x = 42; throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // putfield (Object) try { ((NullPointer) null).y = null; throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } // monitorenter try { synchronized ((Object) null) { int a = 42; } throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } } } ReadyTalk-avian-1e1fff5/test/Observe.java000066400000000000000000000034271231440243200204150ustar00rootroot00000000000000import java.util.Observer; import java.util.Observable; public class Observe { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static class MyObservable extends Observable { private String value; public MyObservable(String value) { this.value = value; } public void set(String newValue) { if(!value.equals(newValue)) { value = newValue; setChanged(); notifyObservers(value); } } } private static class MyObserver implements Observer { private int count = 0; private Observable expectedObs; private Object expectedValue = null; private boolean expected = false; public MyObserver(Observable expectedObs) { this.expectedObs = expectedObs; } public void update(Observable obs, Object value) { expect(expectedObs == expectedObs); expect(expected); expect(value == expectedValue); expectNothing(); } public void noUpdate() { expect(!expected); } public void expect(Object value) { expected = true; expectedValue = value; } public void expectNothing() { expected = false; } } public static void main(String[] args) { MyObservable obs = new MyObservable("test"); MyObserver o = new MyObserver(obs); MyObserver o2 = new MyObserver(obs); obs.set("a"); obs.addObserver(o); o.expect("b"); obs.set("b"); o.noUpdate(); obs.addObserver(o2); o.expect("c"); o2.expect("c"); obs.set("c"); o.noUpdate(); o2.noUpdate(); obs.deleteObserver(o); o.expectNothing(); o2.expect("d"); obs.set("d"); o2.noUpdate(); obs.deleteObserver(o2); o.expectNothing(); o2.expectNothing(); obs.set("e"); } }ReadyTalk-avian-1e1fff5/test/OutOfMemory.java000066400000000000000000000023531231440243200212320ustar00rootroot00000000000000public class OutOfMemory { // assume a 128MB heap size: private static final int Padding = 120 * 1024 * 1024; private static class Node { Object value; Node next; } private static void bigObjects() { Object[] root = null; while (true) { Object[] x = new Object[1024 * 1024]; x[0] = root; root = x; } } private static void littleObjects() { byte[] padding = new byte[Padding]; Node root = null; while (true) { Node x = new Node(); x.next = root; root = x; } } private static void bigAndLittleObjects() { byte[] padding = new byte[Padding]; Node root = null; while (true) { Node x = new Node(); x.value = new Object[1024 * 1024]; x.next = root; root = x; } } public static void main(String[] args) { try { bigObjects(); throw new RuntimeException(); } catch (OutOfMemoryError e) { e.printStackTrace(); } try { littleObjects(); throw new RuntimeException(); } catch (OutOfMemoryError e) { e.printStackTrace(); } try { bigAndLittleObjects(); throw new RuntimeException(); } catch (OutOfMemoryError e) { e.printStackTrace(); } } } ReadyTalk-avian-1e1fff5/test/Processes.java000066400000000000000000000014201231440243200207450ustar00rootroot00000000000000import java.io.IOException; public class Processes { public static void main(String[] args) { long start = System.currentTimeMillis(); try { final Process p = Runtime.getRuntime().exec("sleep 10"); new Thread() { public void run() { try { Thread.sleep(100); } catch(InterruptedException e) { // ignore } p.destroy(); } }.start(); try { p.waitFor(); } catch(InterruptedException e) { // ignore } long stop = System.currentTimeMillis(); if(stop - start > 5000) { throw new RuntimeException("test failed; we didn't kill the process..."); } } catch(IOException e) { throw new RuntimeException(e); } } } ReadyTalk-avian-1e1fff5/test/Proxies.java000066400000000000000000000024311231440243200204330ustar00rootroot00000000000000import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class Proxies { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } public static void main(String[] args) { Foo foo = (Foo) Proxy.newProxyInstance (Proxies.class.getClassLoader(), new Class[] { Foo.class }, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] arguments) { if (method.getName().equals("bar")) { return "bam"; } else if (method.getName().equals("baz")) { return ((Integer) arguments[0]) + 1; } else if (method.getName().equals("bim")) { return ((Long) arguments[0]) - 1L; } else if (method.getName().equals("boom")) { return ((String) arguments[0]).substring(1); } else { throw new IllegalArgumentException(); } } }); expect(foo.bar().equals("bam")); expect(foo.baz(42) == 43); expect(foo.bim(42L) == 41L); expect(foo.boom("hello").equals("ello")); } private interface Foo { public String bar(); public int baz(int v); public long bim(long v); public String boom(String s); } } ReadyTalk-avian-1e1fff5/test/QueueHelper.java000066400000000000000000000065461231440243200212410ustar00rootroot00000000000000import java.util.LinkedList; import java.util.NoSuchElementException; import java.util.Queue; public class QueueHelper { private static void verify(boolean val) { if (! val) { throw new RuntimeException(); } } public static void main(String args[]) { // prevents unit test failure } public static void sizeTest(Queue q) { verify(q.size() == 0); q.add(new Object()); verify(q.size() == 1); } public static void isEmptyTest(Queue q) { verify(q.isEmpty()); q.add(new Object()); verify(! q.isEmpty()); } public static void addTest(Queue q) { Object testObject = new Object(); q.add(testObject); verify(q.size() == 1); verify(q.peek() == testObject); } public static void addAllTest(Queue q) { LinkedList toAdd = new LinkedList(); toAdd.add(new Object()); toAdd.add(new Object()); q.addAll(toAdd); verify(q.size() == toAdd.size()); while (! q.isEmpty()) { verify(q.remove() == toAdd.remove()); } } public static void elementTest(Queue q) { Object testObject = new Object(); q.add(testObject); verify(q.element() == testObject); } public static void elementFail(Queue q) { try { q.element(); throw new RuntimeException("Exception should have thrown"); } catch (NoSuchElementException e) { // expected } } public static void removeTest(Queue q) { Object testObject = new Object(); q.add(testObject); verify(q.remove() == testObject); } public static void removeEmptyFail(Queue q) { try { q.remove(); throw new RuntimeException("Exception should have thrown"); } catch (NoSuchElementException e) { // expected } } public static void containsTest(Queue q) { Object testObject = new Object(); verify(! q.contains(testObject)); q.add(testObject); verify(q.contains(testObject)); } public static void containsAllTest(Queue q) { Object testObject = new Object(); q.add(testObject); LinkedList testList = new LinkedList(); testList.add(testObject); testList.add(new Object()); verify(! q.containsAll(testList)); q.addAll(testList); verify(q.containsAll(testList)); } public static void removeObjectTest(Queue q) { Object testObject = new Object(); verify(! q.remove(testObject)); q.add(testObject); verify(q.remove(testObject)); } public static void removeAllTest(Queue q) { Object testObject = new Object(); q.add(testObject); LinkedList testList = new LinkedList(); testList.add(testObject); testList.add(new Object()); verify(q.removeAll(testList)); q.addAll(testList); verify(q.removeAll(testList)); } public static void clearTest(Queue q) { q.add(new Object()); q.clear(); verify(q.isEmpty()); } public static void toArrayTest(Queue q) { if (q.toArray().length != 0) { throw new RuntimeException(); } Object testObject = new Object(); q.add(testObject); Object[] result = q.toArray(); verify(result.length == 1); verify(result[0] == testObject); } } ReadyTalk-avian-1e1fff5/test/References.java000066400000000000000000000036241231440243200210700ustar00rootroot00000000000000import java.lang.ref.ReferenceQueue; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.lang.ref.PhantomReference; import java.util.WeakHashMap; public class References { public static void main(String[] args) { Object a = new Object(); Object b = new Object(); Object c = new Object(); Object d = new Object(); Object e = new Object(); Object f = new Object(); ReferenceQueue q = new ReferenceQueue(); Reference ar = new WeakReference(a); Reference br = new WeakReference(b, q); Reference cr = new WeakReference(c, q); Reference dr = new PhantomReference(d, q); Reference er = new MyReference(e, q, "foo"); WeakHashMap map = new WeakHashMap(); map.put(new Key("foo"), f); a = b = c = d = e = cr = null; System.out.println("a: " + ar.get()); System.out.println("b: " + br.get()); System.out.println("d: " + dr.get()); System.out.println("e: " + er.get()); System.out.println("f: " + map.get(new Key("foo"))); System.gc(); System.out.println("a: " + ar.get()); System.out.println("b: " + br.get()); System.out.println("d: " + dr.get()); System.out.println("e: " + er.get()); System.out.println("f: " + map.get(new Key("foo"))); for (Reference r = q.poll(); r != null; r = q.poll()) { System.out.println("polled: " + r.get()); } } private static class MyReference extends WeakReference { private final Object foo; public MyReference(Object target, ReferenceQueue queue, Object foo) { super(target, queue); this.foo = foo; } } private static class Key { private final String name; public Key(String name) { this.name = name; } public int hashCode() { return name.hashCode(); } public boolean equals(Object o) { return o instanceof Key && ((Key) o).name.equals(name); } } } ReadyTalk-avian-1e1fff5/test/Reflection.java000066400000000000000000000165541231440243200211070ustar00rootroot00000000000000import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.InvocationTargetException; public class Reflection { public static boolean booleanMethod() { return true; } public static byte byteMethod() { return 1; } public static char charMethod() { return '2'; } public static short shortMethod() { return 3; } public static int intMethod() { return 4; } public static float floatMethod() { return 5.0f; } public static long longMethod() { return 6; } public static double doubleMethod() { return 7.0; } public static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static class Hello { private class World { } } private static void innerClasses() throws Exception { Class c = Reflection.class; Class[] inner = c.getDeclaredClasses(); expect(2 == inner.length); expect(Hello.class == inner[0] || Hello.class == inner[1]); } private int egads; private static void annotations() throws Exception { Field egads = Reflection.class.getDeclaredField("egads"); expect(egads.getAnnotation(Deprecated.class) == null); } private Integer[] array; private Integer integer; public static Hello>.World> pinky; private static void genericType() throws Exception { Field field = Reflection.class.getDeclaredField("egads"); expect(field.getGenericType() == Integer.TYPE); field = Reflection.class.getField("pinky"); expect("Reflection$Hello$World".equals(field.getType().getName())); expect(field.getGenericType() instanceof ParameterizedType); ParameterizedType type = (ParameterizedType) field.getGenericType(); expect(type.getRawType() instanceof Class); Class clazz = (Class) type.getRawType(); expect("Reflection$Hello$World".equals(clazz.getName())); expect(type.getOwnerType() instanceof ParameterizedType); ParameterizedType owner = (ParameterizedType) type.getOwnerType(); clazz = (Class) owner.getRawType(); expect(clazz == Hello.class); Type[] args = type.getActualTypeArguments(); expect(1 == args.length); expect(args[0] instanceof ParameterizedType); ParameterizedType arg = (ParameterizedType) args[0]; expect(arg.getRawType() instanceof Class); clazz = (Class) arg.getRawType(); expect("Reflection$Hello".equals(clazz.getName())); args = arg.getActualTypeArguments(); expect(1 == args.length); expect(args[0] == String.class); } public static void throwOOME() { throw new OutOfMemoryError(); } public static void main(String[] args) throws Exception { innerClasses(); annotations(); genericType(); Class system = Class.forName("java.lang.System"); Field out = system.getDeclaredField("out"); Class output = Class.forName("java.io.PrintStream"); Method println = output.getDeclaredMethod("println", String.class); println.invoke(out.get(null), "Hello, World!"); expect((Boolean) Reflection.class.getMethod("booleanMethod").invoke(null)); expect(1 == (Byte) Reflection.class.getMethod("byteMethod").invoke(null)); expect('2' == (Character) Reflection.class.getMethod ("charMethod").invoke(null)); expect(3 == (Short) Reflection.class.getMethod ("shortMethod").invoke(null)); expect(4 == (Integer) Reflection.class.getMethod ("intMethod").invoke(null)); expect(5.0 == (Float) Reflection.class.getMethod ("floatMethod").invoke(null)); expect(6 == (Long) Reflection.class.getMethod ("longMethod").invoke(null)); expect(7.0 == (Double) Reflection.class.getMethod ("doubleMethod").invoke(null)); { Class[][] array = new Class[][] { { Class.class } }; expect("[Ljava.lang.Class;".equals(array[0].getClass().getName())); expect(Class[].class == array[0].getClass()); expect(array.getClass().getComponentType() == array[0].getClass()); } { Reflection r = new Reflection(); expect(r.egads == 0); Reflection.class.getDeclaredField("egads").set(r, (Integer)42); expect(((Integer)Reflection.class.getDeclaredField("egads").get(r)) == 42); Reflection.class.getDeclaredField("egads").setInt(r, 43); expect(Reflection.class.getDeclaredField("egads").getInt(r) == 43); Integer[] array = new Integer[0]; Reflection.class.getDeclaredField("array").set(r, array); expect(Reflection.class.getDeclaredField("array").get(r) == array); try { Reflection.class.getDeclaredField("array").set(r, new Object()); expect(false); } catch (IllegalArgumentException e) { // cool } Integer integer = 45; Reflection.class.getDeclaredField("integer").set(r, integer); expect(Reflection.class.getDeclaredField("integer").get(r) == integer); try { Reflection.class.getDeclaredField("integer").set(r, new Object()); expect(false); } catch (IllegalArgumentException e) { // cool } try { Reflection.class.getDeclaredField("integer").set (new Object(), integer); expect(false); } catch (IllegalArgumentException e) { // cool } try { Reflection.class.getDeclaredField("integer").get(new Object()); expect(false); } catch (IllegalArgumentException e) { // cool } } try { Foo.class.getMethod("foo").invoke(null); expect(false); } catch (ExceptionInInitializerError e) { expect(e.getCause() instanceof MyException); } try { Foo.class.getConstructor().newInstance(); expect(false); } catch (NoClassDefFoundError e) { // cool } try { Foo.class.getField("foo").get(null); expect(false); } catch (NoClassDefFoundError e) { // cool } try { Foo.class.getField("foo").set(null, (Integer)42); expect(false); } catch (NoClassDefFoundError e) { // cool } try { Foo.class.getField("foo").set(null, new Object()); expect(false); } catch (IllegalArgumentException e) { // cool } catch (NoClassDefFoundError e) { // cool } { Method m = Reflection.class.getMethod("throwOOME"); try { m.invoke(null); } catch(Throwable t) { expect(t.getClass() == InvocationTargetException.class); } } expect((Foo.class.getMethod("toString").getModifiers() & Modifier.PUBLIC) != 0); expect(avian.TestReflection.get(Baz.class.getField("foo"), new Baz()) .equals(42)); expect((Baz.class.getModifiers() & Modifier.PUBLIC) == 0); expect(B.class.getDeclaredMethods().length == 0); new Runnable() { public void run() { expect(getClass().getDeclaringClass() == null); } }.run(); expect(avian.testing.annotations.Test.class.getPackage().getName().equals ("avian.testing.annotations")); } protected static class Baz { public int foo = 42; } } class Foo { static { if (true) throw new MyException(); } public Foo() { } public static int foo; public static void foo() { // ignore } } class MyException extends RuntimeException { } interface A { void foo(); } interface B extends A { } ReadyTalk-avian-1e1fff5/test/Regex.java000066400000000000000000000062511231440243200200600ustar00rootroot00000000000000import java.util.regex.Matcher; import java.util.regex.Pattern; public class Regex { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static Matcher getMatcher(String regex, String string) { return Pattern.compile(regex).matcher(string); } private static void expectMatch(String regex, String string) { expect(getMatcher(regex, string).matches()); } private static void expectNoMatch(String regex, String string) { expect(!getMatcher(regex, string).matches()); } private static void expectGroups(String regex, String string, String... groups) { Matcher matcher = getMatcher(regex, string); expect(matcher.matches()); expect(matcher.groupCount() == groups.length); for (int i = 1; i <= groups.length; ++i) { if (groups[i - 1] == null) { expect(matcher.group(i) == null); } else { expect(groups[i - 1].equals(matcher.group(i))); } } } private static void expectFind(String regex, String string, String... matches) { Matcher matcher = getMatcher(regex, string); int i = 0; while (i < matches.length) { expect(matcher.find()); expect(matches[i++].equals(matcher.group())); } expect(!matcher.find()); } private static void expectSplit(String regex, String string, String... list) { String[] array = Pattern.compile(regex).split(string); expect(array.length == list.length); for (int i = 0; i < list.length; ++ i) { expect(list[i].equals(array[i])); } } public static void main(String[] args) { expectMatch("a(bb)?a", "abba"); expectNoMatch("a(bb)?a", "abbba"); expectNoMatch("a(bb)?a", "abbaa"); expectGroups("a(a*?)(a?)(a??)(a+)(a*)a", "aaaaaa", "", "a", "", "aaa", ""); expectMatch("...", "abc"); expectNoMatch(".", "\n"); expectGroups("a(bb)*a", "abbbba", "bb"); expectGroups("a(bb)?(bb)+a", "abba", null, "bb"); expectFind(" +", "Hello , world! ", " ", " ", " "); expectMatch("[0-9A-Fa-f]+", "08ef"); expectNoMatch("[0-9A-Fa-f]+", "08@ef"); expectGroups("(?:a)", "a"); expectGroups("a|(b|c)", "a", (String)null); expectGroups("a|(b|c)", "c", "c"); expectGroups("(?=a)a", "a"); expectGroups(".*(o)(?<=[A-Z][a-z]{1,4})", "Hello", "o"); expectNoMatch("(?!a).", "a"); expectMatch("[\\d]", "0"); expectMatch("\\0777", "?7"); expectMatch("\\a", "\007"); expectMatch("\\\\", "\\"); expectMatch("\\x4A", "J"); expectMatch("\\x61", "a"); expectMatch("\\078", "\0078"); expectSplit("(?<=\\w)(?=\\W)|(?<=\\W)(?=\\w)", "a + b * x", "a", " + ", "b", " * ", "x"); expectMatch("[0-9[def]]", "f"); expectNoMatch("[a-z&&[^d-f]]", "f"); expectSplit("^H", "Hello\nHobbes!", "", "ello\nHobbes!"); expectSplit("o.*?$", "Hello\r\nHobbes!", "Hello\r\nH"); expectSplit("\\b", "a+ b + c\nd", "", "a", "+ ", "b", " + ", "c", "\n", "d"); expectSplit("\\B", "Hi Cal!", "H", "i C", "a", "l!"); expectMatch("a{2,5}", "aaaa"); expectGroups("a??(a{2,5}?)", "aaaa", "aaaa"); expectGroups("a??(a{3}?)", "aaaa", "aaa"); expectNoMatch("a(a{3}?)", "aaaaa"); expectMatch("a(a{3,}?)", "aaaaa"); } } ReadyTalk-avian-1e1fff5/test/Serialize.java000066400000000000000000000146121231440243200207350ustar00rootroot00000000000000import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Properties; public class Serialize implements Serializable { public static final long serialVersionUID = 1l; public int dummy = 0x12345678; private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static void expectEqual(boolean a, boolean b) { expect(a == b); } private static void expectEqual(int a, int b) { expect(a == b); } private static void expectEqual(String a, String b) { expect(a.equals(b)); } private static String pad(long number, int length) { return pad(Long.toHexString(number), length, '0'); } private static String pad(String s, int length, char padChar) { length -= s.length(); if (length <= 0) { return s; } StringBuilder builder = new StringBuilder(); while (length-- > 0) { builder.append(padChar); } return builder.append(s).toString(); } protected static void hexdump(byte[] a) { StringBuilder builder = new StringBuilder(); System.err.print(pad(0, 8) + " "); for (int i = 0; i < a.length; i++) { String hex = Integer.toHexString(a[i] & 0xff); System.err.print(" " + (hex.length() == 1 ? "0" : "") + hex); builder.append(a[i] < 0x20 || a[i] > 0x7f ? '.' : (char)a[i]); if ((i & 0xf) == 0x7) { System.err.print(" "); } else if ((i & 0xf) == 0xf) { System.err.println(" |" + builder + "|"); builder.setLength(0); System.err.print(pad(i + 1, 8) + " "); } } for (int i = a.length & 0xf; i < 0x10; i++) { System.err.print(" "); if ((i & 0xf) == 0x7) { System.err.print(" "); } } System.err.println(" |" + builder + "|"); } private static void expectEqual(byte[] a, int[] b) { expect(a.length == b.length); for (int i = 0; i < a.length; ++i) { expect(a[i] == (byte)b[i]); } } private static class MyMap implements Serializable { private transient Properties properties = new Properties(); public final static long serialVersionUID = 0x0cc1f63e2d256ae6l; public int size() { return properties.size(); } public void put(String key, String value) { properties.put(key, value); } public String get(String key) { return properties.getProperty(key); } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(size()); for (Object key : properties.keySet()) { out.writeObject(key); out.writeObject(properties.get(key)); } } private void readObject(ObjectInputStream in) throws IOException { try { in.defaultReadObject(); } catch (Exception e) { // OpenJDK's defaultReadObject() can throw a ClassNotFoundException throw new IOException(e); } properties = new Properties(); int size = in.readInt(); for (int i = 0; i < size; i++) try { properties.put(in.readObject(), in.readObject()); } catch (ClassNotFoundException e) { throw new IOException(e); } } } public static void main(String[] args) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream out2 = new ObjectOutputStream(out); out2.writeBoolean(true); out2.flush(); out2.writeByte(17); out2.flush(); out2.writeInt(0xcafebabe); out2.flush(); out2.writeUTF("Max & Möritz"); out2.flush(); out2.writeChar('ɛ'); out2.flush(); out2.writeObject(new Serialize()); out2.close(); byte[] array = out.toByteArray(); expectEqual(array, new int[] { // magic 0xac, 0xed, // version 0x00, 0x05, // blockdata, length 0x77, 0x1, // true 1, // blockdata, length 0x77, 0x1, // (byte)17 17, // blockdata, length 0x77, 0x4, // 0xcafebabe 0xca, 0xfe, 0xba, 0xbe, // blockdata, length 0x77, 0xf, // "Max & Möritz" 0x0, 0xd, 'M', 'a', 'x', ' ', '&', ' ', 'M', 0xc3, 0xb6, 'r', 'i', 't', 'z', // blockdata, length 0x77, 0x2, // 'ö' 0x02, 0x5b, // object 0x73, // class desc, "Serialize" 0x72, 0, 9, 'S', 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'e', // serialVersionUID 0, 0, 0, 0, 0, 0, 0, 1, // flags (SC_SERIALIZABLE) 2, // field count 0x0, 0x1, // int dummy 'I', 0x0, 0x5, 'd', 'u', 'm', 'm', 'y', // class annotation 0x78, // super class desc 0x70, // classdata[] 0x12, 0x34, 0x56, 0x78 }); ByteArrayInputStream in = new ByteArrayInputStream(array); ObjectInputStream in2 = new ObjectInputStream(in); expectEqual(true, in2.readBoolean()); expectEqual(17, in2.readByte()); expectEqual(0xcafebabe, in2.readInt()); expectEqual("Max & Möritz", in2.readUTF()); expectEqual('ɛ', in2.readChar()); Serialize unserialized = (Serialize) in2.readObject(); expectEqual(0x12345678, unserialized.dummy); in2.close(); out.reset(); out2 = new ObjectOutputStream(out); MyMap map = new MyMap(); map.put("key", "value"); out2.writeObject(map); out2.close(); array = out.toByteArray(); expectEqual(array, new int[] { // magic 0xac, 0xed, // version 0x00, 0x05, // object 0x73, // class desc "Serialize$MyMap" 0x72, 0, 15, 'S', 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'e', '$', 'M', 'y', 'M', 'a', 'p', // serial version UID: 0x0cc1f64e2d266ae6 0x0c, 0xc1, 0xf6, 0x3e, 0x2d, 0x25, 0x6a, 0xe6, // flags: SC_SERIALIZABLE | SC_WRITE_METHOD 0x03, // no (non-transient) fields 0, 0, // class annotation 0x78, // super class desc 0x70, // custom TreeMap data written by TreeMap#writeObject 0x77, 4, 0x00 , 0x00, 0x00, 0x01, // (int)1 (== map.size()) 0x74, 0, 3, 'k', 'e', 'y', // "key" 0x74, 0, 5, 'v', 'a', 'l', 'u', 'e', // "value" // end block data 0x78 }); in = new ByteArrayInputStream(array); in2 = new ObjectInputStream(in); map = (MyMap)in2.readObject(); in2.close(); expectEqual(1, map.size()); expectEqual("value", (String)map.get("key")); } } ReadyTalk-avian-1e1fff5/test/Simple.java000066400000000000000000000003421231440243200202320ustar00rootroot00000000000000public class Simple { public static int size(long v, int radix) { int size = 0; for (long n = v; n != 0; n /= radix) ++size; return size; } public static void main(String[] args) { size(42, 10); } } ReadyTalk-avian-1e1fff5/test/StackOverflow.java000066400000000000000000000015231231440243200215740ustar00rootroot00000000000000public class StackOverflow { private static int add(int[] numbers, int offset, int length) { if (length == 0) { return 0; } else { return numbers[offset] + add(numbers, offset + 1, length - 1); } } private static int add(int ... numbers) { return add(numbers, 0, numbers.length); } private static int test1() { add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); return test1() + 1; } private static int test2() { return test3() + 1; } private static int test3() { return test2() + 1; } public static void main(String[] args) { try { test1(); throw new RuntimeException(); } catch (StackOverflowError e) { e.printStackTrace(); } try { test2(); throw new RuntimeException(); } catch (StackOverflowError e) { e.printStackTrace(); } } } ReadyTalk-avian-1e1fff5/test/Strings.java000066400000000000000000000144521231440243200204410ustar00rootroot00000000000000public class Strings { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static boolean equal(Object a, Object b) { return a == b || (a != null && a.equals(b)); } private static boolean arraysEqual(byte[] a, byte[] b) { if (a.length != b.length) { return false; } for (int i = 0; i < a.length; ++i) { if (a[i] != b[i]) { return false; } } return true; } private static byte[] append(byte[] a, byte[] b) { byte[] c = new byte[a.length + b.length]; for (int i = 0; i < a.length; ++i) { c[i] = a[i]; } for (int i = 0; i < b.length; ++i) { c[i + a.length] = b[i]; } return c; } private static boolean arraysEqual(Object[] a, Object[] b) { if (a.length != b.length) { return false; } for (int i = 0; i < a.length; ++i) { if (! equal(a[i], b[i])) { return false; } } return true; } private static void testDecode(final boolean prematureEOS) throws Exception { java.io.Reader r = new java.io.InputStreamReader (new java.io.InputStream() { int state = 0; public int read() { throw new UnsupportedOperationException(); } public int read(byte[] b, int offset, int length) { if (length == 0) return 0; switch (state) { case 0: b[offset] = (byte) 0xc2; state = 1; return 1; case 1: b[offset] = (byte) 0xae; state = 2; return 1; case 2: b[offset] = (byte) 0xea; state = 3; return 1; case 3: b[offset] = (byte) 0xba; state = prematureEOS ? 5 : 4; return 1; case 4: b[offset] = (byte) 0xaf; state = 5; return 1; case 5: return -1; default: throw new RuntimeException(); } } }, "UTF-8"); char[] buffer = new char[2]; int offset = 0; while (offset < buffer.length) { int c = r.read(buffer, offset, buffer.length - offset); if (c == -1) break; offset += c; } expect(new String(buffer, 0, offset).equals (prematureEOS ? "\u00ae\ufffd" : "\u00ae\uaeaf")); } public static void testTrivialPattern() throws Exception { expect("?7".matches("\\0777")); expect("\007".matches("\\a")); expect("\\".matches("\\\\")); expect("J".matches("\\x4A")); expect("a".matches("\\x61")); expect("\0078".matches("\\078")); } public static void main(String[] args) throws Exception { expect(new String(new byte[] { 99, 111, 109, 46, 101, 99, 111, 118, 97, 116, 101, 46, 110, 97, 116, 46, 98, 117, 115, 46, 83, 121, 109, 98, 111, 108 }) .equals("com.ecovate.nat.bus.Symbol")); final String months = "Jan\u00aeFeb\u00aeMar\u00ae"; expect(months.split("\u00ae").length == 3); expect(months.replaceAll("\u00ae", ".").equals("Jan.Feb.Mar.")); expect(arraysEqual ("xyz".split("", 0), new String[] { "", "x", "y", "z" })); expect(arraysEqual ("xyz".split("", 1), new String[] { "xyz" })); expect(arraysEqual ("xyz".split("", 2), new String[] { "", "xyz" })); expect(arraysEqual ("xyz".split("", 3), new String[] { "", "x", "yz" })); expect(arraysEqual ("xyz".split("", 4), new String[] { "", "x", "y", "z" })); expect(arraysEqual ("xyz".split("", 5), new String[] { "", "x", "y", "z", "" })); expect(arraysEqual ("xyz".split("", 6), new String[] { "", "x", "y", "z", "" })); expect(arraysEqual ("xyz".split("", -1), new String[] { "", "x", "y", "z", "" })); expect(arraysEqual("".split("xyz", 0), new String[] { "" })); expect(arraysEqual("".split("xyz", 1), new String[] { "" })); expect(arraysEqual("".split("xyz", -1), new String[] { "" })); expect(arraysEqual("".split("", 0), new String[] { "" })); expect(arraysEqual("".split("", 1), new String[] { "" })); expect(arraysEqual("".split("", -1), new String[] { "" })); expect("foo_foofoo__foo".replaceAll("_", "__") .equals("foo__foofoo____foo")); expect("foo_foofoo__foo".replaceFirst("_", "__") .equals("foo__foofoo__foo")); expect("stereomime".matches("stereomime")); expect(! "stereomime".matches("stereomim")); expect(! "stereomime".matches("tereomime")); expect(! "stereomime".matches("sterEomime")); StringBuilder sb = new StringBuilder(); sb.append('$'); sb.append('2'); expect(sb.substring(1).equals("2")); expect(Character.forDigit(Character.digit('0', 10), 10) == '0'); expect(Character.forDigit(Character.digit('9', 10), 10) == '9'); expect(Character.forDigit(Character.digit('b', 16), 16) == 'b'); expect(Character.forDigit(Character.digit('f', 16), 16) == 'f'); expect(Character.forDigit(Character.digit('z', 36), 36) == 'z'); testDecode(false); testDecode(true); expect (java.text.MessageFormat.format ("{0} enjoy {1} {2}. do {4}? {4} do?", "I", "grape", "nuts", "foobar", new Object() { public String toString() { return "you"; } }) .equals("I enjoy grape nuts. do you? you do?")); { java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream(); java.io.PrintStream pout = new java.io.PrintStream(bout); String s = "I ♥ grape nuts"; System.out.println(s); pout.println(s); expect (arraysEqual (bout.toByteArray(), (s + System.getProperty("line.separator")).getBytes())); // note that this effectively asserts that the VM's default // charset is UTF-8. If we want to make this test more // portable, we should specify the charset explicitly. expect (arraysEqual (bout.toByteArray(), append (new byte[] { 73, 32, -30, -103, -91, 32, 103, 114, 97, 112, 101, 32, 110, 117, 116, 115 }, System.getProperty("line.separator").getBytes()))); } expect("abc".lastIndexOf('b', 100) == 1); testTrivialPattern(); } } ReadyTalk-avian-1e1fff5/test/Subroutine.java000066400000000000000000000171471231440243200211530ustar00rootroot00000000000000import avian.Stream; import avian.ConstantPool; import avian.ConstantPool.PoolEntry; import avian.Assembler; import avian.Assembler.MethodData; import java.util.ArrayList; import java.util.List; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.io.IOException; public class Subroutine { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static void stackMap(Object x) { while (true) { try { try { System.gc(); } catch (DummyException e) { // ignore } finally { x.toString(); } break; } catch (DummyException e) { // ignore } } } private static byte[] makeTestCode(List pool) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); Stream.write2(out, 1); // max stack Stream.write2(out, 1); // max locals Stream.write4(out, 0); // length (we'll set the real value later) // 0: Stream.write1(out, Assembler.ldc_w); Stream.write2(out, ConstantPool.addString(pool, "foo") + 1); // 3: Stream.write1(out, Assembler.astore_0); // 4: Stream.write1(out, Assembler.invokestatic); Stream.write2(out, ConstantPool.addMethodRef (pool, "java/lang/System", "gc", "()V") + 1); // 7: Stream.write1(out, Assembler.goto_); Stream.write2(out, 9); // 16 // 10: Stream.write1(out, Assembler.astore_0); // 11: Stream.write1(out, Assembler.invokestatic); Stream.write2(out, ConstantPool.addMethodRef (pool, "java/lang/System", "gc", "()V") + 1); // 14: Stream.write1(out, Assembler.ret); Stream.write1(out, 0); // 16: Stream.write1(out, Assembler.jsr); Stream.write2(out, -6); // 10 // 19: Stream.write1(out, Assembler.invokestatic); Stream.write2(out, ConstantPool.addMethodRef (pool, "java/lang/System", "gc", "()V") + 1); // 22: Stream.write1(out, Assembler.return_); Stream.write2(out, 0); // exception handler table length Stream.write2(out, 0); // attribute count byte[] result = out.toByteArray(); Stream.set4(result, 4, result.length - 12); return result; } private static Class makeTestClass() throws IOException { List pool = new ArrayList(); ByteArrayOutputStream out = new ByteArrayOutputStream(); String name = "$SubroutineTest$"; Assembler.writeClass (out, pool, ConstantPool.addClass(pool, name), ConstantPool.addClass(pool, "java/lang/Object"), new int[0], new MethodData[] { new MethodData(Assembler.ACC_STATIC | Assembler.ACC_PUBLIC, ConstantPool.addUtf8(pool, "test"), ConstantPool.addUtf8(pool, "()V"), makeTestCode(pool)) }); return new MyClassLoader(Subroutine.class.getClassLoader()) .defineClass(name, out.toByteArray()); } // These tests are intended to cover the jsr and ret instructions. // However, recent Sun javac versions avoid generating these // instructions by default, so we must compile this class using // -source 1.2 -target 1.1 -XDjsrlimit=0. // // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4381996 // private static void test(boolean throw_, boolean predicate) { int x = 42; int y = 99; int a = 0; try { try { int z = x + y; if (throw_) throw new DummyException(); if (predicate) { return; } Integer.valueOf(z).toString(); } finally { a = x + y; System.gc(); } expect(a == x + y); } catch (DummyException e) { e.printStackTrace(); } } private static Object test2(int path) { try { try { switch (path) { case 1: return new Object(); case 2: { int a = 42; return Integer.valueOf(a); } case 3: throw new DummyException(); } } finally { System.gc(); } return null; } catch (DummyException e) { e.printStackTrace(); return null; } } private static Object test3(int path1, int path2, int path3) { try { try { switch (path1) { case 1: return new Object(); case 2: { int a = 42; return Integer.valueOf(a); } case 3: throw new DummyException(); } } finally { try { switch (path2) { case 1: return new Object(); case 2: { int a = 42; return Integer.valueOf(a); } case 3: throw new DummyException(); } } finally { try { switch (path3) { case 1: return new Object(); case 2: { int a = 42; return Integer.valueOf(a); } case 3: throw new DummyException(); } } finally { System.gc(); } } } return null; } catch (DummyException e) { e.printStackTrace(); return null; } } private static long test4(int path) { try { try { switch (path) { case 1: return 0xFABFABFABFL; case 2: { int a = 42; return 52L; } case 3: throw new DummyException(); } } finally { System.gc(); } return 0L; } catch (DummyException e) { e.printStackTrace(); return 0L; } } private boolean test5(boolean predicate) { try { if (predicate) { return false; } } finally { synchronized (this) { notifyAll(); } } return true; } public static void main(String[] args) throws Exception { test(false, false); test(false, true); test(true, false); String.valueOf(test2(1)); String.valueOf(test2(2)); String.valueOf(test2(3)); String.valueOf(test3(1, 1, 1)); String.valueOf(test3(2, 1, 1)); String.valueOf(test3(3, 1, 1)); String.valueOf(test3(1, 2, 1)); String.valueOf(test3(2, 2, 1)); String.valueOf(test3(3, 2, 1)); String.valueOf(test3(1, 3, 1)); String.valueOf(test3(2, 3, 1)); String.valueOf(test3(3, 3, 1)); String.valueOf(test3(1, 1, 2)); String.valueOf(test3(2, 1, 2)); String.valueOf(test3(3, 1, 2)); String.valueOf(test3(1, 2, 2)); String.valueOf(test3(2, 2, 2)); String.valueOf(test3(3, 2, 2)); String.valueOf(test3(1, 3, 2)); String.valueOf(test3(2, 3, 2)); String.valueOf(test3(3, 3, 2)); String.valueOf(test3(1, 1, 3)); String.valueOf(test3(2, 1, 3)); String.valueOf(test3(3, 1, 3)); String.valueOf(test3(1, 2, 3)); String.valueOf(test3(2, 2, 3)); String.valueOf(test3(3, 2, 3)); String.valueOf(test3(1, 3, 3)); String.valueOf(test3(2, 3, 3)); String.valueOf(test3(3, 3, 3)); String.valueOf(test4(1)); String.valueOf(test4(2)); String.valueOf(test4(3)); expect(test4(1) == 0xFABFABFABFL); new Subroutine().test5(true); new Subroutine().test5(false); makeTestClass().getMethod("test", new Class[0]).invoke (null, new Object[0]); stackMap(new Object()); } private static class DummyException extends RuntimeException { } private static class MyClassLoader extends ClassLoader { public MyClassLoader(ClassLoader parent) { super(parent); } public Class defineClass(String name, byte[] bytes) { return super.defineClass(name, bytes, 0, bytes.length); } } } ReadyTalk-avian-1e1fff5/test/Switch.java000066400000000000000000000022261231440243200202450ustar00rootroot00000000000000public class Switch { private static int table(int k) { switch (k) { case 0: return 0; case 1: return 1; case 2: return 2; case 9: return 9; case 10: return 10; case 11: return 11; case 12: return 8; case -5: return 5; default: return 7; } } private static int lookup(int k) { switch (k) { case 0: return 0; case 45: return 45; case 46: return 46; case 47: return -47; case 200: return 200; case 244: return 244; case 245: return 245; default: return 91; } } private static void expect(boolean v) { if (! v) throw new RuntimeException(); } public static void main(String[] args) { expect(table(0) == 0); expect(table(9) == 9); expect(table(10) == 10); expect(table(11) == 11); expect(table(12) == 8); expect(table(-5) == 5); expect(table(-13) == 7); expect(lookup(0) == 0); expect(lookup(45) == 45); expect(lookup(46) == 46); expect(lookup(47) == -47); expect(lookup(245) == 245); expect(lookup(246) == 91); } } ReadyTalk-avian-1e1fff5/test/Threads.java000066400000000000000000000034141231440243200203760ustar00rootroot00000000000000public class Threads implements Runnable { public static void main(String[] args) throws Exception { { Threads test = new Threads(); Thread thread = new Thread(test); synchronized (test) { thread.start(); test.wait(); } } { Thread thread = new Thread() { public void run() { while (true) { System.out.print("."); try { sleep(1000); } catch (Exception e) { System.out.println("thread interrupted? " + interrupted()); break; } } } }; thread.start(); System.out.println("\nAbout to interrupt..."); thread.interrupt(); System.out.println("\nInterrupted!"); } { Thread thread = new Thread() { @Override public void run() { // do nothing } }; thread.start(); thread.join(); } System.out.println("finished"); } public void run() { synchronized (this) { int i = 0; try { System.out.println("I'm running in a separate thread!"); final int arrayCount = 16; final int arraySize = 4; System.out.println("Allocating and discarding " + arrayCount + " arrays of " + arraySize + "MB each"); for (; i < arrayCount; ++i) { byte[] array = new byte[arraySize * 1024 * 1024]; } long nap = 5; System.out.println("sleeping for " + nap + " seconds"); Thread.sleep(nap * 1000); } catch (Throwable e) { System.err.println("caught something in second thread after " + i + " iterations"); e.printStackTrace(); } finally { notifyAll(); } } } } ReadyTalk-avian-1e1fff5/test/TimeUnitConversions.java000066400000000000000000000127271231440243200230020ustar00rootroot00000000000000import java.util.concurrent.TimeUnit; public class TimeUnitConversions { private static void expect(long v1, long v2) { if (v1 != v2) { throw new RuntimeException(v1 + " != " + v2); } } private static void toNanoConversionTest() { long expectedValue = 1; expect(TimeUnit.NANOSECONDS.convert(1, TimeUnit.NANOSECONDS), expectedValue); expectedValue *= 1000; expect(TimeUnit.NANOSECONDS.convert(1, TimeUnit.MICROSECONDS), expectedValue); expectedValue *= 1000; expect(TimeUnit.NANOSECONDS.convert(1, TimeUnit.MILLISECONDS), expectedValue); expectedValue *= 1000; expect(TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS), expectedValue); expectedValue *= 60; expect(TimeUnit.NANOSECONDS.convert(1, TimeUnit.MINUTES), expectedValue); expectedValue *= 60; expect(TimeUnit.NANOSECONDS.convert(1, TimeUnit.HOURS), expectedValue); expectedValue *= 24; expect(TimeUnit.NANOSECONDS.convert(1, TimeUnit.DAYS), expectedValue); } private static void toMicroConversionTest() { long expectedValue = 1; expect(TimeUnit.MICROSECONDS.convert(1000, TimeUnit.NANOSECONDS), expectedValue); expect(TimeUnit.MICROSECONDS.convert(1, TimeUnit.MICROSECONDS), expectedValue); expectedValue *= 1000; expect(TimeUnit.MICROSECONDS.convert(1, TimeUnit.MILLISECONDS), expectedValue); expectedValue *= 1000; expect(TimeUnit.MICROSECONDS.convert(1, TimeUnit.SECONDS), expectedValue); expectedValue *= 60; expect(TimeUnit.MICROSECONDS.convert(1, TimeUnit.MINUTES), expectedValue); expectedValue *= 60; expect(TimeUnit.MICROSECONDS.convert(1, TimeUnit.HOURS), expectedValue); expectedValue *= 24; expect(TimeUnit.MICROSECONDS.convert(1, TimeUnit.DAYS), expectedValue); } private static void toMilliConversionTest() { long expectedValue = 1; expect(TimeUnit.MILLISECONDS.convert(1000L * 1000, TimeUnit.NANOSECONDS), expectedValue); expect(TimeUnit.MILLISECONDS.convert(1000, TimeUnit.MICROSECONDS), expectedValue); expect(TimeUnit.MILLISECONDS.convert(1, TimeUnit.MILLISECONDS), expectedValue); expectedValue *= 1000; expect(TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS), expectedValue); expectedValue *= 60; expect(TimeUnit.MILLISECONDS.convert(1, TimeUnit.MINUTES), expectedValue); expectedValue *= 60; expect(TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS), expectedValue); expectedValue *= 24; expect(TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS), expectedValue); } private static void toSecondConversionTest() { long expectedValue = 1; expect(TimeUnit.SECONDS.convert(1000L * 1000 * 1000, TimeUnit.NANOSECONDS), expectedValue); expect(TimeUnit.SECONDS.convert(1000L * 1000, TimeUnit.MICROSECONDS), expectedValue); expect(TimeUnit.SECONDS.convert(1000, TimeUnit.MILLISECONDS), expectedValue); expect(TimeUnit.SECONDS.convert(1, TimeUnit.SECONDS), expectedValue); expectedValue *= 60; expect(TimeUnit.SECONDS.convert(1, TimeUnit.MINUTES), expectedValue); expectedValue *= 60; expect(TimeUnit.SECONDS.convert(1, TimeUnit.HOURS), expectedValue); expectedValue *= 24; expect(TimeUnit.SECONDS.convert(1, TimeUnit.DAYS), expectedValue); } private static void toMinuteConversionTest() { long expectedValue = 1; expect(TimeUnit.MINUTES.convert(1000L * 1000 * 1000 * 60, TimeUnit.NANOSECONDS), expectedValue); expect(TimeUnit.MINUTES.convert(1000L * 1000 * 60, TimeUnit.MICROSECONDS), expectedValue); expect(TimeUnit.MINUTES.convert(1000L * 60, TimeUnit.MILLISECONDS), expectedValue); expect(TimeUnit.MINUTES.convert(60, TimeUnit.SECONDS), expectedValue); expect(TimeUnit.MINUTES.convert(1, TimeUnit.MINUTES), expectedValue); expectedValue *= 60; expect(TimeUnit.MINUTES.convert(1, TimeUnit.HOURS), expectedValue); expectedValue *= 24; expect(TimeUnit.MINUTES.convert(1, TimeUnit.DAYS), expectedValue); } private static void toHourConversionTest() { long expectedValue = 1; expect(TimeUnit.HOURS.convert(1000L * 1000 * 1000 * 60 * 60, TimeUnit.NANOSECONDS), expectedValue); expect(TimeUnit.HOURS.convert(1000L * 1000 * 60 * 60, TimeUnit.MICROSECONDS), expectedValue); expect(TimeUnit.HOURS.convert(1000L * 60 * 60, TimeUnit.MILLISECONDS), expectedValue); expect(TimeUnit.HOURS.convert(60L * 60, TimeUnit.SECONDS), expectedValue); expect(TimeUnit.HOURS.convert(60, TimeUnit.MINUTES), expectedValue); expect(TimeUnit.HOURS.convert(1, TimeUnit.HOURS), expectedValue); expectedValue *= 24; expect(TimeUnit.HOURS.convert(1, TimeUnit.DAYS), expectedValue); } private static void toDayConversionTest() { long expectedValue = 1; expect(TimeUnit.DAYS.convert(1000L * 1000 * 1000 * 60 * 60 * 24, TimeUnit.NANOSECONDS), expectedValue); expect(TimeUnit.DAYS.convert(1000L * 1000 * 60 * 60 * 24, TimeUnit.MICROSECONDS), expectedValue); expect(TimeUnit.DAYS.convert(1000L * 60 * 60 * 24, TimeUnit.MILLISECONDS), expectedValue); expect(TimeUnit.DAYS.convert(60L * 60 * 24, TimeUnit.SECONDS), expectedValue); expect(TimeUnit.DAYS.convert(60L * 24, TimeUnit.MINUTES), expectedValue); expect(TimeUnit.DAYS.convert(24, TimeUnit.HOURS), expectedValue); expect(TimeUnit.DAYS.convert(1, TimeUnit.DAYS), expectedValue); } public static void main(String[] args) { toNanoConversionTest(); toMicroConversionTest(); toMilliConversionTest(); toSecondConversionTest(); toMinuteConversionTest(); toHourConversionTest(); toDayConversionTest(); } } ReadyTalk-avian-1e1fff5/test/Trace.java000066400000000000000000000037611231440243200200470ustar00rootroot00000000000000public class Trace implements Runnable { private volatile boolean alive = true; private static void throwSomething() { throw new RuntimeException(); } private void bar(Object o) { o.toString(); } private void foo() { { long a = 42; long b = 25; long c = a / b; } try { long a = 42; long b = 0; long c = a / b; } catch (Exception e) { } try { throw new Exception(); } catch (Exception e) { } try { throwSomething(); } catch (Exception e) { } try { Trace.class.getMethod("bar", Object.class).invoke(this, this); } catch (Exception e) { } } private static void dummy() { byte[] a = new byte[10]; byte[] b = new byte[10]; System.arraycopy(a, 0, b, 0, 10); } private static void tail1(int a, int b, int c, int d, int e, int f) { dummy(); } private static void tail2() { tail1(1, 2, 3, 4, 5, 6); tail1(1, 2, 3, 4, 5, 6); } private static void test(Trace trace) { tail1(1, 2, 3, 4, 5, 6); tail2(); trace.foo(); } public void run() { synchronized (this) { notifyAll(); } try { for (int i = 0; i < 10000; ++i) { test(this); if (i % 100 == 0) { System.out.print("r"); System.out.flush(); synchronized (this) { notifyAll(); } } } } finally { synchronized (this) { alive = false; notifyAll(); } } } public static void main(String[] args) throws Exception { Trace trace = new Trace(); Thread thread = new Thread(trace); synchronized (trace) { thread.start(); trace.wait(); int count = 0; while (trace.alive) { thread.getStackTrace(); ++ count; if (count % 100 == 0) { trace.wait(); System.out.print("t"); System.out.flush(); } } System.out.println("\ngot " + count + " traces"); } } } ReadyTalk-avian-1e1fff5/test/Tree.java000066400000000000000000000067641231440243200177160ustar00rootroot00000000000000import java.util.Comparator; import java.util.TreeSet; import java.util.TreeMap; import java.util.ArrayList; import java.util.Collection; import java.util.Map; import java.util.Iterator; public class Tree { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static String printList(TreeSet list) { StringBuilder sb = new StringBuilder(); for (Object o : list) { sb.append(o); sb.append(", "); } sb.setLength(sb.length()-2); return sb.toString(); } private static String printMap(TreeMap map) { StringBuilder sb = new StringBuilder(); for (Iterator it = map.entrySet().iterator(); it.hasNext();) { Map.Entry e = it.next(); sb.append(e.getKey()); sb.append("="); sb.append(e.getValue()); if (it.hasNext()) { sb.append(", "); } } return sb.toString(); } private static void isEqual(String s1, String s2) { System.out.println(s1); expect(s1.equals(s2)); } private static class MyCompare implements Comparator { public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } } private static void ascendingIterator() { TreeSet t = new TreeSet(); t.add(7); t.add(2); t.add(9); t.add(2); Iterator iter = t.iterator(); expect(2 == (int)iter.next()); expect(7 == (int)iter.next()); iter.remove(); expect(9 == (int)iter.next()); expect(!iter.hasNext()); isEqual(printList(t), "2, 9"); } private static void descendingIterator() { TreeSet t = new TreeSet(); t.add(7); t.add(2); t.add(9); t.add(2); Iterator iter = t.descendingIterator(); expect(9 == (int)iter.next()); expect(7 == (int)iter.next()); iter.remove(); expect(2 == (int)iter.next()); expect(!iter.hasNext()); isEqual(printList(t), "2, 9"); } public static void main(String args[]) { ascendingIterator(); descendingIterator(); TreeSet t1 = new TreeSet(new MyCompare()); t1.add(5); t1.add(2); t1.add(1); t1.add(8); t1.add(3); isEqual(printList(t1), "1, 2, 3, 5, 8"); t1.add(4); isEqual(printList(t1), "1, 2, 3, 4, 5, 8"); t1.remove(3); isEqual(printList(t1), "1, 2, 4, 5, 8"); TreeSet t2 = new TreeSet(new Comparator() { public int compare(String s1, String s2) { return s1.compareTo(s2); } }); t2.add("one"); t2.add("two"); t2.add("three"); t2.add("four"); t2.add("five"); isEqual(printList(t2), "five, four, one, three, two"); for (int i=0; i < 1000; i++) { t2.add(Integer.toString(i)); } expect(t2.size() == 1005); for (int i=0; i < 999; i++) { t2.remove(Integer.toString(i)); } expect(t2.size() == 6); t2.add("kappa"); isEqual(printList(t2), "999, five, four, kappa, one, three, two"); TreeMap map = new TreeMap (new Comparator() { public int compare(String s1, String s2) { return s1.compareTo(s2); } }); map.put("q", "Q"); map.put("a", "A"); map.put("b", "B"); map.put("z", "Z"); map.put("c", "C"); map.put("y", "Y"); isEqual(printMap(map), "a=A, b=B, c=C, q=Q, y=Y, z=Z"); Collection list = new ArrayList(); list.add(7); list.add(2); list.add(9); list.add(2); isEqual(printList(new TreeSet(list)), "2, 7, 9"); } } ReadyTalk-avian-1e1fff5/test/UnsafeTest.java000066400000000000000000000044301231440243200210640ustar00rootroot00000000000000import sun.misc.Unsafe; public class UnsafeTest { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static void unsafeThrow(Unsafe u) { u.throwException(new Exception()); } private static void unsafeCatch(Unsafe u) { boolean success = false; try { unsafeThrow(u); } catch(Exception e) { expect(e.getClass() == Exception.class); success = true; } expect(success); } private static void unsafeMemory(Unsafe u) { final long size = 64; long memory = u.allocateMemory(size); try { for (int i = 0; i < size; ++i) u.putByte(memory + i, (byte) 42); for (int i = 0; i < size; ++i) expect(u.getByte(memory + i) == 42); for (int i = 0; i < size / 2; ++i) u.putShort(memory + (i * 2), (short) -12345); for (int i = 0; i < size / 2; ++i) expect(u.getShort(memory + (i * 2)) == -12345); for (int i = 0; i < size / 2; ++i) u.putChar(memory + (i * 2), (char) 23456); for (int i = 0; i < size / 2; ++i) expect(u.getChar(memory + (i * 2)) == 23456); for (int i = 0; i < size / 4; ++i) u.putInt(memory + (i * 4), 0x12345678); for (int i = 0; i < size / 4; ++i) expect(u.getInt(memory + (i * 4)) == 0x12345678); for (int i = 0; i < size / 4; ++i) u.putFloat(memory + (i * 4), 1.2345678F); for (int i = 0; i < size / 4; ++i) expect(u.getFloat(memory + (i * 4)) == 1.2345678F); for (int i = 0; i < size / 8; ++i) u.putLong(memory + (i * 8), 0x1234567890ABCDEFL); for (int i = 0; i < size / 8; ++i) expect(u.getLong(memory + (i * 8)) == 0x1234567890ABCDEFL); for (int i = 0; i < size / 8; ++i) u.putDouble(memory + (i * 8), 1.23456789012345D); for (int i = 0; i < size / 8; ++i) expect(u.getDouble(memory + (i * 8)) == 1.23456789012345D); for (int i = 0; i < size / 8; ++i) u.putAddress(memory + (i * 8), 0x12345678); for (int i = 0; i < size / 8; ++i) expect(u.getAddress(memory + (i * 8)) == 0x12345678); } finally { u.freeMemory(memory); } } public static void main(String[] args) { Unsafe u = avian.Machine.getUnsafe(); unsafeCatch(u); unsafeMemory(u); } } ReadyTalk-avian-1e1fff5/test/UrlTest.java000066400000000000000000000020061231440243200204020ustar00rootroot00000000000000import java.net.MalformedURLException; import java.net.URL; public class UrlTest { private static String query="var1=val1&var2=val2"; private static String path="/testpath"; private static String domain="file://www.readytalk.com"; private static String file=path + "?" + query; private static URL url; private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static void setupURL() throws MalformedURLException { StringBuilder builder = new StringBuilder(); builder.append(domain); builder.append(file); url = new URL(builder.toString()); } private static void testGetPath() { expect(url.getPath().equals(path)); } private static void testGetFile() { expect(url.getFile().equals(file)); } private static void testGetQuery() { expect(url.getQuery().equals(query)); } public static void main(String[] args) throws MalformedURLException { setupURL(); testGetPath(); testGetFile(); testGetQuery(); } } ReadyTalk-avian-1e1fff5/test/Zip.java000066400000000000000000000025521231440243200175500ustar00rootroot00000000000000import java.io.InputStream; import java.io.File; import java.util.Enumeration; import java.util.zip.ZipFile; import java.util.zip.ZipEntry; public class Zip { private static String findJar(File directory) { for (File file: directory.listFiles()) { if (file.isFile()) { if (file.getName().endsWith(".jar")) { System.out.println ("found " + file.getAbsolutePath() + " length " + file.length()); return file.getAbsolutePath(); } } else if (file.isDirectory()) { String result = findJar(file); if (result != null) { return result; } } } return null; } public static void main(String[] args) throws Exception { ZipFile file = new ZipFile (findJar(new File(System.getProperty("user.dir")))); try { byte[] buffer = new byte[4096]; for (Enumeration e = file.entries(); e.hasMoreElements();) { ZipEntry entry = e.nextElement(); InputStream in = file.getInputStream(entry); try { int size = 0; int c; while ((c = in.read(buffer)) != -1) size += c; System.out.println (entry.getName() + " " + entry.getCompressedSize() + " " + size); } finally { in.close(); } } } finally { file.close(); } } } ReadyTalk-avian-1e1fff5/test/ZipOutputStreamTest.java000066400000000000000000000124451231440243200230070ustar00rootroot00000000000000import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.*; public class ZipOutputStreamTest { private static final String TEST1 = "test1.txt"; private static final String TEST2 = "test2.txt"; private static final String TEST3 = "test3.txt"; private static final String TEST4 = "test4.txt"; private static final String TEST1_CONTENTS = "\"this is a test\""; private static final String TEST2_CONTENTS = "this is a\nmulti-line test"; private static final String TEST3_CONTENTS = "74 68 69 73 20 69 73 20 61 20 74 65 73 74"; private static final String TEST4_CONTENTS = "01110100 01101000 01101001 01110011 00100000 01101001 01110011 00100000 01100001 00100000 01110100 01100101 01110011 01110100"; private static final String ONE_PARAM_ZIP_PREFIX = "zos1param"; private static final String THREE_PARAM_ZIP_PREFIX = "zos3param"; private static final String ZIP_SUFFIX = ".zip"; private static final Map FILES_CONTENTS; static { Map m = new HashMap(); m.put(TEST1, TEST1_CONTENTS); m.put(TEST2, TEST2_CONTENTS); m.put(TEST3, TEST3_CONTENTS); m.put(TEST4, TEST4_CONTENTS); FILES_CONTENTS = Collections.unmodifiableMap(m); } private static final boolean USE_ONE_PARAM_WRITE = true; private static final boolean USE_THREE_PARAM_WRITE = false; private static byte[] buffer = new byte[1024]; public static void main(String[] args) { List zipFiles = new ArrayList(2); // Test 1-param write function File f1 = createZip(USE_ONE_PARAM_WRITE); zipFiles.add(f1); verifyContents(f1.getAbsolutePath()); // Test 3-param write function File f2 = createZip(USE_THREE_PARAM_WRITE); zipFiles.add(f2); verifyContents(f2.getAbsolutePath()); // Remove the created zip files cleanUp(zipFiles); } private static File createZip(boolean useOneParam) { FileOutputStream outputStream = null; ZipOutputStream zipContents = null; try { // Create a temporary zip file for this test String prefix = useOneParam ? ONE_PARAM_ZIP_PREFIX : THREE_PARAM_ZIP_PREFIX; File outputZip = File.createTempFile(prefix, ZIP_SUFFIX); System.out.println("Created " + outputZip.getAbsolutePath()); // Prepare the streams outputStream = new FileOutputStream(outputZip); zipContents = new ZipOutputStream(outputStream); // Zip the file contents (convert directly from string to bytes) long startTime = System.currentTimeMillis(); for (Map.Entry f : FILES_CONTENTS.entrySet()) { String name = f.getKey(); String contents = f.getValue(); System.out.println("Zipping " + name + "..."); ZipEntry entry = new ZipEntry(name); zipContents.putNextEntry(entry); byte[] bytesToWrite = contents.getBytes(); if (useOneParam) { // Use the 1-parameter write method; takes a single byte for (int i = 0; i < bytesToWrite.length; i++) { zipContents.write(bytesToWrite[i]); } } else { // Use 3-parameter write method; takes a buffer, offset, and length zipContents.write(bytesToWrite, 0 , bytesToWrite.length); } // Done with this file zipContents.closeEntry(); System.out.println("Done"); } // All files have been written long endTime = System.currentTimeMillis(); System.out.println("Finished " + outputZip.getName() + " in " + ((endTime - startTime) / 1000.0) + " seconds"); return outputZip; } catch (Exception e) { throw new RuntimeException(e); } finally { try { if (zipContents != null) zipContents.close(); if (outputStream != null) outputStream.close(); } catch (Exception e) { throw new RuntimeException(e); } } } private static void verifyContents(String zipName) { System.out.println("Verify " + zipName); ZipFile zf = null; BufferedReader reader = null; int numFilesInZip = 0; try { String line; String contents; // Get the contents of each file in the zip zf = new ZipFile(zipName); for (Enumeration e = zf.entries(); e.hasMoreElements();) { ZipEntry entry = e.nextElement(); reader = new BufferedReader(new InputStreamReader(zf.getInputStream(entry))); contents = ""; numFilesInZip += 1; while ((line = reader.readLine()) != null) { if (contents.length() > 0) { contents += "\n"; } contents += line; } reader.close(); // Assert that this file's contents are correct assert(contents.equals(FILES_CONTENTS.get(entry.getName()))); } zf.close(); // Assert that the zip contained the correct number of files assert(numFilesInZip == FILES_CONTENTS.size()); } catch (Exception e) { throw new RuntimeException(e); } finally { try { if (zf != null) zf.close(); if (reader != null) reader.close(); } catch (Exception e) { throw new RuntimeException(e); } } } private static void cleanUp(List zipFiles) { try { for (File f : zipFiles) { if (f.exists()) { f.delete(); } } } catch (Exception e) { throw new RuntimeException(e); } } } ReadyTalk-avian-1e1fff5/test/avian/000077500000000000000000000000001231440243200172355ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/test/avian/TestReflection.java000066400000000000000000000002751231440243200230360ustar00rootroot00000000000000package avian; import java.lang.reflect.Field; public class TestReflection { public static Object get(Field field, Object target) throws Exception { return field.get(target); } } ReadyTalk-avian-1e1fff5/test/avian/testing/000077500000000000000000000000001231440243200207125ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/test/avian/testing/annotations/000077500000000000000000000000001231440243200232475ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/test/avian/testing/annotations/Color.java000066400000000000000000000001151231440243200251650ustar00rootroot00000000000000package avian.testing.annotations; public enum Color { Red, Yellow, Blue }ReadyTalk-avian-1e1fff5/test/avian/testing/annotations/Test.java000066400000000000000000000003511231440243200250300ustar00rootroot00000000000000package avian.testing.annotations; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface Test { public String value() default "Hello, world!"; } ReadyTalk-avian-1e1fff5/test/avian/testing/annotations/TestComplex.java000066400000000000000000000005241231440243200263620ustar00rootroot00000000000000package avian.testing.annotations; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface TestComplex { public Test[] arrayValue(); public Class classValue(); public String stringValue(); public char charValue(); public double doubleValue(); } ReadyTalk-avian-1e1fff5/test/avian/testing/annotations/TestEnum.java000066400000000000000000000003221231440243200256530ustar00rootroot00000000000000package avian.testing.annotations; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface TestEnum { public Color value(); }ReadyTalk-avian-1e1fff5/test/avian/testing/annotations/TestInteger.java000066400000000000000000000003231231440243200263450ustar00rootroot00000000000000package avian.testing.annotations; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface TestInteger { public int value(); }ReadyTalk-avian-1e1fff5/test/ci.sh000077500000000000000000000005261231440243200170740ustar00rootroot00000000000000#!/bin/sh set -e make ${flags} jdk-test make ${flags} test make ${flags} mode=debug test make ${flags} process=interpret test # bootimage and openjdk builds without openjdk-src don't work: if [ -z "${openjdk}" ]; then make ${flags} bootimage=true test fi make ${flags} tails=true continuations=true test make ${flags} codegen-targets=all ReadyTalk-avian-1e1fff5/test/extra/000077500000000000000000000000001231440243200172625ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/test/extra/ComposableContinuations.java000066400000000000000000000057501231440243200247760ustar00rootroot00000000000000package extra; import static avian.Continuations.shift; import static avian.Cell.cons; import static avian.Cell.equal; import avian.Cell; import avian.Function; import avian.Continuations; import java.util.concurrent.Callable; public class ComposableContinuations { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } public static void main(String[] args) throws Exception { expect(2 * Continuations.reset(new Callable() { public Integer call() throws Exception { return 1 + shift (new Function,Integer>() { public Integer call(Function continuation) throws Exception { return continuation.call(5); } }); } }) == 12); expect(1 + Continuations.reset(new Callable() { public Integer call() throws Exception { return 2 * shift (new Function,Integer>() { public Integer call(Function continuation) throws Exception { return continuation.call(continuation.call(4)); } }); } }) == 17); expect (equal (Continuations.,Cell>reset (new Callable>() { public Cell call() throws Exception { shift(new Function,Cell>, Cell>() { public Cell call (Function,Cell> continuation) throws Exception { return cons(1, continuation.call(null)); } }); shift(new Function,Cell>, Cell>() { public Cell call (Function,Cell> continuation) throws Exception { return cons(2, continuation.call(null)); } }); return null; } }), cons(1, cons(2, null)))); expect (equal (Continuations.reset (new Callable() { public String call() throws Exception { return new String (shift(new Function,Integer>() { public Integer call(Function continuation) throws Exception { return Integer.parseInt (continuation.call(new byte[] { 0x34, 0x32 })); } }), "UTF-8"); } }), 42)); } } ReadyTalk-avian-1e1fff5/test/extra/Continuations.java000066400000000000000000000030631231440243200227640ustar00rootroot00000000000000package extra; import static avian.Continuations.callWithCurrentContinuation; import avian.Function; import avian.Callback; public class Continuations { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } public static void main(String[] args) throws Exception { expect (callWithCurrentContinuation (new Function,Integer>() { public Integer call(Callback continuation) { continuation.handleResult(42); throw new AssertionError(); } }) == 42); expect (callWithCurrentContinuation (new Function,Integer>() { public Integer call(Callback continuation) { return 43; } }) == 43); try { callWithCurrentContinuation(new Function,Integer>() { public Integer call(Callback continuation) { continuation.handleException(new MyException()); throw new AssertionError(); } }); throw new AssertionError(); } catch (MyException e) { e.printStackTrace(); } try { callWithCurrentContinuation(new Function,Integer>() { public Integer call(Callback continuation) throws MyException { throw new MyException(); } }); throw new AssertionError(); } catch (MyException e) { e.printStackTrace(); } } private static class MyException extends Exception { } } ReadyTalk-avian-1e1fff5/test/extra/Coroutines.java000066400000000000000000000047201231440243200222620ustar00rootroot00000000000000package extra; import static avian.Continuations.callWithCurrentContinuation; import avian.Function; import avian.Callback; public class Coroutines { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static void produce(Consumer consumer) throws Exception { System.out.println("produce \"a\""); consumer.consume('a'); System.out.println("produce \"b\""); consumer.consume('b'); System.out.println("produce \"c\""); consumer.consume('c'); } private static void consume(Producer producer) throws Exception { char v = producer.produce(); System.out.println("consume \"" + v + "\""); expect(v == 'a'); v = producer.produce(); System.out.println("consume \"" + v + "\""); expect(v == 'b'); v = producer.produce(); System.out.println("consume \"" + v + "\""); expect(v == 'c'); } public static void main(String[] args) throws Exception { final CoroutineState state = new CoroutineState(); final Consumer consumer = new Consumer() { public void consume(final Character c) throws Exception { callWithCurrentContinuation(new Function,Object>() { public Object call(Callback continuation) { state.produceNext = continuation; state.consumeNext.handleResult(c); throw new AssertionError(); } }); } }; final Producer producer = new Producer() { final Function,Character> receiver = new Function,Character>() { public Character call(Callback continuation) throws Exception { state.consumeNext = continuation; if (state.produceNext == null) { Coroutines.produce(consumer); } else { state.produceNext.handleResult(null); } throw new AssertionError(); } }; public Character produce() throws Exception { return callWithCurrentContinuation(receiver); } }; consume(producer); } private static class CoroutineState { public Callback produceNext; public Callback consumeNext; } private interface Producer { public T produce() throws Exception; } private interface Consumer { public void consume(T value) throws Exception; } } ReadyTalk-avian-1e1fff5/test/extra/DumpStats.java000066400000000000000000000075621231440243200220630ustar00rootroot00000000000000package extra; import java.io.PrintStream; import java.io.InputStream; import java.io.FileInputStream; import java.io.BufferedInputStream; import java.io.IOException; import java.io.EOFException; import java.util.Map; import java.util.HashMap; import java.util.Comparator; import java.util.Arrays; /** * This is a simple utility to generate and print statistics from a * heap dump generated by Avian's heapdump.cpp. The output is a list * of classes (identified by number in the case of anonymous, * VM-internal classes), each followed by (1) the total memory * footprint of all instances of the class in machine words, and (2) * the number of instances. The output is ordered by instance memory * footprint. */ public class DumpStats { private static final int Root = 0; private static final int Size = 1; private static final int ClassName = 2; private static final int Push = 3; private static final int Pop = 4; private static int readInt(InputStream in) throws IOException { int b1 = in.read(); int b2 = in.read(); int b3 = in.read(); int b4 = in.read(); if (b4 == -1) throw new EOFException(); return (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); } private static String readString(InputStream in) throws IOException { int count = readInt(in); byte[] b = new byte[count]; int offset = 0; int c; while ((c = in.read(b, offset, b.length - offset)) != -1 && offset < b.length) { offset += c; } if (offset != b.length) throw new EOFException(); return new String(b); } private static Record record(Map map, int key) { Record r = map.get(key); if (r == null) { map.put(key, r = new Record(key)); } return r; } private static Map read(InputStream in) throws IOException { boolean done = false; boolean popped = false; int size = 0; int last = 0; Map map = new HashMap(); while (! done) { int flag = in.read(); switch (flag) { case Root: { last = readInt(in); popped = false; } break; case ClassName: { record(map, last).name = readString(in); } break; case Push: { last = readInt(in); if (! popped) { Record r = record(map, last); r.footprint += size; ++ r.count; } popped = false; } break; case Pop: { popped = true; } break; case Size: { size = readInt(in); } break; case -1: done = true; break; default: throw new RuntimeException("bad flag: " + flag); } } return map; } private static void usageAndExit() { System.err.println("usage: java DumpStats "); } public static void main(String[] args) throws Exception { if (args.length != 2) { usageAndExit(); } Map map = read (new BufferedInputStream(new FileInputStream(args[0]))); Record[] array = map.values().toArray(new Record[map.size()]); Arrays.sort(array, new Comparator() { public int compare(Record a, Record b) { return b.footprint - a.footprint; } }); int wordSize = Integer.parseInt(args[1]); int footprint = 0; int count = 0; for (Record r: array) { if (r.name == null) { r.name = String.valueOf(r.key); } System.out.println (r.name + ": " + (r.footprint * wordSize) + " " + r.count); footprint += r.footprint; count += r.count; } System.out.println(); System.out.println("total: " + (footprint * wordSize) + " " + count); } private static class Record { public final int key; public String name; public int footprint; public int count; public Record(int key) { this.key = key; } } } ReadyTalk-avian-1e1fff5/test/extra/DynamicWind.java000066400000000000000000000217401231440243200223370ustar00rootroot00000000000000package extra; import static avian.Continuations.callWithCurrentContinuation; import static avian.Continuations.dynamicWind; import avian.Function; import avian.Callback; import java.util.concurrent.Callable; public class DynamicWind { private int before; private int task; private int after; private int continuationCount; private Callback continuationReference; private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private void unwindTest(final Callable unwind) throws Exception { System.out.println("unwindTest enter"); try { expect(dynamicWind(new Runnable() { public void run() { System.out.println("unwindTest before"); expect(before == 0); expect(task == 0); expect(after == 0); before = 1; } }, new Callable() { public Integer call() throws Exception { System.out.println("unwindTest thunk"); expect(before == 1); expect(task == 0); expect(after == 0); task = 1; return unwind.call(); } }, new Runnable() { public void run() { System.out.println("unwindTest after"); expect(before == 1); expect(task == 1); expect(after == 0); after = 1; } }) == 42); } catch (MyException e) { e.printStackTrace(); } System.out.println("unwindTest expect"); expect(before == 1); expect(task == 1); expect(after == 1); System.out.println("unwindTest exit"); } private void normalUnwind() throws Exception { unwindTest(new Callable() { public Integer call() { return 42; } }); } private void exceptionUnwind() throws Exception { unwindTest(new Callable() { public Integer call() throws Exception { throw new MyException(); } }); } private void continuationUnwindTest (final Function,Integer> receiver) throws Exception { System.out.println("continuationUnwindTest enter"); try { expect (callWithCurrentContinuation (new Function,Integer>() { public Integer call(final Callback continuation) throws Exception { unwindTest(new Callable() { public Integer call() throws Exception { return receiver.call(continuation); } }); throw new AssertionError(); } }) == 42); } catch (MyException e) { e.printStackTrace(); } System.out.println("continuationUnwindTest expect"); expect(before == 1); expect(task == 1); expect(after == 1); System.out.println("continuationUnwindTest exit"); } private void continuationResultUnwind() throws Exception { continuationUnwindTest(new Function,Integer>() { public Integer call(final Callback continuation) { continuation.handleResult(42); throw new AssertionError(); } }); } private void continuationExceptionUnwind() throws Exception { continuationUnwindTest(new Function,Integer>() { public Integer call(final Callback continuation) { continuation.handleException(new MyException()); throw new AssertionError(); } }); } private void rewindTest(final Callable unwind, Runnable rewind) throws Exception { System.out.println("rewindTest enter"); int value; try { value = dynamicWind(new Runnable() { public void run() { System.out.println("rewindTest before"); expect(before == continuationCount); expect(task == continuationCount); expect(after == continuationCount); ++ before; } }, new Callable() { public Integer call() throws Exception { System.out.println("rewindTest thunk"); expect(before == 1); expect(task == 0); expect(after == 0); task = 1; return callWithCurrentContinuation (new Function,Integer>() { public Integer call(final Callback continuation) throws Exception { continuationReference = continuation; return unwind.call(); } }); } }, new Runnable() { public void run() { System.out.println("rewindTest after"); expect(before == continuationCount + 1); expect(task == 1); expect(after == continuationCount); ++ after; } }); } catch (MyException e) { value = e.value; } System.out.println("rewindTest expect"); expect(value == continuationCount); if (value == 0) { System.out.println("rewindTest expect 0"); expect(before == 1); expect(task == 1); expect(after == 1); continuationCount = 1; rewind.run(); throw new AssertionError(); } else { System.out.println("rewindTest expect 1"); expect(value == 1); expect(before == 2); expect(task == 1); expect(after == 2); } System.out.println("rewindTest exit"); } private void continuationResultRewind() throws Exception { rewindTest(new Callable() { public Integer call() { return 0; } }, new Runnable() { public void run() { continuationReference.handleResult(1); } }); } private void continuationExceptionRewind() throws Exception { rewindTest(new Callable() { public Integer call() throws Exception { throw new MyException(0); } }, new Runnable() { public void run() { continuationReference.handleException(new MyException(1)); } }); } private void continuationResultUnwindAndRewind() throws Exception { rewindTest(new Callable() { public Integer call() { return 0; } }, new Runnable() { public void run() { try { new DynamicWind().unwindTest(new Callable() { public Integer call() { continuationReference.handleResult(1); throw new AssertionError(); } }); } catch (Exception e) { throw new RuntimeException(e); } } }); } private void continuationExceptionUnwindAndRewind() throws Exception { rewindTest(new Callable() { public Integer call() throws Exception { throw new MyException(0); } }, new Runnable() { public void run() { try { new DynamicWind().unwindTest(new Callable() { public Integer call() { continuationReference.handleException(new MyException(1)); throw new AssertionError(); } }); } catch (Exception e) { throw new RuntimeException(e); } } }); } private void continuationResultUnwindAndRewindWithShared() throws Exception { unwindTest(new Callable() { public Integer call() throws Exception { new DynamicWind().continuationResultUnwindAndRewind(); return 42; } }); } private void continuationExceptionUnwindAndRewindWithShared() throws Exception { unwindTest(new Callable() { public Integer call() throws Exception { new DynamicWind().continuationExceptionUnwindAndRewind(); return 42; } }); } public static void main(String[] args) throws Exception { new DynamicWind().normalUnwind(); new DynamicWind().exceptionUnwind(); new DynamicWind().continuationResultUnwind(); new DynamicWind().continuationExceptionUnwind(); new DynamicWind().continuationResultRewind(); new DynamicWind().continuationExceptionRewind(); new DynamicWind().continuationResultUnwindAndRewind(); new DynamicWind().continuationExceptionUnwindAndRewind(); new DynamicWind().continuationResultUnwindAndRewindWithShared(); new DynamicWind().continuationExceptionUnwindAndRewindWithShared(); } private static class MyException extends Exception { public final int value; public MyException() { this(0); } public MyException(int value) { this.value = value; } } } ReadyTalk-avian-1e1fff5/test/extra/Memory.java000066400000000000000000000112551231440243200214010ustar00rootroot00000000000000package extra; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.TreeSet; public class Memory { private static final int ITERATION_COUNT=1; private static class Item { private static int instanceCount=0; private final int index; private final int val; public Item(int i) { val = i; index = instanceCount++; } public int value() { return val; } public int index() { return index; } } private static void traceFunc(String s) { if (false) { System.out.println(s); } } private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static int runningSum(Item[] items) { int sum=0; for (Item item : items) { sum += item.value(); } return sum; } private static int runningSum(Collection items) { int sum=0; for (Item item : items) { sum += item.value(); } return sum; } private static final void testArray() { traceFunc("testArray()"); Item[] items = new Item[1750]; for (int iter=0; iter < ITERATION_COUNT; iter++) { for (int i=0; i < 1000; i++) { items[i] = new Item(1); } for (int i=0; i < 500; i++) { items[i+1000] = new Item(4); } for (int i=0; i < 250; i++) { items[i+1500] = new Item(9); } expect(runningSum(items) == (1000*1 + 500*4 + 250*9)); Item[] zeroItems = new Item[300]; for (int i=0; i < 300; i++) { zeroItems[i] = new Item(0); } System.arraycopy(zeroItems, 0, items, 900, zeroItems.length); for (int i=0; i < 10000; i++) { items[0] = new Item(1); } expect(runningSum(items) == (900*1 + 300*4 + 250*9)); for (int i=0; i < 300; i++) { zeroItems[i] = new Item((i+900) < 1000 ? 1 : 4); } for (int i=0; i < 10000; i++) { items[0] = new Item(1); } expect(runningSum(items) == (900*1 + 300*4 + 250*9)); System.arraycopy(zeroItems, 0, items, 900, zeroItems.length); expect(runningSum(items) == (1000*1 + 500*4 + 250*9)); for (int i=0; i < 1750; i++) { items[i] = null; } } } private static final void testHashMap() { traceFunc("testHashMap()"); HashMap items = new HashMap(); for (int iter=0; iter < ITERATION_COUNT; iter++) { for (int i=0; i < 1000; i++) { items.put(i, new Item(1)); } for (int i=0; i < 500; i++) { items.put(i+1000, new Item(4)); } for (int i=0; i < 250; i++) { items.put(i+1500, new Item(9)); } expect(runningSum(items.values()) == (1000*1 + 500*4 + 250*9)); for (int i = 900; i < 1200; i++) { items.remove(i); } expect(runningSum(items.values()) == (900*1 + 300*4 + 250*9)); for (int i = 900; i < 1200; i++) { items.put(i, new Item(i < 1000 ? 1 : 4)); } expect(runningSum(items.values()) == (1000*1 + 500*4 + 250*9)); items.clear(); } } private static final void testLinkedList() { traceFunc("testLinkedList()"); LinkedList items = new LinkedList(); for (int iter=0; iter < ITERATION_COUNT; iter++) { for (int i=0; i < 1000; i++) { items.add(new Item(1)); } for (int i=0; i < 500; i++) { items.add(new Item(4)); } for (int i=0; i < 250; i++) { items.add(new Item(9)); } expect(runningSum(items) == (1000*1 + 500*4 + 250*9)); for (int i = 1199; i >= 900; i--) { items.remove(i); } expect(runningSum(items) == (900*1 + 300*4 + 250*9)); for (int i = 900; i < 1200; i++) { items.add(new Item(i < 1000 ? 1 : 4)); } expect(runningSum(items) == (1000*1 + 500*4 + 250*9)); items.clear(); } } private static final void testTreeSet() { traceFunc("testTreeSet()"); TreeSet items = new TreeSet(new Comparator() { public int compare(Item i1, Item i2) { int r = i1.value() - i2.value(); if (r == 0) { return i1.index() - i2.index(); } return r; } }); for (int iter=0; iter < ITERATION_COUNT; iter++) { for (int i=0; i < 1000; i++) { items.add(new Item(1)); } for (int i=0; i < 500; i++) { items.add(new Item(4)); } for (int i=0; i < 250; i++) { items.add(new Item(9)); } expect(runningSum(items) == (1000*1 + 500*4 + 250*9)); items.clear(); } } public static void main(String args[]) { for (int i=0; i < 10; i++) { testArray(); testHashMap(); testLinkedList(); testTreeSet(); } } } ReadyTalk-avian-1e1fff5/test/extra/PrintDump.java000066400000000000000000000046311231440243200220530ustar00rootroot00000000000000package extra; import java.io.PrintStream; import java.io.InputStream; import java.io.FileInputStream; import java.io.BufferedInputStream; import java.io.IOException; import java.io.EOFException; /** * This is a simple utility to print the contents of a heap dump * generated by Avian's heapdump.cpp in a human-readable format. */ public class PrintDump { private static final int Root = 0; private static final int Size = 1; private static final int ClassName = 2; private static final int Push = 3; private static final int Pop = 4; private static void indent(PrintStream out, int level) { for (; level > 0; --level) out.print(" "); } private static int readInt(InputStream in) throws IOException { int b1 = in.read(); int b2 = in.read(); int b3 = in.read(); int b4 = in.read(); if (b4 == -1) throw new EOFException(); return (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); } private static String readString(InputStream in) throws IOException { int count = readInt(in); byte[] b = new byte[count]; int offset = 0; int c; while ((c = in.read(b, offset, b.length - offset)) != -1 && offset < b.length) { offset += c; } if (offset != b.length) throw new EOFException(); return new String(b); } private static void pipe(InputStream in, PrintStream out) throws IOException { boolean done = false; boolean popped = false; int level = 0; while (! done) { int flag = in.read(); switch (flag) { case Root: { out.print("\nroot " + readInt(in)); popped = false; } break; case ClassName: { out.print(" class " + readString(in)); } break; case Push: { ++ level; out.println(); indent(out, level); if (! popped) { out.print("first "); } out.print("child " + readInt(in)); popped = false; } break; case Pop: { -- level; popped = true; } break; case Size: { out.print(" size " + readInt(in)); } break; case -1: out.println(); out.flush(); done = true; break; default: throw new RuntimeException("bad flag: " + flag); } } } public static void main(String[] args) throws Exception { pipe(new BufferedInputStream(new FileInputStream(args[0])), System.out); } } ReadyTalk-avian-1e1fff5/test/extra/QueryDump.java000066400000000000000000000210411231440243200220560ustar00rootroot00000000000000package extra; import java.io.PrintStream; import java.io.InputStream; import java.io.FileInputStream; import java.io.BufferedInputStream; import java.io.IOException; import java.io.EOFException; import java.util.Set; import java.util.HashSet; import java.util.Map; import java.util.HashMap; import java.util.Comparator; import java.util.Arrays; import java.util.List; import java.util.ArrayList; import java.util.Iterator; public class QueryDump { private static final int Root = 0; private static final int Size = 1; private static final int ClassName = 2; private static final int Push = 3; private static final int Pop = 4; private static int readInt(InputStream in) throws IOException { int b1 = in.read(); int b2 = in.read(); int b3 = in.read(); int b4 = in.read(); if (b4 == -1) throw new EOFException(); return (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); } private static String readString(InputStream in) throws IOException { int count = readInt(in); byte[] b = new byte[count]; int offset = 0; int c; while ((c = in.read(b, offset, b.length - offset)) != -1 && offset < b.length) { offset += c; } if (offset != b.length) throw new EOFException(); return new String(b); } private static Record record(Map map, int key) { Record r = map.get(key); if (r == null) { map.put(key, r = new Record(key)); } return r; } private static void push(List stack, T value) { stack.add(value); } private static T pop(List stack) { return stack.remove(stack.size() - 1); } private static T peek(List stack, int offset) { return stack.get(stack.size() - 1 - offset); } private static T peek(List stack) { return peek(stack, 0); } private static Set nodes(Record record) { if (record.nodes == null) { record.nodes = new HashSet(2); } return record.nodes; } private static void query(Map nodes, Record[] query, List stack, int index) { Node node = nodes.get(peek(stack, index).key); if (node != null) { int base = node.index(); for (int i = base + 1; i < query.length; ++i) { int peek = index + i - base; if (peek < stack.size()) { Instance instance = peek(stack, peek); if (query[i] == instance.record) { TreeNode next = (TreeNode) nodes.get(instance); if (next == null) { nodes.put(instance.key, next = new TreeNode(instance, i)); } next.children.add(node); node = next; } else { return; } } else { return; } } if (index + query.length - base < stack.size()) { nodes(peek(stack, index + query.length - base).record).add(node); } } } private static void query(Map nodes, Record[] query, List stack) { if (stack.size() > 1) { Instance instance = peek(stack, 1); if (instance != null && instance.record == query[0]) { Node node = nodes.get(instance.key); if (node == null) { nodes.put(instance.key, new LeafNode(instance)); query(nodes, query, stack, 1); } return; } } query(nodes, query, stack, 0); } private static Map read(InputStream in, String[] queryClasses) throws IOException { boolean done = false; boolean popped = false; Map records = new HashMap(); Map nodes = new HashMap(); List stack = new ArrayList(); Record[] query = new Record[queryClasses.length]; Record roots = new Record(-1, ""); records.put(roots.key, roots); while (! done) { int flag = in.read(); switch (flag) { case Root: { stack.clear(); push(stack, new Instance(readInt(in))); query(nodes, query, stack); popped = false; // System.out.println("root " + last); } break; case ClassName: { String name = readString(in); Record r = record(records, peek(stack).key); r.name = name; for (int i = 0; i < queryClasses.length; ++i) { if (queryClasses[i].equals(name)) { query[i] = r; } } query(nodes, query, stack); } break; case Push: { int key = readInt(in); if (! popped) { peek(stack).record = record(records, key); } push(stack, new Instance(key)); query(nodes, query, stack); popped = false; } break; case Pop: { pop(stack); popped = true; } break; case Size: { peek(stack).size = readInt(in); } break; case -1: done = true; break; default: throw new RuntimeException("bad flag: " + flag); } } return records; } private static String[] copy(String[] array, int offset, int length) { String[] copy = new String[length]; if (length > 0) { System.arraycopy(array, offset, copy, 0, length); } return copy; } private static void visitLeaves(Set nodes, LeafVisitor visitor) { for (Node n: nodes) { n.visitLeaves(visitor); } } private static void usageAndExit() { System.err.println("usage: java QueryDump " + " ..."); } public static void main(String[] args) throws Exception { if (args.length < 3) { usageAndExit(); } Map map = read (new BufferedInputStream(new FileInputStream(args[0])), copy(args, 2, args.length - 2)); for (Iterator it = map.values().iterator(); it.hasNext();) { final Record r = it.next(); if (r.nodes == null) { it.remove(); } else { visitLeaves(r.nodes, new LeafVisitor() { private Set set = new HashSet(); public void visit(LeafNode node) { if (! set.contains(node.instance)) { r.footprint += node.instance.size; ++ r.count; } set.add(node.instance); } }); } } Record[] array = map.values().toArray(new Record[map.size()]); Arrays.sort(array, new Comparator() { public int compare(Record a, Record b) { return b.footprint - a.footprint; } }); int wordSize = Integer.parseInt(args[1]); int footprint = 0; int count = 0; for (Record r: array) { if (r.name == null) { r.name = String.valueOf(r.key); } System.out.println (r.name + ": " + (r.footprint * wordSize) + " " + r.count); footprint += r.footprint; count += r.count; } System.out.println(); System.out.println("total: " + (footprint * wordSize) + " " + count); } private static class Record { public final int key; public String name; public int footprint; public int count; public Set nodes; public Record(int key) { this(key, null); } public Record(int key, String name) { this.key = key; this.name = name; } public String toString() { return name; } } private static class Instance { public final int key; public int size; public Record record; public Instance(int key) { this.key = key; } public String toString() { return "[" + key + " " + record + "]"; } } public interface Node { public void visitLeaves(LeafVisitor visitor); public int index(); } public static class LeafNode implements Node { public final Instance instance; public LeafNode(Instance instance) { this.instance = instance; } public void visitLeaves(LeafVisitor visitor) { visitor.visit(this); } public int index() { return 0; } } public static class TreeNode implements Node { public final Instance instance; public final int index; public final Set children = new HashSet(2); public TreeNode(Instance instance, int index) { this.instance = instance; this.index = index; } public void visitLeaves(LeafVisitor visitor) { QueryDump.visitLeaves(children, visitor); } public int index() { return index; } } public interface LeafVisitor { public void visit(LeafNode node); } } ReadyTalk-avian-1e1fff5/test/extra/RuntimeExec.java000066400000000000000000000040031231440243200223520ustar00rootroot00000000000000package extra; import java.lang.Runtime; import java.lang.Process; public class RuntimeExec { public static void main(String[] args) throws java.io.IOException, java.lang.InterruptedException { Runtime runtime = Runtime.getRuntime(); String ieStr = null; String charmapStr = null; String[] firefox = new String[2]; if(System.getProperty("os.name").equals("windows")){ System.out.println("Executing internet explorer"); ieStr = "\"c:\\program files\\internet explorer\\iexplore.exe\" http://www.google.com"; } else { System.out.println("Executing Firefox using string"); ieStr = "firefox http://www.google.com"; } Process ie = runtime.exec(ieStr); if(System.getProperty("os.name").equals("windows")){ System.out.println("Executing firefox"); firefox[0] = "c:\\program files\\mozilla firefox\\firefox.exe"; firefox[1] = "http://www.google.com"; } else { System.out.println("Executing Firefox using array"); firefox[0] = "firefox"; firefox[1] = "http://www.google.com"; } Process ff = runtime.exec(firefox); boolean ffSuccess = false; boolean ieSuccess = false; while(!(ieSuccess && ffSuccess)){ if(!ffSuccess){ try{ System.out.println("Exit value from string exec: " + ff.exitValue()); ffSuccess = true; } catch(IllegalThreadStateException e) {} } if(!ieSuccess){ try{ System.out.println("Exit value from array exec: " + ie.exitValue()); ieSuccess = true; } catch(IllegalThreadStateException e) {} } } if(System.getProperty("os.name").equals("windows")){ System.out.println("Executing and waiting for charmap"); charmapStr = "c:\\windows\\system32\\charmap.exe"; } else { System.out.println("Executing and waiting for firefox"); charmapStr = "firefox http://www.google.com"; } Process cm = runtime.exec(charmapStr); System.out.println("Exit value: " + cm.waitFor()); } } ReadyTalk-avian-1e1fff5/test/extra/SendFile.java000066400000000000000000000040271231440243200216210ustar00rootroot00000000000000package extra; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.io.IOException; import java.nio.channels.Selector; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.io.OutputStream; import java.io.FileInputStream; public class SendFile { private static class SocketOutputStream extends OutputStream { private final SocketChannel channel; private final Selector selector; public SocketOutputStream(String host, int port) throws Exception { channel = SocketChannel.open(); channel.connect(new InetSocketAddress(host, port)); channel.configureBlocking(false); selector = Selector.open(); channel.register(selector, SelectionKey.OP_WRITE, null); } public void close() throws IOException { channel.close(); } public void write(int c) { throw new RuntimeException("Do not use!"); } public void write(byte[] buffer, int offset, int length) throws IOException { ByteBuffer buf = ByteBuffer.wrap(buffer); buf.position(offset); buf.limit(offset+length); while (buf.hasRemaining()) { selector.select(10000); for (SelectionKey key : selector.selectedKeys()) { if (key.isWritable() && (key.channel() == channel)) { channel.write(buf); } } } } } public static void sendFile(String file, String host, int port) throws Exception { System.out.println("Sending " + file); OutputStream os = new SocketOutputStream(host, port); FileInputStream is = new FileInputStream(file); byte[] buf = new byte[16384]; int count=-1; while ((count = is.read(buf)) >= 0) { os.write(buf, 0, count); } is.close(); os.close(); } public static void main(String args[]) { if (args.length != 2) { System.out.println("Usage: SendFile file host"); } else { try { sendFile(args[0], args[1], 8988); } catch (Exception ex) { ex.printStackTrace(); } } } } ReadyTalk-avian-1e1fff5/test/extra/SendServer.java000066400000000000000000000056771231440243200222240ustar00rootroot00000000000000package extra; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; public class SendServer { private static char cIndex = 'A'; private static ByteBuffer inBuf = ByteBuffer.allocate(8192); private static void dumpByteBuffer(char note, ByteBuffer buf) { System.out.println(note + ": Buffer position: " + buf.position() + " limit: " + buf.limit() + " capacity: " + buf.capacity() + " remaining: " + buf.remaining()); } private static class Connection { private final char myIndex; private final java.io.FileOutputStream fos; public Connection() throws Exception { myIndex = cIndex++; fos = new java.io.FileOutputStream("dump." + myIndex); } public void handleRead(SocketChannel channel) throws Exception { int count = -1; while ((count = channel.read(inBuf)) > 0) { System.out.println(myIndex + ": read " + count); } inBuf.flip(); fos.write(inBuf.array(), inBuf.arrayOffset()+inBuf.position(), inBuf.remaining()); inBuf.position(inBuf.limit()); if (count < 0) { System.out.println(myIndex + ": Closing channel"); fos.close(); channel.close(); } // dumpByteBuffer(myIndex, inBuf); inBuf.compact(); } } public void runMainLoop() throws Exception { boolean keepRunning = true; int port = 8988; ServerSocketChannel serverChannel = ServerSocketChannel.open(); try { serverChannel.configureBlocking(false); serverChannel.socket().bind(new InetSocketAddress("0.0.0.0", port)); Selector selector = Selector.open(); serverChannel.register(selector, SelectionKey.OP_ACCEPT, null); while (keepRunning) { System.out.println("Running main loop"); selector.select(10000); for (SelectionKey key : selector.selectedKeys()) { if (key.isAcceptable()) { System.out.println("Accepting new connection"); SocketChannel c = ((ServerSocketChannel) key.channel()).accept(); if (c != null) { c.configureBlocking(false); c.register(selector, SelectionKey.OP_READ, new Connection()); } } else { SocketChannel c = (SocketChannel) key.channel(); if (c.isOpen() && key.isReadable()) { Connection connection = (Connection)key.attachment(); connection.handleRead(c); } } } selector.selectedKeys().clear(); } } finally { serverChannel.close(); } } public static void main(String args[]) { try { System.out.println("Starting server"); if (args.length > 0) { new SendServer().runMainLoop(); } } catch (Exception ex) { ex.printStackTrace(); } } } ReadyTalk-avian-1e1fff5/test/extra/Sockets.java000066400000000000000000000020721231440243200215410ustar00rootroot00000000000000package extra; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; import java.net.UnknownHostException; public class Sockets { /** * @param args * @throws IOException * @throws UnknownHostException */ public static void main(String[] args) throws UnknownHostException, IOException { System.out.print("Requesting... " + args[0] + "\n"); Socket sock = new Socket(args[0], 80); try { BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream())); String request = "GET /?gws_rd=cr HTTP/1.1\r\n" + "Host: " + args[0] + "\r\n" + "Accept: */*\r\n" + "User-Agent: Java\r\n" + "Connection: close\r\n" + "\r\n"; bw.write(request); bw.flush(); BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream())); String read = null; while ((read = br.readLine()) != null) { System.out.println(read); } bw.close(); } finally { sock.close(); } } }ReadyTalk-avian-1e1fff5/test/extra/Tails.java000066400000000000000000000020431231440243200212000ustar00rootroot00000000000000package extra; public class Tails { private static final int Limit = 1000000; private static void expect(boolean v) { if (! v) throw new RuntimeException(); } private static int staticMethod(Interface i, int n) { if (n < Limit) { return i.interfaceMethod(n + 1); } else { return leafMethod(n); } } private static int leafMethod(int n) { expect(new Throwable().getStackTrace().length == 2); return n; } public static void main(String[] args) { expect(staticMethod(new Foo(), 0) == Limit); } private interface Interface { public int interfaceMethod(int n); } private static class Foo implements Interface { public int interfaceMethod(int n) { if (n < Limit) { return virtualMethod(n + 1, 1, 2, 3, 4, 5); } else { return leafMethod(n); } } public int virtualMethod(int n, int a, int b, int c, int d, int e) { if (n < Limit) { return staticMethod(this, n + 1); } else { return leafMethod(n); } } } } ReadyTalk-avian-1e1fff5/test/jni.cpp000066400000000000000000000070601231440243200174260ustar00rootroot00000000000000#include #include "jni-util.h" extern "C" JNIEXPORT jdouble JNICALL Java_JNI_addDoubles (JNIEnv*, jclass, jdouble a1, jdouble a2, jdouble a3, jdouble a4, jdouble a5, jdouble a6, jdouble a7, jdouble a8, jdouble a9, jdouble a10, jdouble a11, jdouble a12, jdouble a13, jdouble a14, jdouble a15, jdouble a16, jdouble a17, jdouble a18, jdouble a19, jdouble a20) { return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20; } extern "C" JNIEXPORT jfloat JNICALL Java_JNI_addFloats (JNIEnv*, jclass, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6, jfloat a7, jfloat a8, jfloat a9, jfloat a10, jfloat a11, jfloat a12, jfloat a13, jfloat a14, jfloat a15, jfloat a16, jfloat a17, jfloat a18, jfloat a19, jfloat a20) { return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20; } extern "C" JNIEXPORT jdouble JNICALL Java_JNI_addMix (JNIEnv*, jclass, jfloat a1, jdouble a2, jfloat a3, jdouble a4, jfloat a5, jfloat a6, jfloat a7, jfloat a8, jfloat a9, jfloat a10, jfloat a11, jfloat a12, jfloat a13, jfloat a14, jfloat a15, jdouble a16, jfloat a17, jfloat a18, jfloat a19, jfloat a20) { return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20; } extern "C" JNIEXPORT jfloat JNICALL Java_JNI_doEcho__F(JNIEnv* e, jclass c, jfloat f) { jvalue value; value.f = f; jvalue array[] = { value }; return e->CallStaticFloatMethodA (c, e->GetStaticMethodID(c, "echo", "(F)F"), array); } extern "C" JNIEXPORT jdouble JNICALL Java_JNI_doEcho__D(JNIEnv* e, jclass c, jdouble f) { jvalue value; value.d = f; jvalue array[] = { value }; return e->CallStaticDoubleMethodA (c, e->GetStaticMethodID(c, "echo", "(D)D"), array); } extern "C" JNIEXPORT jlong JNICALL Java_JNI_fromReflectedMethod(JNIEnv* e, jclass, jobject method) { return reinterpret_cast(e->FromReflectedMethod(method)); } extern "C" JNIEXPORT jobject JNICALL Java_JNI_toReflectedMethod(JNIEnv* e, jclass, jclass c, jlong id, jboolean isStatic) { return e->ToReflectedMethod(c, reinterpret_cast(id), isStatic); } extern "C" JNIEXPORT jint JNICALL Java_JNI_callStaticIntMethod(JNIEnv* e, jclass, jclass c, jlong id) { return e->CallStaticIntMethod(c, reinterpret_cast(id)); } extern "C" JNIEXPORT jobject JNICALL Java_JNI_newObject(JNIEnv* e, jclass, jclass c, jlong id) { return e->NewObject(c, reinterpret_cast(id)); } extern "C" JNIEXPORT jlong JNICALL Java_JNI_fromReflectedField(JNIEnv* e, jclass, jobject field) { return reinterpret_cast(e->FromReflectedField(field)); } extern "C" JNIEXPORT jobject JNICALL Java_JNI_toReflectedField(JNIEnv* e, jclass, jclass c, jlong id, jboolean isStatic) { return e->ToReflectedField(c, reinterpret_cast(id), isStatic); } extern "C" JNIEXPORT jint JNICALL Java_JNI_getStaticIntField(JNIEnv* e, jclass, jclass c, jlong id) { return e->GetStaticIntField(c, reinterpret_cast(id)); } extern "C" JNIEXPORT jobject JNICALL Java_JNI_testLocalRef(JNIEnv* e, jclass, jobject o) { return e->NewLocalRef(o); } extern "C" JNIEXPORT jobject JNICALL Java_Buffers_allocateNative(JNIEnv* e, jclass, jint capacity) { void* p = allocate(e, capacity); if (p == 0) return 0; return e->NewDirectByteBuffer(p, capacity); } extern "C" JNIEXPORT void JNICALL Java_Buffers_freeNative(JNIEnv* e, jclass, jobject b) { free(e->GetDirectBufferAddress(b)); } ReadyTalk-avian-1e1fff5/test/test.sh000066400000000000000000000017141231440243200174550ustar00rootroot00000000000000#!/bin/sh vg="nice valgrind --leak-check=full --num-callers=32 \ --freelist-vol=100000000 --error-exitcode=1" ld_path=${1}; shift unit_tester=${1}; shift vm=${1}; shift mode=${1}; shift flags=${1}; shift tests=${@} log=log.txt if [ -n "${ld_path}" ]; then export ${ld_path} fi echo -n "" >${log} printf "%20s------- Unit tests -------\n" "" ${unit_tester} 2>>${log} if [ "${?}" != "0" ]; then trouble=1 echo "unit tests failed!" fi echo printf "%20s------- Java tests -------\n" "" for test in ${tests}; do printf "%32s: " "${test}" case ${mode} in debug|debug-fast|fast|small ) ${vm} ${flags} ${test} >>${log} 2>&1;; stress* ) ${vg} ${vm} ${flags} ${test} \ >>${log} 2>&1;; * ) echo "unknown mode: ${mode}" >&2 exit 1;; esac if [ "${?}" = "0" ]; then echo "success" else echo "fail" trouble=1 fi done echo if [ -n "${trouble}" ]; then printf "see ${log} for output\n" exit -1 fi ReadyTalk-avian-1e1fff5/unittest/000077500000000000000000000000001231440243200170375ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/unittest/codegen/000077500000000000000000000000001231440243200204435ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/unittest/codegen/assembler-test.cpp000066400000000000000000000031361231440243200241040ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include "avian/common.h" #include #include #include "avian/target.h" #include #include #include #include #include "test-harness.h" using namespace avian::codegen; using namespace vm; class BasicEnv { public: System* s; Heap* heap; Architecture* arch; BasicEnv(): s(makeSystem()), heap(makeHeap(s, 32 * 1024)), arch(makeArchitectureNative(s, true)) { arch->acquire(); } ~BasicEnv() { arch->release(); s->dispose(); } }; class Asm { public: Zone zone; Assembler* a; Asm(BasicEnv& env): zone(env.s, env.heap, 8192), a(env.arch->makeAssembler(env.heap, &zone)) { } ~Asm() { a->dispose(); } }; TEST(BasicAssembler) { BasicEnv env; Asm a(env); } TEST(ArchitecturePlan) { BasicEnv env; for(int op = (int)lir::Call; op < (int)lir::AlignedJump; op++) { bool thunk; OperandMask mask; env.arch->plan((lir::UnaryOperation)op, vm::TargetBytesPerWord, mask, &thunk); assertFalse(thunk); assertNotEqual(static_cast(0), mask.typeMask); assertNotEqual(static_cast(0), mask.registerMask); } } ReadyTalk-avian-1e1fff5/unittest/codegen/registers-test.cpp000066400000000000000000000016701231440243200241370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include #include "test-harness.h" using namespace avian::codegen; using namespace vm; TEST(RegisterIterator) { RegisterMask regs(0x55); assertEqual(0, regs.start); assertEqual(7, regs.limit); RegisterIterator it(regs); assertTrue(it.hasNext()); assertEqual(0, it.next()); assertTrue(it.hasNext()); assertEqual(2, it.next()); assertTrue(it.hasNext()); assertEqual(4, it.next()); assertTrue(it.hasNext()); assertEqual(6, it.next()); assertFalse(it.hasNext()); } ReadyTalk-avian-1e1fff5/unittest/test-harness.cpp000066400000000000000000000021151231440243200221620ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include "test-harness.h" // since we aren't linking against libstdc++, we must implement this // ourselves: extern "C" void __cxa_pure_virtual(void) { abort(); } Test* Test::first = 0; Test** Test::last = &first; Test::Test(const char* name): next(0), failures(0), runs(0), name(name) { *last = this; last = &next; } bool Test::runAll() { int failures = 0; for(Test* t = Test::first; t; t = t->next) { printf("%32s: ", t->name); t->run(); failures += t->failures; if(t->failures > 0) { printf("failure\n"); } else { printf("success\n"); } } return failures == 0; } int main(int argc UNUSED, char** argv UNUSED) { if(Test::runAll()) { return 0; } return 1; } ReadyTalk-avian-1e1fff5/unittest/test-harness.h000066400000000000000000000050431231440243200216320ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #ifndef TEST_HARNESS_H #define TEST_HARNESS_H #include "avian/common.h" #include class Test { private: Test* next; static Test* first; static Test** last; friend int main(int argc, char** argv); void print(uint64_t value) { fprintf(stderr, "%p", reinterpret_cast(value)); } void print(uint32_t value) { fprintf(stderr, "%p", reinterpret_cast(value)); } void print(uint8_t value) { print(static_cast(value)); } void print(bool value) { fprintf(stderr, "%s", value ? "true" : "false"); } int failures; int runs; protected: template void assertEqual(T expected, T actual) { if (expected != actual) { fprintf(stderr, "assertion failure, expected: "); print(expected); fprintf(stderr, ", actual: "); print(actual); fprintf(stderr, "\n"); failures++; } runs++; } void assertEqual(const char* expected, const char* actual) { if ((expected == 0 && actual != 0) || (expected != 0 && actual == 0) || strcmp(expected, actual) != 0) { fprintf(stderr, "assertion failure, expected: \"%s\", actual: \"%s\"\n", expected, actual); failures++; } runs++; } template void assertNotEqual(T expected, T actual) { if (expected == actual) { fprintf(stderr, "assertion failure, expected: not "); print(expected); fprintf(stderr, ", actual: "); print(actual); fprintf(stderr, "\n"); failures++; } runs++; } void assertTrue(bool value) { assertEqual(true, value); } void assertFalse(bool value) { assertEqual(false, value); } public: const char* const name; Test(const char* name); virtual void run() = 0; static bool runAll(); }; #define TEST(name) \ class name##TestClass : public Test { \ public: \ name##TestClass() : Test(#name) \ { \ } \ virtual void run(); \ } name##TestInstance; \ void name##TestClass::run() #endif // TEST_HARNESS_H ReadyTalk-avian-1e1fff5/unittest/util/000077500000000000000000000000001231440243200200145ustar00rootroot00000000000000ReadyTalk-avian-1e1fff5/unittest/util/arg-parser-test.cpp000066400000000000000000000030151231440243200235370ustar00rootroot00000000000000/* Copyright (c) 2008-2013, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ #include #include "avian/common.h" #include #include "test-harness.h" using namespace avian::util; TEST(ArgParser) { { ArgParser parser; Arg arg1(parser, false, "arg1", ""); Arg required2(parser, true, "required2", ""); const char* args[] = { "myExecutable", "-arg1", "myValue1", "-required2", "myRequired2", 0 }; assertTrue(parser.parse(sizeof(args) / sizeof(char*) - 1, args)); assertEqual("myValue1", arg1.value); assertEqual("myRequired2", required2.value); } { ArgParser parser; Arg arg1(parser, false, "arg1", ""); Arg required2(parser, true, "required2", ""); const char* args[] = { "myExecutable", "-arg1", "myValue1", "-required2", 0 }; assertFalse(parser.parse(sizeof(args) / sizeof(char*) - 1, args)); } { ArgParser parser; Arg arg1(parser, false, "arg1", ""); Arg required2(parser, true, "required2", ""); const char* args[] = { "myExecutable", "-arg1", "myValue1", 0 }; assertFalse(parser.parse(sizeof(args) / sizeof(char*) - 1, args)); } } ReadyTalk-avian-1e1fff5/valgrind.supp000066400000000000000000000012511231440243200176760ustar00rootroot00000000000000 { Memcheck:Cond obj:/lib/ld-2.3.6.so } { Memcheck:Cond obj:/lib/ld-2.6.so } { Memcheck:Addr4 obj:/lib/ld-2.3.6.so } { Memcheck:Addr8 obj:/lib/ld-2.3.6.so } # { # # Memcheck:Param # write(buf) # obj:* # } # { # # Memcheck:Param # writev(vector[...]) # obj:* # } # { # # Memcheck:Cond # obj:* # } # { # # Memcheck:Value8 # obj:* # } ReadyTalk-avian-1e1fff5/vm.pro000066400000000000000000000126021231440243200163250ustar00rootroot00000000000000# proguard include file (http://proguard.sourceforge.net) # we call the values method reflectively in Enum.valueOf(): -keepclassmembers public class * extends java.lang.Enum { public static *** values(); } # the VM depends on the fixed layout of the following classes: -keepclassmembers class java.lang.Class { !static ; } -keepclassmembers class java.lang.ClassLoader { !static ; } -keepclassmembers class java.lang.String { !static ; } -keepclassmembers class java.lang.Thread { !static ; } -keepclassmembers class java.lang.ThreadGroup { !static ; } -keepclassmembers class java.lang.StackTraceElement { !static ; } -keepclassmembers class java.lang.Throwable { !static ; } -keepclassmembers class java.lang.Byte { !static ; } -keepclassmembers class java.lang.Boolean { !static ; } -keepclassmembers class java.lang.Short { !static ; } -keepclassmembers class java.lang.Character { !static ; } -keepclassmembers class java.lang.Integer { !static ; } -keepclassmembers class java.lang.Long { !static ; } -keepclassmembers class java.lang.Float { !static ; } -keepclassmembers class java.lang.Double { !static ; } -keepclassmembers class java.lang.ref.Reference { !static ; } -keepclassmembers class java.lang.ref.ReferenceQueue { !static ; } -keepclassmembers class java.lang.ref.WeakReference { !static ; } -keepclassmembers class java.lang.ref.PhantomReference { !static ; } -keepclassmembers class java.lang.reflect.Field { !static ; } -keepclassmembers class java.lang.reflect.Method { !static ; } -keepclassmembers class java.lang.reflect.Constructor { !static ; } -keepclassmembers class java.lang.reflect.AccessibleObject { !static ; } -keepclassmembers class sun.reflect.ConstantPool { !static ; } -keepclassmembers class avian.VMClass { !static ; } -keepclassmembers class avian.VMMethod { !static ; } -keepclassmembers class avian.VMField { !static ; } -keepclassmembers class avian.ClassAddendum { !static ; } -keepclassmembers class avian.MethodAddendum { !static ; } -keepclassmembers class avian.FieldAddendum { !static ; } -keepclassmembers class avian.Continuations$Continuation { !static ; } -keepclassmembers class avian.Continuations$UnwindResult { !static ; } # the VM may throw instances of the following: -keep public class avian.IncompatibleContinuationException -keep public class java.lang.Exception -keep public class java.lang.RuntimeException -keep public class java.lang.IllegalStateException -keep public class java.lang.IllegalArgumentException -keep public class java.lang.IllegalMonitorStateException -keep public class java.lang.IllegalThreadStateException -keep public class java.lang.IndexOutOfBoundsException -keep public class java.lang.ArrayIndexOutOfBoundsException -keep public class java.lang.ArrayStoreException -keep public class java.lang.NegativeArraySizeException -keep public class java.lang.CloneNotSupportedException -keep public class java.lang.ClassCastException -keep public class java.lang.ClassNotFoundException -keep public class java.lang.NullPointerException -keep public class java.lang.ArithmeticException -keep public class java.lang.InterruptedException -keep public class java.lang.StackOverflowError -keep public class java.lang.NoSuchFieldError -keep public class java.lang.NoSuchMethodError -keep public class java.lang.AbstractMethodError -keep public class java.lang.UnsatisfiedLinkError -keep public class java.lang.ExceptionInInitializerError -keep public class java.lang.OutOfMemoryError -keep public class java.lang.IncompatibleClassChangeError -keep public class java.lang.reflect.InvocationTargetException -keep public class java.io.IOException -keep public class java.io.FileNotFoundException -keep public class java.net.SocketException -keep public class java.util.Locale # ClassLoader.getSystemClassloader() depends on the existence of this class: -keep class avian.SystemClassLoader # the VM references these classes by name, so protect them from obfuscation: -keepnames public class java.lang.** -keepnames public class avian.** # Don't optimize calls to ResourceBundle -keep,allowshrinking,allowobfuscation public class java.util.ResourceBundle { public static java.util.ResourceBundle getBundle(...); } # musn't obfuscate native method names: -keepclasseswithmembernames class * { native ; } # Thread.run is called by name in the VM -keepclassmembers class java.lang.Thread { private static void run(java.lang.Thread); public void run(); } # when continuations are enabled, the VM may call these methods by name: -keepclassmembers class avian.Continuations { *** wind(...); *** rewind(...); } -keepclassmembernames class avian.CallbackReceiver { *** receive(...); } # the above methods include these classes in their signatures: -keepnames public class avian.Callback -keepnames public class java.util.concurrent.Callable # Proguard gets confused about clone() and array classes (http://sourceforge.net/tracker/index.php?func=detail&aid=2851344&group_id=54750&atid=474704): -keepclassmembers class java.lang.Object { protected java.lang.Object clone(); } # called by name in the VM: -keepclassmembers class java.lang.ClassLoader { public java.lang.Class loadClass(java.lang.String); }