From 61468d818f7346548e7156f6165914336014bb03 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 23 Mar 2020 12:07:05 -0700 Subject: [PATCH] Added MD5 file hashes to Beef --- BeefySysLib/util/Hash.cpp | 307 ++++++++++++++++++++++++ BeefySysLib/util/Hash.h | 3 +- IDE/mintest/minlib/src/System/Object.bf | 2 +- IDE/src/Compiler/BfCompiler.bf | 14 +- IDE/src/Compiler/BfParser.bf | 10 + IDE/src/Compiler/BfResolveHelper.bf | 2 +- IDE/src/Compiler/CompilerBase.bf | 6 +- IDE/src/Debugger/DebugManager.bf | 4 +- IDE/src/FileEditData.bf | 2 + IDE/src/IDEApp.bf | 52 +++- IDE/src/TestManager.bf | 2 +- IDE/src/ui/DisassemblyPanel.bf | 2 +- IDE/src/ui/FindResultsPanel.bf | 2 +- IDE/src/ui/LaunchDialog.bf | 2 +- IDE/src/ui/ProjectPanel.bf | 2 +- IDE/src/ui/RenameSymbolDialog.bf | 2 +- IDE/src/ui/SourceEditWidgetContent.bf | 1 + IDE/src/ui/SourceViewPanel.bf | 77 ------ IDE/src/util/GlobalUndoManager.bf | 4 +- IDE/src/util/SourceHash.bf | 92 +++++++ IDEHelper/Backend/BeCOFFObject.cpp | 31 ++- IDEHelper/Backend/BeIRCodeGen.cpp | 11 +- IDEHelper/Backend/BeIRCodeGen.h | 1 + IDEHelper/Backend/BeModule.cpp | 32 +++ IDEHelper/Backend/BeModule.h | 34 +-- IDEHelper/Compiler/BfDefBuilder.cpp | 3 + IDEHelper/Compiler/BfIRBuilder.cpp | 10 +- IDEHelper/Compiler/BfIRBuilder.h | 4 +- IDEHelper/Compiler/BfIRCodeGen.cpp | 17 +- IDEHelper/Compiler/BfIRCodeGen.h | 1 + IDEHelper/Compiler/BfModule.cpp | 2 +- IDEHelper/Compiler/BfParser.cpp | 6 + IDEHelper/Compiler/BfParser.h | 1 + 33 files changed, 598 insertions(+), 143 deletions(-) create mode 100644 IDE/src/util/SourceHash.bf diff --git a/BeefySysLib/util/Hash.cpp b/BeefySysLib/util/Hash.cpp index c5b97293..ec3b72a8 100644 --- a/BeefySysLib/util/Hash.cpp +++ b/BeefySysLib/util/Hash.cpp @@ -1267,6 +1267,301 @@ void MurmurHash3_x64_128(const void * key, const int len, ((uint64_t*) out)[1] = h2; } +////////////////////////////////////////////////////////////////////////// + +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + + /* Any 32-bit or wider unsigned integer data type will do */ +typedef unsigned int MD5_u32plus; + +typedef struct { + MD5_u32plus lo, hi; + MD5_u32plus a, b, c, d; + unsigned char buffer[64]; + MD5_u32plus block[16]; +} MD5_CTX; + + /* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + + /* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + + /* + * SET reads 4 input bytes in little-endian byte order and stores them in a + * properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned memory + * accesses is just an optimization. Nothing will break if it fails to detect + * a suitable architecture. + * + * Unfortunately, this optimization may be a C strict aliasing rules violation + * if the caller's data buffer has effective type that cannot be aliased by + * MD5_u32plus. In practice, this problem may occur if these MD5 routines are + * inlined into a calling function, or with future and dangerously advanced + * link-time optimizations. For the time being, keeping these MD5 routines in + * their own translation unit avoids the problem. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) \ + (*(MD5_u32plus *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = \ + (MD5_u32plus)ptr[(n) * 4] | \ + ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \ + ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \ + ((MD5_u32plus)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (ctx->block[(n)]) +#endif + + /* + * This processes one or more 64-byte data blocks, but does NOT update the bit + * counters. There are no alignment requirements. + */ +static const void *body(MD5_CTX *ctx, const void *data, unsigned long size) +{ + const unsigned char *ptr; + MD5_u32plus a, b, c, d; + MD5_u32plus saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + + /* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + + /* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + + /* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) + + /* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +void MD5_Init(MD5_CTX *ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) +{ + MD5_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) { + available = 64 - used; + + if (size < available) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } + + if (size >= 64) { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +#define MD5_OUT(dst, src) \ + (dst)[0] = (unsigned char)(src); \ + (dst)[1] = (unsigned char)((src) >> 8); \ + (dst)[2] = (unsigned char)((src) >> 16); \ + (dst)[3] = (unsigned char)((src) >> 24); + +void MD5_Final(unsigned char *result, MD5_CTX *ctx) +{ + unsigned long used, available; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + available = 64 - used; + + if (available < 8) { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + MD5_OUT(&ctx->buffer[56], ctx->lo) + MD5_OUT(&ctx->buffer[60], ctx->hi) + + body(ctx, ctx->buffer, 64); + + MD5_OUT(&result[0], ctx->a) + MD5_OUT(&result[4], ctx->b) + MD5_OUT(&result[8], ctx->c) + MD5_OUT(&result[12], ctx->d) + + memset(ctx, 0, sizeof(*ctx)); +} ////////////////////////////////////////////////////////////////////////// @@ -1312,6 +1607,17 @@ Val128 Beefy::Hash128(const void* data, int length, const Val128& seed) return hashVal; } +Val128 Beefy::HashMD5(const void* data, int length) +{ + Val128 result; + MD5_CTX ctx; + MD5_Init(&ctx); + MD5_Update(&ctx, data, length); + MD5_Final((unsigned char*)&result, &ctx); + return result; +} + + ////////////////////////////////////////////////////////////////////////// // Only 63 chars - skip zero @@ -1503,3 +1809,4 @@ uint64 HashContext::Finish64() mBufSize = 0; return val; } + diff --git a/BeefySysLib/util/Hash.h b/BeefySysLib/util/Hash.h index 5ed4a66c..997c7f1d 100644 --- a/BeefySysLib/util/Hash.h +++ b/BeefySysLib/util/Hash.h @@ -96,6 +96,7 @@ uint64 Hash64(uint64 hash, uint64 seed); uint64 Hash64(const void* data, int length, uint64 seed = 0); Val128 Hash128(const void* data, int length); Val128 Hash128(const void* data, int length, const Val128& seed); +Val128 HashMD5(const void* data, int length); String HashEncode64(uint64 val); // Note: this only encodes the low 60 bits. Returns up to 10 characters. StringT<21> HashEncode128(Val128 val); // Returns up to 20 characters. @@ -138,7 +139,7 @@ public: void MixinStr(const char* str); void MixinStr(const StringImpl& str); Val128 Finish128(); - uint64 Finish64(); + uint64 Finish64(); }; NS_BF_END \ No newline at end of file diff --git a/IDE/mintest/minlib/src/System/Object.bf b/IDE/mintest/minlib/src/System/Object.bf index 9221d8d1..d4d0c880 100644 --- a/IDE/mintest/minlib/src/System/Object.bf +++ b/IDE/mintest/minlib/src/System/Object.bf @@ -92,7 +92,7 @@ namespace System return type; } -#if BF_ALLOW_HOT_SWAPPING +#if BF_DYNAMIC_CAST_CHECK || BF_ENABLE_REALTIME_LEAK_CHECK [NoShow] public virtual Object DynamicCastToTypeId(int32 typeId) { diff --git a/IDE/src/Compiler/BfCompiler.bf b/IDE/src/Compiler/BfCompiler.bf index aacc1f5f..23ddc7c2 100644 --- a/IDE/src/Compiler/BfCompiler.bf +++ b/IDE/src/Compiler/BfCompiler.bf @@ -9,6 +9,7 @@ using Beefy; using Beefy.utils; using IDE.Util; using IDE.ui; +using IDE.util; namespace IDE.Compiler { @@ -373,13 +374,19 @@ namespace IDE.Compiler bfProject = mBfSystem.GetBfProject(projectSource.mProject); } + bool wantsHash = !mIsResolveOnly; + bool canMoveSourceString = true; IdSpan char8IdData = projectSourceCommand.mSourceCharIdData; String data = projectSourceCommand.mSourceString; + SourceHash hash = .None; + if (wantsHash) + hash = projectSourceCommand.mSourceHash; if (char8IdData.IsEmpty) { data = scope:ProjectSourceCommandBlock String(); - if (gApp.LoadTextFile(sourceFilePath, data) case .Err) + + if (gApp.LoadTextFile(sourceFilePath, data, true, scope [&] () => { if (wantsHash) hash = SourceHash.Create(.MD5, data); } ) case .Err) data = null; if (data != null) { @@ -390,6 +397,8 @@ namespace IDE.Compiler using (gApp.mMonitor.Enter()) { editData.SetSavedData(data, char8IdData); + if (hash case .MD5(let md5Hash)) + editData.mMD5Hash = md5Hash; } canMoveSourceString = false; } @@ -419,6 +428,9 @@ namespace IDE.Compiler bfParser.SetSource("", sourceFilePath); bfParser.SetCharIdData(ref char8IdData); + if (hash case .MD5(let md5Hash)) + bfParser.SetHashMD5(md5Hash); + //passInstance.SetProject(bfProject); worked &= bfParser.Parse(passInstance, false); worked &= bfParser.Reduce(passInstance); diff --git a/IDE/src/Compiler/BfParser.bf b/IDE/src/Compiler/BfParser.bf index 32b7e4f7..a1f01378 100644 --- a/IDE/src/Compiler/BfParser.bf +++ b/IDE/src/Compiler/BfParser.bf @@ -9,6 +9,7 @@ using IDE.ui; using System.IO; using System.Threading; using Beefy; +using System.Security.Cryptography; namespace IDE.Compiler { @@ -94,6 +95,9 @@ namespace IDE.Compiler [StdCall, CLink] static extern void BfParser_SetCharIdData(void* bfParser, uint8* data, int32 length); + [StdCall, CLink] + static extern void BfParser_SetHashMD5(void* bfParser, ref MD5Hash md5Hash); + [StdCall, CLink] static extern void BfParser_SetNextRevision(void* bfParser, void* nextParser); @@ -352,5 +356,11 @@ namespace IDE.Compiler { BfParser_SetCompleteParse(mNativeBfParser); } + + public void SetHashMD5(MD5Hash md5Hash) + { + var md5Hash; + BfParser_SetHashMD5(mNativeBfParser, ref md5Hash); + } } } diff --git a/IDE/src/Compiler/BfResolveHelper.bf b/IDE/src/Compiler/BfResolveHelper.bf index 47624977..597542a3 100644 --- a/IDE/src/Compiler/BfResolveHelper.bf +++ b/IDE/src/Compiler/BfResolveHelper.bf @@ -112,7 +112,7 @@ namespace IDE.Compiler projectSource.GetFullImportPath(fullPath); if (Path.Equals(fullPath, entry.mFilePath)) { - app.mBfResolveCompiler.QueueProjectSource(projectSource); + app.mBfResolveCompiler.QueueProjectSource(projectSource, false); needsResolveAll = true; DeferRefreshVisibleViews(entry.mExludeSourceViewPanel); } diff --git a/IDE/src/Compiler/CompilerBase.bf b/IDE/src/Compiler/CompilerBase.bf index b3c48919..1a55947b 100644 --- a/IDE/src/Compiler/CompilerBase.bf +++ b/IDE/src/Compiler/CompilerBase.bf @@ -7,6 +7,7 @@ using System.Diagnostics; using Beefy.utils; using Beefy; using System.IO; +using IDE.util; namespace IDE.Compiler { @@ -36,6 +37,7 @@ namespace IDE.Compiler public ProjectSource mProjectSource; public IdSpan mSourceCharIdData ~ _.Dispose(); public String mSourceString ~ delete _; + public SourceHash mSourceHash; } protected class CompileCommand : Command @@ -55,12 +57,12 @@ namespace IDE.Compiler mResolveAllWait = 2; } - public virtual void QueueProjectSource(ProjectSource projectSource) + public virtual void QueueProjectSource(ProjectSource projectSource, bool wantsHash) { ProjectSourceCommand command = new ProjectSourceCommand(); command.mProjectSource = projectSource; command.mSourceString = new String(); - IDEApp.sApp.FindProjectSourceContent(projectSource, out command.mSourceCharIdData, false, command.mSourceString); + IDEApp.sApp.FindProjectSourceContent(projectSource, out command.mSourceCharIdData, false, command.mSourceString, wantsHash ? &command.mSourceHash : null); if (gApp.mBfBuildCompiler == this) { if (gApp.mDbgVersionedCompileDir != null) diff --git a/IDE/src/Debugger/DebugManager.bf b/IDE/src/Debugger/DebugManager.bf index b8a28b08..e85a228d 100644 --- a/IDE/src/Debugger/DebugManager.bf +++ b/IDE/src/Debugger/DebugManager.bf @@ -349,6 +349,7 @@ namespace IDE.Debugger public String mRunningPath ~ delete _; public bool mIsRunning; public bool mIsRunningCompiled; + public bool mIsRunningWithHotSwap; //public RunState mLastUpdatedRunState; public bool mCallStackDirty; public int32 mActiveCallStackIdx; @@ -400,12 +401,13 @@ namespace IDE.Debugger Debugger_FullReportMemory(); } - public bool OpenFile(String launchPath, String targetPath, String args, String workingDir, Span envBlock, bool isCompiled) + public bool OpenFile(String launchPath, String targetPath, String args, String workingDir, Span envBlock, bool isCompiled, bool hotSwapEnabled) { DeleteAndNullify!(mRunningPath); mRunningPath = new String(launchPath); mIsRunningCompiled = isCompiled; + mIsRunningWithHotSwap = hotSwapEnabled; return Debugger_OpenFile(launchPath, targetPath, args, workingDir, envBlock.Ptr, (int32)envBlock.Length); } diff --git a/IDE/src/FileEditData.bf b/IDE/src/FileEditData.bf index c2a4041b..eadab598 100644 --- a/IDE/src/FileEditData.bf +++ b/IDE/src/FileEditData.bf @@ -4,12 +4,14 @@ using System.IO; using Beefy.utils; using System.Collections.Generic; using System.Security.Cryptography; +using IDE.util; namespace IDE { [AllowDuplicates] public enum LineEndingKind { + Unknown, Lf, // \n CrLf, // \r\n Cr, // \r diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 78ff493b..fa1214be 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -382,6 +382,7 @@ namespace IDE class StartDebugCmd : ExecutionCmd { public bool mWasCompiled; + public bool mHotCompileEnabled; public this() { @@ -1298,6 +1299,8 @@ namespace IDE StringView useText = text; + Debug.Assert(!text.Contains('\r')); + if (lineEndingKind != .Lf) { var str = scope:: String()..Append(text); @@ -6372,6 +6375,8 @@ namespace IDE if ((aliasFilePath != null) && (sourceViewPanel.mAliasFilePath == null)) String.NewOrSet!(sourceViewPanel.mAliasFilePath, aliasFilePath); + + if (sourceViewPanel.mLoadFailed) { sourceViewPanel.mWantHash = hash; @@ -6380,11 +6385,16 @@ namespace IDE sourceViewPanel.SetLoadCmd(loadCmd); } } - else if ((hash != .None) && (sourceViewPanel.mEditData != null) && (!sourceViewPanel.mEditData.CheckHash(hash))) + else if ((gApp.mDebugger.mIsRunningWithHotSwap) && (sourceViewPanel.mIsBeefSource)) + { + // No 'wrong hash' warnings + } + else if (((hash != .None) && (sourceViewPanel.mEditData != null) && (!sourceViewPanel.mEditData.CheckHash(hash))) || + (sourceViewPanel.mHasChangedSinceLastCompile)) { sourceViewPanel.ShowWrongHash(); } - + int showHotIdx = -1; if (!onlyShowCurrent) { @@ -7774,12 +7784,12 @@ namespace IDE return worked; } - public bool FindProjectSourceContent(ProjectSource projectSource, out IdSpan char8IdData, bool loadOnFail, String sourceContent) + public bool FindProjectSourceContent(ProjectSource projectSource, out IdSpan char8IdData, bool loadOnFail, String sourceContent, SourceHash* sourceHash) { char8IdData = IdSpan(); var fullPath = scope String(); projectSource.GetFullImportPath(fullPath); - + //SourceViewPanel sourceViewPanel = null; using (mMonitor.Enter()) @@ -7798,6 +7808,12 @@ namespace IDE { char8IdData = projectSource.mEditData.mEditWidget.mEditWidgetContent.mData.mTextIdData.Duplicate(); projectSource.mEditData.mEditWidget.GetText(sourceContent); + if (sourceHash != null) + { + *sourceHash = SourceHash.Create(.MD5, sourceContent, projectSource.mEditData.mLineEndingKind); + if (*sourceHash case .MD5(let md5Hash)) + projectSource.mEditData.mMD5Hash = md5Hash; + } return true; } } @@ -7806,6 +7822,8 @@ namespace IDE { char8IdData = projectSource.mEditData.mSavedCharIdData.Duplicate(); sourceContent.Set(projectSource.mEditData.mSavedContent); + if ((!projectSource.mEditData.mMD5Hash.IsZero) && (sourceHash != null)) + *sourceHash = .MD5(projectSource.mEditData.mMD5Hash); return true; } } @@ -7815,8 +7833,8 @@ namespace IDE { String text = scope String(); bool isValid = false; - if (LoadTextFile(fullPath, text) case .Ok) - { + if (LoadTextFile(fullPath, text, true, scope [&] () => { if (sourceHash != null) *sourceHash = SourceHash.Create(.MD5, text); } ) case .Ok) + { mFileWatcher.FileIsValid(fullPath); isValid = true; } @@ -7835,6 +7853,11 @@ namespace IDE editData.SetSavedData(null, IdSpan()); editData.mFileDeleted = true; } + if (sourceHash != null) + { + if (*sourceHash case .MD5(let md5Hash)) + editData.mMD5Hash = md5Hash; + } } return isValid; } @@ -7931,7 +7954,7 @@ namespace IDE if (bfCompiler != null) { // Process change in resolve compiler - bfCompiler.QueueProjectSource(projectSource); + bfCompiler.QueueProjectSource(projectSource, !bfCompiler.mIsResolveOnly); } } else // Actual build @@ -7941,7 +7964,7 @@ namespace IDE // mHasChangedSinceLastCompile is safe to set 'false' here since it just determines whether or not // we rebuild the TypeDefs from the sources. It isn't affected by any compilation errors. projectSource.mHasChangedSinceLastCompile = false; - bfCompiler.QueueProjectSource(projectSource); + bfCompiler.QueueProjectSource(projectSource, !bfCompiler.mIsResolveOnly); hadBeef = true; } } @@ -9428,9 +9451,12 @@ namespace IDE if ((runAfter) && (success)) { + var options = GetCurWorkspaceOptions(); + var startDebugCmd = new StartDebugCmd(); startDebugCmd.mWasCompiled = true; startDebugCmd.mOnlyIfNotFailed = true; + startDebugCmd.mHotCompileEnabled = options.mAllowHotSwapping; mExecutionQueue.Add(startDebugCmd); } @@ -9963,7 +9989,7 @@ namespace IDE return false; } - if (!mDebugger.OpenFile(launchPath, targetPath, arguments, workingDir, envBlock, wasCompiled)) + if (!mDebugger.OpenFile(launchPath, targetPath, arguments, workingDir, envBlock, wasCompiled, workspaceOptions.mAllowHotSwapping)) { DeleteAndNullify!(mCompileAndRunStopwatch); return false; @@ -10877,7 +10903,7 @@ namespace IDE return; var resolveCompiler = GetProjectCompilerForFile(projectSource.mPath); if (resolveCompiler == mBfResolveCompiler) - resolveCompiler.QueueProjectSource(projectSource); + resolveCompiler.QueueProjectSource(projectSource, false); projectSource.mHasChangedSinceLastCompile = true; } }); @@ -11773,8 +11799,8 @@ namespace IDE { if (IsBeefFile(newPath)) { - mBfResolveCompiler.QueueProjectSource(projectSource); - mBfBuildCompiler.QueueProjectSource(projectSource); + mBfResolveCompiler.QueueProjectSource(projectSource, false); + mBfBuildCompiler.QueueProjectSource(projectSource, true); } else { @@ -12053,7 +12079,7 @@ namespace IDE { if (mBfResolveCompiler != null) { - mBfResolveCompiler.QueueProjectSource(projectSource); + mBfResolveCompiler.QueueProjectSource(projectSource, false); mBfResolveCompiler.QueueDeferredResolveAll(); mBfResolveCompiler.QueueRefreshViewCommand(); } diff --git a/IDE/src/TestManager.bf b/IDE/src/TestManager.bf index 52d07f64..bc367eb8 100644 --- a/IDE/src/TestManager.bf +++ b/IDE/src/TestManager.bf @@ -477,7 +477,7 @@ namespace IDE var envBlock = scope List(); Environment.EncodeEnvironmentVariables(envVars, envBlock); - if (!gApp.mDebugger.OpenFile(curProjectInfo.mTestExePath, curProjectInfo.mTestExePath, mTestInstance.mArgs, mTestInstance.mWorkingDir, envBlock, true)) + if (!gApp.mDebugger.OpenFile(curProjectInfo.mTestExePath, curProjectInfo.mTestExePath, mTestInstance.mArgs, mTestInstance.mWorkingDir, envBlock, true, false)) { QueueOutputLine("ERROR: Failed debug '{0}'", curProjectInfo.mTestExePath); TestFailed(); diff --git a/IDE/src/ui/DisassemblyPanel.bf b/IDE/src/ui/DisassemblyPanel.bf index fdb5c3de..eea8ed6a 100644 --- a/IDE/src/ui/DisassemblyPanel.bf +++ b/IDE/src/ui/DisassemblyPanel.bf @@ -261,7 +261,7 @@ namespace IDE.ui { IdSpan liveCharIdData; String liveText = scope:: String(); - app.FindProjectSourceContent(projectSource, out liveCharIdData, true, liveText); + app.FindProjectSourceContent(projectSource, out liveCharIdData, true, liveText, null); defer(stack) liveCharIdData.Dispose(); var compileInstance = IDEApp.sApp.mWorkspace.GetProjectSourceCompileInstance(projectSource, mHotIdx); diff --git a/IDE/src/ui/FindResultsPanel.bf b/IDE/src/ui/FindResultsPanel.bf index 1d8f5334..099f89fc 100644 --- a/IDE/src/ui/FindResultsPanel.bf +++ b/IDE/src/ui/FindResultsPanel.bf @@ -708,7 +708,7 @@ namespace IDE.ui if ((IDEApp.IsBeefFile(filePath)) && (gApp.mBfResolveCompiler != null)) { for (var projectSource in editData.mProjectSources) - gApp.mBfResolveCompiler.QueueProjectSource(projectSource); + gApp.mBfResolveCompiler.QueueProjectSource(projectSource, false); gApp.mBfResolveCompiler.QueueDeferredResolveAll(); } diff --git a/IDE/src/ui/LaunchDialog.bf b/IDE/src/ui/LaunchDialog.bf index ac6a1300..c53630db 100644 --- a/IDE/src/ui/LaunchDialog.bf +++ b/IDE/src/ui/LaunchDialog.bf @@ -332,7 +332,7 @@ namespace IDE.ui var envBlock = scope List(); Environment.EncodeEnvironmentVariables(envVars, envBlock); - if (!gApp.mDebugger.OpenFile(targetPath, targetPath, arguments, workingDir, envBlock, false)) + if (!gApp.mDebugger.OpenFile(targetPath, targetPath, arguments, workingDir, envBlock, false, false)) { gApp.Fail(scope String()..AppendF("Unable to open executable for debugging: {0}", targetPath)); return; diff --git a/IDE/src/ui/ProjectPanel.bf b/IDE/src/ui/ProjectPanel.bf index 5c468fc9..97e36744 100644 --- a/IDE/src/ui/ProjectPanel.bf +++ b/IDE/src/ui/ProjectPanel.bf @@ -352,7 +352,7 @@ namespace IDE.ui var resolveCompiler = gApp.GetProjectCompilerForFile(projectSource.mName); if (resolveCompiler != null) { - resolveCompiler.QueueProjectSource(projectSource); + resolveCompiler.QueueProjectSource(projectSource, false); resolveCompiler.QueueDeferredResolveAll(); } projectSource.mHasChangedSinceLastCompile = true; diff --git a/IDE/src/ui/RenameSymbolDialog.bf b/IDE/src/ui/RenameSymbolDialog.bf index 45525e10..ba6cb9b7 100644 --- a/IDE/src/ui/RenameSymbolDialog.bf +++ b/IDE/src/ui/RenameSymbolDialog.bf @@ -740,7 +740,7 @@ namespace IDE.ui if ((mKind == Kind.Rename) && (IDEApp.IsBeefFile(editData.mFilePath))) { for (var projectSource in editData.mProjectSources) - app.mBfResolveCompiler.QueueProjectSource(projectSource); + app.mBfResolveCompiler.QueueProjectSource(projectSource, false); app.mBfResolveCompiler.QueueDeferredResolveAll(); } } diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 09f852c2..06ba21fd 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -453,6 +453,7 @@ namespace IDE.ui } Debug.Assert(endingText == text); + Debug.Assert(!endingText.Contains('\r')); //mClangSourceChanged = false; //mLastFileTextVersion = mEditWidget.Content.mData.mCurTextVersionId; diff --git a/IDE/src/ui/SourceViewPanel.bf b/IDE/src/ui/SourceViewPanel.bf index 1ecc2d08..7c82688f 100644 --- a/IDE/src/ui/SourceViewPanel.bf +++ b/IDE/src/ui/SourceViewPanel.bf @@ -262,83 +262,6 @@ namespace IDE.ui } } - public enum SourceHash - { - public enum Kind - { - None, - MD5, - SHA256 - } - - case None; - case MD5(MD5Hash hash); - case SHA256(SHA256Hash hash); - - public Kind GetKind() - { - switch (this) - { - case .MD5: - return .MD5; - case .SHA256: - return .SHA256; - default: - return .None; - } - } - - public static SourceHash Create(StringView hashStr) - { - if (hashStr.Length == 32) - { - if (MD5Hash.Parse(hashStr) case .Ok(let parsedHash)) - { - return .MD5(parsedHash); - } - } - else if (hashStr.Length == 64) - { - if (SHA256Hash.Parse(hashStr) case .Ok(let parsedHash)) - { - return .SHA256(parsedHash); - } - } - - return .None; - } - - public static SourceHash Create(Kind kind, StringView str) - { - switch (kind) - { - case .MD5: - return .MD5(Security.Cryptography.MD5.Hash(.((uint8*)str.Ptr, str.Length))); - case .SHA256: - return .SHA256(Security.Cryptography.SHA256.Hash(.((uint8*)str.Ptr, str.Length))); - default: - return .None; - } - } - - public static bool operator==(SourceHash lhs, SourceHash rhs) - { - switch (lhs) - { - case .None: - return rhs case .None; - case .MD5(let lhsMD5): - if (rhs case .MD5(let rhsMD5)) - return lhsMD5 == rhsMD5; - case .SHA256(let lhsSHA256): - if (rhs case .SHA256(let rhsSHA256)) - return lhsSHA256 == rhsSHA256; - default: - } - return false; - } - } - class QueuedAutoComplete { public char32 mKeyChar; diff --git a/IDE/src/util/GlobalUndoManager.bf b/IDE/src/util/GlobalUndoManager.bf index eace679b..acfcadfe 100644 --- a/IDE/src/util/GlobalUndoManager.bf +++ b/IDE/src/util/GlobalUndoManager.bf @@ -83,7 +83,7 @@ namespace IDE.Util for (var projectSource in editData.mProjectSources) { projectSource.HasChangedSinceLastCompile = true; - IDEApp.sApp.mBfResolveCompiler.QueueProjectSource(projectSource); + IDEApp.sApp.mBfResolveCompiler.QueueProjectSource(projectSource, false); } } } @@ -127,7 +127,7 @@ namespace IDE.Util for (var projectSource in editData.mProjectSources) { projectSource.HasChangedSinceLastCompile = true; - IDEApp.sApp.mBfResolveCompiler.QueueProjectSource(projectSource); + IDEApp.sApp.mBfResolveCompiler.QueueProjectSource(projectSource, false); } } } diff --git a/IDE/src/util/SourceHash.bf b/IDE/src/util/SourceHash.bf new file mode 100644 index 00000000..70f784b8 --- /dev/null +++ b/IDE/src/util/SourceHash.bf @@ -0,0 +1,92 @@ +using System.Security.Cryptography; +using System; + +namespace IDE.util +{ + public enum SourceHash + { + public enum Kind + { + None, + MD5, + SHA256 + } + + case None; + case MD5(MD5Hash hash); + case SHA256(SHA256Hash hash); + + public Kind GetKind() + { + switch (this) + { + case .MD5: + return .MD5; + case .SHA256: + return .SHA256; + default: + return .None; + } + } + + public static SourceHash Create(StringView hashStr) + { + if (hashStr.Length == 32) + { + if (MD5Hash.Parse(hashStr) case .Ok(let parsedHash)) + { + return .MD5(parsedHash); + } + } + else if (hashStr.Length == 64) + { + if (SHA256Hash.Parse(hashStr) case .Ok(let parsedHash)) + { + return .SHA256(parsedHash); + } + } + + return .None; + } + + public static SourceHash Create(Kind kind, StringView str, LineEndingKind lineEndingKind = .Unknown) + { + if ((lineEndingKind != .Unknown) && (lineEndingKind != .Lf)) + { + if (lineEndingKind == .CrLf) + { + String newStr = scope .(str); + newStr.Replace("\n", "\r\n"); + return Create(kind, newStr); + } + } + + switch (kind) + { + case .MD5: + return .MD5(Security.Cryptography.MD5.Hash(.((uint8*)str.Ptr, str.Length))); + case .SHA256: + return .SHA256(Security.Cryptography.SHA256.Hash(.((uint8*)str.Ptr, str.Length))); + default: + return .None; + } + } + + public static bool operator==(SourceHash lhs, SourceHash rhs) + { + switch (lhs) + { + case .None: + return rhs case .None; + case .MD5(let lhsMD5): + if (rhs case .MD5(let rhsMD5)) + return lhsMD5 == rhsMD5; + case .SHA256(let lhsSHA256): + if (rhs case .SHA256(let rhsSHA256)) + return lhsSHA256 == rhsSHA256; + default: + } + return false; + } + } +} diff --git a/IDEHelper/Backend/BeCOFFObject.cpp b/IDEHelper/Backend/BeCOFFObject.cpp index 2a8da92f..076ac280 100644 --- a/IDEHelper/Backend/BeCOFFObject.cpp +++ b/IDEHelper/Backend/BeCOFFObject.cpp @@ -1635,6 +1635,21 @@ void BeCOFFObject::DbgGenerateModuleInfo() } } + Array fileDataPositions; + /// + { + int fileDataPos = 0; + for (auto dbgFile : mBeModule->mDbgModule->mFiles) + { + fileDataPositions.Add(fileDataPos); + fileDataPos += 4; + if (dbgFile->mMD5Hash.IsZero()) + fileDataPos += 4; + else + fileDataPos += 20; + } + } + int emissionStartIdx = 0; BeDbgFile* curDbgFile = NULL; for (int emissionIdx = 0; emissionIdx < (int)emissions.size(); emissionIdx++) @@ -1657,7 +1672,7 @@ void BeCOFFObject::DbgGenerateModuleInfo() curDbgFile = dbgFile; lastBlockStartPos = outS.GetPos(); - outS.Write((int32)dbgFile->mIdx * 8); + outS.Write((int32)fileDataPositions[dbgFile->mIdx]); outS.Write((int32)0); // placeholder nLines outS.Write((int32)0); // placeholder cbBlock @@ -1779,7 +1794,19 @@ void BeCOFFObject::DbgGenerateModuleInfo() for (auto dbgFile : mBeModule->mDbgModule->mFiles) { outS.Write((int32)strTable.size()); - outS.Write((int32)0); // hashLen, hashType, padding + + if (dbgFile->mMD5Hash.IsZero()) + { + outS.Write((int32)0); // hashLen, hashType, padding + } + else + { + outS.Write((uint8)16); // hashLen + outS.Write((uint8)1); // hashType + outS.Write(&dbgFile->mMD5Hash, 16); + outS.Write((int8)0); // padding + outS.Write((int8)0); + } String fullPath; dbgFile->ToString(fullPath); diff --git a/IDEHelper/Backend/BeIRCodeGen.cpp b/IDEHelper/Backend/BeIRCodeGen.cpp index 4aa536ef..2a45b004 100644 --- a/IDEHelper/Backend/BeIRCodeGen.cpp +++ b/IDEHelper/Backend/BeIRCodeGen.cpp @@ -4,6 +4,7 @@ #include "BeefySysLib/util/BeefPerf.h" #include "BeefySysLib/util/AllocDebug.h" +#include "BeefySysLib/util/Hash.h" USING_NS_BF; @@ -518,6 +519,12 @@ void BeIRCodeGen::Read(int64& i) BE_MEM_END("int64"); } +void BeIRCodeGen::Read(Val128& i) +{ + i.mLow = (uint64)ReadSLEB128(); + i.mHigh = (uint64)ReadSLEB128(); +} + void BeIRCodeGen::Read(bool& val) { BE_MEM_START; @@ -2362,10 +2369,12 @@ void BeIRCodeGen::HandleNextCmd() { CMD_PARAM(String, fileName); CMD_PARAM(String, directory); + CMD_PARAM(Val128, md5Hash); auto dbgFile = mBeModule->mDbgModule->mFiles.Alloc(); - dbgFile->mFileName = fileName; + dbgFile->mFileName = fileName; dbgFile->mDirectory = directory; + dbgFile->mMD5Hash = md5Hash; dbgFile->mIdx = (int)mBeModule->mDbgModule->mFiles.size() - 1; SetResult(curId, dbgFile); diff --git a/IDEHelper/Backend/BeIRCodeGen.h b/IDEHelper/Backend/BeIRCodeGen.h index 4bfc6f0b..c4f32d11 100644 --- a/IDEHelper/Backend/BeIRCodeGen.h +++ b/IDEHelper/Backend/BeIRCodeGen.h @@ -95,6 +95,7 @@ public: void Read(StringImpl& str); void Read(int& i); void Read(int64& i); + void Read(Val128& i); void Read(bool& val); void Read(BeIRTypeEntry*& type); void Read(BeType*& beType); diff --git a/IDEHelper/Backend/BeModule.cpp b/IDEHelper/Backend/BeModule.cpp index 56f28f2e..30c86753 100644 --- a/IDEHelper/Backend/BeModule.cpp +++ b/IDEHelper/Backend/BeModule.cpp @@ -884,6 +884,38 @@ int BeDbgLoc::GetInlineMatchDepth(BeDbgLoc* other) return matchDepth; } +void BeDbgFunction::HashContent(BeHashContext& hashCtx) +{ + hashCtx.Mixin(TypeId); + if (mFile != NULL) + mFile->HashReference(hashCtx); + hashCtx.Mixin(mLine); + hashCtx.MixinStr(mName); + hashCtx.MixinStr(mLinkageName); + mType->HashReference(hashCtx); + for (auto genericArg : mGenericArgs) + genericArg->HashReference(hashCtx); + for (auto genericConstValueArgs : mGenericArgs) + genericConstValueArgs->HashReference(hashCtx); + if (mValue != NULL) + mValue->HashReference(hashCtx); + hashCtx.Mixin(mIsLocalToUnit); + hashCtx.Mixin(mIsStaticMethod); + hashCtx.Mixin(mFlags); + hashCtx.Mixin(mVK); + hashCtx.Mixin(mVIndex); + hashCtx.Mixin(mVariables.size()); + for (auto& variable : mVariables) + { + if (variable == NULL) + hashCtx.Mixin(-1); + else + variable->HashReference(hashCtx); + } + hashCtx.Mixin(mPrologSize); + hashCtx.Mixin(mCodeLen); +} + void BeDbgStructType::SetMembers(SizedArrayImpl& members) { mIsFullyDefined = true; diff --git a/IDEHelper/Backend/BeModule.h b/IDEHelper/Backend/BeModule.h index 47c0f590..e220b41f 100644 --- a/IDEHelper/Backend/BeModule.h +++ b/IDEHelper/Backend/BeModule.h @@ -1847,35 +1847,7 @@ public: }*/ } - virtual void HashContent(BeHashContext& hashCtx) override - { - hashCtx.Mixin(TypeId); - hashCtx.Mixin(mLine); - hashCtx.MixinStr(mName); - hashCtx.MixinStr(mLinkageName); - mType->HashReference(hashCtx); - for (auto genericArg : mGenericArgs) - genericArg->HashReference(hashCtx); - for (auto genericConstValueArgs : mGenericArgs) - genericConstValueArgs->HashReference(hashCtx); - if (mValue != NULL) - mValue->HashReference(hashCtx); - hashCtx.Mixin(mIsLocalToUnit); - hashCtx.Mixin(mIsStaticMethod); - hashCtx.Mixin(mFlags); - hashCtx.Mixin(mVK); - hashCtx.Mixin(mVIndex); - hashCtx.Mixin(mVariables.size()); - for (auto& variable : mVariables) - { - if (variable == NULL) - hashCtx.Mixin(-1); - else - variable->HashReference(hashCtx); - } - hashCtx.Mixin(mPrologSize); - hashCtx.Mixin(mCodeLen); - } + virtual void HashContent(BeHashContext& hashCtx) override; }; class BeDbgInlinedScope : public BeMDNode @@ -1982,8 +1954,9 @@ public: BE_VALUE_TYPE(BeDbgFile, BeMDNode); public: - String mFileName; + String mFileName; String mDirectory; + Val128 mMD5Hash; int mIdx; void ToString(String& str); @@ -1992,6 +1965,7 @@ public: { hashCtx.Mixin(TypeId); hashCtx.MixinStr(mFileName); + hashCtx.Mixin(mMD5Hash); hashCtx.MixinStr(mDirectory); } }; diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 146dbb0e..395d04dd 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -1289,7 +1289,10 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) SetAndRestoreValue prevSignatureHashCtx(mSignatureHashCtx, &signatureHashCtx); if (bfParser != NULL) + { mSignatureHashCtx->MixinStr(bfParser->mFileName); + mSignatureHashCtx->Mixin(bfParser->mParserData->mMD5Hash); + } HashNode(*mSignatureHashCtx, typeDeclaration->mTypeNode); for (auto& baseClassNode : typeDeclaration->mBaseClasses) HashNode(*mSignatureHashCtx, baseClassNode); diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index 7b21734c..26a4b7e7 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -1651,6 +1651,12 @@ void BfIRBuilder::Write(int64 intVal) WriteSLEB128(intVal); } +void BfIRBuilder::Write(Val128 val) +{ + WriteSLEB128((int64)val.mLow); + WriteSLEB128((int64)val.mHigh); +} + void BfIRBuilder::Write(const StringImpl&str) { WriteSLEB128((int)str.length()); @@ -4718,9 +4724,9 @@ BfIRMDNode BfIRBuilder::DbgCreateCompileUnit(int lang, const StringImpl& fileNam return retVal; } -BfIRMDNode BfIRBuilder::DbgCreateFile(const StringImpl& fileName, const StringImpl& directory) +BfIRMDNode BfIRBuilder::DbgCreateFile(const StringImpl& fileName, const StringImpl& directory, const Val128& md5Hash) { - BfIRMDNode retVal = WriteCmd(BfIRCmd_DbgCreateFile, fileName, directory); + BfIRMDNode retVal = WriteCmd(BfIRCmd_DbgCreateFile, fileName, directory, md5Hash); NEW_CMD_INSERTED_IRMD; if (mDbgVerifyCodeGen && gDebugDbgLoc) diff --git a/IDEHelper/Compiler/BfIRBuilder.h b/IDEHelper/Compiler/BfIRBuilder.h index cacf7f20..d8c522ff 100644 --- a/IDEHelper/Compiler/BfIRBuilder.h +++ b/IDEHelper/Compiler/BfIRBuilder.h @@ -58,6 +58,7 @@ class BfFieldInstance; class BfFileInstance; class BfParser; class BfParserData; +class Val128; class BfFilePosition { @@ -905,6 +906,7 @@ public: void Write(bool val); void Write(int val); void Write(int64 val); + void Write(Val128 val); void Write(const StringImpl& str); void Write(const BfIRValue& irValue); void Write(BfTypeCode typeCode); @@ -1195,7 +1197,7 @@ public: void DbgAddPrefix(String& name); BfIRMDNode DbgCreateCompileUnit(int lang, const StringImpl& filename, const StringImpl& directory, const StringImpl& producer, bool isOptimized, const StringImpl& flags, int runtimeVer, bool linesOnly); - BfIRMDNode DbgCreateFile(const StringImpl& fileName, const StringImpl& directory); + BfIRMDNode DbgCreateFile(const StringImpl& fileName, const StringImpl& directory, const Val128& md5Hash); BfIRMDNode DbgGetCurrentLocation(); void DbgSetType(BfType * type, BfIRMDNode diType); void DbgSetInstType(BfType * type, BfIRMDNode diType); diff --git a/IDEHelper/Compiler/BfIRCodeGen.cpp b/IDEHelper/Compiler/BfIRCodeGen.cpp index 965de34e..db67df8e 100644 --- a/IDEHelper/Compiler/BfIRCodeGen.cpp +++ b/IDEHelper/Compiler/BfIRCodeGen.cpp @@ -1,6 +1,7 @@ #include "BfIRCodeGen.h" #include "BfModule.h" #include "BeefySysLib/util/BeefPerf.h" +#include "BeefySysLib/util/Hash.h" #pragma warning(push) #pragma warning(disable:4141) @@ -113,6 +114,7 @@ USING_NS_BF; #pragma warning(disable:4146) +#pragma warning(disable:4996) struct BuiltinEntry { @@ -477,6 +479,12 @@ void BfIRCodeGen::Read(int64& i) i = ReadSLEB128(); } +void BfIRCodeGen::Read(Val128& i) +{ + i.mLow = (uint64)ReadSLEB128(); + i.mHigh = (uint64)ReadSLEB128(); +} + void BfIRCodeGen::Read(bool& val) { val = mStream->Read() != 0; @@ -2741,7 +2749,14 @@ void BfIRCodeGen::HandleNextCmd() { CMD_PARAM(String, fileName); CMD_PARAM(String, directory); - SetResult(curId, mDIBuilder->createFile(fileName.c_str(), directory.c_str())); + CMD_PARAM(Val128, md5Hash); + + char hashStr[64]; + for (int i = 0; i < 16; i++) + sprintf(&hashStr[i * 2], "%.2x", ((uint8*)&md5Hash)[i]); + + SetResult(curId, mDIBuilder->createFile(fileName.c_str(), directory.c_str(), + llvm::DIFile::ChecksumInfo(llvm::DIFile::CSK_MD5, hashStr))); } break; case BfIRCmd_ConstValueI64: diff --git a/IDEHelper/Compiler/BfIRCodeGen.h b/IDEHelper/Compiler/BfIRCodeGen.h index 6b86c705..f06ed529 100644 --- a/IDEHelper/Compiler/BfIRCodeGen.h +++ b/IDEHelper/Compiler/BfIRCodeGen.h @@ -111,6 +111,7 @@ public: void Read(StringImpl& str); void Read(int& i); void Read(int64& i); + void Read(Val128& i); void Read(bool& val); void Read(BfIRTypeEntry*& type); void Read(llvm::Type*& llvmType); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index aff664af..b5313812 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2168,7 +2168,7 @@ BfFileInstance* BfModule::GetFileFromNode(BfAstNode* astNode) fileName[i] = DIR_SEP_CHAR; } - bfFileInstance->mDIFile = mBfIRBuilder->DbgCreateFile(fileName.Substring(slashPos + 1), fileName.Substring(0, slashPos)); + bfFileInstance->mDIFile = mBfIRBuilder->DbgCreateFile(fileName.Substring(slashPos + 1), fileName.Substring(0, slashPos), bfParser->mMD5Hash); } return bfFileInstance; } diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index a9deab82..da244acf 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -3382,6 +3382,12 @@ BF_EXPORT void BF_CALLTYPE BfParser_SetCharIdData(BfParser* bfParser, uint8* dat memcpy(bfParser->mParserData->mCharIdData, data, length); } +BF_EXPORT void BF_CALLTYPE BfParser_SetHashMD5(BfParser* bfParser, Val128* md5Hash) +{ + if (md5Hash != NULL) + bfParser->mParserData->mMD5Hash = *md5Hash; +} + BF_EXPORT void BF_CALLTYPE BfParser_Delete(BfParser* bfParser) { if (bfParser->mNextRevision != NULL) diff --git a/IDEHelper/Compiler/BfParser.h b/IDEHelper/Compiler/BfParser.h index dcc8f741..f2130b8a 100644 --- a/IDEHelper/Compiler/BfParser.h +++ b/IDEHelper/Compiler/BfParser.h @@ -68,6 +68,7 @@ public: BfParser* mUniqueParser; // For non-cached usage (ie: autocomplete) String mFileName; uint8* mCharIdData; + Val128 mMD5Hash; HashSet mDefines_Def; HashSet mDefines_NoDef;