├── .clang-format
├── .gitattributes
├── .github
└── workflows
│ └── unittest.yml
├── .gitignore
├── .gitmodules
├── .rgignore
├── CMakeLists.txt
├── Readme.md
├── benchmark
├── gc-stress-test.ch
└── string-concat.ch
├── build.sh
├── build_release.sh
├── clean.sh
├── debug.sh
├── debugp.sh
├── docs
├── .gitkeep
└── charly-vm.png
├── examples
└── .gitkeep
├── experiments
├── .gitignore
├── block-unwind-prototype.py
├── cooperative_threads.cpp
├── cooperative_threads_refactored.cpp
├── custom-stream.cpp
├── small-tagged-double.cpp
└── small_locks.cpp
├── format.sh
├── include
└── charly
│ ├── atomic.h
│ ├── charly.h
│ ├── debug.h
│ ├── handle.h
│ ├── symbol.h
│ ├── utf8.h
│ ├── utils
│ ├── allocator.h
│ ├── buffer.h
│ ├── cast.h
│ ├── guarded_buffer.h
│ ├── lock.h
│ ├── random_device.h
│ ├── timedsection.h
│ └── wait_flag.h
│ └── value.h
├── install.sh
├── libs
└── termcolor
│ ├── termcolor.cpp
│ └── termcolor.h
├── release.sh
├── scratch-files
├── concurrent_map.ch
├── debug.ch
├── gc-stress-test.ch
├── parsertest.ch
├── scratch.ch
└── test.ch
├── src
├── CMakeLists.txt
├── charly
│ ├── charly.cpp
│ ├── core
│ │ ├── compiler
│ │ │ ├── ast.cpp
│ │ │ ├── ast.h
│ │ │ ├── codegenerator.cpp
│ │ │ ├── codegenerator.h
│ │ │ ├── compiler.cpp
│ │ │ ├── compiler.h
│ │ │ ├── diagnostic.cpp
│ │ │ ├── diagnostic.h
│ │ │ ├── ir
│ │ │ │ ├── assembler.cpp
│ │ │ │ ├── assembler.h
│ │ │ │ ├── builder.cpp
│ │ │ │ ├── builder.h
│ │ │ │ ├── builtin.h
│ │ │ │ ├── bytecode.h
│ │ │ │ ├── functioninfo.h
│ │ │ │ ├── ir.cpp
│ │ │ │ ├── ir.h
│ │ │ │ └── valuelocation.h
│ │ │ ├── lexer.cpp
│ │ │ ├── lexer.h
│ │ │ ├── location.cpp
│ │ │ ├── location.h
│ │ │ ├── parser.cpp
│ │ │ ├── parser.h
│ │ │ ├── pass.h
│ │ │ ├── passes
│ │ │ │ ├── code_elimination.cpp
│ │ │ │ ├── code_elimination.h
│ │ │ │ ├── constant_folding_pass.cpp
│ │ │ │ ├── constant_folding_pass.h
│ │ │ │ ├── desugar_pass.cpp
│ │ │ │ ├── desugar_pass.h
│ │ │ │ ├── duplicates_check.cpp
│ │ │ │ ├── duplicates_check.h
│ │ │ │ ├── grammar_validation_check.cpp
│ │ │ │ ├── grammar_validation_check.h
│ │ │ │ ├── repl_prepare_pass.cpp
│ │ │ │ ├── repl_prepare_pass.h
│ │ │ │ ├── reserved_identifiers_check.cpp
│ │ │ │ ├── reserved_identifiers_check.h
│ │ │ │ ├── variable_analyzer_pass.cpp
│ │ │ │ └── variable_analyzer_pass.h
│ │ │ ├── passmacros.h
│ │ │ └── token.h
│ │ └── runtime
│ │ │ ├── builtins
│ │ │ ├── builtin.h
│ │ │ ├── core.cpp
│ │ │ ├── core.h
│ │ │ ├── future.cpp
│ │ │ ├── future.h
│ │ │ ├── list.cpp
│ │ │ ├── list.h
│ │ │ ├── readline.cpp
│ │ │ ├── readline.h
│ │ │ ├── timer.cpp
│ │ │ └── timer.h
│ │ │ ├── compiled_module.cpp
│ │ │ ├── compiled_module.h
│ │ │ ├── gc.cpp
│ │ │ ├── gc.h
│ │ │ ├── heap.cpp
│ │ │ ├── heap.h
│ │ │ ├── interpreter.cpp
│ │ │ ├── interpreter.h
│ │ │ ├── processor.cpp
│ │ │ ├── processor.h
│ │ │ ├── runtime.cpp
│ │ │ ├── runtime.h
│ │ │ ├── scheduler.cpp
│ │ │ ├── scheduler.h
│ │ │ ├── thread.cpp
│ │ │ ├── thread.h
│ │ │ ├── watchdog.cpp
│ │ │ ├── watchdog.h
│ │ │ ├── worker.cpp
│ │ │ └── worker.h
│ ├── handle.cpp
│ ├── stdlib
│ │ ├── boot.ch
│ │ ├── libs
│ │ │ └── unittest.ch
│ │ └── repl.ch
│ ├── utils
│ │ ├── allocator.cpp
│ │ ├── argumentparser.cpp
│ │ ├── argumentparser.h
│ │ ├── buffer.cpp
│ │ ├── colorwriter.h
│ │ └── lock.cpp
│ └── value.cpp
└── main.cpp
├── test
├── .gitkeep
├── charly
│ ├── .gitkeep
│ ├── assertion.ch
│ ├── class.ch
│ ├── control-structures.ch
│ ├── exception.ch
│ ├── fiber.ch
│ ├── function.ch
│ ├── future.ch
│ ├── globals.ch
│ ├── import-test
│ │ ├── compiler-error.ch
│ │ ├── import-test-throws.ch
│ │ └── not-readable.ch
│ ├── import.ch
│ ├── list.ch
│ ├── number.ch
│ ├── string.ch
│ ├── test.ch
│ ├── testlib.ch
│ ├── truthyness.ch
│ ├── tuple.ch
│ └── typeof-instanceof.ch
└── runtime
│ ├── .gitkeep
│ ├── core
│ └── compiler
│ │ ├── astmacros.h
│ │ ├── diagnostic.cpp
│ │ ├── module.cpp
│ │ ├── parser.cpp
│ │ ├── pass.cpp
│ │ └── semantic.cpp
│ ├── utils
│ ├── buffer.cpp
│ ├── cast.cpp
│ ├── random_device.cpp
│ └── wait_flag.cpp
│ └── value.cpp
├── tests.sh
└── todos.md
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | BasedOnStyle: Google
3 | ---
4 | Language: Cpp
5 | AccessModifierOffset: -2
6 | AlignAfterOpenBracket: Align
7 | AlignConsecutiveAssignments: false
8 | AlignConsecutiveDeclarations: false
9 | AlignConsecutiveMacros: false
10 | AlignEscapedNewlines: true
11 | AlignOperands: true
12 | AlignTrailingComments: true
13 | AllowAllArgumentsOnNextLine: false
14 | AllowShortBlocksOnASingleLine: Empty
15 | AllowShortEnumsOnASingleLine: false
16 | AllowShortCaseLabelsOnASingleLine: true
17 | AllowShortFunctionsOnASingleLine: Empty
18 | AllowShortIfStatementsOnASingleLine: Never
19 | AllowShortLambdasOnASingleLine: Empty
20 | AllowShortLoopsOnASingleLine: false
21 | AlwaysBreakAfterReturnType: None
22 | AlwaysBreakBeforeMultilineStrings: false
23 | AlwaysBreakTemplateDeclarations: Yes
24 | BinPackArguments: true
25 | BinPackParameters: false
26 | BreakBeforeBinaryOperators: None
27 | BreakBeforeBraces: Attach
28 | BreakBeforeTernaryOperators: true
29 | BreakConstructorInitializers: AfterColon
30 | BreakInheritanceList: AfterColon
31 | BreakStringLiterals: true
32 | ColumnLimit: 120
33 | CompactNamespaces: true
34 | ConstructorInitializerAllOnOneLineOrOnePerLine: true
35 | ConstructorInitializerIndentWidth: 2
36 | ContinuationIndentWidth: 2
37 | Cpp11BracedListStyle: false
38 | FixNamespaceComments: true
39 | IncludeBlocks: Preserve
40 | IndentCaseLabels: true
41 | IndentGotoLabels: false
42 | IndentPPDirectives: BeforeHash
43 | IndentWidth: 2
44 | IndentWrappedFunctionNames: true
45 | KeepEmptyLinesAtTheStartOfBlocks: false
46 | NamespaceIndentation: Inner
47 | PointerAlignment: Left
48 | ReflowComments: true
49 | SortIncludes: true
50 | SortUsingDeclarations: true
51 | SpaceAfterCStyleCast: false
52 | SpaceAfterLogicalNot: false
53 | SpaceAfterTemplateKeyword: true
54 | SpaceBeforeAssignmentOperators: true
55 | SpaceBeforeCpp11BracedList: false
56 | SpaceBeforeCtorInitializerColon: true
57 | SpaceBeforeInheritanceColon: true
58 | SpaceBeforeParens: ControlStatements
59 | SpaceBeforeRangeBasedForLoopColon: true
60 | SpaceBeforeSquareBrackets: false
61 | SpaceInEmptyBlock: false
62 | SpaceInEmptyParentheses: false
63 | SpacesInAngles: false
64 | SpacesInCStyleCastParentheses: false
65 | SpacesInConditionalStatement: false
66 | SpacesInContainerLiterals: false
67 | SpacesInParentheses: false
68 | SpacesInSquareBrackets: false
69 | Standard: c++17
70 | TabWidth: 2
71 | UseCRLF: false
72 | UseTab: Never
73 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | libs/* linguist-vendored
2 | *.ch linguist-language=Text
3 |
--------------------------------------------------------------------------------
/.github/workflows/unittest.yml:
--------------------------------------------------------------------------------
1 | name: Unit Test
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - name: Install clang-10
11 | run: |
12 | sudo apt update
13 | sudo apt install clang-10
14 | sudo apt install libboost-all-dev
15 | shell: bash
16 |
17 | - name: Checkout repository and submodules
18 | uses: actions/checkout@v2
19 | with:
20 | ref: 'rewrite'
21 | submodules: recursive
22 |
23 | - name: Test
24 | working-directory: ${{github.workspace}}
25 | shell: bash
26 | run: ./tests.sh
27 | env:
28 | CHARLYVMDIR: ${{github.workspace}}
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.dSYM
2 | *.lib
3 | *.swo
4 | *.swp
5 | .DS_Store
6 | .idea/
7 | .vscode/
8 | bin/
9 | build/
10 | cmake-build-debug
11 | cmake-build-minsizerel
12 | cmake-build-release
13 | cmake-build-relwithdebinfo
14 | cmake-build-relwithdebinfo-coverage
15 | code.profdata
16 | default.profraw
17 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "libs/catch2"]
2 | path = libs/catch2
3 | url = https://github.com/catchorg/Catch2
4 |
--------------------------------------------------------------------------------
/.rgignore:
--------------------------------------------------------------------------------
1 | *.dSYM
2 | *.lib
3 | *.swo
4 | *.swp
5 | .DS_Store
6 | .git/
7 | bin/
8 | build/
9 | build_backup/
10 | buildrelease/
11 | buildtest/
12 | code.profdata
13 | default.profraw
14 | experiments/
15 | libs/
16 | test/
17 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.12)
2 | set(CMAKE_C_COMPILER_NAMES clang)
3 | set(CMAKE_CXX_COMPILER_NAMES clang++)
4 | project(charly-vm)
5 |
6 | # create build directories
7 | file(MAKE_DIRECTORY cmake-build-debug cmake-build-release)
8 |
9 | # osx check
10 | if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
11 | message("-- Detected apple installation")
12 | add_compile_definitions(APPLE)
13 | set(APPLE TRUE)
14 | execute_process(COMMAND xcrun --show-sdk-path OUTPUT_VARIABLE OSXSDKPATH)
15 | include_directories(BEFORE SYSTEM ${OSXSDKPATH})
16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/include")
17 | endif ()
18 |
19 | # include directories
20 | include_directories(src)
21 | include_directories(include)
22 | include_directories(libs)
23 |
24 | # explicitly enable debug symbols in debug builds
25 | set(CMAKE_CXX_FLAGS_DEBUG "-g")
26 |
27 | # main executable
28 | add_subdirectory(src)
29 | add_executable(charly src/main.cpp)
30 | target_compile_features(charly PRIVATE cxx_std_17)
31 | target_link_libraries(charly libcharly)
32 | target_compile_options(charly PRIVATE
33 | -Wall
34 | -Wextra
35 | -Wpedantic
36 | -Werror
37 | -Wno-vla-extension
38 | -Wno-c++20-designator
39 | -Wno-gnu-zero-variadic-macro-arguments
40 | -Wno-gnu-label-as-value
41 | -Wno-c99-extensions
42 | -Wno-register
43 | -Wno-extra-semi
44 | -Wno-shadow
45 | -ftemplate-backtrace-limit=8
46 | -mllvm -align-all-functions=3
47 | )
48 |
49 | # enable link-time-optimization for release builds
50 | if (CMAKE_BUILD_TYPE MATCHES Release)
51 | message("-- Enabling LTO for target 'charly'")
52 | target_compile_options(charly PRIVATE -flto -O3)
53 | endif ()
54 |
55 | # install to global folder
56 | install(TARGETS charly RUNTIME DESTINATION bin)
57 |
58 | # unit tests
59 | add_subdirectory(libs/catch2)
60 |
61 | file(GLOB tests_SRC
62 | "test/runtime/core/compiler/diagnostic.cpp"
63 | "test/runtime/core/compiler/module.cpp"
64 | "test/runtime/core/compiler/parser.cpp"
65 | "test/runtime/core/compiler/pass.cpp"
66 | "test/runtime/core/compiler/semantic.cpp"
67 | "test/runtime/utils/buffer.cpp"
68 | "test/runtime/utils/cast.cpp"
69 | "test/runtime/utils/cast.cpp"
70 | "test/runtime/utils/random_device.cpp"
71 | "test/runtime/utils/wait_flag.cpp"
72 | "test/runtime/value.cpp"
73 | )
74 |
75 | add_executable(tests ${tests_SRC})
76 | target_compile_features(tests PRIVATE cxx_std_17)
77 | target_link_libraries(tests Catch2::Catch2WithMain)
78 | target_link_libraries(tests libcharly)
79 | target_compile_definitions(tests PUBLIC CATCH_CONFIG_PREFIX_ALL)
80 | target_compile_options(tests PRIVATE
81 | -Wall
82 | -Wextra
83 | -Wpedantic
84 | -Werror
85 | -Wno-vla-extension
86 | -Wno-c++20-designator
87 | -Wno-gnu-zero-variadic-macro-arguments
88 | -Wno-gnu-label-as-value
89 | -Wno-c99-extensions
90 | -Wno-register
91 | -Wno-extra-semi
92 | -Wno-shadow
93 | -ftemplate-backtrace-limit=8
94 | -mllvm -align-all-functions=3
95 | )
96 |
97 | # enable link-time-optimization for release builds
98 | if (CMAKE_BUILD_TYPE MATCHES Release)
99 | message("-- Enabling LTO for target 'tests'")
100 | target_compile_options(tests PRIVATE -flto -O3)
101 | endif ()
102 |
103 | if (APPLE)
104 | set_target_properties(charly PROPERTIES LINK_FLAGS -fuse-ld=ld)
105 | set_target_properties(tests PROPERTIES LINK_FLAGS -fuse-ld=ld)
106 | else ()
107 | set_target_properties(charly PROPERTIES LINK_FLAGS -fuse-ld=lld)
108 | set_target_properties(tests PROPERTIES LINK_FLAGS -fuse-ld=lld)
109 | endif ()
110 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Charly Programming Language
4 |
5 | 
6 |
7 | > Note: This is the rewrite branch of charly-vm.
8 | > Lots of stuff isn't working yet.
9 | > The [main branch](https://github.com/KCreate/charly-vm/tree/main) contains the previous
10 | > fully functional version of charly-vm.
11 |
12 | This launches a REPL which (at the moment) doesn't do very much.
13 |
14 | This launches a REPL which (at the moment) does some cool stuff, but still not a lot.
15 |
16 | This launches a REPL which supports some cool stuff, but still not a lot
17 |
18 | `./debug.sh [path/to/file.ch]`
19 |
20 | # Dependencies
21 |
22 | - `sudo apt-get install libboost-all-dev`
23 |
24 | # Installation
25 |
26 | Follow the steps below to install the `charly` executable on your system.
27 |
28 | 1. `git clone https://github.com/KCreate/charly-vm charly-vm`
29 | 2. `cd charly-vm`
30 | 3. `git checkout rewrite`
31 | 4. `git submodule init`
32 | 5. `git submodule update`
33 | 6. Set the `CHARLYVMDIR` environment variable to the project's root folder
34 | - e.g. `export CHARLYVMDIR=/home/user/github/KCreate/charly-vm`
35 | 7. `./install.sh`
36 |
37 | > The last step might request sudo permissions in order to access the relevant system directories.
38 |
39 | # Running the unit tests
40 |
41 | ```
42 | $ ./tests.sh
43 | [ 31%] Built target libcharly
44 | [ 87%] Built target Catch2
45 | [ 89%] Built target Catch2WithMain
46 | [100%] Built target tests
47 | ===============================================================================
48 | All tests passed (1422 assertions in 10 test cases)
49 | ```
50 |
--------------------------------------------------------------------------------
/benchmark/gc-stress-test.ch:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | func foo {
28 | let data
29 | let count = 2000
30 | while (count != 0) {
31 | let index = 0
32 | while (index != count - 1) {
33 | data = (1, 2, 3, 4)
34 | index += 1
35 | }
36 |
37 | count -= 1
38 | }
39 | }
40 |
41 | 16.times(->{
42 | const fiber_count = 8
43 | Tuple.make_with(fiber_count, ->spawn foo()).each(->(f) await f)
44 | })
--------------------------------------------------------------------------------
/benchmark/string-concat.ch:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | let string = "x"
28 |
29 | const count = 28
30 |
31 | count.times(->{
32 | string += string
33 | })
34 |
35 | print("string concat done")
36 |
37 | const empty = ""
38 | const copy = "{string}{empty}"
39 |
40 | 10.times(->{
41 | print(string == copy)
42 | print("comparison done")
43 | })
44 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | mkdir -p cmake-build-debug
4 |
5 | # initial cmake run
6 | if ! test -f cmake-build-debug/Makefile;
7 | then
8 | cmake -DCMAKE_BUILD_TYPE=Debug -S . -B cmake-build-debug
9 | fi
10 |
11 | cmake --build cmake-build-debug --target charly
12 |
--------------------------------------------------------------------------------
/build_release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | mkdir -p cmake-build-release
4 |
5 | # initial cmake run
6 | if ! test -f cmake-build-release/Makefile;
7 | then
8 | cmake -DCMAKE_BUILD_TYPE=Release -S . -B cmake-build-release
9 | fi
10 |
11 | cmake --build cmake-build-release --target charly
12 |
--------------------------------------------------------------------------------
/clean.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | rm -r cmake-build-debug
4 | rm -r cmake-build-release
5 |
6 | mkdir -p cmake-build-debug
7 | mkdir -p cmake-build-release
8 |
9 | exit
10 |
11 | for build_dir in cmake-build-*; do
12 | rm -r "$build_dir"
13 | mkdir -p "$build_dir"
14 | cmake -S . -DCMAKE_BUILD_TYPE=Debug -B "$build_dir"
15 | done
--------------------------------------------------------------------------------
/debug.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | mkdir -p cmake-build-debug
4 |
5 | # initial cmake run
6 | if ! test -f cmake-build-debug/Makefile;
7 | then
8 | cmake -DCMAKE_BUILD_TYPE=Debug -S . -B cmake-build-debug
9 | fi
10 |
11 | if cmake --build cmake-build-debug --target charly;
12 | then
13 | cmake-build-debug/charly "$@"
14 | fi
15 |
--------------------------------------------------------------------------------
/debugp.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | mkdir -p cmake-build-debug
4 |
5 | # initial cmake run
6 | if ! test -f cmake-build-debug/Makefile;
7 | then
8 | cmake -DCMAKE_BUILD_TYPE=Debug -S . -B cmake-build-debug
9 | fi
10 |
11 | if cmake --build cmake-build-debug --target charly -j12;
12 | then
13 | cmake-build-debug/charly "$@"
14 | fi
15 |
--------------------------------------------------------------------------------
/docs/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KCreate/charly-vm/b3dabc25954d5f34660281ca3f634aa7252b8b42/docs/.gitkeep
--------------------------------------------------------------------------------
/docs/charly-vm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KCreate/charly-vm/b3dabc25954d5f34660281ca3f634aa7252b8b42/docs/charly-vm.png
--------------------------------------------------------------------------------
/examples/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KCreate/charly-vm/b3dabc25954d5f34660281ca3f634aa7252b8b42/examples/.gitkeep
--------------------------------------------------------------------------------
/experiments/.gitignore:
--------------------------------------------------------------------------------
1 | a.out
2 |
--------------------------------------------------------------------------------
/experiments/cooperative_threads_refactored.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 |
39 | #include
40 |
41 | using namespace boost::context::detail;
42 | using namespace std::chrono_literals;
43 |
44 | /*
45 | * thread-safe printing meant for debugging
46 | * */
47 | inline void safeprint_impl(const char* format) {
48 | std::cout << format;
49 | }
50 |
51 | template
52 | inline void safeprint_impl(const char* format, T value, Targs... Fargs) {
53 | while (*format != '\0') {
54 | if (*format == '%') {
55 | std::cout << value;
56 | safeprint_impl(format + 1, Fargs...);
57 | return;
58 | }
59 | std::cout << *format;
60 |
61 | format++;
62 | }
63 | }
64 |
65 | std::mutex safeprint_mutex;
66 | auto program_start_time = std::chrono::steady_clock::now();
67 |
68 | #ifdef NDEBUG
69 | template
70 | inline void safeprint(const char*, Targs...) {}
71 | #else
72 | template
73 | inline void safeprint(const char* format, Targs... Fargs) {
74 | {
75 | std::unique_lock locker(safeprint_mutex);
76 | auto time_elapsed = std::chrono::steady_clock::now() - program_start_time;
77 | auto ticks = std::chrono::duration_cast(time_elapsed).count();
78 | std::cout << std::setw(12) << std::setfill('_') << ticks << std::setfill(' ') << std::setw(1) << ": ";
79 | safeprint_impl(format, Fargs...);
80 | std::cout << std::endl;
81 | }
82 | }
83 | #endif
84 |
85 |
86 | // actual implementation of scheduler
87 | class SchedulerImpl {
88 |
89 | };
90 |
91 | // runtime scheduler API into scheduler
92 | class Scheduler {
93 | public:
94 |
95 | struct Transfer {
96 | void* data;
97 | };
98 |
99 | // initialize the scheduler
100 | static void initialize();
101 |
102 | // start all the scheduler workers
103 | static void start();
104 |
105 | static void shutdown();
106 |
107 | static void yield();
108 |
109 | private:
110 | inline static const SchedulerImpl* m_instance;
111 | };
112 |
113 |
114 | void task_fn(Fiber* fiber) {
115 |
116 | for (int i = 0; i < 100; i++) {
117 | safeprint("fiber %: counter = %", fiber->id(), i);
118 | Scheduler::yield();
119 | }
120 |
121 | }
122 |
123 |
124 | int main() {
125 |
126 | for (int i = 0; i < 100; i++) {
127 | safeprint("counter = %", i);
128 | std::this_thread::sleep_for(10ms);
129 | }
130 |
131 | return 0;
132 | }
133 |
--------------------------------------------------------------------------------
/experiments/small-tagged-double.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #include "math.h"
33 |
34 | static const uintptr_t kTagFloat = 0b00011111;
35 |
36 | static const uintptr_t kMaskSign = (uintptr_t{0b10000000} << 56);
37 | static const uintptr_t kMaskExponent = (uintptr_t{0b0111111111110000} << 48);
38 | static const uintptr_t kMaskSmallExponent = (uintptr_t{0b0000111111110000} << 48);
39 | static const uintptr_t kMaskMantissa = 0x000fffffffffffff;
40 | static const uintptr_t kMaskSmallMantissa = 0x000fffffffffffe0;
41 | static const uintptr_t kMaskTag = 0b00011111;
42 |
43 | // uintptr_t encode(double value) {
44 | // uintptr_t raw = *reinterpret_cast(&value);
45 | // uintptr_t sign = (raw & kMaskSign);
46 | // uintptr_t exponent = (raw & kMaskSmallExponent);
47 | // uintptr_t mantissa = (raw & kMaskMantissa);
48 | // return (exponent << 4) + (mantissa << 4) + (sign >> 60) + kTagFloat;
49 | // }
50 |
51 | // double decode(uintptr_t value) {
52 | // value >>= 3;
53 | // uintptr_t sign_bit = value & 1;
54 | // value >>= 1;
55 | // value |= (sign_bit << 63);
56 | // return *reinterpret_cast(&value);
57 | // }
58 |
59 | uintptr_t encode(double value) {
60 | uintptr_t raw = *reinterpret_cast(&value);
61 | return (raw & ~kMaskTag) + kTagFloat;
62 | }
63 |
64 | double decode(uintptr_t value) {
65 | value -= kTagFloat;
66 | return *reinterpret_cast(&value);
67 | }
68 |
69 | int main() {
70 | double base = 8388608.0;
71 | double step = 1.0;
72 | int n = 100;
73 |
74 | std::cout.precision(30);
75 |
76 | // test precision without boxing
77 | {
78 | double sum = base;
79 |
80 | for (int i = 0; i < n; i++) {
81 | sum += step;
82 | }
83 |
84 | std::cout << "unboxed sum: " << sum << std::endl;
85 | }
86 |
87 | // test precision with boxing
88 | {
89 | double sum = base;
90 | uintptr_t encoded_step = encode(step);
91 | uintptr_t encoded_sum = encode(sum);
92 |
93 | for (int i = 0; i < n; i++) {
94 | double tmp = decode(encoded_sum) + decode(encoded_step);
95 | encoded_sum = encode(tmp);
96 | }
97 |
98 | sum = decode(encoded_sum);
99 |
100 | std::cout << "boxed sum: " << sum << std::endl;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/format.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SOURCES=`find src -type f -name '*.cpp'`
4 | PRIVATE_HEADERS=`find src -type f -name '*.h'`
5 | PUBLIC_HEADERS=`find include -type f -name '*.h'`
6 |
7 | TEST_SOURCES=`find test -type f -name '*.cpp'`
8 | TEST_HEADERS=`find test -type f -name '*.h'`
9 |
10 | clang-format -i $SOURCES $PRIVATE_HEADERS $PUBLIC_HEADERS $TEST_SOURCES $TEST_HEADERS --style=file
11 |
--------------------------------------------------------------------------------
/include/charly/atomic.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 |
29 | #include "charly/debug.h"
30 |
31 | #pragma once
32 |
33 | namespace charly {
34 |
35 | template
36 | struct atomic : public std::atomic {
37 | using std::atomic::atomic;
38 | using std::atomic::operator=;
39 |
40 | // sane CAS
41 | bool cas(T expected, T desired) {
42 | return std::atomic::compare_exchange_strong(expected, desired, std::memory_order_seq_cst);
43 | }
44 | bool cas_weak(T expected, T desired) {
45 | return std::atomic::compare_exchange_weak(expected, desired, std::memory_order_seq_cst);
46 | }
47 |
48 | // CAS that should not fail
49 | void acas(T expected, T desired) {
50 | bool result = cas(expected, desired);
51 | CHECK(result);
52 | }
53 |
54 | uintptr_t address() const {
55 | return reinterpret_cast(this);
56 | }
57 | };
58 |
59 | } // namespace charly
60 |
--------------------------------------------------------------------------------
/include/charly/charly.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | #include "atomic.h"
37 | #include "debug.h"
38 | #include "symbol.h"
39 | #include "utils/allocator.h"
40 | #include "utils/lock.h"
41 |
42 | #pragma once
43 |
44 | namespace charly {
45 |
46 | #define CHARLY_NON_COPYABLE(C) \
47 | C(const C&) = delete; \
48 | C(C&) = delete; \
49 | C(const C&&) = delete; \
50 | C(C&&) = delete; \
51 | C& operator=(C&) = delete; \
52 | C& operator=(C&&) = delete; \
53 | C& operator=(const C&) = delete; \
54 | C& operator=(const C&&) = delete
55 |
56 | /*
57 | * shorthand method for often used shared_ptr stuff
58 | * */
59 | template
60 | using ref = std::shared_ptr;
61 | template
62 | using weak_ref = std::weak_ptr;
63 |
64 | template
65 | inline ref make(Args&&... params) {
66 | return std::make_shared(std::forward(params)...);
67 | }
68 |
69 | template
70 | inline ref cast(ref node) {
71 | return std::dynamic_pointer_cast(node);
72 | }
73 |
74 | inline size_t get_steady_timestamp() {
75 | auto now = std::chrono::steady_clock::now();
76 | return std::chrono::duration_cast(now.time_since_epoch()).count();
77 | }
78 |
79 | inline size_t get_steady_timestamp_micro() {
80 | auto now = std::chrono::steady_clock::now();
81 | return std::chrono::duration_cast(now.time_since_epoch()).count();
82 | }
83 |
84 | // helper method to cast one type to another
85 | template
86 | B bitcast(A&& value) {
87 | return *reinterpret_cast(&value);
88 | }
89 |
90 | constexpr int64_t kInt32Min = -2147483647 - 1;
91 | constexpr int64_t kInt32Max = 2147483647;
92 | constexpr int64_t kInt24Min = -8388607 - 1;
93 | constexpr int64_t kInt24Max = 8388607;
94 | constexpr int64_t kInt16Min = -32767 - 1;
95 | constexpr int64_t kInt16Max = 32767;
96 | constexpr int64_t kInt8Min = -127 - 1;
97 | constexpr int64_t kInt8Max = 127;
98 |
99 | constexpr uint64_t kUInt32Min = 0;
100 | constexpr uint64_t kUInt32Max = 0xffffffff;
101 | constexpr uint64_t kUInt24Min = 0;
102 | constexpr uint64_t kUInt24Max = 0x00ffffff;
103 | constexpr uint64_t kUInt16Min = 0;
104 | constexpr uint64_t kUInt16Max = 0x0000ffff;
105 | constexpr uint64_t kUInt8Min = 0;
106 | constexpr uint64_t kUInt8Max = 0x000000ff;
107 |
108 | #ifdef NDEBUG
109 | constexpr bool kIsDebugBuild = false;
110 | #else
111 | constexpr bool kIsDebugBuild = true;
112 | #endif
113 |
114 | inline constexpr bool double_fuzzy_equal(double left, double right) {
115 | if (!std::isfinite(left) || !std::isfinite(right)) {
116 | if (std::isnan(left) && std::isnan(right)) {
117 | return true;
118 | }
119 |
120 | return left == right;
121 | }
122 |
123 | constexpr double epsilon = 0.000001;
124 | return std::fabs(left - right) <= epsilon;
125 | }
126 |
127 | } // namespace charly
128 |
--------------------------------------------------------------------------------
/include/charly/handle.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include "value.h"
28 |
29 | #pragma once
30 |
31 | namespace charly::core::runtime {
32 |
33 | class Thread;
34 | class ThreadLocalHandles;
35 |
36 | class HandleScope {
37 | CHARLY_NON_COPYABLE(HandleScope);
38 |
39 | public:
40 | explicit HandleScope(Thread* thread) : m_thread(thread) {}
41 |
42 | Thread* thread() const {
43 | return m_thread;
44 | }
45 |
46 | private:
47 | Thread* m_thread;
48 | };
49 |
50 | template
51 | class Handle : public T {
52 | friend class ThreadLocalHandles;
53 |
54 | public:
55 | Handle(HandleScope& scope);
56 | Handle(HandleScope& scope, RawValue value);
57 | ~Handle();
58 |
59 | static_assert(std::is_base_of::value, "Expected T to be child of RawValue");
60 |
61 | // disallow copies using another handle
62 | template
63 | Handle(HandleScope*, const Handle&) = delete;
64 |
65 | template
66 | Handle& operator=(Handle& other) {
67 | return *this = *other;
68 | }
69 |
70 | // allow assigning RawValue values to the handle
71 | Handle& operator=(RawValue other) {
72 | *static_cast(this) = other;
73 | DCHECK(is_valid_type(), "expected valid type");
74 | return *this;
75 | }
76 |
77 | T& operator*() {
78 | return *static_cast(this);
79 | }
80 |
81 | const T& operator*() const {
82 | return *static_cast(this);
83 | }
84 |
85 | // Handle can be casted to Handle if S is a subclass of T
86 | template
87 | explicit operator const Handle&() const {
88 | static_assert(std::is_base_of::value, "Only up-casts are permitted");
89 | return *reinterpret_cast*>(this);
90 | }
91 |
92 | Handle* next() const {
93 | return m_next;
94 | }
95 |
96 | private:
97 | bool is_valid_type() const {
98 | return T::value_is_type(**this);
99 | }
100 |
101 | Handle* pointer() {
102 | return bitcast*>(this);
103 | }
104 |
105 | Thread* m_thread;
106 | Handle* m_next;
107 | };
108 |
109 | #define HANDLE_DEF(T) using T = Handle;
110 | TYPE_NAMES(HANDLE_DEF)
111 | #undef HANDLE_DEF
112 |
113 | } // namespace charly::core::runtime
114 |
--------------------------------------------------------------------------------
/include/charly/symbol.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 | #include
29 | #include
30 |
31 | #pragma once
32 |
33 | namespace charly {
34 |
35 | // compile-time crc32 hash
36 | // source: https://stackoverflow.com/questions/28675727/using-crc32-algorithm-to-hash-string-at-compile-time
37 | namespace crc32 {
38 | namespace internal {
39 | template
40 | struct f : f<((c & 1) ? 0xedb88320 : 0) ^ (c >> 1), k - 1> {};
41 | template
42 | struct f {
43 | enum {
44 | value = c
45 | };
46 | };
47 |
48 | #define A(x) B(x) B(x + 128)
49 | #define B(x) C(x) C(x + 64)
50 | #define C(x) D(x) D(x + 32)
51 | #define D(x) E(x) E(x + 16)
52 | #define E(x) F(x) F(x + 8)
53 | #define F(x) G(x) G(x + 4)
54 | #define G(x) H(x) H(x + 2)
55 | #define H(x) I(x) I(x + 1)
56 | #define I(x) f::value,
57 | constexpr unsigned crc_table[] = { A(0) };
58 | #undef A
59 | #undef B
60 | #undef C
61 | #undef D
62 | #undef E
63 | #undef F
64 | #undef G
65 | #undef H
66 | #undef I
67 |
68 | namespace constexpr_impl {
69 | constexpr uint32_t crc32_impl(const char* p, size_t len, uint32_t crc) {
70 | return len ? crc32_impl(p + 1, len - 1, (crc >> 8) ^ crc_table[(crc & 0xFF) ^ *p]) : crc;
71 | }
72 |
73 | constexpr uint32_t crc32(const char* data, size_t length) {
74 | return ~crc32_impl(data, length, ~0);
75 | }
76 |
77 | constexpr size_t strlen_c(const char* str) {
78 | return *str ? 1 + strlen_c(str + 1) : 0;
79 | }
80 | } // namespace constexpr_impl
81 |
82 | inline constexpr uint32_t hash_constexpr(const char* str) {
83 | return constexpr_impl::crc32(str, constexpr_impl::strlen_c(str));
84 | }
85 |
86 | inline uint32_t hash_block(const char* data, size_t size) {
87 | uint32_t c = 0xFFFFFFFF;
88 | auto u = reinterpret_cast(data);
89 | for (size_t i = 0; i < size; i++) {
90 | c = crc_table[(c ^ u[i]) & 0xFF] ^ (c >> 8);
91 | }
92 | return c ^ 0xFFFFFFFF;
93 | }
94 | } // namespace internal
95 |
96 | inline uint32_t hash_block(const char* data, size_t size) {
97 | return internal::hash_block(data, size);
98 | }
99 |
100 | inline uint32_t hash_string(const std::string& string) {
101 | return internal::hash_block(string.data(), string.size());
102 | }
103 |
104 | inline uint32_t hash_block(const std::string_view& view) {
105 | return internal::hash_block(view.data(), view.size());
106 | }
107 | } // namespace crc32
108 |
109 | using SYMBOL = uint32_t;
110 |
111 | inline constexpr SYMBOL SYM(const char* str) {
112 | return crc32::internal::hash_constexpr(str);
113 | }
114 |
115 | } // namespace charly
116 |
--------------------------------------------------------------------------------
/include/charly/utils/allocator.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #pragma once
34 |
35 | namespace charly {
36 |
37 | inline static const size_t kPageSize = sysconf(_SC_PAGESIZE);
38 | constexpr size_t kPointerSize = sizeof(uintptr_t);
39 | inline static size_t kPointersPerPage = kPageSize / kPointerSize;
40 |
41 | constexpr size_t kKb = 1024;
42 | constexpr size_t kMb = kKb * 1024;
43 | constexpr size_t kGb = kMb * 1024;
44 |
45 | namespace utils {
46 |
47 | /*
48 | * Charly allocator class
49 | *
50 | * Handles heap memory allocations and guarded page access
51 | * */
52 | class Allocator {
53 | public:
54 | // allocate heap memory
55 | static void* alloc(size_t size);
56 |
57 | // allocate aligned heap memory
58 | static void* aligned_alloc(size_t size, size_t alignment = 8);
59 |
60 | // allocates memory via mmap
61 | // mapped memory region is initially protected with PROT_NONE
62 | static void* mmap_page_aligned(size_t size,
63 | int32_t protection = PROT_NONE,
64 | int32_t flags = MAP_PRIVATE | MAP_ANONYMOUS);
65 | static void* mmap_self_aligned(size_t size,
66 | int32_t protection = PROT_NONE,
67 | int32_t flags = MAP_PRIVATE | MAP_ANONYMOUS);
68 | static void* mmap_address(void* address,
69 | size_t size,
70 | int32_t protection = PROT_NONE,
71 | int32_t flags = MAP_PRIVATE | MAP_ANONYMOUS);
72 |
73 | // reallocate pointer to fit a bigger size or change alignment
74 | // acts like alloc if pointer is null
75 | // returns old pointer if it fulfills the new requirements
76 | static void* realloc(void* old_pointer, size_t old_size, size_t new_size, size_t new_alignment = 8);
77 |
78 | // free a pointer allocated by alloc
79 | static void free(void* pointer);
80 |
81 | // munmap a region of memory
82 | static void munmap(void* pointer, size_t size);
83 |
84 | // protect a section of memory as either read-only or read and writeable
85 | static void protect_none(void* pointer, size_t size);
86 | static void protect_read(void* pointer, size_t size);
87 | static void protect_readwrite(void* pointer, size_t size);
88 | static void protect_exec(void* pointer, size_t size);
89 | };
90 |
91 | } // namespace utils
92 | } // namespace charly
93 |
--------------------------------------------------------------------------------
/include/charly/utils/cast.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | #pragma once
36 |
37 | namespace charly::utils {
38 |
39 | inline int64_t charptr_to_int(const char* data, size_t length, int base = 10) {
40 | char buffer[length + 1];
41 | std::memset(buffer, 0, length + 1);
42 | std::memcpy(buffer, data, length);
43 |
44 | char* end_ptr;
45 | int64_t result = std::strtol(buffer, &end_ptr, base);
46 |
47 | if (errno == ERANGE) {
48 | errno = 0;
49 | return 0;
50 | }
51 |
52 | if (end_ptr == buffer) {
53 | return 0;
54 | }
55 |
56 | return result;
57 | }
58 |
59 | inline int64_t string_to_int(const std::string& str, int base = 10) {
60 | return charptr_to_int(str.data(), str.size(), base);
61 | }
62 |
63 | inline int64_t string_view_to_int(const std::string_view& view, int base = 10) {
64 | return charptr_to_int(view.data(), view.size(), base);
65 | }
66 |
67 | inline double charptr_to_double(const char* data, size_t length) {
68 | char buffer[length + 1];
69 | std::memset(buffer, 0, length + 1);
70 | std::memcpy(buffer, data, length);
71 |
72 | char* end_ptr;
73 | double result = std::strtod(buffer, &end_ptr);
74 |
75 | if (result == HUGE_VAL || end_ptr == buffer)
76 | return NAN;
77 |
78 | return result;
79 | }
80 |
81 | inline double string_to_double(const std::string& str) {
82 | return charptr_to_double(str.data(), str.size());
83 | }
84 |
85 | inline double string_view_to_double(const std::string_view& view) {
86 | return charptr_to_double(view.data(), view.size());
87 | }
88 |
89 | } // namespace charly::utils
90 |
--------------------------------------------------------------------------------
/include/charly/utils/guarded_buffer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include "charly/utils/allocator.h"
28 |
29 | #pragma once
30 |
31 | namespace charly::utils {
32 |
33 | class GuardedBuffer {
34 | public:
35 | explicit GuardedBuffer(size_t size) : m_size(size) {
36 | DCHECK(size >= kPageSize, "expected size to be at least the page size");
37 | DCHECK(size % kPageSize == 0, "expected size to be a multiple of the page size");
38 | m_mapping = Allocator::mmap_page_aligned(size + kPageSize * 2);
39 | Allocator::protect_readwrite((void*)((uintptr_t)m_mapping + kPageSize), size);
40 | }
41 | ~GuardedBuffer() {
42 | DCHECK(m_mapping != nullptr);
43 | Allocator::munmap(m_mapping, m_size);
44 | m_mapping = nullptr;
45 | m_size = 0;
46 | }
47 |
48 | void* data() const {
49 | return (void*)((uintptr_t)m_mapping + kPageSize);
50 | }
51 |
52 | size_t size() const {
53 | return m_size - kPageSize * 2;
54 | }
55 |
56 | private:
57 | void* m_mapping = nullptr;
58 | size_t m_size = 0;
59 | };
60 |
61 | } // namespace charly::utils
62 |
--------------------------------------------------------------------------------
/include/charly/utils/lock.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 | #include
29 | #include // std::hash
30 | #include
31 | #include // std::hardware_concurrency
32 | #include
33 |
34 | #include "charly/atomic.h"
35 |
36 | #pragma once
37 |
38 | namespace charly::utils {
39 |
40 | struct ParkingLotThreadData {
41 | bool should_park = false;
42 | std::mutex parking_lock;
43 | std::condition_variable parking_condition;
44 | static ParkingLotThreadData* get_local_thread_data();
45 | };
46 |
47 | struct ParkingLotThreadQueue {
48 | using QueueEntry = std::tuple;
49 | std::mutex mutex;
50 | std::list queue;
51 |
52 | void push(ParkingLotThreadData* data, uintptr_t address);
53 | ParkingLotThreadData* pop(uintptr_t address);
54 | bool empty() const;
55 | };
56 |
57 | class ParkingLot {
58 | public:
59 | ParkingLot();
60 |
61 | struct UnparkResult {
62 | bool unparked_thread = false;
63 | bool queue_is_empty = false;
64 | };
65 |
66 | static bool park(uintptr_t address, const std::function& validation);
67 | static void unpark_one(uintptr_t address, const std::function& callback);
68 | static UnparkResult unpark_one(uintptr_t address);
69 |
70 | private:
71 | static constexpr size_t kInitialBucketCount = 1;
72 | using ThreadQueueTable = std::vector>;
73 |
74 | bool park_impl(uintptr_t address, const std::function& validation);
75 | void unpark_one_impl(uintptr_t address, const std::function& callback);
76 |
77 | static ParkingLotThreadQueue* get_queue_for_address(ThreadQueueTable* table, uintptr_t address);
78 |
79 | private:
80 | atomic m_table = nullptr;
81 | std::mutex m_old_tables_mutex;
82 | std::vector m_old_tables;
83 | };
84 |
85 | enum LockState : uint8_t {
86 | kFreeLock = 0,
87 | kIsLocked = 1,
88 | kHasParked = 2
89 | };
90 |
91 | // allows threads to barge in and steal the lock away from a parked thread
92 | class TinyLock {
93 | public:
94 | void lock();
95 | void unlock();
96 |
97 | bool is_locked() const {
98 | return (m_state & kIsLocked);
99 | }
100 |
101 | TinyLock& operator=(uint8_t value) {
102 | m_state = value;
103 | return *this;
104 | }
105 |
106 | private:
107 | atomic m_state = kFreeLock;
108 | };
109 | static_assert(sizeof(TinyLock) == 1);
110 |
111 | } // namespace charly::utils
112 |
--------------------------------------------------------------------------------
/include/charly/utils/random_device.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 | #include
29 |
30 | #pragma once
31 |
32 | namespace charly::utils {
33 |
34 | class RandomDevice {
35 | public:
36 | RandomDevice() : m_state(std::time(nullptr)) {}
37 |
38 | size_t get() {
39 | size_t x = m_state;
40 | x ^= x << 13;
41 | x ^= x >> 7;
42 | x ^= x << 17;
43 | m_state = x;
44 | return x;
45 | }
46 |
47 | private:
48 | size_t m_state;
49 | };
50 |
51 | } // namespace charly::utils
52 |
--------------------------------------------------------------------------------
/include/charly/utils/timedsection.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include "charly/charly.h"
28 |
29 | #pragma once
30 |
31 | namespace charly::utils {
32 |
33 | class TimedSection {
34 | public:
35 | // prints the amount of time elapsed inside the callback method to the console
36 | // returns the amount of milliseconds elapsed
37 | template
38 | static double run(const std::string& title, F callback) {
39 | size_t start_time = get_steady_timestamp_micro();
40 | debuglnf("Begin '%'", title);
41 | callback();
42 | size_t end_time = get_steady_timestamp_micro();
43 | double duration = (double)(end_time - start_time) / 1000;
44 | debuglnf("'%' ran for %ms", title, duration);
45 | return duration;
46 | }
47 | };
48 |
49 | } // namespace charly::utils
50 |
--------------------------------------------------------------------------------
/include/charly/utils/wait_flag.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #include "charly/atomic.h"
33 |
34 | #pragma once
35 |
36 | namespace charly::utils {
37 |
38 | class WaitFlag {
39 | public:
40 | explicit WaitFlag(std::mutex& mutex) : m_mutex(mutex) {}
41 |
42 | bool state() const {
43 | return m_state;
44 | }
45 |
46 | void wait() {
47 | std::unique_lock locker(m_mutex);
48 | m_cv.wait(locker, [&]() -> bool {
49 | return m_state;
50 | });
51 | }
52 |
53 | bool signal() {
54 | bool first;
55 | {
56 | std::unique_lock locker(m_mutex);
57 | first = m_state.cas(false, true);
58 | }
59 |
60 | m_cv.notify_all();
61 |
62 | return first;
63 | }
64 |
65 | bool reset() {
66 | bool first;
67 | {
68 | std::unique_lock locker(m_mutex);
69 | first = m_state.cas(true, false);
70 | }
71 |
72 | m_cv.notify_all();
73 |
74 | return first;
75 | }
76 |
77 | private:
78 | std::mutex& m_mutex;
79 | std::condition_variable m_cv;
80 | atomic m_state = false;
81 | };
82 |
83 | } // namespace charly::utils
84 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | mkdir -p cmake-build-release
4 |
5 | # initial cmake run
6 | if ! test -f cmake-build-release/Makefile;
7 | then
8 | cmake -DCMAKE_BUILD_TYPE=Release -S . -B cmake-build-release
9 | fi
10 |
11 | if cmake --build cmake-build-release -j12 --target tests charly;
12 | then
13 | if ./cmake-build-release/tests;
14 | then
15 | sudo cmake --install cmake-build-release
16 | fi
17 | fi
18 |
--------------------------------------------------------------------------------
/libs/termcolor/termcolor.cpp:
--------------------------------------------------------------------------------
1 | #include "termcolor.h"
2 |
3 | namespace termcolor::_internal {
4 | static int colorize_index = ((std::cout << "xalloc" << std::endl), std::ios_base::xalloc());
5 | }
6 |
--------------------------------------------------------------------------------
/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | mkdir -p cmake-build-release
4 |
5 | # initial cmake run
6 | if ! test -f cmake-build-release/Makefile;
7 | then
8 | cmake -DCMAKE_BUILD_TYPE=Release -S . -B cmake-build-release
9 | fi
10 |
11 | if cmake --build cmake-build-release --target charly -j12;
12 | then
13 | cmake-build-release/charly "$@"
14 | fi
15 |
--------------------------------------------------------------------------------
/scratch-files/concurrent_map.ch:
--------------------------------------------------------------------------------
1 | class Array {
2 | func concurrent_map(block) {
3 | // self = [1, 2, 3, ..., 18, 19, 20]
4 | const results = Array.of_size(@length)
5 |
6 | const partition_size = Math.floor(@length / Fiber.MaxParallelism)
7 | const last_error = @length - (Fiber.MaxParallelism * partition_size)
8 |
9 | const partition_counters = Array.of_size(Fiber.MaxParallelism).map(->(p_index) {
10 | const start = p_index * partition_size
11 | let limit = start + partition_size
12 |
13 | if p_index + 1 == Fiber.MaxParallelism {
14 | limit += last_error
15 | }
16 |
17 | AtomicCounter(start, limit)
18 | })
19 |
20 | Fiber.MaxParallelism.map(->(i) {
21 | spawn {
22 |
23 | // work through own partition first
24 | const own_counter = partition_counters[i]
25 | loop {
26 | const index = own_counter.next()
27 | if index == null break
28 | results[index] = block(self[index], index, self)
29 | }
30 |
31 | // steal from other partitions
32 | loop {
33 | let stolen_index
34 | partition_counters.find(->(counter) {
35 | stolen_index = counter.next()
36 | return stolen_index != null
37 | })
38 |
39 | if stolen_index == null break
40 | results[index] = block(self[index], index, self)
41 | }
42 | }
43 | }).each(->(worker) await worker)
44 |
45 | return results
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/scratch-files/gc-stress-test.ch:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | const fiber_count = 60000
28 | const allocator_limit = 10000
29 |
30 | func allocator(index) {
31 | let data
32 | allocator_limit.times(->(i) {
33 | data = (i,)
34 | })
35 |
36 | data[0]
37 | }
38 |
39 | const list = Tuple.create_with(fiber_count, ->(i) {
40 | spawn allocator(i)
41 | })
42 |
43 | const result = list.reduce(0, ->(p, f, i) p + await f)
44 | print(result)
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/scratch-files/parsertest.ch:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | let result = 0
28 |
29 | let r1
30 |
31 | func foo {
32 | let r2
33 |
34 | func bar {
35 | let r3
36 |
37 | func baz {
38 | let r4 = result
39 | r3 = r4 + 1
40 | }
41 |
42 | baz()
43 | r2 = r3 + 1
44 | }
45 |
46 | bar()
47 | r1 = r2 + 1
48 | }
49 |
50 | foo()
51 |
52 | return r1
53 |
--------------------------------------------------------------------------------
/scratch-files/scratch.ch:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | func times(n, cb) {
28 | let i = 0
29 | while i != n {
30 | cb(i)
31 | i += 1
32 | }
33 | }
34 |
35 | func sleep(n = 1) {
36 | const limit = 1000
37 | let i = 0
38 | let j = 0
39 |
40 | while j != n {
41 | while i != limit {
42 | i += 1
43 | }
44 | j += 1
45 | i = 0
46 | }
47 | }
48 |
49 | func map(size, cb) {
50 | const result = list(size)
51 | times(size, ->(i) {
52 | result[i] = cb(i)
53 | })
54 | return result
55 | }
56 |
57 | const job = spawn {
58 | return (1, 2, 3)
59 | }
60 |
61 | const result = await job
62 |
63 | echo("result: {result}")
64 |
65 |
66 |
67 | // Represents a basic thread in the charly runtime
68 | // A thread can either run in task mode or generator mode
69 | class Thread {
70 |
71 |
72 | }
73 |
74 | class Task extends Thread {
75 |
76 | }
77 |
78 | class Generator extends Thread {
79 | func next(argument = null)
80 | }
81 |
82 |
83 |
84 |
85 |
86 |
87 | class Container {
88 | property list
89 |
90 | // declaration: signature: error:
91 | func foo() // foo()
92 | func foo(&block) // foo_()
93 | func foo(bar = null) // foo() duplicate function signature
94 | func foo(bar = null, &block) // foo_() duplicate function signature
95 | func foo(bar, baz = null) // foo(_)
96 | func foo(bar, baz = null, &block) // foo_(_)
97 | func foo(bar, baz) // foo(_, _)
98 | func foo(bar, baz, &block) // foo_(_, _)
99 |
100 | // optional parameters do not count towards function signature
101 | // functions that accept a callback block have a different signature
102 | // than functions that do not accept one
103 | }
104 |
105 | func maketask(context, function, args)
106 | func makegenerator(context, function, args)
107 | func taskjoin(task)
108 | func taskyield(arg)
109 |
110 | class Container {
111 | func +(other) // binary + operator
112 | func ==(other) // binary == operator
113 | func !() // unary ! operator (not)
114 | func -() // unary - operator
115 |
116 | func await() // await operator
117 |
118 | func [](index)
119 | func []=(index, value)
120 | }
121 |
122 |
123 |
124 | class Generator {
125 | construct new(&function) {
126 |
127 | }
128 | }
129 |
130 | const counter = async {
131 | let i = 0
132 | loop {
133 | yield i
134 | i++
135 | }
136 | }
137 |
138 |
139 |
140 |
141 | // use-case: concurrently request and load files from a server
142 | // provided is a list of URLs
143 | // result should be a list of strings
144 |
145 | const urls = get_urls()
146 |
147 | const requests = urls.map -> (url) spawn fetch(url)
148 |
149 | const files = requests.map -> (req) await req
150 |
151 | files.each -> (file) print(file)
152 |
153 | urls.map -> spawn fetch($)
154 | .map -> await $
155 | .each -> print($)
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
--------------------------------------------------------------------------------
/scratch-files/test.ch:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 |
28 | const limit = 1000
29 | const tasks = 512.map(->(i) spawn {
30 | limit.times(->sleep(1))
31 | })
32 |
33 | const w = Stopwatch()
34 | defer print("waited", w.check(), "ms")
35 |
36 | tasks.each(->(t) await t)
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | file(GLOB charlycore_SRC
2 | "charly/charly.cpp"
3 | "charly/core/compiler/ast.cpp"
4 | "charly/core/compiler/codegenerator.cpp"
5 | "charly/core/compiler/compiler.cpp"
6 | "charly/core/compiler/diagnostic.cpp"
7 | "charly/core/compiler/ir/assembler.cpp"
8 | "charly/core/compiler/ir/builder.cpp"
9 | "charly/core/compiler/ir/ir.cpp"
10 | "charly/core/compiler/lexer.cpp"
11 | "charly/core/compiler/location.cpp"
12 | "charly/core/compiler/parser.cpp"
13 | "charly/core/compiler/passes/constant_folding_pass.cpp"
14 | "charly/core/compiler/passes/desugar_pass.cpp"
15 | "charly/core/compiler/passes/code_elimination.cpp"
16 | "charly/core/compiler/passes/duplicates_check.cpp"
17 | "charly/core/compiler/passes/grammar_validation_check.cpp"
18 | "charly/core/compiler/passes/repl_prepare_pass.cpp"
19 | "charly/core/compiler/passes/reserved_identifiers_check.cpp"
20 | "charly/core/compiler/passes/variable_analyzer_pass.cpp"
21 | "charly/core/runtime/compiled_module.cpp"
22 | "charly/core/runtime/gc.cpp"
23 | "charly/core/runtime/heap.cpp"
24 | "charly/core/runtime/interpreter.cpp"
25 | "charly/core/runtime/processor.cpp"
26 | "charly/core/runtime/runtime.cpp"
27 | "charly/core/runtime/scheduler.cpp"
28 | "charly/core/runtime/watchdog.cpp"
29 | "charly/core/runtime/thread.cpp"
30 | "charly/core/runtime/worker.cpp"
31 | "charly/core/runtime/builtins/core.cpp"
32 | "charly/core/runtime/builtins/future.cpp"
33 | "charly/core/runtime/builtins/list.cpp"
34 | "charly/core/runtime/builtins/timer.cpp"
35 | "charly/core/runtime/builtins/readline.cpp"
36 | "charly/handle.cpp"
37 | "charly/utils/argumentparser.cpp"
38 | "charly/utils/buffer.cpp"
39 | "charly/utils/allocator.cpp"
40 | "charly/utils/lock.cpp"
41 | "charly/value.cpp"
42 | "libs/termcolor/termcolor.cpp"
43 | )
44 |
45 | # explicitly enable debug symbols in debug builds
46 | set(CMAKE_CXX_FLAGS_DEBUG "-g")
47 |
48 | find_package(Boost REQUIRED COMPONENTS context)
49 |
50 | # osx check
51 | if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
52 | message("-- Detected apple installation")
53 | add_compile_definitions(APPLE)
54 | set(APPLE TRUE)
55 | execute_process(COMMAND xcrun --show-sdk-path OUTPUT_VARIABLE OSXSDKPATH)
56 | include_directories(BEFORE SYSTEM ${OSXSDKPATH})
57 | endif ()
58 |
59 | add_library(libcharly ${charlycore_SRC})
60 | target_compile_features(libcharly PRIVATE cxx_std_17)
61 | if (Boost_FOUND)
62 | target_include_directories(libcharly PRIVATE ${Boost_INCLUDE_DIRS})
63 | target_link_libraries(libcharly Boost::context)
64 | endif ()
65 | target_link_libraries(libcharly stdc++)
66 | target_link_libraries(libcharly m)
67 | target_link_libraries(libcharly readline)
68 | target_link_libraries(libcharly pthread)
69 | target_include_directories(libcharly PRIVATE "./")
70 | target_compile_options(libcharly PRIVATE
71 | -Wall
72 | -Wextra
73 | -Wpedantic
74 | -Werror
75 | -Wno-vla-extension
76 | -Wno-c++20-designator
77 | -Wno-gnu-zero-variadic-macro-arguments
78 | -Wno-gnu-label-as-value
79 | -Wno-c99-extensions
80 | -Wno-register
81 | -Wno-extra-semi
82 | -Wno-shadow
83 | -ftemplate-backtrace-limit=8
84 | -mllvm -align-all-functions=3
85 | )
86 |
87 | # enable link-time-optimization for release builds
88 | if (CMAKE_BUILD_TYPE MATCHES Release)
89 | message("-- Enabling LTO for target 'libcharly'")
90 | target_compile_options(libcharly PRIVATE -flto -O3)
91 | endif ()
92 |
93 | set_target_properties(libcharly PROPERTIES PREFIX "")
94 |
95 | if (APPLE)
96 | set_target_properties(libcharly PROPERTIES LINK_FLAGS -fuse-ld=ld)
97 | else ()
98 | set_target_properties(libcharly PROPERTIES LINK_FLAGS -fuse-ld=lld)
99 | endif ()
100 |
--------------------------------------------------------------------------------
/src/charly/charly.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 |
29 | #include "charly/charly.h"
30 | #include "charly/core/runtime/interpreter.h"
31 | #include "charly/core/runtime/runtime.h"
32 |
33 | namespace charly {
34 |
35 | std::recursive_mutex debugln_mutex;
36 | auto program_startup_timestamp = std::chrono::steady_clock::now();
37 |
38 | void print_runtime_debug_state(std::ostream& stream) {
39 | using namespace core::runtime;
40 |
41 | if (Thread* thread = Thread::current()) {
42 | debugln_impl_time(stream, "\n");
43 | debugln_impl_time(stream, "Thread: %\n", thread->id());
44 |
45 | if (Frame* frame = thread->frame()) {
46 | if (frame->is_builtin_frame()) {
47 | auto* builtin_frame = static_cast(frame);
48 | debugln_impl_time(stream, "Builtin Function: %\n", builtin_frame->function);
49 | } else {
50 | auto* interpreter_frame = static_cast(frame);
51 | debugln_impl_time(stream, "IP: %\n", (void*)interpreter_frame->oldip);
52 | debugln_impl_time(stream, "Function: %\n", interpreter_frame->function);
53 | }
54 |
55 | Frame* old = frame;
56 | debugln_impl_time(stream, "Frames:\n", frame);
57 | while (frame) {
58 | if (frame->is_builtin_frame()) {
59 | auto* builtin_frame = static_cast(frame);
60 | debugln_impl_time(stream, " - %\n", builtin_frame->function);
61 | } else {
62 | auto* interpreter_frame = static_cast(frame);
63 | debugln_impl_time(stream, " - %: %\n", interpreter_frame->function, (void*)interpreter_frame->oldip);
64 | }
65 | frame = frame->parent;
66 | }
67 | frame = old;
68 |
69 | if (frame->is_interpreter_frame()) {
70 | auto* interpreter_frame = static_cast(frame);
71 | if (interpreter_frame->stack && interpreter_frame->sp > 0) {
72 | debugln_impl_time(stream, "\n");
73 | debugln_impl_time(stream, "Stack:\n");
74 | for (int64_t i = interpreter_frame->sp - 1; i >= 0; i--) {
75 | debugln_impl_time(stream, " - %\n", interpreter_frame->stack[i]);
76 | }
77 | }
78 | }
79 | } else {
80 | debugln_impl_time(stream, "No active frame!\n");
81 | }
82 | } else {
83 | debugln_impl_time(stream, "No active thread!\n");
84 | }
85 |
86 | void* callstack[128];
87 | int frames = backtrace(callstack, 128);
88 | char** frame_symbols = backtrace_symbols(callstack, frames);
89 | debugln_impl_time(stream, "Hardware Stack:\n");
90 | for (int i = 0; i < frames; ++i) {
91 | debugln_impl_time(stream, " - % %\n", i, frame_symbols[i] + 58);
92 | }
93 | utils::Allocator::free(frame_symbols);
94 | }
95 |
96 | } // namespace charly
97 |
--------------------------------------------------------------------------------
/src/charly/core/compiler/compiler.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 |
29 | #include "charly/core/compiler/ast.h"
30 | #include "charly/core/compiler/diagnostic.h"
31 | #include "charly/core/compiler/ir/builder.h"
32 | #include "charly/core/runtime/compiled_module.h"
33 | #include "charly/utils/buffer.h"
34 |
35 | #pragma once
36 |
37 | namespace charly::core::compiler {
38 |
39 | struct CompilationUnit {
40 | enum class Type : uint8_t {
41 | Module,
42 | ReplInput
43 | };
44 |
45 | CompilationUnit(Type type, const std::string& filepath, utils::Buffer& source) :
46 | type(type), console(filepath, source), filepath(filepath) {}
47 |
48 | Type type;
49 | DiagnosticConsole console;
50 | std::string filepath;
51 | ref ast;
52 | ref ir_module;
53 | ref compiled_module;
54 | };
55 |
56 | class Compiler {
57 | public:
58 | // compile source code into a compilation unit
59 | static ref compile(const std::string& filepath,
60 | utils::Buffer& source,
61 | CompilationUnit::Type type = CompilationUnit::Type::ReplInput);
62 | };
63 |
64 | } // namespace charly::core::compiler
65 |
--------------------------------------------------------------------------------
/src/charly/core/compiler/ir/assembler.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the Charly Virtual Machine (https://github.com/KCreate/charly-vm)
3 | *
4 | * MIT License
5 | *
6 | * Copyright (c) 2017 - 2022 Leonard Schütz
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include
28 | #include
29 | #include
30 |
31 | #include "charly/core/compiler/ir/builder.h"
32 | #include "charly/core/compiler/ir/ir.h"
33 |
34 | #include "charly/utils/buffer.h"
35 |
36 | #include "charly/core/runtime/compiled_module.h"
37 |
38 | #pragma once
39 |
40 | namespace charly::core::compiler::ir {
41 |
42 | class Assembler {
43 | public:
44 | static ref compile_module(const ref& module);
45 |
46 | private:
47 | explicit Assembler(const ref& module) : m_ir_module(module), m_label_counter(module->next_label) {}
48 |
49 | // assemble set ir module
50 | void assemble();
51 |
52 | // encode op into buffer
53 | void encode_instruction(const ref& op);
54 |
55 | // emit some padding bytes to align the next write to a pointer boundary
56 | void align_to_pointer();
57 |
58 | // reserve a new label
59 | Label reserve_label();
60 | void place_label(Label label);
61 |
62 | // resolve all unresolved label references in the bytecode buffer
63 | void patch_unresolved_labels();
64 |
65 | // returns the offset a given label refers to
66 | // asserts that the label was placed, programming error otherwise
67 | uint32_t offset_of_label(Label label);
68 |
69 | struct UnresolvedLabel {
70 | Label label;
71 | Label base;
72 | };
73 |
74 | ref m_runtime_module = nullptr;
75 | ref m_ir_module = nullptr;
76 | Label m_label_counter;
77 | std::unordered_map