ããªãã«ã€ããŠã¯ç¥ããŸããããæè¿ãæ°ããJavaãã¯ãããžãŒã«é¢ããèšäºïŒGraalãTruffleãall-all-allïŒã«æéãåããŸããã 以åã«èšèªãçºæããã€ã³ã¿ããªã¿ãäœæããã©ã®èšèªãè¯ããæ²ããããé
ããããã€ãã£ãã³ã³ãã€ã©ããã³/ãŸãã¯JITããããæžããããšãåãã ãã®ããã«èŠããŸããããŸã ãããã¬ãå¿
èŠã§ã... LLVMããããããããšãããããŸãã ãã®èšäºãèªãã åŸãç¹å¥ãªçš®é¡ã®éèš³ãæžããåŸããã®ä»äºã¯ååãšããŠå®äºããããšãã§ãããšããïŒããã°ããã¹ã¯ãªïŒå°è±¡ãåããŸããã ãMake a Hurtããã¿ã³ãã³ã³ãã€ã©ããã°ã©ãã«å©çšå¯èœã«ãªã£ããšããæèŠã ãããããã¡ãããJITèšèªã¯ãã£ãããšèµ·åãããŠã©ãŒã ã¢ããããæéãå¿
èŠã§ãã ããããçµå±ã®ãšãããããã°ã©ããŒã®æéãšè³æ Œãèªç±ã§ã¯ãããŸãã-ã¢ã»ã³ãã©ãŒã§ãã¹ãŠãæžããããã©ã®ãããªæ
å ±æè¡ã®äžçã«çããã§ããããïŒ ãããããã¡ããããããããã¹ãŠãé£ãã ã§ãããïŒããã°ã©ããŒãæ瀺ãæ£ããã¬ã€ã¢ãŠãããå ŽåïŒããç©æ¥µçã«äœ¿çšãããããã°ã©ã ã®å
šäœçãªè€éãã«ã€ããŠã¯ãããã€ãã®çåããããŸã...
äžè¬ã«ããããã°ã©ããŒãè²»ããæéãšçµæãšããŠåŸããã補åã®çæ³æ§ïŒãæäœæ¥ãïŒã®ãžã¬ã³ãã§ã¯ãå¢çç·ãäžçŽã®çµããã«ç§»åã§ããããšãããç解ããŠããŸãããã®ãããä»æ¥ã§ã¯ãã€ãã£ãã³ãŒããæãçŽç²ãªåœ¢åŒã§ããŒãããã«åŸæ¥ã®SQLiteã©ã€ãã©ãªã䜿çšããããšããŠããŸãã SulongãšåŒã°ããLLVM IRã®æ¢è£œã®ããªã¥ãèšèªå®è£
ã䜿çšããŸãã
å
責äºé
ïŒãã®èšäºã¯ãåå¿è
åãã®ããåãã®ã¹ããŒãªãŒã§ã¯ãªãããã¯ãããžãŒã«æ
£ããããšããŠããã ãã®åãåå¿è
åãã®äžçš®ã®å®éšäœæ¥ãšèŠãªãã¹ãã§ãã ãããŠãã1ã€ïŒLLVM IRã¯å®å
šã«ãã©ãããã©ãŒã ã«äŸåããªããšèããããšã¯ã§ããŸããã
ãããã£ãŠãå®éã«ã¯ãSQLiteã®ãœãŒã¹ã³ãŒããååŸããæ¥ç¶ã³ãŒãã Java ScalaïŒãŸãããã¿ãŸãã...ïŒããããŠGraalVMããã€ã³ãã£ã³ã°ãšClangã§ååŸããŸãïŒããã䜿çšããŠSQLiteãLLVM IRã«ã³ã³ãã€ã«ããScalaã³ãŒãã«ããŒãããŸãïŒã
ããã«ãã¹ãŠãUbuntu 18.04 LTSïŒ64ãããïŒã§çºçããããšãäºçŽããŠãã ããã Mac OS Xã§ã¯ã倧ããªåé¡ã¯çºçããªããšä¿¡ãããããGraalãšWindowsã«å¿
èŠãªãã¹ãŠã®ã³ã³ããŒãã³ããååšãããã©ããã¯ããããªãã ãã ããçŸåšã§ã¯ãªãå Žåã§ããããããåŸã§è¡šç€ºãããŸãã
æºåãã
- å®éšçšã®ãŠãµã®SQLiteãããŠã³ããŒãããŸãïŒå®éãèšäºã«æ·»ä»ãããŠãããªããžããªã«ã¯ãã¹ãŠãæã£ãŠããŸãïŒã
- å
¬åŒã®SQLite In 5 Minutes Or Lessã®èšäºãèªãã§ãã ããã ãã®å Žåã®SQLiteã¯äŸãšããŠã®ã¿äœ¿çšããããããããããŸãã«å¿
èŠãªãã®ã§ãã SQLiteã®ã³ã³ãã€ã«æ¹æ³ã圹ç«ã¡ãŸãã
- ãããã GraalVM Community Edition ãããŠã³ããŒãããŠè§£åããŸãã æçºã«å±ããŠ
PATH
ã«è¿œå ããããšã¯ãå§ãããŸããããªããèªç¶ãšåãnode
ãšlli
ãå¿
èŠãªã®ã§ããïŒ - clangãã€ã³ã¹ããŒã«ããŸã-ç§ã®å Žåãéåžžã®Ubuntuãªããžããªã®Clang 6ã§ã
ãŸããç§ã®ãã¹ããããžã§ã¯ãã§ã¯ã sbtãã«ãã·ã¹ãã ã䜿çšããŸã ã ãããžã§ã¯ããç·šéããã«ã¯ãå人çã«ã¯æšæºã®Scalaãã©ã°ã€ã³ãåããIntelliJ Idea Communityã奜ã¿ãŸãã
ãããŠãããã§ç§ã¯å人çã«æåã®ã¬ãŒããéå§ããŸãããGraalVMã®Webãµã€ãã§ã¯ãããã¯JDKã®åãªããã£ã¬ã¯ããªã§ãããšæžãããŠããŸãã ããã ãšããã°ããããåçŽãªJDKãšããŠIdeaã«è¿œå ããŸãã ã1.8ããšIdeaã¯èšã£ãã ããŒã...å¥åŠãªã Grailããããã£ã¬ã¯ããªã®ã³ã³ãœãŒã«ã«å
¥ãbin/javac -version
æ¬åœã«1.8ãšèšãbin/javac -version
ã ãŸãã8ãªã®ã§ã8ã¯æããªãã æãã®ã¯ã org.graal
ããã±ãŒãžãšãIdeaãèŠãªããã¹ãŠã®ãã®ã§ãããããããå¿
èŠãªããšã§ãã File -> Other Settings -> Default Project Structure...
ã«ç§»åããŸããJDKèšå®ã§ãã¯ã©ã¹ãã¹ã«jre/lib
ããã³jre/lib/ext
jarãã¡ã€ã«ãå«ãŸããŠããããšãããããŸãã ãã¹ãŠãã©ãã-ãã§ãã¯ããŸããã§ããã ãããŠãç§ãã¡ãããããå¿
èŠãšãããã®ã¯æ¬¡ã®ãšããã§ãã
é衚瀺ã®ããã¹ã trosinenko@trosinenko-pc:~/tmp/graal/graalvm-1.0.0-rc1/jre/lib$ find . -name '*.jar' ./truffle/truffle-dsl-processor.jar ./truffle/truffle-api.jar ./truffle/truffle-nfi.jar ./truffle/locator.jar ./truffle/truffle-tck.jar ./polyglot/polyglot-native-api.jar ./boot/graaljs-scriptengine.jar ./boot/graal-sdk.jar ./management-agent.jar ./rt.jar ./jsse.jar ./resources.jar ./jvmci/jvmci-hotspot.jar ./jvmci/graal.jar ./jvmci/jvmci-api.jar ./installer/installer.jar ./ext/cldrdata.jar ./ext/sunjce_provider.jar ./ext/nashorn.jar ./ext/sunec.jar ./ext/zipfs.jar ./ext/sunpkcs11.jar ./ext/jaccess.jar ./ext/localedata.jar ./ext/dnsns.jar ./jce.jar ./svm/builder/objectfile.jar ./svm/builder/svm.jar ./svm/builder/pointsto.jar ./svm/library-support.jar ./graalvm/svm-driver.jar ./graalvm/launcher-common.jar ./graalvm/sulong-launcher.jar ./graalvm/graaljs-launcher.jar ./charsets.jar ./jvmci-services.jar ./security/policy/unlimited/US_export_policy.jar ./security/policy/unlimited/local_policy.jar ./security/policy/limited/US_export_policy.jar ./security/policy/limited/local_policy.jar
ããã«ãéåžžã®JDKã«è¿œå ããããã®ããå€æãããšãåèšãªã¹ãããå€ãã®ãµããã£ã¬ã¯ããªã衚瀺ãããŸã./security
ã¯èå³ããããŸããã ãã®å Žåãã+ãã¡ãœããïŒexpanded-directory-shift-click-clickãOKïŒã䜿çšããŠããµããã£ã¬ã¯ããªtruffle
ã polyglot
ã boot
ããã³graalvm
ã®å
容ãè¿œå ãboot
ã äœããèŠã€ãããªãå Žå-è¿œå ããŸã-ããã¯æ¯æ¥äœãã§ã...
Scalaã§ãããžã§ã¯ããäœæãã
ã ãããã¢ã€ãã¢ã¯èª¿æŽãããããã§ãã sbtãããžã§ã¯ããäœæããŠã¿ãŸãããã å®éãèœãšãç©Žã¯ãªãããã¹ãŠãçŽæçã§ããäž»ãªããšã¯ãæ°ããJDKã瀺ãããšãå¿ããªãããšã§ãã
æ°ããscalaãã¡ã€ã«ãäœæããŠã ã³ããŒã¢ã³ãããŒã¹ã ãã¿ãŒã²ããèšèª-LLVMããã¯ãªãã¯ããŠã Start Language Java
ã»ã¯ã·ã§ã³ã®Start Language Java
Polyglotãªãã¡ã¬ã³ã¹ãã«èšè¿°ãããã³ãŒããåµé çã«ãªãµã€ã¯ã«ããŸãã
ã¡ãªã¿ã«ãJavaScriptãRãRubyãããã«ã¯Cã®ãããªä»ã®éå§èšèªã®è±å¯ãã«æ³šæãæãããšããå§ãããŸãããããã¯ãŸã èªãã§ããªãå®å
šã«ç°ãªã話ã§ã...
object SQLiteTest { val polyglot = Context.newBuilder().allowAllAccess(true).build() val file: File = ??? val source = Source.newBuilder("llvm", file).build() val cpart = polyglot.eval(source) ??? }
App
ããobject
ãç¶æ¿ãããããã£ãŒã«ãããã©ã€ããŒãã«ãããããããšã¯ãããŸãããScalaã³ã³ãœãŒã«ããã¢ã¯ã»ã¹ã§ããŸãïŒãã®æ§æã¯æ¢ã«ãããžã§ã¯ãã«è¿œå ãããŠããŸãïŒã
ãã®çµæãã»ãŒïŒ80ïŒ
ãïŒ5ã€ã®æå³ã®ããè¡ãããµã³ãã«ãããŒã«ã¢ããããŸãããã¹ããŒã«ã«é Œã£ãŠæåŸã«èªãæéã§ãã äœãæžããŸããã ããã«ãJavadocã¯main()
åŒã³åºãã ãã§ãªããšãªãéå±ã§ãããäžè¬ã«ãã¢ãã«ã®äŸã¯SQLiteãªã®ã§ã5è¡ç®ã§ã¯ãªããäœãæžãããæ£ç¢ºã«ç解ããå¿
èŠããããŸãã Polyglotãªãã¡ã¬ã³ã¹ã¯çŽ æŽãããã§ãããAPIããã¥ã¡ã³ããå¿
èŠã§ãã ãããèŠã€ããã«ã¯ããªããžããªãæ©ãåãå¿
èŠããããŸããreadmeãããã Javadocãžã®ãªã³ã¯ãå«ãŸããŠããŸã ã
ãããŸã§ã®éãç§ãã¡ã«æžããããã®ã®æå³ã¯ãŸã æ確ã§ã¯ãããŸãããäž»ãªè³ªåãžã®åçãJSã«å°ããŸããã¢ã€ãã¢ã§Scalaã³ã³ãœãŒã«æ§æãéžæãã...
scala> import org.graalvm.polyglot.Context val polyglot = Context.newBuilder().allowAllAccess(true).build() polyglot.eval("js", "6 * 7") import org.graalvm.polyglot.Context scala> polyglot: org.graalvm.polyglot.Context = org.graalvm.polyglot.Context@68e24e7 scala> res0: org.graalvm.polyglot.Value = 42
...ãŸãããã¹ãŠãããŸããããçãã¯ã ãããŠã質åã¯èªè
ã«ç·Žç¿åé¡ãšããŠæ®ãããŸãã
ãµã³ãã«ã³ãŒãã«æ»ããŸãããã polyglot
å€æ°ã«ã¯ãããŸããŸãªèšèªãååšããã³ã³ããã¹ããå«ãŸããŸãã誰ãããªãã«ãªãã誰ãããªã³ã«ãªãã誰ãããã§ã«é
延åæåãããŠããŸãã ãã®å³ããäžçã§ã¯ããã¡ã€ã«ãžã®ã¢ã¯ã»ã¹ã§ãã£ãŠãèš±å¯ãæ±ããå¿
èŠãããããããã®äŸã§ã¯allowAllAccess(true)
ã䜿çšããŠå¶éããªãã«ã allowAllAccess(true)
ã
次ã«ãLLVMãããã³ãŒãã䜿çšããŠSourceãªããžã§ã¯ããäœæããŸãã ãã®ããœãŒã¹ã³ãŒãããããŠã³ããŒãããèšèªãšãã¡ã€ã«ã瀺ããŸãã ãŸãããœãŒã¹è¡ãçŽæ¥äœ¿çšããããšãã§ããŸãïŒãã§ã«ç¢ºèªæžã¿ã§ãïŒãURLïŒJARãã¡ã€ã«ã®ãªãœãŒã¹ãå«ãïŒãããã³java.io.Reader
ã€ã³ã¹ã¿ã³ã¹ã®ã¿ã䜿çšã§ããŸãã 次ã«ãçµæã®ãœãŒã¹ãã³ã³ããã¹ãã§èšç®ãã ValueãååŸããŸãã ãã®ã¡ãœããã®ããã¥ã¡ã³ãã«ãããšã null
ååŸããããšã¯ãããŸãããã Value
ããããããã¯Null
ã§ãã ããããç§ãã¡ã¯ãŸã ç¹å®ã®ãã®ãããŠã³ããŒãããå¿
èŠãããã®ã§...
SQLiteããã«ããã
... SQLiteã¯Oracleã®ä»£ããã§ã¯ãªããfopenïŒïŒã®ä»£ãããšèããŠãã ãã
-SQLiteã«ã€ã㊠ã ããããã®ããã«ãSQLiteãGraalVMã§å®è¡ã§ããããã«ããããšã¯ãéçºè
ã«ãšã£ãŠã²ã©ãééãã§ã¯ãããŸããã§ããã
SQLiteã®ããã¥ã¡ã³ãã®åè¿°ã®éšåã®ãã³ããšGraalã®æ瀺ã«åºã¥ããŠãã³ãã³ãã©ã€ã³ãäœæããŸãã ããã«ãããŸãïŒ
clang -g -c -O1 -emit-llvm sqlite3. \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_THREADSAFE=0 \ -o ../../sqlite3.bc
Sulongå
ã§ã³ãŒããæ£ããæ©èœããã«ã¯ãå°ãªããšã-O1
æé©åãå¿
èŠã§ãã SQLITE_OMIT_LOAD_EXTENSION
ã¯åå-g
ä¿åããŸãïŒãããã®2ã€ã®ãªãã·ã§ã³ããã³ãã®ä»ã®ãªãã·ã§ã³ã«ã€ããŠã¯ ã詳现ãããã¥ã¡ã³ããåç
§ããŠãã ããïŒããããŠãpthreadãšã®ãªã³ã¯ã¯äžæã§ãããããã¹ã¬ããã»ãŒããç¡å¹ã«ããŸãïŒããããªããšãèµ·åæã«å€±æããŸãïŒã 以äžã§ãã
ãããžã§ã¯ããç«ã¡äžããŸã
ããã§2è¡ç®ã«äœãæžãããšãã§ããŸãã
val file: File = new File("./sqlite3.bc")
ããã§ãã©ã€ãã©ãªããå¿
èŠãªé¢æ°ãååŸã§ããŸãã
val sqliteOpen = cpart.getMember("sqlite3_open") val sqliteExec = cpart.getMember("sqlite3_exec") val sqliteClose = cpart.getMember("sqlite3_close") val sqliteFree = cpart.getMember("sqlite3_free")
ãããŠããã¯æ©èœããŸã-ããããæ£ããé åºã§åŒã³åºãã ãã§ã-ãããŠããã¯ããã§ãïŒ ããšãã°ã sqlite3_open
ã¯ããã¡ã€ã«åãšæ§é äœãžã®ãã€ã³ã¿ãŒãžã®ãã€ã³ã¿ãŒãå¿
èŠã§ãïŒãã®å
éšã¯åèªããã¯ãŸã£ããèå³ããããŸããïŒã ããŒã...ãš2çªç®ã®åŒæ°ã圢æããæ¹æ³ïŒ ãã€ã³ã¿ãŒãäœæããé¢æ°ãå¿
èŠã§ã-ããããSulongåºæã®ãã®ã§ãã sulong.jar
ãã¯ã©ã¹ãã¹ã«è¿œå ããsbtã·ã§ã«å
šäœãåèµ·åããŸãã ãããŠäœããªãã sbtãããžã§ã¯ãã®ã«ãŒãïŒã¢ã³ãããŒãžãjarã®æšæºãã£ã¬ã¯ããªïŒã«lib
ãã£ã¬ã¯ããªãäœæããŠå®è¡ããã®ã«ãã©ãã»ã©è³¢ããªãã£ãã
find ../../graalvm-1.0.0-rc1/jre/languages/ -name '*.jar' -exec ln -s {} . \;
sbtãªãã¬ãã·ã¥ã®ã³ã³ãã€ã«ãæ£åžžã«å®äºããåŸã ããããäœãå§ãŸããŸãã...ããŠãã¯ã©ã¹ãã¹ããã®å Žæã«æ»ããŠããŸãã äžè¬ã«ã5è¡ç®ãè¿œå ãããšæããŸããã ããŠã5ã€ã®ããããã«ã€ããŠJavadocã玹ä»ããŸããããã¯çãèšäºã§ããã誰ãããTwitterã¯ããã«ãããŸããïŒã
ããããçŽ3æéããããŸããsqlite3_open
çªç®ã®åŒæ°ãsqlite3_open
é¢æ°ã§ã©ããããããšããŸãã...
ããæç¹ã§ããã¯ç§ã«æ°ã¥ããŸããïŒåè«ã®ããã«ããã¯å¿
èŠã§ãïŒãããªãã¯ãæŠäºãšå¹³åãã§äœãå§ããŸãããã sqlite3.c
ããèªãã§ãã ãã-ããªãã®ã¬ãã«ã®ããã ãã«ã...ãããã£ãŠã sqlite3.c
äžæçã«test.c
眮ãæããããŸãã
void f(int *x) { *x = 42; }
ããŸããŸãªã¬ãã«ã®ãã©ã€ãã·ãŒã®ããããçš®é¡ã®APIã¿ã€ãå€æã«ããå°ãã€ãŸãããã®ã§ãç§ã¯ãããæ§ããã«èšã£ãŠãç²ããŸããã åè«ã ããç§ã®é ã«æ®ã£ãã ããšãã°ããiOSã¯çŽæçãªã·ã¹ãã ã§ããç解ããã«ã¯ãããžãã¯ã¯ç¡åã§ããçŽæãå¿
èŠã§ããã 確ãã«ãGraalVMã®äž»ãªååãšãããã¹ãŠ-ãã¹ãŠãéæã§ãªã©ãã¯ã¹ããŠããå¿
èŠããããŸãããã®ãããFFIã®ããããªçµéšãæšãŠãŠã䟿å©ãªã·ã¹ãã ã®éçºè
ãšããŠèããå¿
èŠããããŸãã intã®ã³ã³ãããå¿
èŠã§ãã new java.lang.Integer(0)
-ã¬ã³ãŒãããŒãã¢ãã¬ã¹ã«æž¡ããŸãã ããããCã®åºæ¬ã§æããããããšã¯ãé
åãšãŒãèŠçŽ ãžã®ãã€ã³ã¿ãŒã®éãã¯éåžžã«arbitraryæçãªããšã§ãã å®éãé¢æ°f
åçŽã«intã®é
åãåããå€ãnullèŠçŽ ã«æžã蟌ã¿ãŸãã ç§ãã¡ã¯è©ŠããŸãïŒ
scala> val x = Array(new java.lang.Integer(12)) x: Array[Integer] = Array(12) scala> SQLiteTest.cpart.getMember("f").execute(x) res0: org.graalvm.polyglot.Value = LLVMTruffleObject(null:0) scala> x res1: Array[Integer] = Array(42)
ãããŸã!!!
ããã§ã¯ã query
é¢æ°ããã°ããèšè¿°ããŠããã§çµäºããããã«èŠãquery
ãã2çªç®ã®åŒæ°ãšããŠãããæž¡ããªãã§ãã ããïŒ Array(new Object)
ã Array(Array(new Object))
-LLVMå
éšã®strlen
ãèªã£ãŠåäœãæåŠããŸã- O_Oãããã³ãŒãïŒã¡ãªã¿ã«ãLLVM IRã¯ããŸããŸãã®éåžžã®ãã·ã³ã³ãŒããšã¯ç°ãªããéåžžã«å
žåçã§ãïŒã
nååŸã§ãã java.lang.String
ãšArray[Byte]
ãexecute()
æåã®åŒæ°ãšããŠæž¡ãã ãã§execute()
çŽæçããããšããèããæšãŠãã®ãããã void f()
äœãçŽãã§ããã確èªããŸããã
ãã®çµæãææãªåå__sulong_byte_array_to_native
æã€é¢æ°ãSulongã®çµã¿èŸŒã¿ãã€ã³ããŒïŒ SQLiteTest.polyglot.getBindings("llvm")
ïŒã§èŠã€ãããŸããã ç§ãã¡ã¯è©ŠããŸãïŒ
val str = SQLiteTest.polyglot.getBindings("llvm") .getMember("__sulong_byte_array_to_native") .execute("toc.db".getBytes) val db = new Array[Object](1) SQLiteTest.sqliteOpen.execute(str, db) scala> str: org.graalvm.polyglot.Value = LLVMTruffleObject(null:139990504321152) scala> db: Array[Object] = Array(null) scala> res0: org.graalvm.polyglot.Value = 0 scala> val str = SQLiteTest.polyglot.getBindings("llvm") .getMember("__sulong_byte_array_to_native") .execute("toc123.db".getBytes) SQLiteTest.sqliteOpen.execute(str, db) str: org.graalvm.polyglot.Value = LLVMTruffleObject(null:139990517528064) scala> res1: org.graalvm.polyglot.Value = 0
åäœããŸã!!! ããããªãééã£ããã¡ã€ã«åã§ãæ©èœããã®ã§ããïŒ..æ¯ãæ¢ããŠããããžã§ã¯ããã£ã¬ã¯ããªã調ã¹ãŸã-ãããŠãæ°ããtoc123.db
ã¯ãã§ã«toc123.db
ãŸãã ãã£ãïŒ
ããã§ãScalaã®SQLiteããã¥ã¡ã³ãããäŸãæžãæããŸãããïŒ
def query(dbFile: String, queryString: String): Unit = { val filenameStr = toCString(dbFile) val ptrToDb = new Array[Object](1) val rc = sqliteOpen.execute(filenameStr, ptrToDb) val db = ptrToDb.head if (rc.asInt() != 0) { println(s"Cannot open $dbFile: ${sqliteErrmsg.execute(db)}!") sqliteClose.execute(db) } else { val zErrMsg = new Array[Object](1) val execRc = sqliteExec.execute(db, toCString(queryString), ???, zErrMsg) if (execRc.asInt != 0) { val errorMessage = zErrMsg.head.asInstanceOf[Value] assert(errorMessage.isString) println(s"Cannot execute query: ${errorMessage.asString}") sqliteFree.execute(errorMessage) } sqliteClose.executeVoid(db) } }
é害ã¯1ã€ã ãã§ã-ç¹å®ã®ã³ãŒã«ããã¯ã§ãã ããŠã誰ãèŠãªããšããåŠçãšã³ãžãã¢ã¯ããªãŒããã³ã¢ã説æããJavaScriptã§ã³ãŒã«ããã¯ãèšè¿°ããããšããŸãã
val callback = polyglot.eval("js", """function(unused, argc, argv, azColName) { | print("argc = " + argc); | print("argv = " + argv); | print("azColName = " + azColName); | return 0; |} """.stripMargin)
ãããŠãããã«ç§ãã¡ãåŸããã®ããããŸãïŒ
io.github.trosinenko.SQLiteTest.query("toc.db", "select * from toc;") argc = 5 argv = foreign {} azColName = foreign {} argc = 5 argv = foreign {} azColName = foreign {} argc = 5 argv = foreign {} azColName = foreign {}
ãŸããéæ³ã¯ååã§ã¯ãããŸããã ããã«ã zErrMsg
ãšã©ãŒãçºçããå Žåãããèªäœãã¹ããªã³ã°ã«å€æã§ããªãå¥åŠãªãªããžã§ã¯ããååšããããšãzErrMsg
ãŸãã ããŠãå¥ã®lib.bc
åéããŠããŒããããã®ãœãŒã¹lib.c
ã«ä»¥äžãèšè¿°ããŸãã
#include <polyglot.h> void *fromCString(const char *str) { return polyglot_from_string(str, "UTF-8"); }
ãªãpolyglot_from_string
ãã€ã³ãã£ã³ã°ãä»ããŠçŽæ¥å©çšã§ããªãã®ããç解ããŠããªãã£ãã®ã§ãåŒãåºããŠãã€ã³ãã£ã³ã°ãå®è¡ããŸãã
val lib_fromCString = lib.getMember("fromCString") def fromCString(ptr: Value): String = { if (ptr.isNull) "<null>" else lib_fromCString.execute(ptr).asString() }
ããŠããšã©ãŒã¡ãã»ãŒãžãè¿ãããããšãããããŸãããããŸã Scalaã§ã³ãŒã«ããã¯ããŸãããã
val lib_copyToArray = lib.getMember("copy_to_array_from_pointers") val callback = new ProxyExecutable { override def execute(arguments: Value*): AnyRef = { val argc = arguments(1).asInt() val xargv = new Array[Long](argc) val xazColName = new Array[Long](argc) lib_copyToArray.execute(xargv, arguments(2)) lib_copyToArray.execute(xazColName, arguments(3)) (0 until argc) foreach { i => val name = fromCString(polyglot.asValue(xazColName(i) ^ 1)) val value = fromCString(polyglot.asValue(xargv(i) ^ 1)) println(s"$name = $value") } println("========================") Int.box(0) } }
åæã«ããã®ãããªéæ³ãé
åããPolyglot-ovskyã«lib.cã«è¿œå ããŸãã
void copy_to_array_from_pointers(void *arr, void **ptrs) { int size = polyglot_get_array_size(arr); for(int i = 0; i < size; ++i) { polyglot_set_array_element(arr, i, ((uintptr_t)ptrs[i]) ^ 1); } }
ãã€ã³ã¿ãŒã«æ³šæããŠãã ãã^ 1-誰ããpolyglot_set_array_element
ãããã®ã§ããããå¿
èŠã§ãïŒããªãã¡ã polyglot_set_array_element
ã¯ãããªããã£ãåãšPolyglotå€ãžã®ãã€ã³ã¿ãŒãåãå
¥ããæ£ç¢ºã«3ã€ã®åŒæ°ãæã€å¯å€é·é¢æ°ã§ãã ãã®çµæãåäœããŸãïŒ
io.github.atrosinenko.SQLiteTest.query("toc.db", "select * from toc;") name = sqlite3 type = object status = 0 title = Database Connection Handle uri = c3ref/sqlite3.html ======================== name = sqlite3_int64 type = object status = 0 title = 64-Bit Integer Types uri = c3ref/int64.html ======================== name = sqlite3_uint64 type = object status = 0 title = 64-Bit Integer Types uri = c3ref/int64.html ======================== ...
main
ã¡ãœãããè¿œå ããããã«æ®ããŸãïŒ
def main(args: Array[String]): Unit = { query(args(0), args(1)) polyglot.close() }
å®éã«ã¯ãã³ã³ããã¹ããéããå¿
èŠããããŸããã SQLiteTest
ã®åæååŸãScalaã³ã³ãœãŒã«ã«å¿
èŠãªããããªããžã§ã¯ãèªäœã§ã¯ãããè¡ããŸããã§ããã
ããã§ç§ã®è©±ã¯çµããã§ããèªè
ã«æ¬¡ã®ããšãç³ãäžããŸãã
- SubstrateVMã䜿çšããŠãScalaãååšããªããã®ããã«ãããããã¹ãŠããã€ãã£ããã€ããªã«åéããŠãã ããã
- ïŒ*ïŒåãããšãè¡ããŸããããããã¡ã€ã«ã¬ã€ãã«ããæé©åã䜿çšããŸã
çµæã®ãã¡ã€ã«ïŒ
SQLiteTest.scala package io.github.atrosinenko import java.io.File import org.graalvm.polyglot.proxy.ProxyExecutable import org.graalvm.polyglot.{Context, Source, Value} object SQLiteTest { val polyglot: Context = Context.newBuilder().allowAllAccess(true).build() def loadBcFile(file: File): Value = { val source = Source.newBuilder("llvm", file).build() polyglot.eval(source) } val cpart: Value = loadBcFile(new File("./sqlite3.bc")) val lib: Value = loadBcFile(new File("./lib.bc")) val sqliteOpen: Value = cpart.getMember("sqlite3_open") val sqliteExec: Value = cpart.getMember("sqlite3_exec") val sqliteErrmsg: Value = cpart.getMember("sqlite3_errmsg") val sqliteClose: Value = cpart.getMember("sqlite3_close") val sqliteFree: Value = cpart.getMember("sqlite3_free") val bytesToNative: Value = polyglot.getBindings("llvm").getMember("__sulong_byte_array_to_native") def toCString(str: String): Value = { bytesToNative.execute(str.getBytes()) } val lib_fromCString: Value = lib.getMember("fromCString") def fromCString(ptr: Value): String = { if (ptr.isNull) "<null>" else lib_fromCString.execute(ptr).asString() } val lib_copyToArray: Value = lib.getMember("copy_to_array_from_pointers") val callback: ProxyExecutable = new ProxyExecutable { override def execute(arguments: Value*): AnyRef = { val argc = arguments(1).asInt() val xargv = new Array[Long](argc) val xazColName = new Array[Long](argc) lib_copyToArray.execute(xargv, arguments(2)) lib_copyToArray.execute(xazColName, arguments(3)) (0 until argc) foreach { i => val name = fromCString(polyglot.asValue(xazColName(i) ^ 1)) val value = fromCString(polyglot.asValue(xargv(i) ^ 1)) println(s"$name = $value") } println("========================") Int.box(0) } } def query(dbFile: String, queryString: String): Unit = { val filenameStr = toCString(dbFile) val ptrToDb = new Array[Object](1) val rc = sqliteOpen.execute(filenameStr, ptrToDb) val db = ptrToDb.head if (rc.asInt() != 0) { println(s"Cannot open $dbFile: ${fromCString(sqliteErrmsg.execute(db))}!") sqliteClose.execute(db) } else { val zErrMsg = new Array[Object](1) val execRc = sqliteExec.execute(db, toCString(queryString), callback, Int.box(0), zErrMsg) if (execRc.asInt != 0) { val errorMessage = zErrMsg.head.asInstanceOf[Value] println(s"Cannot execute query: ${fromCString(errorMessage)}") sqliteFree.execute(errorMessage) } sqliteClose.execute(db) } } def main(args: Array[String]): Unit = { query(args(0), args(1)) polyglot.close() } }
lib.c #include <polyglot.h> void *fromCString(const char *str) { return polyglot_from_string(str, "UTF-8"); } void copy_to_array_from_pointers(void *arr, void **ptrs) { int size = polyglot_get_array_size(arr); for(int i = 0; i < size; ++i) { polyglot_set_array_element(arr, i, ((uintptr_t)ptrs[i]) ^ 1); } }
ãªããžããªãžã®ãªã³ã¯ ã