├── .gitignore ├── Makefile ├── README.md ├── compile ├── project.clj └── src ├── core.clj ├── other_triple.clj ├── triple.cc └── triple.h /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.cpcache 3 | /*.so 4 | /target 5 | /woop -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | -rm classes/* 3 | -rm *.so 4 | -rm woop 5 | 6 | JavaFiles: 7 | javac -d classes/ src/Headers.java src/Main.java src/TripletLib.java src/Triple.java src/Value.java 8 | 9 | CFiles: 10 | clang -shared -o libtriple.so src/triple.cc -Itriple.h 11 | 12 | ni: JavaFiles CFiles 13 | native-image -cp ./classes2 --verbose -Djava.library.path=./classes2 -H:CLibraryPath=. Main 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clojure calling c -- compiled to a binary with native-image 2 | 3 | ## Prerequisites 4 | 5 | * graalvm -- tested with `graalvm-ce-java11-20.2.0-dev`: https://github.com/graalvm/graalvm-ce-dev-builds/releases 6 | * download, then add the following to e.g. .zprofile 7 | * `export GRAALVM_HOME = "/path/to/graalvm-ce-java11-20.2.0-dev/Contents/Home/"` 8 | * `export JAVA_HOME = $GRAALVM_HOME` 9 | * install native-image: `$GRAALVM_HOME/bin/gu install native-image` (will be installed by `./compile` otherwise) 10 | * leiningen -- https://leiningen.org/ 11 | 12 | I've only tested on mac. 13 | 14 | ## Steps 15 | 16 | Modify `src/Headers.java`, specifically: `/Users/test/programmering/clojure/graal-native-interaction/graal/src/triple.h` needs to point to your `src/triple.h`. 17 | 18 | ``` 19 | $ make clean CFiles && ./compile && ./woop 20 | 1 # this value comes from a c-struct! 21 | ``` 22 | 23 | ## Acknowledgements 24 | 25 | * Java code from: https://github.com/cornerwings/graal-native-interaction 26 | * Project setup for clojure / native compilation from: https://github.com/borkdude/clj-kondo 27 | 28 | Thanks sogaiu for helping me get this working. :) 29 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ -z "$GRAALVM_HOME" ]; then 4 | echo "Please set GRAALVM_HOME" 5 | exit 1 6 | fi 7 | 8 | "$GRAALVM_HOME/bin/gu" install native-image || true 9 | 10 | lein with-profiles +clojure-1.10.2-alpha1 do clean, uberjar 11 | 12 | args=( "-jar" "target/woop-0.0.1-standalone.jar" \ 13 | "-H:CLibraryPath=." \ 14 | "-H:Name=woop" \ 15 | "-H:+ReportExceptionStackTraces" \ 16 | "-J-Dclojure.spec.skip-macros=true" \ 17 | "-J-Dclojure.compiler.direct-linking=true" \ 18 | "--initialize-at-build-time" \ 19 | "-H:Log=registerResource:" \ 20 | "--verbose" \ 21 | "--no-fallback" \ 22 | "--no-server" \ 23 | "-J-Xmx3g" ) 24 | 25 | $GRAALVM_HOME/bin/native-image "${args[@]}" -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject woop "0.0.1" 2 | :dependencies [[org.clojure/clojure "1.10.1"]] 3 | :source-paths ["src"] 4 | ;;:java-source-paths ["src"] 5 | :resource-paths [#_"extra-classes" #_"classes"] 6 | :jvm-opts ["-Dclojure.compiler.direct-linking=true" 7 | "-Dclojure.spec.skip-macros=true" 8 | "-Dclojure.server.repl={:port 5555 :accept clojure.core.server/repl}" 9 | ] 10 | :aot :all 11 | :profiles {:clojure-1.10.2-alpha1 {:dependencies [[org.clojure/clojure "1.10.2-alpha1"]]} 12 | :uberjar {:global-vars {*assert* false} 13 | :jvm-opts ["-Dclojure.compiler.direct-linking=true" 14 | "-Dclojure.spec.skip-macros=true"] 15 | :main core 16 | :aot :all}}) 17 | -------------------------------------------------------------------------------- /src/core.clj: -------------------------------------------------------------------------------- 1 | (ns core 2 | (:require [other-triple]) 3 | #_(:import TripletLib) 4 | (:import wat.cool.OOTripletLib) 5 | 6 | (:gen-class)) 7 | 8 | (defn -main [& args] 9 | (println "lul") 10 | (let [t (OOTripletLib/allocRandomTriple)] 11 | (println (.getId (.subject t))) 12 | (OOTripletLib/freeTriple t))) 13 | -------------------------------------------------------------------------------- /src/other_triple.clj: -------------------------------------------------------------------------------- 1 | (in-ns 'clojure.core) 2 | 3 | (defn- generate-class2 [options-map] 4 | (validate-generate-class-options options-map) 5 | (let [default-options {:prefix "-" :load-impl-ns true :impl-ns (ns-name *ns*)} 6 | {:keys [name extends implements constructors methods main factory state init exposes 7 | exposes-methods prefix load-impl-ns impl-ns post-init]} 8 | (merge default-options options-map) 9 | name-meta (meta name) 10 | name (str name) 11 | super (if extends (the-class extends) Object) 12 | interfaces (map the-class implements) 13 | supers (cons super interfaces) 14 | ctor-sig-map (or constructors (zipmap (ctor-sigs super) (ctor-sigs super))) 15 | cv (clojure.lang.Compiler/classWriter) 16 | cname (. name (replace "." "/")) 17 | pkg-name name 18 | impl-pkg-name (str impl-ns) 19 | impl-cname (.. impl-pkg-name (replace "." "/") (replace \- \_)) 20 | ctype (. Type (getObjectType cname)) 21 | iname (fn [^Class c] (.. Type (getType c) (getInternalName))) 22 | totype (fn [^Class c] (. Type (getType c))) 23 | to-types (fn [cs] (if (pos? (count cs)) 24 | (into-array (map totype cs)) 25 | (make-array Type 0))) 26 | obj-type ^Type (totype Object) 27 | arg-types (fn [n] (if (pos? n) 28 | (into-array (replicate n obj-type)) 29 | (make-array Type 0))) 30 | super-type ^Type (totype super) 31 | init-name (str init) 32 | post-init-name (str post-init) 33 | factory-name (str factory) 34 | state-name (str state) 35 | main-name "main" 36 | var-name (fn [s] (clojure.lang.Compiler/munge (str s "__var"))) 37 | class-type (totype Class) 38 | rt-type (totype clojure.lang.RT) 39 | var-type ^Type (totype clojure.lang.Var) 40 | ifn-type (totype clojure.lang.IFn) 41 | iseq-type (totype clojure.lang.ISeq) 42 | ex-type (totype java.lang.UnsupportedOperationException) 43 | util-type (totype clojure.lang.Util) 44 | all-sigs (distinct (concat (map #(let[[m p] (key %)] {m [p]}) (mapcat non-private-methods supers)) 45 | (map (fn [[m p]] {(str m) [p]}) methods))) 46 | sigs-by-name (apply merge-with concat {} all-sigs) 47 | overloads (into1 {} (filter (fn [[m s]] (next s)) sigs-by-name)) 48 | var-fields (concat (when init [init-name]) 49 | (when post-init [post-init-name]) 50 | (when main [main-name]) 51 | ;(when exposes-methods (map str (vals exposes-methods))) 52 | (distinct (concat (keys sigs-by-name) 53 | (mapcat (fn [[m s]] (map #(overload-name m (map the-class %)) s)) overloads) 54 | (mapcat (comp (partial map str) vals val) exposes)))) 55 | emit-get-var (fn [^GeneratorAdapter gen v] 56 | (let [false-label (. gen newLabel) 57 | end-label (. gen newLabel)] 58 | (. gen getStatic ctype (var-name v) var-type) 59 | (. gen dup) 60 | (. gen invokeVirtual var-type (. Method (getMethod "boolean isBound()"))) 61 | (. gen ifZCmp (. GeneratorAdapter EQ) false-label) 62 | (. gen invokeVirtual var-type (. Method (getMethod "Object get()"))) 63 | (. gen goTo end-label) 64 | (. gen mark false-label) 65 | (. gen pop) 66 | (. gen visitInsn (. Opcodes ACONST_NULL)) 67 | (. gen mark end-label))) 68 | emit-unsupported (fn [^GeneratorAdapter gen ^Method m] 69 | (. gen (throwException ex-type (str (. m (getName)) " (" 70 | impl-pkg-name "/" prefix (.getName m) 71 | " not defined?)")))) 72 | emit-forwarding-method 73 | (fn [name pclasses rclass as-static as-native else-gen] 74 | (let [mname (str name) 75 | pmetas (map meta pclasses) 76 | pclasses (map the-class pclasses) 77 | rclass (the-class rclass) 78 | ptypes (to-types pclasses) 79 | rtype ^Type (totype rclass) 80 | m (new Method mname rtype ptypes) 81 | is-overload (seq (overloads mname)) 82 | gen (new GeneratorAdapter (+ (. Opcodes ACC_PUBLIC) 83 | (if as-static (. Opcodes ACC_STATIC) 0) 84 | (if as-native (. Opcodes ACC_NATIVE) 0)) 85 | m nil nil cv) 86 | found-label (. gen (newLabel)) 87 | else-label (. gen (newLabel)) 88 | end-label (. gen (newLabel))] 89 | (add-annotations gen (meta name)) 90 | (dotimes [i (count pmetas)] 91 | (add-annotations gen (nth pmetas i) i)) 92 | (when-not as-native 93 | (. gen (visitCode)) 94 | (if (> (count pclasses) 18) 95 | (else-gen gen m) 96 | (do 97 | (when is-overload 98 | (emit-get-var gen (overload-name mname pclasses)) 99 | (. gen (dup)) 100 | (. gen (ifNonNull found-label)) 101 | (. gen (pop))) 102 | (emit-get-var gen mname) 103 | (. gen (dup)) 104 | (. gen (ifNull else-label)) 105 | (when is-overload 106 | (. gen (mark found-label))) 107 | ;if found 108 | (.checkCast gen ifn-type) 109 | (when-not as-static 110 | (. gen (loadThis))) 111 | ;box args 112 | (dotimes [i (count ptypes)] 113 | (. gen (loadArg i)) 114 | (. clojure.lang.Compiler$HostExpr (emitBoxReturn nil gen (nth pclasses i)))) 115 | ;call fn 116 | (. gen (invokeInterface ifn-type (new Method "invoke" obj-type 117 | (to-types (replicate (+ (count ptypes) 118 | (if as-static 0 1)) 119 | Object))))) 120 | ;(into-array (cons obj-type 121 | ; (replicate (count ptypes) obj-type)))))) 122 | ;unbox return 123 | (. gen (unbox rtype)) 124 | (when (= (. rtype (getSort)) (. Type VOID)) 125 | (. gen (pop))) 126 | (. gen (goTo end-label)) 127 | 128 | ;else call supplied alternative generator 129 | (. gen (mark else-label)) 130 | (. gen (pop)) 131 | 132 | (else-gen gen m) 133 | 134 | (. gen (mark end-label)))) 135 | (. gen (returnValue))) 136 | (. gen (endMethod)))) 137 | ] 138 | ;start class definition 139 | (. cv (visit (. Opcodes V1_8) (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_SUPER)) 140 | cname nil (iname super) 141 | (when-let [ifc (seq interfaces)] 142 | (into-array (map iname ifc))))) 143 | 144 | ; class annotations 145 | (add-annotations cv name-meta) 146 | 147 | ;static fields for vars 148 | (doseq [v var-fields] 149 | (. cv (visitField (+ (. Opcodes ACC_PRIVATE) (. Opcodes ACC_FINAL) (. Opcodes ACC_STATIC)) 150 | (var-name v) 151 | (. var-type getDescriptor) 152 | nil nil))) 153 | 154 | ;instance field for state 155 | (when state 156 | (. cv (visitField (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_FINAL)) 157 | state-name 158 | (. obj-type getDescriptor) 159 | nil nil))) 160 | 161 | ;static init to set up var fields and load init 162 | (let [gen (new GeneratorAdapter (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_STATIC)) 163 | (. Method getMethod "void ()") 164 | nil nil cv)] 165 | (. gen (visitCode)) 166 | (doseq [v var-fields] 167 | (. gen push impl-pkg-name) 168 | (. gen push (str prefix v)) 169 | (. gen (invokeStatic var-type (. Method (getMethod "clojure.lang.Var internPrivate(String,String)")))) 170 | (. gen putStatic ctype (var-name v) var-type)) 171 | 172 | (when load-impl-ns 173 | (. gen push (str "/" impl-cname)) 174 | (. gen push ctype) 175 | (. gen (invokeStatic util-type (. Method (getMethod "Object loadWithClass(String,Class)")))) 176 | ; (. gen push (str (.replace impl-pkg-name \- \_) "__init")) 177 | ; (. gen (invokeStatic class-type (. Method (getMethod "Class forName(String)")))) 178 | (. gen pop)) 179 | 180 | (. gen (returnValue)) 181 | (. gen (endMethod))) 182 | 183 | ;ctors 184 | (doseq [[pclasses super-pclasses] ctor-sig-map] 185 | (let [constructor-annotations (meta pclasses) 186 | pclasses (map the-class pclasses) 187 | super-pclasses (map the-class super-pclasses) 188 | ptypes (to-types pclasses) 189 | super-ptypes (to-types super-pclasses) 190 | m (new Method "" (. Type VOID_TYPE) ptypes) 191 | super-m (new Method "" (. Type VOID_TYPE) super-ptypes) 192 | gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv) 193 | _ (add-annotations gen constructor-annotations) 194 | no-init-label (. gen newLabel) 195 | end-label (. gen newLabel) 196 | no-post-init-label (. gen newLabel) 197 | end-post-init-label (. gen newLabel) 198 | nth-method (. Method (getMethod "Object nth(Object,int)")) 199 | local (. gen newLocal obj-type)] 200 | (. gen (visitCode)) 201 | 202 | (if init 203 | (do 204 | (emit-get-var gen init-name) 205 | (. gen dup) 206 | (. gen ifNull no-init-label) 207 | (.checkCast gen ifn-type) 208 | ;box init args 209 | (dotimes [i (count pclasses)] 210 | (. gen (loadArg i)) 211 | (. clojure.lang.Compiler$HostExpr (emitBoxReturn nil gen (nth pclasses i)))) 212 | ;call init fn 213 | (. gen (invokeInterface ifn-type (new Method "invoke" obj-type 214 | (arg-types (count ptypes))))) 215 | ;expecting [[super-ctor-args] state] returned 216 | (. gen dup) 217 | (. gen push (int 0)) 218 | (. gen (invokeStatic rt-type nth-method)) 219 | (. gen storeLocal local) 220 | 221 | (. gen (loadThis)) 222 | (. gen dupX1) 223 | (dotimes [i (count super-pclasses)] 224 | (. gen loadLocal local) 225 | (. gen push (int i)) 226 | (. gen (invokeStatic rt-type nth-method)) 227 | (. clojure.lang.Compiler$HostExpr (emitUnboxArg nil gen (nth super-pclasses i)))) 228 | (. gen (invokeConstructor super-type super-m)) 229 | 230 | (if state 231 | (do 232 | (. gen push (int 1)) 233 | (. gen (invokeStatic rt-type nth-method)) 234 | (. gen (putField ctype state-name obj-type))) 235 | (. gen pop)) 236 | 237 | (. gen goTo end-label) 238 | ;no init found 239 | (. gen mark no-init-label) 240 | (. gen (throwException ex-type (str impl-pkg-name "/" prefix init-name " not defined"))) 241 | (. gen mark end-label)) 242 | (if (= pclasses super-pclasses) 243 | (do 244 | (. gen (loadThis)) 245 | (. gen (loadArgs)) 246 | (. gen (invokeConstructor super-type super-m))) 247 | (throw (new Exception ":init not specified, but ctor and super ctor args differ")))) 248 | 249 | (when post-init 250 | (emit-get-var gen post-init-name) 251 | (. gen dup) 252 | (. gen ifNull no-post-init-label) 253 | (.checkCast gen ifn-type) 254 | (. gen (loadThis)) 255 | ;box init args 256 | (dotimes [i (count pclasses)] 257 | (. gen (loadArg i)) 258 | (. clojure.lang.Compiler$HostExpr (emitBoxReturn nil gen (nth pclasses i)))) 259 | ;call init fn 260 | (. gen (invokeInterface ifn-type (new Method "invoke" obj-type 261 | (arg-types (inc (count ptypes)))))) 262 | (. gen pop) 263 | (. gen goTo end-post-init-label) 264 | ;no init found 265 | (. gen mark no-post-init-label) 266 | (. gen (throwException ex-type (str impl-pkg-name "/" prefix post-init-name " not defined"))) 267 | (. gen mark end-post-init-label)) 268 | 269 | (. gen (returnValue)) 270 | (. gen (endMethod)) 271 | ;factory 272 | (when factory 273 | (let [fm (new Method factory-name ctype ptypes) 274 | gen (new GeneratorAdapter (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_STATIC)) 275 | fm nil nil cv)] 276 | (. gen (visitCode)) 277 | (. gen newInstance ctype) 278 | (. gen dup) 279 | (. gen (loadArgs)) 280 | (. gen (invokeConstructor ctype m)) 281 | (. gen (returnValue)) 282 | (. gen (endMethod)))))) 283 | 284 | ;add methods matching supers', if no fn -> call super 285 | (let [mm (non-private-methods super)] 286 | (doseq [^java.lang.reflect.Method meth (vals mm)] 287 | (emit-forwarding-method (.getName meth) (.getParameterTypes meth) (.getReturnType meth) false false 288 | (fn [^GeneratorAdapter gen ^Method m] 289 | (. gen (loadThis)) 290 | ;push args 291 | (. gen (loadArgs)) 292 | ;call super 293 | (. gen (visitMethodInsn (. Opcodes INVOKESPECIAL) 294 | (. super-type (getInternalName)) 295 | (. m (getName)) 296 | (. m (getDescriptor))))))) 297 | ;add methods matching interfaces', if no fn -> throw 298 | (reduce1 (fn [mm ^java.lang.reflect.Method meth] 299 | (if (contains? mm (method-sig meth)) 300 | mm 301 | (do 302 | (emit-forwarding-method (.getName meth) (.getParameterTypes meth) (.getReturnType meth) false false 303 | emit-unsupported) 304 | (assoc mm (method-sig meth) meth)))) 305 | mm (mapcat #(.getMethods ^Class %) interfaces)) 306 | ;extra methods 307 | (doseq [[mname pclasses rclass :as msig] methods] 308 | (emit-forwarding-method mname pclasses rclass (:static (meta msig)) (:native (meta msig)) 309 | emit-unsupported)) 310 | ;expose specified overridden superclass methods 311 | (doseq [[local-mname ^java.lang.reflect.Method m] (reduce1 (fn [ms [[name _ _] m]] 312 | (if (contains? exposes-methods (symbol name)) 313 | (conj ms [((symbol name) exposes-methods) m]) 314 | ms)) [] (concat (seq mm) 315 | (seq (protected-final-methods super))))] 316 | (let [ptypes (to-types (.getParameterTypes m)) 317 | rtype (totype (.getReturnType m)) 318 | exposer-m (new Method (str local-mname) rtype ptypes) 319 | target-m (new Method (.getName m) rtype ptypes) 320 | gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) exposer-m nil nil cv)] 321 | (. gen (loadThis)) 322 | (. gen (loadArgs)) 323 | (. gen (visitMethodInsn (. Opcodes INVOKESPECIAL) 324 | (. super-type (getInternalName)) 325 | (. target-m (getName)) 326 | (. target-m (getDescriptor)))) 327 | (. gen (returnValue)) 328 | (. gen (endMethod))))) 329 | ;main 330 | (when main 331 | (let [m (. Method getMethod "void main (String[])") 332 | gen (new GeneratorAdapter (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_STATIC)) 333 | m nil nil cv) 334 | no-main-label (. gen newLabel) 335 | end-label (. gen newLabel)] 336 | (. gen (visitCode)) 337 | 338 | (emit-get-var gen main-name) 339 | (. gen dup) 340 | (. gen ifNull no-main-label) 341 | (.checkCast gen ifn-type) 342 | (. gen loadArgs) 343 | (. gen (invokeStatic rt-type (. Method (getMethod "clojure.lang.ISeq seq(Object)")))) 344 | (. gen (invokeInterface ifn-type (new Method "applyTo" obj-type 345 | (into-array [iseq-type])))) 346 | (. gen pop) 347 | (. gen goTo end-label) 348 | ;no main found 349 | (. gen mark no-main-label) 350 | (. gen (throwException ex-type (str impl-pkg-name "/" prefix main-name " not defined"))) 351 | (. gen mark end-label) 352 | (. gen (returnValue)) 353 | (. gen (endMethod)))) 354 | ;field exposers 355 | (doseq [[f {getter :get setter :set}] exposes] 356 | (let [fld (find-field super (str f)) 357 | ftype (totype (.getType fld)) 358 | static? (Modifier/isStatic (.getModifiers fld)) 359 | acc (+ Opcodes/ACC_PUBLIC (if static? Opcodes/ACC_STATIC 0))] 360 | (when getter 361 | (let [m (new Method (str getter) ftype (to-types [])) 362 | gen (new GeneratorAdapter acc m nil nil cv)] 363 | (. gen (visitCode)) 364 | (if static? 365 | (. gen getStatic ctype (str f) ftype) 366 | (do 367 | (. gen loadThis) 368 | (. gen getField ctype (str f) ftype))) 369 | (. gen (returnValue)) 370 | (. gen (endMethod)))) 371 | (when setter 372 | (let [m (new Method (str setter) Type/VOID_TYPE (into-array [ftype])) 373 | gen (new GeneratorAdapter acc m nil nil cv)] 374 | (. gen (visitCode)) 375 | (if static? 376 | (do 377 | (. gen loadArgs) 378 | (. gen putStatic ctype (str f) ftype)) 379 | (do 380 | (. gen loadThis) 381 | (. gen loadArgs) 382 | (. gen putField ctype (str f) ftype))) 383 | (. gen (returnValue)) 384 | (. gen (endMethod)))))) 385 | ;finish class def 386 | (. cv (visitEnd)) 387 | [cname (. cv (toByteArray))])) 388 | 389 | (defmacro gen-class2 390 | "When compiling, generates compiled bytecode for a class with the 391 | given package-qualified :name (which, as all names in these 392 | parameters, can be a string or symbol), and writes the .class file 393 | to the *compile-path* directory. When not compiling, does 394 | nothing. The gen-class construct contains no implementation, as the 395 | implementation will be dynamically sought by the generated class in 396 | functions in an implementing Clojure namespace. Given a generated 397 | class org.mydomain.MyClass with a method named mymethod, gen-class 398 | will generate an implementation that looks for a function named by 399 | (str prefix mymethod) (default prefix: \"-\") in a 400 | Clojure namespace specified by :impl-ns 401 | (defaults to the current namespace). All inherited methods, 402 | generated methods, and init and main functions (see :methods, :init, 403 | and :main below) will be found similarly prefixed. By default, the 404 | static initializer for the generated class will attempt to load the 405 | Clojure support code for the class as a resource from the classpath, 406 | e.g. in the example case, ``org/mydomain/MyClass__init.class``. This 407 | behavior can be controlled by :load-impl-ns 408 | 409 | Note that methods with a maximum of 18 parameters are supported. 410 | 411 | In all subsequent sections taking types, the primitive types can be 412 | referred to by their Java names (int, float etc), and classes in the 413 | java.lang package can be used without a package qualifier. All other 414 | classes must be fully qualified. 415 | 416 | Options should be a set of key/value pairs, all except for :name are optional: 417 | 418 | :name aname 419 | 420 | The package-qualified name of the class to be generated 421 | 422 | :extends aclass 423 | 424 | Specifies the superclass, the non-private methods of which will be 425 | overridden by the class. If not provided, defaults to Object. 426 | 427 | :implements [interface ...] 428 | 429 | One or more interfaces, the methods of which will be implemented by the class. 430 | 431 | :init name 432 | 433 | If supplied, names a function that will be called with the arguments 434 | to the constructor. Must return [ [superclass-constructor-args] state] 435 | If not supplied, the constructor args are passed directly to 436 | the superclass constructor and the state will be nil 437 | 438 | :constructors {[param-types] [super-param-types], ...} 439 | 440 | By default, constructors are created for the generated class which 441 | match the signature(s) of the constructors for the superclass. This 442 | parameter may be used to explicitly specify constructors, each entry 443 | providing a mapping from a constructor signature to a superclass 444 | constructor signature. When you supply this, you must supply an :init 445 | specifier. 446 | 447 | :post-init name 448 | 449 | If supplied, names a function that will be called with the object as 450 | the first argument, followed by the arguments to the constructor. 451 | It will be called every time an object of this class is created, 452 | immediately after all the inherited constructors have completed. 453 | Its return value is ignored. 454 | 455 | :methods [ [name [param-types] return-type], ...] 456 | 457 | The generated class automatically defines all of the non-private 458 | methods of its superclasses/interfaces. This parameter can be used 459 | to specify the signatures of additional methods of the generated 460 | class. Static methods can be specified with ^{:static true} in the 461 | signature's metadata. Do not repeat superclass/interface signatures 462 | here. 463 | 464 | :main boolean 465 | 466 | If supplied and true, a static public main function will be generated. It will 467 | pass each string of the String[] argument as a separate argument to 468 | a function called (str prefix main). 469 | 470 | :factory name 471 | 472 | If supplied, a (set of) public static factory function(s) will be 473 | created with the given name, and the same signature(s) as the 474 | constructor(s). 475 | 476 | :state name 477 | 478 | If supplied, a public final instance field with the given name will be 479 | created. You must supply an :init function in order to provide a 480 | value for the state. Note that, though final, the state can be a ref 481 | or agent, supporting the creation of Java objects with transactional 482 | or asynchronous mutation semantics. 483 | 484 | :exposes {protected-field-name {:get name :set name}, ...} 485 | 486 | Since the implementations of the methods of the generated class 487 | occur in Clojure functions, they have no access to the inherited 488 | protected fields of the superclass. This parameter can be used to 489 | generate public getter/setter methods exposing the protected field(s) 490 | for use in the implementation. 491 | 492 | :exposes-methods {super-method-name exposed-name, ...} 493 | 494 | It is sometimes necessary to call the superclass' implementation of an 495 | overridden method. Those methods may be exposed and referred in 496 | the new method implementation by a local name. 497 | 498 | :prefix string 499 | 500 | Default: \"-\" Methods called e.g. Foo will be looked up in vars called 501 | prefixFoo in the implementing ns. 502 | 503 | :impl-ns name 504 | 505 | Default: the name of the current ns. Implementations of methods will be 506 | looked up in this namespace. 507 | 508 | :load-impl-ns boolean 509 | 510 | Default: true. Causes the static initializer for the generated class 511 | to reference the load code for the implementing namespace. Should be 512 | true when implementing-ns is the default, false if you intend to 513 | load the code via some other method." 514 | {:added "1.0"} 515 | 516 | [& options] 517 | (when *compile-files* 518 | (let [options-map (into1 {} (map vec (partition 2 options))) 519 | [cname bytecode] (generate-class2 options-map)] 520 | (clojure.lang.Compiler/writeClassFile cname bytecode)))) 521 | 522 | (ns other-triple 523 | (:import org.graalvm.word.PointerBase 524 | org.graalvm.nativeimage.c.struct.CField 525 | org.graalvm.nativeimage.c.CContext 526 | org.graalvm.nativeimage.c.function.CFunction 527 | org.graalvm.nativeimage.c.function.CLibrary 528 | org.graalvm.nativeimage.c.struct.CFieldAddress 529 | org.graalvm.nativeimage.c.struct.CStruct 530 | org.graalvm.nativeimage.c.struct.AllowWideningCast 531 | org.graalvm.nativeimage.c.function.CFunction) 532 | (:gen-class)) 533 | 534 | (deftype Headers 535 | [] 536 | org.graalvm.nativeimage.c.CContext$Directives 537 | (getHeaderFiles 538 | [this] 539 | ["\"/Users/test/programmering/clojure/graal-native-interaction/graal/src/triple.h\""])) 540 | 541 | (gen-interface 542 | :name ^{org.graalvm.nativeimage.c.CContext other_triple.Headers 543 | org.graalvm.nativeimage.c.function.CLibrary "triple" 544 | org.graalvm.nativeimage.c.struct.CStruct "value_t"} 545 | wat.cool.OOValue 546 | :extends [org.graalvm.word.PointerBase] 547 | :methods [[^{org.graalvm.nativeimage.c.struct.CField "id" 548 | org.graalvm.nativeimage.c.struct.AllowWideningCast true} getId [] long]]) 549 | 550 | (gen-interface 551 | :name ^{org.graalvm.nativeimage.c.CContext other_triple.Headers 552 | org.graalvm.nativeimage.c.function.CLibrary "triple" 553 | org.graalvm.nativeimage.c.struct.CStruct "triple_t"} 554 | wat.cool.OOTriple 555 | :extends [org.graalvm.word.PointerBase] 556 | :methods [[^{org.graalvm.nativeimage.c.struct.CFieldAddress "subject"} subject [] wat.cool.OOValue]]) 557 | 558 | (gen-class2 559 | :name ^{org.graalvm.nativeimage.c.CContext other_triple.Headers 560 | org.graalvm.nativeimage.c.function.CLibrary "triple"} 561 | wat.cool.OOTripletLib 562 | 563 | :methods [^:static ^:native [^{org.graalvm.nativeimage.c.function.CFunction 564 | {:transition org.graalvm.nativeimage.c.function.CFunction$Transition/NO_TRANSITION}} 565 | allocRandomTriple 566 | [] 567 | wat.cool.OOTriple] 568 | ^:static ^:native [^{org.graalvm.nativeimage.c.function.CFunction 569 | {:transition org.graalvm.nativeimage.c.function.CFunction$Transition/NO_TRANSITION}} 570 | freeTriple 571 | [wat.cool.OOTriple] 572 | void]]) 573 | 574 | ;; (comment 575 | ;; public class TripletLib { 576 | ;; @CEnum("type_t") 577 | ;; enum DataType { 578 | ;; I, 579 | ;; F, 580 | ;; S; 581 | 582 | ;; @CEnumValue 583 | ;; public native int getCValue(); 584 | 585 | ;; @CEnumLookup 586 | ;; public static native DataType fromCValue(int value); 587 | ;; } 588 | 589 | ;; @CFunction(transition = Transition.NO_TRANSITION) 590 | ;; public static native OOTriple allocRandomTriple(); 591 | 592 | ;; @CFunction(transition = Transition.NO_TRANSITION) 593 | ;; public static native void freeTriple(OOTriple triple); 594 | 595 | ;; public static long getThing(OOTriple triple) { 596 | ;; return triple.subject().getId(); 597 | ;; } 598 | ;; } 599 | ;; ) 600 | -------------------------------------------------------------------------------- /src/triple.cc: -------------------------------------------------------------------------------- 1 | #include "triple.h" 2 | 3 | static uint64_t counter = 1; 4 | 5 | extern "C" { 6 | 7 | triple_t* allocRandomTriple() { 8 | triple_t *triple = (triple_t*) malloc(sizeof(triple_t)); 9 | triple->subject.id = counter++; 10 | triple->predicate.id = counter++; 11 | triple->object.id = counter++; 12 | return triple; 13 | } 14 | 15 | void freeTriple(triple_t *triple) { 16 | free(triple); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/triple.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef enum type_t { 6 | I, 7 | F, 8 | S 9 | } type_t; 10 | 11 | typedef struct value_t { 12 | type_t type; 13 | uint64_t id; 14 | } value_t; 15 | 16 | typedef struct triple_t { 17 | value_t subject; 18 | value_t predicate; 19 | value_t object; 20 | } triple_t; 21 | --------------------------------------------------------------------------------