Commit 97c9f61db4

Andrew Kelley <superjoe30@gmail.com>
2018-09-05 06:34:46
start creating a hash of input parameters
See #1416
1 parent 2d4b959
src/all_types.hpp
@@ -1543,23 +1543,17 @@ struct LinkLib {
     bool provided_explicitly;
 };
 
+// When adding fields, check if they should be added to the hash computation in build_with_cache
 struct CodeGen {
+    //////////////////////////// Runtime State
     LLVMModuleRef module;
     ZigList<ErrorMsg*> errors;
     LLVMBuilderRef builder;
     ZigLLVMDIBuilder *dbuilder;
     ZigLLVMDICompileUnit *compile_unit;
     ZigLLVMDIFile *compile_unit_file;
-
-    ZigList<LinkLib *> link_libs_list;
     LinkLib *libc_link_lib;
 
-    // add -framework [name] args to linker
-    ZigList<Buf *> darwin_frameworks;
-    // add -rpath [name] args to linker
-    ZigList<Buf *> rpath_list;
-
-
     // reminder: hash tables must be initialized before use
     HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
     HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
@@ -1575,7 +1569,6 @@ struct CodeGen {
     HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
     HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
 
-
     ZigList<ImportTableEntry *> import_queue;
     size_t import_queue_index;
     ZigList<Tld *> resolve_queue;
@@ -1620,7 +1613,20 @@ struct CodeGen {
         ZigType *entry_promise;
     } builtin_types;
 
+    //////////////////////////// Participates in Input Parameter Cache Hash
+    ZigList<LinkLib *> link_libs_list;
+    // add -framework [name] args to linker
+    ZigList<Buf *> darwin_frameworks;
+    // add -rpath [name] args to linker
+    ZigList<Buf *> rpath_list;
+
     EmitFileType emit_file_type;
+    BuildMode build_mode;
+    OutType out_type;
+
+
+    //////////////////////////// Unsorted
+
     ZigTarget zig_target;
     LLVMTargetDataRef target_data_ref;
     unsigned pointer_size_bytes;
@@ -1647,7 +1653,6 @@ struct CodeGen {
     Buf *ar_path;
     ZigWindowsSDK *win_sdk;
     Buf triple_str;
-    BuildMode build_mode;
     bool is_test_build;
     bool have_err_ret_tracing;
     uint32_t target_os_index;
@@ -1657,13 +1662,13 @@ struct CodeGen {
     LLVMTargetMachineRef target_machine;
     ZigLLVMDIFile *dummy_di_file;
     bool is_native_target;
-    PackageTableEntry *root_package;
+    PackageTableEntry *root_package; // participates in cache hash
     PackageTableEntry *std_package;
     PackageTableEntry *panic_package;
     PackageTableEntry *test_runner_package;
     PackageTableEntry *compile_var_package;
     ImportTableEntry *compile_var_import;
-    Buf *root_out_name;
+    Buf *root_out_name; // participates in cache hash
     bool windows_subsystem_windows;
     bool windows_subsystem_console;
     Buf *mmacosx_version_min;
@@ -1676,7 +1681,6 @@ struct CodeGen {
     size_t fn_defs_index;
     ZigList<TldVar *> global_vars;
 
-    OutType out_type;
     ZigFn *cur_fn;
     ZigFn *main_fn;
     ZigFn *panic_fn;
src/codegen.cpp
@@ -19,6 +19,7 @@
 #include "target.hpp"
 #include "util.hpp"
 #include "zig_llvm.h"
+#include "blake2.h"
 
 #include <stdio.h>
 #include <errno.h>
@@ -183,10 +184,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
     return g;
 }
 
-void codegen_destroy(CodeGen *codegen) {
-    LLVMDisposeTargetMachine(codegen->target_machine);
-}
-
 void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {
     g->out_h_path = h_path;
 }
@@ -7112,23 +7109,30 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
     g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig");
 }
 
-static void gen_root_source(CodeGen *g) {
+static Buf *get_resolved_root_src_path(CodeGen *g) {
+    // TODO memoize
     if (buf_len(&g->root_package->root_src_path) == 0)
-        return;
-
-    codegen_add_time_event(g, "Semantic Analysis");
+        return nullptr;
 
-    Buf *rel_full_path = buf_alloc();
-    os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, rel_full_path);
+    Buf rel_full_path = BUF_INIT;
+    os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, &rel_full_path);
 
     Buf *resolved_path = buf_alloc();
-    Buf *resolve_paths[] = {rel_full_path};
+    Buf *resolve_paths[] = {&rel_full_path};
     *resolved_path = os_path_resolve(resolve_paths, 1);
 
+    return resolved_path;
+}
+
+static void gen_root_source(CodeGen *g) {
+    Buf *resolved_path = get_resolved_root_src_path(g);
+    if (resolved_path == nullptr)
+        return;
+
     Buf *source_code = buf_alloc();
     int err;
-    if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
-        fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(rel_full_path), err_str(err));
+    if ((err = os_fetch_file_path(resolved_path, source_code, true))) {
+        fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(resolved_path), err_str(err));
         exit(1);
     }
 
@@ -7671,10 +7675,155 @@ void codegen_add_time_event(CodeGen *g, const char *name) {
     g->timing_events.append({os_get_time(), name});
 }
 
+static void add_cache_str(blake2b_state *blake, const char *ptr) {
+    assert(ptr != nullptr);
+    // + 1 to include the null byte
+    blake2b_update(blake, ptr, strlen(ptr) + 1);
+}
+
+static void add_cache_int(blake2b_state *blake, int x) {
+    // + 1 to include the null byte
+    uint8_t buf[sizeof(int) + 1];
+    memcpy(buf, &x, sizeof(int));
+    buf[sizeof(int)] = 0;
+    blake2b_update(blake, buf, sizeof(int) + 1);
+}
+
+static void add_cache_buf(blake2b_state *blake, Buf *buf) {
+    assert(buf != nullptr);
+    // + 1 to include the null byte
+    blake2b_update(blake, buf_ptr(buf), buf_len(buf) + 1);
+}
+
+static void add_cache_buf_opt(blake2b_state *blake, Buf *buf) {
+    if (buf == nullptr) {
+        add_cache_str(blake, "");
+        add_cache_str(blake, "");
+    } else {
+        add_cache_buf(blake, buf);
+    }
+}
+
+static void add_cache_list_of_link_lib(blake2b_state *blake, LinkLib **ptr, size_t len) {
+    for (size_t i = 0; i < len; i += 1) {
+        LinkLib *lib = ptr[i];
+        if (lib->provided_explicitly) {
+            add_cache_buf(blake, lib->name);
+        }
+    }
+    add_cache_str(blake, "");
+}
+
+static void add_cache_list_of_buf(blake2b_state *blake, Buf **ptr, size_t len) {
+    for (size_t i = 0; i < len; i += 1) {
+        Buf *buf = ptr[i];
+        add_cache_buf(blake, buf);
+    }
+    add_cache_str(blake, "");
+}
+
+//static void add_cache_file(CodeGen *g, blake2b_state *blake, Buf *resolved_path) {
+//    assert(file_name != nullptr);
+//    g->cache_files.append(resolved_path);
+//}
+//
+//static void add_cache_file_opt(CodeGen *g, blake2b_state *blake, Buf *resolved_path) {
+//    if (resolved_path == nullptr) {
+//        add_cache_str(blake, "");
+//        add_cache_str(blake, "");
+//    } else {
+//        add_cache_file(g, blake, resolved_path);
+//    }
+//}
+
+// Ported from std/base64.zig
+static uint8_t base64_fs_alphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
+static void base64_encode(Slice<uint8_t> dest, Slice<uint8_t> source) {
+    size_t dest_len = ((source.len + 2) / 3) * 4;
+    assert(dest.len == dest_len);
+
+    size_t i = 0;
+    size_t out_index = 0;
+    for (; i + 2 < source.len; i += 3) {
+        dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] >> 2) & 0x3f];
+        out_index += 1;
+
+        dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i] & 0x3) << 4) | ((source.ptr[i + 1] & 0xf0) >> 4)];
+        out_index += 1;
+
+        dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i + 1] & 0xf) << 2) | ((source.ptr[i + 2] & 0xc0) >> 6)];
+        out_index += 1;
+
+        dest.ptr[out_index] = base64_fs_alphabet[source.ptr[i + 2] & 0x3f];
+        out_index += 1;
+    }
+
+    // Assert that we never need pad characters.
+    assert(i == source.len);
+    //if (i < source.len) {
+    //    dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] >> 2) & 0x3f];
+    //    out_index += 1;
+
+    //    if (i + 1 == source.len) {
+    //        dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i] & 0x3) << 4];
+    //        out_index += 1;
+
+    //        dest.ptr[out_index] = encoder.pad_char;
+    //        out_index += 1;
+    //    } else {
+    //        dest.ptr[out_index] = base64_fs_alphabet[((source.ptr[i] & 0x3) << 4) | ((source.ptr[i + 1] & 0xf0) >> 4)];
+    //        out_index += 1;
+
+    //        dest.ptr[out_index] = base64_fs_alphabet[(source.ptr[i + 1] & 0xf) << 2];
+    //        out_index += 1;
+    //    }
+
+    //    dest.ptr[out_index] = encoder.pad_char;
+    //    out_index += 1;
+    //}
+}
+
+// Called before init()
+static bool build_with_cache(CodeGen *g) {
+    blake2b_state blake;
+    int rc = blake2b_init(&blake, 48);
+    assert(rc == 0);
+
+    // TODO zig exe & dynamic libraries
+
+    add_cache_buf(&blake, g->root_out_name);
+    add_cache_buf_opt(&blake, get_resolved_root_src_path(g)); // Root source file
+    add_cache_list_of_link_lib(&blake, g->link_libs_list.items, g->link_libs_list.length);
+    add_cache_list_of_buf(&blake, g->darwin_frameworks.items, g->darwin_frameworks.length);
+    add_cache_list_of_buf(&blake, g->rpath_list.items, g->rpath_list.length);
+    add_cache_int(&blake, g->emit_file_type);
+    add_cache_int(&blake, g->build_mode);
+    add_cache_int(&blake, g->out_type);
+    // TODO the rest of the struct CodeGen fields
+
+    uint8_t bin_digest[48];
+    rc = blake2b_final(&blake, bin_digest, 48);
+    assert(rc == 0);
+
+    Buf b64_digest = BUF_INIT;
+    buf_resize(&b64_digest, 64);
+    base64_encode(buf_to_slice(&b64_digest), {bin_digest, 48});
+
+    fprintf(stderr, "input params hash: %s\n", buf_ptr(&b64_digest));
+    // TODO next look for a manifest file that has all the files from the input parameters
+    // use that to construct the real hash, which looks up the output directory and another manifest file
+
+    return false;
+}
+
 void codegen_build(CodeGen *g) {
     assert(g->out_type != OutTypeUnknown);
+    if (build_with_cache(g))
+        return;
     init(g);
 
+    codegen_add_time_event(g, "Semantic Analysis");
+
     gen_global_asm(g);
     gen_root_source(g);
     do_code_gen(g);
src/codegen.hpp
@@ -16,7 +16,6 @@
 
 CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
     Buf *zig_lib_dir);
-void codegen_destroy(CodeGen *codegen);
 
 void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
 void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
src/link.cpp
@@ -69,8 +69,6 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path)
     os_path_join(&parent_gen->cache_dir, o_out_name, output_path);
     codegen_link(child_gen, buf_ptr(output_path));
 
-    codegen_destroy(child_gen);
-
     return output_path;
 }
 
src/main.cpp
@@ -461,7 +461,6 @@ int main(int argc, char **argv) {
         g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
         codegen_build(g);
         codegen_link(g, buf_ptr(path_to_build_exe));
-        codegen_destroy(g);
 
         Termination term;
         os_spawn_process(buf_ptr(path_to_build_exe), args, &term);