wasm_interface.cpp 19.4 KB
Newer Older
1
#include <boost/function.hpp>
2
#include <eos/chain/wasm_interface.hpp>
3
#include <eos/chain/chain_controller.hpp>
4 5 6 7 8 9 10 11 12
#include "Platform/Platform.h"
#include "WAST/WAST.h"
#include "Runtime/Runtime.h"
#include "Runtime/Linker.h"
#include "Runtime/Intrinsics.h"
#include "IR/Module.h"
#include "IR/Operators.h"
#include "IR/Validate.h"
#include <eos/chain/key_value_object.hpp>
13
#include <eos/chain/account_object.hpp>
14
#include <chrono>
15 16 17 18

namespace eos { namespace chain {
   using namespace IR;
   using namespace Runtime;
19

20 21 22
   wasm_interface::wasm_interface() {
   }

23
#ifdef NDEBUG
24
   const int CHECKTIME_LIMIT = 3000;
25
#else
26
   const int CHECKTIME_LIMIT = 18000;
27 28
#endif

29
DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
30 31 32
   auto dur = wasm_interface::get().current_execution_time();
   if (dur > CHECKTIME_LIMIT) {
      wlog("checktime called ${d}", ("d", dur));
33 34 35
      throw checktime_exceeded();
   }
}
36 37
   template <typename Function, typename KeyType, int numberOfKeys>
   int32_t validate(int32_t valueptr, int32_t valuelen, Function func) {
38
      
39
      static const uint32_t keylen = numberOfKeys*sizeof(KeyType);
40 41 42 43
      
      FC_ASSERT( valuelen >= keylen, "insufficient data passed" );

      auto& wasm  = wasm_interface::get();
M
Matias Romeo 已提交
44
      FC_ASSERT( wasm.current_apply_context, "no apply context found" );
45 46

      char* value = memoryArrayPtr<char>( wasm.current_memory, valueptr, valuelen );
47
      KeyType*  keys = reinterpret_cast<KeyType*>(value);
48 49 50 51
      
      valuelen -= keylen;
      value    += keylen;

52
      return func(wasm.current_apply_context, keys, value, valuelen);
M
Matias Romeo 已提交
53 54
   }

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
#define READ_RECORD(READFUNC, INDEX, SCOPE) \
   auto lambda = [&](apply_context* ctx, INDEX::value_type::key_type* keys, char *data, uint32_t datalen) -> int32_t { \
      auto res = ctx->READFUNC<INDEX, SCOPE>( Name(scope), Name(code), Name(table), keys, data, datalen); \
      if (res >= 0) res += INDEX::value_type::number_of_keys*sizeof(INDEX::value_type::key_type); \
      return res; \
   }; \
   return validate<decltype(lambda), INDEX::value_type::key_type, INDEX::value_type::number_of_keys>(valueptr, valuelen, lambda);

#define UPDATE_RECORD(UPDATEFUNC, INDEX, DATASIZE) \
   auto lambda = [&](apply_context* ctx, INDEX::value_type::key_type* keys, char *data, uint32_t datalen) -> int32_t { \
      return ctx->UPDATEFUNC<INDEX::value_type>( Name(scope), Name(ctx->code.value), Name(table), keys, data, datalen); \
   }; \
   return validate<decltype(lambda), INDEX::value_type::key_type, INDEX::value_type::number_of_keys>(valueptr, DATASIZE, lambda);

#define DEFINE_RECORD_UPDATE_FUNCTIONS(OBJTYPE, INDEX) \
   DEFINE_INTRINSIC_FUNCTION4(env,store_##OBJTYPE,store_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { \
      UPDATE_RECORD(store_record, INDEX, valuelen); \
   } \
   DEFINE_INTRINSIC_FUNCTION4(env,update_##OBJTYPE,update_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) { \
      UPDATE_RECORD(update_record, INDEX, valuelen); \
   } \
   DEFINE_INTRINSIC_FUNCTION3(env,remove_##OBJTYPE,remove_##OBJTYPE,i32,i64,scope,i64,table,i32,valueptr) { \
      UPDATE_RECORD(remove_record, INDEX, sizeof(typename INDEX::value_type::key_type)*INDEX::value_type::number_of_keys); \
78
   }
M
Matias Romeo 已提交
79

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
#define DEFINE_RECORD_READ_FUNCTIONS(OBJTYPE, FUNCPREFIX, INDEX, SCOPE) \
   DEFINE_INTRINSIC_FUNCTION5(env,load_##FUNCPREFIX##OBJTYPE,load_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(load_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,front_##FUNCPREFIX##OBJTYPE,front_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(front_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,back_##FUNCPREFIX##OBJTYPE,back_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(back_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,next_##FUNCPREFIX##OBJTYPE,next_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(next_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,previous_##FUNCPREFIX##OBJTYPE,previous_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(previous_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,lower_bound_##FUNCPREFIX##OBJTYPE,lower_bound_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(lower_bound_record, INDEX, SCOPE); \
   } \
   DEFINE_INTRINSIC_FUNCTION5(env,upper_bound_##FUNCPREFIX##OBJTYPE,upper_bound_##FUNCPREFIX##OBJTYPE,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) { \
      READ_RECORD(upper_bound_record, INDEX, SCOPE); \
   }
M
Matias Romeo 已提交
102

103 104
DEFINE_RECORD_UPDATE_FUNCTIONS(i64, key_value_index);
DEFINE_RECORD_READ_FUNCTIONS(i64,,key_value_index, by_scope_primary);
M
Matias Romeo 已提交
105

106 107 108
DEFINE_RECORD_UPDATE_FUNCTIONS(i128i128, key128x128_value_index);
DEFINE_RECORD_READ_FUNCTIONS(i128i128, primary_,   key128x128_value_index, by_scope_primary);
DEFINE_RECORD_READ_FUNCTIONS(i128i128, secondary_, key128x128_value_index, by_scope_secondary);
M
Matias Romeo 已提交
109

110 111 112 113
DEFINE_RECORD_UPDATE_FUNCTIONS(i64i64i64, key64x64x64_value_index);
DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, primary_,   key64x64x64_value_index, by_scope_primary);
DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, secondary_, key64x64x64_value_index, by_scope_secondary);
DEFINE_RECORD_READ_FUNCTIONS(i64i64i64, tertiary_,  key64x64x64_value_index, by_scope_tertiary);
M
Matias Romeo 已提交
114

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
DEFINE_INTRINSIC_FUNCTION3(env, assert_sha256,assert_sha256,none,i32,dataptr,i32,datalen,i32,hash) {
   FC_ASSERT( datalen > 0 );

   auto& wasm  = wasm_interface::get();
   auto  mem          = wasm.current_memory;

   char* data = memoryArrayPtr<char>( mem, dataptr, datalen );
   const auto& v = memoryRef<fc::sha256>( mem, hash );

   auto result = fc::sha256::hash( data, datalen );
   FC_ASSERT( result == v, "hash miss match" );
}

