├── .clang-format ├── .clang-tidy ├── .gitignore ├── .gitmodules ├── .travis.yml ├── .vscode └── tasks.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── b9 ├── CMakeLists.txt ├── include │ └── b9 │ │ ├── ExecutionContext.hpp │ │ ├── Module.hpp │ │ ├── OperandStack.hpp │ │ ├── VirtualMachine.hpp │ │ ├── assemble.hpp │ │ ├── binaryformat.hpp │ │ ├── compiler │ │ ├── Compiler.hpp │ │ ├── GlobalTypes.hpp │ │ ├── MethodBuilder.hpp │ │ └── State.hpp │ │ ├── deserialize.hpp │ │ ├── instructions.hpp │ │ └── serialize.hpp └── src │ ├── Compiler.cpp │ ├── ExecutionContext.cpp │ ├── MethodBuilder.cpp │ ├── VirtualMachine.cpp │ ├── assemble.cpp │ ├── deserialize.cpp │ ├── primitives.cpp │ └── serialize.cpp ├── b9asm ├── CMakeLists.txt └── b9asm.cpp ├── b9disasm ├── CMakeLists.txt └── b9disasm.cpp ├── b9docker ├── dev.dockerfile └── tutorial.dockerfile ├── b9run ├── CMakeLists.txt └── main.cpp ├── cmake └── Modules │ └── FindOmr.cmake ├── docker ├── Dockerfile ├── README ├── build └── go ├── docs ├── 404.html ├── CNAME ├── Gemfile ├── Gemfile.lock ├── _config.yml ├── _data │ └── sections.yaml ├── _includes │ ├── active │ ├── chapter_list.liquid │ ├── dbg │ ├── debug.liquid │ ├── fig_img │ ├── footer.liquid │ ├── head.liquid │ ├── img │ ├── logo.liquid │ ├── nav_helpers.liquid │ ├── prev_next.liquid │ ├── side_navbar.liquid │ ├── subchapter_list.liquid │ └── top_navbar.liquid ├── _layouts │ ├── about.liquid │ ├── blog.liquid │ ├── book.liquid │ ├── chapter.liquid │ ├── content.liquid │ ├── default.liquid │ ├── doc.liquid │ ├── index.liquid │ ├── page.liquid │ └── subchapter.liquid ├── _sass │ ├── minima.scss │ ├── minima │ │ ├── _base.scss │ │ └── _layout.scss │ └── syntax-highlight.scss ├── about.md ├── assets │ ├── favicon.ico │ ├── images │ │ ├── b9backend.png │ │ ├── b9frontend.png │ │ ├── b9overview.png │ │ ├── bcStack1.png │ │ ├── bcStack2.png │ │ ├── bcStack3.png │ │ ├── bcStack4.png │ │ ├── binModFunctions.png │ │ ├── binModSections.png │ │ ├── binModStrings.png │ │ ├── downArrow.png │ │ ├── github_logo.svg │ │ ├── jitOverview.png │ │ ├── legend.png │ │ ├── logoBase9.png │ │ ├── logoIcon.png │ │ ├── logoREADME.png │ │ ├── omrOverview.png │ │ ├── perfConsole.png │ │ └── vmDesign.png │ ├── main.scss │ └── presentations │ │ ├── CASCON2017_SuperchargeALanguageRuntime.pdf │ │ ├── CUSEC2017_BuilderingAJIT.pdf │ │ ├── EclipseOMRandJitBuilder-CUSEC.pdf │ │ └── index.md ├── b9.org ├── build-a-runtime │ ├── 1-0-getting-started.md │ ├── 1-1-the-frontend-language.md │ ├── 1-2-bytecodes.md │ ├── 1-3-modules.md │ ├── 1-4-implementing-the-interpreter.md │ ├── 1-5-compiling-functions-with-jitbuilder.md │ └── index.md ├── docs │ ├── AssemblerSyntax.md │ ├── B9Assembly.md │ ├── Dictionary.md │ ├── DirectoryStructure.md │ ├── Disassembler.md │ ├── FrontendAndBinaryMod.md │ ├── index.md │ └── operators.md ├── index.md └── setup │ ├── index.md │ ├── osx.md │ └── ubuntu.md ├── js_compiler ├── README.md ├── b9stdlib.js └── compile.js ├── package.json ├── test ├── CMakeLists.txt ├── b9test.cpp ├── factorial.js ├── fib.js ├── hello.js ├── interpreter_test.js ├── simple_add.js ├── test.js ├── testAsm.cpp └── testDisasm.cpp └── third_party └── CMakeLists.txt /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | BasedOnStyle: Google 3 | 4 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | { 2 | Checks: '*' 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### B9 ### 2 | 3 | node_modules 4 | build 5 | 6 | # clang 7 | compile_commands.json 8 | 9 | ### C++ ### 10 | # Prerequisites 11 | *.d 12 | 13 | ### 14 | .vscode 15 | 16 | # Compiled Object files 17 | *.slo 18 | *.lo 19 | *.o 20 | *.obj 21 | 22 | # Precompiled Headers 23 | *.gch 24 | *.pch 25 | 26 | # Compiled Dynamic libraries 27 | *.so 28 | *.dylib 29 | *.dll 30 | 31 | # Fortran module files 32 | *.mod 33 | *.smod 34 | 35 | # Compiled Static libraries 36 | *.lai 37 | *.la 38 | *.a 39 | *.lib 40 | e 41 | *.app 42 | 43 | ### GDB ### 44 | /.gdb_history 45 | 46 | # Eclipse 47 | /.cproject 48 | /.project 49 | 50 | # Node 51 | node_modules/ 52 | 53 | 54 | # Docs and site generation 55 | docs/_site 56 | docs/.sass-cache 57 | 58 | # Other 59 | package-lock.json 60 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "omr"] 2 | path = third_party/omr 3 | url = https://github.com/b9org/omr.git 4 | branch = om 5 | [submodule "googletest"] 6 | path = third_party/googletest 7 | url = https://github.com/google/googletest.git 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: C++ 2 | sudo: false 3 | git: 4 | depth: 1 5 | addons: 6 | apt: 7 | sources: 8 | - ubuntu-toolchain-r-test 9 | packages: 10 | - g++-5 11 | os: 12 | - linux 13 | cache: 14 | ccache: true 15 | directories: 16 | - node_modules 17 | install: 18 | - npm install 19 | - pip install --user cpp-coveralls 20 | before_script: 21 | - export CXX="g++-5" 22 | - export CC="gcc-5" 23 | - export GCOV="gcov-5" 24 | script: 25 | - mkdir build && cd build 26 | - cmake -DB9_GCOV=ON .. 27 | - make -j4 || echo "*BUILD_FAILURE*" && make -j1 VERBOSE=1 28 | - ctest --output-on-failure 29 | - cd "${TRAVIS_BUILD_DIR}" 30 | after_script: 31 | - echo "Uploading code coverage report" 32 | - coveralls --exclude third_party --exclude build/third_party --exclude build/CMakeFiles --gcov $(which $GCOV) --gcov-options '\-lp' --build-root build > /dev/null 33 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "0.1.0", 5 | "command": "make", 6 | "isShellCommand": true, 7 | "args": ["b9", "gen"], 8 | "showOutput": "always" 9 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | find_program(NODE_EXECUTABLE 4 | NAMES node nodejs 5 | ) 6 | if(NOT NODE_EXECUTABLE) 7 | message(SEND_ERROR "Could not find Node executable") 8 | endif() 9 | 10 | list(APPEND CMAKE_MODULE_PATH 11 | cmake/Modules 12 | ${CMAKE_CURRENT_LIST_DIR}/third_party/omr/cmake/modules/ 13 | ) 14 | 15 | project(base9 16 | LANGUAGES C CXX 17 | VERSION 0.1 18 | ) 19 | 20 | include(OmrPlatform) 21 | 22 | # Global Configuration 23 | 24 | omr_platform_global_setup() 25 | 26 | set(CMAKE_CXX_STANDARD 14) 27 | 28 | set(CMAKE_EXPORT_COMPILE_COMMANDS true) 29 | 30 | enable_testing() 31 | 32 | # Optional debug and testing features 33 | 34 | set(B9_GCOV OFF CACHE BOOL "Run tests with gcov to gather code coverage data.") 35 | 36 | if(B9_GCOV) 37 | add_compile_options( 38 | -fprofile-arcs 39 | -ftest-coverage 40 | -O0 41 | -g 42 | ) 43 | link_libraries( 44 | -fprofile-arcs 45 | -ftest-coverage 46 | ) 47 | endif(B9_GCOV) 48 | 49 | set(B9_ASAN OFF CACHE BOOL "Build b9 with clang address sanitizer enabled.") 50 | 51 | if(B9_ASAN) 52 | add_compile_options( 53 | -fsanitize=address -fno-omit-frame-pointer 54 | ) 55 | link_libraries( 56 | -fsanitize=address 57 | ) 58 | endif(B9_ASAN) 59 | 60 | set(B9_UBSAN OFF CACHE BOOL "Build b9 with clang undefined behaviour sanitizer.") 61 | 62 | if(B9_UBSAN) 63 | add_compile_options( 64 | -fsanitize=undefined 65 | ) 66 | link_libraries( 67 | -fsanitize=undefined 68 | ) 69 | endif(B9_UBSAN) 70 | 71 | # OMR Configuration 72 | 73 | set(OMR_COMPILER ON CACHE INTERNAL "Enable the Compiler.") 74 | set(OMR_JITBUILDER ON CACHE INTERNAL "We use OMR's jitbuilder tool for the b9 JIT") 75 | set(OMR_EXAMPLE OFF CACHE INTERNAL "Disable the GC example") 76 | set(OMR_OM ON CACHE INTERNAL "Enable OMR Om, a GC object model") 77 | set(OMR_GC ON CACHE INTERNAL "Enable the GC") 78 | set(OMR_FVTEST OFF CACHE INTERNAL "Disable OMR's internal test suite, it's incompatible with b9") 79 | set(OMR_WARNINGS_AS_ERRORS OFF CACHE INTERNAL "OMR doesn't compile cleanly on my laptop :p") 80 | 81 | # Compile a b9-js *.js to C++ 82 | function(add_b9_module src) 83 | add_custom_command( 84 | OUTPUT 85 | "${CMAKE_CURRENT_BINARY_DIR}/${src}.b9mod" 86 | COMMAND 87 | ${NODE_EXECUTABLE} 88 | "${CMAKE_SOURCE_DIR}/js_compiler/compile.js" 89 | "${CMAKE_CURRENT_SOURCE_DIR}/${src}.js" 90 | "${src}.b9mod" 91 | MAIN_DEPENDENCY 92 | "${CMAKE_CURRENT_SOURCE_DIR}/${src}.js" 93 | DEPENDS 94 | "${CMAKE_SOURCE_DIR}/js_compiler/compile.js" 95 | ) 96 | add_custom_target(compile_${src} ALL 97 | DEPENDS 98 | "${CMAKE_CURRENT_BINARY_DIR}/${src}.b9mod" 99 | ) 100 | endfunction(add_b9_module) 101 | 102 | # Add a b9 test program written in b9-js 103 | function(add_b9_test test) 104 | add_b9_module("${test}") 105 | add_test( 106 | NAME "run_${test}" 107 | COMMAND b9run ${test}.b9mod 108 | ) 109 | # add_dependencies(run_${test} ${test}.b9mod) 110 | add_test( 111 | NAME "run_${test}_jit" 112 | COMMAND b9run -jit ${test}.b9mod 113 | ) 114 | add_test( 115 | NAME "run_${test}_jit_directcall" 116 | COMMAND b9run -jit -directcall ${test}.b9mod 117 | ) 118 | add_test( 119 | NAME "run_${test}_jit_passparam" 120 | COMMAND b9run -jit -directcall -passparam ${test}.b9mod 121 | ) 122 | add_test( 123 | NAME "run_${test}_jit_lazyvmstate" 124 | COMMAND b9run -jit -directcall -passparam -lazyvmstate ${test}.b9mod 125 | ) 126 | endfunction(add_b9_test) 127 | 128 | # Subdirectories 129 | 130 | add_subdirectory(b9) 131 | 132 | add_subdirectory(b9run) 133 | 134 | add_subdirectory(b9disasm) 135 | 136 | add_subdirectory(b9asm) 137 | 138 | add_subdirectory(test) 139 | 140 | add_subdirectory(third_party) 141 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | # Welcome to base9! 6 | 7 | [![Build Status](https://api.travis-ci.org/b9org/b9.svg?branch=master)](https://travis-ci.org/b9org/b9) 8 | [![Coverage Status](https://coveralls.io/repos/github/b9org/b9/badge.svg?branch=master)](https://coveralls.io/github/b9org/b9?branch=master) 9 | 10 | Base9 is an educational language runtime and programming language! We’re using it to show people how to use [Eclipse OMR] to build their own language runtime with a Just in Time (JIT) Compiler! The base9 front-end language is a simple subset of JavaScript. For more information, visit the [base9 website]. 11 | 12 | [Eclipse OMR]: https://github.com/eclipse/omr 13 | [base9 website]: https://www.base9.xyz 14 | 15 | ## Build your own Language Runtime 16 | 17 | If you'd like to build your own language runtime, visit our guide on [Building a Language Runtime]! 18 | 19 | [Building A Language Runtime]: https://www.base9.xyz/build-a-runtime 20 | 21 | ## Getting started 22 | 23 | This page contains some basic instructions to get you started. For more detailed instructions, go to: 24 | 25 | * [Ubuntu set-up page](./docs/setup/ubuntu.md). 26 | * [OSX set-up page](./docs/setup/osx.md). 27 | 28 | ### 1. Requirements 29 | 30 | To get started with base9 using the Ninja build system, you'll need the following: 31 | 32 | * `git` 33 | * `build-essential` 34 | * `nodejs` **(Minimum version 4.5.0)** 35 | * `npm` 36 | * `esprima` 37 | * `cmake` **(Minimum version 3.2.0)** 38 | * `ninja` 39 | 40 | ### 2. Clone the repository and get the submodules 41 | 42 | ```sh 43 | git clone --recursive https://github.com/b9org/b9.git 44 | ``` 45 | 46 | ### 3. Install Esprima 47 | 48 | ```sh 49 | cd b9 \ 50 | && npm install esprima 51 | ``` 52 | 53 | ### 4. Build base9 54 | 55 | ```sh 56 | mkdir build \ 57 | && cd build \ 58 | && cmake -GNinja -DCMAKE_BUILD_TYPE=Debug .. \ 59 | && ninja 60 | ``` 61 | 62 | ### 5. Run Hello World! 63 | 64 | In the `build` directory, run: 65 | 66 | ```sh 67 | ./b9run/b9run ./test/hello.b9mod 68 | ``` 69 | 70 | ### 6. Test base9 71 | 72 | You can run the full base9 test suite with: 73 | 74 | ```sh 75 | ninja test 76 | ``` 77 | -------------------------------------------------------------------------------- /b9/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(b9 SHARED 2 | src/assemble.cpp 3 | src/Compiler.cpp 4 | src/deserialize.cpp 5 | src/ExecutionContext.cpp 6 | src/MethodBuilder.cpp 7 | src/primitives.cpp 8 | src/serialize.cpp 9 | src/VirtualMachine.cpp 10 | ) 11 | 12 | target_include_directories(b9 13 | PUBLIC 14 | include/ 15 | ) 16 | 17 | target_link_libraries(b9 18 | PUBLIC 19 | jitbuilder 20 | omrgc 21 | ) 22 | -------------------------------------------------------------------------------- /b9/include/b9/ExecutionContext.hpp: -------------------------------------------------------------------------------- 1 | #if !defined(B9_EXECUTIONCONTEXT_HPP_) 2 | #define B9_EXECUTIONCONTEXT_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace b9 { 10 | 11 | class ExecutionContext { 12 | public: 13 | ExecutionContext(VirtualMachine &virtualMachine, const Config &cfg); 14 | 15 | StackElement interpret(std::size_t functionIndex); 16 | 17 | void reset(); 18 | 19 | StackElement pop(); 20 | 21 | void push(StackElement e); 22 | 23 | const OperandStack &stack() const { return stack_; } 24 | 25 | template 26 | void visit(VisitorT &visitor) { 27 | stack_.visit(visitor); 28 | } 29 | 30 | Om::RunContext &omContext() { return omContext_; } 31 | 32 | operator Om::RunContext &() { return omContext_; } 33 | 34 | operator const Om::RunContext &() const { return omContext_; } 35 | 36 | VirtualMachine *virtualMachine() const { return virtualMachine_; } 37 | 38 | // Available externally for jit-to-primitive calls. 39 | void doPrimitiveCall(Immediate value); 40 | 41 | friend std::ostream &operator<<(std::ostream &stream, 42 | const ExecutionContext &ec); 43 | 44 | private: 45 | friend class VirtualMachine; 46 | friend class ExecutionContextOffset; 47 | 48 | void doFunctionCall(Immediate value); 49 | 50 | /// A helper for interpreter-to-jit transitions. 51 | Om::Value callJitFunction(JitFunction jitFunction, std::size_t argCount); 52 | 53 | void doFunctionReturn(StackElement returnVal); 54 | 55 | Immediate doJmp(Immediate offset); 56 | 57 | void doDuplicate(); 58 | 59 | void doDrop(); 60 | 61 | void doPushFromLocal(StackElement *locals, Immediate offset); 62 | 63 | void doPopIntoLocal(StackElement *locals, Immediate offset); 64 | 65 | void doPushFromParam(StackElement *params, Immediate offset); 66 | 67 | void doPopIntoParam(StackElement *params, Immediate offset); 68 | 69 | void doIntAdd(); 70 | 71 | void doIntSub(); 72 | 73 | void doIntMul(); 74 | 75 | void doIntDiv(); 76 | 77 | void doIntPushConstant(Immediate value); 78 | 79 | void doIntNot(); 80 | 81 | Immediate doJmpEq(Immediate delta); 82 | 83 | Immediate doJmpNeq(Immediate delta); 84 | 85 | Immediate doJmpGt(Immediate delta); 86 | 87 | Immediate doJmpGe(Immediate delta); 88 | 89 | Immediate doJmpLt(Immediate delta); 90 | 91 | Immediate doJmpLe(Immediate delta); 92 | 93 | void doStrPushConstant(Immediate value); 94 | 95 | void doNewObject(); 96 | 97 | void doPushFromObject(Om::Id slotId); 98 | 99 | void doPopIntoObject(Om::Id slotId); 100 | 101 | void doCallIndirect(); 102 | 103 | void doSystemCollect(); 104 | 105 | Om::RunContext omContext_; 106 | OperandStack stack_; 107 | const Config *cfg_; 108 | VirtualMachine *virtualMachine_; 109 | Instruction *programCounter_ = 0; 110 | }; 111 | 112 | // static_assert(std::is_standard_layout::value); 113 | 114 | struct ExecutionContextOffset { 115 | static constexpr std::size_t OM_CONTEXT = 116 | offsetof(ExecutionContext, omContext_); 117 | static constexpr std::size_t STACK = offsetof(ExecutionContext, stack_); 118 | static constexpr std::size_t PROGRAM_COUNTER = 119 | offsetof(ExecutionContext, programCounter_); 120 | }; 121 | 122 | } // namespace b9 123 | 124 | #endif // B9_EXECUTIONCONTEXT_HPP_ 125 | -------------------------------------------------------------------------------- /b9/include/b9/Module.hpp: -------------------------------------------------------------------------------- 1 | #if !defined(B9_MODULE_HPP_) 2 | #define B9_MODULE_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace b9 { 13 | 14 | class Compiler; 15 | class ExecutionContext; 16 | class VirtualMachine; 17 | 18 | // Function Definition 19 | 20 | struct FunctionDef { 21 | std::string name; 22 | std::vector instructions; 23 | std::uint32_t nparams; 24 | std::uint32_t nlocals; 25 | }; 26 | 27 | inline void operator<<(std::ostream& out, const FunctionDef& f) { 28 | out << "(function \"" << f.name << "\" " << f.nparams << " " << f.nlocals; 29 | std::size_t i = 0; 30 | for (auto instruction : f.instructions) { 31 | out << std::endl << " " << i << " " << instruction; 32 | i++; 33 | } 34 | out << ")" << std::endl << std::endl; 35 | } 36 | 37 | inline bool operator==(const FunctionDef& lhs, const FunctionDef& rhs) { 38 | return lhs.name == rhs.name && lhs.nparams == rhs.nparams && 39 | lhs.nlocals == rhs.nlocals; 40 | } 41 | 42 | /// Function not found exception. 43 | struct FunctionNotFoundException : public std::runtime_error { 44 | using std::runtime_error::runtime_error; 45 | }; 46 | 47 | // Primitive Function from Interpreter call 48 | extern "C" typedef void(PrimitiveFunction)(ExecutionContext* context); 49 | 50 | /// An interpreter module. 51 | struct Module { 52 | std::vector functions; 53 | std::vector strings; 54 | 55 | std::size_t getFunctionIndex(const std::string& name) const { 56 | for (std::size_t i = 0; i < functions.size(); i++) { 57 | if (functions[i].name == name) { 58 | return i; 59 | } 60 | } 61 | throw FunctionNotFoundException{name}; 62 | } 63 | }; 64 | 65 | inline void operator<<(std::ostream& out, const Module& m) { 66 | int32_t index = 0; 67 | for (auto function : m.functions) { 68 | out << function; 69 | ++index; 70 | } 71 | for (auto string : m.strings) { 72 | out << "(string \"" << string << "\")" << std::endl; 73 | } 74 | out << std::endl; 75 | } 76 | 77 | inline bool operator==(const Module& lhs, const Module& rhs) { 78 | return lhs.functions == rhs.functions && lhs.strings == rhs.strings; 79 | } 80 | 81 | } // namespace b9 82 | 83 | #endif // B9_MODULE_HPP_ 84 | -------------------------------------------------------------------------------- /b9/include/b9/OperandStack.hpp: -------------------------------------------------------------------------------- 1 | #if !defined(B9_OPERANDSTACK_HPP_) 2 | #define B9_OPERANDSTACK_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace b9 { 11 | 12 | namespace Om = OMR::Om; 13 | 14 | using StackElement = Om::Value; 15 | 16 | class OperandStack { 17 | public: 18 | static constexpr std::size_t SIZE = 1000; 19 | 20 | OperandStack() noexcept : top_(&stack_[0]) { 21 | memset(stack_, 0, sizeof(stack_)); 22 | } 23 | 24 | void reset() { top_ = &stack_[0]; } 25 | 26 | void push(const StackElement &value) { 27 | *top_ = value; 28 | ++top_; 29 | } 30 | 31 | StackElement *pushn(std::size_t n) { 32 | memset(top_, 0, sizeof(*top_) * n); 33 | top_ += n; 34 | return top_; 35 | } 36 | 37 | StackElement pop() { 38 | --top_; 39 | return *top_; 40 | } 41 | 42 | StackElement *popn(std::size_t n) { 43 | top_ -= n; 44 | return top_; 45 | } 46 | 47 | StackElement *top() { return top_; } 48 | 49 | void drop() { --top_; } 50 | 51 | StackElement peek() const { return *(top_ - 1); } 52 | 53 | StackElement *begin() { return stack_; } 54 | 55 | StackElement *end() { return top_; } 56 | 57 | const StackElement *begin() const { return stack_; } 58 | 59 | const StackElement *end() const { return top_; } 60 | 61 | void restore(StackElement *top) { top_ = top; } 62 | 63 | template 64 | void visit(VisitorT &visitor) { 65 | for (StackElement &element : *this) { 66 | if (element.isRef()) { 67 | visitor.edge(nullptr, Om::ValueSlotHandle(&element)); 68 | } 69 | } 70 | } 71 | 72 | private: 73 | friend class OperandStackOffset; 74 | 75 | StackElement *top_; 76 | StackElement stack_[SIZE]; 77 | }; 78 | 79 | inline std::ostream &printStack(std::ostream &out, const OperandStack &stack) { 80 | out << "(stack"; 81 | 82 | for (auto e : stack) { 83 | out << std::endl << " " << e; 84 | } 85 | 86 | out << ")" << std::endl; 87 | return out; 88 | } 89 | 90 | struct OperandStackOffset { 91 | static constexpr std::size_t TOP = offsetof(OperandStack, top_); 92 | static constexpr std::size_t STACK = offsetof(OperandStack, stack_); 93 | }; 94 | 95 | } // namespace b9 96 | 97 | #endif // B9_OPERANDSTACK_HPP_ 98 | -------------------------------------------------------------------------------- /b9/include/b9/VirtualMachine.hpp: -------------------------------------------------------------------------------- 1 | #ifndef B9_VIRTUALMACHINE_HPP_ 2 | #define B9_VIRTUALMACHINE_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | extern "C" { 25 | b9::PrimitiveFunction b9_prim_print_string; 26 | b9::PrimitiveFunction b9_prim_print_number; 27 | b9::PrimitiveFunction b9_prim_print_stack; 28 | } 29 | 30 | namespace b9 { 31 | 32 | namespace Om = ::OMR::Om; 33 | 34 | class Compiler; 35 | class ExecutionContext; 36 | class VirtualMachine; 37 | 38 | struct Config { 39 | std::size_t maxInlineDepth = 0; //< The JIT's max inline depth 40 | bool jit = false; //< Enable the JIT 41 | bool directCall = false; //< Enable direct JIT to JIT calls 42 | bool passParam = false; //< Pass arguments in CPU registers 43 | bool lazyVmState = false; //< Simulate the VM state 44 | bool debug = false; //< Enable debug code 45 | bool verbose = false; //< Enable verbose printing and tracing 46 | }; 47 | 48 | inline std::ostream &operator<<(std::ostream &out, const Config &cfg) { 49 | out << std::boolalpha; 50 | out << "Mode: " << (cfg.jit ? "JIT" : "Interpreter") << std::endl 51 | << "Inline depth: " << cfg.maxInlineDepth << std::endl 52 | << "directcall: " << cfg.directCall << std::endl 53 | << "passparam: " << cfg.passParam << std::endl 54 | << "lazyvmstate: " << cfg.lazyVmState << std::endl 55 | << "debug: " << cfg.debug; 56 | out << std::noboolalpha; 57 | return out; 58 | } 59 | 60 | struct BadFunctionCallException : public std::runtime_error { 61 | using std::runtime_error::runtime_error; 62 | }; 63 | 64 | extern "C" typedef Om::RawValue (*JitFunction)(void *executionContext, ...); 65 | 66 | class VirtualMachine { 67 | public: 68 | VirtualMachine(Om::ProcessRuntime &runtime, const Config &cfg); 69 | 70 | ~VirtualMachine() noexcept; 71 | 72 | /// Load a module into the VM. 73 | void load(std::shared_ptr module); 74 | 75 | StackElement run(const std::size_t index, 76 | const std::vector &usrArgs); 77 | 78 | StackElement run(const std::string &name, 79 | const std::vector &usrArgs); 80 | 81 | const FunctionDef *getFunction(std::size_t index); 82 | 83 | PrimitiveFunction *getPrimitive(std::size_t index); 84 | 85 | JitFunction getJitAddress(std::size_t functionIndex); 86 | 87 | void setJitAddress(std::size_t functionIndex, JitFunction value); 88 | 89 | std::size_t getFunctionCount(); 90 | 91 | JitFunction generateCode(const std::size_t functionIndex); 92 | 93 | void generateAllCode(); 94 | 95 | const std::string &getString(int index); 96 | 97 | const std::shared_ptr &module() { return module_; } 98 | 99 | Om::MemorySystem &memoryManager() { return memoryManager_; } 100 | 101 | const Om::MemorySystem &memoryManager() const { return memoryManager_; } 102 | 103 | std::shared_ptr compiler() { return compiler_; } 104 | 105 | const Config &config() { return cfg_; } 106 | 107 | private: 108 | static constexpr PrimitiveFunction *const primitives_[] = { 109 | b9_prim_print_string, b9_prim_print_number, b9_prim_print_stack}; 110 | 111 | Config cfg_; 112 | Om::MemorySystem memoryManager_; 113 | std::shared_ptr compiler_; 114 | std::shared_ptr module_; 115 | std::vector compiledFunctions_; 116 | }; 117 | 118 | } // namespace b9 119 | 120 | // define C callable Interpret API for each arg call 121 | // if args are passed to the function, they are not passed 122 | // on the intepreter stack 123 | 124 | extern "C" { 125 | 126 | using namespace b9; 127 | 128 | Om::RawValue interpret(ExecutionContext *context, 129 | const std::size_t functionIndex); 130 | 131 | void primitive_call(ExecutionContext *context, Immediate value); 132 | } 133 | 134 | #endif // B9_VIRTUALMACHINE_HPP_ 135 | -------------------------------------------------------------------------------- /b9/include/b9/assemble.hpp: -------------------------------------------------------------------------------- 1 | #ifndef B9_ASSEMBLE_HPP_ 2 | #define B9_ASSEMBLE_HPP_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace b9 { 13 | 14 | void assembleStringTable(std::istream &in, std::ostream &out); 15 | 16 | void assembleInstruction(std::istream &in, std::ostream &out); 17 | 18 | void assembleFunctionData(std::istream &in, std::ostream &out); 19 | 20 | void assembleFunction(std::istream &in, std::ostream &out); 21 | 22 | void assemble(std::istream &in, std::ostream &out); 23 | 24 | } // namespace b9 25 | 26 | #endif // B9_ASSEMBLE_HPP_ 27 | -------------------------------------------------------------------------------- /b9/include/b9/binaryformat.hpp: -------------------------------------------------------------------------------- 1 | #if !defined(B9_BINARY_HPP_) 2 | #define B9_BINARYFORMAT_HPP_ 3 | 4 | #include 5 | 6 | #endif // B9_BINARYFORMAT_HPP_ 7 | -------------------------------------------------------------------------------- /b9/include/b9/compiler/Compiler.hpp: -------------------------------------------------------------------------------- 1 | #if !defined(B9_COMPILER_HPP_) 2 | #define B9_COMPILER_HPP_ 3 | 4 | #include "b9/compiler/GlobalTypes.hpp" 5 | #include "b9/instructions.hpp" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | namespace b9 { 15 | 16 | namespace Om = OMR::Om; 17 | 18 | class Config; 19 | class FunctionDef; 20 | class Stack; 21 | class VirtualMachine; 22 | class ExecutionContext; 23 | 24 | extern "C" typedef Om::RawValue (*JitFunction)(void *executionContext, ...); 25 | 26 | /// Function not found exception. 27 | struct CompilationException : public std::runtime_error { 28 | using std::runtime_error::runtime_error; 29 | }; 30 | 31 | class Compiler { 32 | public: 33 | Compiler(VirtualMachine &virtualMachine, const Config &cfg); 34 | JitFunction generateCode(const std::size_t functionIndex); 35 | 36 | const GlobalTypes &globalTypes() const { return globalTypes_; } 37 | 38 | TR::TypeDictionary &typeDictionary() { return typeDictionary_; } 39 | 40 | const TR::TypeDictionary &typeDictionary() const { return typeDictionary_; } 41 | 42 | private: 43 | TR::TypeDictionary typeDictionary_; 44 | const GlobalTypes globalTypes_; 45 | VirtualMachine &virtualMachine_; 46 | const Config &cfg_; 47 | }; 48 | 49 | } // namespace b9 50 | 51 | #endif // B9_COMPILER_HPP_ 52 | -------------------------------------------------------------------------------- /b9/include/b9/compiler/GlobalTypes.hpp: -------------------------------------------------------------------------------- 1 | #if !defined(B9_GLOBALTYPES_HPP_) 2 | #define B9_GLOBALTYPES_HPP_ 3 | 4 | #include 5 | 6 | namespace b9 { 7 | 8 | /// A collection of basic, built in types. 9 | class GlobalTypes { 10 | public: 11 | GlobalTypes(TR::TypeDictionary &td); 12 | 13 | TR::IlType *size; 14 | TR::IlType *addressPtr; 15 | TR::IlType *int64Ptr; 16 | TR::IlType *int32Ptr; 17 | TR::IlType *int16Ptr; 18 | 19 | TR::IlType *stackElement; 20 | TR::IlType *stackElementPtr; 21 | TR::IlType *instruction; 22 | TR::IlType *instructionPtr; 23 | 24 | TR::IlType *operandStack; 25 | TR::IlType *operandStackPtr; 26 | TR::IlType *executionContext; 27 | TR::IlType *executionContextPtr; 28 | }; 29 | 30 | } // namespace b9 31 | 32 | #endif // B9_GLOBALTYPES_HPP_ -------------------------------------------------------------------------------- /b9/include/b9/compiler/MethodBuilder.hpp: -------------------------------------------------------------------------------- 1 | #if !defined(B9_METHODBBUILDER_HPP_) 2 | #define B9_METHODBBUILDER_HPP_ 3 | 4 | #include "b9/VirtualMachine.hpp" 5 | #include "b9/compiler/Compiler.hpp" 6 | #include "b9/compiler/GlobalTypes.hpp" 7 | #include "b9/compiler/State.hpp" 8 | #include "b9/instructions.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace b9 { 19 | 20 | class VirtualMachine; 21 | 22 | class MethodBuilder : public TR::MethodBuilder { 23 | public: 24 | MethodBuilder(VirtualMachine &virtualMachine, 25 | const std::size_t functionIndex); 26 | 27 | virtual bool buildIL(); 28 | 29 | private: 30 | void defineFunctions(); 31 | 32 | void defineParams(); 33 | 34 | void defineLocals(); 35 | 36 | /// For a single bytecode, generate the 37 | bool generateILForBytecode( 38 | const FunctionDef *function, 39 | std::vector bytecodeBuilderTable, 40 | std::size_t instructionIndex, 41 | TR::BytecodeBuilder *jumpToBuilderForInlinedReturn); 42 | 43 | bool inlineProgramIntoBuilder( 44 | const std::size_t functionIndex, bool isTopLevel, 45 | TR::BytecodeBuilder *currentBuilder = 0, 46 | TR::BytecodeBuilder *jumpToBuilderForInlinedReturn = 0); 47 | 48 | // Helpers 49 | 50 | void pushValue(TR::BytecodeBuilder *builder, TR::IlValue *value); 51 | 52 | TR::IlValue *popValue(TR::BytecodeBuilder *builder); 53 | 54 | void pushInt48(TR::BytecodeBuilder *builder, TR::IlValue *value); 55 | 56 | void pushUint48(TR::BytecodeBuilder *builder, TR::IlValue *value); 57 | 58 | TR::IlValue *popInt48(TR::BytecodeBuilder *builder); 59 | 60 | TR::IlValue *popUint48(TR::BytecodeBuilder *builder); 61 | 62 | void drop(TR::BytecodeBuilder *builder, std::size_t n = 1); 63 | 64 | TR::IlValue *loadLocal(TR::IlBuilder *b, std::size_t index); 65 | 66 | void storeLocal(TR::IlBuilder *b, std::size_t index, TR::IlValue *value); 67 | 68 | TR::IlValue *loadParam(TR::IlBuilder *b, std::size_t index); 69 | 70 | void storeParam(TR::IlBuilder *b, std::size_t index, TR::IlValue *value); 71 | 72 | void interpreterCall(TR::BytecodeBuilder *builder, std::size_t target); 73 | 74 | void directCall(TR::BytecodeBuilder *builder, std::size_t target); 75 | 76 | void passParamCall(TR::BytecodeBuilder *builder, std::size_t target); 77 | 78 | // Bytecode Handlers 79 | 80 | void handle_bc_function_call(TR::BytecodeBuilder *builder, 81 | TR::BytecodeBuilder *nextBuilder, 82 | std::size_t target); 83 | 84 | void handle_bc_push_constant(TR::BytecodeBuilder *builder, 85 | TR::BytecodeBuilder *nextBuilder); 86 | void handle_bc_push_string(TR::BytecodeBuilder *builder, 87 | TR::BytecodeBuilder *nextBuilder); 88 | void handle_bc_drop(TR::BytecodeBuilder *builder, 89 | TR::BytecodeBuilder *nextBuilder); 90 | void handle_bc_push_from_local(TR::BytecodeBuilder *builder, 91 | TR::BytecodeBuilder *nextBuilder); 92 | void handle_bc_pop_into_local(TR::BytecodeBuilder *builder, 93 | TR::BytecodeBuilder *nextBuilder); 94 | void handle_bc_push_from_param(TR::BytecodeBuilder *builder, 95 | TR::BytecodeBuilder *nextBuilder); 96 | void handle_bc_pop_into_param(TR::BytecodeBuilder *builder, 97 | TR::BytecodeBuilder *nextBuilder); 98 | void handle_bc_sub(TR::BytecodeBuilder *builder, 99 | TR::BytecodeBuilder *nextBuilder); 100 | void handle_bc_add(TR::BytecodeBuilder *builder, 101 | TR::BytecodeBuilder *nextBuilder); 102 | void handle_bc_mul(TR::BytecodeBuilder *builder, 103 | TR::BytecodeBuilder *nextBuilder); 104 | void handle_bc_div(TR::BytecodeBuilder *builder, 105 | TR::BytecodeBuilder *nextBuilder); 106 | void handle_bc_not(TR::BytecodeBuilder *builder, 107 | TR::BytecodeBuilder *nextBuilder); 108 | void handle_bc_call(TR::BytecodeBuilder *builder, 109 | TR::BytecodeBuilder *nextBuilder); 110 | void handle_bc_jmp( 111 | TR::BytecodeBuilder *builder, 112 | const std::vector &bytecodeBuilderTable, 113 | const std::vector &program, long bytecodeIndex, 114 | TR::BytecodeBuilder *nextBuilder); 115 | void handle_bc_jmp_eq( 116 | TR::BytecodeBuilder *builder, 117 | const std::vector &bytecodeBuilderTable, 118 | const std::vector &program, long bytecodeIndex, 119 | TR::BytecodeBuilder *nextBuilder); 120 | void handle_bc_jmp_neq( 121 | TR::BytecodeBuilder *builder, 122 | const std::vector &bytecodeBuilderTable, 123 | const std::vector &program, long bytecodeIndex, 124 | TR::BytecodeBuilder *nextBuilder); 125 | void handle_bc_jmp_lt( 126 | TR::BytecodeBuilder *builder, 127 | const std::vector &bytecodeBuilderTable, 128 | const std::vector &program, long bytecodeIndex, 129 | TR::BytecodeBuilder *nextBuilder); 130 | void handle_bc_jmp_le( 131 | TR::BytecodeBuilder *builder, 132 | const std::vector &bytecodeBuilderTable, 133 | const std::vector &program, long bytecodeIndex, 134 | TR::BytecodeBuilder *nextBuilder); 135 | void handle_bc_jmp_gt( 136 | TR::BytecodeBuilder *builder, 137 | const std::vector &bytecodeBuilderTable, 138 | const std::vector &program, long bytecodeIndex, 139 | TR::BytecodeBuilder *nextBuilder); 140 | void handle_bc_jmp_ge( 141 | TR::BytecodeBuilder *builder, 142 | const std::vector &bytecodeBuilderTable, 143 | const std::vector &program, long bytecodeIndex, 144 | TR::BytecodeBuilder *nextBuilder); 145 | 146 | const GlobalTypes &globalTypes() { return globalTypes_; } 147 | 148 | VirtualMachine &virtualMachine_; 149 | const GlobalTypes &globalTypes_; 150 | const Config &cfg_; 151 | const std::size_t functionIndex_; 152 | std::vector params_; 153 | std::vector locals_; 154 | int32_t maxInlineDepth_; 155 | int32_t firstArgumentIndex = 0; 156 | }; 157 | 158 | } // namespace b9 159 | 160 | #endif // B9_METHODBBUILDER_HPP_ 161 | -------------------------------------------------------------------------------- /b9/include/b9/compiler/State.hpp: -------------------------------------------------------------------------------- 1 | #if !defined(B9_STATE_HPP_) 2 | #define B9_STATE_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace b9 { 13 | 14 | /// An interface to working with the state of the B9 execution context. 15 | class State : public TR::VirtualMachineState { 16 | public: 17 | /// Push an Om::Value onto the stack 18 | virtual void pushValue(TR::IlBuilder *, TR::IlValue *value) = 0; 19 | 20 | /// Pop an Om::Value from the stack 21 | virtual TR::IlValue *popValue(TR::IlBuilder *) = 0; 22 | 23 | /// The size of the stack has been changed as part of an external operation. 24 | /// Adjust the model to note the new size. 25 | virtual void adjust(TR::IlBuilder *b, int n) = 0; 26 | }; 27 | 28 | template 29 | State *state(BuilderT *b) { 30 | return dynamic_cast(b->vmState()); 31 | } 32 | 33 | /// State object that keeps VM structures up to date. Commit and reload are 34 | /// no-ops, since state is always written out immediately. Copy and Merge are 35 | /// also no-ops, there is no model to merge or copy. 36 | class ActiveState : public State { 37 | public: 38 | ActiveState(TR::MethodBuilder *b, const GlobalTypes &types) : types_(types) {} 39 | 40 | ActiveState(const ActiveState &) = default; 41 | 42 | /// Push a Value onto the OperandStack. Will actually update the stack. 43 | virtual void pushValue(TR::IlBuilder *b, TR::IlValue *value) override final { 44 | TR::IlValue *stack = this->stack(b); 45 | 46 | TR::IlValue *stackTop = b->LoadIndirect("b9::OperandStack", "top_", stack); 47 | 48 | b->StoreAt(stackTop, b->ConvertTo(types_.stackElement, value)); 49 | 50 | TR::IlValue *newStackTop = 51 | b->IndexAt(types_.stackElementPtr, stackTop, b->ConstInt32(1)); 52 | 53 | b->StoreIndirect("b9::OperandStack", "top_", stack, newStackTop); 54 | } 55 | 56 | /// Pop a Value from the OperandStack. Will actually update the stack. 57 | virtual TR::IlValue *popValue(TR::IlBuilder *b) override final { 58 | auto stack = this->stack(b); 59 | 60 | TR::IlValue *stackTop = b->LoadIndirect("b9::OperandStack", "top_", stack); 61 | 62 | TR::IlValue *newStackTop = 63 | b->IndexAt(types_.stackElementPtr, stackTop, b->ConstInt32(-1)); 64 | 65 | b->StoreIndirect("b9::OperandStack", "top_", stack, newStackTop); 66 | 67 | TR::IlValue *value = b->LoadAt(types_.stackElementPtr, newStackTop); 68 | 69 | return value; 70 | } 71 | 72 | virtual void adjust(TR::IlBuilder *b, int n) override final { 73 | assert(n < 1); 74 | // TODO: No way to increase stack size in model. 75 | } 76 | 77 | /// @group VirtualMachineState overrides 78 | /// @{ 79 | 80 | virtual void Commit(TR::IlBuilder *b) override final { 81 | // nothing to commit 82 | } 83 | 84 | virtual void Reload(TR::IlBuilder *b) override final { 85 | // nothing to reload 86 | } 87 | 88 | virtual VirtualMachineState *MakeCopy() override final { 89 | return new ActiveState(*this); 90 | } 91 | 92 | virtual void MergeInto(TR::VirtualMachineState *other, 93 | TR::IlBuilder *b) override final { 94 | // nothing to merge 95 | } 96 | 97 | /// @} 98 | 99 | private: 100 | TR::IlValue *stack(TR::IlBuilder *b) { 101 | return b->StructFieldInstanceAddress("b9::ExecutionContext", "stack_", 102 | b->Load("executionContext")); 103 | } 104 | 105 | const GlobalTypes &types_; 106 | }; 107 | 108 | /// Lazy VM state that only commits state on demand. 109 | /// Simulates all state of the virtual machine state while compiled code is 110 | /// running. It simulates the stack and the pointer to the top of the stack. 111 | class ModelState : public State { 112 | public: 113 | ModelState(TR::MethodBuilder *b, const GlobalTypes &types) 114 | : stack_(nullptr), stackTop_(nullptr) { 115 | stackTop_ = new TR::VirtualMachineRegisterInStruct( 116 | b, "b9::OperandStack", "stack", "top_", "stackTop"); 117 | 118 | stack_ = new TR::VirtualMachineOperandStack(b, 64, types.stackElement, 119 | stackTop_, true, 0); 120 | } 121 | 122 | ModelState(const ModelState &other) 123 | : stack_(other.stack_), stackTop_(other.stackTop_) {} 124 | 125 | /// Model a push onto the OperandStack. The Value will be saved in an 126 | /// intermediate IlValue. 127 | virtual void pushValue(TR::IlBuilder *b, TR::IlValue *value) override final { 128 | return stack_->Push(b, value); 129 | } 130 | 131 | /// Model a pop from the OperandStack. The result is an Il Value. 132 | virtual TR::IlValue *popValue(TR::IlBuilder *b) override final { 133 | return stack_->Pop(b); 134 | } 135 | 136 | virtual void adjust(TR::IlBuilder *b, int n) override final { 137 | assert(n < 1); 138 | // TODO: No way to increase stack size yet. 139 | stack_->Drop(b, -int32_t(n)); 140 | } 141 | 142 | /// @group TR::VirtualMachineState overrides 143 | /// @{ 144 | 145 | virtual void Commit(TR::IlBuilder *b) override final { 146 | stack_->Commit(b); 147 | stackTop_->Commit(b); 148 | } 149 | 150 | virtual void Reload(TR::IlBuilder *b) override final { 151 | stackTop_->Reload(b); 152 | stack_->Reload(b); 153 | } 154 | 155 | virtual TR::VirtualMachineState *MakeCopy() override final { 156 | return new ModelState(*this); 157 | } 158 | 159 | virtual void MergeInto(TR::VirtualMachineState *other, 160 | TR::IlBuilder *b) override final { 161 | MergeInto(dynamic_cast(other), b); 162 | } 163 | 164 | void MergeInto(ModelState *other, TR::IlBuilder *b) { 165 | stack_->MergeInto(other->stack_, b); 166 | stackTop_->MergeInto(other->stackTop_, b); 167 | } 168 | 169 | /// @} 170 | 171 | private: 172 | TR::VirtualMachineOperandStack *stack_; 173 | TR::VirtualMachineRegister *stackTop_; 174 | }; 175 | 176 | } // namespace b9 177 | 178 | #endif // B9_STATE_HPP_ 179 | -------------------------------------------------------------------------------- /b9/include/b9/deserialize.hpp: -------------------------------------------------------------------------------- 1 | #ifndef B9_DESERIALIZE_HPP_ 2 | #define B9_DESERIALIZE_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace b9 { 13 | 14 | struct DeserializeException : public std::runtime_error { 15 | using std::runtime_error::runtime_error; 16 | }; 17 | 18 | inline bool readBytes(std::istream &in, char *buffer, long bytes) { 19 | long count = 0; 20 | do { 21 | in.read(&buffer[count], bytes - count); 22 | count += in.gcount(); 23 | } while (count < bytes && in.good()); 24 | return count == bytes; 25 | } 26 | 27 | template 28 | bool readNumber(std::istream &in, Number &out, long bytes = sizeof(Number)) { 29 | char *buffer = (char *)&out; 30 | return readBytes(in, buffer, bytes); 31 | } 32 | 33 | void readString(std::istream &in, std::string &toRead) { 34 | uint32_t length; 35 | if (!readNumber(in, length, sizeof(length))) { 36 | throw DeserializeException{"Error reading string length"}; 37 | } 38 | for (size_t i = 0; i < length; i++) { 39 | if (in.eof()) { 40 | throw DeserializeException{"Error reading string"}; 41 | } 42 | char current = in.get(); 43 | toRead.push_back(current); 44 | } 45 | } 46 | 47 | void readStringSection(std::istream &in, std::vector &strings); 48 | 49 | bool readInstructions(std::istream &in, std::vector &instructions); 50 | 51 | void readFunctionData(std::istream &in, FunctionDef &functionSpec); 52 | 53 | void readFunction(std::istream &in, FunctionDef &functionDef); 54 | 55 | void readFunctionSection(std::istream &in, std::vector &functions); 56 | 57 | void readSection(std::istream &in, std::shared_ptr &module); 58 | 59 | void readHeader(std::istream &in, char *buffer); 60 | 61 | std::shared_ptr deserialize(std::istream &in); 62 | 63 | } // namespace b9 64 | 65 | #endif // B9_DESERIALIZE_HPP_ 66 | -------------------------------------------------------------------------------- /b9/include/b9/instructions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef B9_INSTRUCTIONS_HPP_ 2 | #define B9_INSTRUCTIONS_HPP_ 3 | 4 | #include 5 | #include 6 | 7 | namespace b9 { 8 | 9 | using RawOpCode = std::uint8_t; 10 | 11 | enum class OpCode : RawOpCode { 12 | 13 | // Generic ByteCodes 14 | 15 | // A special uninterpreted OpCode placed the end of a 16 | // OpCode array. 17 | END_SECTION = 0x0, 18 | 19 | // Call a Base9 function 20 | FUNCTION_CALL = 0x1, 21 | // Return from a function 22 | FUNCTION_RETURN = 0x2, 23 | // Call a native C function 24 | PRIMITIVE_CALL = 0x3, 25 | // Jump unconditionally by the offset 26 | JMP = 0x4, 27 | // Duplicate the top element on the stack 28 | DUPLICATE = 0x5, 29 | // Drop the top element of the stack 30 | DROP = 0x6, 31 | // Push from a local variable 32 | PUSH_FROM_LOCAL = 0x7, 33 | // Pop into a local variable 34 | POP_INTO_LOCAL = 0x8, 35 | // Push from a function parameter 36 | PUSH_FROM_PARAM = 0x9, 37 | // Pop into a function parameter 38 | POP_INTO_PARAM = 0xa, 39 | 40 | // Integer opcodes 41 | 42 | // Add two integers 43 | INT_ADD = 0xb, 44 | // Subtract two integers 45 | INT_SUB = 0xc, 46 | // Multiply two integers 47 | INT_MUL = 0xd, 48 | // Divide two integers 49 | INT_DIV = 0xe, 50 | 51 | // Push a constant 52 | INT_PUSH_CONSTANT = 0xf, 53 | // Invert a boolean value, all non-zero integers are true 54 | INT_NOT = 0x10, 55 | // Jump if two values are equal 56 | JMP_EQ = 0x11, 57 | // Jump if two values are not equal 58 | JMP_NEQ = 0x12, 59 | // Jump if the first value is greater than the second 60 | JMP_GT = 0x13, 61 | // Jump if the first value is greater than or equal to the second 62 | JMP_GE = 0x14, 63 | // Jump if the first value is less than to the second 64 | JMP_LT = 0x15, 65 | // Jump if the first value is less than or equal to the second 66 | JMP_LE = 0x16, 67 | 68 | // String ByteCodes 69 | 70 | // Push a string from this module's constant pool 71 | STR_PUSH_CONSTANT = 0x17, 72 | 73 | // Object Bytecodes 74 | 75 | NEW_OBJECT = 0x20, 76 | 77 | PUSH_FROM_OBJECT = 0x21, 78 | 79 | POP_INTO_OBJECT = 0x22, 80 | 81 | CALL_INDIRECT = 0x23, 82 | 83 | SYSTEM_COLLECT = 0x24, 84 | }; 85 | 86 | inline const char *toString(OpCode bc) { 87 | switch (bc) { 88 | case OpCode::END_SECTION: 89 | return "end_section"; 90 | case OpCode::FUNCTION_CALL: 91 | return "function_call"; 92 | case OpCode::FUNCTION_RETURN: 93 | return "function_return"; 94 | case OpCode::PRIMITIVE_CALL: 95 | return "primitive_call"; 96 | case OpCode::JMP: 97 | return "jmp"; 98 | case OpCode::DUPLICATE: 99 | return "duplicate"; 100 | case OpCode::DROP: 101 | return "drop"; 102 | case OpCode::PUSH_FROM_LOCAL: 103 | return "push_from_local"; 104 | case OpCode::POP_INTO_LOCAL: 105 | return "pop_into_local"; 106 | case OpCode::PUSH_FROM_PARAM: 107 | return "push_from_param"; 108 | case OpCode::POP_INTO_PARAM: 109 | return "pop_into_param"; 110 | case OpCode::INT_ADD: 111 | return "int_add"; 112 | case OpCode::INT_SUB: 113 | return "int_sub"; 114 | case OpCode::INT_MUL: 115 | return "int_mul"; 116 | case OpCode::INT_DIV: 117 | return "int_div"; 118 | case OpCode::INT_PUSH_CONSTANT: 119 | return "int_push_constant"; 120 | case OpCode::INT_NOT: 121 | return "int_not"; 122 | case OpCode::JMP_EQ: 123 | return "jmp_eq"; 124 | case OpCode::JMP_NEQ: 125 | return "jmp_neq"; 126 | case OpCode::JMP_GT: 127 | return "jmp_gt"; 128 | case OpCode::JMP_GE: 129 | return "jmp_ge"; 130 | case OpCode::JMP_LT: 131 | return "jmp_lt"; 132 | case OpCode::JMP_LE: 133 | return "jmp_le"; 134 | case OpCode::STR_PUSH_CONSTANT: 135 | return "str_push_constant"; 136 | case OpCode::NEW_OBJECT: 137 | return "new_object"; 138 | case OpCode::PUSH_FROM_OBJECT: 139 | return "push_from_object"; 140 | case OpCode::POP_INTO_OBJECT: 141 | return "pop_into_object"; 142 | case OpCode::CALL_INDIRECT: 143 | return "call_indirect"; 144 | case OpCode::SYSTEM_COLLECT: 145 | return "system_collect"; 146 | default: 147 | return "UNKNOWN_BYTECODE"; 148 | } 149 | } 150 | 151 | /// Print a OpCode 152 | inline std::ostream &operator<<(std::ostream &out, OpCode bc) { 153 | return out << toString(bc); 154 | } 155 | 156 | using RawInstruction = std::uint32_t; 157 | 158 | /// The 24bit immediate encoded in an instruction. Note that parameters are 159 | /// signed values, so special care must be taken to sign extend 24bits to 32. 160 | using Immediate = std::int32_t; 161 | 162 | /// A RawInstruction wrapper that will encode and decode instruction opcodes 163 | /// and immediate parameters. The Instruction layout is: 164 | /// ``` 165 | /// |0000-0000 0000-0000 0000-0000 0000-0000 166 | /// |---------| opcode (8bits) 167 | /// |-----------------------------| immediate (24bits) 168 | /// ``` 169 | /// 170 | /// For many ByteCodes, the immediate is unused and left as zero. 171 | class Instruction { 172 | public: 173 | constexpr Instruction() noexcept : raw_{0} {} 174 | 175 | constexpr Instruction(RawInstruction raw) noexcept : raw_{raw} {} 176 | 177 | constexpr Instruction(OpCode op) noexcept 178 | : raw_{RawInstruction(op) << OPCODE_SHIFT} {} 179 | 180 | constexpr Instruction(OpCode op, Immediate p) noexcept 181 | : raw_{(RawInstruction(op) << OPCODE_SHIFT) | (p & IMMEDIATE_MASK)} {} 182 | 183 | constexpr Instruction &set(OpCode op, Immediate p) noexcept { 184 | raw_ = (RawInstruction(op) << OPCODE_SHIFT) | (p & IMMEDIATE_MASK); 185 | return *this; 186 | } 187 | 188 | /// Encode the opcode 189 | constexpr Instruction &opCode(OpCode op) noexcept { 190 | raw_ = (RawInstruction(op) << OPCODE_SHIFT) | (raw_ & IMMEDIATE_MASK); 191 | return *this; 192 | } 193 | 194 | /// Decode the opcode 195 | constexpr OpCode opCode() const noexcept { 196 | return static_cast(raw_ >> OPCODE_SHIFT); 197 | } 198 | 199 | /// Encode the immediate 200 | constexpr Instruction &immediate(Immediate p) noexcept { 201 | raw_ = (raw_ & OPCODE_MASK) | (p & IMMEDIATE_MASK); 202 | return *this; 203 | } 204 | 205 | /// Decode the immediate 206 | constexpr Immediate immediate() const noexcept { 207 | auto param = static_cast(raw_ & IMMEDIATE_MASK); 208 | // Sign extend when top (24th) bit is 1 209 | if (param & 0x0080'0000) param |= 0xFF00'0000; 210 | return param; 211 | } 212 | 213 | constexpr RawInstruction raw() const noexcept { return raw_; } 214 | 215 | constexpr bool operator==(const Instruction rhs) const { 216 | return raw_ == rhs.raw_; 217 | } 218 | 219 | constexpr bool operator!=(const Instruction rhs) const { 220 | return raw_ != rhs.raw_; 221 | } 222 | 223 | private: 224 | static constexpr const RawInstruction OPCODE_SHIFT = 24; 225 | static constexpr const RawInstruction IMMEDIATE_MASK = 0x00FF'FFFF; 226 | static constexpr const RawInstruction OPCODE_MASK = ~IMMEDIATE_MASK; 227 | 228 | RawInstruction raw_; 229 | }; 230 | 231 | /// A special constant indicating the end of a sequence of instructions. 232 | /// END_SECTION should be the last element in every functions opcode array. 233 | static constexpr Instruction END_SECTION{OpCode::END_SECTION, 0}; 234 | 235 | /// Print an Instruction. 236 | inline std::ostream &operator<<(std::ostream &out, Instruction i) { 237 | out << "(" << i.opCode(); 238 | 239 | switch (i.opCode()) { 240 | // 0 immediate 241 | case OpCode::END_SECTION: 242 | case OpCode::DUPLICATE: 243 | case OpCode::FUNCTION_RETURN: 244 | case OpCode::DROP: 245 | case OpCode::INT_ADD: 246 | case OpCode::INT_SUB: 247 | case OpCode::INT_MUL: 248 | case OpCode::INT_DIV: 249 | case OpCode::INT_NOT: 250 | case OpCode::NEW_OBJECT: 251 | case OpCode::CALL_INDIRECT: 252 | case OpCode::SYSTEM_COLLECT: 253 | break; 254 | // 1 immediate 255 | case OpCode::FUNCTION_CALL: 256 | case OpCode::PRIMITIVE_CALL: 257 | case OpCode::JMP: 258 | case OpCode::PUSH_FROM_LOCAL: 259 | case OpCode::POP_INTO_LOCAL: 260 | case OpCode::PUSH_FROM_PARAM: 261 | case OpCode::POP_INTO_PARAM: 262 | case OpCode::INT_PUSH_CONSTANT: 263 | case OpCode::JMP_EQ: 264 | case OpCode::JMP_NEQ: 265 | case OpCode::JMP_GT: 266 | case OpCode::JMP_GE: 267 | case OpCode::JMP_LT: 268 | case OpCode::JMP_LE: 269 | case OpCode::STR_PUSH_CONSTANT: 270 | case OpCode::PUSH_FROM_OBJECT: 271 | case OpCode::POP_INTO_OBJECT: 272 | default: 273 | out << " " << i.immediate(); 274 | break; 275 | } 276 | return out << ")"; 277 | } 278 | 279 | } // namespace b9 280 | 281 | #endif // B9_INSTRUCTIONS_HPP_ 282 | -------------------------------------------------------------------------------- /b9/include/b9/serialize.hpp: -------------------------------------------------------------------------------- 1 | #ifndef B9_SERIALIZE_HPP_ 2 | #define B9_SERIALIZE_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace b9 { 9 | 10 | struct SerializeException : public std::runtime_error { 11 | using std::runtime_error::runtime_error; 12 | }; 13 | 14 | template 15 | bool writeNumber(std::ostream &out, const Number &n) { 16 | const long bytes = sizeof(Number); 17 | auto buffer = reinterpret_cast(&n); 18 | out.write(buffer, bytes); 19 | return out.good(); 20 | } 21 | 22 | inline void writeString(std::ostream &out, std::string toWrite) { 23 | uint32_t length = toWrite.length(); 24 | if (!writeNumber(out, length)) { 25 | throw SerializeException{"Error writing string length"}; 26 | } 27 | out << toWrite; 28 | if (!out.good()) { 29 | throw SerializeException{"Error writing string"}; 30 | } 31 | } 32 | 33 | void writeStringSection(std::ostream &out, 34 | const std::vector &strings); 35 | 36 | bool writeInstructions(std::ostream &out, 37 | const std::vector &instructions); 38 | 39 | void writeFunctionData(std::ostream &out, const FunctionDef &functionDef); 40 | 41 | void writeFunction(std::ostream &out, const FunctionDef &functionDef); 42 | 43 | void writeFunctionSection(std::ostream &out, 44 | const std::vector &functions); 45 | 46 | void writeSections(std::ostream &out, const Module &module); 47 | 48 | void writeHeader(std::ostream &out); 49 | 50 | void serialize(std::ostream &out, const Module &module); 51 | 52 | } // namespace b9 53 | 54 | #endif // B9_SERIALIZE_HPP_ 55 | -------------------------------------------------------------------------------- /b9/src/Compiler.cpp: -------------------------------------------------------------------------------- 1 | #include "b9/compiler/Compiler.hpp" 2 | #include "b9/ExecutionContext.hpp" 3 | #include "b9/VirtualMachine.hpp" 4 | #include "b9/compiler/GlobalTypes.hpp" 5 | #include "b9/compiler/MethodBuilder.hpp" 6 | #include "b9/instructions.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace b9 { 21 | 22 | GlobalTypes::GlobalTypes(TR::TypeDictionary &td) { 23 | // Core Integer Types 24 | 25 | size = td.toIlType(); 26 | addressPtr = td.PointerTo(TR::Address); 27 | int64Ptr = td.PointerTo(TR::Int64); 28 | int32Ptr = td.PointerTo(TR::Int32); 29 | int16Ptr = td.PointerTo(TR::Int16); 30 | 31 | // Basic VM Data 32 | 33 | stackElement = td.toIlType(); 34 | stackElementPtr = td.PointerTo(stackElement); 35 | 36 | instruction = td.toIlType(); 37 | instructionPtr = td.PointerTo(instruction); 38 | 39 | // VM Structures 40 | 41 | auto os = "b9::OperandStack"; 42 | operandStack = td.DefineStruct(os); 43 | td.DefineField(os, "top_", td.PointerTo(stackElementPtr), 44 | OperandStackOffset::TOP); 45 | td.DefineField(os, "stack_", stackElementPtr, OperandStackOffset::STACK); 46 | td.CloseStruct(os); 47 | 48 | operandStackPtr = td.PointerTo(operandStack); 49 | 50 | auto ec = "b9::ExecutionContext"; 51 | executionContext = td.DefineStruct(ec); 52 | // td.DefineField(ec, "omContext", ???, ExecutionContextOffset::OM_CONTEXT); 53 | td.DefineField(ec, "stack_", operandStack, ExecutionContextOffset::STACK); 54 | // td.DefineField(ec, "programCounter", ???, 55 | // ExecutionContextOffset::PROGRAM_COUNTER); 56 | td.CloseStruct(ec); 57 | 58 | executionContextPtr = td.PointerTo(executionContext); 59 | } 60 | 61 | Compiler::Compiler(VirtualMachine &virtualMachine, const Config &cfg) 62 | : typeDictionary_(), 63 | globalTypes_(typeDictionary_), 64 | virtualMachine_(virtualMachine), 65 | cfg_(cfg) {} 66 | 67 | JitFunction Compiler::generateCode(const std::size_t functionIndex) { 68 | const FunctionDef *function = virtualMachine_.getFunction(functionIndex); 69 | MethodBuilder methodBuilder(virtualMachine_, functionIndex); 70 | 71 | if (cfg_.verbose) 72 | std::cout << "MethodBuilder for function: " << function->name 73 | << " is constructed" << std::endl; 74 | 75 | uint8_t *result = nullptr; 76 | auto rc = compileMethodBuilder(&methodBuilder, &result); 77 | 78 | if (rc != 0) { 79 | std::cout << "Failed to compile function: " << function->name 80 | << " nparams: " << function->nparams << std::endl; 81 | throw b9::CompilationException{"IL generation failed"}; 82 | } 83 | 84 | if (cfg_.verbose) 85 | std::cout << "Compilation completed with return code: " << rc 86 | << ", code address: " << static_cast(result) << std::endl; 87 | 88 | return (JitFunction)result; 89 | } 90 | 91 | } // namespace b9 92 | -------------------------------------------------------------------------------- /b9/src/VirtualMachine.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace b9 { 25 | 26 | constexpr PrimitiveFunction *const VirtualMachine::primitives_[3]; 27 | 28 | VirtualMachine::VirtualMachine(Om::ProcessRuntime &runtime, const Config &cfg) 29 | : cfg_{cfg}, memoryManager_(runtime), compiler_{nullptr} { 30 | if (cfg_.verbose) std::cout << "VM initializing..." << std::endl; 31 | 32 | if (cfg_.jit) { 33 | auto ok = initializeJit(); 34 | if (!ok) { 35 | throw std::runtime_error{"Failed to init JIT"}; 36 | } 37 | 38 | compiler_ = std::make_shared(*this, cfg_); 39 | } 40 | } 41 | 42 | VirtualMachine::~VirtualMachine() noexcept { 43 | if (cfg_.jit) { 44 | shutdownJit(); 45 | } 46 | } 47 | 48 | void VirtualMachine::load(std::shared_ptr module) { 49 | module_ = module; 50 | compiledFunctions_.reserve(getFunctionCount()); 51 | } 52 | 53 | /// OpCode Interpreter 54 | 55 | JitFunction VirtualMachine::getJitAddress(std::size_t functionIndex) { 56 | if (functionIndex >= compiledFunctions_.size()) { 57 | return nullptr; 58 | } 59 | return compiledFunctions_[functionIndex]; 60 | } 61 | 62 | void VirtualMachine::setJitAddress(std::size_t functionIndex, 63 | JitFunction value) { 64 | compiledFunctions_[functionIndex] = value; 65 | } 66 | 67 | PrimitiveFunction *VirtualMachine::getPrimitive(std::size_t index) { 68 | return primitives_[index]; 69 | } 70 | 71 | const FunctionDef *VirtualMachine::getFunction(std::size_t index) { 72 | return &module_->functions[index]; 73 | } 74 | 75 | JitFunction VirtualMachine::generateCode(const std::size_t functionIndex) { 76 | try { 77 | return compiler_->generateCode(functionIndex); 78 | } catch (const CompilationException &e) { 79 | auto f = getFunction(functionIndex); 80 | std::cerr << "Warning: Failed to compile " << f << std::endl; 81 | std::cerr << " with error: " << e.what() << std::endl; 82 | return nullptr; 83 | } 84 | } 85 | 86 | const std::string &VirtualMachine::getString(int index) { 87 | return module_->strings[index]; 88 | } 89 | 90 | std::size_t VirtualMachine::getFunctionCount() { 91 | return module_->functions.size(); 92 | } 93 | 94 | void VirtualMachine::generateAllCode() { 95 | assert(cfg_.jit); 96 | auto functionIndex = 0; // 0 index for 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/_includes/head.liquid: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{ page.title | default: "Base9" }} 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/_includes/img: -------------------------------------------------------------------------------- 1 | {{ include.alt }} 6 | -------------------------------------------------------------------------------- /docs/_includes/logo.liquid: -------------------------------------------------------------------------------- 1 |
2 |

3 | 10 | 11 |

12 |
13 | -------------------------------------------------------------------------------- /docs/_includes/nav_helpers.liquid: -------------------------------------------------------------------------------- 1 | {%- comment -%} 2 | WARNING: This code assumes there is only one book-layout page. 3 | {%- endcomment -%} 4 | 5 | {%- assign all_books = site.pages | where: "layout", "book" -%} 6 | {%- assign all_chapters = site.pages | where: "layout", "chapter" -%} 7 | {%- assign all_subchapters = site.pages | where: "layout", "subchapter" -%} 8 | 9 | {%- assign book = all_books | first -%} 10 | 11 | {%- comment -%} 12 | For all pages: 13 | * page_found - true if the current page was correctly indexed 14 | * curr_chapter - current chapter object 15 | * curr_chapter_num - 1-based current chapter index 16 | * curr_chapter_idx - 0-based chapter index 17 | * curr_chapter_name - name of the current chapter (curr_chapter.name) 18 | 19 | For subchapters only: 20 | * curr_subchapter - current subchapter object (aka `page`). 21 | * curr_subchapter_num - 1-based subchapter index 22 | * curr_subchapter_idx - 0-based subchapter index 23 | * curr_subchapter_name - name of the current subchapter (page.name) 24 | {%- endcomment -%} 25 | 26 | {%- assign page_found = false -%} 27 | 28 | {%- for chapter_name in book.chapters -%} 29 | 30 | {%- assign chapter = all_chapters | where: "name", chapter_name | first -%} 31 | {%- assign chapter_num = forloop.index -%} 32 | {%- assign chapter_idx = forloop.index0 -%} 33 | 34 | {%- if chapter.name == page.name -%} 35 | {%- assign curr_chapter_name = chapter_name -%} 36 | {%- assign curr_chapter_num = chapter_num -%} 37 | {%- assign curr_chapter_idx = chapter_idx -%} 38 | {%- assign curr_chapter = chapter -%} 39 | {%- assign curr_subchapter_num = nil -%} 40 | {%- assign curr_subchapter_idx = nil -%} 41 | {%- assign page_found = true -%} 42 | {%- break -%} 43 | {%- endif -%} 44 | 45 | {%- for subchapter_name in chapter.subchapters -%} 46 | 47 | {%- assign subchapter = all_subchapters | where: "name", subchapter_name | first -%} 48 | {%- assign subchapter_num = forloop.index -%} 49 | {%- assign subchapter_idx = forloop.index0 -%} 50 | 51 | {%- if subchapter.name == page.name -%} 52 | {%- assign curr_chapter_num = chapter_num -%} 53 | {%- assign curr_chapter_idx = chapter_idx -%} 54 | {%- assign curr_chapter_name = chapter_name -%} 55 | {%- assign curr_chapter = chapter -%} 56 | {%- assign curr_subchapter_num = subchapter_num -%} 57 | {%- assign curr_subchapter_idx = subchapter_idx -%} 58 | {%- assign curr_subchapter_name = subchapter_name -%} 59 | {%- assign curr_subchapter = subchapter -%} 60 | {%- assign page_found = true -%} 61 | {%- break -%} 62 | {%- endif -%} 63 | {%- endfor -%} 64 | {%- endfor -%} 65 | 66 | {%- comment -%} 67 | * prev_chapter - object representing the previous chapter 68 | * prev_chapter_num - 1-based index of the previous chapter 69 | * prev_chapter_idx - 0-based index of the previous chapter 70 | {%- endcomment -%} 71 | 72 | {%- if 1 < curr_chapter_num -%} 73 | {%- assign prev_chapter_num = curr_chapter_num | minus: 1 -%} 74 | {%- assign prev_chapter_idx = curr_chapter_idx | minus: 1 -%} 75 | {%- assign prev_chapter_name = book.chapters[prev_chapter_idx] -%} 76 | {%- assign prev_chapter = all_chapters | where: "name", prev_chapter_name | first -%} 77 | {%- endif -%} 78 | 79 | {%- comment -%} 80 | If a previous chapter exists, and it has at least one subchapter: 81 | * prev_chapter_last_subchapter - previous chapter's last subchapter object. 82 | * prev_chapter_last_subchapter_num - the 1-based subchapter index of the previous chapter's last subchapter 83 | * prev_chapter_last_subchapter_idx - the 0-based subchapter index of the previous chapter's last subchapter 84 | {%- endcomment -%} 85 | 86 | {%- if prev_chapter and 0 < prev_chapter.subchapter.size -%} 87 | {%- assign prev_chapter_last_subchapter_name = prev_chapter.subchapters.last -%} 88 | {%- assign prev_chapter_last_subchapter_num = prev_chapter.subchapters.size -%} 89 | {%- assign prev_chapter_last_subchapter_idx = prev_chapter.subchapters.size | minus: 1 -%} 90 | {%- assign prev_chapter_last_subchapter = all_subchapters | where: "name", prev_chapter_last_subchapter_name | first -%} 91 | {%- endif -%} 92 | 93 | {%- comment -%} 94 | * next_chapter - next chapter object, or nil 95 | * next_chapter_num - 1-based index of the next chapter 96 | * next_chapter_idx - 0-based index of the next chapter 97 | {%- endcomment -%} 98 | 99 | {%- if curr_chapter_num < book.chapters.size -%} 100 | {%- assign next_chapter_num = curr_chapter_num | plus: 1 -%} 101 | {%- assign next_chapter_idx = curr_chapter_idx | plus: 1 -%} 102 | {%- assign next_chapter_name = book.chapters[next_chapter_idx] -%} 103 | {%- assign next_chapter = site.pages | where: "name", next_chapter_name | first -%} 104 | {%- endif -%} 105 | 106 | {%- comment -%} 107 | For chapters only: 108 | * first_subchapter 109 | {%- endcomment -%} 110 | 111 | {%- if page.layout == "chapter" and page.subchapters -%} 112 | {%- assign first_subchapter = all_subchapters | where: "name", page.subchapters.first | first -%} 113 | {%- else -%} 114 | {%- assign first_subchapter = nil -%} 115 | {%- endif -%} 116 | 117 | {%- comment -%} 118 | For subchapters only: 119 | * prev_subchapter - the prev subchapter object 120 | * prev_subchapter_num - the 1-based index of the prev subchapter 121 | * prev_subchapter_idx - the 0-based index of the prev subchapter 122 | * prev_subchapter_name - the name of the prev subchapter (subchapter.name) 123 | * next_subchapter - the next subchapter object 124 | * next_subchapter_num - the 1-based index of the next subchapter 125 | * next_subchapter_idx - the 0-based index of the next subchapter 126 | * next_subchapter_name - the name of the next subchapter (subchapter.name) 127 | {%- endcomment -%} 128 | 129 | {%- if page.layout == "subchapter" -%} 130 | 131 | {%- if 1 < curr_subchapter_num -%} 132 | {%- assign prev_subchapter_num = curr_subchapter_num | minus: 1 -%} 133 | {%- assign prev_subchapter_idx = curr_subchapter_idx | minus: 1 -%} 134 | {%- assign prev_subchapter_name = curr_chapter.subchapters[prev_subchapter_idx] -%} 135 | {%- assign prev_subchapter = site.pages | where: 'name', prev_subchapter_name | first -%} 136 | {%- endif -%} 137 | 138 | {%- if curr_subchapter_num < curr_chapter.subchapters.size -%} 139 | {%- assign next_subchapter_num = curr_subchapter_num | plus: 1 -%} 140 | {%- assign next_subchapter_idx = curr_subchapter_idx | plus: 1 -%} 141 | {%- assign next_subchapter_name = curr_chapter.subchapters[next_subchapter_idx] -%} 142 | {%- assign next_subchapter = site.pages | where: 'name', next_subchapter_name | first -%} 143 | {%- endif -%} 144 | 145 | {%- endif -%} 146 | 147 | {%- comment -%} 148 | For all pages: 149 | * prev_page 150 | * prev_page_chapter_num 151 | * prev_page_subchapter_num 152 | * next_page 153 | * next_page_chapter_num 154 | * next_page_subchapter_num 155 | {%- endcomment -%} 156 | 157 | {%- if page.layout == "chapter" -%} 158 | {%- if prev_chapter_last_subchapter -%} 159 | {%- assign prev_page = prev_chapter_last_subchapter -%} 160 | {%- assign prev_page_chapter_num = prev_chapter_num -%} 161 | {%- assign prev_page_subchapter_num = prev_chapter_last_subchapter_num -%} 162 | {%- elsif prev_chapter -%} 163 | {%- assign prev_page = prev_chapter -%} 164 | {%- assign prev_page_chapter_num = prev_chapter_num -%} 165 | {%- assign prev_page_subchapter_num = nil -%} 166 | {%- else -%} 167 | {%- assign prev_page = nil -%} 168 | {%- assign prev_page_chapter_num = nil -%} 169 | {%- assign prev_page_subchapter_num = nil -%} 170 | {%- endif -%} 171 | {%- endif -%} 172 | 173 | {%- if page.layout == "subchapter" -%} 174 | {%- if prev_subchapter -%} 175 | {%- assign prev_page = prev_subchapter -%} 176 | {%- assign prev_page_chapter_num = curr_chapter_num -%} 177 | {%- assign prev_page_subchapter_num = prev_subchapter_num -%} 178 | {%- elsif curr_chapter -%} 179 | {%- assign prev_page = curr_chapter -%} 180 | {%- assign prev_page_chapter_num = curr_chapter_num -%} 181 | {%- assign prev_page_subchapter_num = nil -%} 182 | {%- else -%} 183 | {%- assign prev_page = nil -%} 184 | {%- assign prev_page_chapter_num = nil -%} 185 | {%- assign prev_page_subchapter_num = nil -%} 186 | {%- endif -%} 187 | {%- endif -%} 188 | 189 | {% if page.layout == "chapter" -%} 190 | {%- if first_subchapter -%} 191 | {%- assign next_page = first_subchapter -%} 192 | {%- assign next_page_chapter_num = curr_chapter_num -%} 193 | {%- assign next_page_subchapter_num = 1 -%} 194 | {%- elsif next_chapter -%} 195 | {%- assign next_page = next_chapter -%} 196 | {%- assign next_page_chapter_num = next_chapter_num -%} 197 | {%- assign next_page_subchapter_num = nil -%} 198 | {%- else -%} 199 | {%- assign next_page = nil -%} 200 | {%- assign next_page_chapter_num = nil -%} 201 | {%- assign next_page_subchapter_num = nil -%} 202 | {%- endif -%} 203 | {%- endif -%} 204 | 205 | {%- if page.layout == "subchapter" -%} 206 | {%- if next_subchapter -%} 207 | {%- assign next_page = next_subchapter -%} 208 | {%- assign next_page_chapter_num = curr_chapter_num -%} 209 | {%- assign next_page_subchapter_num = next_subchapter_num -%} 210 | {%- elsif next_chapter -%} 211 | {%- assign next_page = next_chapter -%} 212 | {%- assign next_page_chapter_num = next_chapter_num -%} 213 | {%- assign next_page_subchapter_num = nil -%} 214 | {%- else -%} 215 | {%- assign next_page = nil -%} 216 | {%- assign next_page_chapter_num = nil -%} 217 | {%- assign next_page_subchapter_num = nil -%} 218 | {%- endif -%} 219 | {%- endif -%} 220 | -------------------------------------------------------------------------------- /docs/_includes/prev_next.liquid: -------------------------------------------------------------------------------- 1 | {%- capture prev_page_title_str -%} 2 | {%- if prev_page_chapter_num -%} 3 | {{ prev_page_chapter_num }} 4 | {%- if prev_page_subchapter_num -%} 5 | .{{ prev_page_subchapter_num }} 6 | {%- endif -%} 7 | {%- endif -%} 8 | –{{ prev_page.title }} 9 | {%- endcapture -%} 10 | 11 | {%- capture next_page_title_str -%} 12 | {%- if next_page_chapter_num -%} 13 | {{ next_page_chapter_num }} 14 | {%- if next_page_subchapter_num -%} 15 | .{{ next_page_subchapter_num }} 16 | {%- endif -%} 17 | {%- endif -%} 18 | –{{ next_page.title }} 19 | {%- endcapture -%} 20 | 21 |
22 |
23 | {% if prev_page -%} 24 | 25 | « {{ prev_page_title_str }} 26 | 27 | {%- else -%} 28 | 29 | « Contents 30 | 31 | {%- endif -%} 32 |
33 |
34 | {% if next_page -%} 35 | 36 | {{ next_page_title_str }} » 37 | 38 | {%- endif -%} 39 |
40 |
41 | -------------------------------------------------------------------------------- /docs/_includes/side_navbar.liquid: -------------------------------------------------------------------------------- 1 | {%- assign book = site.pages | where: "layout", "book" | first -%} 2 | 3 | 31 | -------------------------------------------------------------------------------- /docs/_includes/subchapter_list.liquid: -------------------------------------------------------------------------------- 1 | {% if page.subchapters -%} 2 |
3 |
4 |

Chapter Contents

5 |
6 |
7 |
8 |
9 | 17 |
18 |
19 | {% endif -%} 20 | -------------------------------------------------------------------------------- /docs/_includes/top_navbar.liquid: -------------------------------------------------------------------------------- 1 | 2 | 41 | -------------------------------------------------------------------------------- /docs/_layouts/about.liquid: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 | {%- include logo.liquid -%} 6 |
7 | {{ content }} 8 | -------------------------------------------------------------------------------- /docs/_layouts/blog.liquid: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 | {%- include logo.liquid -%} 6 | {{ content }} 7 |
8 | -------------------------------------------------------------------------------- /docs/_layouts/book.liquid: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | {%- include nav_helpers.liquid -%} 5 |
6 |
7 |
8 |

9 | {{ page.title }} 10 |

11 |
12 |
13 |
14 |
15 |
16 | {{ content }} 17 |
18 |
19 |
20 | {% include chapter_list.liquid %} 21 |
22 | -------------------------------------------------------------------------------- /docs/_layouts/chapter.liquid: -------------------------------------------------------------------------------- 1 | --- 2 | layout: content 3 | --- 4 | {%- include nav_helpers.liquid -%} 5 |
6 |
7 |

{{ curr_chapter_num }}–{{ page.title }}

8 |
9 |
10 |
11 |
12 |
13 | {{ content }} 14 |
15 |
16 |
17 | {% include subchapter_list.liquid %} 18 | -------------------------------------------------------------------------------- /docs/_layouts/content.liquid: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | {%- include nav_helpers.liquid -%} 5 |
6 |
7 | {%- include side_navbar.liquid -%} 8 |
9 | {{ content }} 10 | {% include prev_next.liquid %} 11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /docs/_layouts/default.liquid: -------------------------------------------------------------------------------- 1 | 2 | 3 | {%- include head.liquid -%} 4 | 5 | {%- include top_navbar.liquid -%} 6 | {{ content }} 7 | {%- include footer.liquid -%} 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/_layouts/doc.liquid: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | --- 4 | {{ content }} 5 | -------------------------------------------------------------------------------- /docs/_layouts/index.liquid: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 |
6 |
7 |
8 |
{%- include logo.liquid -%}
9 | {{ content }} 10 |
11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /docs/_layouts/page.liquid: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 |
6 |
7 |
8 |

{{page.title}}

9 | {{ content }} 10 |
11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /docs/_layouts/subchapter.liquid: -------------------------------------------------------------------------------- 1 | --- 2 | layout: content 3 | --- 4 | {%- include nav_helpers.liquid -%} 5 |
6 |
7 |

8 | {{ curr_chapter_num }}.{{ curr_subchapter_num }}–{{ page.title }} 9 |

10 |
11 |
12 |
13 |
14 |
15 | {{ content }} 16 |
17 |
18 |
19 | {% include subchapter_list.liquid %} 20 | -------------------------------------------------------------------------------- /docs/_sass/minima.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | // Define defaults for each variable. 4 | 5 | $base-font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !default; 6 | $base-font-size: 16px !default; 7 | $base-font-weight: 400 !default; 8 | $small-font-size: $base-font-size * 0.875 !default; 9 | $base-line-height: 1.5 !default; 10 | 11 | $spacing-unit: 30px !default; 12 | 13 | $text-color: #111 !default; 14 | $background-color: #fdfdfd !default; 15 | $brand-color: #2a7ae2 !default; 16 | 17 | $grey-color: #828282 !default; 18 | $grey-color-light: lighten($grey-color, 40%) !default; 19 | $grey-color-dark: darken($grey-color, 25%) !default; 20 | 21 | // Width of the content area 22 | $content-width: 800px !default; 23 | 24 | $on-palm: 600px !default; 25 | $on-laptop: 800px !default; 26 | 27 | // Use media queries like this: 28 | // @include media-query($on-palm) { 29 | // .wrapper { 30 | // padding-right: $spacing-unit / 2; 31 | // padding-left: $spacing-unit / 2; 32 | // } 33 | // } 34 | @mixin media-query($device) { 35 | @media screen and (max-width: $device) { 36 | @content; 37 | } 38 | } 39 | 40 | @mixin relative-font-size($ratio) { 41 | font-size: $base-font-size * $ratio; 42 | } 43 | 44 | // Import partials. 45 | @import 46 | "minima/base", 47 | "minima/layout", 48 | "minima/syntax-highlighting" 49 | ; 50 | -------------------------------------------------------------------------------- /docs/_sass/minima/_base.scss: -------------------------------------------------------------------------------- 1 | /* Website Colours */ 2 | $main: #000000; 3 | $omr-red: #af000c; 4 | $b9-yellow: #feda05; 5 | $side-nav: #e0ebeb; 6 | $top-nav: #b3cccc; 7 | $caption: #666666; 8 | $link-colour: $main; 9 | $link-hover: $main; 10 | $link-clicked: #8c8c8c; 11 | $light: #e7edf4; 12 | $header: #ffffff; 13 | 14 | 15 | %vertical-rhythm { 16 | margin-bottom: $spacing-unit / 2; 17 | } 18 | -------------------------------------------------------------------------------- /docs/_sass/minima/_layout.scss: -------------------------------------------------------------------------------- 1 | 2 | /* Defaults */ 3 | -------------------------------------------------------------------------------- /docs/_sass/syntax-highlight.scss: -------------------------------------------------------------------------------- 1 | 2 | .highlight div { 3 | padding: 20pt; 4 | } 5 | 6 | .highlight pre { 7 | border-radius: 10px; 8 | padding: 10pt; 9 | } 10 | 11 | .highlight pre { color: #f8f8f2; background-color: #272822; } 12 | .highlight .hll { background-color: #272822; } 13 | .highlight .c { color: #75715e } /* Comment */ 14 | .highlight .err { color: #960050; background-color: #1e0010 } /* Error */ 15 | .highlight .k { color: #66d9ef } /* Keyword */ 16 | .highlight .l { color: #ae81ff } /* Literal */ 17 | .highlight .n { color: #f8f8f2 } /* Name */ 18 | .highlight .o { color: #f92672 } /* Operator */ 19 | .highlight .p { color: #f8f8f2 } /* Punctuation */ 20 | .highlight .cm { color: #75715e } /* Comment.Multiline */ 21 | .highlight .cp { color: #75715e } /* Comment.Preproc */ 22 | .highlight .c1 { color: #75715e } /* Comment.Single */ 23 | .highlight .cs { color: #75715e } /* Comment.Special */ 24 | .highlight .ge { font-style: italic } /* Generic.Emph */ 25 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 26 | .highlight .kc { color: #66d9ef } /* Keyword.Constant */ 27 | .highlight .kd { color: #66d9ef } /* Keyword.Declaration */ 28 | .highlight .kn { color: #f92672 } /* Keyword.Namespace */ 29 | .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ 30 | .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ 31 | .highlight .kt { color: #66d9ef } /* Keyword.Type */ 32 | .highlight .ld { color: #e6db74 } /* Literal.Date */ 33 | .highlight .m { color: #ae81ff } /* Literal.Number */ 34 | .highlight .s { color: #e6db74 } /* Literal.String */ 35 | .highlight .na { color: #a6e22e } /* Name.Attribute */ 36 | .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ 37 | .highlight .nc { color: #a6e22e } /* Name.Class */ 38 | .highlight .no { color: #66d9ef } /* Name.Constant */ 39 | .highlight .nd { color: #a6e22e } /* Name.Decorator */ 40 | .highlight .ni { color: #f8f8f2 } /* Name.Entity */ 41 | .highlight .ne { color: #a6e22e } /* Name.Exception */ 42 | .highlight .nf { color: #a6e22e } /* Name.Function */ 43 | .highlight .nl { color: #f8f8f2 } /* Name.Label */ 44 | .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ 45 | .highlight .nx { color: #a6e22e } /* Name.Other */ 46 | .highlight .py { color: #f8f8f2 } /* Name.Property */ 47 | .highlight .nt { color: #f92672 } /* Name.Tag */ 48 | .highlight .nv { color: #f8f8f2 } /* Name.Variable */ 49 | .highlight .ow { color: #f92672 } /* Operator.Word */ 50 | .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ 51 | .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ 52 | .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ 53 | .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ 54 | .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ 55 | .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ 56 | .highlight .sc { color: #e6db74 } /* Literal.String.Char */ 57 | .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ 58 | .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ 59 | .highlight .se { color: #ae81ff } /* Literal.String.Escape */ 60 | .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ 61 | .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ 62 | .highlight .sx { color: #e6db74 } /* Literal.String.Other */ 63 | .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ 64 | .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ 65 | .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ 66 | .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ 67 | .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ 68 | .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ 69 | .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ 70 | .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ 71 | 72 | .highlight .gh { } /* Generic Heading & Diff Header */ 73 | .highlight .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */ 74 | .highlight .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */ 75 | .highlight .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */ 76 | -------------------------------------------------------------------------------- /docs/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: About Base9 3 | layout: page 4 | section: about 5 | --- 6 | 7 | Base9 is an educational [language runtime] and JavaScript [interpreter]. It's front-end language is a subset of JavaScript with limited functionality. It compiles into a simple set of [bytecodes] which run on a primitive interpreter. We've also plugged in [OMR], a language-agnostic runtime toolkit, which provides our runtime with a [JIT compiler]! Plugging in OMR is made easy with the use of [JitBuilder], a easy-to-use tool that allows you to programmatically describe the semantics of your language's bytecodes. 8 | 9 | [language runtime]: ./docs/Dictionary.md#language-runtime 10 | [bytecodes]: ./docs/Dictionary.md#bytecode 11 | [interpreter]: ./docs/Dictionary.md#interpreter 12 | [OMR]: https://www.eclipse.org/omr/ 13 | [JIT compiler]: ./docs/Dictionary.md#jit-compiler 14 | [JitBuilder]: https://developer.ibm.com/open/2016/07/19/jitbuilder-library-and-eclipse-omr-just-in-time-compilers-made-easy/ 15 | 16 | Interested in building language runtimes? Check out our [Build your own Runtime] tutorial to learn how! Or if you want to learn more about base9, visit the [base9 overview section] of the tutorial. And be sure to visit our [documentation page] for a complete listing of our docs and tutorials. 17 | 18 | [Build your own Runtime]: ./build-a-runtime/index.md 19 | [base9 overview section]: ./build-a-runtime/index.md#base9-overview 20 | [documentation page]: ./docs/index.md 21 | -------------------------------------------------------------------------------- /docs/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/favicon.ico -------------------------------------------------------------------------------- /docs/assets/images/b9backend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/b9backend.png -------------------------------------------------------------------------------- /docs/assets/images/b9frontend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/b9frontend.png -------------------------------------------------------------------------------- /docs/assets/images/b9overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/b9overview.png -------------------------------------------------------------------------------- /docs/assets/images/bcStack1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/bcStack1.png -------------------------------------------------------------------------------- /docs/assets/images/bcStack2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/bcStack2.png -------------------------------------------------------------------------------- /docs/assets/images/bcStack3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/bcStack3.png -------------------------------------------------------------------------------- /docs/assets/images/bcStack4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/bcStack4.png -------------------------------------------------------------------------------- /docs/assets/images/binModFunctions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/binModFunctions.png -------------------------------------------------------------------------------- /docs/assets/images/binModSections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/binModSections.png -------------------------------------------------------------------------------- /docs/assets/images/binModStrings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/binModStrings.png -------------------------------------------------------------------------------- /docs/assets/images/downArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/downArrow.png -------------------------------------------------------------------------------- /docs/assets/images/github_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/assets/images/jitOverview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/jitOverview.png -------------------------------------------------------------------------------- /docs/assets/images/legend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/legend.png -------------------------------------------------------------------------------- /docs/assets/images/logoBase9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/logoBase9.png -------------------------------------------------------------------------------- /docs/assets/images/logoIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/logoIcon.png -------------------------------------------------------------------------------- /docs/assets/images/logoREADME.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/logoREADME.png -------------------------------------------------------------------------------- /docs/assets/images/omrOverview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/omrOverview.png -------------------------------------------------------------------------------- /docs/assets/images/perfConsole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/perfConsole.png -------------------------------------------------------------------------------- /docs/assets/images/vmDesign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/images/vmDesign.png -------------------------------------------------------------------------------- /docs/assets/main.scss: -------------------------------------------------------------------------------- 1 | --- 2 | # Front matter comment to ensure Jekyll properly reads file. 3 | --- 4 | 5 | .h1 { 6 | margin-top: 10px; 7 | } 8 | 9 | .h2 { 10 | margin-top: 40px; 11 | } 12 | 13 | .h3 { 14 | margin-top: 100px; 15 | } 16 | 17 | @import 18 | "syntax-highlight" 19 | -------------------------------------------------------------------------------- /docs/assets/presentations/CASCON2017_SuperchargeALanguageRuntime.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/presentations/CASCON2017_SuperchargeALanguageRuntime.pdf -------------------------------------------------------------------------------- /docs/assets/presentations/CUSEC2017_BuilderingAJIT.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/presentations/CUSEC2017_BuilderingAJIT.pdf -------------------------------------------------------------------------------- /docs/assets/presentations/EclipseOMRandJitBuilder-CUSEC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/presentations/EclipseOMRandJitBuilder-CUSEC.pdf -------------------------------------------------------------------------------- /docs/assets/presentations/index.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b9org/b9/da514541c3fd41fb63d2f798b4a27de394a2dd50/docs/assets/presentations/index.md -------------------------------------------------------------------------------- /docs/b9.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Road Map 2 | 3 | * OMR Cleanup 4 | 5 | * Minor Tasks 6 | ** TODO Force set the glue component names 7 | ** TODO Port visitor scheme to OMR Marking 8 | ** TODO Remove OMR's object iterator code 9 | ** TODO Single transitionSet opimization 10 | - More than just an opti 11 | - Delay allocating the transition table potentially means less rooting during object map allocation 12 | 13 | * Version 1: Basic object features 14 | ** DONE Transition Tables 15 | ** TODO Fixed / Dynamic Slots 16 | ** TODO Split high-level public api from low-level 17 | ** TODO Write barriers 18 | ** TODO Finalization 19 | - List of objects and finalizers 20 | - Finalization calls are dispatched to threads 21 | 22 | *** TODO Expose OMR thread dispatch library to language 23 | - Possibly expose OMR work-sharing API so languages can work out their own multithreadedness in Finalization 24 | - Reuse the GC's work dispatcher for finalization 25 | 26 | * Version 2: Java-style classes 27 | ** TODO Typed, variable width slots 28 | ** TODO Fat Object Maps 29 | - Merge SlotMap, ObjectMap, EmptyObjectMap to one type. 30 | 31 | * Version 3: Jit 32 | ** TODO Jit Integration 33 | 34 | * Version 4: Arrays 35 | ** TODO Array Objects 36 | 37 | * Version 5: Threading and atomics 38 | ** Atomic sets/gets 39 | ** Object Locks 40 | ** Shared heap lock 41 | 42 | * Version 6 43 | ** TODO Constructors and construction sites 44 | *** TODO Slack Tracking 45 | *** TODO Root Constructors 46 | 47 | * Version 7: Dictionary Objects 48 | ** TODO Dictionary Objects 49 | 50 | * Problems 51 | ** Rooting 52 | *** Rooting through Value-slots 53 | *** Rooting a prexisting pointer sloti 54 | 55 | ``` 56 | 57 | for (const Map& map : object->mapHierachy()) { 58 | for (const SlotLookup& slot : map->slotRange()) { 59 | switch(slot.desc.type().coreType()) { 60 | case CoreType::REF: 61 | edge.mark() 62 | case CoreType::VALUE: 63 | return handleValue(); 64 | } 65 | object->access(slot); 66 | 67 | } 68 | } -------------------------------------------------------------------------------- /docs/build-a-runtime/1-0-getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: chapter 3 | title: Base9 4 | subchapters: 5 | - 1-1-the-frontend-language.md 6 | - 1-2-bytecodes.md 7 | - 1-3-modules.md 8 | - 1-4-implementing-the-interpreter.md 9 | - 1-5-compiling-functions-with-jitbuilder.md 10 | --- 11 | 12 | Before getting started, you should [get yourself set up]. We're going 13 | to use it throughout the tutorial to explore and learn about language runtime 14 | concepts. Don't forget to read [about base9] before getting started. 15 | 16 | [get yourself setup with base9]: ../setup/index.md 17 | [about base9]: ../about.md 18 | 19 | ## Base 9 20 | 21 | Base9 has several major components that we'll discuss throughout the course of this tutorial. We'll provide insight about design decisions and implementation. Many of the design and implementation decisions were made based on the specific needs of the project. You may wish to deviate from these decisions along the way in order to best suit your own project. 22 | 23 | {%include fig_img src="b9overview.png" %} 24 | 25 | The above diagram details the two high-level components of the base9 architecture: the [ahead-of-time compilation] (AOT) and the [virtual machine] (VM) units. The AOT unit runs the frontend language through the frontend compiler (the base9 frontend language is a primitive subset of JavaScript). The frontend compiler outputs the [bytecodes] to be consumed by the VM. The VM (or runtime unit) will either execute tbe bytecodes one by one using the [interpreter], or it can employ the [JIT compiler] to produce optimized native machine code. 26 | 27 | [ahead-of-time compilation]: ../docs/Dictionary.md#ahead-of-time-compilation 28 | [virtual machine]: ../docs/Dictionary.md#virtual-machine 29 | [bytecodes]: ../docs/Dictionary.md#bytecode 30 | [interpreter]: ../docs/Dictionary.md#interpreter 31 | [JIT compiler]: ../docs/Dictionary.md#jit-compiler 32 | 33 | ## OMR and JitBuilder 34 | 35 | [OMR] is an open source and reusable C++ library for building language runtimes. It is designed to run on many different hardware and operating system platforms. It contains a JIT compiler, garbage collection, a platform porting library, a thread library, diagnostic services, and monitoring services. It's language agnostic functionality allows developers to easily bootstrap their own language runtimes. It is most notably employed in [OpenJ9], IBM's open sourced Java Virtual Machine, but has also been integrated with Ruby, CSOM, Lua, Swift, and Rosie Pattern Language. 36 | 37 | [OMR]: https://www.eclipse.org/omr/ 38 | [OpenJ9]: https://www.eclipse.org/openj9/ 39 | 40 | {% include fig_img src="omrOverview.png" cap="OMR Overview" %} 41 | 42 | The above diagram depicts the base9 components in yellow. These are the components that a developer must implement independantly. The red areas are the components belonging to OMR. 43 | 44 | ## JitBuilder 45 | 46 | [JitBuilder] is an interface to the JIT compiler technology in OMR. It's designed to bootstrap a native-code JIT compiler for interpreted methods, and it allows the user to programatically describe the [intermediate language] (IL) that implements the semantics of the bytecodes. Using JitBuilder to employ the OMR JIT is not strictly necessary, but without it, one would require a deep understanding of JIT Compilation. JitBuilder makes it possible for someone without a background in compilers to easily plug-in and use the JIT compiler for their runtime. 47 | 48 | [JitBuilder]: https://developer.ibm.com/open/2016/07/19/jitbuilder-library-and-eclipse-omr-just-in-time-compilers-made-easy/ 49 | [intermediate language]: ../docs/Dictionary.md#intermediate-language 50 | 51 | -------------------------------------------------------------------------------- /docs/build-a-runtime/1-1-the-frontend-language.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: subchapter 3 | title: The Frontend Language 4 | --- 5 | 6 | ## Frontend 7 | 8 | {% include fig_img src="b9frontend.png" %} 9 | 10 | ### Frontend Language 11 | 12 | Our frontend language is a primitive subset of JavaScript. Let's have a look at some code: 13 | 14 | ```js 15 | b9PrintString("Hello World!"); 16 | ``` 17 | 18 | `b9PrintString` is a method from a tiny library of functions that will be compiled with every program, called `b9stdlib`. This library acts as a kind of prelude . The library is called b9stdlib and can be found in [b9/js_compiler/b9stdlib.js]. The functions in b9stdlib all call base9 [primitive functions]. In the Hello, World! program, Our script uses `b9PrintString` from b9stdlib to write text to console. 19 | 20 | [test/hello.js]: https://github.com/b9org/b9/blob/master/test/hello.js 21 | [primitive functions]: ../docs/Dictionary.md#primitive-function 22 | [b9/js_compiler/b9stdlib.js]: https://github.com/b9org/b9/blob/master/js_compiler/b9stdlib.js 23 | 24 | ### Frontend Compiler 25 | 26 | The frontend compiler is in [js_compiler/compiler.js]. It takes the source code and uses [Esprima] to convert the program into an [abstract syntax tree] (or AST). The frontend compiler walks the AST and converts it into a portable binary format. This portable binary format is represented as a [binary module]. 27 | 28 | [js_compiler/compiler.js]: https://github.com/b9org/b9/blob/master/js_compiler/compile.js 29 | [frontend compiler]: https://github.com/b9org/b9/blob/master/js_compiler/compile.js 30 | [Esprima]: http://esprima.org 31 | [abstract syntax tree]: https://en.wikipedia.org/wiki/Abstract_syntax_tree 32 | [binary module]: ../docs/Dictionary.md#binary-module 33 | 34 | For a brief overview of the frontend compiler, as well as a more in depth look at the binary module, visit the link below: 35 | 36 | [Frontend Compiler and Binary Format](/docs/FrontendAndBinaryMod.md) 37 | 38 | Let’s convert the Hello, World! program to its binary format by running it through the frontend compiler. Hello, World! is in [b9/test/hello.js]. 39 | 40 | [b9/test/hello.js]: https://github.com/b9org/b9/blob/master/test/hello.js 41 | 42 | From the root directory, run: 43 | 44 | `node js_compiler/compile.js test/hello.js hello.b9mod` 45 | 46 | The above command will run the frontend compiler on `test/hello.js` and output a binary module with the name `hello.b9mod`. If you run the above command, you'll see `hello.b9mod` in the base9 root directory. The `.b9mod` files are in raw hexadecimal format, and are legible using a hex editor like `dhex`. 47 | -------------------------------------------------------------------------------- /docs/build-a-runtime/1-2-bytecodes.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: subchapter 3 | title: Bytecodes 4 | --- 5 | 6 | ## Backend 7 | 8 | {%include fig_img src="b9backend.png" %} 9 | 10 | Let's explore the VM design in greater detail. 11 | 12 | {%include fig_img src="vmDesign.png" %} 13 | 14 | The above diagram shows the components of the VM in detail. The VM takes the binary module and uses the deserializer to convert it into an in-memory Module containing the bytecodes. After the conversion, the VM will employ either the interpreter or the JIT to run the program. The interpreter processes the bytecodes directly and one at a time. The JIT converts the bytecodes to native machine code and returns a function pointer. Once a program is JIT compiled, the bytecodes are no longer interpreted. Instead, the JIT compiled version is always executed. Currently, when we run the JIT, we employ user flags to tell the VM to JIT compile an entire program and to interpret nothing. 15 | 16 | 17 | ### Bytecodes 18 | 19 | The base9 instruction set is stack oriented, which allows for straight-forward compilation and simple VM implementation. All instructions operate on the operand stack, which can be thought of as the VM's memory. One advantage of a stack-based instruction set over a register-based model is that stack-based instructions are smaller, with no need for a register immediate. One disadvantage is that the total number of instructions is larger. For more information on the difference between stack and register based virtual machines, you can [read this article on the internet]. 20 | 21 | [read this article on the internet]: https://markfaction.wordpress.com/2012/07/15/stack-based-vs-register-based-virtual-machine-architecture-and-the-dalvik-vm/ 22 | 23 | All of the base9 bytecodes are fixed-width. This puts constraints on what we can encode in the instructions, but it simplifies instruction decoding and jumps. 24 | 25 | Finally, the base9 instruction set is untyped. This means that the bytecodes can operate on values of varying types. The way this works is by popping the operands off the operand stack, checking their types, and doing the correct operation once the type is known. 26 | 27 | All base9 bytecodes are defined in [b9/include/b9/instructions.hpp]. 28 | 29 | [b9/include/b9/instructions.hpp]: https://github.com/b9org/b9/blob/master/b9/include/b9/instructions.hpp 30 | 31 | ### The Operand Stack 32 | 33 | As mentioned, the base9 bytecodes are stack oriented. Let's take a look at what happens with the operand stack during a simple addition function: 34 | 35 | ```js 36 | function simple_add() { 37 | return 5 + 6; 38 | } 39 | ``` 40 | 41 | The following diagrams display the bytecodes generated from the "simple_add()" function. 42 | 43 | **IP** = Instruction Pointer 44 | 45 | **SP** = Stack Pointer 46 | 47 | Push 5 onto the operand stack: 48 | 49 | {%include fig_img src="bcStack1.png" %} 50 | 51 | Push 6 onto the operand stack: 52 | 53 | {%include fig_img src="bcStack2.png" %} 54 | 55 | Pop 5 and 6 off that stack, add them, push the result to the operand stack: 56 | 57 | {%include fig_img src="bcStack3.png" %} 58 | 59 | Pop and return the result from the operand stack: 60 | 61 | {%include fig_img src="bcStack4.png" %} 62 | 63 | ### The Deserializer 64 | 65 | The base9 [deserializer] at [b9/src/deserialize.cpp] is responsible for taking the binary module and converting it to the in-memory Module. The deserializer is used in base9 in two different ways. Firstly, it's used by the VM to convert a binary module to an in-memory Module. Secondly, it is used by the disassembler at [b9/b9disasm/b9disasm.cpp]. The disassembler employs the deserializer to convert a binary module into an assembly-like interpretation, which we're calling [base9 assembly]. It's primarily used for debugging. Click the link below to learn more: 66 | 67 | [deserializer]: ../docs/Dictionary.md#deserializer 68 | [b9/src/deserialize.cpp]: https://github.com/b9org/b9/blob/master/b9/src/deserialize.cpp 69 | [b9/b9disasm/b9disasm.cpp]: https://github.com/b9org/b9/blob/master/b9disasm/b9disasm.cpp 70 | [base9 assembly]: ../docs/B9Assembly.md 71 | 72 | [Base9 Disassembler](../docs/Disassembler.md) 73 | 74 | Let's run the disassembler using the binary module we generated in the [Frontend Compiler section]! From the `build/` directory, run the following command: 75 | 76 | [Frontend Compiler section]: #frontend-compiler 77 | 78 | `b9disasm/b9disasm ../hello.b9mod` 79 | 80 | You should now be looking at a human readable version of the Hello, World! program as represented by [base9 assembly]. You'll notice that the first three functions (`b9PrintString`, `b9PrintNumber`, and `b9PrintStack`) are the b9stdlib functions that are included in each compiled program. They can be ignored. The important part is the `