1 /// Copyright: Copyright (c) 2017-2020 Andrey Penechko. 2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 3 /// Authors: Andrey Penechko. 4 module vox.driver; 5 6 import std.stdio : writeln, write, writef, writefln, stdout; 7 import std.path : baseName, stripExtension; 8 9 import vox.all; 10 11 /// To compile a set of modules do following steps: 12 /// 1. initialize(passes) 13 /// 2. beginCompilation() 14 /// 3. addHostSymbols(hostSymbols) --+ 15 /// foreach(module; modules) | In any order 16 /// 4. addModule(module) ------------+ 17 /// 5. compile() 18 /// 6. markCodeAsExecutable() if in JIT mode 19 /// 7. releaseMemory() 20 struct Driver 21 { 22 CompilationContext context; 23 CompilePassGlobal[] passes; 24 25 ArenaPool arenaPool; 26 27 static void funWithAddress(){} 28 void initialize(CompilePassGlobal[] passes_) 29 { 30 passes = passes_; 31 32 // IrIndex can address 2^28 * 4 bytes = 1GB 33 size_t BYTES_TO_RESERVE = GiB*186; 34 arenaPool.reserve(BYTES_TO_RESERVE); 35 //writefln("arenaPool %X .. %X", arenaPool.buffer.ptr, arenaPool.buffer.ptr+arenaPool.buffer.length); 36 37 /// Those 3 must be allocated in this order (or in inverse order) 38 /// Code must be able to use RIP-relative addressing into static data (and into import data when in JIT mode) 39 context.importBuffer.setBuffer(arenaPool.take(GiB), 0); 40 context.codeBuffer.setBuffer(arenaPool.take(GiB), 0); 41 context.staticDataBuffer.setBuffer(arenaPool.take(GiB/2), 0); 42 context.roStaticDataBuffer.setBuffer(arenaPool.take(GiB/2), 0); 43 44 context.sourceBuffer.setBuffer(arenaPool.take(GiB), 0); 45 context.files.setBuffer(arenaPool.take(GiB), 0); 46 context.tokenBuffer.setBuffer(arenaPool.take(GiB), 0); 47 context.tokenLocationBuffer.setBuffer(arenaPool.take(GiB), 0); 48 context.binaryBuffer.setBuffer(arenaPool.take(GiB), 0); 49 context.bundleBuffer.setBuffer(arenaPool.take(GiB), 0); 50 51 context.irStorage.instrHeaderBuffer.setBuffer(arenaPool.take(8*GiB), 0); 52 context.irStorage.instrPayloadBuffer.setBuffer(arenaPool.take(8*GiB), 0); 53 context.irStorage.instrNextBuffer.setBuffer(arenaPool.take(8*GiB), 0); 54 context.irStorage.instrPrevBuffer.setBuffer(arenaPool.take(8*GiB), 0); 55 context.irStorage.vregBuffer.setBuffer(arenaPool.take(8*GiB), 0); 56 context.irStorage.phiBuffer.setBuffer(arenaPool.take(8*GiB), 0); 57 context.irStorage.basicBlockBuffer.setBuffer(arenaPool.take(8*GiB), 0); 58 context.irStorage.arrayBuffer.setBuffer(arenaPool.take(8*GiB), 0); 59 context.irStorage.stackSlotBuffer.setBuffer(arenaPool.take(8*GiB), 0); 60 61 context.types.buffer.setBuffer(arenaPool.take(GiB), 0); 62 context.tempBuffer.setBuffer(arenaPool.take(8*GiB), 0); 63 context.vmBuffer.setBuffer(arenaPool.take(4*GiB), 0); 64 context.objSymTab.buffer.setBuffer(arenaPool.take(GiB), 0); 65 context.globals.buffer.setBuffer(arenaPool.take(GiB), 0); 66 context.globals.initializerBuffer.setBuffer(arenaPool.take(GiB), 0); 67 context.constants.buffer.setBuffer(arenaPool.take(GiB), 0); 68 context.constants.aggregateBuffer.setBuffer(arenaPool.take(4*GiB), 0); 69 context.astBuffer.setBuffer(arenaPool.take(16*GiB), 0); 70 context.arrayArena.setBuffers( 71 arenaPool.take(12*4*GiB), 72 arenaPool.take(16*GiB)); 73 74 context.idMap.entries.setBuffer(arenaPool.take(2*GiB), 0); 75 context.idMap.stringDataBuffer.setBuffer(arenaPool.take(2*GiB), 0); 76 77 // all arena sizes must sum up to predefined constant 78 context.assertf(arenaPool.takenBytes == BYTES_TO_RESERVE, 79 "%s bytes taken, %s bytes to take", arenaPool.takenBytes, BYTES_TO_RESERVE); 80 81 context.initialize(); 82 } 83 84 void releaseMemory() 85 { 86 arenaPool.decommitAll; 87 } 88 89 void beginCompilation() 90 { 91 markAsRW(context.codeBuffer.bufPtr, divCeil(context.codeBuffer.length, PAGE_SIZE)); 92 markAsRW(context.roStaticDataBuffer.bufPtr, divCeil(context.roStaticDataBuffer.length, PAGE_SIZE)); 93 context.beginCompilation; 94 foreach(ref pass; passes) pass.clear; 95 } 96 97 void addModule(SourceFileInfo moduleFile) 98 { 99 uint fileIndex = cast(uint)context.files.length; 100 context.files.put(moduleFile); 101 SourceFileInfo* file = &context.files.back(); 102 103 Identifier id = context.idMap.getOrReg(&context, file.name.baseName.stripExtension); 104 ObjectModule localModule = { 105 kind : ObjectModuleKind.isLocal, 106 id : id 107 }; 108 auto mod = context.appendAst!ModuleDeclNode(); 109 file.mod = context.getAst!ModuleDeclNode(mod); 110 file.mod.moduleIndex = ModuleIndex(fileIndex); 111 file.mod.fqn = id; 112 file.mod.objectSymIndex = context.objSymTab.addModule(localModule); 113 } 114 115 void addHar(string harFilename, const(char)[] harData) 116 { 117 void onHarFile(SourceFileInfo fileInfo) { 118 addModule(fileInfo); 119 } 120 parseHar(context, harFilename, harData, &onHarFile); 121 } 122 123 void compile() 124 { 125 foreach (ref pass; passes) 126 { 127 auto time1 = currTime; 128 129 // throws immediately on unrecoverable error or ICE 130 pass.run(context, pass.subPasses); 131 132 auto time2 = currTime; 133 pass.duration = time2-time1; 134 135 // throws if there were recoverable error in the pass 136 context.throwOnErrors; 137 } 138 } 139 140 /// Must be called after compilation is finished and before execution 141 /// Effect is reverted with the call to beginCompilation 142 /// Marks code pages as read-execute, and readonly data pages as read-only 143 /// Clears zero-initialized data 144 /// Only needed in JIT mode, not needed in AOT mode 145 void markCodeAsExecutable() 146 { 147 markAsExecutable(context.codeBuffer.bufPtr, divCeil(context.codeBuffer.length, PAGE_SIZE)); 148 markAsRO(context.roStaticDataBuffer.bufPtr, divCeil(context.roStaticDataBuffer.length, PAGE_SIZE)); 149 // we cannot have a separate section for zeroinitialized data (would require 2 smaller arenas) 150 // because it needs to occupy the same GiB as initialized data 151 // to be RIP addressable in JIT mode 152 context.staticDataBuffer.voidPut(context.zeroDataLength)[] = 0; // zero initialize 153 } 154 155 void addHostSymbols(HostSymbol[] hostSymbols) 156 { 157 if (hostSymbols.length > 0) 158 context.assertf(context.buildType == BuildType.jit, "Can only add host symbols in JIT mode"); 159 160 LinkIndex hostModuleIndex = context.getOrCreateExternalModule(CommonIds.id_host, ObjectModuleKind.isHost); 161 162 foreach (HostSymbol hostSym; hostSymbols) 163 { 164 Identifier symId = context.idMap.getOrReg(&context, hostSym.symName); 165 context.addHostSymbol(hostModuleIndex, symId, hostSym.ptr); 166 } 167 } 168 }