DEFINE_INTRINSIC_FUNCTION3(env,sha256,sha256,none,i32,dataptr,i32,datalen,i32,hash) {
   FC_ASSERT( datalen > 0 );

   auto& wasm  = wasm_interface::get();
   auto  mem          = wasm.current_memory;

   char* data = memoryArrayPtr<char>( mem, dataptr, datalen );
   auto& v = memoryRef<fc::sha256>( mem, hash );
   v  = fc::sha256::hash( data, datalen );
}
138

139 140 141
DEFINE_INTRINSIC_FUNCTION2(env,multeq_i128,multeq_i128,none,i32,self,i32,other) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
142 143
   auto& v = memoryRef<unsigned __int128>( mem, self );
   const auto& o = memoryRef<const unsigned __int128>( mem, other );
144 145
   v *= o;
}
146

147
DEFINE_INTRINSIC_FUNCTION2(env,diveq_i128,diveq_i128,none,i32,self,i32,other) {
148
   auto& wasm  = wasm_interface::get();
149
   auto  mem          = wasm.current_memory;
150 151
   auto& v = memoryRef<unsigned __int128>( mem, self );
   const auto& o = memoryRef<const unsigned __int128>( mem, other );
152 153 154
   FC_ASSERT( o != 0, "divide by zero" );
   v /= o;
}
155

156 157 158
DEFINE_INTRINSIC_FUNCTION0(env,now,now,i32) {
   return wasm_interface::get().current_validate_context->controller.head_block_time().sec_since_epoch();
}
159

160 161 162 163 164 165
DEFINE_INTRINSIC_FUNCTION0(env,currentCode,currentCode,i64) {
   auto& wasm  = wasm_interface::get();
   return wasm.current_validate_context->code.value;
}

DEFINE_INTRINSIC_FUNCTION1(env,requireAuth,requireAuth,none,i64,account) {
166
   wasm_interface::get().current_validate_context->require_authorization( Name(account) );
167
}
168

169
DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) {
170
   wasm_interface::get().current_apply_context->require_recipient( account );
171
}
172

173
DEFINE_INTRINSIC_FUNCTION1(env,requireScope,requireScope,none,i64,scope) {
174
   wasm_interface::get().current_validate_context->require_scope( scope );
175 176 177 178 179
}

