├── .gitignore ├── .vscode └── settings.json ├── CMakeLists.txt ├── README.md ├── cmake └── modules │ └── Cobra.cmake ├── doc ├── Bytecode.md ├── GC.md ├── Guides.md ├── IR.md ├── Interpreter.md ├── Optimization.md └── Runtime.md ├── include └── cobra │ ├── AST │ ├── ASTBuilder.h │ ├── ASTVisitor.h │ ├── Context.h │ ├── DeclNodes.def │ ├── ExprNodes.def │ ├── PatternNodes.def │ ├── StmtNodes.def │ └── Tree.h │ ├── BCGen │ ├── BCGen.h │ ├── BCPasses.h │ ├── Bytecode.h │ ├── BytecodeGenerator.h │ ├── BytecodeInstructionGenerator.h │ ├── BytecodeInstructionSelector.h │ ├── BytecodeList.def │ ├── BytecodeRawData.h │ ├── Lowering.h │ ├── MovElimination.h │ └── RegAlloc.h │ ├── Driver │ └── Driver.h │ ├── IR │ ├── Analysis.h │ ├── CFG.h │ ├── Dominance.h │ ├── IR.h │ ├── IRBuilder.h │ ├── Instrs.def │ ├── Instrs.h │ ├── Scope.h │ └── ValueKinds.def │ ├── IRGen │ └── IRGen.h │ ├── Inst │ └── Inst.h │ ├── Optimizer │ ├── CSE.h │ ├── DCE.h │ ├── Inlining.h │ ├── Mem2Reg.h │ ├── Pass.h │ ├── PassManager.h │ ├── Passes.def │ ├── Pipeline.h │ ├── SSADestruction.h │ └── SimplifyCFG.h │ ├── Parser │ ├── Lexer.h │ ├── Parser.h │ └── TokenKinds.def │ ├── Support │ ├── Allocator.h │ ├── ArraySlice.h │ ├── Base64.h │ ├── BitSet.h │ ├── BitVector.h │ ├── Common.h │ ├── FixedArray.h │ ├── Leb128.h │ ├── MathExtras.h │ ├── OSCompat.h │ ├── SMLoc.h │ ├── StdLibExtras.h │ ├── StrideIterator.h │ ├── StringRef.h │ ├── StringTable.h │ ├── iterator.h │ ├── iterator_range.h │ ├── miniz.h │ └── zip.h │ ├── Utils │ └── IRPrinter.h │ └── VM │ ├── Array.h │ ├── CBValue.h │ ├── CardTable.h │ ├── CexFile.h │ ├── Class.h │ ├── ClassDataAccessor.h │ ├── ClassLinker.h │ ├── CobraCache.h │ ├── CobraVM.h │ ├── CodeBlock.h │ ├── CodeDataAccessor.h │ ├── Field.h │ ├── FreeList.h │ ├── GC.h │ ├── GCCell.h │ ├── GCPointer.h │ ├── GCRoot.h │ ├── Handle.h │ ├── HeapRegion.h │ ├── HeapRegionSpace.h │ ├── InterfaceTable.h │ ├── Interpreter.h │ ├── MarkBitSet.h │ ├── MemMapAllocator.h │ ├── Method.h │ ├── Modifiers.h │ ├── Object.h │ ├── ObjectAccessor.h │ ├── Offset.h │ ├── Operations.h │ ├── Primitive.h │ ├── Runtime.h │ ├── RuntimeGlobals.h │ ├── RuntimeModule.h │ ├── RuntimeOptions.h │ ├── StackFrame.h │ └── String.h ├── lib ├── AST │ ├── ASTBuilder.cpp │ ├── ASTVisitor.cpp │ ├── CMakeLists.txt │ ├── SemanticChecker.cpp │ ├── SemanticChecker.h │ └── Tree.cpp ├── BCGen │ ├── BCGen.cpp │ ├── BCPasses.cpp │ ├── Bytecode.cpp │ ├── BytecodeGenerator.cpp │ ├── BytecodeInstructionSelector.cpp │ ├── BytecodeRawData.cpp │ ├── CMakeLists.txt │ ├── Lowering.cpp │ ├── MovElimination.cpp │ └── RegAlloc.cpp ├── CMakeLists.txt ├── Driver │ ├── CMakeLists.txt │ └── Driver.cpp ├── IR │ ├── Analysis.cpp │ ├── Dominance.cpp │ ├── IR.cpp │ ├── IRBuilder.cpp │ ├── Instrs.cpp │ └── Scope.cpp ├── IRGen │ ├── IRGen.cpp │ ├── IRGenExpr.cpp │ ├── IRGenFunction.cpp │ └── IRGenStmt.cpp ├── Optimizer │ ├── CMakeLists.txt │ ├── CSE.cpp │ ├── DCE.cpp │ ├── Inlining.cpp │ ├── Mem2Reg.cpp │ ├── PassManager.cpp │ ├── Pipeline.cpp │ ├── SSADestruction.cpp │ └── SimplifyCFG.cpp ├── Parser │ ├── CMakeLists.txt │ ├── Lexer.cpp │ └── Parser.cpp ├── Support │ ├── Base64.cpp │ ├── CMakeLists.txt │ ├── OSCompatPosix.cpp │ ├── StringRef.cpp │ └── zip.cpp ├── Utils │ └── IRPrinter.cpp └── VM │ ├── Array.cpp │ ├── CBValue.cpp │ ├── CMakeLists.txt │ ├── CardTable.cpp │ ├── CexFile.cpp │ ├── Class.cpp │ ├── ClassDataAccessor.cpp │ ├── ClassLinker.cpp │ ├── CobraCache.cpp │ ├── CobraVM.cpp │ ├── CodeBlock.cpp │ ├── CodeDataAccessor.cpp │ ├── Field.cpp │ ├── FreeList.cpp │ ├── GC.cpp │ ├── GCCell.cpp │ ├── GCPointer.cpp │ ├── GCRoot.cpp │ ├── Handle.cpp │ ├── HeapRegion.cpp │ ├── HeapRegionSpace.cpp │ ├── InterfaceTable.cpp │ ├── Interpreter-inl.h │ ├── Interpreter.cpp │ ├── MemMapAllocator.cpp │ ├── Method.cpp │ ├── Object.cpp │ ├── ObjectAccessor.cpp │ ├── Offset.cpp │ ├── Operations.cpp │ ├── Primitive.cpp │ ├── Runtime.cpp │ ├── RuntimeModule.cpp │ ├── RuntimeOptions.cpp │ ├── StackFrame.cpp │ └── String.cpp ├── test ├── fibonacci.co └── num.co └── tools ├── CMakeLists.txt └── cobra ├── CMakeLists.txt └── cobra.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Xcode 4 | # 5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 6 | 7 | ## User settings 8 | xcuserdata/ 9 | 10 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 11 | *.xcscmblueprint 12 | *.xccheckout 13 | 14 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 15 | build/ 16 | DerivedData/ 17 | *.moved-aside 18 | *.pbxuser 19 | !default.pbxuser 20 | *.mode1v3 21 | !default.mode1v3 22 | *.mode2v3 23 | !default.mode2v3 24 | *.perspectivev3 25 | !default.perspectivev3 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | 30 | ## App packaging 31 | *.ipa 32 | *.dSYM.zip 33 | *.dSYM 34 | 35 | # CocoaPods 36 | # 37 | # We recommend against adding the Pods directory to your .gitignore. However 38 | # you should judge for yourself, the pros and cons are mentioned at: 39 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 40 | # 41 | Pods/ 42 | # 43 | # Add this line if you want to avoid checking in source code from the Xcode workspace 44 | # *.xcworkspace 45 | 46 | # Carthage 47 | # 48 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 49 | # Carthage/Checkouts 50 | 51 | Carthage/Build/ 52 | 53 | # fastlane 54 | # 55 | # It is recommended to not store the screenshots in the git repo. 56 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 57 | # For more information about the recommended setup visit: 58 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 59 | 60 | fastlane/report.xml 61 | fastlane/Preview.html 62 | fastlane/screenshots/**/*.png 63 | fastlane/test_output 64 | 65 | # Code Injection 66 | # 67 | # After new code Injection tools there's a generated folder /iOSInjectionProject 68 | # https://github.com/johnno1962/injectionforxcode 69 | 70 | iOSInjectionProject/ 71 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.def": "cpp", 4 | "string": "cpp" 5 | } 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Cobra 2 | 3 | Cobra is a high-level statically typed programming language, it's a variant and subset of [TypeScript ](https://www.typescriptlang.org/), it's mainly used for Mobile App cross-platform dynamic scenarios. It can be run in two ways, one is to interprete and execute bytecode, and the other is to be compiled into machine code through LLVM. Its goal is to be more lightweight and faster than JS/TS. 4 | 5 | You can check more about the Syntax here [Guides](./doc/Guides.md) 6 | 7 | Cobra references a lot of [hermes](https://github.com/facebook/hermes), [art](https://android.googlesource.com/platform/art) and [arkcompiler](https://gitee.com/openharmony/arkcompiler_runtime_core) 8 | 9 | ## Hello World! 10 | 11 | Be bold! End every statement with an exclamation mark! 12 | 13 | ``` 14 | print("Hello world") 15 | ``` 16 | 17 | ## Building the compiler 18 | To build a local debug version of the Cobra CLI tools the following steps should get you started on macOS/Linux 19 | 20 | ``` 21 | mkdir cobra_workingdir 22 | cd cobra_workingdir 23 | git clone https://github.com/cobra-language/cobra 24 | cmake -B build -G Ninja 25 | cmake --build ./build 26 | ``` 27 | 28 | Build a Xcode project 29 | 30 | ``` 31 | mkdir cobra_workingdir 32 | cd cobra_workingdir 33 | mkdir build && cd build 34 | cmake .. -G "Xcode" 35 | ``` 36 | 37 | ## Implementation status 38 | 39 | This project is under active development; expect things to break and APIs to change. 40 | 41 | The compiler pipeline is organized as below. Incidentally, early stages of this pipeline are more stable than later ones. (Note: completion percentages are very rough estimations.) 42 | 43 | * Parsing (20%) 44 | * Type checking (0%) 45 | * IR lowering (40%) 46 | * IR analysis and transformations (20%) 47 | * Bytecode generation (40%) 48 | * Bytecode Interpreter (5%) 49 | * Debug info(0%) 50 | * Runtime (10%) 51 | * GC (5%) 52 | * Machine code generation (0%) 53 | 54 | ## Contributing 55 | We welcome contributions to Cobra, if you has any questions, you can contact Roy (335050309@qq.com). 56 | 57 | ## Authors 58 | Roy [woshiccm](https://github.com/woshiccm) 59 | 60 | -------------------------------------------------------------------------------- /doc/Bytecode.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobra-language/cobra/37f8560a9ac30123b5942db0c9b106b8d15a86a6/doc/Bytecode.md -------------------------------------------------------------------------------- /doc/GC.md: -------------------------------------------------------------------------------- 1 | [Deep Dive into Garbage Collection in Ruby 3: Incremental Garbage Collection](https://patrickkarsh.medium.com/deep-dive-into-garbage-collection-in-ruby-3-incremental-garbage-collection-29775d48e253) 2 | 3 | [Incremental cycle GC #613](https://github.com/faster-cpython/ideas/issues/613) 4 | 5 | [GH-108362: Incremental GC implementation #116206](https://github.com/python/cpython/pull/116206) 6 | 7 | [Understanding GC in JSC From Scratch](https://sillycross.github.io/2022/06/02/2022-06-02/) 8 | 9 | [JVM成神路之GC分代篇:分代GC器、CMS收集器及YoungGC、FullGC](https://www.leyeah.com/article/generation-jvm-shenzhen-road-gc-collector-younggc-fullgc-743283) 10 | 11 | [[典藏版]Golang三色标记+混合写屏障GC模式全分析](https://developer.aliyun.com/article/861507) 12 | 13 | [我是这么理解双色/三色标记清除GC算法的](https://zhuanlan.zhihu.com/p/527512898) 14 | 15 | 16 | # Handle 17 | 18 | [Art handle](https://android.googlesource.com/platform/art/+/refs/heads/main/runtime/handle.h#44) 19 | [V8 handle](https://github.com/v8/v8/blob/5792f3587116503fc047d2f68c951c72dced08a5/src/handles/handles.h#L78C24-L78C33) 20 | [JSC handle](https://github.com/WebKit/WebKit/blob/main/Source/JavaScriptCore/heap/Handle.h#L34) 21 | [ArkCompiler - handleBase](https://gitee.com/openharmony/arkcompiler_runtime_core/blob/master/static_core/runtime/handle_base.h#L27) 22 | [ArkCompiler - handle](https://gitee.com/openharmony/arkcompiler_runtime_core/blob/master/static_core/runtime/mem/vm_handle.h#L33) 23 | [LibJS handle](https://github.com/SerenityOS/serenity/blob/master/Userland/Libraries/LibJS/Heap/Handle.h#L20) -------------------------------------------------------------------------------- /doc/Guides.md: -------------------------------------------------------------------------------- 1 | # Values 2 | 3 | ### Booleans 4 | 5 | 6 | ### Numbers 7 | 8 | 9 | ### Strings 10 | 11 | ### Null 12 | 13 | # Array 14 | 15 | 16 | # Map 17 | 18 | # Enums 19 | 20 | We’ll first start off with numeric enums, which are probably more familiar if you’re coming from other languages. An enum can be defined using the enum keyword. 21 | 22 | ``` 23 | enum Direction { 24 | Up = 1, 25 | Down, 26 | Left, 27 | Right, 28 | } 29 | 30 | ``` 31 | 32 | If we wanted, we could leave off the initializers entirely: 33 | 34 | ``` 35 | enum Direction { 36 | Up, 37 | Down, 38 | Left, 39 | Right, 40 | } 41 | 42 | ``` 43 | 44 | Using an enum is simple: just access any member as a property off of the enum itself, and declare types using the name of the enum: 45 | 46 | ``` 47 | enum UserResponse { 48 | No = 0, 49 | Yes = 1, 50 | } 51 | 52 | function respond(recipient: string, message: UserResponse): void { 53 | // ... 54 | } 55 | 56 | respond("Princess Caroline", UserResponse.Yes); 57 | ``` 58 | 59 | String enums are a similar concept, but have some subtle runtime differences as documented below. In a string enum, each member has to be constant-initialized with a string literal, or with another string enum member. 60 | 61 | ``` 62 | enum Direction { 63 | Up = "UP", 64 | Down = "DOWN", 65 | Left = "LEFT", 66 | Right = "RIGHT", 67 | } 68 | 69 | ``` 70 | 71 | 72 | # Function 73 | 74 | The simplest way to describe a function is with a function type expression. These types are syntactically similar to arrow functions: 75 | 76 | ``` 77 | function greeter(fn: (a: string) => void) { 78 | fn("Hello, World"); 79 | } 80 | 81 | function printToConsole(s: string) { 82 | console.log(s); 83 | } 84 | 85 | greeter(printToConsole); 86 | 87 | ``` 88 | Of course, we can use a type alias to name a function type: 89 | 90 | ``` 91 | type GreetFunction = (a: string) => void; 92 | function greeter(fn: GreetFunction) { 93 | // ... 94 | } 95 | ``` 96 | 97 | We can model this in TypeScript by marking the parameter as optional with ?: 98 | 99 | ``` 100 | function f(x?: number) { 101 | // ... 102 | } 103 | f(); // OK 104 | f(10); // OK 105 | 106 | ``` 107 | 108 | You can also provide a parameter default: 109 | 110 | ``` 111 | function f(x = 10) { 112 | // ... 113 | } 114 | 115 | f(); // OK 116 | f(10); // OK 117 | 118 | ``` 119 | 120 | # Class 121 | 122 | A field declaration creates a public writeable property on a class: 123 | 124 | ``` 125 | class Point { 126 | x: number; 127 | y: number; 128 | } 129 | 130 | const pt = new Point(); 131 | pt.x = 0; 132 | pt.y = 0; 133 | 134 | ``` 135 | 136 | Fields can also have initializers; these will run automatically when the class is instantiated: 137 | 138 | ``` 139 | class Point { 140 | x = 0; 141 | y = 0; 142 | } 143 | 144 | const pt = new Point(); 145 | 146 | ``` 147 | 148 | Classes may extend from a base class. A derived class has all the properties and methods of its base class, and can also define additional members. 149 | 150 | ``` 151 | class Animal { 152 | move() { 153 | console.log("Moving along!"); 154 | } 155 | } 156 | 157 | class Dog extends Animal { 158 | woof(times: number) { 159 | for (let i = 0; i < times; i++) { 160 | console.log("woof!"); 161 | } 162 | } 163 | } 164 | 165 | const d = new Dog(); 166 | // Base class method 167 | d.move(); 168 | // Derived class method 169 | d.woof(3); 170 | 171 | ``` 172 | 173 | A derived class can also override a base class field or property. You can use the super. syntax to access base class methods 174 | 175 | ``` 176 | class Base { 177 | greet() { 178 | console.log("Hello, world!"); 179 | } 180 | } 181 | 182 | class Derived extends Base { 183 | greet(name?: string) { 184 | if (name === undefined) { 185 | super.greet(); 186 | } else { 187 | console.log(`Hello, ${name.toUpperCase()}`); 188 | } 189 | } 190 | } 191 | 192 | const d = new Derived(); 193 | d.greet(); 194 | d.greet("reader"); 195 | 196 | ``` 197 | 198 | -------------------------------------------------------------------------------- /doc/IR.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobra-language/cobra/37f8560a9ac30123b5942db0c9b106b8d15a86a6/doc/IR.md -------------------------------------------------------------------------------- /doc/Interpreter.md: -------------------------------------------------------------------------------- 1 | 2 | ### Key Design Decisions 3 | 4 | 1. Interpreter uses indirect threaded dispatch technique (implemented via computed goto) to reduce dispatch overhead. 5 | 2. Bytecode is register-based: all arguments and variables are mapped to virtual registers, and most of bytecodes encode virtual registers as operands. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | [PEP 659 – Specializing Adaptive Interpreter](https://peps.python.org/pep-0659/) 14 | 15 | [ arkcompiler runtime core/docs/design-of-interpreter.md ](https://gitee.com/openharmony/arkcompiler_runtime_core/blob/master/docs/design-of-interpreter.md) 16 | 17 | [Dynamic Interpretation for Dynamic Scripting Languages](https://publications.scss.tcd.ie/tech-reports/reports.09/TCD-CS-2009-37.pdf) 18 | [Swift: A Register-based JIT Compiler for Embedded JVMs](https://yuanxzhang.github.io/paper/swift-vee2012.pdf) 19 | 20 | [The construction of high-performance virtual machines for dynamic languages, Mark Shannon 2011.](https://theses.gla.ac.uk/2975/1/2011shannonphd.pdf) 21 | 22 | [ The fastest WebAssembly interpreter \(and the most universal wasm runtime\)](https://github.com/wasm3/wasm3) 23 | 24 | [Building the fastest Lua interpreter.. automatically!](https://sillycross.github.io/2022/11/22/2022-11-22/) -------------------------------------------------------------------------------- /doc/Optimization.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobra-language/cobra/37f8560a9ac30123b5942db0c9b106b8d15a86a6/doc/Optimization.md -------------------------------------------------------------------------------- /doc/Runtime.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobra-language/cobra/37f8560a9ac30123b5942db0c9b106b8d15a86a6/doc/Runtime.md -------------------------------------------------------------------------------- /include/cobra/AST/ASTBuilder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef ASTBuilder_h 9 | #define ASTBuilder_h 10 | 11 | namespace cobra { 12 | 13 | class ASTBuilder { 14 | 15 | }; 16 | 17 | } 18 | 19 | #endif /* ASTBuilder_h */ 20 | -------------------------------------------------------------------------------- /include/cobra/AST/ASTVisitor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef ASTVisitor_h 9 | #define ASTVisitor_h 10 | 11 | #include "cobra/AST/Tree.h" 12 | 13 | namespace cobra { 14 | 15 | template 20 | class ASTVisitor { 21 | public: 22 | 23 | void visit(ASTNode *n) { 24 | if (auto *D = dynamic_cast(n)) { 25 | visitDecl(D); 26 | } else if (auto *S = dynamic_cast(n)) { 27 | visitStmt(S); 28 | } else if (auto *E = dynamic_cast(n)) { 29 | visitExpr(E); 30 | } 31 | } 32 | 33 | DeclRetTy visitDecl(Decl *D, Args... AA) { 34 | switch (D->getKind()) { 35 | 36 | #define DECL(CLASS, PARENT) \ 37 | case DeclKind::CLASS: \ 38 | return static_cast(this) \ 39 | ->visit##CLASS##Decl(static_cast(D), \ 40 | ::std::forward(AA)...); 41 | #include "cobra/AST/DeclNodes.def" 42 | 43 | } 44 | } 45 | 46 | ExprRetTy visitExpr(Expr *E, Args... AA) { 47 | switch (E->getKind()) { 48 | 49 | #define EXPR(CLASS, PARENT) \ 50 | case ExprKind::CLASS: \ 51 | return static_cast(this) \ 52 | ->visit##CLASS##Expr(static_cast(E), \ 53 | ::std::forward(AA)...); 54 | #include "cobra/AST/ExprNodes.def" 55 | 56 | } 57 | } 58 | 59 | StmtRetTy visitStmt(Stmt *S, Args... AA) { 60 | switch (S->getKind()) { 61 | 62 | #define STMT(CLASS, PARENT) \ 63 | case StmtKind::CLASS: \ 64 | return static_cast(this) \ 65 | ->visit##CLASS##Stmt(static_cast(S), \ 66 | ::std::forward(AA)...); 67 | #include "cobra/AST/StmtNodes.def" 68 | } 69 | } 70 | 71 | }; 72 | 73 | } 74 | 75 | #endif /* ASTVisitor_h */ 76 | -------------------------------------------------------------------------------- /include/cobra/AST/Context.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Context_h 9 | #define Context_h 10 | 11 | #include "cobra/Support/Allocator.h" 12 | #include "cobra/Support/StringTable.h" 13 | 14 | namespace cobra { 15 | 16 | class Context { 17 | private: 18 | Allocator allocator_{}; 19 | Allocator identifierAllocator_{}; 20 | StringTable stringTable_{identifierAllocator_}; 21 | 22 | public: 23 | explicit Context() = default; 24 | ~Context() = default; 25 | 26 | Allocator &getAllocator() { 27 | return allocator_; 28 | } 29 | 30 | Identifier getIdentifier(StringRef str) { 31 | return stringTable_.getIdentifier(str); 32 | } 33 | 34 | StringRef toString(Identifier iden) { 35 | return iden.str(); 36 | } 37 | 38 | template 39 | T *allocateNode(size_t num = 1) { 40 | return allocator_.template Allocate(num); 41 | } 42 | 43 | void *allocateNode(size_t size, size_t alignment) { 44 | return allocator_.Allocate(size, alignment); 45 | } 46 | 47 | }; 48 | 49 | } 50 | 51 | #endif /* Context_h */ 52 | -------------------------------------------------------------------------------- /include/cobra/AST/ExprNodes.def: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | /// EXPR(Id, Parent) 9 | /// If the expression node is not abstract, its enumerator value is 10 | /// ExprKind::Id. The node's class name is Id##Expr, and the name of 11 | /// its base class (in the Expr hierarchy) is Parent. 12 | #ifndef EXPR 13 | #define EXPR(Id, Parent) 14 | #endif 15 | 16 | /// An abstract expression node is an abstract base class in the hierarchy; 17 | /// it is never a most-derived type, and it does not have an enumerator in 18 | /// ExprKind. 19 | /// 20 | /// Most metaprograms do not care about abstract expressions, so the default 21 | /// is to ignore them. 22 | #ifndef ABSTRACT_EXPR 23 | #define ABSTRACT_EXPR(Id, Parent) 24 | #endif 25 | 26 | /// An "unchecked" expression node is removed from valid code by the end 27 | /// of the type-checking phase. 28 | /// 29 | /// By default, these are treated like any other expression. 30 | #ifndef UNCHECKED_EXPR 31 | #define UNCHECKED_EXPR(Id, Parent) EXPR(Id, Parent) 32 | #endif 33 | 34 | /// A literal expression node represents a literal value, such as a number, 35 | /// boolean, string, etc. 36 | /// 37 | /// By default, these are treated like any other expression. 38 | #ifndef LITERAL_EXPR 39 | #define LITERAL_EXPR(Id, Parent) EXPR(Id, Parent) 40 | #endif 41 | 42 | /// A expression node with a DeclContext. For example: closures. 43 | /// 44 | /// By default, these are treated like any other expression. 45 | #ifndef CONTEXT_EXPR 46 | #define CONTEXT_EXPR(Id, Parent) EXPR(Id, Parent) 47 | #endif 48 | 49 | /// A convenience for determining the range of expressions. These will always 50 | /// appear immediately after the last member. 51 | #ifndef EXPR_RANGE 52 | #define EXPR_RANGE(Id, First, Last) 53 | #endif 54 | 55 | #ifndef LAST_EXPR 56 | #define LAST_EXPR(Id) 57 | #endif 58 | 59 | EXPR(BooleanLiteral, Expr) 60 | EXPR(NumericLiteral, Expr) 61 | EXPR(StringLiteral, Expr) 62 | EXPR(Call, Expr) 63 | EXPR(Member, Expr) 64 | EXPR(Identifier, Expr) 65 | EXPR(Unary, Expr) 66 | EXPR(PostfixUnary, Expr) 67 | EXPR(Binary, Expr) 68 | EXPR(Conditional, Expr) 69 | EXPR(Assignment, Expr) 70 | EXPR(SpreadElement, Expr) 71 | 72 | // Don't forget to update the LAST_EXPR below when adding a new Expr here. 73 | LAST_EXPR(Binary) 74 | 75 | #undef EXPR_RANGE 76 | #undef LITERAL_EXPR 77 | #undef UNCHECKED_EXPR 78 | #undef ABSTRACT_EXPR 79 | #undef CONTEXT_EXPR 80 | #undef EXPR 81 | #undef LAST_EXPR 82 | -------------------------------------------------------------------------------- /include/cobra/AST/PatternNodes.def: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | /// PATTERN(Id, Parent) 9 | /// The pattern's enumerator value is PatternKind::Id. The pattern's 10 | /// class name is Id##Pattern, and the name of its base class is Parent. 11 | #ifndef PATTERN 12 | # error Included PatternNodes.def without defining PATTERN! 13 | #endif 14 | 15 | /// REFUTABLE_PATTERN(Id, Parent) 16 | /// Matching this pattern can fail. These patterns cannot appear syntactically 17 | /// in variable declarations, assignments, or function declarations. 18 | #ifndef REFUTABLE_PATTERN 19 | # define REFUTABLE_PATTERN(Id, Parent) PATTERN(Id, Parent) 20 | #endif 21 | 22 | #ifndef LAST_PATTERN 23 | #define LAST_PATTERN(Id) 24 | #endif 25 | 26 | // Metavars: x (variable binding), pat (pattern), e (expression) 27 | PATTERN(Paren, Pattern) // (pat) 28 | PATTERN(Tuple, Pattern) // (pat1, ..., patN), N >= 1 29 | PATTERN(Named, Pattern) // let pat, var pat 30 | PATTERN(Any, Pattern) // _ 31 | PATTERN(Typed, Pattern) // pat : type 32 | PATTERN(Binding, Pattern) // x 33 | REFUTABLE_PATTERN(Is, Pattern) // x is myclass 34 | REFUTABLE_PATTERN(EnumElement, Pattern) // .mycase(pat1, ..., patN) 35 | // MyType.mycase(pat1, ..., patN) 36 | REFUTABLE_PATTERN(OptionalSome, Pattern) // pat? nil 37 | REFUTABLE_PATTERN(Bool, Pattern) // true, false 38 | REFUTABLE_PATTERN(Expr, Pattern) // e 39 | LAST_PATTERN(Expr) 40 | 41 | #undef REFUTABLE_PATTERN 42 | #undef PATTERN 43 | #undef LAST_PATTERN 44 | -------------------------------------------------------------------------------- /include/cobra/AST/StmtNodes.def: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | /// STMT(Id, Parent) 9 | /// If the statement node is not abstract, its enumerator value is 10 | /// StmtKind::Id. The node's class name is Id##Stmt, and the name of 11 | /// its base class (in the Stmt hierarchy) is Parent. 12 | 13 | /// An abstract statement node is an abstract base class in the hierarchy; 14 | /// it is never a most-derived type, and it does not have an enumerator in 15 | /// StmtKind. 16 | /// 17 | /// Most metaprograms do not care about abstract statements, so the default 18 | /// is to ignore them. 19 | #ifndef ABSTRACT_STMT 20 | #define ABSTRACT_STMT(Id, Parent) 21 | #endif 22 | 23 | /// A subclass of LabeledStmt. Forwards to STMT by default. 24 | #ifndef LABELED_STMT 25 | #define LABELED_STMT(Id, Parent) STMT(Id, Parent) 26 | #endif 27 | 28 | /// A convenience for determining the range of statements. These will always 29 | /// appear immediately after the last member. 30 | #ifndef STMT_RANGE 31 | #define STMT_RANGE(Id, First, Last) 32 | #endif 33 | 34 | #ifndef LAST_STMT 35 | #define LAST_STMT(Id) 36 | #endif 37 | 38 | STMT(Block, Stmt) 39 | STMT(Return, Stmt) 40 | STMT(If, Stmt) 41 | STMT(Variable, Stmt) 42 | STMT(Expression, Stmt) 43 | LAST_STMT(Expression) 44 | 45 | #undef STMT_RANGE 46 | #undef LABELED_STMT 47 | #undef ABSTRACT_STMT 48 | #undef STMT 49 | #undef LAST_STMT 50 | -------------------------------------------------------------------------------- /include/cobra/BCGen/BCGen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef BCGen_h 9 | #define BCGen_h 10 | 11 | #include "cobra/IR/IR.h" 12 | #include "cobra/BCGen/Bytecode.h" 13 | 14 | #include 15 | 16 | namespace cobra { 17 | 18 | std::unique_ptr generateBytecode(Module *M); 19 | 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/cobra/BCGen/BCPasses.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef BCPasses_h 9 | #define BCPasses_h 10 | 11 | 12 | #include "cobra/IR/IR.h" 13 | #include "cobra/Optimizer/Pass.h" 14 | 15 | namespace cobra { 16 | 17 | class LoadConstants : public FunctionPass { 18 | 19 | public: 20 | explicit LoadConstants() : FunctionPass("LoadConstants") {} 21 | ~LoadConstants() override = default; 22 | 23 | bool runOnFunction(Function *F) override; 24 | }; 25 | 26 | class LoadParameters : public FunctionPass { 27 | public: 28 | explicit LoadParameters() : FunctionPass("LoadParameters") {} 29 | ~LoadParameters() override = default; 30 | 31 | bool runOnFunction(Function *F) override; 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/cobra/BCGen/Bytecode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Bytecode_h 9 | #define Bytecode_h 10 | 11 | #include 12 | 13 | namespace cobra { 14 | 15 | using opcode_t = uint8_t; 16 | 17 | struct FunctionHeader { 18 | uint32_t size; 19 | uint32_t paramCount; 20 | uint32_t functionNameID; 21 | }; 22 | 23 | // This class represents the in-memory representation of the bytecode function. 24 | class BytecodeFunction { 25 | 26 | std::vector opcodesAndJumpTables_; 27 | 28 | public: 29 | explicit BytecodeFunction(std::vector &&opcodesAndJumpTables) 30 | : opcodesAndJumpTables_(std::move(opcodesAndJumpTables)) {} 31 | 32 | std::vector &getOpcodes() { 33 | return opcodesAndJumpTables_; 34 | } 35 | 36 | }; 37 | 38 | class BytecodeModule { 39 | using FunctionList = std::vector>; 40 | 41 | FunctionList functions_{}; 42 | 43 | public: 44 | explicit BytecodeModule(uint32_t functionCount) { 45 | functions_.resize(functionCount); 46 | } 47 | 48 | uint32_t getNumFunctions() const { 49 | return functions_.size(); 50 | } 51 | 52 | /// Add a new bytecode function to the module at \p index. 53 | void setFunction(uint32_t index, std::unique_ptr F); 54 | 55 | BytecodeFunction &getFunction(unsigned index); 56 | 57 | }; 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /include/cobra/BCGen/BytecodeGenerator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef BytecodeGenerator_h 9 | #define BytecodeGenerator_h 10 | 11 | #include 12 | 13 | #include "cobra/IR/IR.h" 14 | #include "cobra/IR/Instrs.h" 15 | #include "cobra/BCGen/Bytecode.h" 16 | #include "cobra/BCGen/RegAlloc.h" 17 | #include "cobra/BCGen/BytecodeInstructionGenerator.h" 18 | 19 | namespace cobra { 20 | 21 | class BytecodeGenerator; 22 | 23 | struct Relocation { 24 | enum RelocationType { 25 | // A short jump instruction 26 | JumpType = 0, 27 | // A long jump instruction 28 | LongJumpType, 29 | // A basic block 30 | BasicBlockType, 31 | // A catch instruction 32 | CatchType, 33 | }; 34 | 35 | /// The current location of this relocation. 36 | offset_t loc; 37 | /// Type of the relocation. 38 | RelocationType type; 39 | /// We multiplex pointer for different things under different types: 40 | /// If the type is jump or long jump, pointer is the target basic block; 41 | /// if the type is basic block, pointer is the pointer to it. 42 | /// if the type is catch instruction, pointer is the pointer to it. 43 | Value *pointer; 44 | }; 45 | 46 | class BytecodeFunctionGenerator : public BytecodeInstructionGenerator { 47 | 48 | BytecodeGenerator &BCGen_; 49 | 50 | Function *F_; 51 | 52 | VirtualRegisterAllocator &RA_; 53 | 54 | /// For each Basic Block, we map to its beginning instruction location 55 | /// and the next basic block. We need this information to resolve jump 56 | /// targets and exception handler table. 57 | std::map> basicBlockMap_{}; 58 | 59 | /// The list of all jump instructions and jump targets that require 60 | /// relocation and address resolution. 61 | std::vector relocations_{}; 62 | 63 | void emitMovIfNeeded(param_t dest, param_t src); 64 | 65 | public: 66 | explicit BytecodeFunctionGenerator( 67 | BytecodeGenerator &BCGen, 68 | Function *F, 69 | VirtualRegisterAllocator &RA) 70 | : BCGen_(BCGen), F_(F), RA_(RA) {} 71 | 72 | static std::unique_ptr create( 73 | BytecodeGenerator &BCGen, 74 | Function *F, 75 | VirtualRegisterAllocator &RA) { 76 | return std::unique_ptr( 77 | new BytecodeFunctionGenerator(BCGen, F, RA)); 78 | } 79 | 80 | /// Add long jump instruction to the relocation list. 81 | void addJumpToRelocations(offset_t loc, BasicBlock *target); 82 | 83 | void generateJumpTable(); 84 | 85 | void resolveRelocations(); 86 | 87 | unsigned encodeValue(Value *value); 88 | 89 | #define INCLUDE_HBC_INSTRS 90 | #define DEF_VALUE(CLASS, PARENT) \ 91 | void generate##CLASS(CLASS *Inst, BasicBlock *next); 92 | #include "cobra/IR/ValueKinds.def" 93 | #undef DEF_VALUE 94 | #undef MARK_VALUE 95 | #undef INCLUDE_HBC_INSTRS 96 | 97 | void generateBody(); 98 | 99 | void generateCodeBlock(BasicBlock *BB, BasicBlock *next); 100 | 101 | void generateInst(Instruction *ii, BasicBlock *next); 102 | 103 | std::unique_ptr generateBytecodeFunction(); 104 | 105 | void shrinkJump(offset_t loc); 106 | 107 | void updateJumpTarget(offset_t loc, int newVal, int bytes); 108 | 109 | /// Change the opcode of a long jump instruction into a short jump. 110 | inline void longToShortJump(offset_t loc) { 111 | switch (opcodes_[loc]) { 112 | #define DEFINE_JUMP_LONG_VARIANT(shortName, longName) \ 113 | case longName##Op: \ 114 | opcodes_[loc] = shortName##Op; \ 115 | break; 116 | #include "cobra/BCGen/BytecodeList.def" 117 | default: 118 | COBRA_UNREACHABLE(); 119 | } 120 | } 121 | 122 | }; 123 | 124 | class BytecodeGenerator : public BytecodeInstructionGenerator { 125 | 126 | std::map> 127 | functionGenerators_{}; 128 | std::vector functions; 129 | std::map functionIDMap; 130 | 131 | public: 132 | 133 | unsigned addFunction(Function *F); 134 | 135 | void setFunctionGenerator( 136 | Function *F, 137 | std::unique_ptr BFG); 138 | 139 | std::unique_ptr generate(); 140 | 141 | }; 142 | 143 | } 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /include/cobra/BCGen/BytecodeInstructionSelector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef BytecodeInstructionSelector_h 9 | #define BytecodeInstructionSelector_h 10 | 11 | #include "cobra/IR/IR.h" 12 | #include "cobra/BCGen/BytecodeGenerator.h" 13 | 14 | namespace cobra { 15 | 16 | class BytecodeInstructionSelector { 17 | 18 | }; 19 | 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/cobra/BCGen/BytecodeRawData.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef BytecodeRawData_h 9 | #define BytecodeRawData_h 10 | 11 | #include 12 | 13 | #include "cobra/BCGen/Bytecode.h" 14 | 15 | namespace cobra { 16 | 17 | class BytecodeRawData { 18 | std::unique_ptr byteCodeModule_; 19 | 20 | public: 21 | explicit BytecodeRawData(std::unique_ptr byteCodeModule); 22 | 23 | static std::unique_ptr create( 24 | std::unique_ptr byteCodeModule) { 25 | return std::unique_ptr( 26 | new BytecodeRawData(std::move(byteCodeModule))); 27 | } 28 | 29 | const uint8_t *getBytecode(uint32_t functionID) const { 30 | return byteCodeModule_->getFunction(functionID).getOpcodes().data(); 31 | } 32 | 33 | }; 34 | 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/cobra/BCGen/Lowering.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Lowering_h 9 | #define Lowering_h 10 | 11 | namespace cobra { 12 | 13 | } 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /include/cobra/BCGen/MovElimination.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef MovElimination_h 9 | #define MovElimination_h 10 | 11 | #include "cobra/IR/IR.h" 12 | #include "cobra/Optimizer/Pass.h" 13 | 14 | namespace cobra { 15 | 16 | class VirtualRegisterAllocator; 17 | 18 | class MovElimination : public FunctionPass { 19 | public: 20 | explicit MovElimination(VirtualRegisterAllocator &RA) 21 | : FunctionPass("MovElimination"), RA_(RA) {} 22 | ~MovElimination() override = default; 23 | 24 | bool runOnFunction(Function *F) override; 25 | 26 | private: 27 | VirtualRegisterAllocator &RA_; 28 | }; 29 | 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/cobra/Driver/Driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Driver_h 9 | #define Driver_h 10 | 11 | #include 12 | 13 | #include "cobra/Parser/Parser.h" 14 | #include "cobra/IRGen/IRGen.h" 15 | 16 | namespace cobra { 17 | namespace driver { 18 | 19 | bool compile(std::string source); 20 | 21 | 22 | } // namespace driver 23 | } // namespace cobra 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/cobra/IR/Analysis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Analysis_h 9 | #define Analysis_h 10 | 11 | #include "cobra/IR/CFG.h" 12 | #include "cobra/IR/IR.h" 13 | 14 | namespace cobra { 15 | 16 | /// This is an implementation of the post-order scan. We use our own 17 | /// implementation and not the LLVM RPO analysis because we currently have 18 | /// basic blocks that are not linked to the entry blocks (catch blocks), 19 | /// and LLVM's graph traits expect all blocks to be reachable from the entry 20 | /// blocks. The analysis does not enumerate unreachable blocks. 21 | class PostOrderAnalysis { 22 | using BlockList = std::vector; 23 | 24 | /// The AST context, which here is only used by Dump(). 25 | Context &ctx_; 26 | 27 | /// Holds the ordered list of basic blocks. 28 | BlockList Order; 29 | 30 | /// This function does the recursive scan of the function. \p BB is the basic 31 | /// block that starts the scan. \p order is the ordered list of blocks, and 32 | /// the output. 33 | static void visitPostOrder(BasicBlock *BB, BlockList &order); 34 | 35 | public: 36 | explicit PostOrderAnalysis(Function *F); 37 | 38 | using iterator = decltype(Order)::iterator; 39 | using const_iterator = decltype(Order)::const_iterator; 40 | using reverse_iterator = decltype(Order)::reverse_iterator; 41 | using const_reverse_iterator = decltype(Order)::const_reverse_iterator; 42 | 43 | using range = llvh::iterator_range; 44 | using const_range = llvh::iterator_range; 45 | using reverse_range = llvh::iterator_range; 46 | using const_reverse_range = llvh::iterator_range; 47 | 48 | inline iterator begin() { 49 | return Order.begin(); 50 | } 51 | inline iterator end() { 52 | return Order.end(); 53 | } 54 | inline reverse_iterator rbegin() { 55 | return Order.rbegin(); 56 | } 57 | inline reverse_iterator rend() { 58 | return Order.rend(); 59 | } 60 | inline const_iterator begin() const { 61 | return Order.begin(); 62 | } 63 | inline const_iterator end() const { 64 | return Order.end(); 65 | } 66 | inline const_reverse_iterator rbegin() const { 67 | return Order.rbegin(); 68 | } 69 | inline const_reverse_iterator rend() const { 70 | return Order.rend(); 71 | } 72 | }; 73 | 74 | } // end namespace cobra 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /include/cobra/IR/IRBuilder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef IRBuilder_h 9 | #define IRBuilder_h 10 | 11 | #include 12 | #include "cobra/IR/IR.h" 13 | #include "cobra/Support/StringTable.h" 14 | #include "cobra/IR/Instrs.h" 15 | #include "cobra/AST/Context.h" 16 | 17 | namespace cobra { 18 | 19 | class IRBuilder { 20 | IRBuilder(const IRBuilder &) = delete; 21 | void operator=(const IRBuilder &) = delete; 22 | 23 | Module *M; 24 | BasicBlock::iterator InsertionPoint{}; 25 | BasicBlock *Block{}; 26 | SMLoc Location{}; 27 | 28 | LiteralEmpty literalEmpty{}; 29 | LiteralUndefined literalUndefined{}; 30 | LiteralNull literalNull{}; 31 | LiteralBool literalFalse{false}; 32 | LiteralBool literalTrue{true}; 33 | 34 | public: 35 | explicit IRBuilder(Module *Mod) : M(Mod) {} 36 | 37 | explicit IRBuilder(Function *F) : M(F->getParent()) {} 38 | 39 | Module *getModule() { 40 | return M; 41 | } 42 | 43 | BasicBlock *createBasicBlock(Function *Parent); 44 | 45 | Function *createFunction(Identifier OriginalName); 46 | 47 | Parameter *createParameter(Function *Parent, Identifier OriginalName); 48 | 49 | Variable *createVariable(Variable::DeclKind declKind, Identifier Name); 50 | 51 | LiteralNumber *getLiteralNumber(double value); 52 | 53 | LiteralString *getLiteralString(StringRef value); 54 | 55 | LiteralBool *getLiteralBool(bool value); 56 | 57 | LiteralEmpty *getLiteralEmpty(); 58 | 59 | LiteralUndefined *getLiteralUndefined(); 60 | 61 | LiteralNull *getLiteralNull(); 62 | 63 | Identifier createIdentifier(StringRef str); 64 | 65 | private: 66 | void insert(Instruction *Inst); 67 | 68 | public: 69 | 70 | void setInsertionBlock(BasicBlock *BB); 71 | 72 | BasicBlock *getInsertionBlock(); 73 | 74 | Function *getFunction() { 75 | assert(Block && "Builder has no current function"); 76 | return Block->getParent(); 77 | } 78 | 79 | void setInsertionPoint(Instruction *IP); 80 | 81 | BranchInst *createBranchInst(BasicBlock *Destination); 82 | 83 | CondBranchInst * 84 | createCondBranchInst(Value *Cond, BasicBlock *T, BasicBlock *F); 85 | 86 | ReturnInst *createReturnInst(Value *Val); 87 | 88 | AllocStackInst *createAllocStackInst(Identifier varName); 89 | 90 | LoadStackInst *createLoadStackInst(AllocStackInst *ptr); 91 | 92 | StoreStackInst *createStoreStackInst(Value *storedValue, AllocStackInst *ptr); 93 | 94 | BinaryOperatorInst *createBinaryOperatorInst( 95 | Value *left, 96 | Value *right, 97 | BinaryOperatorInst::OpKind opKind); 98 | 99 | PhiInst *createPhiInst( 100 | const PhiInst::ValueListType &values, 101 | const PhiInst::BasicBlockListType &blocks); 102 | 103 | PhiInst *createPhiInst(); 104 | 105 | MovInst *createMovInst(Value *input); 106 | 107 | LoadConstInst *createLoadConstInst(Literal *value); 108 | 109 | LoadParamInst *createLoadParamInst(LiteralNumber *value); 110 | 111 | /// This is an RAII object that destroys instructions when it is destroyed. 112 | class InstructionDestroyer { 113 | InstructionDestroyer(const InstructionDestroyer &) = delete; 114 | void operator=(const InstructionDestroyer &) = delete; 115 | 116 | std::vector list{}; 117 | 118 | public: 119 | explicit InstructionDestroyer() = default; 120 | 121 | /// \returns true if the instruction \p A is already in the destruction 122 | /// queue. Notice that this is an O(n) search and should only be used for 123 | /// debugging. 124 | bool hasInstruction(Instruction *A) { 125 | return std::find(list.begin(), list.end(), A) != list.end(); 126 | } 127 | 128 | /// Add the instruction \p A to the list of instructions to delete. 129 | void add(Instruction *A) { 130 | #ifndef NDEBUG 131 | assert(!hasInstruction(A) && "Instruction already in list!"); 132 | #endif 133 | list.push_back(A); 134 | } 135 | 136 | ~InstructionDestroyer() { 137 | for (auto *I : list) { 138 | I->eraseFromParent(); 139 | } 140 | } 141 | }; 142 | 143 | }; 144 | 145 | } 146 | 147 | #endif /* IRBuilder_h */ 148 | -------------------------------------------------------------------------------- /include/cobra/IR/Instrs.def: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef DEF_VALUE 9 | #define DEF_VALUE(NAME, PARENT) 10 | #endif 11 | #ifndef MARK_FIRST 12 | #define MARK_FIRST(NAME) 13 | #endif 14 | #ifndef MARK_LAST 15 | #define MARK_LAST(NAME) 16 | #endif 17 | 18 | #ifndef TERMINATOR 19 | #define TERMINATOR(NAME, PARENT) DEF_VALUE(NAME, PARENT) 20 | #endif 21 | 22 | #if defined(INCLUDE_ALL_INSTRS) || defined(INCLUDE_HBC_INSTRS) 23 | #define INCLUDE_HBC_BACKEND 24 | #endif 25 | 26 | MARK_FIRST(SingleOperandInst) 27 | DEF_VALUE(SingleOperandInst, Instruction) 28 | DEF_VALUE(LoadStackInst, SingleOperandInst) 29 | DEF_VALUE(MovInst, SingleOperandInst) 30 | DEF_VALUE(UnaryOperatorInst, SingleOperandInst) 31 | DEF_VALUE(LoadConstInst, SingleOperandInst) 32 | DEF_VALUE(LoadParamInst, SingleOperandInst) 33 | MARK_LAST(SingleOperandInst) 34 | 35 | DEF_VALUE(PhiInst, Instruction) 36 | DEF_VALUE(BinaryOperatorInst, Instruction) 37 | 38 | DEF_VALUE(StoreStackInst, Instruction) 39 | DEF_VALUE(AllocStackInst, Instruction) 40 | 41 | MARK_FIRST(TerminatorInst) 42 | DEF_VALUE(TerminatorInst, Instruction) 43 | TERMINATOR(BranchInst, TerminatorInst) 44 | TERMINATOR(ReturnInst, TerminatorInst) 45 | TERMINATOR(CondBranchInst, TerminatorInst) 46 | MARK_LAST(TerminatorInst) 47 | 48 | 49 | 50 | // Don't undef these if this file is being included in ValueKinds.def, since 51 | // these macros are still used after the #include. 52 | #ifndef INCLUDED_FROM_VALUEKINDS 53 | #undef DEF_VALUE 54 | #undef MARK_FIRST 55 | #undef MARK_LAST 56 | #undef TERMINATOR 57 | #endif 58 | -------------------------------------------------------------------------------- /include/cobra/IR/Scope.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Scope_h 9 | #define Scope_h 10 | 11 | #include 12 | #include 13 | #include "cobra/IR/IR.h" 14 | 15 | namespace cobra { 16 | 17 | class Scope { 18 | using ValueListType = std::map; 19 | 20 | Scope(const Scope &) = delete; 21 | Scope &operator=(const Scope &) = delete; 22 | 23 | public: 24 | using ScopeListTy = std::vector; 25 | 26 | explicit Scope(Scope *p) : parent(p) {} 27 | 28 | ~Scope(); 29 | 30 | Scope *createInnerScope() { 31 | auto *S = new Scope(this); 32 | innerScopes.emplace_back(S); 33 | return S; 34 | } 35 | 36 | Scope *getParent() const { 37 | return parent; 38 | } 39 | 40 | ScopeListTy &getMutableInnerScopes() { 41 | return innerScopes; 42 | } 43 | 44 | const ScopeListTy &getInnerScopes() const { 45 | return innerScopes; 46 | } 47 | 48 | ValueListType &getMutableVariables() { 49 | return values; 50 | } 51 | 52 | const ValueListType &getVariables() const { 53 | return values; 54 | } 55 | 56 | void insert(Identifier K, Value *V) { 57 | values.insert({K, V}); 58 | } 59 | 60 | Value *lookup(Identifier K) { 61 | auto it = values.find(K); 62 | return it == values.end() ? nullptr : it->second; 63 | } 64 | 65 | private: 66 | Scope *parent{}; 67 | ScopeListTy innerScopes; 68 | 69 | ValueListType values; 70 | 71 | }; 72 | 73 | } 74 | #endif /* Scope_h */ 75 | -------------------------------------------------------------------------------- /include/cobra/IR/ValueKinds.def: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef DEF_VALUE 9 | #define DEF_VALUE(NAME, PARENT) 10 | #endif 11 | #ifndef MARK_FIRST 12 | #define MARK_FIRST(NAME) 13 | #endif 14 | #ifndef MARK_LAST 15 | #define MARK_LAST(NAME) 16 | #endif 17 | #ifndef MARK_VALUE 18 | #define MARK_VALUE(NAME) 19 | #endif 20 | 21 | MARK_FIRST(Value) 22 | MARK_VALUE(Value) 23 | 24 | MARK_FIRST(Instruction) 25 | DEF_VALUE(Instruction, Value) 26 | #define INCLUDED_FROM_VALUEKINDS 27 | #include "cobra/IR/Instrs.def" 28 | #undef INCLUDED_FROM_VALUEKINDS 29 | MARK_LAST(Instruction) 30 | 31 | MARK_FIRST(Literal) 32 | DEF_VALUE(Literal, Value) 33 | DEF_VALUE(LiteralEmpty, Literal) 34 | DEF_VALUE(LiteralUndefined, Literal) 35 | DEF_VALUE(LiteralNull, Literal) 36 | DEF_VALUE(LiteralNumber, Literal) 37 | DEF_VALUE(LiteralString, Literal) 38 | DEF_VALUE(LiteralBool, Literal) 39 | MARK_LAST(Literal) 40 | 41 | DEF_VALUE(Label, Value) 42 | DEF_VALUE(Variable, Value) 43 | DEF_VALUE(Parameter, Value) 44 | DEF_VALUE(BasicBlock, Value) 45 | MARK_FIRST(Function) 46 | DEF_VALUE(Function, Value) 47 | MARK_LAST(Function) 48 | DEF_VALUE(Module, Value) 49 | 50 | MARK_LAST(Value) 51 | 52 | #undef DEF_VALUE 53 | #undef MARK_FIRST 54 | #undef MARK_LAST 55 | #undef MARK_VALUE 56 | -------------------------------------------------------------------------------- /include/cobra/IRGen/IRGen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef IRGen_h 9 | #define IRGen_h 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "cobra/AST/ASTVisitor.h" 16 | #include "cobra/IR/IR.h" 17 | #include "cobra/IR/IRBuilder.h" 18 | #include "cobra/IR/Scope.h" 19 | #include "cobra/AST/Tree.h" 20 | #include "cobra/Support/StringTable.h" 21 | 22 | namespace cobra { 23 | namespace Lowering { 24 | 25 | using NameTableTy = std::map; 26 | using NameTableScopeTy = std::map; 27 | 28 | inline Identifier getNameFieldFromID(ASTNode *ID) { 29 | return Identifier::getFromPointer(dynamic_cast(ID)->name); 30 | } 31 | 32 | class TreeIRGen : public ASTVisitor { 33 | TreeIRGen(const TreeIRGen &) = delete; 34 | void operator=(const TreeIRGen &) = delete; 35 | 36 | Module *Mod; 37 | IRBuilder Builder; 38 | ASTNode *Root; 39 | Function *curFunction{}; 40 | 41 | Scope *currentScope{}; 42 | std::vector ScopeStack; 43 | 44 | bool returnAdd; 45 | 46 | NameTableTy nameTable{}; 47 | 48 | public: 49 | explicit TreeIRGen(ASTNode *root, Module *M); 50 | 51 | ~TreeIRGen(); 52 | 53 | void visitChildren(); 54 | void visitProgram(Program *fd) {}; 55 | 56 | Value *visitFuncDecl(FuncDecl *fd); 57 | 58 | Value *visitParamDecl(ParamDecl *pd); 59 | 60 | Value *visitVariableDecl(VariableDecl *vd); 61 | 62 | Value *visitBlockStmt(BlockStmt *bs); 63 | 64 | Value *visitReturnStmt(ReturnStmt *rs); 65 | 66 | Value *visitIfStmt(IfStmt *is); 67 | 68 | Value *visitVariableStmt(VariableStmt *vs); 69 | 70 | Value *visitExpressionStmt(ExpressionStmt *es); 71 | 72 | Value *visitBooleanLiteralExpr(BooleanLiteralExpr *be); 73 | 74 | Value *visitNumericLiteralExpr(NumericLiteralExpr *ne); 75 | 76 | Value *visitStringLiteralExpr(StringLiteralExpr *se); 77 | 78 | Value *visitCallExpr(CallExpr *ce); 79 | 80 | Value *visitMemberExpr(MemberExpr *me); 81 | 82 | Value *visitIdentifierExpr(IdentifierExpr *ie); 83 | 84 | Value *visitUnaryExpr(UnaryExpr *ue); 85 | 86 | Value *visitPostfixUnaryExpr(PostfixUnaryExpr *pe); 87 | 88 | Value *visitBinaryExpr(BinaryExpr *be); 89 | 90 | Value *visitConditionalExpr(ConditionalExpr *ce); 91 | 92 | Value *visitSpreadElementExpr(SpreadElementExpr *se); 93 | 94 | Value *visitAssignmentExpr(AssignmentExpr *ae); 95 | 96 | void emitFunction(FuncDecl *fd); 97 | 98 | void emitFunctionPreamble(BasicBlock *entry); 99 | 100 | void emitParameters(AbstractFunctionDecl *funcNode); 101 | 102 | void emitFunctionEpilogue(Value *returnValue); 103 | 104 | void emitStatement(Stmt *stmt); 105 | 106 | Instruction *emitLoad(Value *from); 107 | 108 | Instruction *emitStore(Value *storedValue, Value *ptr, bool declInit); 109 | 110 | void emitExpressionBranch( 111 | Expr *expr, 112 | BasicBlock *onTrue, 113 | BasicBlock *onFalse, 114 | BasicBlock *onNullish); 115 | 116 | Value *ensureVariableExists(IdentifierExpr *id); 117 | 118 | 119 | 120 | }; 121 | 122 | } 123 | } 124 | 125 | #endif /* IRGen_h */ 126 | -------------------------------------------------------------------------------- /include/cobra/Inst/Inst.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Inst_h 9 | #define Inst_h 10 | 11 | #include "cobra/Support/StringRef.h" 12 | #include "cobra/Support/Common.h" 13 | 14 | namespace cobra { 15 | namespace inst { 16 | 17 | enum class OpCode : uint8_t { 18 | #define DEFINE_OPCODE(name) name, 19 | #include "cobra/BCGen/BytecodeList.def" 20 | }; 21 | 22 | // Define all instructions. 23 | #define DEFINE_OPERAND_TYPE(name, type) typedef type Operand##name; 24 | 25 | #define DEFINE_OPCODE_0(name) LLVM_PACKED(struct name##Inst { OpCode opCode; }); 26 | 27 | #define DEFINE_OPCODE_1(name, op1type) \ 28 | LLVM_PACKED(struct name##Inst { \ 29 | OpCode opCode; \ 30 | Operand##op1type op1; \ 31 | }); 32 | 33 | #define DEFINE_OPCODE_2(name, op1type, op2type) \ 34 | LLVM_PACKED(struct name##Inst { \ 35 | OpCode opCode; \ 36 | Operand##op1type op1; \ 37 | Operand##op2type op2; \ 38 | }); 39 | 40 | #define DEFINE_OPCODE_3(name, op1type, op2type, op3type) \ 41 | LLVM_PACKED(struct name##Inst { \ 42 | OpCode opCode; \ 43 | Operand##op1type op1; \ 44 | Operand##op2type op2; \ 45 | Operand##op3type op3; \ 46 | }); 47 | 48 | #define DEFINE_OPCODE_4(name, op1type, op2type, op3type, op4type) \ 49 | LLVM_PACKED(struct name##Inst { \ 50 | OpCode opCode; \ 51 | Operand##op1type op1; \ 52 | Operand##op2type op2; \ 53 | Operand##op3type op3; \ 54 | Operand##op4type op4; \ 55 | }); 56 | 57 | #define DEFINE_OPCODE_5(name, op1type, op2type, op3type, op4type, op5type) \ 58 | LLVM_PACKED(struct name##Inst { \ 59 | OpCode opCode; \ 60 | Operand##op1type op1; \ 61 | Operand##op2type op2; \ 62 | Operand##op3type op3; \ 63 | Operand##op4type op4; \ 64 | Operand##op5type op5; \ 65 | }); 66 | 67 | #define DEFINE_OPCODE_6( \ 68 | name, op1type, op2type, op3type, op4type, op5type, op6type) \ 69 | LLVM_PACKED(struct name##Inst { \ 70 | OpCode opCode; \ 71 | Operand##op1type op1; \ 72 | Operand##op2type op2; \ 73 | Operand##op3type op3; \ 74 | Operand##op4type op4; \ 75 | Operand##op5type op5; \ 76 | Operand##op6type op6; \ 77 | }); 78 | 79 | #include "cobra/BCGen/BytecodeList.def" 80 | 81 | /// A union of all instructions. 82 | LLVM_PACKED_START 83 | struct Inst { 84 | union { 85 | OpCode opCode; 86 | #define DEFINE_OPCODE(name) name##Inst i##name; 87 | #include "cobra/BCGen/BytecodeList.def" 88 | }; 89 | }; 90 | LLVM_PACKED_END 91 | 92 | } 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /include/cobra/Optimizer/CSE.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef CSE_h 9 | #define CSE_h 10 | 11 | #include "cobra/IR/IR.h" 12 | #include "cobra/Optimizer/Pass.h" 13 | 14 | namespace cobra { 15 | 16 | class CSE : public FunctionPass { 17 | public: 18 | explicit CSE() : FunctionPass("CSE") {} 19 | ~CSE() override = default; 20 | 21 | bool runOnFunction(Function *F) override; 22 | }; 23 | 24 | } // namespace cobra 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/cobra/Optimizer/DCE.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef DCE_h 9 | #define DCE_h 10 | 11 | #include "cobra/IR/IR.h" 12 | #include "cobra/Optimizer/Pass.h" 13 | 14 | namespace cobra { 15 | 16 | class DCE : public ModulePass { 17 | public: 18 | explicit DCE() : ModulePass("DCE") {} 19 | ~DCE() override = default; 20 | 21 | bool runOnModule(Module *M) override; 22 | }; 23 | 24 | } // namespace cobra 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/cobra/Optimizer/Inlining.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Inlining_h 9 | #define Inlining_h 10 | 11 | #include "cobra/IR/IR.h" 12 | #include "cobra/Optimizer/Pass.h" 13 | 14 | namespace cobra { 15 | 16 | class Inlining : public ModulePass { 17 | public: 18 | explicit Inlining() : ModulePass("Inlining") {} 19 | ~Inlining() override = default; 20 | 21 | bool runOnModule(Module *M) override; 22 | }; 23 | 24 | } // namespace cobra 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/cobra/Optimizer/Mem2Reg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Mem2Reg_h 9 | #define Mem2Reg_h 10 | 11 | #include "cobra/IR/IR.h" 12 | #include "cobra/IR/CFG.h" 13 | #include "cobra/Optimizer/Pass.h" 14 | 15 | namespace cobra { 16 | 17 | /// This optimization promotes stack allocations into virtual registers. 18 | /// The algorithm is based on: 19 | /// 20 | /// Sreedhar and Gao. A linear time algorithm for placing phi-nodes. POPL '95. 21 | class Mem2Reg : public FunctionPass { 22 | public: 23 | explicit Mem2Reg() : FunctionPass("Mem2Reg") {} 24 | ~Mem2Reg() override = default; 25 | 26 | bool runOnFunction(Function *F) override; 27 | }; 28 | 29 | } // namespace cobra 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/cobra/Optimizer/Pass.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Pass_h 9 | #define Pass_h 10 | 11 | #include "cobra/Support/StringRef.h" 12 | 13 | #include 14 | 15 | namespace cobra { 16 | 17 | class Function; 18 | class Module; 19 | class Instruction; 20 | class IRBuilder; 21 | 22 | /// This class represents a pass, which is a transformation of the IR. Passes 23 | /// are either Function passes, which transform one function, and are not 24 | /// allowed to create new functions or modify other functions, or module 25 | /// passes which operate on the entire module and are free to manipulate 26 | /// multiple functions. 27 | class Pass { 28 | public: 29 | enum class PassKind { 30 | Function, 31 | Module, 32 | }; 33 | 34 | private: 35 | /// Stores the kind of derived class. 36 | const PassKind kind; 37 | /// The textual name of the pass. 38 | StringRef name; 39 | 40 | public: 41 | /// Constructor. \p K indicates the kind of pass this is. 42 | explicit Pass(Pass::PassKind K, StringRef name) : kind(K), name(name) {} 43 | 44 | virtual ~Pass() = default; 45 | 46 | /// Returns the kind of the pass. 47 | PassKind getKind() const { 48 | return kind; 49 | } 50 | 51 | /// Returns the textual name of the pass. 52 | StringRef getName() const { 53 | return name; 54 | } 55 | }; 56 | 57 | class FunctionPass : public Pass { 58 | public: 59 | explicit FunctionPass(StringRef name) 60 | : Pass(Pass::PassKind::Function, name) {} 61 | ~FunctionPass() override = default; 62 | 63 | /// Runs the current pass on the function \p F. 64 | /// \returns true if the function was modified. 65 | virtual bool runOnFunction(Function *F) = 0; 66 | 67 | static bool classof(const Pass *S) { 68 | return S->getKind() == PassKind::Function; 69 | } 70 | }; 71 | 72 | class ModulePass : public Pass { 73 | public: 74 | explicit ModulePass(StringRef name) 75 | : Pass(Pass::PassKind::Module, name) {} 76 | ~ModulePass() override = default; 77 | 78 | /// Runs the current pass on the module \p M. 79 | /// \returns true if module was modified. 80 | virtual bool runOnModule(Module *M) = 0; 81 | 82 | static bool classof(const Pass *S) { 83 | return S->getKind() == PassKind::Module; 84 | } 85 | }; 86 | 87 | /// Pass header declaration. 88 | #define PASS(ID, NAME, DESCRIPTION) std::unique_ptr create##ID(); 89 | #include "Passes.def" 90 | 91 | } // namespace cobra 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /include/cobra/Optimizer/PassManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef PassManager_h 9 | #define PassManager_h 10 | 11 | #include "cobra/Optimizer/Pass.h" 12 | 13 | #include "cobra/AST/Context.h" 14 | #include "cobra/Support/StringRef.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | namespace cobra { 21 | 22 | /// The pass manager is responsible for running the transformation passes on the 23 | /// whole module and on the functions in the module. The pass manager determines 24 | /// the order of the passes, the order of the functions to be processed and the 25 | /// invalidation of analysis. 26 | class PassManager { 27 | std::vector> pipeline_; 28 | 29 | public: 30 | explicit PassManager() = default; 31 | 32 | ~PassManager(); 33 | 34 | /// Add a pass by appending its name. 35 | #define PASS(ID, NAME, DESCRIPTION) \ 36 | void add##ID() { \ 37 | addPass(std::unique_ptr(cobra::create##ID())); \ 38 | } 39 | #include "Passes.def" 40 | 41 | /// Add a pass by name. 42 | /// Note: Only works for passes that are part of Passes.def. 43 | bool addPassForName(StringRef name) { 44 | #define PASS(ID, NAME, DESCRIPTION) \ 45 | if (name == NAME) { \ 46 | add##ID(); \ 47 | return true; \ 48 | } 49 | #include "Passes.def" 50 | return false; 51 | } 52 | 53 | /// Lists and describes the passes in Passes.def. 54 | static StringRef getCustomPassText() { 55 | return 56 | #define PASS(ID, NAME, DESCRIPTION) NAME ": " DESCRIPTION "\n" 57 | #include "Passes.def" 58 | ; 59 | } 60 | 61 | /// Adds the pass \p Pass with the provided \p args to this pass manager. 62 | template 63 | void addPass(Args &&...args) { 64 | addPass(std::make_unique(std::forward(args)...)); 65 | } 66 | 67 | /// Runs this pass manager on the given Function \p F. 68 | /// \pre Only FunctionPasses are registered with this PassManager. 69 | void run(Function *F); 70 | 71 | /// Runs this pass manager on the given Module \p M. 72 | void run(Module *M); 73 | 74 | private: 75 | /// Adds \p P to the pipeline managed by this pass manager. 76 | void addPass(std::unique_ptr P); 77 | 78 | /// \return A pass that dumps the IR before/after \p pass runs. The options 79 | /// controlling the IR dump live in CodeGenSettings. 80 | std::unique_ptr makeDumpPass(std::unique_ptr pass); 81 | }; 82 | } // namespace cobra 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /include/cobra/Optimizer/Passes.def: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file defines macros used for macro-metaprogramming with Hermes Passes. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | /// PASS(Id, Name, Description) 15 | /// There exists a global function hermes::create##Id(). 16 | /// 17 | /// This macro must be defined by the includer. 18 | #ifndef PASS 19 | #error "Macro must be defined by includer" 20 | #endif 21 | 22 | PASS(DCE, "dce", "Eliminate dead code") 23 | PASS(CSE, "cse", "Common subexpression elimination") 24 | PASS(Mem2Reg, "mem2reg", "Construct SSA") 25 | PASS(SimplifyCFG, "simplifycfg", "Simplify CFG") 26 | PASS(Inlining, "inlining", "Inlining") 27 | PASS(SSADestruction, "ssadestruction", "SSA Destruction") 28 | 29 | #undef PASS 30 | -------------------------------------------------------------------------------- /include/cobra/Optimizer/Pipeline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Pipeline_h 9 | #define Pipeline_h 10 | 11 | #include "cobra/IR/IR.h" 12 | 13 | #include 14 | #include 15 | 16 | namespace cobra { 17 | class Module; 18 | 19 | /// Run a custom set of optimizations. 20 | bool runCustomOptimizationPasses( 21 | Module &M, 22 | const std::vector &Opts); 23 | 24 | /// Run optimization passes corresponding to -O3 25 | void runFullOptimizationPasses(Module &M); 26 | 27 | /// Run optimization passes corresponding to -Og 28 | void runDebugOptimizationPasses(Module &M); 29 | 30 | /// Run optimization passes corresponding to -O0 31 | void runNoOptimizationPasses(Module &M); 32 | } // namespace cobra 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/cobra/Optimizer/SSADestruction.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef SSADestruction_h 9 | #define SSADestruction_h 10 | 11 | #include "cobra/IR/IR.h" 12 | #include "cobra/Optimizer/Pass.h" 13 | 14 | namespace cobra { 15 | 16 | class SSADestruction : public FunctionPass { 17 | public: 18 | explicit SSADestruction() : FunctionPass("SSADestruction") {} 19 | ~SSADestruction() override = default; 20 | 21 | bool runOnFunction(Function *F) override; 22 | }; 23 | } // namespace cobra 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/cobra/Optimizer/SimplifyCFG.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef SimplifyCFG_h 9 | #define SimplifyCFG_h 10 | 11 | #include "cobra/IR/IR.h" 12 | #include "cobra/Optimizer/Pass.h" 13 | 14 | namespace cobra { 15 | 16 | class SimplifyCFG : public FunctionPass { 17 | public: 18 | explicit SimplifyCFG() : FunctionPass("SimplifyCFG") {} 19 | ~SimplifyCFG() override = default; 20 | 21 | bool runOnFunction(Function *F) override; 22 | }; 23 | } // namespace cobra 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/cobra/Support/Allocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Allocator_h 9 | #define Allocator_h 10 | 11 | #include 12 | #include 13 | 14 | namespace cobra { 15 | 16 | class Allocator { 17 | public: 18 | 19 | explicit Allocator() 20 | : root(static_cast(operator new(sizeof(Page)))) , offset(0) { 21 | root->next = nullptr; 22 | } 23 | 24 | ~Allocator() { 25 | Page* page = root; 26 | 27 | while (page) { 28 | Page* next = page->next; 29 | operator delete(page); 30 | page = next; 31 | } 32 | } 33 | 34 | inline void *Allocate( 35 | size_t size, 36 | size_t alignment = kDefaultPlatformAlignment) { 37 | if (root) { 38 | uintptr_t data = reinterpret_cast(root->data); 39 | uintptr_t result = (data + offset + alignment - 1) & ~(alignment - 1); 40 | if (result + size <= data + sizeof(root->data)) { 41 | offset = result - data + size; 42 | return reinterpret_cast(result); 43 | } 44 | } 45 | 46 | // allocate new page 47 | size_t pageSize = size > sizeof(root->data) ? size : sizeof(root->data); 48 | void *pageData = operator new(offsetof(Page, data) + pageSize); 49 | 50 | Page* page = static_cast(pageData); 51 | page->next = root; 52 | 53 | root = page; 54 | offset = size; 55 | 56 | return page->data; 57 | } 58 | 59 | template 60 | inline T *Allocate(size_t num = 1, size_t alignment = sizeof(double)) { 61 | int size = sizeof(T) * num; 62 | return static_cast(Allocate(size, alignment)); 63 | } 64 | 65 | private: 66 | 67 | static const unsigned kDefaultPlatformAlignment = sizeof(double); 68 | 69 | struct Page { 70 | Page* next; 71 | char data[8192]; 72 | }; 73 | 74 | Page* root; 75 | size_t offset; 76 | }; 77 | 78 | } 79 | 80 | #endif /* Allocator_h */ 81 | -------------------------------------------------------------------------------- /include/cobra/Support/Base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Base64_h 9 | #define Base64_h 10 | 11 | #include 12 | 13 | #endif /* Base64_h */ 14 | -------------------------------------------------------------------------------- /include/cobra/Support/Common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #pragma once 9 | 10 | #ifdef _MSC_VER 11 | #define COBRA_NORETURN __declspec(noreturn) 12 | #define COBRA_NOINLINE __declspec(noinline) 13 | #define COBRA_FORCEINLINE __forceinline 14 | #define COBRA_LIKELY(x) x 15 | #define COBRA_UNLIKELY(x) x 16 | #define COBRA_UNREACHABLE() __assume(false) 17 | #define COBRA_DEBUGBREAK() __debugbreak() 18 | #else 19 | #define COBRA_NORETURN __attribute__((__noreturn__)) 20 | #define COBRA_NOINLINE __attribute__((noinline)) 21 | #define COBRA_FORCEINLINE inline __attribute__((always_inline)) 22 | #define COBRA_LIKELY(x) __builtin_expect(x, 1) 23 | #define COBRA_UNLIKELY(x) __builtin_expect(x, 0) 24 | #define COBRA_UNREACHABLE() __builtin_unreachable() 25 | #define COBRA_DEBUGBREAK() __builtin_trap() 26 | #endif 27 | 28 | #if __cplusplus > 201402L && __has_cpp_attribute(nodiscard) 29 | #define COBRA_NODISCARD [[nodiscard]] 30 | #elif !__cplusplus 31 | // Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious 32 | // error when __has_cpp_attribute is given a scoped attribute in C mode. 33 | #define COBRA_NODISCARD 34 | #elif __has_cpp_attribute(clang::warn_unused_result) 35 | #define COBRA_NODISCARD [[clang::warn_unused_result]] 36 | #else 37 | #define COBRA_NODISCARD 38 | #endif 39 | 40 | #ifdef __GNUC__ 41 | #define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn)) 42 | #elif defined(_MSC_VER) 43 | #define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn) 44 | #else 45 | #define LLVM_ATTRIBUTE_NORETURN 46 | #endif 47 | 48 | #define FATAL_ERROR(fmt) \ 49 | do { fprintf(stderr, "FATAL ERROR in %s:%d:%s(): " fmt "\n", __FILE__, \ 50 | __LINE__, __func__); exit(-2); } while (0) 51 | 52 | #define FATAL_ERRORF(fmt, ...) \ 53 | do { fprintf(stderr, "FATAL ERROR in %s:%d:%s(): " fmt "\n", __FILE__, \ 54 | __LINE__, __func__, __VA_ARGS__); exit(-2); } while (0) 55 | 56 | #define TODO do { \ 57 | fprintf(stderr, "Exit due to TODO in %s:%d:%s()\n", __FILE__, __LINE__, __func__); \ 58 | abort(); \ 59 | } while (0) 60 | 61 | # define LLVM_PACKED(d) d __attribute__((packed)) 62 | # define LLVM_PACKED_START _Pragma("pack(push, 1)") 63 | # define LLVM_PACKED_END _Pragma("pack(pop)") 64 | 65 | #define MEMBER_OFFSET(t, f) offsetof(t, f) 66 | -------------------------------------------------------------------------------- /include/cobra/Support/FixedArray.h: -------------------------------------------------------------------------------- 1 | /* 2 | * * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef FixedArray_h 9 | #define FixedArray_h 10 | 11 | #include 12 | #include 13 | 14 | #include "cobra/Support/StdLibExtras.h" 15 | #include "cobra/Support/StrideIterator.h" 16 | 17 | namespace cobra { 18 | 19 | template 20 | class FixedArray { 21 | private: 22 | uint32_t size_; 23 | uint8_t data_[0]; 24 | 25 | T &atUnchecked(size_t index, size_t elementSize, size_t alignment) { 26 | return *reinterpret_cast( 27 | reinterpret_cast(this) + offsetOfElement(index, elementSize, alignment)); 28 | } 29 | 30 | const T &atUnchecked(size_t index, size_t elementSize, size_t alignment) const { 31 | return *reinterpret_cast( 32 | reinterpret_cast(this) + offsetOfElement(index, elementSize, alignment)); 33 | } 34 | 35 | public: 36 | explicit FixedArray(size_t length) : size_(static_cast(length)) {} 37 | 38 | size_t size() const { 39 | return size_; 40 | } 41 | 42 | /// Update the length but does not reallocate storage. 43 | void setSize(size_t length) { 44 | size_ = static_cast(length); 45 | } 46 | 47 | T &at(size_t index, size_t elementSize = sizeof(T), size_t alignment = alignof(T)) { 48 | return atUnchecked(index, elementSize, alignment); 49 | } 50 | 51 | const T &at(size_t index, size_t elementSize = sizeof(T), size_t alignment = alignof(T)) const { 52 | return atUnchecked(index, elementSize, alignment); 53 | } 54 | 55 | StrideIterator begin(size_t elementSize = sizeof(T), size_t alignment = alignof(T)) { 56 | return StrideIterator(&atUnchecked(0, elementSize, alignment), elementSize); 57 | } 58 | 59 | StrideIterator begin( 60 | size_t elementSize = sizeof(T), 61 | size_t alignment = alignof(T)) const { 62 | return StrideIterator(&atUnchecked(0, elementSize, alignment), elementSize); 63 | } 64 | 65 | StrideIterator end(size_t elementSize = sizeof(T), size_t alignment = alignof(T)) { 66 | return StrideIterator(&atUnchecked(size_, elementSize, alignment), elementSize); 67 | } 68 | 69 | StrideIterator end( 70 | size_t elementSize = sizeof(T), 71 | size_t alignment = alignof(T)) const { 72 | return StrideIterator(&atUnchecked(size_, elementSize, alignment), elementSize); 73 | } 74 | 75 | static size_t offsetOfElement( 76 | size_t index, 77 | size_t elementSize = sizeof(T), 78 | size_t alignment = alignof(T)) { 79 | return roundUp(offsetof(FixedArray, data_), alignment) + index * elementSize; 80 | } 81 | 82 | /// Clear the potentially uninitialized padding between the size_ and actual data. 83 | void clearPadding(size_t elementSize = sizeof(T), size_t alignment = alignof(T)) { 84 | size_t gapOffset = offsetof(FixedArray, data_); 85 | size_t gapSize = offsetOfElement(0, elementSize, alignment) - gapOffset; 86 | memset(reinterpret_cast(this) + gapOffset, 0, gapSize); 87 | } 88 | }; 89 | 90 | } 91 | 92 | 93 | #endif /* FixedArray_h */ 94 | -------------------------------------------------------------------------------- /include/cobra/Support/SMLoc.h: -------------------------------------------------------------------------------- 1 | //===- SMLoc.h - Source location for use with diagnostics -------*- C++ -*-===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file declares the SMLoc class. This class encapsulates a location in 11 | // source code for use in diagnostics. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #ifndef SMLoc_h 16 | #define SMLoc_h 17 | 18 | #include 19 | #include 20 | 21 | namespace cobra { 22 | 23 | /// A simple null object to allow implicit construction of Optional 24 | /// and similar types without having to spell out the specialization's name. 25 | // (constant value 1 in an attempt to workaround MSVC build issue... ) 26 | enum class NoneType { None = 1 }; 27 | const NoneType None = NoneType::None; 28 | 29 | /// Represents a location in source code. 30 | class SMLoc { 31 | const char *Ptr = nullptr; 32 | 33 | public: 34 | SMLoc() = default; 35 | 36 | bool isValid() const { return Ptr != nullptr; } 37 | 38 | bool operator==(const SMLoc &RHS) const { return RHS.Ptr == Ptr; } 39 | bool operator!=(const SMLoc &RHS) const { return RHS.Ptr != Ptr; } 40 | 41 | const char *getPointer() const { return Ptr; } 42 | 43 | static SMLoc getFromPointer(const char *Ptr) { 44 | SMLoc L; 45 | L.Ptr = Ptr; 46 | return L; 47 | } 48 | }; 49 | 50 | /// Represents a range in source code. 51 | /// 52 | /// SMRange is implemented using a half-open range, as is the convention in C++. 53 | /// In the string "abc", the range [1,3) represents the substring "bc", and the 54 | /// range [2,2) represents an empty range between the characters "b" and "c". 55 | class SMRange { 56 | public: 57 | SMLoc Start, End; 58 | 59 | SMRange() = default; 60 | SMRange(NoneType) {} 61 | SMRange(SMLoc St, SMLoc En) : Start(St), End(En) { 62 | assert(Start.isValid() == End.isValid() && 63 | "Start and End should either both be valid or both be invalid!"); 64 | } 65 | 66 | bool isValid() const { return Start.isValid(); } 67 | }; 68 | 69 | } 70 | 71 | #endif /* SMLoc_h */ 72 | -------------------------------------------------------------------------------- /include/cobra/Support/StrideIterator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef StrideIterator_h 9 | #define StrideIterator_h 10 | 11 | #include 12 | 13 | namespace cobra { 14 | 15 | template 16 | class StrideIterator { 17 | public: 18 | using iterator_category = std::random_access_iterator_tag; 19 | using value_type = T; 20 | using difference_type = ptrdiff_t; 21 | using pointer = value_type*; 22 | using reference = value_type&; 23 | 24 | StrideIterator(const StrideIterator&) = default; 25 | StrideIterator(StrideIterator&&) noexcept = default; 26 | StrideIterator& operator=(const StrideIterator&) = default; 27 | StrideIterator& operator=(StrideIterator&&) noexcept = default; 28 | 29 | StrideIterator(T* ptr, size_t stride) 30 | : ptr_(reinterpret_cast(ptr)), 31 | stride_(stride) {} 32 | 33 | bool operator==(const StrideIterator& other) const { 34 | return ptr_ == other.ptr_; 35 | } 36 | 37 | bool operator!=(const StrideIterator& other) const { 38 | return !(*this == other); 39 | } 40 | 41 | StrideIterator& operator++() { // Value after modification. 42 | ptr_ += stride_; 43 | return *this; 44 | } 45 | 46 | StrideIterator operator++(int) { 47 | StrideIterator temp = *this; 48 | ++*this; 49 | return temp; 50 | } 51 | 52 | StrideIterator& operator--() { // Value after modification. 53 | ptr_ -= stride_; 54 | return *this; 55 | } 56 | 57 | StrideIterator operator--(int) { 58 | StrideIterator temp = *this; 59 | --*this; 60 | return temp; 61 | } 62 | 63 | StrideIterator& operator+=(difference_type delta) { 64 | ptr_ += static_cast(stride_) * delta; 65 | return *this; 66 | } 67 | 68 | StrideIterator operator+(difference_type delta) const { 69 | StrideIterator temp = *this; 70 | temp += delta; 71 | return temp; 72 | } 73 | 74 | StrideIterator& operator-=(difference_type delta) { 75 | ptr_ -= static_cast(stride_) * delta; 76 | return *this; 77 | } 78 | 79 | StrideIterator operator-(difference_type delta) const { 80 | StrideIterator temp = *this; 81 | temp -= delta; 82 | return temp; 83 | } 84 | 85 | difference_type operator-(const StrideIterator& rhs) { 86 | return (ptr_ - rhs.ptr_) / stride_; 87 | } 88 | 89 | T& operator*() const { 90 | return *reinterpret_cast(ptr_); 91 | } 92 | 93 | T* operator->() const { 94 | return &**this; 95 | } 96 | 97 | T& operator[](difference_type n) { 98 | return *(*this + n); 99 | } 100 | 101 | private: 102 | uintptr_t ptr_; 103 | // Not const for operator=. 104 | size_t stride_; 105 | 106 | template 107 | friend bool operator<(const StrideIterator& lhs, const StrideIterator& rhs); 108 | }; 109 | 110 | template 111 | StrideIterator operator+( 112 | typename StrideIterator::difference_type dist, 113 | const StrideIterator& it) { 114 | return it + dist; 115 | } 116 | 117 | template 118 | bool operator<(const StrideIterator& lhs, const StrideIterator& rhs) { 119 | return lhs.ptr_ < rhs.ptr_; 120 | } 121 | 122 | template 123 | bool operator>(const StrideIterator& lhs, const StrideIterator& rhs) { 124 | return rhs < lhs; 125 | } 126 | 127 | template 128 | bool operator<=(const StrideIterator& lhs, const StrideIterator& rhs) { 129 | return !(rhs < lhs); 130 | } 131 | 132 | template 133 | bool operator>=(const StrideIterator& lhs, const StrideIterator& rhs) { 134 | return !(lhs < rhs); 135 | } 136 | 137 | } 138 | 139 | #endif /* StrideIterator_h */ 140 | -------------------------------------------------------------------------------- /include/cobra/Support/StringRef.h: -------------------------------------------------------------------------------- 1 | //===- StringRef.h - Constant String Reference Wrapper ----------*- C++ -*-===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | 10 | #ifndef String_h 11 | #define String_h 12 | 13 | #include 14 | 15 | namespace cobra { 16 | 17 | class StringRef { 18 | public: 19 | static const size_t npos = ~size_t(0); 20 | 21 | using iterator = const char *; 22 | using const_iterator = const char *; 23 | using size_type = size_t; 24 | 25 | private: 26 | const char *Data = nullptr; 27 | 28 | /// The length of the string. 29 | size_t Length = 0; 30 | 31 | static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) { 32 | if (Length == 0) { return 0; } 33 | return ::memcmp(Lhs,Rhs,Length); 34 | } 35 | 36 | public: 37 | 38 | StringRef() = default; 39 | 40 | StringRef(std::nullptr_t) = delete; 41 | 42 | StringRef(const char *Str) 43 | : Data(Str), Length(Str ? ::strlen(Str) : 0) {} 44 | 45 | constexpr StringRef(const char *data, size_t length) 46 | : Data(data), Length(length) {} 47 | 48 | StringRef(const std::string &Str) 49 | : Data(Str.data()), Length(Str.length()) {} 50 | 51 | std::string str() const { 52 | if (!Data) return std::string(); 53 | return std::string(Data, Length); 54 | } 55 | 56 | static StringRef withNullAsEmpty(const char *data) { 57 | return StringRef(data ? data : ""); 58 | } 59 | 60 | iterator begin() const { return Data; } 61 | 62 | iterator end() const { return Data + Length; } 63 | 64 | const char *data() const { return Data; } 65 | 66 | bool empty() const { return Length == 0; } 67 | 68 | size_t size() const { return Length; } 69 | 70 | char front() const { 71 | assert(!empty()); 72 | return Data[0]; 73 | } 74 | 75 | char back() const { 76 | assert(!empty()); 77 | return Data[Length-1]; 78 | } 79 | 80 | bool equals(StringRef RHS) const { 81 | return (Length == RHS.Length && 82 | compareMemory(Data, RHS.Data, RHS.Length) == 0); 83 | } 84 | 85 | int compare(StringRef RHS) const { 86 | // Check the prefix for a mismatch. 87 | if (int Res = compareMemory(Data, RHS.Data, std::min(Length, RHS.Length))) 88 | return Res < 0 ? -1 : 1; 89 | 90 | // Otherwise the prefixes match, so we only need to check the lengths. 91 | if (Length == RHS.Length) 92 | return 0; 93 | return Length < RHS.Length ? -1 : 1; 94 | } 95 | 96 | size_t count(char C) const { 97 | size_t Count = 0; 98 | for (size_t i = 0, e = Length; i != e; ++i) 99 | if (Data[i] == C) 100 | ++Count; 101 | return Count; 102 | } 103 | 104 | /// Return the number of non-overlapped occurrences of \p Str in 105 | /// the string. 106 | size_t count(StringRef Str) const; 107 | 108 | StringRef substr(size_t Start, size_t N = npos) const { 109 | Start = std::min(Start, Length); 110 | return StringRef(Data + Start, std::min(N, Length - Start)); 111 | } 112 | 113 | }; 114 | 115 | inline bool operator==(StringRef LHS, StringRef RHS) { 116 | return LHS.equals(RHS); 117 | } 118 | 119 | inline bool operator!=(StringRef LHS, StringRef RHS) { return !(LHS == RHS); } 120 | 121 | inline bool operator<(StringRef LHS, StringRef RHS) { 122 | return LHS.compare(RHS) == -1; 123 | } 124 | 125 | inline bool operator<=(StringRef LHS, StringRef RHS) { 126 | return LHS.compare(RHS) != 1; 127 | } 128 | 129 | inline bool operator>(StringRef LHS, StringRef RHS) { 130 | return LHS.compare(RHS) == 1; 131 | } 132 | 133 | inline bool operator>=(StringRef LHS, StringRef RHS) { 134 | return LHS.compare(RHS) != -1; 135 | } 136 | 137 | inline std::string &operator+=(std::string &buffer, StringRef string) { 138 | return buffer.append(string.data(), string.size()); 139 | } 140 | 141 | } 142 | 143 | #endif /* String_h */ 144 | -------------------------------------------------------------------------------- /include/cobra/Support/StringTable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef StringTable_h 9 | #define StringTable_h 10 | 11 | #include "cobra/Support/StringRef.h" 12 | #include "cobra/Support/Allocator.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace cobra { 19 | 20 | /// Allocate a StringRef with a '\0' following after the end. 21 | template 22 | StringRef zeroTerminate(Allocator &allocator, StringRef str) { 23 | // Allocate a copy of the name, adding a trailing \0 for convenience. 24 | auto *s = allocator.template Allocate(str.size() + 1); 25 | auto end = std::copy(str.begin(), str.end(), s); 26 | *end = 0; // Zero terminate string. 27 | 28 | // NOTE: returning the original size. 29 | return StringRef(s, str.size()); 30 | } 31 | 32 | class UniqueString { 33 | const StringRef str_; 34 | 35 | UniqueString(const UniqueString &) = delete; 36 | UniqueString &operator=(const UniqueString &) = delete; 37 | 38 | public: 39 | explicit UniqueString(StringRef str) : str_(str){}; 40 | 41 | const StringRef &str() const { 42 | return str_; 43 | } 44 | const char *c_str() const { 45 | return str_.begin(); 46 | } 47 | 48 | explicit operator StringRef() const { 49 | return str_; 50 | } 51 | }; 52 | 53 | /// This is an instance of a uniqued identifier created by StringTable. It is 54 | /// just a wrapper around a StringRef pointer. Identifier is passed by value 55 | /// and must be kept small. 56 | class Identifier { 57 | public: 58 | using PtrType = UniqueString *; 59 | 60 | explicit Identifier() = default; 61 | 62 | private: 63 | PtrType ptr_{nullptr}; 64 | 65 | explicit Identifier(PtrType ptr) : ptr_(ptr) {} 66 | 67 | public: 68 | bool isValid() const { 69 | return ptr_ != nullptr; 70 | } 71 | 72 | /// \returns the pointer value that the context uses to index this string. We 73 | /// Also use this value to hash the identifier. 74 | PtrType getUnderlyingPointer() const { 75 | return ptr_; 76 | } 77 | 78 | static Identifier getFromPointer(UniqueString *ptr) { 79 | return Identifier(ptr); 80 | } 81 | 82 | bool operator<(Identifier RHS) const { 83 | return ptr_ < RHS.ptr_; 84 | } 85 | 86 | bool operator==(Identifier RHS) const { 87 | return ptr_ == RHS.ptr_; 88 | } 89 | bool operator!=(Identifier RHS) const { 90 | return !(*this == RHS); 91 | } 92 | 93 | const StringRef &str() const { 94 | return ptr_->str(); 95 | } 96 | const char *c_str() const { 97 | return ptr_->c_str(); 98 | } 99 | }; 100 | 101 | class StringTable { 102 | Allocator &allocator_; 103 | 104 | std::map strMap_{}; 105 | 106 | StringTable(const StringTable &) = delete; 107 | StringTable &operator=(const StringTable &_) = delete; 108 | 109 | public: 110 | explicit StringTable(Allocator &allocator) : allocator_(allocator){}; 111 | 112 | /// Return a unique zero-terminated copy of the supplied string \p name. 113 | UniqueString *getString(StringRef name) { 114 | // Already in the map? 115 | auto it = strMap_.find(name); 116 | if (it != strMap_.end()) 117 | return it->second; 118 | 119 | // Allocate a zero-terminated copy of the string 120 | auto *str = new (allocator_.Allocate()) 121 | UniqueString(zeroTerminate(allocator_, name)); 122 | strMap_.insert({str->str(), str}); 123 | return str; 124 | } 125 | 126 | /// A wrapper arond getString() returning an Identifier. 127 | Identifier getIdentifier(StringRef name) { 128 | return Identifier::getFromPointer(getString(name)); 129 | } 130 | }; 131 | 132 | } 133 | 134 | 135 | #endif /* StringTable_h */ 136 | -------------------------------------------------------------------------------- /include/cobra/Support/iterator_range.h: -------------------------------------------------------------------------------- 1 | //===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file 10 | /// This provides a very simple, boring adaptor for a begin and end iterator 11 | /// into a range type. This should be used to build range views that work well 12 | /// with range based for loops and range based constructors. 13 | /// 14 | /// Note that code here follows more standards-based coding conventions as it 15 | /// is mirroring proposed interfaces for standardization. 16 | /// 17 | //===----------------------------------------------------------------------===// 18 | 19 | #ifndef LLVM_ADT_ITERATOR_RANGE_H 20 | #define LLVM_ADT_ITERATOR_RANGE_H 21 | 22 | #include 23 | #include 24 | 25 | namespace llvh { 26 | 27 | /// A range adaptor for a pair of iterators. 28 | /// 29 | /// This just wraps two iterators into a range-compatible interface. Nothing 30 | /// fancy at all. 31 | template 32 | class iterator_range { 33 | IteratorT begin_iterator, end_iterator; 34 | 35 | public: 36 | //TODO: Add SFINAE to test that the Container's iterators match the range's 37 | // iterators. 38 | template 39 | iterator_range(Container &&c) 40 | //TODO: Consider ADL/non-member begin/end calls. 41 | : begin_iterator(c.begin()), end_iterator(c.end()) {} 42 | iterator_range(IteratorT begin_iterator, IteratorT end_iterator) 43 | : begin_iterator(std::move(begin_iterator)), 44 | end_iterator(std::move(end_iterator)) {} 45 | 46 | IteratorT begin() const { return begin_iterator; } 47 | IteratorT end() const { return end_iterator; } 48 | }; 49 | 50 | /// Convenience function for iterating over sub-ranges. 51 | /// 52 | /// This provides a bit of syntactic sugar to make using sub-ranges 53 | /// in for loops a bit easier. Analogous to std::make_pair(). 54 | template iterator_range make_range(T x, T y) { 55 | return iterator_range(std::move(x), std::move(y)); 56 | } 57 | 58 | template iterator_range make_range(std::pair p) { 59 | return iterator_range(std::move(p.first), std::move(p.second)); 60 | } 61 | 62 | template 63 | iterator_range()))> drop_begin(T &&t, 64 | int n) { 65 | return make_range(std::next(adl_begin(t), n), adl_end(t)); 66 | } 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /include/cobra/Utils/IRPrinter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef IRPrinter_h 9 | #define IRPrinter_h 10 | 11 | #include 12 | #include 13 | 14 | #include "cobra/Support/StringRef.h" 15 | 16 | namespace cobra { 17 | class Value; 18 | class Argument; 19 | class Instruction; 20 | class BasicBlock; 21 | class Function; 22 | class Module; 23 | 24 | class CondBranchInst; 25 | class AllocaInst; 26 | class ReturnInst; 27 | class Parameter; 28 | class BranchInst; 29 | 30 | /// Display a nice dotty graph that depicts the function. 31 | void viewGraph(Function *F); 32 | 33 | /// A utility class for naming instructions. This should only be used for 34 | /// pretty-printing instructions. 35 | struct InstructionNamer { 36 | InstructionNamer() = default; 37 | std::map InstrMap; 38 | unsigned Counter{0}; 39 | void clear(); 40 | unsigned getNumber(Value *); 41 | }; 42 | 43 | struct IRPrinter { 44 | /// Indentation level. 45 | unsigned Indent; 46 | 47 | std::ostream &os; 48 | 49 | bool needEscape; 50 | 51 | InstructionNamer InstNamer; 52 | InstructionNamer BBNamer; 53 | InstructionNamer ScopeNamer; 54 | 55 | explicit IRPrinter(Context &ctx, std::ostream &ost, bool escape = false) 56 | : Indent(0), 57 | os(ost), 58 | needEscape(escape) {} 59 | 60 | virtual ~IRPrinter() = default; 61 | 62 | virtual void printFunctionHeader(Function *F); 63 | virtual void printFunctionVariables(Function *F); 64 | virtual void printValueLabel(Instruction *I, Value *V, unsigned opIndex); 65 | virtual void printTypeLabel(Type T); 66 | virtual void printInstruction(Instruction *I); 67 | 68 | /// Prints \p F's name in the following format: 69 | /// 70 | /// name#a#b#c(params?)#d 71 | /// 72 | /// which means name is declared in scope "c"( which is an inner scope of "b", 73 | /// itself an inner scope of "a"), and its "function" scope is "d". "params" 74 | /// are omitted if \p printFunctionParams == PrintFunctionParams::No. 75 | enum class PrintFunctionParams { No, Yes }; 76 | void printFunctionName(Function *F, PrintFunctionParams printFunctionParams); 77 | void printVariableName(Variable *V); 78 | 79 | std::string getQuoteSign() { 80 | return needEscape ? R"(\")" : R"(")"; 81 | } 82 | 83 | /// Quote the string if it has spaces. 84 | std::string quoteStr(StringRef name); 85 | 86 | /// Escapes the string if it has non-printable characters. 87 | std::string escapeStr(StringRef name); 88 | 89 | /// Declare the functions we are going to reimplement. 90 | void visitInstruction(Instruction &I); 91 | void visitBasicBlock(BasicBlock &BB); 92 | void visitFunction(Function &F); 93 | void visitModule(Module &M); 94 | }; 95 | 96 | } // namespace cobra 97 | 98 | #endif /* IRPrinter_h */ 99 | -------------------------------------------------------------------------------- /include/cobra/VM/Array.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Array_h 9 | #define Array_h 10 | 11 | #include "cobra/VM/Object.h" 12 | #include "cobra/Support/Common.h" 13 | 14 | namespace cobra { 15 | namespace vm { 16 | 17 | class Array : Object { 18 | public: 19 | static Array *create(Class arrayClass, uint32_t length); 20 | 21 | static size_t computeSize(size_t elementSize, uint32_t length) { 22 | assert(elementSize != 0); 23 | size_t size = sizeof(Array) + elementSize * length; 24 | size_t size_limit = (std::numeric_limits::max() - sizeof(Array)) / elementSize; 25 | if (COBRA_UNLIKELY(size_limit < static_cast(length))) { 26 | return 0; 27 | } 28 | return size; 29 | } 30 | 31 | uint32_t getLength() const { 32 | // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints 33 | // imposed on other reads or writes 34 | return length_.load(std::memory_order_relaxed); 35 | } 36 | 37 | uint32_t *getData() { 38 | return data_; 39 | } 40 | 41 | const uint32_t *getData() const { 42 | return data_; 43 | } 44 | 45 | template 46 | T getPrimitive(size_t offset) const; 47 | 48 | template 49 | void setPrimitive(size_t offset, T value); 50 | 51 | template 52 | Object *getObject(int offset) const; 53 | 54 | template 55 | void setObject(size_t offset, Object *value); 56 | 57 | template 58 | static constexpr size_t getElementSize(); 59 | 60 | size_t objectSize(uint32_t componentSize) const { 61 | return computeSize(componentSize, length_); 62 | } 63 | 64 | static constexpr uint32_t getLengthOffset() { 65 | return MEMBER_OFFSET(Array, length_); 66 | } 67 | 68 | static constexpr uint32_t getDataOffset() { 69 | return MEMBER_OFFSET(Array, data_); 70 | } 71 | 72 | template 73 | void set(uint32_t idx, T value); 74 | 75 | template 76 | T get(uint32_t idx) const; 77 | 78 | 79 | private: 80 | void setLength(uint32_t length) { 81 | // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints 82 | // imposed on other reads or writes 83 | length_.store(length, std::memory_order_relaxed); 84 | } 85 | 86 | std::atomic length_; 87 | uint32_t data_[0]; 88 | }; 89 | 90 | } 91 | } 92 | 93 | #endif /* Array_h */ 94 | -------------------------------------------------------------------------------- /include/cobra/VM/CardTable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef CardTable_h 9 | #define CardTable_h 10 | 11 | #include 12 | 13 | namespace cobra { 14 | namespace vm { 15 | 16 | // Art 17 | 18 | // Maintain a card table from the the write barrier. All writes of 19 | // non-null values to heap addresses should go through an entry in 20 | // WriteBarrier, and from there to here. 21 | class CardTable { 22 | public: 23 | static constexpr size_t kLogCardSize = 9; 24 | static constexpr size_t kCardSize = 1 << kLogCardSize; 25 | static constexpr uint8_t kCardClean = 0x0; 26 | static constexpr uint8_t kCardDirty = 0x70; 27 | 28 | CardTable() = default; 29 | /// CardTable is not copyable or movable: It must be constructed in-place. 30 | CardTable(const CardTable &) = delete; 31 | CardTable(CardTable &&) = delete; 32 | CardTable &operator=(const CardTable &) = delete; 33 | CardTable &operator=(CardTable &&) = delete; 34 | 35 | inline const uint8_t *base() const; 36 | 37 | uint8_t getCard(const void *addr) const { 38 | return *addressToCard(addr); 39 | } 40 | 41 | /// Returns the address corresponding to the given card address 42 | inline void *cardToAddress(const uint8_t *cardAddr) const; 43 | 44 | /// Returns the card address corresponding to the given address 45 | inline uint8_t *addressToCard(const void *addr) const; 46 | 47 | void clear(); 48 | 49 | inline void markCard(const void *addr) { 50 | *addressToCard(addr) = kCardDirty; 51 | } 52 | 53 | bool isClean(const void *addr) { 54 | return getCard(addr) == kCardClean; 55 | } 56 | 57 | bool isDirty(const void *addr) { 58 | return getCard(addr) == kCardDirty; 59 | } 60 | 61 | 62 | 63 | }; 64 | 65 | } // namespace vm 66 | } // namespace cobra 67 | 68 | #endif // CardTable_h 69 | -------------------------------------------------------------------------------- /include/cobra/VM/ClassDataAccessor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef ClassDataAccessor_h 9 | #define ClassDataAccessor_h 10 | 11 | #include 12 | 13 | #include "cobra/VM/CexFile.h" 14 | 15 | namespace cobra { 16 | 17 | /// Ref ArkCompiler ClassDataAccessor 18 | /// And Art ClassDataAccessor 19 | class ClassDataAccessor { 20 | public: 21 | ClassDataAccessor(const CexFile &file, uint32_t classID); 22 | 23 | ~ClassDataAccessor() = default; 24 | 25 | uint32_t getStaticFieldCount() const { 26 | return staticFieldCount_; 27 | } 28 | 29 | uint32_t getInstanceFieldCount() const { 30 | return instanceFieldCount_; 31 | } 32 | 33 | uint32_t getFieldCount() const { 34 | return staticFieldCount_ + instanceFieldCount_; 35 | } 36 | 37 | uint32_t getDirectMethodCount() const { 38 | return directMethodCount_; 39 | } 40 | 41 | uint32_t getVirtualMethodCount() const { 42 | return directMethodCount_; 43 | } 44 | 45 | uint32_t getMethodCount() const { 46 | return directMethodCount_ + virtualMethodCount_; 47 | } 48 | 49 | const CexFile &getFile() const { 50 | return file_; 51 | } 52 | 53 | const char *getDescriptor() const; 54 | 55 | private: 56 | const CexFile &file_; 57 | uint32_t classID_; 58 | uint32_t access_flags_; 59 | uint32_t staticFieldCount_{0}; 60 | uint32_t instanceFieldCount_{0}; 61 | uint32_t directMethodCount_{0}; 62 | uint32_t virtualMethodCount_{0}; 63 | 64 | }; 65 | 66 | } 67 | 68 | #endif /* ClassDataAccessor_h */ 69 | -------------------------------------------------------------------------------- /include/cobra/VM/ClassLinker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef ClassLinker_h 9 | #define ClassLinker_h 10 | 11 | #include "cobra/VM/Class.h" 12 | #include "cobra/VM/CexFile.h" 13 | #include "cobra/VM/ClassDataAccessor.h" 14 | 15 | namespace cobra { 16 | namespace vm { 17 | 18 | class ClassLinker { 19 | 20 | public: 21 | ClassLinker() = default; 22 | 23 | ~ClassLinker(); 24 | 25 | Class *getClass(const uint8_t *descriptor); 26 | 27 | Class *loadClass(const CexFile *file, uint32_t classID); 28 | 29 | bool loadFields(Class *klass); 30 | 31 | bool loadMethods(Class *klass); 32 | 33 | private: 34 | 35 | }; 36 | 37 | } 38 | } 39 | 40 | #endif /* ClassLinker_h */ 41 | -------------------------------------------------------------------------------- /include/cobra/VM/CobraCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef CobraCache_h 9 | #define CobraCache_h 10 | 11 | #include 12 | 13 | namespace cobra { 14 | 15 | class CobraCache { 16 | 17 | }; 18 | 19 | } 20 | 21 | #endif /* CobraCache_h */ 22 | -------------------------------------------------------------------------------- /include/cobra/VM/CobraVM.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef CobraVM_h 9 | #define CobraVM_h 10 | 11 | #include "cobra/VM/Runtime.h" 12 | 13 | namespace cobra { 14 | namespace vm { 15 | 16 | class CobraVM { 17 | 18 | static CobraVM *create(Runtime *runtime, const RuntimeOptions &options); 19 | 20 | }; 21 | 22 | } 23 | } 24 | 25 | #endif /* CobraVM_h */ 26 | -------------------------------------------------------------------------------- /include/cobra/VM/CodeBlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef CodeBlock_h 9 | #define CodeBlock_h 10 | 11 | #include 12 | #include 13 | 14 | namespace cobra { 15 | namespace vm { 16 | 17 | class CodeBlock { 18 | public: 19 | CodeBlock( 20 | const uint8_t *bytecode, 21 | const uint32_t bytecodeSize, 22 | uint32_t functionID) 23 | : bytecode_(bytecode), 24 | bytecodeSize_(bytecodeSize), 25 | functionID_(functionID) { 26 | 27 | } 28 | 29 | /// Pointer to the bytecode opcodes. 30 | const uint8_t *bytecode_; 31 | 32 | const uint32_t bytecodeSize_; 33 | 34 | /// ID of this function in the module's function list. 35 | uint32_t functionID_; 36 | 37 | 38 | 39 | }; 40 | 41 | } 42 | } 43 | 44 | #endif /* CodeBlock_h */ 45 | -------------------------------------------------------------------------------- /include/cobra/VM/CodeDataAccessor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef CodeDataAccessor_h 9 | #define CodeDataAccessor_h 10 | 11 | #include 12 | 13 | #include "cobra/VM/CexFile.h" 14 | 15 | namespace cobra { 16 | 17 | /// Ref ArkCompiler CodeDataAccessor 18 | /// And Art CodeItemDataAccessor 19 | class CodeDataAccessor { 20 | public: 21 | 22 | CodeDataAccessor(const CexFile &file); 23 | 24 | ~CodeDataAccessor() = default; 25 | 26 | inline static const uint8_t *getInstructions(const CexFile &file); 27 | 28 | const uint8_t *getInstructions() const { 29 | return instructionsPtr_; 30 | } 31 | 32 | private: 33 | const CexFile &file_; 34 | 35 | /// Pointer to the instructions, null if there is no code item. 36 | const uint8_t *instructionsPtr_; 37 | 38 | /// the number of try_items for this instance. If non-zero, 39 | /// then these appear as the tries array just after the 40 | /// insns in this instance. 41 | uint32_t tries_size_; 42 | 43 | }; 44 | 45 | const uint8_t *CodeDataAccessor::getInstructions(const CexFile &file) { 46 | // TODO 47 | } 48 | 49 | } 50 | 51 | #endif /* CodeDataAccessor_h */ 52 | -------------------------------------------------------------------------------- /include/cobra/VM/Field.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Field_h 9 | #define Field_h 10 | 11 | #include "cobra/VM/Object.h" 12 | 13 | namespace cobra { 14 | namespace vm { 15 | 16 | class Class; 17 | 18 | class Field : public Object { 19 | 20 | const char *name; 21 | 22 | /// Offset of field within an instance or in the Class' static fields 23 | uint32_t offset_ = 0; 24 | 25 | uint32_t accessFlags_; 26 | 27 | public: 28 | ~Field() = default; 29 | 30 | Field() = delete; 31 | Field(const Field &) = delete; 32 | Field(Field &&) = delete; 33 | Field &operator=(const Field &) = delete; 34 | Field &operator=(Field &&) = delete; 35 | 36 | bool isPublic() const { 37 | return (accessFlags_ & kAccPublic) != 0; 38 | } 39 | 40 | bool isPrivate() const { 41 | return (accessFlags_ & kAccPrivate) != 0; 42 | } 43 | 44 | bool isProtected() const { 45 | return (accessFlags_ & kAccProtected) != 0; 46 | } 47 | 48 | bool isStatic() const { 49 | return (accessFlags_ & kAccStatic) != 0; 50 | } 51 | 52 | bool isFinal() const { 53 | return (accessFlags_ & kAccFinal) != 0; 54 | } 55 | 56 | uint32_t getAccessFlags() const { 57 | return accessFlags_; 58 | } 59 | 60 | void setClass(ObjPtr cls); 61 | 62 | uint32_t getOffset() const { 63 | return offset_; 64 | } 65 | 66 | void setOffset(uint32_t offset) { 67 | offset_ = offset; 68 | } 69 | 70 | static constexpr uint32_t getOffsetOffset() { 71 | return MEMBER_OFFSET(Field, offset_); 72 | } 73 | 74 | static constexpr uint32_t getAccessFlagsOffset() { 75 | return MEMBER_OFFSET(Field, accessFlags_); 76 | } 77 | 78 | static constexpr uint32_t getClassOffset() { 79 | return MEMBER_OFFSET(Field, accessFlags_); 80 | } 81 | }; 82 | 83 | } 84 | } 85 | 86 | #endif /* Method_h */ 87 | -------------------------------------------------------------------------------- /include/cobra/VM/FreeList.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef FreeList_h 9 | #define FreeList_h 10 | 11 | namespace cobra { 12 | namespace vm { 13 | 14 | class FreeList { 15 | 16 | 17 | }; 18 | 19 | } 20 | } 21 | 22 | #endif /* FreeList_h */ 23 | -------------------------------------------------------------------------------- /include/cobra/VM/GC.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef GC_h 9 | #define GC_h 10 | 11 | #include 12 | 13 | #include "cobra/VM/HeapRegion.h" 14 | #include "cobra/VM/CardTable.h" 15 | #include "cobra/VM/GCRoot.h" 16 | 17 | namespace cobra { 18 | namespace vm { 19 | 20 | // The CellState of a cell is a kind of hint about what the state of the cell is. 21 | enum class CellState : uint8_t { 22 | // The object is either currently being scanned, or it has finished being scanned, or this 23 | // is a full collection and it's actually a white object (you'd know because its mark bit 24 | // would be clear). 25 | Black = 0, 26 | 27 | // The object is in eden. During GC, this means that the object has not been marked yet. 28 | White = 1, 29 | 30 | // This sorta means that the object is grey - i.e. it will be scanned. Or it could be white 31 | // during a full collection if its mark bit is clear. That would happen if it had been black, 32 | // got barriered, and we did a full collection. 33 | Grey = 2 34 | }; 35 | 36 | class GC { 37 | 38 | enum class Phase : uint8_t { 39 | Idle, 40 | Mark, 41 | CompleteMarking, 42 | Sweep, 43 | }; 44 | 45 | public: 46 | GC() = default; 47 | 48 | void writeBarrier(const Object *obj, const Object *value); 49 | 50 | private: 51 | 52 | 53 | }; 54 | 55 | } 56 | } 57 | 58 | #endif /* GC_h */ 59 | -------------------------------------------------------------------------------- /include/cobra/VM/GCCell.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef GCCell_h 9 | #define GCCell_h 10 | 11 | #include "cobra/VM/CBValue.h" 12 | 13 | namespace cobra { 14 | namespace vm { 15 | 16 | class GCCell { 17 | 18 | public: 19 | GCCell() = default; 20 | 21 | // GCCell-s are not copyable (in the C++ sense). 22 | GCCell(const GCCell &) = delete; 23 | void operator=(const GCCell &) = delete; 24 | 25 | CBValueKind getKind() const { 26 | return CBValueKind::NullKind; 27 | } 28 | 29 | }; 30 | 31 | } 32 | } 33 | 34 | #endif /* GCCell_h */ 35 | -------------------------------------------------------------------------------- /include/cobra/VM/GCRoot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef GCRoot_h 9 | #define GCRoot_h 10 | 11 | #include 12 | 13 | #include "cobra/VM/Object.h" 14 | 15 | namespace cobra { 16 | namespace vm { 17 | 18 | enum RootType { 19 | Unknown = 0, 20 | Class, 21 | Frame, 22 | Local, 23 | StringTable, 24 | }; 25 | 26 | class RootVisitor { 27 | public: 28 | virtual ~RootVisitor() { } 29 | 30 | void VisitRoot(Object **root, RootType type) { 31 | 32 | } 33 | 34 | virtual void VisitRoots(Object ***roots, size_t count, RootType type) { 35 | 36 | } 37 | 38 | }; 39 | 40 | class GCRoot { 41 | public: 42 | 43 | GCRoot() : GCRoot(nullptr) {} 44 | GCRoot(std::nullptr_t) : root_() {} 45 | GCRoot(Object *object) : root_(object) {} 46 | 47 | Object *getRoot() const { 48 | return root_; 49 | } 50 | 51 | void VisitRoot(RootVisitor *visitor, RootType type) const { 52 | 53 | } 54 | 55 | private: 56 | Object *root_; 57 | 58 | }; 59 | 60 | 61 | } 62 | } 63 | 64 | #endif /* GCRoot_h */ 65 | -------------------------------------------------------------------------------- /include/cobra/VM/Handle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef VM_h 9 | #define VM_h 10 | 11 | #include 12 | 13 | #include "cobra/VM/CBValue.h" 14 | #include "cobra/VM/GCPointer.h" 15 | #include "cobra/VM/Object.h" 16 | 17 | namespace cobra { 18 | namespace vm { 19 | 20 | using Address = uintptr_t; 21 | 22 | // https://thlorenz.com/v8-dox/build/v8-3.14.5/html/d3/dd5/classv8_1_1_handle.html 23 | 24 | /// A Handle provides a reference to an object that survives relocation by 25 | /// the garbage collector. 26 | /// This is a very lightweight class: copies are very cheap (just copying a 27 | /// register); construction is also relatively cheap (in the common case a 28 | /// comparison and increment). 29 | class HandleBase { 30 | 31 | Address location_; 32 | 33 | public: 34 | explicit HandleBase(Address location) : location_(location) {} 35 | 36 | template 37 | explicit HandleBase(T value); 38 | 39 | ~HandleBase() = default; 40 | 41 | bool isNull() const { 42 | return location_ == reinterpret_cast(location_); 43 | } 44 | 45 | Address address() const { 46 | return location_; 47 | } 48 | }; 49 | 50 | template 51 | class Handle final : public HandleBase { 52 | 53 | public: 54 | explicit Handle(Address *location) : HandleBase(location) {} 55 | 56 | Handle(const Handle& handle) = default; 57 | Handle(Handle &&) = default; 58 | 59 | T *get() const { 60 | 61 | } 62 | 63 | T operator*() const { 64 | return get(); 65 | } 66 | 67 | T *operator->() const { 68 | 69 | } 70 | 71 | }; 72 | 73 | template 74 | class MutableHandle : public Handle { 75 | public: 76 | 77 | }; 78 | 79 | class HandleScope { 80 | private: 81 | uint32_t size_ = 0; 82 | 83 | HandleScope *const prev_; 84 | 85 | const int32_t capacity_; 86 | 87 | static constexpr size_t capacityOffset(PointerSize pointer_size) { 88 | return static_cast(pointer_size); 89 | } 90 | 91 | static constexpr size_t referencesOffset(PointerSize pointer_size) { 92 | return capacityOffset(pointer_size) + sizeof(capacity_) + sizeof(size_); 93 | } 94 | 95 | ObjectReference *getReferences() const { 96 | uintptr_t address = reinterpret_cast(this) + referencesOffset(kRuntimePointerSize); 97 | return reinterpret_cast*>(address); 98 | } 99 | 100 | public: 101 | explicit HandleScope(HandleScope* prev, uint32_t capacity) : prev_(prev), capacity_(capacity) {} 102 | 103 | ~HandleScope() {} 104 | 105 | ObjPtr getReference(size_t i) const; 106 | 107 | template 108 | Handle getHandle(size_t i); 109 | 110 | template 111 | MutableHandle getMutableHandle(size_t i); 112 | 113 | void setReference(size_t i, ObjPtr object); 114 | 115 | template 116 | Handle makeHandle(T *object); 117 | 118 | template 119 | MutableHandle makeHandle(ObjPtr object); 120 | 121 | template 122 | MutableHandle makeMutableHandle(T *object); 123 | 124 | template 125 | MutableHandle makeMutableHandle(ObjPtr object); 126 | 127 | inline uint32_t size() const { 128 | return size_; 129 | } 130 | 131 | uint32_t capacity() const { 132 | return static_cast(capacity_); 133 | } 134 | 135 | }; 136 | 137 | } 138 | } 139 | 140 | #endif /* VM_h */ 141 | -------------------------------------------------------------------------------- /include/cobra/VM/HeapRegionSpace.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef HeapRegionSpace_h 9 | #define HeapRegionSpace_h 10 | 11 | #include 12 | #include 13 | #include "cobra/VM/HeapRegion.h" 14 | 15 | namespace cobra { 16 | namespace vm { 17 | 18 | enum HeapRegionSpaceType { 19 | Young, 20 | LargeObject, 21 | Old 22 | }; 23 | 24 | class HeapRegionSpace { 25 | 26 | public: 27 | static HeapRegionSpace *create(const std::string& name); 28 | 29 | /// Ref arkcompiler HeapRegionAllocator::AllocateAlignedRegion 30 | /// and art RegionSpace::AllocateRegion 31 | /// and hermes HadesGC::createSegment 32 | HeapRegion *allocRegion(); 33 | 34 | HeapRegion *getCurrentRegion() const { 35 | return regions_.back(); 36 | } 37 | 38 | HeapRegion *getFirstRegion() const { 39 | return regions_.front(); 40 | } 41 | 42 | uint32_t getRegionCount() { 43 | return regions_.size(); 44 | } 45 | 46 | std::list &getRegions() { 47 | return regions_; 48 | } 49 | 50 | const std::list &getRegions() const { 51 | return regions_; 52 | } 53 | 54 | private: 55 | std::list regions_; 56 | }; 57 | 58 | } 59 | 60 | } 61 | 62 | #endif /* HeapRegion_h */ 63 | -------------------------------------------------------------------------------- /include/cobra/VM/InterfaceTable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef InterfaceTable_h 9 | #define InterfaceTable_h 10 | 11 | #include 12 | #include "cobra/VM/Object.h" 13 | 14 | namespace cobra { 15 | namespace vm { 16 | 17 | class InterfaceTable { 18 | 19 | 20 | 21 | 22 | 23 | }; 24 | 25 | } 26 | } 27 | 28 | #endif /* InterfaceTable_h */ 29 | -------------------------------------------------------------------------------- /include/cobra/VM/Interpreter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Interpreter_h 9 | #define Interpreter_h 10 | 11 | #include 12 | 13 | #include "cobra/VM/Method.h" 14 | #include "cobra/VM/StackFrame.h" 15 | #include "cobra/VM/Runtime.h" 16 | 17 | namespace cobra { 18 | namespace vm { 19 | 20 | // dalvik 21 | struct InterpSaveState { 22 | 23 | 24 | }; 25 | 26 | class Interpreter { 27 | 28 | public: 29 | static bool execute(Method *method, uint32_t *args, uint32_t argCount); 30 | 31 | static bool execute(StackFrame *frame); 32 | 33 | }; 34 | 35 | } 36 | } 37 | 38 | #endif /* Interpreter_h */ 39 | -------------------------------------------------------------------------------- /include/cobra/VM/MarkBitSet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef MarkBitSet_h 9 | #define MarkBitSet_h 10 | 11 | #include "cobra/Support/BitSet.h" 12 | #include "cobra/VM/RuntimeGlobals.h" 13 | 14 | namespace cobra { 15 | namespace vm { 16 | 17 | class MarkBitSet { 18 | public: 19 | MarkBitSet() = default; 20 | 21 | /// MarkBitSet is not copyable or movable: It must be constructed 22 | /// in-place. 23 | MarkBitSet(const MarkBitSet &) = delete; 24 | MarkBitSet(MarkBitSet &&) = delete; 25 | MarkBitSet &operator=(const MarkBitSet &) = delete; 26 | MarkBitSet &operator=(MarkBitSet &&) = delete; 27 | 28 | private: 29 | static constexpr size_t kNumBits = 1; 30 | BitSet bitSet; 31 | 32 | public: 33 | static constexpr size_t size() { 34 | return kNumBits; 35 | } 36 | 37 | /// Refto JSC candidateAtomNumber 38 | /// And hermes MarkBitArrayNC::addressToIndex 39 | inline size_t index(const void *ptr) const { 40 | return (reinterpret_cast(ptr) - reinterpret_cast(this)) >> LogHeapAlign; 41 | } 42 | 43 | inline bool at(size_t idx) const { 44 | assert(idx < kNumBits && "precondition: ind must be within the index range"); 45 | return true; 46 | return bitSet.at(idx); 47 | } 48 | 49 | inline void mark(size_t idx) { 50 | assert(idx < kNumBits && "precondition: ind must be within the index range"); 51 | bitSet.set(idx, true); 52 | } 53 | 54 | inline void mark(const void *ptr) { 55 | size_t idx = index(ptr); 56 | mark(idx); 57 | } 58 | 59 | inline void clear() { 60 | bitSet.reset(); 61 | } 62 | 63 | inline void markAll() { 64 | bitSet.set(); 65 | } 66 | 67 | }; 68 | 69 | 70 | 71 | } 72 | } 73 | 74 | #endif /* MarkBitSet_h */ 75 | -------------------------------------------------------------------------------- /include/cobra/VM/MemMapAllocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef MemMapAllocator_h 9 | #define MemMapAllocator_h 10 | 11 | #include 12 | #include 13 | 14 | namespace cobra { 15 | namespace vm { 16 | 17 | class MemMapAllocator { 18 | public: 19 | MemMapAllocator() = default; 20 | ~MemMapAllocator() = default; 21 | 22 | MemMapAllocator(const MemMapAllocator &) = delete; 23 | MemMapAllocator(MemMapAllocator &&) = delete; 24 | MemMapAllocator &operator=(const MemMapAllocator &) = delete; 25 | MemMapAllocator &operator=(MemMapAllocator &&) = delete; 26 | 27 | 28 | 29 | }; 30 | 31 | } 32 | } 33 | 34 | #endif /* MemMapAllocator_h */ 35 | -------------------------------------------------------------------------------- /include/cobra/VM/Method.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Method_h 9 | #define Method_h 10 | 11 | #include "cobra/VM/Object.h" 12 | #include "cobra/VM/CodeDataAccessor.h" 13 | 14 | namespace cobra { 15 | namespace vm { 16 | 17 | class Class; 18 | 19 | class Method : public Object { 20 | 21 | /// Access flags; low 16 bits are defined by spec. 22 | /// Getting and setting this flag needs to be atomic when concurrency is 23 | /// possible, e.g. after this method's class is linked. Such as when setting 24 | /// verifier flags and single-implementation flag. 25 | std::atomic accessFlags_ {0}; 26 | 27 | uint32_t argsCount_ {0}; 28 | 29 | uint16_t methodIndex_; 30 | 31 | const CexFile *file_; 32 | 33 | /// Method prototype descriptor string (return and argument types). 34 | const char *shorty_; 35 | 36 | public: 37 | 38 | ~Method() = default; 39 | 40 | Method() = delete; 41 | Method(const Method &) = delete; 42 | Method(Method &&) = delete; 43 | Method &operator=(const Method &) = delete; 44 | Method &operator=(Method &&) = delete; 45 | 46 | bool isPublic() const { 47 | return (getAccessFlags() & kAccPublic) != 0; 48 | } 49 | 50 | bool isPrivate() const { 51 | return (getAccessFlags() & kAccPrivate) != 0; 52 | } 53 | 54 | bool isProtected() const { 55 | return (getAccessFlags() & kAccProtected) != 0; 56 | } 57 | 58 | bool isStatic() const { 59 | return (getAccessFlags() & kAccStatic) != 0; 60 | } 61 | 62 | bool isNative() const { 63 | return (getAccessFlags() & kAccNative) != 0; 64 | } 65 | 66 | bool isAbstract() const { 67 | return (getAccessFlags() & kAccAbstract) != 0; 68 | } 69 | 70 | bool isFinal() const { 71 | return (getAccessFlags() & kAccFinal) != 0; 72 | } 73 | 74 | bool isConstructor() const { 75 | return (getAccessFlags() & kAccConstructor) != 0; 76 | } 77 | 78 | bool isInstanceConstructor() const { 79 | return isConstructor() && !isStatic(); 80 | } 81 | 82 | bool isStaticConstructor() const { 83 | return isConstructor() && isStatic(); 84 | } 85 | 86 | bool isObsolete() const { 87 | return (getAccessFlags() & kAccObsoleteMethod) != 0; 88 | } 89 | 90 | uint32_t getAccessFlags() const { 91 | return accessFlags_.load(std::memory_order_relaxed); 92 | } 93 | 94 | void setAccessFlags(uint32_t accessFlags) { 95 | /// Atomic with release order reason: data race with \p accessFlags_ with dependecies on writes before the store 96 | /// which should become visible acquire 97 | accessFlags_.store(accessFlags, std::memory_order_release); 98 | } 99 | 100 | uint16_t getMethodIndex() { 101 | return methodIndex_; 102 | } 103 | 104 | void setMethodIndex(uint16_t idx) { 105 | /// Not called within a transaction. 106 | methodIndex_ = idx; 107 | } 108 | 109 | const uint8_t *getInstructions() const { 110 | return CodeDataAccessor::getInstructions(*file_); 111 | } 112 | 113 | const char *getShorty() { 114 | return shorty_; 115 | } 116 | 117 | static constexpr uint32_t getArgCountOffset() { 118 | return MEMBER_OFFSET(Method, argsCount_); 119 | } 120 | 121 | static constexpr uint32_t getmethodIndexOffset() { 122 | return MEMBER_OFFSET(Method, methodIndex_); 123 | } 124 | 125 | void invoke(uint32_t *args, uint32_t argCount); 126 | 127 | void invokeCompiledCode(uint32_t *args, uint32_t argCount); 128 | 129 | }; 130 | 131 | } 132 | } 133 | 134 | #endif /* Method_h */ 135 | -------------------------------------------------------------------------------- /include/cobra/VM/Modifiers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Modifiers_h 9 | #define Modifiers_h 10 | 11 | #include 12 | #include 13 | 14 | namespace cobra { 15 | namespace vm { 16 | 17 | static constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic 18 | static constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic 19 | static constexpr uint32_t kAccProtected = 0x0004; // field, method, ic 20 | static constexpr uint32_t kAccStatic = 0x0008; // field, method, ic 21 | static constexpr uint32_t kAccFinal = 0x0010; // class, field, method, ic 22 | static constexpr uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives) 23 | static constexpr uint32_t kAccSuper = 0x0020; // class (not used in dex) 24 | static constexpr uint32_t kAccVolatile = 0x0040; // field 25 | static constexpr uint32_t kAccBridge = 0x0040; // method (1.5) 26 | static constexpr uint32_t kAccTransient = 0x0080; // field 27 | static constexpr uint32_t kAccVarargs = 0x0080; // method (1.5) 28 | static constexpr uint32_t kAccNative = 0x0100; // method 29 | static constexpr uint32_t kAccInterface = 0x0200; // class, ic 30 | static constexpr uint32_t kAccAbstract = 0x0400; // class, method, ic 31 | static constexpr uint32_t kAccStrict = 0x0800; // method 32 | static constexpr uint32_t kAccSynthetic = 0x1000; // class, field, method, ic 33 | static constexpr uint32_t kAccAnnotation = 0x2000; // class, ic (1.5) 34 | static constexpr uint32_t kAccEnum = 0x4000; // class, field, ic (1.5) 35 | 36 | static constexpr uint32_t kAccConstructor = 0x00010000; // method <(cl)init> 37 | 38 | // Set to indicate that the Method is obsolete. 39 | // This flag may only be applied to methods. 40 | static constexpr uint32_t kAccObsoleteMethod = 0x00040000; // method (runtime) 41 | 42 | } 43 | } 44 | 45 | #endif /* Modifiers_h */ 46 | -------------------------------------------------------------------------------- /include/cobra/VM/Object.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Object_h 9 | #define Object_h 10 | 11 | #include 12 | #include "cobra/VM/CBValue.h" 13 | #include "cobra/VM/GCCell.h" 14 | #include "cobra/Support/ArraySlice.h" 15 | #include "cobra/VM/GCPointer.h" 16 | #include "cobra/VM/Modifiers.h" 17 | #include "cobra/VM/ObjectAccessor.h" 18 | #include "cobra/VM/RuntimeGlobals.h" 19 | #include "cobra/Support/StringRef.h" 20 | #include "cobra/Support/Common.h" 21 | 22 | namespace cobra { 23 | namespace vm { 24 | 25 | class Class; 26 | 27 | class Object : public GCCell { 28 | /// The Class representing the type of the object. 29 | GCPointer clazz{nullptr}; 30 | 31 | public: 32 | 33 | Object() = default; 34 | 35 | static constexpr uint32_t instanceSize() { 36 | return sizeof(Object); 37 | } 38 | 39 | static constexpr uint32_t classOffset() { 40 | return MEMBER_OFFSET(Object, clazz); 41 | } 42 | 43 | inline Class *getClass() { 44 | return clazz.get(); 45 | } 46 | 47 | /// Ref to https://android.googlesource.com/platform/art/+/refs/heads/main/runtime/mirror/object.h#373 48 | /// and https://gitee.com/openharmony/arkcompiler_runtime_core/blob/master/static_core/runtime/include/object_accessor-inl.h#L111 49 | template 50 | inline T getFieldPrimitive(size_t offset) { 51 | auto *addr = reinterpret_cast(reinterpret_cast(this) + offset); 52 | if (IsVolatile) { 53 | // Atomic with seq_cst order reason: required for volatile 54 | return reinterpret_cast *>(addr)->load(std::memory_order_seq_cst); 55 | } 56 | // Atomic with relaxed order reason: to be compatible with other vms 57 | return reinterpret_cast *>(addr)->load(std::memory_order_relaxed); 58 | } 59 | 60 | template 61 | T getField(size_t offset) { 62 | return getFieldPrimitive(offset); 63 | } 64 | 65 | }; 66 | 67 | } 68 | } 69 | 70 | #endif /* Object_h */ 71 | -------------------------------------------------------------------------------- /include/cobra/VM/ObjectAccessor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef ObjectAccessor_h 9 | #define ObjectAccessor_h 10 | 11 | #include 12 | #include 13 | 14 | namespace cobra { 15 | namespace vm { 16 | 17 | class Object; 18 | 19 | class ObjectAccessor { 20 | public: 21 | template 22 | static T getPrimitive(const void *obj, size_t offset) { 23 | return get(obj, offset); 24 | } 25 | 26 | template 27 | static void setPrimitive(void *obj, size_t offset, T value) { 28 | set(obj, offset, value); 29 | } 30 | 31 | template 32 | static Object *getObject(const void *obj, size_t offset); 33 | 34 | template 35 | static void setObject(void *obj, size_t offset, Object *value); 36 | 37 | template 38 | static void setFieldPrimitive(void *obj, size_t offset, T value, std::memory_order memory_order) { 39 | set(obj, offset, value, memory_order); 40 | } 41 | 42 | template 43 | static Object *getFieldObject(const void *obj, int offset, std::memory_order memory_order) { 44 | return get(obj, offset, memory_order); 45 | } 46 | 47 | private: 48 | template 49 | static T get(const void *obj, size_t offset) { 50 | auto *addr = reinterpret_cast(reinterpret_cast(obj) + offset); 51 | if (IsVolatile) { 52 | // Atomic with seq_cst order reason: required for volatile 53 | return reinterpret_cast *>(addr)->load(std::memory_order_seq_cst); 54 | } 55 | // Atomic with relaxed order reason: to be compatible with other vms 56 | return reinterpret_cast *>(addr)->load(std::memory_order_relaxed); 57 | } 58 | 59 | template 60 | static void set(void *obj, size_t offset, T value) { 61 | auto *addr = reinterpret_cast(reinterpret_cast(obj) + offset); 62 | if (IsVolatile) { 63 | // Atomic with seq_cst order reason: required for volatile 64 | return reinterpret_cast *>(addr)->store(value, std::memory_order_seq_cst); 65 | } 66 | // Atomic with relaxed order reason: to be compatible with other vms 67 | return reinterpret_cast *>(addr)->store(value, std::memory_order_relaxed); 68 | } 69 | 70 | template 71 | static T get(const void *obj, size_t offset, std::memory_order memory_order) { 72 | auto *addr = reinterpret_cast(reinterpret_cast(obj) + offset); 73 | // Atomic with parameterized order reason: memory order passed as argument 74 | return reinterpret_cast *>(addr)->load(memory_order); 75 | } 76 | 77 | template 78 | static void set(void *obj, size_t offset, T value, std::memory_order memory_order){ 79 | auto *addr = reinterpret_cast(reinterpret_cast(obj) + offset); 80 | // Atomic with parameterized order reason: memory order passed as argument 81 | return reinterpret_cast *>(addr)->store(value, memory_order); 82 | } 83 | 84 | 85 | }; 86 | 87 | } 88 | } 89 | 90 | #endif /* ObjectAccessor_h */ 91 | -------------------------------------------------------------------------------- /include/cobra/VM/Offset.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Offset_h 9 | #define Offset_h 10 | 11 | #include 12 | 13 | namespace cobra { 14 | namespace vm { 15 | 16 | /// Allow the meaning of offsets to be strongly typed. 17 | class Offset { 18 | public: 19 | constexpr explicit Offset(size_t val) : val_(val) {} 20 | 21 | constexpr int32_t int32Value() const { 22 | return static_cast(val_); 23 | } 24 | constexpr uint32_t uint32Value() const { 25 | return static_cast(val_); 26 | } 27 | constexpr size_t sizeValue() const { 28 | return val_; 29 | } 30 | Offset& operator+=(const size_t rhs) { 31 | val_ += rhs; 32 | return *this; 33 | } 34 | constexpr bool operator==(Offset o) const { 35 | return sizeValue() == o.sizeValue(); 36 | } 37 | constexpr bool operator!=(Offset o) const { 38 | return !(*this == o); 39 | } 40 | constexpr bool operator<(Offset o) const { 41 | return sizeValue() < o.sizeValue(); 42 | } 43 | constexpr bool operator<=(Offset o) const { 44 | return !(*this > o); 45 | } 46 | constexpr bool operator>(Offset o) const { 47 | return o < *this; 48 | } 49 | constexpr bool operator>=(Offset o) const { 50 | return !(*this < o); 51 | } 52 | 53 | protected: 54 | size_t val_; 55 | }; 56 | std::ostream& operator<<(std::ostream& os, const Offset& offs); 57 | 58 | /// Offsets relative to an object. 59 | class MemberOffset : public Offset { 60 | public: 61 | constexpr explicit MemberOffset(size_t val) : Offset(val) {} 62 | }; 63 | 64 | } 65 | } 66 | 67 | #endif /* Offset_h */ 68 | -------------------------------------------------------------------------------- /include/cobra/VM/Operations.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Operations_h 9 | #define Operations_h 10 | 11 | #include 12 | 13 | #include "cobra/VM/Runtime.h" 14 | 15 | namespace cobra { 16 | namespace vm { 17 | 18 | bool strictEqualityTest(CBValue x, CBValue y); 19 | 20 | } 21 | } 22 | 23 | #endif /* Operations_h */ 24 | -------------------------------------------------------------------------------- /include/cobra/VM/Primitive.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Primitive_h 9 | #define Primitive_h 10 | 11 | #include "cobra/VM/Object.h" 12 | #include 13 | 14 | namespace cobra { 15 | namespace vm { 16 | 17 | class String final : public Object { 18 | public: 19 | using Super = Object; 20 | 21 | explicit String(std::string value) : value_(std::move(value)) {} 22 | 23 | static constexpr CBValueKind getCellKind() { 24 | return CBValueKind::StringKind; 25 | } 26 | static bool classof(const GCCell *cell) { 27 | return cell->getKind() == CBValueKind::StringKind; 28 | } 29 | 30 | std::string &value() { return value_; } 31 | 32 | private: 33 | std::string value_; 34 | 35 | }; 36 | 37 | class CBNumber final : public Object { 38 | public: 39 | 40 | 41 | 42 | }; 43 | 44 | class CBBoolean final : public Object { 45 | public: 46 | 47 | 48 | }; 49 | 50 | } 51 | } 52 | 53 | #endif /* Primitive_h */ 54 | -------------------------------------------------------------------------------- /include/cobra/VM/Runtime.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef Runtime_h 9 | #define Runtime_h 10 | 11 | #include 12 | 13 | #include "cobra/VM/Interpreter.h" 14 | #include "cobra/BCGen/BytecodeRawData.h" 15 | #include "cobra/VM/Handle.h" 16 | #include "cobra/VM/ClassLinker.h" 17 | #include "cobra/VM/RuntimeOptions.h" 18 | #include "cobra/VM/CexFile.h" 19 | #include "cobra/VM/StackFrame.h" 20 | 21 | namespace cobra { 22 | namespace vm { 23 | 24 | class Runtime { 25 | 26 | static Runtime* instance_; 27 | static RuntimeOptions options_; 28 | 29 | ClassLinker *classLinker_{}; 30 | HandleScope *topScope_{}; 31 | 32 | /// The package of the app running in this process. 33 | std::string processPackageName_{}; 34 | 35 | /// The data directory of the app running in this process. 36 | std::string processDataDirectory_{}; 37 | 38 | /// For saving class path. 39 | std::string pathString_{}; 40 | 41 | StackFrame *currentFrame_{nullptr}; 42 | 43 | public: 44 | 45 | Runtime(); 46 | 47 | static bool create(const RuntimeOptions &options); 48 | 49 | ~Runtime(); 50 | 51 | static bool destroy(); 52 | 53 | static Runtime *getCurrent(); 54 | 55 | HandleScope *getTopScope(); 56 | 57 | StackFrame *getCurrentFrame() { 58 | return currentFrame_; 59 | } 60 | 61 | bool runBytecode(std::shared_ptr &&bytecode); 62 | 63 | private: 64 | 65 | bool init(const RuntimeOptions &options); 66 | 67 | }; 68 | 69 | } 70 | 71 | } 72 | 73 | #endif /* Runtime_h */ 74 | -------------------------------------------------------------------------------- /include/cobra/VM/RuntimeGlobals.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef RuntimeGlobals_h 9 | #define RuntimeGlobals_h 10 | 11 | #include 12 | #include "cobra/Support/MathExtras.h" 13 | #pragma GCC diagnostic push 14 | 15 | #ifdef COBRA_COMPILER_SUPPORTS_WSHORTEN_64_TO_32 16 | #pragma GCC diagnostic ignored "-Wshorten-64-to-32" 17 | #endif 18 | 19 | namespace cobra { 20 | 21 | /// A type big enough to accomodate the entire allocated address space. 22 | /// Individual allocations are always 'uint32_t', but on a 64-bit machine we 23 | /// might want to accommodate a larger total heap (or not, in which case we keep 24 | /// it 32-bit). 25 | using gcheapsize_t = uint32_t; 26 | 27 | static const uint32_t LogHeapAlign = 3; 28 | static const uint32_t HeapAlign = 1 << LogHeapAlign; 29 | 30 | /// Align requested size according to the alignment requirement of the GC. 31 | constexpr inline uint32_t heapAlignSize(gcheapsize_t size) { 32 | return alignTo(size); 33 | } 34 | 35 | /// Return true if the requested size is properly aligned according to the 36 | /// alignment requirement of the GC. 37 | constexpr inline bool isSizeHeapAligned(gcheapsize_t size) { 38 | return (size & (HeapAlign - 1)) == 0; 39 | } 40 | 41 | using ObjectPointerType = uint32_t; 42 | static constexpr size_t ObjectPointerSize = sizeof(ObjectPointerType); 43 | 44 | enum class PointerSize : size_t { 45 | k32 = 4, 46 | k64 = 8 47 | }; 48 | 49 | static constexpr PointerSize kRuntimePointerSize = sizeof(void*) == 8U 50 | ? PointerSize::k64 51 | : PointerSize::k32; 52 | 53 | /// A constexpr value that is highly likely (but not absolutely 54 | /// guaranteed) to be at least as large, and a multiple of, 55 | /// oscompat::page_size(). Thus, this value can be used to compute 56 | /// page-aligned sizes statically. However, operations that require 57 | /// actual page_size()-alignment for correctness (e.g., ensuring that 58 | /// mprotect only protects what is intended) should verify the 59 | /// correctness of this value, using the function below. 60 | constexpr size_t kExpectedPageSize = 61 | #if defined(__APPLE__) 62 | 16 * 1024 63 | #else 64 | 4 * 1024 65 | #endif 66 | ; 67 | 68 | } 69 | 70 | #endif /* RuntimeGlobals_h */ 71 | -------------------------------------------------------------------------------- /include/cobra/VM/RuntimeModule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef RuntimeModule_h 9 | #define RuntimeModule_h 10 | 11 | #include 12 | 13 | #include "cobra/VM/Interpreter.h" 14 | #include "cobra/BCGen/BytecodeRawData.h" 15 | 16 | namespace cobra { 17 | namespace vm { 18 | 19 | class CodeBlock; 20 | class Runtime; 21 | 22 | class RuntimeModule { 23 | 24 | Runtime &runtime_; 25 | 26 | std::shared_ptr bytecode{}; 27 | 28 | public: 29 | explicit RuntimeModule(Runtime &runtime) : runtime_(runtime) {} 30 | 31 | ~RuntimeModule(); 32 | 33 | }; 34 | 35 | } 36 | } 37 | 38 | #endif /* Runtime_h */ 39 | -------------------------------------------------------------------------------- /include/cobra/VM/RuntimeOptions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef RuntimeOptions_h 9 | #define RuntimeOptions_h 10 | 11 | #include 12 | #include 13 | 14 | namespace cobra { 15 | 16 | using RuntimeRawOptions = std::vector>; 17 | 18 | class RuntimeOptions { 19 | public: 20 | 21 | static bool create(const RuntimeRawOptions& rawOptions); 22 | 23 | 24 | 25 | }; 26 | 27 | } 28 | 29 | #endif /* RuntimeOptions_h */ 30 | -------------------------------------------------------------------------------- /include/cobra/VM/StackFrame.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef StackFrame_h 9 | #define StackFrame_h 10 | 11 | #include 12 | 13 | namespace cobra { 14 | namespace vm { 15 | 16 | class Method; 17 | 18 | class StackFrame { 19 | public: 20 | static StackFrame *create(StackFrame *prev, Method *method, uint32_t argCount) { 21 | return new StackFrame(prev, method, argCount); 22 | } 23 | 24 | StackFrame *getPrevFrame() const { 25 | return prev_; 26 | } 27 | 28 | Method *getMethod() const { 29 | return method_; 30 | } 31 | 32 | void setMethod(Method *method){ 33 | method_ = method; 34 | } 35 | 36 | uint32_t getArgCount() const { 37 | return argCount_; 38 | } 39 | 40 | void setArgCount(uint32_t argCount) { 41 | argCount_ = argCount; 42 | } 43 | 44 | void setInstructions(const uint8_t *insts) { 45 | insts_ = insts; 46 | } 47 | 48 | const uint8_t *getInstructions() const { 49 | return insts_; 50 | } 51 | 52 | private: 53 | StackFrame( 54 | StackFrame *prev, 55 | Method *method, 56 | uint32_t argCount) 57 | : prev_(prev), 58 | method_(method), 59 | argCount_(argCount), 60 | insts_(nullptr){} 61 | 62 | ~StackFrame() = default; 63 | 64 | StackFrame() = delete; 65 | StackFrame(const StackFrame &) = delete; 66 | StackFrame(StackFrame &&) = delete; 67 | StackFrame &operator=(const StackFrame &) = delete; 68 | StackFrame &operator=(StackFrame &&) = delete; 69 | 70 | StackFrame *prev_; 71 | Method *method_; 72 | uint32_t argCount_; 73 | const uint8_t *insts_; 74 | 75 | }; 76 | 77 | } 78 | } 79 | 80 | #endif /* StackFrame_h */ 81 | -------------------------------------------------------------------------------- /include/cobra/VM/String.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef String_h 9 | #define String_h 10 | 11 | #include "cobra/VM/Object.h" 12 | 13 | namespace cobra { 14 | namespace vm { 15 | 16 | // String Compression 17 | static constexpr bool kUseStringCompression = true; 18 | enum class StringCompressionFlag : uint32_t { 19 | kCompressed = 0u, 20 | kUncompressed = 1u 21 | }; 22 | 23 | class String : public Object { 24 | 25 | public: 26 | String() = default; 27 | 28 | static constexpr uint32_t getLengthOffset() { 29 | return MEMBER_OFFSET(String, length_); 30 | } 31 | 32 | static constexpr uint32_t getDataOffset() { 33 | return MEMBER_OFFSET(String, data_); 34 | } 35 | 36 | static constexpr uint32_t getHashCodeOffset() { 37 | return MEMBER_OFFSET(String, hashCode_); 38 | } 39 | 40 | uint16_t *getData() { 41 | return &data_[0]; 42 | } 43 | 44 | uint8_t *getDataCompressed() { 45 | return &dataCompressed_[0]; 46 | } 47 | 48 | uint32_t getLength() const { 49 | return kUseStringCompression ? (length_ >> 1U) : length_; 50 | } 51 | 52 | bool isEmpty() const{ 53 | return length_ == 0; 54 | } 55 | 56 | uint32_t getHashCode() { 57 | if (hashCode_ == 0) { 58 | hashCode_ = computeHashCode(); 59 | } 60 | return hashCode_; 61 | } 62 | 63 | uint32_t computeHashCode(); 64 | 65 | bool isCompressed() { 66 | return kUseStringCompression && isCompressed(getLength()); 67 | } 68 | 69 | static bool isCompressed(int32_t length) { 70 | return getCompressionFlagFromLength(length) == StringCompressionFlag::kCompressed; 71 | } 72 | 73 | static StringCompressionFlag getCompressionFlagFromLength(int32_t length) { 74 | return kUseStringCompression 75 | ? static_cast(length & 1u) 76 | : StringCompressionFlag::kUncompressed; 77 | } 78 | 79 | bool equals(String* that); 80 | 81 | private: 82 | uint32_t length_; 83 | uint32_t hashCode_; 84 | 85 | /// Compression of all-ASCII into 8-bit memory leads to usage one of these fields 86 | union { 87 | uint16_t data_[0]; 88 | uint8_t dataCompressed_[0]; 89 | }; 90 | }; 91 | 92 | } 93 | } 94 | 95 | #endif /* String_h */ 96 | -------------------------------------------------------------------------------- /lib/AST/ASTBuilder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/AST/ASTBuilder.h" 9 | -------------------------------------------------------------------------------- /lib/AST/ASTVisitor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/AST/ASTVisitor.h" 9 | -------------------------------------------------------------------------------- /lib/AST/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the Cobra project authors. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | add_cobra_library(cobraAST 7 | ASTBuilder.cpp 8 | Tree.cpp 9 | ASTVisitor.cpp 10 | ) 11 | -------------------------------------------------------------------------------- /lib/AST/SemanticChecker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "SemanticChecker.h" 9 | 10 | using namespace cobra; 11 | -------------------------------------------------------------------------------- /lib/AST/SemanticChecker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef SemanticChecker_h 9 | #define SemanticChecker_h 10 | 11 | #include 12 | #include "cobra/AST/ASTVisitor.h" 13 | #include "cobra/AST/Tree.h" 14 | 15 | namespace cobra { 16 | 17 | class SemanticChecker { 18 | 19 | 20 | 21 | }; 22 | 23 | 24 | } 25 | 26 | #endif /* SemanticChecker_h */ 27 | -------------------------------------------------------------------------------- /lib/AST/Tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/AST/Tree.h" 9 | 10 | using namespace cobra; 11 | 12 | namespace Tree { 13 | 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /lib/BCGen/BCGen.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/BCGen/BCGen.h" 9 | #include "cobra/IR/CFG.h" 10 | #include "cobra/IR/Instrs.h" 11 | #include "cobra/BCGen/BytecodeGenerator.h" 12 | #include "cobra/Optimizer/Pass.h" 13 | #include "cobra/Optimizer/PassManager.h" 14 | #include "cobra/IR/Analysis.h" 15 | #include "cobra/BCGen/BCPasses.h" 16 | #include "cobra/BCGen/MovElimination.h" 17 | 18 | #include 19 | #include 20 | 21 | using namespace cobra; 22 | 23 | void lowerIR(Module *M) { 24 | PassManager PM; 25 | 26 | PM.addPass(); 27 | PM.addPass(); 28 | 29 | PM.run(M); 30 | 31 | } 32 | 33 | std::unique_ptr cobra::generateBytecode(Module *M) { 34 | lowerIR(M); 35 | 36 | BytecodeGenerator BCGen{}; 37 | 38 | for (auto &F : *M) { 39 | VirtualRegisterAllocator RA{F}; 40 | 41 | PostOrderAnalysis PO(F); 42 | std::vector order(PO.rbegin(), PO.rend()); 43 | 44 | RA.allocate(); 45 | 46 | F->dump(); 47 | 48 | PassManager PM; 49 | PM.addPass(RA); 50 | PM.run(F); 51 | 52 | F->dump(); 53 | 54 | auto funcGen = BytecodeFunctionGenerator::create(BCGen, F, RA); 55 | funcGen->generateBody(); 56 | 57 | BCGen.addFunction(F); 58 | BCGen.setFunctionGenerator(F, std::move(funcGen)); 59 | } 60 | 61 | return BCGen.generate(); 62 | } 63 | 64 | -------------------------------------------------------------------------------- /lib/BCGen/BCPasses.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/BCGen/BCPasses.h" 9 | #include "cobra/IR/IRBuilder.h" 10 | 11 | using namespace cobra; 12 | 13 | bool LoadConstants::runOnFunction(Function *F) { 14 | IRBuilder builder(F); 15 | builder.setInsertionPoint(F->front()->front()); 16 | 17 | bool changed = false; 18 | 19 | std::map constMap{}; 20 | 21 | auto createLoadLiteral = [&builder](Literal *literal) -> Instruction * { 22 | return dynamic_cast(builder.createLoadConstInst(literal)); 23 | }; 24 | 25 | F->dump(); 26 | 27 | for (auto BB : F->getBasicBlockList()) { 28 | for (auto &it : BB->getInstList()) { 29 | for (unsigned i = 0, n = it->getNumOperands(); i < n; i++) { 30 | 31 | auto *operand = dynamic_cast(it->getOperand(i)); 32 | if (!operand) 33 | continue; 34 | 35 | auto load = createLoadLiteral(operand); 36 | 37 | it->setOperand(load, i); 38 | changed = true; 39 | } 40 | } 41 | } 42 | 43 | F->dump(); 44 | 45 | return changed; 46 | } 47 | 48 | bool LoadParameters::runOnFunction(Function *F) { 49 | IRBuilder builder(F); 50 | builder.setInsertionPoint(F->front()->front()); 51 | 52 | bool changed = false; 53 | 54 | unsigned index = 1; 55 | for (Parameter *p : F->getParameters()) { 56 | auto *load = 57 | builder.createLoadParamInst(builder.getLiteralNumber(index)); 58 | p->replaceAllUsesWith(load); 59 | index++; 60 | changed = true; 61 | } 62 | 63 | return changed; 64 | } 65 | -------------------------------------------------------------------------------- /lib/BCGen/Bytecode.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/BCGen/Bytecode.h" 9 | 10 | using namespace cobra; 11 | 12 | void BytecodeModule::setFunction( 13 | uint32_t index, 14 | std::unique_ptr F) { 15 | assert(index < getNumFunctions() && "Function ID out of bound"); 16 | functions_[index] = std::move(F); 17 | } 18 | 19 | BytecodeFunction &BytecodeModule::getFunction(unsigned index) { 20 | assert(index < getNumFunctions() && "Function ID out of bound"); 21 | assert(functions_[index] && "Invalid function"); 22 | return *functions_[index]; 23 | } 24 | -------------------------------------------------------------------------------- /lib/BCGen/BytecodeInstructionSelector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/BCGen/BytecodeInstructionSelector.h" 9 | 10 | using namespace cobra; 11 | 12 | -------------------------------------------------------------------------------- /lib/BCGen/BytecodeRawData.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/BCGen/BytecodeRawData.h" 9 | 10 | using namespace cobra; 11 | 12 | BytecodeRawData::BytecodeRawData( 13 | std::unique_ptr byteCodeModule) 14 | : byteCodeModule_(std::move(byteCodeModule)) { 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /lib/BCGen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the Cobra project authors. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | add_cobra_library(cobraBackend 7 | RegAlloc.cpp 8 | Bytecode.cpp 9 | Lowering.cpp 10 | BytecodeGenerator.cpp 11 | BCGen.cpp 12 | BytecodeRawData.cpp 13 | BytecodeInstructionSelector.cpp 14 | BCPasses.cpp 15 | MovElimination.cpp 16 | LINK_LIBS cobraFrontend cobraOptimizer 17 | ) 18 | -------------------------------------------------------------------------------- /lib/BCGen/Lowering.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/BCGen/Lowering.h" 9 | #include "cobra/IR/IR.h" 10 | #include "cobra/IR/IRBuilder.h" 11 | #include "cobra/IR/Instrs.h" 12 | 13 | 14 | -------------------------------------------------------------------------------- /lib/BCGen/MovElimination.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/BCGen/MovElimination.h" 9 | #include "cobra/IR/IRBuilder.h" 10 | #include "cobra/IR/Instrs.h" 11 | #include "cobra/IR/Analysis.h" 12 | #include "cobra/BCGen/RegAlloc.h" 13 | 14 | using namespace cobra; 15 | 16 | bool MovElimination::runOnFunction(Function *F) { 17 | bool changed = false; 18 | 19 | // Keeps track of last assignment point of each register. 20 | std::unordered_map lastAssignment; 21 | // Keeps track of last use point of each register. 22 | std::unordered_map lastUse; 23 | 24 | IRBuilder::InstructionDestroyer destroyer; 25 | 26 | // For each basic block, do a forward scan and remember when each variable was 27 | // last assigned. Use this information to remove MOVs. 28 | PostOrderAnalysis PO(F); 29 | std::vector order(PO.rbegin(), PO.rend()); 30 | for (auto *BB : order) { 31 | unsigned index = 0; 32 | lastAssignment.clear(); 33 | lastUse.clear(); 34 | for (auto &it : *BB) { 35 | // Skip basic blocks with unallocated instructions. 36 | if (!RA_.isAllocated(it)) 37 | continue; 38 | 39 | // Set to true if the current instruction is a mov which we eliminated. 40 | bool movRemoved = false; 41 | 42 | index++; 43 | VirtualRegister dest = RA_.getRegister(it); 44 | 45 | if (auto *mov = dynamic_cast(it)) { 46 | Value *op = mov->getSingleOperand(); 47 | // If the operand is an instruction in the current basic block and it 48 | // has one user then maybe we can write it directly into the target 49 | // register. 50 | auto *IOp = dynamic_cast(op); 51 | 52 | // Skip basic blocks with unallocated instructions. 53 | if (!RA_.isAllocated(op)) 54 | continue; 55 | 56 | if (IOp && op->hasOneUser() && IOp->getParent() == BB) { 57 | VirtualRegister src = RA_.getRegister(IOp); 58 | // Get the index of the instructions that last wrote to the source and 59 | // dest registers. Note lookup() returns 0 if not found. 60 | auto iter = lastAssignment.find(src); 61 | unsigned srcIdx = iter != lastAssignment.end() ? iter->second : 0; 62 | iter = lastAssignment.find(dest); 63 | unsigned destIdx = iter != lastAssignment.end() ? iter->second : 0; 64 | iter = lastUse.find(dest); 65 | unsigned destUseIdx = iter != lastUse.end() ? iter->second : 0; 66 | 67 | // If the dest register was last written *after* the src register was 68 | // written into then we know that it is *live* in the range src..dest 69 | // so we can't remove the MOV. Only if the dest was live before the 70 | // src can we remove it. 71 | // Additionally, dest must not have uses in the range (src..dest). 72 | if (destIdx < srcIdx && !dynamic_cast(IOp) && 73 | destUseIdx <= srcIdx) { 74 | RA_.updateRegister(op, dest); 75 | destroyer.add(mov); 76 | mov->replaceAllUsesWith(op); 77 | changed = true; 78 | movRemoved = true; 79 | } 80 | } 81 | } 82 | 83 | // Save the current instruction and report the last index where the 84 | // register was modified. 85 | lastAssignment[dest] = index; 86 | 87 | // Save the last use point of every register, but skip mov-s which we just 88 | // eliminated. 89 | if (!movRemoved) { 90 | for (unsigned i = 0, e = it->getNumOperands(); i != e; ++i) { 91 | auto *op = it->getOperand(i); 92 | if (RA_.isAllocated(op)) 93 | lastUse[RA_.getRegister(op)] = index; 94 | } 95 | } 96 | } 97 | } 98 | 99 | return changed; 100 | } 101 | 102 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the Cobra project authors. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | add_cobra_library(cobraFrontend 7 | IRGen/IRGen.cpp 8 | IR/IR.cpp 9 | IR/IRBuilder.cpp 10 | IR/Instrs.cpp 11 | IR/Dominance.cpp 12 | IR/Analysis.cpp 13 | Utils/IRPrinter.cpp 14 | IRGen/IRGenStmt.cpp 15 | IRGen/IRGenExpr.cpp 16 | IRGen/IRGenFunction.cpp 17 | LINK_LIBS cobraSupport cobraAST cobraParser 18 | ) 19 | 20 | add_subdirectory(VM) 21 | add_subdirectory(AST) 22 | add_subdirectory(Parser) 23 | add_subdirectory(Support) 24 | add_subdirectory(BCGen) 25 | add_subdirectory(Optimizer) 26 | add_subdirectory(Driver) 27 | -------------------------------------------------------------------------------- /lib/Driver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the Cobra project authors. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | set(source_files 7 | Driver.cpp 8 | ) 9 | 10 | add_cobra_library(cobraDriver STATIC ${source_files} 11 | LINK_LIBS 12 | cobraAST 13 | cobraBackend 14 | cobraOptimizer 15 | cobraFrontend 16 | cobraParser 17 | cobraSupport 18 | cobraRuntime 19 | ) 20 | -------------------------------------------------------------------------------- /lib/Driver/Driver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/Driver/Driver.h" 9 | #include "cobra/Optimizer/Pipeline.h" 10 | #include "cobra/VM/Runtime.h" 11 | #include "cobra/BCGen/BCGen.h" 12 | #include "cobra/BCGen/BytecodeRawData.h" 13 | 14 | using namespace cobra; 15 | using namespace driver; 16 | using namespace Lowering; 17 | using namespace vm; 18 | 19 | bool driver::compile(std::string source) { 20 | auto context = std::make_shared(); 21 | Module M(context); 22 | 23 | parser::Parser cbParser(*context, source.c_str(), source.size()); 24 | auto parsedCb = cbParser.parse(); 25 | 26 | NodePtr ast = parsedCb.value(); 27 | 28 | TreeIRGen irGen(ast, &M); 29 | irGen.visitChildren(); 30 | 31 | runFullOptimizationPasses(M); 32 | 33 | auto BM = generateBytecode(&M); 34 | 35 | auto result = Runtime::create(RuntimeOptions()); 36 | auto BR = cobra::BytecodeRawData::create(std::move(BM)); 37 | Runtime::getCurrent()->runBytecode(std::move(BR)); 38 | 39 | return true; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /lib/IR/Analysis.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include "cobra/IR/Analysis.h" 12 | #include "cobra/IR/CFG.h" 13 | #include "cobra/IR/IR.h" 14 | 15 | #ifdef DEBUG_TYPE 16 | #undef DEBUG_TYPE 17 | #endif 18 | #define DEBUG_TYPE "IR Analysis" 19 | 20 | using namespace cobra; 21 | 22 | 23 | void PostOrderAnalysis::visitPostOrder(BasicBlock *BB, BlockList &order) { 24 | struct State { 25 | BasicBlock *BB; 26 | succ_iterator cur, end; 27 | explicit State(BasicBlock *BB) 28 | : BB(BB), cur(succ_begin(BB)), end(succ_end(BB)) {} 29 | }; 30 | 31 | std::unordered_set visited{}; 32 | std::vector stack{}; 33 | 34 | stack.emplace_back(new State(BB)); 35 | do { 36 | while (stack.back()->cur != stack.back()->end) { 37 | BB = *stack.back()->cur++; 38 | if (visited.insert(BB).second) 39 | stack.emplace_back(new State(BB)); 40 | } 41 | 42 | order.push_back(stack.back()->BB); 43 | stack.pop_back(); 44 | } while (!stack.empty()); 45 | } 46 | 47 | PostOrderAnalysis::PostOrderAnalysis(Function *F) : ctx_(F->getContext()) { 48 | assert(Order.empty() && "vector must be empty"); 49 | 50 | BasicBlock *entry = *F->begin(); 51 | 52 | // Finally, do an PO scan from the entry block. 53 | visitPostOrder(entry, Order); 54 | 55 | assert( 56 | !Order.empty() && Order[Order.size() - 1] == entry && 57 | "Entry block must be the last element in the vector"); 58 | } 59 | 60 | #undef DEBUG_TYPE 61 | -------------------------------------------------------------------------------- /lib/IR/Dominance.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/IR/Dominance.h" 9 | 10 | using namespace cobra; 11 | 12 | DominanceInfo::DominanceInfo(Function *F) : Parent(F) { 13 | assert(F->begin() != F->end() && "Function is empty!"); 14 | calculate(); 15 | } 16 | 17 | void DominanceInfo::calculate() { 18 | for (auto BB : *Parent) 19 | DomTreeNodes.insert({BB, std::make_unique(BB, nullptr)}); 20 | 21 | auto FindEntry = getNode(Parent->front()); 22 | assert(FindEntry && "must have entry node"); 23 | RootNode = FindEntry; 24 | 25 | createReversePostOrder(); 26 | createIDoms(); 27 | createDominanceFrontier(); 28 | createDominanceTreeSuccs(); 29 | } 30 | 31 | void DominanceInfo::postOrderVisit(BasicBlock *BB, std::set &Visited) { 32 | Visited.insert(BB); 33 | for (auto B : successors(BB)) { 34 | if (Visited.find(B) == Visited.end()) 35 | postOrderVisit(B, Visited); 36 | } 37 | PostOrderMap[getNode(BB)] = ReversePostOrder.size(); 38 | ReversePostOrder.push_back(getNode(BB)); 39 | } 40 | 41 | DomTreeNode *DominanceInfo::intersect(DomTreeNode *A, DomTreeNode *B) { 42 | while (A != B) { 43 | while (PostOrderMap[A] < PostOrderMap[B]) { 44 | A = A->getIDom(); 45 | } 46 | while (PostOrderMap[B] < PostOrderMap[A]) { 47 | B = B->getIDom(); 48 | } 49 | } 50 | return A; 51 | } 52 | 53 | std::vector DominanceInfo::getDomNodePreds(DomTreeNode *Node) { 54 | auto R = PredecessorrsOfNode.find(Node); 55 | if (R != PredecessorrsOfNode.end()) 56 | return R->second; 57 | 58 | std::vector PredDomTreeNodes; 59 | auto preds = predecessors(Node->getBlock()); 60 | 61 | for (auto pre : preds) 62 | PredDomTreeNodes.push_back(getNode(pre)); 63 | 64 | if (std::distance(preds.begin(), preds.end()) >= 2) 65 | JoinNodes.push_back(Node); 66 | 67 | PredecessorrsOfNode.insert({Node, PredDomTreeNodes}); 68 | return PredDomTreeNodes; 69 | } 70 | 71 | void DominanceInfo::createReversePostOrder() { 72 | ReversePostOrder.clear(); 73 | PostOrderMap.clear(); 74 | 75 | std::set visited; 76 | postOrderVisit(Parent->front(), visited); 77 | ReversePostOrder.reverse(); 78 | } 79 | 80 | void DominanceInfo::createIDoms() { 81 | RootNode->setIDom(RootNode); 82 | 83 | bool changed = true; 84 | while (changed) { 85 | changed = false; 86 | for (auto Node : ReversePostOrder) { 87 | if (Node == RootNode) 88 | continue; 89 | 90 | // (1) Find the first non-nullptr predecessor. 91 | DomTreeNode *IDom = nullptr; 92 | for (auto pred : getDomNodePreds(Node)) { 93 | if (pred->getIDom()) { 94 | IDom = pred; 95 | break; 96 | } 97 | } 98 | 99 | // (2) Traverse other predecessors. 100 | DomTreeNode *newIDom = IDom; 101 | for (auto *pred : getDomNodePreds(Node)) { 102 | if (pred == IDom) 103 | continue; 104 | 105 | if (pred->getIDom()) 106 | newIDom = intersect(pred, newIDom); 107 | } 108 | 109 | // (3) Judge the IDom is changed. 110 | if (Node->getIDom() != newIDom) { 111 | Node->setIDom(newIDom); 112 | changed = true; 113 | } 114 | } 115 | } 116 | } 117 | 118 | void DominanceInfo::createDominanceFrontier() { 119 | for (auto &Node : JoinNodes) { 120 | for (auto *pred : getDomNodePreds(Node)) { 121 | auto runner = pred; 122 | while (runner != Node->getIDom()) { 123 | addDominanceFrontier(runner, Node); 124 | runner = runner->getIDom(); 125 | } 126 | } 127 | } 128 | } 129 | 130 | void DominanceInfo::createDominanceTreeSuccs() { 131 | for (auto &Node : JoinNodes) { 132 | auto idom = Node->getIDom(); 133 | if (idom != Node) 134 | addDominanceTreeSucc(idom, Node); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /lib/IR/Scope.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/IR/Scope.h" 9 | -------------------------------------------------------------------------------- /lib/IRGen/IRGen.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/IRGen/IRGen.h" 9 | #include 10 | #include 11 | 12 | using namespace cobra; 13 | using namespace Lowering; 14 | 15 | TreeIRGen::TreeIRGen(ASTNode *root, Module *M) : Mod(M), Builder(Mod), Root(root) { 16 | currentScope = new Scope(nullptr); 17 | } 18 | 19 | TreeIRGen::~TreeIRGen() { 20 | 21 | } 22 | 23 | void TreeIRGen::visitChildren() { 24 | Program *Program = dynamic_cast(Root); 25 | for (auto Node : Program->body) { 26 | visit(Node); 27 | } 28 | } 29 | 30 | Value *TreeIRGen::visitFuncDecl(FuncDecl *fd) { emitFunction(fd); } 31 | 32 | Value *TreeIRGen::visitParamDecl(ParamDecl *pd) { 33 | 34 | } 35 | 36 | Value *TreeIRGen::visitVariableDecl(VariableDecl *vd) { 37 | Identifier name{}; 38 | if (dynamic_cast(vd->id)) 39 | name = getNameFieldFromID(vd->id); 40 | // Variable *V = Builder.createVariable(Variable::DeclKind::Var, name); 41 | // currentScope->insert(&name, V); 42 | auto *stackVar = Builder.createAllocStackInst(name); 43 | currentScope->insert(name, stackVar); 44 | if (vd->init) { 45 | auto *storedValue = visitExpr(vd->init); 46 | Builder.createStoreStackInst(storedValue, stackVar); 47 | } 48 | } 49 | 50 | Value *TreeIRGen::ensureVariableExists(IdentifierExpr *id) { 51 | Identifier name = getNameFieldFromID(id); 52 | 53 | if (auto *var = currentScope->lookup(name)) 54 | return var; 55 | 56 | return nullptr; 57 | } 58 | -------------------------------------------------------------------------------- /lib/IRGen/IRGenExpr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/IRGen/IRGen.h" 9 | 10 | using namespace cobra; 11 | using namespace Lowering; 12 | 13 | Value *TreeIRGen::visitBooleanLiteralExpr(BooleanLiteralExpr *be) { 14 | return Builder.getLiteralBool(be->value); 15 | } 16 | 17 | Value *TreeIRGen::visitNumericLiteralExpr(NumericLiteralExpr *ne) { 18 | return Builder.getLiteralNumber(ne->value); 19 | } 20 | 21 | Value *TreeIRGen::visitStringLiteralExpr(StringLiteralExpr *se) { 22 | return Builder.getLiteralString(se->value->str()); 23 | } 24 | 25 | Value *TreeIRGen::visitCallExpr(CallExpr *ce) { 26 | 27 | } 28 | 29 | Value *TreeIRGen::visitMemberExpr(MemberExpr *me) { 30 | 31 | } 32 | 33 | Value *TreeIRGen::visitIdentifierExpr(IdentifierExpr *ie) { 34 | auto StrName = getNameFieldFromID(ie); 35 | auto *Var = ensureVariableExists(ie); 36 | if (returnAdd) { 37 | returnAdd = false; 38 | return Var; 39 | } 40 | return Builder.createLoadStackInst(dynamic_cast(Var)); 41 | } 42 | 43 | Value *TreeIRGen::visitUnaryExpr(UnaryExpr *ue) { 44 | 45 | } 46 | 47 | Value *TreeIRGen::visitPostfixUnaryExpr(PostfixUnaryExpr *pe) { 48 | 49 | } 50 | 51 | Value *TreeIRGen::visitBinaryExpr(BinaryExpr *be) { 52 | auto Kind = BinaryOperatorInst::parseOperator(be->Operator->str()); 53 | auto lhs = visitExpr(be->left); 54 | auto rhs = visitExpr(be->right); 55 | 56 | BinaryOperatorInst *result = Builder.createBinaryOperatorInst(lhs, rhs, Kind); 57 | return result; 58 | } 59 | 60 | Value *TreeIRGen::visitSpreadElementExpr(SpreadElementExpr *se) { 61 | 62 | } 63 | 64 | 65 | Value *TreeIRGen::visitConditionalExpr(ConditionalExpr *ce) { 66 | 67 | } 68 | 69 | Value *TreeIRGen::visitAssignmentExpr(AssignmentExpr *ae) { 70 | returnAdd = true; 71 | auto left = visitExpr(ae->left); 72 | auto right = visitExpr(ae->right); 73 | 74 | Builder.createStoreStackInst(right, dynamic_cast(left)); 75 | } 76 | 77 | void TreeIRGen::emitExpressionBranch( 78 | Expr *expr, 79 | BasicBlock *onTrue, 80 | BasicBlock *onFalse, 81 | BasicBlock *onNullish) { 82 | 83 | Value *condVal = visitExpr(expr); 84 | Builder.createCondBranchInst(condVal, onTrue, onFalse); 85 | } 86 | -------------------------------------------------------------------------------- /lib/IRGen/IRGenFunction.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/IRGen/IRGen.h" 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace cobra; 14 | using namespace Lowering; 15 | 16 | void TreeIRGen::emitFunction(FuncDecl *fd) { 17 | Identifier functionName = getNameFieldFromID(fd->id); 18 | Function *newFunction = Builder.createFunction(functionName); 19 | this->curFunction = newFunction; 20 | 21 | emitFunctionPreamble(Builder.createBasicBlock(newFunction)); 22 | 23 | emitParameters(fd); 24 | 25 | emitStatement(fd->body); 26 | 27 | newFunction->dump(); 28 | } 29 | 30 | void TreeIRGen::emitFunctionPreamble(BasicBlock *entry) { 31 | BasicBlock *realEntry = this->curFunction->front(); 32 | if (realEntry->empty()) { 33 | Builder.setInsertionBlock(realEntry); 34 | }else { 35 | Builder.setInsertionPoint(realEntry->front()); 36 | } 37 | 38 | Builder.setInsertionBlock(entry); 39 | } 40 | 41 | void TreeIRGen::emitParameters(AbstractFunctionDecl *funcNode) { 42 | for (auto paramDecl : funcNode->params) { 43 | auto paramName = getNameFieldFromID(paramDecl->id); 44 | auto *param = Builder.createParameter(this->curFunction, paramName); 45 | 46 | if (paramDecl->init) { 47 | auto *currentBlock = Builder.getInsertionBlock(); 48 | auto *getDefaultBlock = Builder.createBasicBlock(Builder.getFunction()); 49 | auto *storeBlock = Builder.createBasicBlock(Builder.getFunction()); 50 | 51 | Builder.createCondBranchInst( 52 | Builder.createBinaryOperatorInst( 53 | param, 54 | Builder.getLiteralUndefined(), 55 | BinaryOperatorInst::OpKind::StrictlyNotEqualKind), 56 | storeBlock, 57 | getDefaultBlock); 58 | 59 | Builder.setInsertionBlock(getDefaultBlock); 60 | auto *defaultValue = visitExpr(paramDecl->init); 61 | auto *defaultResultBlock = Builder.getInsertionBlock(); 62 | Builder.createBranchInst(storeBlock); 63 | 64 | // storeBlock: 65 | Builder.setInsertionBlock(storeBlock); 66 | auto *phi = Builder.createPhiInst( 67 | {param, defaultValue}, {currentBlock, defaultResultBlock}); 68 | 69 | } else { 70 | auto *stackVar = Builder.createAllocStackInst(paramName); 71 | currentScope->insert(paramName, stackVar); 72 | Builder.createStoreStackInst(param, stackVar); 73 | } 74 | } 75 | } 76 | 77 | void TreeIRGen::emitFunctionEpilogue(Value *returnValue) { 78 | Builder.createReturnInst(returnValue); 79 | } 80 | -------------------------------------------------------------------------------- /lib/IRGen/IRGenStmt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/IRGen/IRGen.h" 9 | 10 | using namespace cobra; 11 | using namespace Lowering; 12 | 13 | void TreeIRGen::emitStatement(Stmt *stmt) { 14 | visitStmt(stmt); 15 | } 16 | 17 | Value *TreeIRGen::visitBlockStmt(BlockStmt *bs) { 18 | for (auto node : bs->body) { 19 | visit(node); 20 | } 21 | } 22 | 23 | Value *TreeIRGen::visitReturnStmt(ReturnStmt *rs) { 24 | Value *Value; 25 | // Generate IR for the return value, or undefined if this is an empty return 26 | // statement. 27 | if (auto *A = rs->argument) { 28 | Value = visitExpr(A); 29 | } else { 30 | Value = Builder.getLiteralUndefined(); 31 | } 32 | Builder.createReturnInst(Value); 33 | auto Parent = Builder.getInsertionBlock()->getParent(); 34 | Builder.setInsertionBlock(Builder.createBasicBlock(Parent)); 35 | } 36 | 37 | Value *TreeIRGen::visitIfStmt(IfStmt *is) { 38 | auto parent = Builder.getInsertionBlock()->getParent(); 39 | auto thenBB = Builder.createBasicBlock(parent); 40 | auto elseBB = Builder.createBasicBlock(parent); 41 | auto continueBB = Builder.createBasicBlock(parent); 42 | 43 | emitExpressionBranch(is->Condition, thenBB, elseBB, nullptr); 44 | 45 | Builder.setInsertionBlock(thenBB); 46 | visit(is->Then); 47 | Builder.createBranchInst(continueBB); 48 | 49 | // IRGen the Else, if it exists: 50 | Builder.setInsertionBlock(elseBB); 51 | if (is->Else) { 52 | visit(is->Else); 53 | } 54 | 55 | Builder.createBranchInst(continueBB); 56 | Builder.setInsertionBlock(continueBB); 57 | } 58 | 59 | Value *TreeIRGen::visitVariableStmt(VariableStmt *vs) { 60 | for (auto decl : vs->declarations) { 61 | visitDecl(decl); 62 | } 63 | } 64 | 65 | Value *TreeIRGen::visitExpressionStmt(ExpressionStmt *es) { 66 | Value *value = visitExpr(es->expression); 67 | } 68 | 69 | Instruction *TreeIRGen::emitLoad(Value *from) { 70 | 71 | } 72 | 73 | Instruction *TreeIRGen::emitStore(Value *storedValue, Value *ptr, bool declInit) { 74 | 75 | } 76 | 77 | -------------------------------------------------------------------------------- /lib/Optimizer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the Cobra project authors. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | add_cobra_library(cobraOptimizer 7 | CSE.cpp 8 | DCE.cpp 9 | Inlining.cpp 10 | Mem2Reg.cpp 11 | PassManager.cpp 12 | Pipeline.cpp 13 | SimplifyCFG.cpp 14 | SSADestruction.cpp 15 | LINK_LIBS cobraFrontend 16 | ) 17 | -------------------------------------------------------------------------------- /lib/Optimizer/CSE.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #define DEBUG_TYPE "cse" 9 | #include "cobra/Optimizer/CSE.h" 10 | #include "cobra/IR/Instrs.h" 11 | 12 | -------------------------------------------------------------------------------- /lib/Optimizer/DCE.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #define DEBUG_TYPE "dce" 9 | 10 | #include "cobra/Optimizer/DCE.h" 11 | #include "cobra/IR/IRBuilder.h" 12 | #include "cobra/IR/Instrs.h" 13 | #include "cobra/IR/Analysis.h" 14 | 15 | using namespace cobra; 16 | 17 | static bool performFunctionDCE(Function *F) { 18 | bool changed = false; 19 | F->dump(); 20 | PostOrderAnalysis PO(F); 21 | F->dump(); 22 | 23 | IRBuilder::InstructionDestroyer destroyer; 24 | 25 | for (auto *BB : PO) { 26 | // Scan the instructions in the block from end to start. 27 | for (auto it = BB->rbegin(), e = BB->rend(); it != e; /* nothing */) { 28 | Instruction *I = *it; 29 | // Move the iterator to the next instruction in the block. This will 30 | // allow us to delete the current instruction. 31 | ++it; 32 | 33 | // If the instruction writes to memory then we can't remove it. Notice 34 | // that it is okay to delete instructions that only read memory and are 35 | // unused. 36 | // 37 | // Terminators don't have any uses but are never supposed to be removed 38 | // as dead code. 39 | // 40 | // CreateScopeInst may not have any users, but it is lowered to 41 | // HBCCreateEnvironmentInst which should always be emitted and DCE'd if 42 | // appropriate. 43 | // 44 | // HasRestrictedGlobalPropertyInst doesn't have a result but should never 45 | // be removed as they perform runtime validation. 46 | if (I->mayWriteMemory() || dynamic_cast(I)) { 47 | continue; 48 | } 49 | 50 | // If some other instruction is using the result of this instruction then 51 | // we can't delete it. 52 | if (I->getNumUsers()) 53 | continue; 54 | 55 | destroyer.add(I); 56 | changed = true; 57 | } 58 | } 59 | 60 | return changed; 61 | } 62 | 63 | bool DCE::runOnModule(Module *M) { 64 | bool changed = false; 65 | 66 | for (auto &F : *M) { 67 | F->dump(); 68 | changed |= performFunctionDCE(F); 69 | F->dump(); 70 | } 71 | 72 | return changed; 73 | } 74 | 75 | std::unique_ptr cobra::createDCE() { 76 | return std::make_unique(); 77 | } 78 | 79 | #undef DEBUG_TYPE 80 | -------------------------------------------------------------------------------- /lib/Optimizer/Inlining.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #define DEBUG_TYPE "inline" 9 | #include "cobra/Optimizer/Inlining.h" 10 | #include "cobra/IR/IRBuilder.h" 11 | 12 | 13 | 14 | #undef DEBUG_TYPE 15 | -------------------------------------------------------------------------------- /lib/Optimizer/PassManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/Optimizer/PassManager.h" 9 | #include "cobra/IR/IR.h" 10 | 11 | #include 12 | 13 | #define DEBUG_TYPE "passmanager" 14 | 15 | using namespace cobra; 16 | 17 | PassManager::~PassManager() = default; 18 | 19 | void PassManager::addPass(std::unique_ptr P) { 20 | pipeline_.emplace_back(std::move(P)); 21 | } 22 | 23 | void PassManager::run(Module *M) { 24 | for (std::unique_ptr &P : pipeline_) { 25 | if (auto *FP = dynamic_cast(P.get())) {; 26 | for (auto &F : *M) { 27 | FP->runOnFunction(F); 28 | } 29 | // Move to the next pass. 30 | continue; 31 | } 32 | 33 | if (auto *MP = dynamic_cast(P.get())) {; 34 | MP->runOnModule(M); 35 | // Move to the next pass. 36 | continue; 37 | } 38 | } 39 | } 40 | 41 | void PassManager::run(Function *F) { 42 | 43 | // For each pass: 44 | for (const std::unique_ptr &P : pipeline_) { 45 | auto *FP = dynamic_cast(P.get()); 46 | assert(FP && "Invalid pass kind"); 47 | FP->runOnFunction(F); 48 | } 49 | } 50 | 51 | #undef DEBUG_TYPE 52 | -------------------------------------------------------------------------------- /lib/Optimizer/Pipeline.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/Optimizer/Pipeline.h" 9 | #include "cobra/Optimizer/PassManager.h" 10 | #include "cobra/Optimizer/DCE.h" 11 | #include "cobra/Optimizer/SimplifyCFG.h" 12 | 13 | 14 | #define DEBUG_TYPE "pipeline" 15 | 16 | void cobra::runFullOptimizationPasses(Module &M) { 17 | PassManager PM; 18 | PM.addSimplifyCFG(); 19 | PM.addMem2Reg(); 20 | PM.addDCE(); 21 | // PM.addSSADestruction(); 22 | 23 | PM.run(&M); 24 | } 25 | 26 | #undef DEBUG_TYPE 27 | -------------------------------------------------------------------------------- /lib/Optimizer/SimplifyCFG.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #define DEBUG_TYPE "simplifycfg" 9 | 10 | #include 11 | 12 | #include "cobra/Optimizer/SimplifyCFG.h" 13 | #include "cobra/IR/IRBuilder.h" 14 | #include "cobra/IR/CFG.h" 15 | 16 | using namespace cobra; 17 | 18 | static int NumUnreachableBlock = 0; 19 | 20 | static void deleteBasicBlock(BasicBlock *B) { 21 | Value::UseListTy users(B->getUsers().begin(), B->getUsers().end()); 22 | 23 | for (auto *I : users) { 24 | if (auto *Phi = dynamic_cast(I)) { 25 | Phi->removeEntry(B); 26 | continue; 27 | } 28 | } 29 | 30 | B->replaceAllUsesWith(nullptr); 31 | B->eraseFromParent(); 32 | } 33 | 34 | static bool removeUnreachedBasicBlocks(Function *F) { 35 | bool changed = false; 36 | 37 | std::unordered_set visited; 38 | std::vector workList; 39 | 40 | workList.push_back(*F->begin()); 41 | while (!workList.empty()) { 42 | auto BB = workList.back(); 43 | workList.pop_back(); 44 | 45 | if (!visited.insert(BB).second) 46 | continue; 47 | 48 | for (auto *succ : successors(BB)) 49 | workList.push_back(succ); 50 | } 51 | 52 | for (auto it = F->begin(), e = F->end(); it != e;) { 53 | auto *BB = *it++; 54 | if (std::find(visited.begin(), visited.end(), BB) == visited.end()) { 55 | ++NumUnreachableBlock; 56 | deleteBasicBlock(BB); 57 | changed = true; 58 | } 59 | } 60 | 61 | return changed; 62 | } 63 | 64 | bool SimplifyCFG::runOnFunction(Function *F) { 65 | bool changed = false; 66 | 67 | bool iterChanged = false; 68 | // Keep iterating over deleting unreachable code and removing trampolines as 69 | // long as we are making progress. 70 | do { 71 | iterChanged = removeUnreachedBasicBlocks(F); 72 | changed |= iterChanged; 73 | } while (iterChanged); 74 | 75 | return changed; 76 | } 77 | 78 | std::unique_ptr cobra::createSimplifyCFG() { 79 | return std::make_unique(); 80 | } 81 | 82 | #undef DEBUG_TYPE 83 | -------------------------------------------------------------------------------- /lib/Parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the Cobra project authors. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | add_cobra_library(cobraParser 7 | Lexer.cpp 8 | Parser.cpp 9 | LINK_LIBS cobraSupport cobraAST 10 | ) 11 | 12 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 13 | -------------------------------------------------------------------------------- /lib/Support/Base64.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/Support/Base64.h" 9 | -------------------------------------------------------------------------------- /lib/Support/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the Cobra project authors. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | add_cobra_library(cobraSupport 7 | Base64.cpp 8 | StringRef.cpp 9 | OSCompatPosix.cpp 10 | zip.cpp 11 | LINK_LIBS ${link_libs} 12 | ) 13 | -------------------------------------------------------------------------------- /lib/Support/StringRef.cpp: -------------------------------------------------------------------------------- 1 | //===- StringRef.h - Constant String Reference Wrapper ----------*- C++ -*-===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | 10 | #include "cobra/Support/StringRef.h" 11 | 12 | using namespace cobra; 13 | 14 | size_t StringRef::count(StringRef Str) const { 15 | size_t Count = 0; 16 | size_t N = Str.size(); 17 | if (N > Length) 18 | return 0; 19 | for (size_t i = 0, e = Length - N + 1; i != e; ++i) 20 | if (substr(i, N).equals(Str)) 21 | ++Count; 22 | return Count; 23 | } 24 | -------------------------------------------------------------------------------- /lib/VM/Array.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/Array.h" 9 | #include "cobra/VM/ObjectAccessor.h" 10 | 11 | using namespace cobra; 12 | using namespace vm; 13 | 14 | template 15 | constexpr size_t Array::getElementSize() { 16 | constexpr bool isREF = std::is_pointer_v && std::is_base_of_v>; 17 | static_assert(std::is_arithmetic_v || isREF, "T should be arithmetic type or pointer to managed object type"); 18 | 19 | return isREF ? ObjectPointerSize : sizeof(T); 20 | } 21 | 22 | template 23 | T Array::getPrimitive(size_t offset) const { 24 | return ObjectAccessor::getPrimitive(this, getDataOffset() + offset); 25 | } 26 | 27 | template 28 | void Array::setPrimitive(size_t offset, T value) { 29 | ObjectAccessor::setPrimitive(this, getDataOffset() + offset, value); 30 | } 31 | 32 | template 33 | Object *Array::getObject(int offset) const { 34 | return ObjectAccessor::getObject(this, getDataOffset() + offset); 35 | } 36 | 37 | template 38 | void Array::setObject(size_t offset, Object *value) { 39 | ObjectAccessor::setObject(this, getDataOffset() + offset, value); 40 | } 41 | 42 | template 43 | void Array::set(uint32_t idx, T value) { 44 | constexpr bool isREF = std::is_pointer_v && std::is_base_of_v>; 45 | static_assert(std::is_arithmetic_v || isREF, "T should be arithmetic type or pointer to managed object type"); 46 | 47 | size_t elementSize = isREF ? ObjectPointerSize : sizeof(T); 48 | size_t offset = elementSize * idx; 49 | 50 | if constexpr (isREF) { 51 | ObjectAccessor::setObject(this, getDataOffset() + offset, value); 52 | } else { 53 | ObjectAccessor::setPrimitive(this, getDataOffset() + offset, value); 54 | } 55 | } 56 | 57 | template 58 | T Array::get(uint32_t idx) const { 59 | 60 | } 61 | -------------------------------------------------------------------------------- /lib/VM/CBValue.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/CBValue.h" 9 | -------------------------------------------------------------------------------- /lib/VM/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the Cobra project authors. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | add_cobra_library(cobraRuntime 7 | Method.cpp 8 | Object.cpp 9 | String.cpp 10 | Class.cpp 11 | Field.cpp 12 | Array.cpp 13 | InterfaceTable.cpp 14 | CBValue.cpp 15 | CodeBlock.cpp 16 | GC.cpp 17 | GCRoot.cpp 18 | GCCell.cpp 19 | Interpreter.cpp 20 | Primitive.cpp 21 | Runtime.cpp 22 | RuntimeModule.cpp 23 | String.cpp 24 | CardTable.cpp 25 | HeapRegion.cpp 26 | Handle.cpp 27 | Offset.cpp 28 | GCPointer.cpp 29 | ClassLinker.cpp 30 | RuntimeOptions.cpp 31 | CobraVM.cpp 32 | CexFile.cpp 33 | StackFrame.cpp 34 | ObjectAccessor.cpp 35 | FreeList.cpp 36 | MemMapAllocator.cpp 37 | HeapRegionSpace.cpp 38 | CodeDataAccessor.cpp 39 | CobraCache.cpp 40 | ClassDataAccessor.cpp 41 | Operations.cpp 42 | LINK_LIBS cobraSupport 43 | ) 44 | 45 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 46 | -------------------------------------------------------------------------------- /lib/VM/CardTable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/CardTable.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | inline const uint8_t *CardTable::base() const { 14 | return reinterpret_cast(this); 15 | } 16 | 17 | inline void *CardTable::cardToAddress(const uint8_t *cardAddr) const { 18 | uintptr_t offset = cardAddr - base(); 19 | return reinterpret_cast(offset << kLogCardSize); 20 | } 21 | 22 | inline uint8_t *CardTable::addressToCard(const void *addr) const { 23 | const uint8_t *cardAddr = base()+ (reinterpret_cast(addr) >> kLogCardSize); 24 | return const_cast(cardAddr); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /lib/VM/CexFile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/CexFile.h" 9 | 10 | using namespace cobra; 11 | 12 | bool static isZipMagic(uint32_t magic) { 13 | return (('P' == ((magic >> 0) & 0xff)) && ('K' == ((magic >> 8) & 0xff))); 14 | } 15 | 16 | uint32_t CexFile::Header::getVersion() const { 17 | const char* version = reinterpret_cast(&magic_[kMagicSize]); 18 | return atoi(version); 19 | } 20 | 21 | inline const char *CexFile::getStringData(EntityId id) const { 22 | auto array = getArrayFromId(id); 23 | return reinterpret_cast(array.data()); 24 | } 25 | 26 | static ArraySlice getData(const uint8_t *base) { 27 | auto header = reinterpret_cast(base); 28 | ArraySlice array(base, header->fileSize); 29 | return array; 30 | } 31 | 32 | CexFile::CexFile(const uint8_t *base, std::string location) 33 | : location_(location), 34 | header_(reinterpret_cast(base)), 35 | data_(getData(base)), 36 | stringIds_(getSection(header_->stringIdxOffset)), 37 | fieldIds_(getSection(header_->fieldIdxOffset)), 38 | methodIds_(getSection(header_->methodIdxOffset)), 39 | protoIds_(getSection(header_->protoIdxOffset)) { 40 | 41 | } 42 | 43 | template 44 | inline const T *CexFile::getSection(const uint32_t offset) { 45 | return reinterpret_cast(data_.data() + offset); 46 | } 47 | 48 | std::unique_ptr CexFile::open(std::string_view filename) { 49 | // TODO: mmap 50 | } 51 | 52 | std::unique_ptr cobra::openCexFile(std::string_view location) { 53 | uint32_t magic; 54 | 55 | FILE *fp = fopen(std::string(location).c_str(), "rb"); 56 | if (fp == nullptr) { 57 | return nullptr; 58 | } 59 | (void)fseek(fp, 0, SEEK_SET); 60 | if (fread(&magic, sizeof(magic), 1, fp) != 1) { 61 | fclose(fp); 62 | return nullptr; 63 | } 64 | (void)fseek(fp, 0, SEEK_SET); 65 | std::unique_ptr file; 66 | 67 | if (isZipMagic(magic)) { 68 | struct zip_t *zip = zip_open(location.data(), 0, 'r'); 69 | 70 | if (zip) { 71 | zip_close(zip); 72 | } 73 | 74 | 75 | } else { 76 | file = CexFile::open(location); 77 | } 78 | 79 | fclose(fp); 80 | return file; 81 | } 82 | -------------------------------------------------------------------------------- /lib/VM/Class.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/Class.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | -------------------------------------------------------------------------------- /lib/VM/ClassDataAccessor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/ClassDataAccessor.h" 9 | 10 | using namespace cobra; 11 | 12 | ClassDataAccessor::ClassDataAccessor(const CexFile &file, uint32_t classID) 13 | : file_(file), classID_(classID) { 14 | 15 | } 16 | 17 | const char *ClassDataAccessor::getDescriptor() const { 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /lib/VM/ClassLinker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/ClassLinker.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | Class *ClassLinker::loadClass(const CexFile *file, uint32_t classID) { 14 | ClassDataAccessor accessor(*file, classID); 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /lib/VM/CobraCache.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/CobraCache.h" 9 | 10 | using namespace cobra; 11 | 12 | 13 | -------------------------------------------------------------------------------- /lib/VM/CobraVM.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/CobraVM.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | CobraVM *CobraVM::create(Runtime *runtime, const RuntimeOptions &options) { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /lib/VM/CodeBlock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/CodeBlock.h" 9 | -------------------------------------------------------------------------------- /lib/VM/CodeDataAccessor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/CodeDataAccessor.h" 9 | 10 | using namespace cobra; 11 | 12 | uint32_t CexFile::Header::getVersion() const { 13 | const char* version = reinterpret_cast(&magic_[kMagicSize]); 14 | return atoi(version); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /lib/VM/Field.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/Field.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | -------------------------------------------------------------------------------- /lib/VM/FreeList.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/FreeList.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | -------------------------------------------------------------------------------- /lib/VM/GC.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/GC.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | void GC::writeBarrier(const Object *obj, const Object *value) { 14 | HeapRegion::getCardTable(obj)->markCard(obj); 15 | } 16 | -------------------------------------------------------------------------------- /lib/VM/GCCell.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/GCCell.h" 9 | -------------------------------------------------------------------------------- /lib/VM/GCPointer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/GCPointer.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | template 14 | inline uintptr_t ObjPtr::encode(T *ptr) { 15 | uintptr_t ref = reinterpret_cast(ptr); 16 | return ref; 17 | } 18 | 19 | template 20 | template > */> 22 | inline ObjPtr::ObjPtr(Type *ptr) 23 | : reference_(encode(static_cast(ptr))) { 24 | } 25 | 26 | template 27 | template > */> 29 | inline ObjPtr::ObjPtr(const ObjPtr &other) 30 | : reference_(other.reference_) {} 31 | 32 | template 33 | template > */> 35 | inline ObjPtr &ObjPtr::operator=(const ObjPtr &other) { 36 | reference_ = other.reference_; 37 | return *this; 38 | } 39 | 40 | template 41 | inline ObjPtr &ObjPtr::operator=(T *ptr) { 42 | reference_ = encode(ptr); 43 | return *this; 44 | } 45 | 46 | template 47 | inline T *ObjPtr::operator->() const { 48 | return ptr(); 49 | } 50 | 51 | template 52 | template 53 | inline ObjPtr ObjPtr::downCast(ObjPtr ptr) { 54 | static_assert(std::is_base_of_v, 55 | "Target type must be a subtype of source type"); 56 | return static_cast(ptr.ptr()); 57 | } 58 | 59 | template 60 | template 61 | inline ObjPtr ObjPtr::downCast(SourceType *ptr) { 62 | static_assert(std::is_base_of_v, 63 | "Target type must be a subtype of source type"); 64 | return static_cast(ptr); 65 | } 66 | 67 | template 68 | inline uint32_t PtrCompression::compress(ObjPtr ptr) { 69 | return compress(ptr.ptr()); 70 | } 71 | 72 | template 73 | inline void ObjectReference::assign(ObjPtr ptr) { 74 | assign(ptr.ptr()); 75 | } 76 | 77 | template 78 | inline void HeapReference::assign(ObjPtr ptr) { 79 | assign(ptr.ptr()); 80 | } 81 | -------------------------------------------------------------------------------- /lib/VM/GCRoot.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/GCRoot.h" 9 | -------------------------------------------------------------------------------- /lib/VM/Handle.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/Handle.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | ObjPtr HandleScope::getReference(size_t i) const { 14 | return getReferences()[i].getPtr(); 15 | } 16 | 17 | template 18 | Handle HandleScope::getHandle(size_t i) { 19 | return Handle(&getReferences()[i]); 20 | } 21 | 22 | template 23 | MutableHandle HandleScope::getMutableHandle(size_t i) { 24 | return MutableHandle(&getReferences()[i]); 25 | } 26 | 27 | void HandleScope::setReference(size_t i, ObjPtr object) { 28 | getReferences()[i].assign(object); 29 | } 30 | 31 | template 32 | Handle HandleScope::makeHandle(T *object) { 33 | return makeHandle(ObjPtr(object)); 34 | } 35 | 36 | template 37 | inline MutableHandle HandleScope::makeHandle(ObjPtr object) { 38 | size_t pos = size_; 39 | ++size_; 40 | setReference(pos, object); 41 | Handle h(getHandle(pos)); 42 | return h; 43 | } 44 | 45 | template 46 | MutableHandle HandleScope::makeMutableHandle(T *object) { 47 | return makeMutableHandle(ObjPtr(object)); 48 | } 49 | 50 | template 51 | inline MutableHandle HandleScope::makeMutableHandle(ObjPtr object) { 52 | size_t pos = size_; 53 | ++size_; 54 | setReference(pos, object); 55 | MutableHandle h(getMutableHandle(pos)); 56 | return h; 57 | } 58 | -------------------------------------------------------------------------------- /lib/VM/HeapRegion.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/HeapRegion.h" 9 | #include "cobra/Support/Common.h" 10 | 11 | using namespace cobra; 12 | using namespace vm; 13 | 14 | void HeapRegion::Contents::protectGuardPage(oscompat::ProtectMode mode) { 15 | char *begin = &paddedGuardPage_[kGuardPagePadding]; 16 | size_t size = sizeof(paddedGuardPage_) - kGuardPagePadding; 17 | size_t PS = oscompat::page_size(); 18 | // Only protect if the actual system page size matches expectations. 19 | if (reinterpret_cast(begin) % PS == 0 && PS <= size) { 20 | vm_protect(begin, PS, mode); 21 | } 22 | } 23 | 24 | HeapRegion::HeapRegion(void *allocateBase) : allocateBase_(static_cast(allocateBase)) { 25 | assert( 26 | reinterpret_cast(end()) % oscompat::page_size() == 0 && 27 | "storage end must be page-aligned"); 28 | new (contents()) Contents(); 29 | contents()->protectGuardPage(oscompat::ProtectMode::None); 30 | } 31 | 32 | /// Ref arkcompiler BumpPointerAllocator::Allocate 33 | /// and art RegionSpace::Region::Alloc 34 | /// and hermes AlignedHeapSegment::alloc 35 | void *HeapRegion::alloc(size_t size) { 36 | assert(isSizeHeapAligned(size) && "size must be heap aligned"); 37 | char *oldTop; 38 | char *newTop = top_ + size; 39 | if (COBRA_UNLIKELY(newTop > end())) { 40 | return nullptr; 41 | } 42 | oldTop = top_; 43 | top_ = newTop; 44 | 45 | return reinterpret_cast(oldTop); 46 | } 47 | -------------------------------------------------------------------------------- /lib/VM/HeapRegionSpace.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include 9 | 10 | #include "cobra/VM/HeapRegionSpace.h" 11 | #include "cobra/Support/OSCompat.h" 12 | 13 | using namespace cobra; 14 | using namespace vm; 15 | 16 | bool isAligned(void *p) { 17 | return (reinterpret_cast(p) & (HeapRegion::kSize - 1)) == 0; 18 | } 19 | 20 | char *alignAlloc(void *p) { 21 | return reinterpret_cast( 22 | alignTo(reinterpret_cast(p), HeapRegion::kSize)); 23 | } 24 | 25 | void *getMmapHint() { 26 | uintptr_t addr = std::random_device()(); 27 | if constexpr (sizeof(uintptr_t) >= 8) { 28 | // std::random_device() yields an unsigned int, so combine two. 29 | addr = (addr << 32) | std::random_device()(); 30 | // Don't use the entire address space, to prevent too much fragmentation. 31 | addr &= std::numeric_limits::max() >> 18; 32 | } 33 | return alignAlloc(reinterpret_cast(addr)); 34 | } 35 | 36 | static void *alloc(const char *name) { 37 | auto result = oscompat::vm_allocate_aligned(HeapRegion::kSize, HeapRegion::kSize, getMmapHint()); 38 | if (!result) { 39 | return result; 40 | } 41 | void *mem = result; 42 | assert(isAligned(mem)); 43 | 44 | // Name the memory region on platforms that support naming. 45 | oscompat::vm_name(mem, HeapRegion::kSize, name); 46 | return mem; 47 | } 48 | 49 | HeapRegion *HeapRegionSpace::allocRegion() { 50 | auto addr = alloc("cobra-heapregion"); 51 | return new HeapRegion(addr); 52 | } 53 | -------------------------------------------------------------------------------- /lib/VM/InterfaceTable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/InterfaceTable.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | -------------------------------------------------------------------------------- /lib/VM/Interpreter-inl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #ifndef InterpreterInl_h 9 | #define InterpreterInl_h 10 | 11 | #include "cobra/VM/Interpreter.h" 12 | 13 | namespace cobra { 14 | namespace vm { 15 | 16 | inline double doDiv(double x, double y) { 17 | // UBSan will complain about float divide by zero as our implementation 18 | // of OpCode::Div depends on IEEE 754 float divide by zero. All modern 19 | // compilers implement this and there is no trivial work-around without 20 | // sacrificing performance and readability. 21 | return x / y; 22 | } 23 | 24 | inline double doMod(double x, double y) { 25 | // We use fmod here for simplicity. Theoretically fmod behaves slightly 26 | // differently than the ECMAScript Spec. fmod applies round-towards-zero for 27 | // the remainder when it's not representable by a double; while the spec 28 | // requires round-to-nearest. As an example, 5 % 0.7 will give 29 | // 0.10000000000000031 using fmod, but using the rounding style described by 30 | // the spec, the output should really be 0.10000000000000053. Such difference 31 | // can be ignored in practice. 32 | return std::fmod(x, y); 33 | } 34 | 35 | /// \return the product of x multiplied by y. 36 | inline double doMul(double x, double y) { 37 | return x * y; 38 | } 39 | 40 | /// \return the difference of y subtracted from x. 41 | inline double doSub(double x, double y) { 42 | return x - y; 43 | } 44 | 45 | inline int32_t doBitAnd(int32_t x, int32_t y) { 46 | return x & y; 47 | } 48 | 49 | inline int32_t doBitOr(int32_t x, int32_t y) { 50 | return x | y; 51 | } 52 | 53 | inline int32_t doBitXor(int32_t x, int32_t y) { 54 | return x ^ y; 55 | } 56 | 57 | inline int32_t doLShift(uint32_t x, uint32_t y) { 58 | return x << y; 59 | } 60 | 61 | inline int32_t doRShift(int32_t x, uint32_t y) { 62 | return x >> y; 63 | } 64 | 65 | inline uint32_t doURshift(uint32_t x, uint32_t y) { 66 | return x >> y; 67 | } 68 | 69 | inline double doInc(double d) { 70 | return d + 1; 71 | } 72 | 73 | inline double doDec(double d) { 74 | return d - 1; 75 | } 76 | 77 | 78 | } 79 | } 80 | #endif /* InterpreterInl_h */ 81 | -------------------------------------------------------------------------------- /lib/VM/MemMapAllocator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/MemMapAllocator.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | -------------------------------------------------------------------------------- /lib/VM/Method.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/Method.h" 9 | #include "cobra/VM/Runtime.h" 10 | 11 | using namespace cobra; 12 | using namespace vm; 13 | 14 | class Interpreter; 15 | 16 | void Method::invoke(uint32_t *args, uint32_t argCount) { 17 | auto frame = Runtime::getCurrent()->getCurrentFrame(); 18 | StackFrame *newFrame = StackFrame::create(frame, this, argCount); 19 | if (!isNative()) { 20 | Interpreter::execute(newFrame); 21 | } 22 | 23 | invokeCompiledCode(args, argCount); 24 | } 25 | 26 | void Method::invokeCompiledCode(uint32_t *args, uint32_t argCount) { 27 | auto frame = Runtime::getCurrent()->getCurrentFrame(); 28 | auto newFrame = StackFrame::create(frame, this, argCount); 29 | } 30 | -------------------------------------------------------------------------------- /lib/VM/Object.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/Object.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | -------------------------------------------------------------------------------- /lib/VM/ObjectAccessor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/ObjectAccessor.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | template 14 | Object *ObjectAccessor::getObject(const void *obj, size_t offset) { 15 | return get(obj, offset); 16 | } 17 | 18 | template 19 | void ObjectAccessor::setObject(void *obj, size_t offset, Object *value) { 20 | if (needWriterBarrier) { 21 | // TODO: record obj to BarrierSet 22 | } 23 | 24 | set(obj, offset, value); 25 | } 26 | -------------------------------------------------------------------------------- /lib/VM/Offset.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include 9 | #include "cobra/VM/Offset.h" 10 | 11 | using namespace cobra; 12 | using namespace vm; 13 | 14 | std::ostream& operator<<(std::ostream& os, const Offset& offs) { 15 | return os << offs.int32Value(); 16 | } 17 | -------------------------------------------------------------------------------- /lib/VM/Operations.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/Operations.h" 9 | 10 | namespace cobra { 11 | namespace vm { 12 | 13 | bool strictEqualityTest(CBValue x, CBValue y) { 14 | // Numbers are special because they can have different tags and they don't 15 | // obey bit-exact equality (because of NaN). 16 | if (x.isNumber()) 17 | return y.isNumber() && x.getNumber() == y.getNumber(); 18 | // If they are not numbers and are bit exact, they must be the same. 19 | if (x.getRaw() == y.getRaw()) 20 | return true; 21 | // All the rest of the cases need to have the same tags. 22 | if (x.getTag() != y.getTag()) 23 | return false; 24 | // Strings need deep comparison. 25 | 26 | // TODO 27 | 28 | return false; 29 | } 30 | 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /lib/VM/Primitive.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/Primitive.h" 9 | -------------------------------------------------------------------------------- /lib/VM/Runtime.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/Runtime.h" 9 | #include "cobra/VM/GCPointer.h" 10 | 11 | using namespace cobra; 12 | using namespace vm; 13 | 14 | Runtime *Runtime::instance_ = nullptr; 15 | 16 | Runtime::Runtime() { 17 | 18 | } 19 | 20 | Runtime::~Runtime() { 21 | 22 | } 23 | 24 | bool Runtime::create(const RuntimeOptions &options) { 25 | if (instance_ != nullptr) { 26 | return false; 27 | } 28 | instance_ = new Runtime; 29 | if (!instance_->init(std::move(options))) { 30 | instance_ = nullptr; 31 | return false; 32 | } 33 | return true; 34 | } 35 | 36 | bool Runtime::destroy() { 37 | if (instance_ == nullptr) { 38 | return false; 39 | } 40 | 41 | return true; 42 | } 43 | 44 | Runtime *Runtime::getCurrent() { 45 | return instance_; 46 | } 47 | 48 | inline HandleScope *Runtime::getTopScope() { 49 | return topScope_; 50 | } 51 | 52 | bool Runtime::runBytecode(std::shared_ptr &&bytecode) { 53 | // return Interpreter::interpretFunction(code); 54 | 55 | return true; 56 | } 57 | 58 | bool Runtime::init(const RuntimeOptions &options) { 59 | 60 | } 61 | -------------------------------------------------------------------------------- /lib/VM/RuntimeModule.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/RuntimeModule.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | -------------------------------------------------------------------------------- /lib/VM/RuntimeOptions.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/RuntimeOptions.h" 9 | 10 | using namespace cobra; 11 | 12 | bool RuntimeOptions::create(const RuntimeRawOptions& rawOptions) { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /lib/VM/StackFrame.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/StackFrame.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | -------------------------------------------------------------------------------- /lib/VM/String.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include "cobra/VM/String.h" 9 | 10 | using namespace cobra; 11 | using namespace vm; 12 | 13 | template 14 | int32_t computeUtf16Hash(const MemoryType* chars, size_t char_count) { 15 | static_assert(std::is_same_v || 16 | std::is_same_v || 17 | std::is_same_v); 18 | using UnsignedMemoryType = std::make_unsigned_t; 19 | uint32_t hash = 0; 20 | while (char_count--) { 21 | hash = hash * 31 + static_cast(*chars++); 22 | } 23 | return static_cast(hash); 24 | } 25 | 26 | uint32_t String::computeHashCode() { 27 | uint32_t hash = isCompressed() 28 | ? computeUtf16Hash(getDataCompressed(), getLength()) 29 | : computeUtf16Hash(getData(), getLength()); 30 | return hash; 31 | } 32 | 33 | bool String::equals(String* that) { 34 | if (this == that) { 35 | return true; 36 | } else if (that == nullptr) { 37 | return false; 38 | } else if (this->getLength() != that->getLength()) { 39 | return false; 40 | } else { 41 | if (this->isCompressed()) { 42 | return memcmp(this->getDataCompressed(), that->getDataCompressed(), this->getLength()) == 0; 43 | } else { 44 | return memcmp(this->getData(), that->getData(), sizeof(uint16_t) * this->getLength()) == 0; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/fibonacci.co: -------------------------------------------------------------------------------- 1 | function printParity(x: number) : number { 2 | var y = 100; 3 | var s; 4 | if (x % 2 == 0) { 5 | s = y + 1; 6 | } else { 7 | s = y + 2; 8 | } 9 | return s; 10 | } 11 | -------------------------------------------------------------------------------- /test/num.co: -------------------------------------------------------------------------------- 1 | var a : number = 1, b : number = 2; 2 | var c = (a + b) * 2 + a * b; 3 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the Cobra project authors. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | add_subdirectory(cobra) 7 | -------------------------------------------------------------------------------- /tools/cobra/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) the Cobra project authors. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | find_library(LIBREADLINE_FOUND readline) 7 | find_library(LIBTINFO_FOUND tinfo) 8 | 9 | if(LIBREADLINE_FOUND) 10 | set(LIBREADLINE ${LIBREADLINE_FOUND}) 11 | endif() 12 | if(LIBTINFO_FOUND) 13 | list(APPEND LIBREADLINE ${LIBTINFO_FOUND}) 14 | endif() 15 | set(CMAKE_REQUIRED_LIBRARIES ${LIBREADLINE}) 16 | 17 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 18 | 19 | add_cobra_tool(cobra 20 | cobra.cpp 21 | ${ALL_HEADER_FILES} 22 | ) 23 | 24 | if(HAVE_LIBREADLINE) 25 | target_compile_definitions(cobra PRIVATE HAVE_LIBREADLINE) 26 | set_target_properties(cobra PROPERTIES UNITY_BUILD false) 27 | endif() 28 | 29 | target_link_libraries(cobra 30 | cobraAST 31 | cobraParser 32 | cobraFrontend 33 | cobraBackend 34 | cobraOptimizer 35 | cobraSupport 36 | cobraDriver 37 | ${LIBREADLINE} 38 | ) 39 | 40 | install(TARGETS cobra 41 | RUNTIME DESTINATION bin 42 | ) 43 | -------------------------------------------------------------------------------- /tools/cobra/cobra.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) the Cobra project authors. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "cobra/VM/CobraVM.h" 12 | #include "cobra/Driver/Driver.h" 13 | #include "cobra/Support/BitSet.h" 14 | 15 | #include "cobra/Support/OSCompat.h" 16 | 17 | using namespace cobra; 18 | using namespace driver; 19 | 20 | static std::string loadFile(std::string path) { 21 | std::ifstream file{path}; 22 | 23 | std::string source{std::istreambuf_iterator(file), std::istreambuf_iterator()}; 24 | 25 | return source; 26 | } 27 | 28 | int main(int argc, const char * argv[]) { 29 | 30 | std::string source = loadFile(argv[1]); 31 | driver::compile(source); 32 | 33 | // auto to = cbLexer.advance(); 34 | // 35 | // while (to->getKind() != parser::TokenKind::eof) { 36 | // to = cbLexer.advance(); 37 | // } 38 | 39 | return 0; 40 | } 41 | --------------------------------------------------------------------------------