diff --git a/.github/workflows/extended_checks.yml b/.github/workflows/extended_checks.yml index 278cb34a31..221d8432aa 100644 --- a/.github/workflows/extended_checks.yml +++ b/.github/workflows/extended_checks.yml @@ -181,6 +181,10 @@ jobs: run: | set -eux $BIN/daslang_static _dasroot_/dastest/dastest.das -- --color --failures-only --test ./tests + - name: "Test ser/deser" + run: | + $BIN/daslang _dasroot_/dastest/dastest.das -- --color --failures-only --test ./tests --ser serialized.bin + $BIN/daslang _dasroot_/dastest/dastest.das -- --color --failures-only --test ./tests --deser serialized.bin - name: "Run self-binder (bind_clangbind.das)" if: matrix.target == 'linux' diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b094e7d9a..f32fa3be9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -654,6 +654,7 @@ SOURCE_GROUP_FILES("vecmath" VECMATH_SRC) SET(AST_SRC src/ast/ast.cpp +src/ast/ast_dispatch.cpp src/ast/ast_interop.cpp src/ast/ast_tls.cpp src/ast/ast_visitor.cpp diff --git a/daslib/aot_cpp.das b/daslib/aot_cpp.das index aab68b87f5..2bd8278ae3 100644 --- a/daslib/aot_cpp.das +++ b/daslib/aot_cpp.das @@ -3990,11 +3990,12 @@ def public compile_and_simulate(input : string, var access; var mg : ModuleGroup set_aot(); compile_file(input, access, mg, cop) $(ok; var program : smart_ptr; issues) { if (!ok) { - print("failed to compile {input}\n{issues}\n") + to_log(LOG_ERROR, "failed to compile {input}\n{issues}\n") return } simulate(program) $(sok; var pctx : smart_ptr; serrors) { if (!sok) { + to_log(LOG_ERROR, "failed to simulate {input}\n{serrors}\n") panic("Failed to simulate {serrors}") } blk(program, pctx) diff --git a/dastest/dastest.das b/dastest/dastest.das index cb0ff899b4..8bd37f6224 100644 --- a/dastest/dastest.das +++ b/dastest/dastest.das @@ -156,6 +156,13 @@ def serialize_path(ctx : SuiteCtx, files : array, out_file : string) { var inscope access <- make_file_access(ctx.projectPath) access |> add_file_access_root("dastest", ctx.dastestRoot) for (file in files) { + // Tests whose basename starts with cant_, failed_, or invalid_ + // are expected-failure compile tests anywhere in the tests tree; + // they have nothing to serialize. + let base = base_name(file) + if (base |> starts_with("cant_") || base |> starts_with("failed_") || base |> starts_with("invalid_")) { + continue + } using() $(var mg : ModuleGroup) { using() $(var cop : CodeOfPolicies) { cop.aot_module = true diff --git a/include/daScript/ast/ast.h b/include/daScript/ast/ast.h index b7e864ec0e..01eaa904ea 100644 --- a/include/daScript/ast/ast.h +++ b/include/daScript/ast/ast.h @@ -25,6 +25,7 @@ namespace das { struct AstSerializer; + class Visitor; class Function; typedef Function * FunctionPtr; @@ -691,7 +692,7 @@ namespace das virtual Expression * tail() { return this; } virtual bool swap_tail ( Expression *, Expression * ) { return false; } virtual uint32_t getEvalFlags() const { return 0; } - virtual void serialize ( AstSerializer & ser ); + virtual void dispatch ( Visitor & vis ); virtual void gc_collect ( gc_root * target, gc_root * from ); LineInfo at; TypeDeclPtr type = nullptr; @@ -745,7 +746,7 @@ namespace das virtual bool rtti_isConstant() const override { return true; } template QQ & cvalue() { return *((QQ *)&value); } template const QQ & cvalue() const { return *((const QQ *)&value); } - virtual void serialize ( AstSerializer & ser ) override; + virtual void dispatch ( Visitor & vis ) override; Type baseType = Type::none; vec4f value = v_zero(); bool foldedNonConst = false; diff --git a/include/daScript/ast/ast_expressions.h b/include/daScript/ast/ast_expressions.h index 51ebdb80bf..eb00710e7c 100644 --- a/include/daScript/ast/ast_expressions.h +++ b/include/daScript/ast/ast_expressions.h @@ -12,7 +12,7 @@ namespace das : Expression(a), macro(rm) { __rtti = "ExprReader"; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ReaderMacroPtr macro = nullptr; string sequence; @@ -25,7 +25,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isLabel() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; int32_t label = -1; string comment; @@ -41,7 +41,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isGoto() const override { return true; } virtual uint32_t getEvalFlags() const override { return EvalFlags::jumpToLabel; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; int32_t label = -1; ExpressionPtr subexpr = nullptr; @@ -52,7 +52,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isR2V() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; ExpressionPtr subexpr = nullptr; @@ -65,7 +65,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isRef2Ptr() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; ExpressionPtr subexpr = nullptr; @@ -78,7 +78,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isPtr2Ref() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr subexpr = nullptr; bool unsafeDeref = false; @@ -92,7 +92,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isAddr() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; string target; TypeDeclPtr funcType = nullptr; @@ -106,7 +106,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isNullCoalescing() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; ExpressionPtr defaultValue = nullptr; @@ -118,7 +118,7 @@ namespace das : Expression(a), subexpr(s) { __rtti = "ExprDelete"; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr subexpr = nullptr; ExpressionPtr sizeexpr = nullptr; @@ -132,7 +132,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isAt() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; ExpressionPtr subexpr = nullptr, index = nullptr; @@ -157,7 +157,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isAt() const override { return false; } virtual bool rtti_isSafeAt() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; }; @@ -174,7 +174,7 @@ namespace das string getMangledName(bool includeName = false, bool includeResult = false) const; bool collapse(); static void collapse ( vector & res, const vector & lst ); - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; TypeDeclPtr makeBlockType () const; vector list; @@ -226,7 +226,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isVar() const override { return true; } bool isGlobalVariable() const { return !local && !argument && !block; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; string name; VariablePtr variable = nullptr; @@ -255,7 +255,7 @@ namespace das : Expression(a), subexpr(se), value(va), name(n) { __rtti = "ExprTag"; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr subexpr = nullptr; ExpressionPtr value = nullptr; @@ -273,7 +273,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isField() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; Structure::FieldDeclaration * field() const; @@ -332,7 +332,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isField() const override { return false; } virtual bool rtti_isSafeAsVariant() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; bool skipQQ = false; }; @@ -344,7 +344,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isSwizzle() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr value = nullptr; string mask; @@ -369,7 +369,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isField() const override { return false; } virtual bool rtti_isSafeField() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; bool skipQQ = false; }; @@ -383,7 +383,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual string describe() const; virtual bool rtti_isCallLikeExpr() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; string name; vector arguments; @@ -398,7 +398,7 @@ namespace das : ExprLooksLikeCall(a,n) { __rtti = "ExprCallMacro"; } virtual ExpressionPtr visit(Visitor & vis) override; virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; Function * inFunction = nullptr; CallMacro * macro = nullptr; @@ -409,7 +409,7 @@ namespace das ExprCallFunc ( const LineInfo & a, const string & n ) : ExprLooksLikeCall(a,n) { __rtti = "ExprCallFunc"; } virtual bool rtti_isCallFunc() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; Function * func = nullptr; uint32_t stackTop = 0; @@ -427,7 +427,7 @@ namespace das ExprOp ( const LineInfo & a, const string & o ) : ExprCallFunc(a,o), op(o) { __rtti = "ExprOp"; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; string op; }; @@ -443,7 +443,7 @@ namespace das virtual bool swap_tail ( Expression * expr, Expression * swapExpr ) override; virtual bool rtti_isOp1() const override { return true; } virtual string describe() const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; ExpressionPtr subexpr = nullptr; @@ -460,7 +460,7 @@ namespace das virtual bool swap_tail ( Expression * expr, Expression * swapExpr ) override; virtual bool rtti_isOp2() const override { return true; } virtual string describe() const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; ExpressionPtr left = nullptr, right = nullptr; @@ -473,7 +473,7 @@ namespace das : ExprOp2(a, "=", l, r) { __rtti = "ExprCopy"; }; virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual bool rtti_isCopy() const override { return true; } union { @@ -493,7 +493,7 @@ namespace das : ExprOp2(a, "<-", l, r) { __rtti = "ExprMove"; }; virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; union { struct { @@ -512,7 +512,7 @@ namespace das : ExprOp2(a, ":=", l, r) { __rtti = "ExprClone"; }; virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual bool rtti_isClone() const override { return true; } }; @@ -538,7 +538,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isOp3() const override { return true; } virtual string describe() const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; ExpressionPtr subexpr = nullptr, left = nullptr, right = nullptr; @@ -551,7 +551,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual uint32_t getEvalFlags() const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr try_block = nullptr, catch_block = nullptr; }; @@ -568,7 +568,7 @@ namespace das return ef; } virtual bool rtti_isReturn() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr subexpr = nullptr; union { @@ -638,7 +638,7 @@ namespace das TypeDeclPtr ptrType = nullptr; virtual ExpressionPtr clone( ExpressionPtr expr ) const override; virtual bool rtti_isNullPtr() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; auto getValue() const { return ExprConstT::getValue(); }; }; @@ -670,7 +670,7 @@ namespace das } virtual ExpressionPtr visit(Visitor & vis) override; virtual ExpressionPtr clone( ExpressionPtr expr ) const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; EnumerationPtr enumType = nullptr; string text; @@ -707,7 +707,7 @@ namespace das : ExprConstT(a,i,Type::tBitfield) { __rtti = "ExprConstBitfield"; } virtual ExpressionPtr clone( ExpressionPtr expr ) const override; auto getValue() const { return ExprConstT::getValue(); }; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; TypeDeclPtr bitfieldType = nullptr; }; @@ -889,7 +889,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr ) const override; const string & getValue() const { return text; } virtual bool rtti_isStringConstant() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; string text; }; @@ -901,7 +901,7 @@ namespace das virtual bool rtti_isStringBuilder() const override { return true; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; vector elements; union { @@ -918,7 +918,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isLet() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; vector variables; LineInfo visibility; @@ -943,7 +943,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual uint32_t getEvalFlags() const override; virtual bool rtti_isFor() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; vector iterators; vector iteratorsAka; @@ -966,7 +966,7 @@ namespace das virtual uint32_t getEvalFlags() const override; virtual bool rtti_isUnsafe() const override { return true; } virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr body = nullptr; }; @@ -979,7 +979,7 @@ namespace das virtual uint32_t getEvalFlags() const override; virtual bool rtti_isWhile() const override { return true; } virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr cond = nullptr, body = nullptr; }; @@ -991,7 +991,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isWith() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr with = nullptr, body = nullptr; }; @@ -1005,7 +1005,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isAssume() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; string alias; ExpressionPtr subexpr = nullptr; @@ -1050,7 +1050,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual bool rtti_isMakeBlock() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; vector capture; LineInfo captureAt; @@ -1071,7 +1071,7 @@ namespace das ExprMakeGenerator ( const LineInfo & a, ExpressionPtr b = nullptr ); virtual ExpressionPtr visit(Visitor & vis) override; virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; TypeDeclPtr iterType = nullptr; vector capture; @@ -1084,7 +1084,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual uint32_t getEvalFlags() const override { return EvalFlags::yield; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr subexpr = nullptr; union { @@ -1103,7 +1103,7 @@ namespace das virtual bool rtti_isInvoke() const override { return true; } bool isCopyOrMove() const; __forceinline bool allowCmresSkip() const { return !cmresAlias && isCopyOrMove(); } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; uint32_t stackTop = 0; bool doesNotNeedSp = false; @@ -1116,7 +1116,7 @@ namespace das ExprAssert ( const LineInfo & a, const string & name, bool isV ) : ExprLikeCall(a,name) { isVerify = isV; __rtti = "ExprAssert"; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; bool isVerify = false; }; @@ -1127,7 +1127,7 @@ namespace das : ExprLikeCall(a,name) { __rtti = "ExprQuote"; } virtual ExpressionPtr visit(Visitor & vis) override; virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; }; @@ -1166,7 +1166,7 @@ namespace das return cexpr; } virtual ExpressionPtr visit ( Visitor & vis ) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; }; @@ -1181,7 +1181,7 @@ namespace das return cexpr; } virtual ExpressionPtr visit ( Visitor & vis ) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; }; @@ -1227,7 +1227,7 @@ namespace das : Expression(a), trait(tr), typeexpr(d), subtrait(stt), extratrait(ett) { __rtti = "ExprTypeInfo"; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; string trait; ExpressionPtr subexpr = nullptr; @@ -1243,7 +1243,7 @@ namespace das : Expression(a), subexpr(s), typeexpr(t) { __rtti = "ExprIs"; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr subexpr = nullptr; TypeDeclPtr typeexpr = nullptr; @@ -1256,7 +1256,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isAscend() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr subexpr = nullptr; TypeDeclPtr ascType = nullptr; @@ -1277,7 +1277,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isCast() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr subexpr = nullptr; TypeDeclPtr castType = nullptr; @@ -1296,7 +1296,7 @@ namespace das : ExprCallFunc(a,"new"), typeexpr(t), initializer(ini) { __rtti = "ExprNew"; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; TypeDeclPtr typeexpr = nullptr; bool initializer = false; @@ -1309,7 +1309,7 @@ namespace das virtual bool rtti_isCall() const override { return true; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; bool doesNotNeedSp = false; @@ -1330,7 +1330,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isIfThenElse() const override { return true; } virtual uint32_t getEvalFlags() const override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr cond = nullptr, if_true = nullptr, if_false = nullptr; union { @@ -1384,7 +1384,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isNamedCall() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; string name; vector nonNamedArguments; @@ -1399,7 +1399,7 @@ namespace das : Expression(at) { __rtti = "ExprMakeLocal"; } virtual bool rtti_isMakeLocal() const override { return true; } virtual void setRefSp ( bool ref, bool cmres, uint32_t sp, uint32_t off ); - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; TypeDeclPtr makeType = nullptr; uint32_t stackTop = 0; @@ -1425,7 +1425,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual void setRefSp ( bool ref, bool cmres, uint32_t sp, uint32_t off ) override; virtual bool rtti_isMakeStruct() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; vector structs; @@ -1458,7 +1458,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual void setRefSp ( bool ref, bool cmres, uint32_t sp, uint32_t off ) override; virtual bool rtti_isMakeVariant() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; vector variants; @@ -1472,7 +1472,7 @@ namespace das virtual ExpressionPtr visit(Visitor & vis) override; virtual void setRefSp ( bool ref, bool cmres, uint32_t sp, uint32_t off ) override; virtual bool rtti_isMakeArray() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; virtual void markNoDiscard() override; TypeDeclPtr recordType = nullptr; @@ -1488,7 +1488,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual void setRefSp ( bool ref, bool cmres, uint32_t sp, uint32_t off ) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; bool isKeyValue = false; vector recordNames; @@ -1500,7 +1500,7 @@ namespace das : Expression(at) { __rtti = "ExprArrayComprehension"; } virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; ExpressionPtr exprFor = nullptr; ExpressionPtr exprWhere = nullptr; @@ -1516,7 +1516,7 @@ namespace das virtual ExpressionPtr clone( ExpressionPtr expr = nullptr ) const override; virtual ExpressionPtr visit(Visitor & vis) override; virtual bool rtti_isTypeDecl() const override { return true; } - virtual void serialize( AstSerializer & ser ) override; + virtual void dispatch( Visitor & vis ) override; virtual void gc_collect ( gc_root * target, gc_root * from ) override; TypeDeclPtr typeexpr = nullptr; }; diff --git a/include/daScript/ast/ast_serializer.h b/include/daScript/ast/ast_serializer.h index 490274149a..4f9ba018ca 100644 --- a/include/daScript/ast/ast_serializer.h +++ b/include/daScript/ast/ast_serializer.h @@ -64,6 +64,30 @@ namespace das { } }; + // Composite key for serializer maps. Pairs a raw pointer with a per- + // AstSerializer epoch so reused addresses don't collide with prior entries. + // Hoisted to namespace das so daslang_hash can be specialized before the + // map instantiations inside AstSerializer. + struct SerializeNodeId { + void * ptr = nullptr; + size_t epoch = 0; + bool operator == ( const SerializeNodeId & o ) const noexcept { + return ptr == o.ptr && epoch == o.epoch; + } + bool operator != ( const SerializeNodeId & o ) const noexcept { + return !(*this == o); + } + }; + + template <> + struct daslang_hash { + size_t operator () ( const SerializeNodeId & s ) const noexcept { + const size_t pmix = (reinterpret_cast(s.ptr) >> 4) + * size_t(0x9E3779B97F4A7C15ull); + return pmix ^ (s.epoch * size_t(0xBF58476D1CE4E5B9ull)); + } + }; + struct DAS_API AstSerializer { ~AstSerializer (); AstSerializer ( SerializationStorage * storage, bool isWriting ); @@ -90,26 +114,32 @@ namespace das { das_hash_set doNotDelete; // profile data uint64_t totMacroTime = 0; + // Per-program epoch for SerializeNodeId. Bumped at the start of each + // serialize/deserialize call so reused pointer addresses across program + // boundaries don't collide with prior map entries on this persistent + // serializer. Must be initialized — uninitialized epoch produces garbage + // keys and silent map collisions. + size_t epoch = 0; // pointers - das_hash_map exprBlockMap; + das_hash_map exprBlockMap; using DataOffset = uint64_t; - das_hash_map writingFileInfoMap; - das_hash_map readingFileInfoMap; - das_hash_map fileAccessMap; + das_hash_map writingFileInfoMap; + das_hash_map readingFileInfoMap; + das_hash_map fileAccessMap; // smart pointers - das_hash_map smartMakeFieldDeclMap; - das_hash_map smartEnumerationMap; - das_hash_map smartStructureMap; - das_hash_map smartVariableMap; - das_hash_map smartFunctionMap; - das_hash_map smartMakeStructMap; - das_hash_map smartTypeDeclMap; + das_hash_map smartMakeFieldDeclMap; + das_hash_map smartEnumerationMap; + das_hash_map smartStructureMap; + das_hash_map smartVariableMap; + das_hash_map smartFunctionMap; + das_hash_map smartMakeStructMap; + das_hash_map smartTypeDeclMap; // refs - vector> blockRefs; - vector> functionRefs; - vector> variableRefs; - vector> structureRefs; - vector> enumerationRefs; + vector> blockRefs; + vector> functionRefs; + vector> variableRefs; + vector> structureRefs; + vector> enumerationRefs; // fieldRefs tuple contains: fieldptr, module, structname, fieldname vector> fieldRefs; // parseModule tuple contains: moduleName, mtime, thisModule, thisModule @@ -185,6 +215,7 @@ namespace das { AstSerializer & operator << ( CaptureEntry & entry ); AstSerializer & operator << ( MakeFieldDeclPtr & ptr ); AstSerializer & operator << ( MakeStructPtr & ptr ); + AstSerializer & operator << ( SerializeNodeId & value ); // Top-level AstSerializer & operator << ( Module & module ); AstSerializer & serializeModule ( Module & module, bool already_exists ); @@ -194,9 +225,6 @@ namespace das { void serializeProgram ( ProgramPtr program, ModuleGroup & libGroup ) noexcept; bool serializeScript ( ProgramPtr program ) noexcept; - template - void serializeSmartPtr( smart_ptr & obj, das_hash_map> & objMap ); - template AstSerializer& operator << ( int (&value)[n] ) { serialize(value, n * sizeof(int)); return *this; @@ -248,10 +276,10 @@ namespace das { void writeIdentifications ( Variable * & ptr ); void writeIdentifications ( TypeInfoMacro * & ptr ); - void fillOrPatchLater ( Function * & func, uint64_t id ); - void fillOrPatchLater ( Enumeration * & ptr, uint64_t id ); - void fillOrPatchLater ( Structure * & ptr, uint64_t id ); - void fillOrPatchLater ( Variable * & ptr, uint64_t id ); + void fillOrPatchLater ( Function * & func, SerializeNodeId id ); + void fillOrPatchLater ( Enumeration * & ptr, SerializeNodeId id ); + void fillOrPatchLater ( Structure * & ptr, SerializeNodeId id ); + void fillOrPatchLater ( Variable * & ptr, SerializeNodeId id ); auto readModuleAndName () -> pair; auto readModuleAndNameHash () -> pair; @@ -262,6 +290,8 @@ namespace das { void findExternal ( Variable * & ptr ); void findExternal ( TypeInfoMacro * & ptr ); + SerializeNodeId getSerializeId(void *ptr) { return {ptr, epoch}; } + template void serialize_small_enum ( EnumType & baseType ) { if ( writing ) { @@ -290,6 +320,7 @@ namespace das { // Opaque handle to expose serializer to daslang. struct AstSerializerState { unique_ptr storage; + unique_ptr serializer; }; // Create a writing serializer. diff --git a/include/daScript/ast/ast_visitor.h b/include/daScript/ast/ast_visitor.h index 901748f903..2806af408d 100644 --- a/include/daScript/ast/ast_visitor.h +++ b/include/daScript/ast/ast_visitor.h @@ -376,6 +376,11 @@ namespace das { return llk == this ? vis.visit(static_cast(this)) : llk; } + template + void ExprTableKeysOrValues::dispatch ( Visitor & vis ) { + vis.preVisit(static_cast(this)); + } + template ExpressionPtr ExprArrayCallWithSizeOrIndex::visit(Visitor & vis) { vis.preVisit(static_cast(this)); @@ -383,6 +388,11 @@ namespace das { return llk == this ? vis.visit(static_cast(this)) : llk; } + template + void ExprArrayCallWithSizeOrIndex::dispatch ( Visitor & vis ) { + vis.preVisit(static_cast(this)); + } + template ExpressionPtr ExprConstT::visit(Visitor & vis) { vis.preVisit((ExprConst*)this); diff --git a/src/ast/ast_dispatch.cpp b/src/ast/ast_dispatch.cpp new file mode 100644 index 0000000000..fafe036aa9 --- /dev/null +++ b/src/ast/ast_dispatch.cpp @@ -0,0 +1,91 @@ +#include "daScript/misc/platform.h" + +#include "daScript/ast/ast.h" +#include "daScript/ast/ast_expressions.h" +#include "daScript/ast/ast_visitor.h" + +// Per-class virtual shim for SerializeVisitor-style dispatch: +// static-type-aware single call to the matching Visitor::preVisit(ExprXxx*) overload, +// with no child walk and no post-visit. Abstract intermediate classes and templates +// without a matching preVisit overload fall through to preVisitExpression. + +namespace das +{ + + void Expression::dispatch ( Visitor & vis ) { + vis.preVisitExpression(this); + } + + // concrete Expression subclasses -> preVisit(ExprXxx*) + void ExprReader::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprLabel::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprGoto::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprRef2Value::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprRef2Ptr::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprPtr2Ref::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprAddr::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprNullCoalescing::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprDelete::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprAt::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprSafeAt::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprBlock::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprVar::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprTag::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprField::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprSafeAsVariant::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprSwizzle::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprSafeField::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprLooksLikeCall::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprCallMacro::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprOp1::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprOp2::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprCopy::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprMove::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprClone::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprOp3::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprTryCatch::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprReturn::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprConstPtr::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprConstEnumeration::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprConstBitfield::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprConstString::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprStringBuilder::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprLet::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprFor::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprUnsafe::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprWhile::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprWith::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprAssume::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprMakeBlock::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprMakeGenerator::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprYield::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprInvoke::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprAssert::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprQuote::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprTypeInfo::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprIs::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprAscend::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprCast::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprNew::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprCall::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprIfThenElse::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprNamedCall::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprMakeStruct::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprMakeVariant::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprMakeArray::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprMakeTuple::dispatch ( Visitor & vis ) { vis.preVisit(this); } + void ExprArrayComprehension::dispatch( Visitor & vis ) { vis.preVisit(this); } + void ExprTypeDecl::dispatch ( Visitor & vis ) { vis.preVisit(this); } + + // abstract intermediate classes -> route to nearest concrete preVisit overload + void ExprOp::dispatch ( Visitor & vis ) { vis.preVisit(static_cast(this)); } + void ExprCallFunc::dispatch ( Visitor & vis ) { vis.preVisit(static_cast(this)); } + void ExprMakeLocal::dispatch ( Visitor & vis ) { vis.preVisitExpression(this); } + + void ExprConst::dispatch ( Visitor & vis ) { vis.preVisit(this); } + + // ExprTableKeysOrValues / ExprArrayCallWithSizeOrIndex dispatch live in + // ast_visitor.h alongside their visit() templates so every TU that + // instantiates a specialization picks up the definition. + +} diff --git a/src/builtin/module_builtin_ast_serialize.cpp b/src/builtin/module_builtin_ast_serialize.cpp index bf0708c8b7..22a56c11e0 100644 --- a/src/builtin/module_builtin_ast_serialize.cpp +++ b/src/builtin/module_builtin_ast_serialize.cpp @@ -5,6 +5,7 @@ #include "daScript/ast/ast_serializer.h" #include "daScript/ast/ast_handle.h" #include "daScript/ast/ast.h" +#include "daScript/ast/ast_visitor.h" #include #include #include @@ -64,7 +65,7 @@ namespace das { } template - void patchRefs ( vector> & refs, const das_hash_map> & objects) { + void patchRefs ( vector> & refs, const das_hash_map> & objects) { for ( auto & p : refs ) { auto it = objects.find(p.second); if ( it == objects.end() ) { @@ -77,7 +78,7 @@ namespace das { } template - void patchRefs ( vector> & refs, const das_hash_map & objects) { + void patchRefs ( vector> & refs, const das_hash_map & objects) { for ( auto & p : refs ) { auto it = objects.find(p.second); if ( it == objects.end() ) { @@ -224,6 +225,64 @@ namespace das { } } + AstSerializer & AstSerializer::operator << ( SerializeNodeId & value ) { + dtag(HASH_TAG("SerializeNodeId")); + // 64-bit user-space pointers fit in 48 bits (canonical form on x86-64 + // and AArch64 Linux/macOS — top 16 bits are sign-extended copies of + // bit 47, and we only ever see user-space addresses here, so they are + // zero). Pack a small epoch into those unused top 16 bits so the + // common case is a single 8-byte word. Reserve sentinel 0xFFFF for + // "epoch overflow" — fall back to a separate adaptive-size write. + // 32-bit hosts have no headroom; always emit ptr + adaptive epoch. + if constexpr ( sizeof(void *) == 8 ) { + constexpr uint64_t kPtrMask = (uint64_t(1) << 48) - 1; + constexpr uint64_t kEpochOverflowTag = 0xFFFFull << 48; + if ( writing ) { + uintptr_t pbits = reinterpret_cast(value.ptr); + DAS_ASSERTF((uint64_t(pbits) & ~kPtrMask) == 0, + "SerializeNodeId: pointer %p has non-zero top 16 bits — " + "non-canonical address violates packing assumption", value.ptr); + if ( value.epoch < 0xFFFFull ) { + uint64_t packed = (uint64_t(value.epoch) << 48) | uint64_t(pbits); + *this << packed; + } else { + uint64_t packed = kEpochOverflowTag | uint64_t(pbits); + *this << packed; + uint32_t epoch32 = uint32_t(value.epoch); + serializeAdaptiveSize32(epoch32); + } + } else { + uint64_t packed = 0; + *this << packed; + uint64_t topBits = packed & ~kPtrMask; + value.ptr = reinterpret_cast(uintptr_t(packed & kPtrMask)); + if ( topBits == kEpochOverflowTag ) { + uint32_t epoch32 = 0; + serializeAdaptiveSize32(epoch32); + value.epoch = size_t(epoch32); + } else { + value.epoch = size_t(topBits >> 48); + } + } + } else { + // 32-bit: pointer fills the word; epoch goes in its own adaptive int. + if ( writing ) { + uint32_t pbits = uint32_t(reinterpret_cast(value.ptr)); + uint32_t epoch32 = uint32_t(value.epoch); + *this << pbits; + serializeAdaptiveSize32(epoch32); + } else { + uint32_t pbits = 0; + *this << pbits; + uint32_t epoch32 = 0; + serializeAdaptiveSize32(epoch32); + value.ptr = reinterpret_cast(uintptr_t(pbits)); + value.epoch = size_t(epoch32); + } + } + return *this; + } + AstSerializer & AstSerializer::operator << ( string & str ) { dtag(HASH_TAG("string")); if ( writing ) { @@ -321,31 +380,6 @@ namespace das { return *this; } - AstSerializer & AstSerializer::operator << ( ExpressionPtr & expr ) { - dtag(HASH_TAG("ExpressionPtr")); - bool is_null = expr == nullptr; - *this << is_null; - if ( is_null ) { - if ( !writing ) expr = nullptr; - return *this; - } - if ( writing ) { - uint32_t rtti = hash_tag(expr->__rtti); - DAS_ASSERT(rtti); - *this << rtti; - expr->serialize(*this); - } else { - uint32_t rtti = 0; *this << rtti; - auto itA = rttiHash2Annotation.find(rtti); - SERIALIZER_VERIFYF(itA != rttiHash2Annotation.end(), "annotation '%u' is not found", rtti); - auto annotation = itA->second; - expr = (Expression *) static_cast(annotation)->factory(); - expr->serialize(*this); - } - dtag(HASH_TAG("/ExpressionPtr")); - return *this; - } - bool AstSerializer::isInThisModule ( Function * & ptr ) { return ptr->module == thisModule; } @@ -392,7 +426,7 @@ namespace das { *this << ptr->module->nameHash << ptr->name; } - void AstSerializer::fillOrPatchLater ( Function * & func, uint64_t id ) { + void AstSerializer::fillOrPatchLater ( Function * & func, SerializeNodeId id ) { auto it = smartFunctionMap.find(id); if ( it == smartFunctionMap.end() ) { func = ( Function * ) 1; @@ -402,7 +436,7 @@ namespace das { } } - void AstSerializer::fillOrPatchLater ( Enumeration * & ptr, uint64_t id ) { + void AstSerializer::fillOrPatchLater ( Enumeration * & ptr, SerializeNodeId id ) { auto it = smartEnumerationMap.find(id); if ( it == smartEnumerationMap.end() ) { ptr = ( Enumeration * ) 1; @@ -412,7 +446,7 @@ namespace das { } } - void AstSerializer::fillOrPatchLater ( Structure * & ptr, uint64_t id ) { + void AstSerializer::fillOrPatchLater ( Structure * & ptr, SerializeNodeId id ) { auto it = smartStructureMap.find(id); if ( it == smartStructureMap.end() ) { ptr = ( Structure * ) 1; @@ -422,7 +456,7 @@ namespace das { } } - void AstSerializer::fillOrPatchLater ( Variable * & ptr, uint64_t id ) { + void AstSerializer::fillOrPatchLater ( Variable * & ptr, SerializeNodeId id ) { auto it = smartVariableMap.find(id); if ( it == smartVariableMap.end() ) { ptr = ( Variable * ) 1; @@ -499,9 +533,9 @@ namespace das { template AstSerializer & AstSerializer::serializePointer ( TT * & ptr ) { - uint64_t fid = uintptr_t(ptr); + auto fid = getSerializeId(ptr); *this << fid; - if ( !fid ) { + if ( !fid.ptr ) { if ( !writing ) ptr = nullptr; return *this; } @@ -527,9 +561,9 @@ namespace das { if ( writing && func ) { SERIALIZER_VERIFYF(!func->builtIn, "cannot serialize built-in function"); } - uint64_t id = uint64_t(uintptr_t(func)); + auto id = getSerializeId(func); *this << id; - if ( id == 0 ) { + if ( id.ptr == 0 ) { if ( !writing ) func = nullptr; return *this; } @@ -555,7 +589,7 @@ namespace das { } else { string name; *this << name; string expect = func->name; - SERIALIZER_VERIFYF(name == expect, "expected different function"); + SERIALIZER_VERIFYF(name == expect, "expected different function %s %s", name.c_str(), expect.c_str()); } } return *this; @@ -563,9 +597,12 @@ namespace das { AstSerializer & AstSerializer::operator << ( TypeInfoMacro * & ptr ) { dtag(HASH_TAG("TypeInfoMacroPtr")); - uint64_t id = uintptr_t(ptr); - *this << id; - if ( !id ) { + // TypeInfoMacro is not gc_node and is always external (lives in another + // module). It is identified by name+module hash, so the wire form only + // needs a presence bit — no pointer/id leaks into the stream. + bool is_null = ptr == nullptr; + *this << is_null; + if ( is_null ) { if ( !writing ) ptr = nullptr; return *this; } @@ -591,7 +628,7 @@ namespace das { if ( !writing ) type = nullptr; return *this; } - uint64_t id = intptr_t(type); + auto id = getSerializeId(type); *this << id; if ( writing ) { if ( smartTypeDeclMap[id] == nullptr ) { @@ -777,9 +814,9 @@ namespace das { } AstSerializer & AstSerializer::operator << ( StructurePtr & struct_ ) { - uint64_t id = uint64_t(uintptr_t(struct_)); + auto id = getSerializeId(struct_); *this << id; - if ( id == 0 ) { + if ( id.ptr == 0 ) { if ( !writing ) struct_ = nullptr; return *this; } @@ -826,14 +863,14 @@ namespace das { return *this; } if ( writing ) { - uint64_t p = (uint64_t) ptr.get(); + auto p = getSerializeId(ptr.get()); *this << p; if ( fileAccessMap[p] == nullptr ) { fileAccessMap[p] = ptr.get(); ptr->serialize(*this); } } else { - uint64_t p = 0; *this << p; + SerializeNodeId p; *this << p; if ( fileAccessMap[p] == nullptr ) { uint8_t tag = 0; *this << tag; switch ( tag ) { @@ -852,32 +889,6 @@ namespace das { return *this; } - // This method creates concrete (i.e. non-polymorphic types without duplications) - template - void AstSerializer::serializeSmartPtr( smart_ptr & obj, das_hash_map> & objMap) { - uint64_t id = uint64_t(uintptr_t(obj.get())); - *this << id; - if ( id == 0 ) { - if ( !writing ) obj = nullptr; - return; - } - if ( writing ) { - if ( objMap.find(id) == objMap.end() ) { - objMap[id] = obj; - obj->serialize(*this); - } - } else { - auto it = objMap.find(id); - if ( it == objMap.end() ) { - obj = make_smart(); - objMap[id] = obj; - obj->serialize(*this); - } else { - obj = it->second; - } - } - } - AstSerializer & AstSerializer::operator << ( EnumerationPtr & enum_type ) { if ( writing ) { bool builtin = enum_type->module->builtIn && !enum_type->module->promoted; @@ -887,7 +898,7 @@ namespace das { string name = enum_type->name; *this << module << name; } else { - uint64_t id = uint64_t(uintptr_t(enum_type)); + auto id = getSerializeId(enum_type); *this << id; if ( smartEnumerationMap.find(id) == smartEnumerationMap.end() ) { smartEnumerationMap[id] = enum_type; @@ -906,9 +917,9 @@ namespace das { enum_type = pModule->findEnum(name); SERIALIZER_VERIFYF(enum_type, "expected to find enumeration '%llu'::'%s'", module, name.c_str()); } else { - uint64_t id = 0; + SerializeNodeId id; *this << id; - SERIALIZER_VERIFYF(id != 0, "expected non-null enumeration id"); + SERIALIZER_VERIFYF(id.ptr != 0, "expected non-null enumeration id"); auto it = smartEnumerationMap.find(id); if ( it == smartEnumerationMap.end() ) { enum_type = new Enumeration(); @@ -938,9 +949,9 @@ namespace das { } AstSerializer & AstSerializer::operator << ( VariablePtr & var ) { - uint64_t id = uint64_t(uintptr_t(var)); + auto id = getSerializeId(var); *this << id; - if ( id == 0 ) { + if ( id.ptr == 0 ) { if ( !writing ) var = nullptr; return *this; } @@ -1009,11 +1020,11 @@ namespace das { AstSerializer & AstSerializer::operator << ( ExprBlock * & block ) { dtag(HASH_TAG("ExprBlock*")); - void * addr = block; - *this << addr; - if ( !writing && addr ) { + auto id = getSerializeId(block); + *this << id; + if ( !writing && id.ptr ) { block = ( ExprBlock * ) 1; - blockRefs.emplace_back(&block, (uint64_t) addr); + blockRefs.emplace_back(&block, id); } return *this; } @@ -1328,447 +1339,602 @@ namespace das { } // Expressions +// +// Per-node serialization lives in SerializeVisitor. AstSerializer::operator<<(ExpressionPtr&) +// calls expr->dispatch(v), which selects the matching preVisit(ExprXxx*) override below. +// Helper methods serializeXxx(...) replicate the old virtual inheritance chain +// (ExprOp1 -> ExprOp -> ExprCallFunc -> ExprLooksLikeCall -> Expression) without +// relying on virtual dispatch inside this visitor. + + class SerializeVisitor : public Visitor { + AstSerializer & ser; + + void serializeBase ( Expression * expr ); + void serializeLooksLikeCall ( ExprLooksLikeCall * expr ); + void serializeCallFunc ( ExprCallFunc * expr ); + void serializeOp ( ExprOp * expr ); + void serializeOp2 ( ExprOp2 * expr ); + void serializeConst ( ExprConst * expr ); + void serializeMakeLocal ( ExprMakeLocal * expr ); + void serializeAt ( ExprAt * expr ); + void serializePtr2Ref ( ExprPtr2Ref * expr ); + void serializeField ( ExprField * expr ); + void serializeMakeArray ( ExprMakeArray * expr ); - void ExprReader::serialize ( AstSerializer & ser ) { + public: + explicit SerializeVisitor ( AstSerializer & s ) : ser(s) {} + using Visitor::preVisit; + + void preVisitExpression ( Expression * expr ) override; + void preVisit ( ExprReader * expr ) override; + void preVisit ( ExprLabel * expr ) override; + void preVisit ( ExprGoto * expr ) override; + void preVisit ( ExprRef2Value * expr ) override; + void preVisit ( ExprRef2Ptr * expr ) override; + void preVisit ( ExprPtr2Ref * expr ) override; + void preVisit ( ExprAddr * expr ) override; + void preVisit ( ExprNullCoalescing * expr ) override; + void preVisit ( ExprDelete * expr ) override; + void preVisit ( ExprAt * expr ) override; + void preVisit ( ExprSafeAt * expr ) override; + void preVisit ( ExprBlock * expr ) override; + void preVisit ( ExprVar * expr ) override; + void preVisit ( ExprTag * expr ) override; + void preVisit ( ExprField * expr ) override; + void preVisit ( ExprSafeAsVariant * expr ) override; + void preVisit ( ExprSwizzle * expr ) override; + void preVisit ( ExprSafeField * expr ) override; + void preVisit ( ExprLooksLikeCall * expr ) override; + void preVisit ( ExprCallMacro * expr ) override; + void preVisit ( ExprOp1 * expr ) override; + void preVisit ( ExprOp2 * expr ) override; + void preVisit ( ExprCopy * expr ) override; + void preVisit ( ExprMove * expr ) override; + void preVisit ( ExprClone * expr ) override; + void preVisit ( ExprOp3 * expr ) override; + void preVisit ( ExprTryCatch * expr ) override; + void preVisit ( ExprReturn * expr ) override; + void preVisit ( ExprConst * expr ) override; + void preVisit ( ExprConstPtr * expr ) override; + void preVisit ( ExprConstEnumeration * expr ) override; + void preVisit ( ExprConstBitfield * expr ) override; + void preVisit ( ExprConstString * expr ) override; + void preVisit ( ExprStringBuilder * expr ) override; + void preVisit ( ExprLet * expr ) override; + void preVisit ( ExprFor * expr ) override; + void preVisit ( ExprUnsafe * expr ) override; + void preVisit ( ExprWhile * expr ) override; + void preVisit ( ExprWith * expr ) override; + void preVisit ( ExprAssume * expr ) override; + void preVisit ( ExprMakeBlock * expr ) override; + void preVisit ( ExprMakeGenerator * expr ) override; + void preVisit ( ExprYield * expr ) override; + void preVisit ( ExprInvoke * expr ) override; + void preVisit ( ExprAssert * expr ) override; + void preVisit ( ExprQuote * expr ) override; + void preVisit ( ExprTypeInfo * expr ) override; + void preVisit ( ExprIs * expr ) override; + void preVisit ( ExprAscend * expr ) override; + void preVisit ( ExprCast * expr ) override; + void preVisit ( ExprNew * expr ) override; + void preVisit ( ExprCall * expr ) override; + void preVisit ( ExprIfThenElse * expr ) override; + void preVisit ( ExprNamedCall * expr ) override; + void preVisit ( ExprMakeStruct * expr ) override; + void preVisit ( ExprMakeVariant * expr ) override; + void preVisit ( ExprMakeArray * expr ) override; + void preVisit ( ExprMakeTuple * expr ) override; + void preVisit ( ExprArrayComprehension * expr ) override; + void preVisit ( ExprTypeDecl * expr ) override; + }; + + void SerializeVisitor::serializeBase ( Expression * expr ) { + ser << expr->at + << expr->type + << expr->genFlags + << expr->flags + << expr->printFlags; + ser.dtag(HASH_TAG("ptr_ref_count")); + } + + void SerializeVisitor::serializeLooksLikeCall ( ExprLooksLikeCall * expr ) { + serializeBase(expr); + ser << expr->name << expr->arguments; + ser << expr->argumentsFailedToInfer << expr->aliasSubstitution << expr->atEnclosure; + } + + void SerializeVisitor::serializeCallFunc ( ExprCallFunc * expr ) { + serializeLooksLikeCall(expr); + ser.serializePointer(expr->func); + ser << expr->stackTop; + } + + void SerializeVisitor::serializeOp ( ExprOp * expr ) { + serializeCallFunc(expr); + ser << expr->op; + } + + void SerializeVisitor::serializeOp2 ( ExprOp2 * expr ) { + serializeOp(expr); + ser << expr->left; + ser << expr->right; + } + + void SerializeVisitor::serializeConst ( ExprConst * expr ) { + serializeBase(expr); + ser << expr->baseType << expr->value << expr->foldedNonConst; + } + + void SerializeVisitor::serializeMakeLocal ( ExprMakeLocal * expr ) { + serializeBase(expr); + ser << expr->makeType << expr->stackTop << expr->extraOffset << expr->makeFlags; + } + + void SerializeVisitor::serializeAt ( ExprAt * expr ) { + ser.dtag(HASH_TAG("ExprAt")); + serializeBase(expr); + ser << expr->subexpr << expr->index; + ser << expr->atFlags; + } + + void SerializeVisitor::serializePtr2Ref ( ExprPtr2Ref * expr ) { + serializeBase(expr); + ser << expr->subexpr << expr->unsafeDeref << expr->assumeNoAlias; + } + + void SerializeVisitor::serializeField ( ExprField * expr ) { + ser.dtag(HASH_TAG("ExprField")); + serializeBase(expr); + ser << expr->value << expr->name << expr->atField + << expr->fieldIndex << expr->annotation << expr->derefFlags + << expr->fieldFlags; + + if ( ser.writing ) { + bool has_field = expr->value->type && ( + expr->value->type->isStructure() || ( expr->value->type->isPointer() && expr->value->type->firstType->isStructure() ) + ); + ser << has_field; + if ( !has_field ) return; + string mangledName; + if ( expr->value->type->isPointer() ) { + SERIALIZER_VERIFYF(expr->value->type->firstType->isStructure(), "expected to see structure field access via pointer"); + mangledName = expr->value->type->firstType->structType->getMangledName(); + ser << expr->value->type->firstType->structType->module; + } else { + SERIALIZER_VERIFYF(expr->value->type->isStructure(), "expected to see structure field access"); + mangledName = expr->value->type->structType->getMangledName(); + ser << expr->value->type->structType->module; + } + ser << mangledName; + if ( expr->annotation != nullptr && expr->annotation->getFieldOffset(expr->name) == static_cast(-1) ) { + LOG(LogLevel::warning) << "das: serialize: Field '" << expr->name << "' not found in '" << expr->annotation->name << "'"; + } + } else { + if ( expr->annotation != nullptr && expr->annotation->getFieldOffset(expr->name) == static_cast(-1) ) { + SERIALIZER_VERIFYF(false, "Field '%s' not found in '%s'", expr->name.c_str(), expr->annotation->name.c_str()); + } + bool has_field = false; ser << has_field; + if ( !has_field ) return; + Module * module = nullptr; ser << module; + string mangledName; ser << mangledName; + ser.fieldRefs.emplace_back(&expr->fieldRef, module, das::move(mangledName), expr->name); + } + } + + void SerializeVisitor::serializeMakeArray ( ExprMakeArray * expr ) { + serializeMakeLocal(expr); + ser << expr->recordType << expr->values << expr->gen2; + } + + void SerializeVisitor::preVisitExpression ( Expression * expr ) { + // ExprMakeLocal::dispatch routes here (no dedicated preVisit overload). + // ExprMakeLocal carries makeType/stackTop/extraOffset/makeFlags that + // serializeBase alone would drop, so detect it and use the proper helper. + if ( expr->rtti_isMakeLocal() ) { + serializeMakeLocal(static_cast(expr)); + return; + } + serializeBase(expr); + } + + void SerializeVisitor::preVisit ( ExprReader * expr ) { ser.dtag(HASH_TAG("ExprReader")); - Expression::serialize(ser); - ser << macro << sequence; + serializeBase(expr); + ser << expr->macro << expr->sequence; } - void ExprLabel::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprLabel * expr ) { ser.dtag(HASH_TAG("ExprLabel")); - Expression::serialize(ser); - ser << label << comment; + serializeBase(expr); + ser << expr->label << expr->comment; } - void ExprGoto::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprGoto * expr ) { ser.dtag(HASH_TAG("ExprGoto")); - Expression::serialize(ser); - ser << label << subexpr; + serializeBase(expr); + ser << expr->label << expr->subexpr; } - void ExprRef2Value::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprRef2Value * expr ) { ser.dtag(HASH_TAG("ExprRef2Value")); - Expression::serialize(ser); - ser << subexpr; + serializeBase(expr); + ser << expr->subexpr; } - void ExprRef2Ptr::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprRef2Ptr * expr ) { ser.dtag(HASH_TAG("ExprRef2Ptr")); - Expression::serialize(ser); - ser << subexpr; + serializeBase(expr); + ser << expr->subexpr; } - void ExprPtr2Ref::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprPtr2Ref * expr ) { ser.dtag(HASH_TAG("ExprPtr2Ref")); - Expression::serialize(ser); - ser << subexpr << unsafeDeref << assumeNoAlias; + serializePtr2Ref(expr); } - void ExprAddr::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprAddr * expr ) { ser.dtag(HASH_TAG("ExprAddr")); - Expression::serialize(ser); - ser << target << funcType; - ser.serializePointer(func); + serializeBase(expr); + ser << expr->target << expr->funcType; + ser.serializePointer(expr->func); } - void ExprNullCoalescing::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprNullCoalescing * expr ) { ser.dtag(HASH_TAG("ExprNullCoalescing")); - ExprPtr2Ref::serialize(ser); - ser << defaultValue; + serializePtr2Ref(expr); + ser << expr->defaultValue; } - void ExprDelete::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprDelete * expr ) { ser.dtag(HASH_TAG("ExprDelete")); - Expression::serialize(ser); - ser << subexpr << sizeexpr << native; + serializeBase(expr); + ser << expr->subexpr << expr->sizeexpr << expr->native; } - void ExprAt::serialize ( AstSerializer & ser ) { - ser.dtag(HASH_TAG("ExprAt")); - Expression::serialize(ser); - ser << subexpr << index; - ser << atFlags; + void SerializeVisitor::preVisit ( ExprAt * expr ) { + serializeAt(expr); } - void ExprSafeAt::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprSafeAt * expr ) { ser.dtag(HASH_TAG("ExprSafeAt")); - ExprAt::serialize(ser); + serializeAt(expr); } - void ExprBlock::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprBlock * expr ) { ser.dtag(HASH_TAG("ExprBlock")); - Expression::serialize(ser); + serializeBase(expr); if ( ser.writing ) { - void * thisBlock = this; - ser << thisBlock; + auto thisBlockId = ser.getSerializeId(expr); + ser << thisBlockId; } else { - void * thisBlock = nullptr; ser << thisBlock; - ser.exprBlockMap.emplace((uint64_t) thisBlock, this); + SerializeNodeId thisBlockId; ser << thisBlockId; + ser.exprBlockMap.emplace(thisBlockId, expr); } - ser << list << finalList << returnType << arguments << stackTop - << stackVarTop << stackVarBottom << stackCleanVars << maxLabelIndex - << annotationData << annotationDataSid << blockFlags; - ser.serializePointer(inFunction); + ser << expr->list << expr->finalList << expr->returnType << expr->arguments << expr->stackTop + << expr->stackVarTop << expr->stackVarBottom << expr->stackCleanVars << expr->maxLabelIndex + << expr->annotationData << expr->annotationDataSid << expr->blockFlags; + ser.serializePointer(expr->inFunction); - serializeAnnotationList(ser, annotations); + serializeAnnotationList(ser, expr->annotations); } - void ExprVar::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprVar * expr ) { ser.dtag(HASH_TAG("ExprVar")); - Expression::serialize(ser); + serializeBase(expr); - ser << name << argumentIndex << varFlags; - ser << pBlock; + ser << expr->name << expr->argumentIndex << expr->varFlags; + ser << expr->pBlock; // The variable is smart_ptr but we actually need // non-owning semantics if ( ser.writing ) { - bool inThisModule = variable == nullptr // this happens with [generic] functions, for example - || variable->module == nullptr - || variable->module == ser.thisModule; + bool inThisModule = expr->variable == nullptr // this happens with [generic] functions, for example + || expr->variable->module == nullptr + || expr->variable->module == ser.thisModule; ser << inThisModule; if ( inThisModule ) { - ser << variable; // serialize as smart pointer + ser << expr->variable; // serialize as smart pointer } else { - ser << variable->name; - ser << variable->module->nameHash; + ser << expr->variable->name; + ser << expr->variable->module->nameHash; } } else { bool inThisModule = false; ser << inThisModule; if ( inThisModule ) { - ser << variable; + ser << expr->variable; } else { string varname; uint64_t modname = 0; ser << varname << modname; auto mod = ser.moduleLibrary->findModuleByMangledNameHash(modname); SERIALIZER_VERIFYF(mod, "expected to find module '%llu'", modname); - variable = mod->findVariable(varname); + expr->variable = mod->findVariable(varname); } } } - void ExprTag::serialize ( AstSerializer & ser ) { + void SerializeVisitor::preVisit ( ExprTag * expr ) { ser.dtag(HASH_TAG("ExprTag")); - Expression::serialize(ser); - ser << subexpr << value << name; + serializeBase(expr); + ser << expr->subexpr << expr->value << expr->name; } - void ExprField::serialize ( AstSerializer & ser ) { - ser.dtag(HASH_TAG("ExprField")); - Expression::serialize(ser); - ser << value << name << atField - << fieldIndex << annotation << derefFlags - << fieldFlags; - - if ( ser.writing ) { - bool has_field = value->type && ( - value->type->isStructure() || ( value->type->isPointer() && value->type->firstType->isStructure() ) - ); - ser << has_field; - if ( !has_field ) return; - string mangledName; - if ( value->type->isPointer() ) { - SERIALIZER_VERIFYF(value->type->firstType->isStructure(), "expected to see structure field access via pointer"); - mangledName = value->type->firstType->structType->getMangledName(); - ser << value->type->firstType->structType->module; - } else { - SERIALIZER_VERIFYF(value->type->isStructure(), "expected to see structure field access"); - mangledName = value->type->structType->getMangledName(); - ser << value->type->structType->module; - } - ser << mangledName; - if ( annotation != nullptr && annotation->getFieldOffset(name) == static_cast(-1) ) { - LOG(LogLevel::warning) << "das: serialize: Field '" << name << "' not found in '" << annotation->name << "'"; - } - } else { - if ( annotation != nullptr && annotation->getFieldOffset(name) == static_cast(-1) ) { - SERIALIZER_VERIFYF("Field '%s' not found in '%s'", name.c_str(), annotation->name.c_str()); - } - bool has_field = false; ser << has_field; - if ( !has_field ) return; - Module * module = nullptr; ser << module; - string mangledName; ser << mangledName; - ser.fieldRefs.emplace_back(&fieldRef, module, das::move(mangledName), name); - } + void SerializeVisitor::preVisit ( ExprField * expr ) { + serializeField(expr); } - void ExprSafeAsVariant::serialize ( AstSerializer & ser ) { - ExprField::serialize(ser); - ser << skipQQ; + void SerializeVisitor::preVisit ( ExprSafeAsVariant * expr ) { + serializeField(expr); + ser << expr->skipQQ; } - void ExprSwizzle::serialize ( AstSerializer & ser ) { - Expression::serialize(ser); - ser << value << mask << fields << fieldFlags; + void SerializeVisitor::preVisit ( ExprSwizzle * expr ) { + serializeBase(expr); + ser << expr->value << expr->mask << expr->fields << expr->fieldFlags; } - void ExprSafeField::serialize ( AstSerializer & ser ) { - ExprField::serialize(ser); - ser << skipQQ; + void SerializeVisitor::preVisit ( ExprSafeField * expr ) { + serializeField(expr); + ser << expr->skipQQ; } - void ExprLooksLikeCall::serialize ( AstSerializer & ser ) { - Expression::serialize(ser); - ser << name << arguments; - ser << argumentsFailedToInfer << aliasSubstitution << atEnclosure; - } - - void ExprCallMacro::serialize ( AstSerializer & ser ) { - ExprLooksLikeCall::serialize(ser); - ser << macro; - ser.serializePointer(inFunction); - } - - void ExprCallFunc::serialize ( AstSerializer & ser ) { - ExprLooksLikeCall::serialize(ser); - ser.serializePointer(func); - ser << stackTop; + void SerializeVisitor::preVisit ( ExprLooksLikeCall * expr ) { + // ExprCallFunc::dispatch and ExprOp::dispatch route here (no dedicated + // preVisit overload). They carry func/stackTop/callFlags (and op for + // ExprOp) that serializeLooksLikeCall alone would drop, so detect them + // via __rtti and use the proper helper. + if ( expr->rtti_isCallFunc() ) { + if ( expr->__rtti && strcmp(expr->__rtti, "ExprOp") == 0 ) { + serializeOp(static_cast(expr)); + return; + } + serializeCallFunc(static_cast(expr)); + return; + } + serializeLooksLikeCall(expr); } - void ExprOp::serialize ( AstSerializer & ser ) { - ExprCallFunc::serialize(ser); - ser << op; + void SerializeVisitor::preVisit ( ExprCallMacro * expr ) { + serializeLooksLikeCall(expr); + ser << expr->macro; + ser.serializePointer(expr->inFunction); } - void ExprOp1::serialize ( AstSerializer & ser ) { - ExprOp::serialize(ser); - ser << subexpr; + void SerializeVisitor::preVisit ( ExprOp1 * expr ) { + serializeOp(expr); + ser << expr->subexpr; } - void ExprOp2::serialize ( AstSerializer & ser ) { - ExprOp::serialize(ser); - ser << left; - ser << right; + void SerializeVisitor::preVisit ( ExprOp2 * expr ) { + serializeOp2(expr); } - void ExprCopy::serialize ( AstSerializer & ser ) { - ExprOp2::serialize(ser); - ser << copyFlags; + void SerializeVisitor::preVisit ( ExprCopy * expr ) { + serializeOp2(expr); + ser << expr->copyFlags; } - void ExprMove::serialize ( AstSerializer & ser ) { - ExprOp2::serialize(ser); - ser << moveFlags; + void SerializeVisitor::preVisit ( ExprMove * expr ) { + serializeOp2(expr); + ser << expr->moveFlags; } - void ExprClone::serialize ( AstSerializer & ser ) { - ExprOp2::serialize(ser); + void SerializeVisitor::preVisit ( ExprClone * expr ) { + serializeOp2(expr); } - void ExprOp3::serialize ( AstSerializer & ser ) { - ExprOp::serialize(ser); - ser << subexpr << left << right; + void SerializeVisitor::preVisit ( ExprOp3 * expr ) { + serializeOp(expr); + ser << expr->subexpr << expr->left << expr->right; } - void ExprTryCatch::serialize ( AstSerializer & ser ) { - Expression::serialize(ser); - ser << try_block << catch_block; + void SerializeVisitor::preVisit ( ExprTryCatch * expr ) { + serializeBase(expr); + ser << expr->try_block << expr->catch_block; } - void ExprReturn::serialize ( AstSerializer & ser ) { - Expression::serialize(ser); - ser << subexpr << returnFlags << stackTop << refStackTop - << returnFunc << block << returnType; + void SerializeVisitor::preVisit ( ExprReturn * expr ) { + serializeBase(expr); + ser << expr->subexpr << expr->returnFlags << expr->stackTop << expr->refStackTop + << expr->returnFunc << expr->block << expr->returnType; } - void ExprConst::serialize ( AstSerializer & ser ) { - Expression::serialize(ser); - ser << baseType << value << foldedNonConst; + void SerializeVisitor::preVisit ( ExprConst * expr ) { + serializeConst(expr); } - void ExprConstPtr::serialize( AstSerializer & ser ) { - ExprConstT::serialize(ser); - ser << isSmartPtr << ptrType; + void SerializeVisitor::preVisit ( ExprConstPtr * expr ) { + serializeConst(expr); + ser << expr->isSmartPtr << expr->ptrType; } - void ExprConstEnumeration::serialize( AstSerializer & ser ) { - ExprConst::serialize(ser); - ser << enumType << text; + void SerializeVisitor::preVisit ( ExprConstEnumeration * expr ) { + serializeConst(expr); + ser << expr->enumType << expr->text; } - void ExprConstBitfield::serialize( AstSerializer & ser ) { - ExprConst::serialize(ser); - ser << bitfieldType; + void SerializeVisitor::preVisit ( ExprConstBitfield * expr ) { + serializeConst(expr); + ser << expr->bitfieldType; } - void ExprConstString::serialize(AstSerializer& ser) { - ExprConst::serialize(ser); - ser << text; + void SerializeVisitor::preVisit ( ExprConstString * expr ) { + serializeConst(expr); + ser << expr->text; } - void ExprStringBuilder::serialize(AstSerializer& ser) { - Expression::serialize(ser); - ser << elements << stringBuilderFlags; + void SerializeVisitor::preVisit ( ExprStringBuilder * expr ) { + serializeBase(expr); + ser << expr->elements << expr->stringBuilderFlags; } - void ExprLet::serialize(AstSerializer& ser) { - Expression::serialize(ser); - ser << variables << visibility << atInit << letFlags; + void SerializeVisitor::preVisit ( ExprLet * expr ) { + serializeBase(expr); + ser << expr->variables << expr->visibility << expr->atInit << expr->letFlags; } - void ExprFor::serialize(AstSerializer& ser) { - Expression::serialize(ser); - ser << iterators << iteratorsAka << iteratorsAt << iteratorsTupleExpansion << iteratorsTags - << iteratorVariables << sources << body << visibility - << allowIteratorOptimization << canShadow; + void SerializeVisitor::preVisit ( ExprFor * expr ) { + serializeBase(expr); + ser << expr->iterators << expr->iteratorsAka << expr->iteratorsAt << expr->iteratorsTupleExpansion << expr->iteratorsTags + << expr->iteratorVariables << expr->sources << expr->body << expr->visibility + << expr->allowIteratorOptimization << expr->canShadow; } - void ExprUnsafe::serialize(AstSerializer& ser) { - Expression::serialize(ser); - ser << body; + void SerializeVisitor::preVisit ( ExprUnsafe * expr ) { + serializeBase(expr); + ser << expr->body; } - void ExprWhile::serialize(AstSerializer& ser) { - Expression::serialize(ser); - ser << cond << body; + void SerializeVisitor::preVisit ( ExprWhile * expr ) { + serializeBase(expr); + ser << expr->cond << expr->body; } - void ExprWith::serialize(AstSerializer& ser) { - Expression::serialize(ser); - ser << with << body; + void SerializeVisitor::preVisit ( ExprWith * expr ) { + serializeBase(expr); + ser << expr->with << expr->body; } - void ExprAssume::serialize(AstSerializer& ser) { - Expression::serialize(ser); - ser << alias << subexpr << assumeType; + void SerializeVisitor::preVisit ( ExprAssume * expr ) { + serializeBase(expr); + ser << expr->alias << expr->subexpr << expr->assumeType; } - void ExprMakeBlock::serialize(AstSerializer & ser) { - Expression::serialize(ser); - ser << capture << captureAt << block << stackTop << mmFlags; + void SerializeVisitor::preVisit ( ExprMakeBlock * expr ) { + serializeBase(expr); + ser << expr->capture << expr->captureAt << expr->block << expr->stackTop << expr->mmFlags; } - void ExprMakeGenerator::serialize(AstSerializer & ser) { - ExprLooksLikeCall::serialize(ser); - ser << iterType << capture << captureAt; + void SerializeVisitor::preVisit ( ExprMakeGenerator * expr ) { + serializeLooksLikeCall(expr); + ser << expr->iterType << expr->capture << expr->captureAt; } - void ExprYield::serialize(AstSerializer & ser) { - Expression::serialize(ser); - ser << subexpr << returnFlags; + void SerializeVisitor::preVisit ( ExprYield * expr ) { + serializeBase(expr); + ser << expr->subexpr << expr->returnFlags; } - void ExprInvoke::serialize(AstSerializer & ser) { - ExprLikeCall::serialize(ser); - ser << stackTop << doesNotNeedSp << isInvokeMethod << cmresAlias; + void SerializeVisitor::preVisit ( ExprInvoke * expr ) { + serializeLooksLikeCall(expr); + ser << expr->stackTop << expr->doesNotNeedSp << expr->isInvokeMethod << expr->cmresAlias; } - void ExprAssert::serialize(AstSerializer & ser) { - ExprLikeCall::serialize(ser); - ser << isVerify; + void SerializeVisitor::preVisit ( ExprAssert * expr ) { + serializeLooksLikeCall(expr); + ser << expr->isVerify; } - void ExprQuote::serialize(AstSerializer & ser) { - ExprLikeCall::serialize(ser); + void SerializeVisitor::preVisit ( ExprQuote * expr ) { + serializeLooksLikeCall(expr); } - template - void ExprTableKeysOrValues::serialize(AstSerializer & ser) { - ExprLooksLikeCall::serialize(ser); + void SerializeVisitor::preVisit ( ExprTypeInfo * expr ) { + serializeBase(expr); + ser << expr->trait << expr->subexpr << expr->typeexpr << expr->subtrait << expr->extratrait << expr->macro; } - template - void ExprArrayCallWithSizeOrIndex::serialize(AstSerializer & ser) { - ExprLooksLikeCall::serialize(ser); + void SerializeVisitor::preVisit ( ExprIs * expr ) { + serializeBase(expr); + ser << expr->subexpr << expr->typeexpr; } - void ExprTypeInfo::serialize(AstSerializer & ser) { - Expression::serialize(ser); - ser << trait << subexpr << typeexpr << subtrait << extratrait << macro; + void SerializeVisitor::preVisit ( ExprAscend * expr ) { + serializeBase(expr); + ser << expr->subexpr << expr->ascType << expr->stackTop << expr->ascendFlags; } - void ExprIs::serialize(AstSerializer & ser) { - Expression::serialize(ser); - ser << subexpr << typeexpr; + void SerializeVisitor::preVisit ( ExprCast * expr ) { + serializeBase(expr); + ser << expr->subexpr << expr->castType << expr->castFlags; } - void ExprAscend::serialize(AstSerializer & ser) { - Expression::serialize(ser); - ser << subexpr << ascType << stackTop << ascendFlags; + void SerializeVisitor::preVisit ( ExprNew * expr ) { + serializeCallFunc(expr); + ser << expr->typeexpr << expr->initializer; } - void ExprCast::serialize(AstSerializer & ser) { - Expression::serialize(ser); - ser << subexpr << castType << castFlags; + void SerializeVisitor::preVisit ( ExprCall * expr ) { + serializeCallFunc(expr); + ser << expr->doesNotNeedSp << expr->cmresAlias; } - void ExprNew::serialize(AstSerializer & ser) { - ExprCallFunc::serialize(ser); - ser << typeexpr << initializer; + void SerializeVisitor::preVisit ( ExprIfThenElse * expr ) { + serializeBase(expr); + ser << expr->cond << expr->if_true << expr->if_false << expr->ifFlags; } - void ExprCall::serialize(AstSerializer & ser) { - ExprCallFunc::serialize(ser); - ser << doesNotNeedSp << cmresAlias; + void SerializeVisitor::preVisit ( ExprNamedCall * expr ) { + serializeBase(expr); + ser << expr->name << expr->nonNamedArguments << expr->arguments << expr->argumentsFailedToInfer; } - void ExprIfThenElse::serialize ( AstSerializer & ser ) { - Expression::serialize(ser); - ser << cond << if_true << if_false << ifFlags; + void SerializeVisitor::preVisit ( ExprMakeStruct * expr ) { + serializeMakeLocal(expr); + ser << expr->structs << expr->block << expr->makeStructFlags; + ser.serializePointer(expr->constructor); } - void MakeFieldDecl::serialize ( AstSerializer & ser ) { - ser << at << name << value << tag << flags; + void SerializeVisitor::preVisit ( ExprMakeVariant * expr ) { + serializeMakeLocal(expr); + ser << expr->variants; } - void MakeStruct::serialize( AstSerializer & ser ) { - ser << static_cast &> ( *this ); + void SerializeVisitor::preVisit ( ExprMakeArray * expr ) { + serializeMakeArray(expr); } - void ExprNamedCall::serialize ( AstSerializer & ser ) { - Expression::serialize(ser); - ser << name << nonNamedArguments << arguments << argumentsFailedToInfer; + void SerializeVisitor::preVisit ( ExprMakeTuple * expr ) { + serializeMakeArray(expr); + ser << expr->isKeyValue << expr->recordNames; } - void ExprMakeLocal::serialize ( AstSerializer & ser ) { - Expression::serialize(ser); - ser << makeType << stackTop << extraOffset << makeFlags; + void SerializeVisitor::preVisit ( ExprArrayComprehension * expr ) { + serializeBase(expr); + ser << expr->exprFor << expr->exprWhere << expr->subexpr << expr->generatorSyntax << expr->tableSyntax; } - void ExprMakeStruct::serialize ( AstSerializer & ser ) { - ExprMakeLocal::serialize(ser); - ser << structs << block << makeStructFlags; - ser.serializePointer(constructor); + void SerializeVisitor::preVisit ( ExprTypeDecl * expr ) { + serializeBase(expr); + ser << expr->typeexpr; } - void ExprMakeVariant::serialize ( AstSerializer & ser ) { - ExprMakeLocal::serialize(ser); - ser << variants; - } - - void ExprMakeArray::serialize ( AstSerializer & ser ) { - ExprMakeLocal::serialize(ser); - ser << recordType << values << gen2; - } - - void ExprMakeTuple::serialize ( AstSerializer & ser ) { - ExprMakeArray::serialize(ser); - ser << isKeyValue << recordNames; - } - - void ExprArrayComprehension::serialize ( AstSerializer & ser ) { - Expression::serialize(ser); - ser << exprFor << exprWhere << subexpr << generatorSyntax << tableSyntax; + AstSerializer & AstSerializer::operator << ( ExpressionPtr & expr ) { + dtag(HASH_TAG("ExpressionPtr")); + bool is_null = expr == nullptr; + *this << is_null; + if ( is_null ) { + if ( !writing ) expr = nullptr; + return *this; + } + SerializeVisitor sv(*this); + if ( writing ) { + uint32_t rtti = hash_tag(expr->__rtti); + DAS_ASSERT(rtti); + *this << rtti; + expr->dispatch(sv); + } else { + uint32_t rtti = 0; *this << rtti; + auto itA = rttiHash2Annotation.find(rtti); + SERIALIZER_VERIFYF(itA != rttiHash2Annotation.end(), "annotation '%u' is not found", rtti); + auto annotation = itA->second; + expr = (Expression *) static_cast(annotation)->factory(); + expr->dispatch(sv); + } + dtag(HASH_TAG("/ExpressionPtr")); + return *this; } - void ExprTypeDecl::serialize ( AstSerializer & ser ) { - Expression::serialize(ser); - ser << typeexpr; + void MakeFieldDecl::serialize ( AstSerializer & ser ) { + ser << at << name << value << tag << flags; } - void Expression::serialize ( AstSerializer & ser ) { - ser << at - << type - << genFlags - << flags - << printFlags; - ser.dtag(HASH_TAG("ptr_ref_count")); + void MakeStruct::serialize( AstSerializer & ser ) { + ser << static_cast &> ( *this ); } void FileInfo::serialize ( AstSerializer & ser ) { @@ -1913,13 +2079,13 @@ namespace das { uint64_t mnh = usedFun->getMangledNameHash(); ser << module << mnh; } else { - void * addr = usedFun; - ser << addr; + auto fid = ser.getSerializeId(usedFun); + ser << fid; } } } else { string fname; ser << fname; - SERIALIZER_VERIFYF(fname == f->name, "expected to serialize in the same order"); + SERIALIZER_VERIFYF(fname == f->name, "expected to serialize in the same order: %s != %s", fname.c_str(), f->name.c_str()); uint64_t size = 0; ser << size; f->useFunctions.reserve(size); for ( uint64_t i = 0; i < size; i++ ) { @@ -1935,8 +2101,8 @@ namespace das { SERIALIZER_VERIFYF(fun, "expected to find function"); f->useFunctions.emplace(fun); } else { - void * addr = nullptr; ser << addr; - auto fun = ser.smartFunctionMap[(uint64_t)(uintptr_t) addr]; + SerializeNodeId fid; ser << fid; + auto fun = ser.smartFunctionMap[fid]; SERIALIZER_VERIFYF(fun, "expected to find function"); f->useFunctions.emplace(fun); } @@ -1958,14 +2124,13 @@ namespace das { uint64_t mnh = usedFun->getMangledNameHash(); ser << module << mnh; } else { - // we serialize the address of the function (not the function itself - void * addr = usedFun; - ser << addr; + auto fid = ser.getSerializeId(usedFun); + ser << fid; } } } else { string name; ser << name; - SERIALIZER_VERIFYF(name == f->name, "expected to serialize in the same order"); + SERIALIZER_VERIFYF(name == f->name, "expected to serialize in the same order: %s != %s", name.c_str(), f->name.c_str()); uint64_t size = 0; ser << size; f->useFunctions.reserve(size); for ( uint64_t i = 0; i < size; i++ ) { @@ -1981,8 +2146,8 @@ namespace das { SERIALIZER_VERIFYF(fun, "expected to find function"); f->useFunctions.emplace(fun); } else { - void * addr = nullptr; ser << addr; - auto fun = ser.smartFunctionMap[(uint64_t)(uintptr_t) addr]; + SerializeNodeId fid; ser << fid; + auto fun = ser.smartFunctionMap[fid]; SERIALIZER_VERIFYF(fun, "expected to find function"); f->useFunctions.emplace(fun); } @@ -2004,13 +2169,13 @@ namespace das { string varname = use->name; ser << module << varname; } else { - void * addr = use; - ser << addr; + auto vid = ser.getSerializeId(use); + ser << vid; } } } else { string name; ser << name; - SERIALIZER_VERIFYF(name == f->name, "expected to serialize in the same order"); + SERIALIZER_VERIFYF(name == f->name, "expected to serialize in the same order: %s %s", name.c_str(), f->name.c_str()); uint64_t size = 0; ser << size; f->useGlobalVariables.reserve(size); for ( uint64_t i = 0; i < size; i++ ) { @@ -2026,8 +2191,8 @@ namespace das { SERIALIZER_VERIFYF(var, "expected to find variable '%s::%s'", pModule->name.c_str(), varname.c_str()); f->useGlobalVariables.emplace(var); } else { - void * addr = nullptr; ser << addr; - auto var = ser.smartVariableMap[(uint64_t)(uintptr_t) addr]; + SerializeNodeId vid; ser << vid; + auto var = ser.smartVariableMap[vid]; SERIALIZER_VERIFYF(var, "expected to find variable"); f->useGlobalVariables.emplace(var); } @@ -2049,13 +2214,13 @@ namespace das { string varname = use->name; ser << module << varname; } else { - void * addr = use; - ser << addr; + auto vid = ser.getSerializeId(use); + ser << vid; } } } else { string name; ser << name; - SERIALIZER_VERIFYF(name == f->name, "expected to serialize in the same order"); + SERIALIZER_VERIFYF(name == f->name, "expected to serialize in the same order: %s != %s", name.c_str(), f->name.c_str()); uint64_t size = 0; ser << size; f->useGlobalVariables.reserve(size); for ( uint64_t i = 0; i < size; i++ ) { @@ -2071,8 +2236,8 @@ namespace das { SERIALIZER_VERIFYF(var, "expected to find variable '%s::%s'", pModule->name.c_str(), varname.c_str()); f->useGlobalVariables.emplace(var); } else { - void * addr = nullptr; ser << addr; - auto var = ser.smartVariableMap[(uint64_t)(uintptr_t) addr]; + SerializeNodeId vid; ser << vid; + auto var = ser.smartVariableMap[vid]; SERIALIZER_VERIFYF(var, "expected to find variable"); f->useGlobalVariables.emplace(var); } @@ -2217,7 +2382,7 @@ namespace das { ser << f->name; } else { string fname; ser << fname; - SERIALIZER_VERIFYF(fname == f->name, "expected to walk in the same order"); + SERIALIZER_VERIFYF(fname == f->name, "expected to walk in the same order: %s != %s", fname.c_str(), f->name.c_str()); } serializeUseVariables(ser, f); serializeUseFunctions(ser, f); @@ -2228,18 +2393,20 @@ namespace das { ser << f->name; } else { string fname; ser << fname; - SERIALIZER_VERIFYF(fname == f->name, "expected to walk in the same order"); + SERIALIZER_VERIFYF(fname == f->name, "expected to walk in the same order: %s != %s", fname.c_str(), f->name.c_str()); } serializeUseVariables(ser, f); serializeUseFunctions(ser, f); }); - globals.foreach_with_hash ([&](VariablePtr g, uint64_t hash) { + globals.foreach ([&]( VariablePtr g ) { + uint64_t hash = hash64z(g->name.c_str()); if ( ser.writing ) { ser << hash; } else { uint64_t h = 0; ser << h; - SERIALIZER_VERIFYF(h == hash, "expected to walk in the same order"); + SERIALIZER_VERIFYF(h == hash, "expected to walk in the same order: %llu != %llu", + (unsigned long long) h, (unsigned long long) hash); } serializeUseVariables(ser, g); serializeUseFunctions(ser, g); @@ -2389,6 +2556,9 @@ namespace das { // Used in eden void AstSerializer::serializeProgram ( ProgramPtr program, ModuleGroup & libGroup ) noexcept { auto & ser = *this; + // Bump epoch so reused pointer addresses across program boundaries + // get distinct SerializeNodeIds on this persistent serializer. + ser.epoch++; ser << program->thisNamespace << program->thisModuleName; @@ -2487,7 +2657,13 @@ namespace das { } // drop ref_counts + smartEnumerationMap.clear(); + smartStructureMap.clear(); + smartVariableMap.clear(); + smartFunctionMap.clear(); + smartMakeStructMap.clear(); smartTypeDeclMap.clear(); + exprBlockMap.clear(); } uint32_t AstSerializer::getVersion () { @@ -2511,6 +2687,10 @@ namespace das { // Used in daNetGame currently void Program::serialize ( AstSerializer & ser ) { + // Bump epoch so reused pointer addresses across program boundaries + // get distinct SerializeNodeIds on this persistent serializer. + ser.epoch++; + ser << thisNamespace << thisModuleName; ser << totalFunctions << totalVariables << newLambdaIndex; @@ -2628,7 +2808,7 @@ namespace das { AstSerializerState * rtti_create_ast_serializer () { auto state = new AstSerializerState(); state->storage = make_unique(); - // state->serializer = make_unique(state->storage.get(), true); + state->serializer = make_unique(state->storage.get(), true); return state; } @@ -2636,13 +2816,13 @@ namespace das { auto state = new AstSerializerState(); state->storage = make_unique(); state->storage->buffer.assign(data.data, data.data + data.size); - // state->serializer = make_unique(state->storage.get(), false); + state->serializer = make_unique(state->storage.get(), false); return state; } void rtti_delete_ast_serializer ( AstSerializerState * state ) { if ( state ) { - //state->serializer->moduleLibrary = nullptr; + state->serializer->moduleLibrary = nullptr; delete state; } } @@ -2651,9 +2831,7 @@ namespace das { AstSerializerState * state, const smart_ptr & program ) { auto & prog = const_cast &>(program); - auto serializer = make_unique(state->storage.get(), true); - prog->serialize(*serializer); - serializer->moduleLibrary = nullptr; + prog->serialize(*state->serializer); return !prog->failToCompile; } @@ -2664,9 +2842,7 @@ namespace das { auto prog = make_smart(); { gc_guard deserialize_gc_scope; - auto serializer = make_unique(state->storage.get(), false); - prog->serialize(*serializer); - serializer->moduleLibrary = nullptr; + prog->serialize(*state->serializer); /* // THIS ONES ARE FROM THE "already exist" MODULES auto leftover = deserialize_gc_scope.guard_root.gc_count; @@ -2676,15 +2852,27 @@ namespace das { } */ } + // Module::serialize leaves g_Program pointing to a temporary program with a + // released thisModule. Restore it so compiling_module() sees the correct module + // during simulate() and while tests run inside the block. + auto & bound = *daScriptEnvironment::getBound(); + auto savedProg = bound.g_Program; + bound.g_Program = prog.get(); if ( prog->failToCompile ) { string err = "deserialization failed"; das_invoke::invoke,const string &>( context, at, block, false, ProgramPtr(), err); + (void)prog->thisModule.release(); + prog->library.reset(); + bound.g_Program = savedProg; return; } string okStr; das_invoke::invoke,const string &>( context, at, block, true, prog, okStr); + (void)prog->thisModule.release(); + prog->library.reset(); + bound.g_Program = savedProg; } void rtti_ast_serializer_get_data ( diff --git a/tests/README.md b/tests/README.md index 66f8a0250e..c63df3332a 100644 --- a/tests/README.md +++ b/tests/README.md @@ -4,6 +4,8 @@ Every `.das` file in this directory tree is listed below, grouped by subdirectory. Files marked **expect** use `expect` directives and are expected to produce specific compile errors. Helper/module files that are not standalone tests are marked *(helper)*. +**Naming convention for expected-failure tests:** Files that are expected to *fail compilation* use one of three filename prefixes: `failed_`, `cant_`, or `invalid_`. Tools that need to skip files with no compilable AST (e.g. `--ser` serialization passes) should filter on these three prefixes. + ## live_host/ > **Note:** These tests require the dasLiveHost module. Skipped automatically via `.das_test` when the module is not available. Run separately: `dastest -- --test tests/live_host/` diff --git a/tests/aot/CMakeLists.txt b/tests/aot/CMakeLists.txt index 2576d00547..3c6bad2f41 100644 --- a/tests/aot/CMakeLists.txt +++ b/tests/aot/CMakeLists.txt @@ -251,7 +251,7 @@ FILE(GLOB AOT_LINQ_FILES RELATIVE ${PROJECT_SOURCE_DIR} CONFIGURE_DEPENDS "tests # Exclude module files (they are compiled via DAS_AOT_LIB below) and # expect-error tests (use `expect` to assert intentional macro_failed # diagnostics; AOT cannot compile them) -list(FILTER AOT_LINQ_FILES EXCLUDE REGEX "/_|_errors\\.das$") +list(FILTER AOT_LINQ_FILES EXCLUDE REGEX "/_|failed_") # Linq test module files (libraries required by linq tests) SET(AOT_LINQ_MODULE_FILES @@ -295,7 +295,7 @@ FILE(GLOB AOT_SPOOF_FILES RELATIVE ${PROJECT_SOURCE_DIR} CONFIGURE_DEPENDS "test # AOT for strings test files FILE(GLOB AOT_STRINGS_FILES RELATIVE ${PROJECT_SOURCE_DIR} CONFIGURE_DEPENDS "tests/strings/*.das") # Exclude expect-error tests -list(FILTER AOT_STRINGS_FILES EXCLUDE REGEX "_failed") +list(FILTER AOT_STRINGS_FILES EXCLUDE REGEX "failed_") # AOT for template test files FILE(GLOB AOT_TEMPLATE_FILES RELATIVE ${PROJECT_SOURCE_DIR} CONFIGURE_DEPENDS "tests/template/*.das") diff --git a/tests/constexpr/test_constexpr_fail.das b/tests/constexpr/failed_test_constexpr.das similarity index 100% rename from tests/constexpr/test_constexpr_fail.das rename to tests/constexpr/failed_test_constexpr.das diff --git a/tests/interfaces/test_missing_inherited.das b/tests/interfaces/failed_test_missing_inherited.das similarity index 100% rename from tests/interfaces/test_missing_inherited.das rename to tests/interfaces/failed_test_missing_inherited.das diff --git a/tests/interfaces/test_missing_method.das b/tests/interfaces/failed_test_missing_method.das similarity index 100% rename from tests/interfaces/test_missing_method.das rename to tests/interfaces/failed_test_missing_method.das diff --git a/tests/language/failed_containers_failed.das b/tests/language/failed_failed_containers.das similarity index 100% rename from tests/language/failed_containers_failed.das rename to tests/language/failed_failed_containers.das diff --git a/tests/language/failed_local_classes_failed.das b/tests/language/failed_failed_local_classes.das similarity index 100% rename from tests/language/failed_local_classes_failed.das rename to tests/language/failed_failed_local_classes.das diff --git a/tests/linq/test_linq_join_errors.das b/tests/linq/failed_test_linq_join.das similarity index 100% rename from tests/linq/test_linq_join_errors.das rename to tests/linq/failed_test_linq_join.das diff --git a/tests/strings/temporary_strings_failed.das b/tests/strings/failed_temporary_strings.das similarity index 100% rename from tests/strings/temporary_strings_failed.das rename to tests/strings/failed_temporary_strings.das diff --git a/tests/unsafe/unsafe_reference.das b/tests/unsafe/failed_unsafe_reference.das similarity index 100% rename from tests/unsafe/unsafe_reference.das rename to tests/unsafe/failed_unsafe_reference.das diff --git a/tests/verify/test_verify_completion.das b/tests/verify/failed_test_verify_completion.das similarity index 100% rename from tests/verify/test_verify_completion.das rename to tests/verify/failed_test_verify_completion.das diff --git a/web/CMakeLists.txt b/web/CMakeLists.txt index d8bca88dee..03cdb357f9 100644 --- a/web/CMakeLists.txt +++ b/web/CMakeLists.txt @@ -324,6 +324,7 @@ SOURCE_GROUP_FILES("vecmath" VECMATH_SRC) SET(AST_SRC ../src/ast/ast.cpp +../src/ast/ast_dispatch.cpp ../src/ast/ast_interop.cpp ../src/ast/ast_tls.cpp ../src/ast/ast_visitor.cpp