DEFINE_INTRINSIC_FUNCTION3(env,memcpy,memcpy,i32,i32,dstp,i32,srcp,i32,len) {
   auto& wasm          = wasm_interface::get();
   auto  mem           = wasm.current_memory;
D
Daniel Larimer 已提交
180 181 182
   char* dst           = memoryArrayPtr<char>( mem, dstp, len);
   const char* src     = memoryArrayPtr<const char>( mem, srcp, len );
   FC_ASSERT( len > 0 );
183 184

   if( dst > src )
D
Daniel Larimer 已提交
185
      FC_ASSERT( dst >= (src + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
186
   else
D
Daniel Larimer 已提交
187 188
      FC_ASSERT( src >= (dst + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );

189 190 191 192 193
   memcpy( dst, src, uint32_t(len) );
   return dstp;
}


194 195 196 197 198 199 200 201 202
DEFINE_INTRINSIC_FUNCTION2(env,send,send,i32,i32,trx_buffer, i32,trx_buffer_size ) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
   const char* buffer = &memoryRef<const char>( mem, trx_buffer );

   FC_ASSERT( trx_buffer_size > 0 );
   FC_ASSERT( wasm.current_apply_context, "not in apply context" );

   fc::datastream<const char*> ds(buffer, trx_buffer_size );
203
   eos::chain::GeneratedTransaction gtrx;
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
   eos::chain::Transaction& trx = gtrx;
   fc::raw::unpack( ds, trx );

/**
 *  The code below this section provides sanity checks that the generated message is well formed
 *  before being accepted. These checks do not need to be applied during reindex.
 */
#warning TODO: reserve per-thread static memory for MAX TRX SIZE 
/** make sure that packing what we just unpacked produces expected output */
   auto test = fc::raw::pack( trx );
   FC_ASSERT( 0 == memcmp( buffer, test.data(), test.size() ) );

/** TODO: make sure that we can call validate() on the message and it passes, this is thread safe and
 *   ensures the type is properly registered and can be deserialized... one issue is that this could
 *   construct a RECURSIVE virtual machine state which means the wasm_interface state needs to be a STACK vs
 *   a per-thread global.
 **/

222
//   wasm.current_apply_context->generated.emplace_back( std::move(gtrx) );
223

D
Daniel Larimer 已提交
224 225
   return 0;
}
226

227 228 229



230 231
DEFINE_INTRINSIC_FUNCTION2(env,readMessage,readMessage,i32,i32,destptr,i32,destsize) {
   FC_ASSERT( destsize > 0 );
232

233 234
   wasm_interface& wasm = wasm_interface::get();
   auto  mem   = wasm.current_memory;
235
   char* begin = memoryArrayPtr<char>( mem, destptr, uint32_t(destsize) );
236 237

   int minlen = std::min<int>(wasm.current_validate_context->msg.data.size(), destsize);
238

D
Daniel Larimer 已提交
239
//   wdump((destsize)(wasm.current_validate_context->msg.data.size()));
240 241 242 243
   memcpy( begin, wasm.current_validate_context->msg.data.data(), minlen );
   return minlen;
}

244
DEFINE_INTRINSIC_FUNCTION2(env,assert,assert,none,i32,test,i32,msg) {
245 246
   const char* m = &Runtime::memoryRef<char>( wasm_interface::get().current_memory, msg );
  std::string message( m );
247
  if( !test ) edump((message));
248
  FC_ASSERT( test, "assertion failed: ${s}", ("s",message)("ptr",msg) );
249
}
250

251 252 253 254
DEFINE_INTRINSIC_FUNCTION0(env,messageSize,messageSize,i32) {
   return wasm_interface::get().current_validate_context->msg.data.size();
}

255
DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
256 257 258 259 260 261 262 263
   FC_ASSERT( size > 0 );
   int32_t& end = Runtime::memoryRef<int32_t>( Runtime::getDefaultMemory(wasm_interface::get().current_module), 0);
   int32_t old_end = end;
   end += 8*((size+7)/8);
   FC_ASSERT( end > old_end );
   return old_end;
}

264
DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i64,val) {
265
  std::cerr << uint64_t(val);
266
}
267

268 269 270
DEFINE_INTRINSIC_FUNCTION1(env,printi128,printi128,none,i32,val) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;
271 272 273
  auto& value = memoryRef<unsigned __int128>( mem, val );
  fc::uint128_t v(value>>64, uint64_t(value) );
  std::cerr << fc::variant(v).get_string();
