diff --git a/Compiler/CMakeLists.txt b/Compiler/CMakeLists.txt index 70f94c499c3..e108beb79b8 100644 --- a/Compiler/CMakeLists.txt +++ b/Compiler/CMakeLists.txt @@ -22,7 +22,7 @@ SET(SRCMO Absyn.mo AbsynDep.mo Algorithm.mo Builtin.mo SET(ALLMO ${SRCMO} DAEEXT.mo DynLoad.mo Print.mo System.mo Parser.mo TaskGraphExt.mo Corba.mo Socket.mo ErrorExt.mo Settings.mo - UnitParserExt.mo SimulationResults.mo) + UnitParserExt.mo SimulationResults.mo Serializer.mo) # RML IF(NOT RML) diff --git a/Compiler/FrontEnd/Expression.mo b/Compiler/FrontEnd/Expression.mo index 9be665d2d4f..dfc19613d88 100644 --- a/Compiler/FrontEnd/Expression.mo +++ b/Compiler/FrontEnd/Expression.mo @@ -1116,6 +1116,25 @@ algorithm end match; end unliftExp; +public function liftExp + input DAE.Exp inExp; + input DAE.Dimension inDimension; + output DAE.Exp outExp; +algorithm + outExp := DAE.ARRAY(Types.liftArray(typeof(inExp), inDimension), + false, List.fill(inExp, dimensionSize(inDimension))); +end liftExp; + +public function liftExpList + input DAE.Exp inExp; + input list inDimensions; + output DAE.Exp outExp = inExp; +algorithm + for dim in listReverse(inDimensions) loop + outExp := liftExp(outExp, dim); + end for; +end liftExpList; + public function liftArrayRight " This function adds an array dimension to a type on the right side, i.e. liftArrayRigth(Real[2,3],SOME(4)) => Real[2,3,4]. diff --git a/Compiler/FrontEnd/InstVar.mo b/Compiler/FrontEnd/InstVar.mo index 591192c0eae..8b8dbdbb80d 100644 --- a/Compiler/FrontEnd/InstVar.mo +++ b/Compiler/FrontEnd/InstVar.mo @@ -590,6 +590,7 @@ algorithm attr := inAttributes; else // Userdefined array type, e.g. type Point = Real[3]. + type_mods := liftUserTypeMod(type_mods, inDimensions); dims := listAppend(inDimensions, dims); mod := Mod.merge(inMod, type_mods, inEnv, inPrefix); attr := InstUtil.propagateClassPrefix(inAttributes, inPrefix); @@ -615,6 +616,83 @@ algorithm end try; end instVar_dispatch; +protected function liftUserTypeMod + "This function adds dimensions to a modifier. This is a bit of a hack to make + modifiers on user-defined types behave as expected, e.g.: + + type T = Real[3](start = {1, 2, 3}); + T x[2]; // Modifier from T must be lifted to become [2, 3]. + " + input DAE.Mod inMod; + input list inDims; + output DAE.Mod outMod = inMod; +algorithm + if listEmpty(inDims) then + return; + end if; + + outMod := matchcontinue outMod + case DAE.MOD() + algorithm + // Only lift modifiers without 'each'. + if not SCode.eachBool(outMod.eachPrefix) then + outMod.eqModOption := liftUserTypeEqMod(outMod.eqModOption, inDims); + outMod.subModLst := list(liftUserTypeSubMod(s, inDims) for s in outMod.subModLst); + end if; + then + outMod; + + else outMod; + end matchcontinue; +end liftUserTypeMod; + +protected function liftUserTypeSubMod + input DAE.SubMod inSubMod; + input list inDims; + output DAE.SubMod outSubMod = inSubMod; +algorithm + outSubMod := match outSubMod + case DAE.NAMEMOD() + algorithm + outSubMod.mod := liftUserTypeMod(outSubMod.mod, inDims); + then + outSubMod; + end match; +end liftUserTypeSubMod; + +protected function liftUserTypeEqMod + input Option inEqMod; + input list inDims; + output Option outEqMod; +protected + DAE.EqMod eq; + DAE.Type ty; +algorithm + if isNone(inEqMod) then + outEqMod := inEqMod; + return; + end if; + + SOME(eq) := inEqMod; + + eq := match eq + case DAE.TYPED() + algorithm + eq.modifierAsExp := Expression.liftExpList(eq.modifierAsExp, inDims); + eq.modifierAsValue := Util.applyOption1(eq.modifierAsValue, + ValuesUtil.liftValueList, inDims); + ty := Types.getPropType(eq.properties); + eq.properties := Types.setPropType(eq.properties, + Types.liftArrayListDims(ty, inDims)); + then + eq; + + else eq; + end match; + + outEqMod := SOME(eq); +end liftUserTypeEqMod; + protected function addArrayVarEquation input FCore.Cache inCache; input FCore.Graph inEnv; diff --git a/Compiler/FrontEnd/Types.mo b/Compiler/FrontEnd/Types.mo index e159f337aaf..ce27dd63570 100644 --- a/Compiler/FrontEnd/Types.mo +++ b/Compiler/FrontEnd/Types.mo @@ -3786,10 +3786,9 @@ public function getPropType "author: LS input DAE.Properties inProperties; output DAE.Type outType; algorithm - outType := match (inProperties) - local Type ty; - case DAE.PROP(type_ = ty) then ty; - case DAE.PROP_TUPLE(type_ = ty) then ty; + outType := match inProperties + case DAE.PROP() then inProperties.type_; + case DAE.PROP_TUPLE() then inProperties.type_; end match; end getPropType; @@ -3798,12 +3797,9 @@ public function setPropType "Set the Type from Properties." input DAE.Type ty; output DAE.Properties outProperties; algorithm - outProperties := match (inProperties,ty) - local - DAE.Const constFlag; - DAE.TupleConst tupleConst; - case (DAE.PROP(constFlag = constFlag),_) then DAE.PROP(ty,constFlag); - case (DAE.PROP_TUPLE(tupleConst = tupleConst),_) then DAE.PROP_TUPLE(ty,tupleConst); + outProperties := match inProperties + case DAE.PROP() then DAE.PROP(ty, inProperties.constFlag); + case DAE.PROP_TUPLE() then DAE.PROP_TUPLE(ty, inProperties.tupleConst); end match; end setPropType; diff --git a/Compiler/FrontEnd/ValuesUtil.mo b/Compiler/FrontEnd/ValuesUtil.mo index c322e2088c6..e5893455ba8 100644 --- a/Compiler/FrontEnd/ValuesUtil.mo +++ b/Compiler/FrontEnd/ValuesUtil.mo @@ -2582,5 +2582,15 @@ algorithm end for; end arrayContainsEmpty; +public function liftValueList + input Values.Value inValue; + input list inDimensions; + output Values.Value outValue = inValue; +algorithm + for dim in listReverse(inDimensions) loop + outValue := makeArray(List.fill(outValue, Expression.dimensionSize(dim))); + end for; +end liftValueList; + annotation(__OpenModelica_Interface="frontend"); end ValuesUtil; diff --git a/Compiler/SimCode/SimCodeUtil.mo b/Compiler/SimCode/SimCodeUtil.mo index 9fc7001043d..3de9b76209f 100644 --- a/Compiler/SimCode/SimCodeUtil.mo +++ b/Compiler/SimCode/SimCodeUtil.mo @@ -14835,13 +14835,15 @@ author: waurich TUD 2015-05" protected list vars, states; list idcs; + array markVars; algorithm vars := BackendDAEUtil.getAllVarLst(inDAE); states := List.filterOnTrue(vars, BackendVariable.isStateVar); if listEmpty(states) then highestDerivation := 0; else - idcs := List.map2(states,getHighestDerivation1,BackendVariable.listVar1(states),0); + markVars := arrayCreate(listLength(states),false); + idcs := List.map3(states,getHighestDerivation1,BackendVariable.listVar1(states),markVars,0); highestDerivation := List.fold(idcs,intMax,0); end if; end getHighestDerivation; @@ -14850,22 +14852,30 @@ protected function getHighestDerivation1"checks if a state is the derivative of author: waurich TUD 2015-05" input BackendDAE.Var stateIn; input BackendDAE.Variables allStates; + input array markVarsIn; input Integer derivationIn; output Integer derivationOut; algorithm - derivationOut := matchcontinue(stateIn,allStates,derivationIn) + derivationOut := matchcontinue(stateIn,allStates,markVarsIn,derivationIn) local - Integer index; + Integer index, pos; + array markVars; BackendDAE.Var var; DAE.ComponentRef derCref; - case(BackendDAE.VAR(varKind=BackendDAE.STATE(index=index,derName = SOME(derCref))),_,_) + case(BackendDAE.VAR(varKind=BackendDAE.STATE(index=index,derName = SOME(derCref))),_,_,_) algorithm // try to find the derivative in the states - ({var},_) := BackendVariable.getVar(derCref, allStates); + ({var},{pos}) := BackendVariable.getVar(derCref, allStates); + // has this var already been checked or is the derivative the var itself? + false := arrayGet(markVarsIn,pos); false := BackendVariable.varEqual(stateIn,var); - true := false; - then getHighestDerivation1(var,allStates,derivationIn+1); + markVars := arrayUpdate(markVarsIn,pos,true); + then getHighestDerivation1(var,allStates,markVars,derivationIn+1); else + algorithm + for i in List.intRange(arrayLength(markVarsIn)) loop + _ := arrayUpdate(markVarsIn,i,false); + end for; then derivationIn+1; end matchcontinue; end getHighestDerivation1; diff --git a/Compiler/Template/CodegenCppHpcom.tpl b/Compiler/Template/CodegenCppHpcom.tpl index 81d5b3fdd45..1f929b74ae6 100644 --- a/Compiler/Template/CodegenCppHpcom.tpl +++ b/Compiler/Template/CodegenCppHpcom.tpl @@ -421,6 +421,7 @@ template generateAdditionalConstructorBodyStatements(Option tt hasindex i0 fromindex 0 => generateThread(i0, type, modelNamePrefixStr,"evaluateThreadFunc"); separator="\n" << + omp_set_dynamic(0); <%threadFuncs%> <%initlocksOde%> <%initlocksDae%> @@ -458,6 +459,7 @@ template generateAdditionalConstructorBodyStatements(Option >> else "" @@ -744,7 +746,6 @@ template generateParallelEvaluate(list allEquationsPlusWhen, Absyn. { this->_evaluateODE = evaluateODE; this->_command = command; - omp_set_dynamic(1); <%&varDecls%> if(_evaluateODE) { @@ -1028,28 +1029,30 @@ template function_HPCOM_Thread(list allEquationsPlusWhen, array tt hasindex i0 fromindex 0 => function_HPCOM_releaseThreadLocks(arrayGet(threadTasksDae, intAdd(i0, 1)), "_lockDae", i0, iType); separator="\n" << - if (omp_get_dynamic()) - omp_set_dynamic(0); #pragma omp parallel num_threads(<%arrayLength(threadTasksOde)%>) { int threadNum = omp_get_thread_num(); - //Assign locks first - <%threadAssignLocksOde%> - <%threadAssignLocksDae%> - #pragma omp barrier if(_evaluateODE) { + //Assign locks first + <%threadAssignLocksOde%> + #pragma omp barrier <%odeEqs%> + //Release locks after calculation + #pragma omp barrier + <%threadReleaseLocksOde%> } else { + //Assign locks first + <%threadAssignLocksDae%> + #pragma omp barrier <%daeEqs%> + //Release locks after calculation + #pragma omp barrier + <%threadReleaseLocksDae%> } - #pragma omp barrier - //Release locks after calculation - <%threadReleaseLocksOde%> - <%threadReleaseLocksDae%> } >> case ("mpi") then diff --git a/Compiler/Template/SimCodeTV.mo b/Compiler/Template/SimCodeTV.mo index 3d8eb8b4829..a321539393f 100644 --- a/Compiler/Template/SimCodeTV.mo +++ b/Compiler/Template/SimCodeTV.mo @@ -140,13 +140,6 @@ package builtin output Real z; end realDiv; - function listGet - replaceable type TypeVar subtypeof Any; - input list lst; - input Integer index; - output TypeVar result; - end listGet; - function stringLength input String str; output Integer length; diff --git a/Compiler/Util/Serializer.mo b/Compiler/Util/Serializer.mo new file mode 100644 index 00000000000..afa081937a1 --- /dev/null +++ b/Compiler/Util/Serializer.mo @@ -0,0 +1,62 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + + +encapsulated package Serializer +"file: Serializer.mo + package: Serializer + description: External Stream Utilities + @author: Leonardo Laguna Ruiz [leonardo@wolfram.com] + @date: 2015-05-19 + + RCS: $Id$ + + This package provides functions to serialize MetaModelica data. + The external C implementation is in TOP/Compiler/runtime/Serializer.c" + + +public function outputFile " +Prints the structure of the object." + input T object; + input String filename; + external "C" Serializer_outputFile(object,filename) annotation(Library = {"omcruntime"}); +end outputFile; + +public function bypass " +Serializes the object and reads it back. This function is used for testing purposes." + input T object; + output T out_object; + external "C" out_object = Serializer_bypass(object) annotation(Library = {"omcruntime"}); +end bypass; + + +annotation(__OpenModelica_Interface="util"); +end Serializer; diff --git a/Compiler/boot/LoadCompilerSources.mos b/Compiler/boot/LoadCompilerSources.mos index a1572608baf..9e004322044 100644 --- a/Compiler/boot/LoadCompilerSources.mos +++ b/Compiler/boot/LoadCompilerSources.mos @@ -293,7 +293,8 @@ if true then /* Suppress output */ "../Util/System.mo", "../Util/Util.mo", "../Util/VarTransform.mo", - "../Util/VisualXML.mo" + "../Util/VisualXML.mo", + "../Util/Serializer.mo" }; LoadCompilerSourcesRes:= OpenModelica.Scripting.loadFiles(files,numThreads=min(5,OpenModelica.Scripting.numProcessors())); if not LoadCompilerSourcesRes then diff --git a/Compiler/runtime/CMakeLists.txt b/Compiler/runtime/CMakeLists.txt index ed4aaa4fa4c..d2515fb6a29 100644 --- a/Compiler/runtime/CMakeLists.txt +++ b/Compiler/runtime/CMakeLists.txt @@ -33,7 +33,7 @@ ADD_CUSTOM_TARGET(omc_communication ALL DEPENDS ${IDL_OUTPUT}) SET(CORBASRC ${IDL_OUTPUT} omc_communication_impl.cpp corbaimpl.cpp) SET(SRC socketimpl.c printimpl.c systemimpl.c settingsimpl.c SimulationResults.c) SET(CPPSRC unitparser.cpp unitparserext.cpp ptolemyio.cpp Dynload.cpp BackendDAEEXT.cpp ErrorMessage.cpp errorext.cpp - systemimplmisc.cpp ${CORBASRC}) + systemimplmisc.cpp ${CORBASRC} serializer.cpp) SET(OBJ ${SRC} ${CPPSRC}) IF(WIN32) diff --git a/Compiler/runtime/Makefile.common b/Compiler/runtime/Makefile.common index 95799ef66a8..9000f70edf7 100644 --- a/Compiler/runtime/Makefile.common +++ b/Compiler/runtime/Makefile.common @@ -19,7 +19,7 @@ else configUnix = endif -OMC_OBJ = Error_omc.o Print_omc.o System_omc.o Settings_omc.o \ +OMC_OBJ = Error_omc.o Print_omc.o System_omc.o Settings_omc.o serializer.o \ IOStreamExt_omc.o ErrorMessage.o FMI_omc.o systemimplmisc.o \ UnitParserExt_omc.o unitparser.o BackendDAEEXT_omc.o Socket_omc.o matching.o matching_cheap.o \ Database_omc.o Dynload_omc.o SimulationResults_omc.o TaskGraphResults_omc.o HpcOmSchedulerExt_omc.o HpcOmBenchmarkExt_omc.o ptolemyio_omc.o \ @@ -58,6 +58,7 @@ ptolemyio_omc.o : ptolemyio.cpp errorext.h $(RML_COMPAT) ErrorMessage.o : ErrorMessage.cpp ErrorMessage.hpp errorext.h FMI_omc.o : FMIImpl.c ../OpenModelicaBootstrappingHeader.h GraphStreamExt_omc.o : ../OpenModelicaBootstrappingHeader.h GraphStreamExt_impl.cpp $(RML_COMPAT) +serializer.o: serializer.cpp clean: $(RM) -rf *.a *.o omc_communication.cc omc_communication.h omc_communication-* diff --git a/Compiler/runtime/serializer.cpp b/Compiler/runtime/serializer.cpp new file mode 100644 index 00000000000..45d585da2a6 --- /dev/null +++ b/Compiler/runtime/serializer.cpp @@ -0,0 +1,682 @@ + + +#include +//#include +#include +#include +#include +#include +#include "meta_modelica.h" +#include + +extern "C" +{ + + +/* This is used to keep track of generated record_description, + that way we don't generate new every time something is de-serialized */ +std::map record_cache; + + +static const uint8_t TAG_INT_TINY = 0x00; +static const uint8_t TAG_INT_SMALL = 0x10; +static const uint8_t TAG_INT_BIG = 0x20; +static const uint8_t TAG_DOUBLE = 0x30; +static const uint8_t TAG_STRING_SMALL = 0x40; +static const uint8_t TAG_STRING_BIG = 0x50; +static const uint8_t TAG_STRUCT_SMALL = 0x60; +static const uint8_t TAG_STRUCT_BIG = 0x70; +static const uint8_t TAG_SHARED_TINY = 0x80; +static const uint8_t TAG_SHARED_SMALL = 0x90; +static const uint8_t TAG_SHARED_BIG = 0xA0; + + +/* SERIALIZATION */ + +/* Writes 8 bits to the buffer */ +void write8(uint8_t v0,std::string& buffer){ + buffer.push_back(v0); + //printf("%02X ",v0); +} + +/* Writes 16 bits to the buffer */ +void write16(uint16_t v0,std::string& buffer){ + uint8_t h = (v0 & 0xFF00)>>8; + uint8_t l = v0 & 0xFF; + buffer.push_back(h); + buffer.push_back(l); + //printf("%02X ",h); + //printf("%02X ",l); +} + +/* Writes 32 bits to the buffer */ +void write32(uint32_t v0,std::string& buffer){ + write16((v0>>16) & 0xFFFF,buffer); + write16(v0 & 0xFFFF,buffer); +} + +/* Writes 64 bits to the buffer */ +void write64(uint64_t v0,std::string& buffer){ + write32((v0>>32) & 0xFFFFFFFF,buffer); + write32(v0 & 0xFFFFFFFF,buffer); +} + +/* Writes a tag value */ +void writeTag(uint8_t v0,std::string& buffer){ + write8(v0,buffer); +} + +/* Writes an integer considering the required size */ +void writeInt(mmc_sint_t value,std::string& buffer){ + if(value >= -8 && value <= 7){ // tiny integer + writeTag(TAG_INT_TINY | (0x0F & value),buffer); + } + else if(value >= -2147483648 && value <= 2147483647) // regular 32 signed int + { + int32_t cropped = value; + uint32_t* pv = (uint32_t*)&cropped; + writeTag(TAG_INT_SMALL,buffer); + write32(*pv,buffer); + } + else + { + int64_t cropped = value; + uint64_t* pv = (uint64_t*)&cropped; + writeTag(TAG_INT_BIG,buffer); + write64(*pv,buffer); + } + +} + +/* Writes an real value always as 64 bits */ +void writeReal(double value,std::string& buffer){ + writeTag(TAG_DOUBLE,buffer); // double -> 3 + unsigned long long* ivalue = (unsigned long long*) &value; + write64(*ivalue,buffer); +} + +/* Writes a string considering the required size */ +void writeString(mmc_uint_t size,const char* data,std::string& buffer){ + if(size<256){ + writeTag(TAG_STRING_SMALL,buffer); + write8(size,buffer); + } + else { + writeTag(TAG_STRING_BIG,buffer); + write64(size,buffer); + } + mmc_uint_t i = 0; + while(i ",index); + if(index<=0xFFFF){ + writeTag(TAG_SHARED_TINY,buffer); + write16(index,buffer); + } + else if(index <= 0xFFFFFFFF) + { + writeTag(TAG_SHARED_SMALL,buffer); + write32(index,buffer); + } + else + { + writeTag(TAG_SHARED_BIG,buffer); + write64(index,buffer); + } + //printf("\n"); +} + +/* Tries to insert the object to the seen-object list. If it has been found before it writes a shared object instead. + Returns true if the object is new, false if it's shared */ +bool isNewObject(void* ptr,std::string& buffer, std::map &objcache){ + std::pair::iterator,bool> ret; + ret = objcache.insert(std::pair(ptr,objcache.size())); + if(ret.second==false){ + writeShared(ret.first->second,buffer); + return false; + } + //printf("%i:",objcache.size()-1); + return true; +} + +/* Record descriptions are serialized as [path,name,[field1,...,fieldn]] */ +void writeRecordDescription(struct record_description* desc,mmc_uint_t slots,std::string& buffer,std::map &objcache){ + mmc_uint_t size = 0; + //printf("ctor(%i,%i) -> ", 3,255); + writeStruct(3,255,buffer); // Serializes the objec as an array. + //printf("\n"); + + // Here's a hack that adds 1 to the pointer (&desc->path+1) since &desc == &desc->path + bool new_path = isNewObject((void*)((char*)(&desc->path)+1),buffer,objcache); + if(new_path){ + size = strlen(desc->path); + //printf("%s ->", desc->path); + writeString(size,desc->path,buffer); + //printf("\n"); + } + bool new_name = isNewObject((void*)(&desc->name),buffer,objcache); + if(new_name){ + size = strlen(desc->name); + //printf("%s ->", desc->name); + writeString(size,desc->name,buffer); + //printf("\n"); + } + + bool new_fields = isNewObject((void*)(&desc->fieldNames),buffer,objcache); + if(new_fields){ + //printf("ctor(%i,%i) -> ", slots-1,255); + writeStruct(slots-1,255,buffer); + //printf("\n"); + for(mmc_uint_t i = 0; ifieldNames[i]),buffer,objcache); + size = strlen(desc->fieldNames[i]); + //printf("%s -> ", desc->fieldNames[i]); + writeString(size,desc->fieldNames[i],buffer); + //printf("\n"); + } + } +} + +void serialize(modelica_metatype input_object,std::string& buffer){ + + std::stack objstack; + std::map objcache; + buffer.reserve(1024*1024); + //Inserts the object to the stack + objstack.push(input_object); + + while(!objstack.empty()){ + // Takes the next object in the stack + modelica_metatype object = objstack.top(); + objstack.pop(); + + /* Integer */ + if(MMC_IS_IMMEDIATE(object)){ + mmc_sint_t value = MMC_UNTAGFIXNUM(object); + //printf("%i -> ",value); + writeInt(value,buffer); + //printf("\n"); + continue; + } + mmc_uint_t hdr = MMC_GETHDR(object); + /* Real */ + if(hdr==MMC_REALHDR){ + double value = mmc_unbox_real(object); + //printf("%f -> ",value); + writeReal(value,buffer); + //printf("\n"); + continue; + } + + void* ptr = MMC_UNTAGPTR(object); + + /* any other value */ + if(isNewObject(ptr,buffer,objcache)){ // the element was not in the map + if(MMC_HDRISSTRING(hdr)){ + //printf("%s -> ",MMC_STRINGDATA(object)); + writeString(MMC_HDRSTRLEN(hdr),MMC_STRINGDATA(object),buffer); + //printf("\n"); + } + else if(MMC_HDRISSTRUCT(hdr)){ + mmc_uint_t slots = MMC_HDRSLOTS(hdr); + mmc_uint_t ctor = MMC_HDRCTOR(hdr); + int count = slots; + int left = 0; + + //printf("ctor(%i,%i) -> ", slots,ctor); + writeStruct(slots,ctor,buffer); + //printf("\n"); + if(ctor>=3 && ctor!=255){ // It's a meta record + struct record_description* desc = (struct record_description*) MMC_FETCH(MMC_OFFSET(ptr,1)); + if(isNewObject((void*)desc,buffer,objcache)){ // it's a new record + writeRecordDescription(desc,slots,buffer,objcache); + } + left=1; + } + // Push the sub-objects to the stack + while(count>left){ + objstack.push(MMC_FETCH(MMC_OFFSET(ptr, count))); + count--; + } + } + } + } + write64(objcache.size(),buffer); + //printf("\nserialized %i objects\n",objcache.size()); +} + + +/* DE-SERIALIZATION */ + + +void readFile(char* filename,std::string& buffer){ + std::ifstream input_file(filename,std::ifstream::in | std::ifstream::binary); + + input_file.seekg(0, std::ios::end); + buffer.reserve(input_file.tellg()); + input_file.seekg(0, std::ios::beg); + + buffer.assign((std::istreambuf_iterator(input_file)), + std::istreambuf_iterator()); +} + +/* Reads 16 bits from the buffer and moves the index forward */ +uint16_t read16(mmc_uint_t &index,unsigned char* data){ + uint16_t value = (uint16_t)data[index]<<8 | data[index+1]; + index+=2; + return value; +} + +/* Reads 32 bits from the buffer and moves the index forward */ +uint32_t read32(mmc_uint_t &index,unsigned char* data){ + uint32_t value = (uint32_t)data[index]<<24 | (uint32_t)data[index+1]<<16 | (uint32_t)data[index+2]<<8 | (uint32_t)data[index+3]; + index+=4; + return value; +} + +/* Reads 32 bits from the buffer and moves the index forward */ +uint64_t read64(mmc_uint_t &index,unsigned char* data){ + uint64_t value = + (uint64_t)data[index]<<56 | (uint64_t)data[index+1]<<48 | (uint64_t)data[index+2]<<32 | (uint64_t)data[index+3] | (uint64_t)data[index+4]<<24 | (uint64_t)data[index+5]<<16 | (uint64_t)data[index+6]<<8 | (uint64_t)data[index+7]; + index+=8; + return value; +} + +modelica_metatype readInteger(uint8_t tag,mmc_uint_t &index,unsigned char* data){ + uint8_t uvalue8; + int8_t value8; + int32_t value32; + int64_t value64; + switch(tag){ + case TAG_INT_TINY: + uvalue8 = data[index]&0x0F; + if(uvalue8>7) + value8 = uvalue8 | 0xF0; + else + value8 = uvalue8; + index=index+1; + //printf("%i\n", value8); + return mmc_mk_integer(value8); + case TAG_INT_SMALL: + index++; + value32 = read32(index,data); + //printf("%i\n", value32); + return mmc_mk_integer(value32); + case TAG_INT_BIG: + index++; + value64 = read64(index,data); + //printf("%i\n", value64); + return mmc_mk_integer(value64); + default: return mmc_mk_integer(0); + } +} + + +modelica_metatype readReal(uint8_t tag,mmc_uint_t &index,unsigned char* data){ + index++; + uint64_t ivalue = read64(index,data); + double* fvalue = (double*)(&ivalue); + //printf("%f\n", *fvalue); + return mmc_mk_real(*fvalue); +} + + +modelica_metatype readString(uint8_t tag,mmc_uint_t &index,unsigned char* data){ + uint64_t size = 0; + switch(tag){ + case TAG_STRING_SMALL: + index++; + size = data[index]; + index++; + break; + case TAG_STRING_BIG: + index++; + size = read64(index,data); + break; + default: break; + } + + modelica_metatype res = mmc_mk_scon_len(size+1); + const char* str = (const char*)&(data[index]); + index += size; + + // debug prints + //for(int i = 0;i &shared){ + uint64_t i64; + uint16_t i16; + uint32_t i32; + index++; + switch(tag){ + case TAG_SHARED_TINY: + i16 = read16(index,data); + //printf("shared(%i)\n",i16); + return shared[i16]; + break; + case TAG_SHARED_SMALL: + i32 = read32(index,data); + //printf("shared(%i)\n",i32); + return shared[i32]; + break; + case TAG_SHARED_BIG: + i64 = read64(index,data); + //printf("shared(%i)\n",i64); + return shared[i64]; + break; + default: break; + } + return 0; +} + +void readStruct(uint8_t tag, mmc_uint_t &index, uint8_t* data, mmc_uint_t &size, mmc_uint_t &ctor){ + switch(tag){ + case TAG_STRUCT_SMALL: + size = data[index] & 0x0F; + index++; + break; + case TAG_STRUCT_BIG: + index++; + size = read64(index,data); + break; + default: break; + } + ctor = data[index]; + index++; +} + +modelica_metatype allocValue(mmc_uint_t size,mmc_uint_t ctor){ + struct mmc_struct *p = (struct mmc_struct *) mmc_alloc_words(size+1); + p->header = MMC_STRUCTHDR(size, ctor); + return MMC_TAGPTR(p); +} + +void setToNextField(modelica_metatype sub,std::stack > &stack){ + std::pair next = stack.top(); + stack.pop(); + MMC_STRUCTDATA(next.first)[next.second-1]=sub; +} + +/* This is a special case of the de-serialization to restore the record_descriptions */ +record_description* readRecordDescription(mmc_uint_t &index,unsigned char* data,std::vector &shared){ + mmc_uint_t size,ctor; + struct record_description* pdesc; + uint8_t tag = data[index]&0xF0; + switch(tag){ + case TAG_SHARED_TINY: + case TAG_SHARED_SMALL: + case TAG_SHARED_BIG: + pdesc = (struct record_description*)readShared(tag,index,data,shared); + break; + + case TAG_STRUCT_SMALL: + case TAG_STRUCT_BIG: + readStruct(tag,index,data,size,ctor); // skipping since we already know what it is + // Read the path + char* path = readString_raw(data[index]&0xF0,index,data); + // check if we already have a description for this path + std::map::iterator it = record_cache.find(std::string(path)); + + if(it==record_cache.end()){ + pdesc = new struct record_description; + shared.push_back(pdesc); + + shared.push_back(path); + // Read the name + char* name = readString_raw(data[index]&0xF0,index,data); + shared.push_back(name); + // Read the array + readStruct(data[index]&0xF0,index,data,size,ctor); // this should be an array + shared.push_back(0); // pushes anything since this objects are not reused + char** fields = new char*[size]; + // Now read the fields + for(int i=0;ipath = path; + pdesc->name = name; + pdesc->fieldNames = (const char**) fields; + // Insert the record description to the global cache of descriptions + record_cache.insert( std::pair(std::string(path),pdesc)); + } + else { + pdesc = it->second; + // Now we read the data but we release the memory since we are not gonna use it + // (This part can be optimized) + shared.push_back(pdesc); + shared.push_back(0); + // Read the name + char* name = readString_raw(data[index]&0xF0,index,data); + shared.push_back(0); + // Read the array + readStruct(data[index]&0xF0,index,data,size,ctor); // this should be an array + shared.push_back(0); // pushes anything since this objects are not reused + // Now read the fields + for(int i=0;i shared; + std::stack > stack; + + stack.push(std::make_pair(result,1)); + + while(!stack.empty()){ + unsigned char tag = data[index] & 0xF0; + switch(tag){ // integer + case TAG_INT_TINY: + case TAG_INT_SMALL: + case TAG_INT_BIG: + current = readInteger(tag,index,data); + setToNextField(current,stack); + break; + case TAG_DOUBLE: + current = readReal(tag,index,data); + setToNextField(current,stack); + break; + case TAG_STRING_SMALL: + case TAG_STRING_BIG: + current = readString(tag,index,data); + setToNextField(current,stack); + shared.push_back(current); + break; + case TAG_SHARED_TINY: + case TAG_SHARED_SMALL: + case TAG_SHARED_BIG: + current = readShared(tag,index,data,shared); + setToNextField(current,stack); + break; + case TAG_STRUCT_SMALL: + case TAG_STRUCT_BIG: + size = 0; + ctor = 0; + readStruct(tag,index,data,size,ctor); + //printf("%i:ctor(%i,%i)\n",shared.size(),size,ctor); + if(ctor>=3 && ctor!=255){ // not an array + current = allocValue(size,ctor); + shared.push_back(current); + setToNextField(current,stack); + while(size>0){ + stack.push(std::make_pair(current,size)); + size--; + } + modelica_metatype record_desc = readRecordDescription(index,data,shared); + setToNextField(record_desc,stack); + } + else { + current = allocValue(size,ctor); + shared.push_back(current); + setToNextField(current,stack); + while(size>0){ + stack.push(std::make_pair(current,size)); + size--; + } + } + break; + default: break; + } + } + uint64_t total = read64(index,data); + //printf("Sent %i : Received %i\n",total,shared.size()); + return MMC_FETCH(MMC_OFFSET(MMC_UNTAGPTR(result), 1)); +} + + +static int indent_level = 0; + +void pushBlock(){ + indent_level++; +} + +void popBlock(){ + indent_level--; +} + +void indent(){ + int count = indent_level; + while(count){ + putchar(' '); + putchar(' '); + count--; + } +} + +void Serializer_showBlocks(modelica_metatype object){ + if(MMC_IS_IMMEDIATE(object)){ + indent(); + printf("%i\n",MMC_UNTAGFIXNUM(object)); + return; + } + mmc_uint_t hdr = MMC_GETHDR(object); + if(MMC_HDRISSTRING(hdr)){ + indent(); + printf("str(%i)=\"%s\"\n",MMC_HDRSTRLEN(hdr),MMC_STRINGDATA(object)); + return; + } + if(hdr==MMC_REALHDR){ + indent(); + printf("%f\n",mmc_unbox_real(object)); + return; + } + if(MMC_HDRISSTRUCT(hdr)){ + mmc_uint_t slots = MMC_HDRSLOTS(hdr); + mmc_uint_t ctor = MMC_HDRCTOR(hdr); + int count = slots-1; + if(ctor==255){// it's an array + indent(); + printf("array(%i)\n",slots); + } + else { + indent(); + printf("ctr(%i,%i)\n",ctor,slots); + if(ctor>=3 && ctor!=255){ // It's a meta record + struct record_description* desc = (struct record_description*) MMC_FETCH(MMC_OFFSET(MMC_UNTAGPTR(object),1)); + indent();printf(" - %s\n",desc->path); + count--; + } + } + pushBlock(); + while(count>=0){ + Serializer_showBlocks(MMC_FETCH(MMC_OFFSET(MMC_UNTAGPTR(object), slots-count))); + count--; + } + popBlock(); + return; + } + + printf("Unknown object %i\n",hdr); +} + + +void Serializer_outputFile(modelica_metatype input_object,char* filename){ + std::fstream fs; + std::string buffer; + serialize(input_object,buffer); + fs.open (filename,std::fstream::out | std::fstream::binary); + fs.write(buffer.c_str(),buffer.size()); + fs.close(); +} + +modelica_metatype Serializer_bypass(modelica_metatype input_object){ + std::string buffer; + serialize(input_object,buffer); + modelica_metatype out = deserialize(buffer); + //printf("Input object\n"); + //Serializer_showBlocks(input_object); + //printf("Output object\n"); + //Serializer_showBlocks(out); + return out; +} + + + +} \ No newline at end of file