274 275 276
}
DEFINE_INTRINSIC_FUNCTION1(env,printn,printn,none,i64,val) {
  std::cerr << Name(val).toString();
277
}
278

279
DEFINE_INTRINSIC_FUNCTION1(env,prints,prints,none,i32,charptr) {
280 281 282
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;

283
  const char* str = &memoryRef<const char>( mem, charptr );
284

D
Daniel Larimer 已提交
285
  std::cerr << std::string( str, strnlen(str, wasm.current_state->mem_end-charptr) );
286 287
}

288
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
289 290 291 292
}

   wasm_interface& wasm_interface::get() {
      static wasm_interface*  wasm = nullptr;
293
      if( !wasm )
294 295
      {
         wlog( "Runtime::init" );
296
         Runtime::init();
297 298 299 300 301 302 303 304 305 306 307 308 309
         wasm = new wasm_interface();
      }
      return *wasm;
   }



   struct RootResolver : Runtime::Resolver
   {
      std::map<std::string,Resolver*> moduleNameToResolverMap;

     bool resolve(const std::string& moduleName,const std::string& exportName,ObjectType type,ObjectInstance*& outObject) override
     {
310 311 312 313
         // Try to resolve an intrinsic first.
         if(IntrinsicResolver::singleton.resolve(moduleName,exportName,type,outObject)) { return true; }
         FC_ASSERT( !"unresolvable", "${module}.${export}", ("module",moduleName)("export",exportName) );
         return false;
314 315 316
     }
   };

317 318 319 320 321
   int64_t wasm_interface::current_execution_time()
   {
      return (fc::time_point::now() - checktimeStart).count();
   }

322 323

   char* wasm_interface::vm_allocate( int bytes ) {
324 325
      FunctionInstance* alloc_function = asFunctionNullable(getInstanceExport(current_module,"alloc"));
      const FunctionType* functionType = getFunctionType(alloc_function);
326
      FC_ASSERT( functionType->parameters.size() == 1 );
327
      std::vector<Value> invokeArgs(1);
328 329
      invokeArgs[0] = U32(bytes);

330
      checktimeStart = fc::time_point::now();
331

332 333 334 335 336 337 338 339 340
      auto result = Runtime::invokeFunction(alloc_function,invokeArgs);

      return &memoryRef<char>( current_memory, result.i32 );
   }

   U32 wasm_interface::vm_pointer_to_offset( char* ptr ) {
      return U32(ptr - &memoryRef<char>(current_memory,0));
   }

D
Daniel Larimer 已提交
341
   void  wasm_interface::vm_call( const char* name ) {
342
   try {
343
      try {
D
Daniel Larimer 已提交
344
         /*
345
         name += "_" + std::string( current_validate_context->msg.code ) + "_";
346
         name += std::string( current_validate_context->msg.type );
D
Daniel Larimer 已提交
347 348 349
         */
         /// TODO: cache this somehow
         FunctionInstance* call = asFunctionNullable(getInstanceExport(current_module,name) );
350 351 352 353
         if( !call ) {
            //wlog( "unable to find call ${name}", ("name",name));
            return;
         }
D
Daniel Larimer 已提交
354
         //FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name))  );
355

D
Daniel Larimer 已提交
356
         FC_ASSERT( getFunctionType(call)->parameters.size() == 2 );
357

D
Daniel Larimer 已提交
358
  //       idump((current_validate_context->msg.code)(current_validate_context->msg.type)(current_validate_context->code));
359
         std::vector<Value> args = { Value(uint64_t(current_validate_context->msg.code)),
D
Daniel Larimer 已提交
360
                                     Value(uint64_t(current_validate_context->msg.type)) };
361 362 363 364 365 366

         auto& state = *current_state;
         char* memstart = &memoryRef<char>( current_memory, 0 );
         memset( memstart + state.mem_end, 0, ((1<<16) - state.mem_end) );
         memcpy( memstart, state.init_memory.data(), state.mem_end);

367
         checktimeStart = fc::time_point::now();
368

D
Daniel Larimer 已提交
369
         Runtime::invokeFunction(call,args);
370 371
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
372 373
          edump((e.callStack));
          throw;
374
      }
375 376
   } FC_CAPTURE_AND_RETHROW( (name)(current_validate_context->msg.type) ) }

D
Daniel Larimer 已提交
377
   void  wasm_interface::vm_apply()        { vm_call("apply" );          }
378

379
   void  wasm_interface::vm_onInit()
380 381
   { try {
      try {
382
          wlog( "on_init" );
383 384
            FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init"));
            if( !apply ) {
385
               elog( "no onInit method found" );
386
               return; /// if not found then it is a no-op
387 388
         }

389
         checktimeStart = fc::time_point::now();
390

391 392
            const FunctionType* functionType = getFunctionType(apply);
            FC_ASSERT( functionType->parameters.size() == 0 );
393

394
            std::vector<Value> args(0);
395

396
            Runtime::invokeFunction(apply,args);
397 398
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
399 400
          edump((e.callStack));
          throw;
401
      }
402
   } FC_CAPTURE_AND_RETHROW() }
403

404
   void wasm_interface::validate( apply_context& c ) {
D
Daniel Larimer 已提交
405
      /*
406 407 408 409
      current_validate_context       = &c;
      current_precondition_context   = nullptr;
      current_apply_context          = nullptr;

D
Daniel Larimer 已提交
410
      load( c.code, c.db );
411
      vm_validate();
D
Daniel Larimer 已提交
412
      */
413
   }
414
   void wasm_interface::precondition( apply_context& c ) {
415 416
   try {

D
Daniel Larimer 已提交
417
      /*
418 419 420
      current_validate_context       = &c;
      current_precondition_context   = &c;

D
Daniel Larimer 已提交
421
      load( c.code, c.db );
422
      vm_precondition();
D
Daniel Larimer 已提交
423
      */
424 425

   } FC_CAPTURE_AND_RETHROW() }
426 427


428 429
   void wasm_interface::apply( apply_context& c ) {
    try {
430 431 432 433
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
434
      load( c.code, c.db );
435 436 437 438 439 440
      vm_apply();

   } FC_CAPTURE_AND_RETHROW() }

   void wasm_interface::init( apply_context& c ) {
    try {
441 442 443 444
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
445
      load( c.code, c.db );
446
      vm_onInit();
447 448 449

   } FC_CAPTURE_AND_RETHROW() }

450

451

452 453
   void wasm_interface::load( const AccountName& name, const chainbase::database& db ) {
      const auto& recipient = db.get<account_object,by_name>( name );
454
  //    idump(("recipient")(Name(name))(recipient.code_version));
455 456 457 458 459 460 461 462

      auto& state = instances[name];
      if( state.code_version != recipient.code_version ) {
         if( state.instance ) {
            /// TODO: free existing instance and module
#warning TODO: free existing module if the code has been updated, currently leak memory
            state.instance     = nullptr;
            state.module       = nullptr;
463
            state.code_version = fc::sha256();
464 465 466 467 468
         }
         state.module = new IR::Module();

        try
        {
469
          wlog( "LOADING CODE" );
470
          auto start = fc::time_point::now();
471
          Serialization::MemoryInputStream stream((const U8*)recipient.code.data(),recipient.code.size());
472
          WASM::serializeWithInjection(stream,*state.module);
473 474 475 476 477

          RootResolver rootResolver;
          LinkResult linkResult = linkModule(*state.module,rootResolver);
          state.instance = instantiateModule( *state.module, std::move(linkResult.resolvedImports) );
          FC_ASSERT( state.instance );
478 479 480
          auto end = fc::time_point::now();
          idump(( (end-start).count()/1000000.0) );

481 482 483
          current_memory = Runtime::getDefaultMemory(state.instance);

          char* memstart = &memoryRef<char>( current_memory, 0 );
484
         // state.init_memory.resize(1<<16); /// TODO: actually get memory size
485
          for( uint32_t i = 0; i < 10000; ++i )
486
              if( memstart[i] ) {
487
                   state.mem_end = i+1;
488
                   //std::cerr << (char)memstart[i];
489
              }
490
          ilog( "INIT MEMORY: ${size}", ("size", state.mem_end) );
491 492 493

          state.init_memory.resize(state.mem_end);
          memcpy( state.init_memory.data(), memstart, state.mem_end ); //state.init_memory.size() );
494 495
          std::cerr <<"\n";
          state.code_version = recipient.code_version;
496
          idump((state.code_version));
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
        }
        catch(Serialization::FatalSerializationException exception)
        {
          std::cerr << "Error deserializing WebAssembly binary file:" << std::endl;
          std::cerr << exception.message << std::endl;
          throw;
        }
        catch(IR::ValidationException exception)
        {
          std::cerr << "Error validating WebAssembly binary file:" << std::endl;
          std::cerr << exception.message << std::endl;
          throw;
        }
        catch(std::bad_alloc)
        {
          std::cerr << "Memory allocation failed: input is likely malformed" << std::endl;
          throw;
        }
      }
      current_module = state.instance;
      current_memory = getDefaultMemory( current_module );
518
      current_state  = &state;
519
   }
520 521

} }