wasm_interface.cpp 19.9 KB
Newer Older
1
#include <eos/chain/wasm_interface.hpp>
2
#include <eos/chain/chain_controller.hpp>
3 4 5 6 7 8 9 10 11
#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>
12
#include <eos/chain/account_object.hpp>
13 14 15 16

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

18 19 20
   wasm_interface::wasm_interface() {
   }

21 22 23
DEFINE_INTRINSIC_FUNCTION2(env,multeq_i128,multeq_i128,none,i32,self,i32,other) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
24 25
   auto& v = memoryRef<unsigned __int128>( mem, self );
   const auto& o = memoryRef<const unsigned __int128>( mem, other );
26 27 28 29 30 31 32
   v *= o;
}


DEFINE_INTRINSIC_FUNCTION2(env,diveq_i128,diveq_i128,none,i32,self,i32,other) {
   auto& wasm  = wasm_interface::get();
   auto  mem          = wasm.current_memory;
33 34
   auto& v = memoryRef<unsigned __int128>( mem, self );
   const auto& o = memoryRef<const unsigned __int128>( mem, other );
35 36 37 38 39 40 41 42 43
   FC_ASSERT( o != 0, "divide by zero" );
   v /= o;
}

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

DEFINE_INTRINSIC_FUNCTION4(env,store_i128i128,store_i128i128,i32,i64,scope,i64,table,i32,data,i32,datalen) {
44 45 46
   static const uint32_t keylen = 2*sizeof(uint128_t);
   FC_ASSERT( datalen >= keylen, "insufficient data passed" );

47 48 49
   auto& wasm  = wasm_interface::get();
   FC_ASSERT( wasm.current_apply_context, "not a valid apply context" );

50 51 52 53 54 55 56 57
   char* v     = memoryArrayPtr<char>( wasm.current_memory, data, datalen );

   uint128_t*  primary   = ((uint128_t*)v);
   uint128_t*  secondary = primary + 1;

   char* value = (char*)(secondary+1);
   uint32_t valuelen = datalen - keylen;
   auto result = wasm_interface::get().current_apply_context->store_i128i128( 
58
                Name(scope), Name(table),
59 60 61
                *primary, *secondary, value, valuelen ) + keylen;
   wdump((datalen)(valuelen)(result));
   return result;
62 63
}

64 65 66 67 68
struct i128_keys {
   uint128_t primary;
   uint128_t secondary;
};

69
DEFINE_INTRINSIC_FUNCTION3(env,remove_i128i128,remove_i128i128,i32,i64,scope,i64,table,i32,data) {
70 71 72 73 74
   auto& wasm  = wasm_interface::get();
   FC_ASSERT( wasm.current_apply_context, "not a valid apply context" );

   const i128_keys& keys = memoryRef<const i128_keys>( wasm.current_memory, data );
   return wasm_interface::get().current_apply_context->remove_i128i128( Name(scope), Name(table), keys.primary, keys.secondary );
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
}

DEFINE_INTRINSIC_FUNCTION5(env,load_primary_i128i128,load_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,data,i32,datalen) {
   auto& wasm  = wasm_interface::get();
   char* v     = &memoryRef<char>( wasm.current_memory, data );
   return wasm_interface::get().current_validate_context->load_primary_i128i128( Name(scope), Name(code), Name(table),
                                                                          (uint128_t*)v, (uint128_t*)(v+sizeof(uint128_t)), v, datalen-(2*sizeof(uint128_t)) );
}


DEFINE_INTRINSIC_FUNCTION5(env,load_secondary_i128i128,load_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,data,i32,datalen) {
   FC_ASSERT( !"load_secondary_i128i128 not implemented" );
   return 0;
}

DEFINE_INTRINSIC_FUNCTION5(env,back_primary_i128i128,back_primary_i128i128,i32,i64,scope,i64,code,i64,table,i32,data,i32,datalen) {
91
   wlog( "back primary" );
92 93 94 95 96 97
   auto& wasm  = wasm_interface::get();
   char* v     = &memoryRef<char>( wasm.current_memory, data );
   return wasm_interface::get().current_validate_context->back_primary_i128i128( Name(scope), Name(code), Name(table),
                                                                          (uint128_t*)v, (uint128_t*)(v+sizeof(uint128_t)), v, datalen-(2*sizeof(uint128_t)) );
}
DEFINE_INTRINSIC_FUNCTION5(env,front_primary_i128i128,front_primary,i32,i64,scope,i64,code,i64,table,i32,data,i32,datalen) {
98
   wlog( "front primary" );
99 100 101
   auto& wasm  = wasm_interface::get();
   char* v     = &memoryRef<char>( wasm.current_memory, data );
   return wasm_interface::get().current_validate_context->front_primary_i128i128( Name(scope), Name(code), Name(table),
102 103
                                                                          (uint128_t*)v, (uint128_t*)(v+sizeof(uint128_t)), 
                                                                          v, datalen-(2*sizeof(uint128_t)) ) + 2*sizeof(uint128_t);
104 105 106
}

DEFINE_INTRINSIC_FUNCTION5(env,back_secondary_i128i128,back_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,data,i32,datalen) {
107
   wlog( "back secondary" );
108
   auto& wasm  = wasm_interface::get();
109 110 111 112
   char* v     = memoryArrayPtr<char>( wasm.current_memory, data, datalen );



113 114 115 116
   return wasm_interface::get().current_validate_context->back_secondary_i128i128( Name(scope), Name(code), Name(table),
                                                                          (uint128_t*)v, (uint128_t*)(v+sizeof(uint128_t)), v, datalen-(2*sizeof(uint128_t)) );
}
DEFINE_INTRINSIC_FUNCTION5(env,front_secondary_i128i128,front_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,data,i32,datalen) {
117 118
   wlog( "front secondary" );
   FC_ASSERT( datalen >= 2*sizeof(uint128_t), "insufficient data passed" );
119
   auto& wasm  = wasm_interface::get();
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

   char* v = memoryArrayPtr<char>( wasm.current_memory, data, datalen );

   uint128_t* primary   = (uint128_t*)v;
   uint128_t* secondary = primary+1;
   const uint32_t keylen = 2*sizeof(uint128_t);

   char* value       = v + keylen;
   uint64_t valuelen = datalen - keylen;

   auto result = wasm_interface::get().current_validate_context->front_secondary_i128i128( Name(scope), Name(code), Name(table),
                                                                          primary, secondary, value, valuelen);
   if( result >= 0) {
      result += keylen;
   }
   wdump((result)(datalen));
   return result;
137 138
}

139 140 141 142
DEFINE_INTRINSIC_FUNCTION0(env,currentCode,currentCode,i64) {
   auto& wasm  = wasm_interface::get();
   return wasm.current_validate_context->code.value;
}
143

144
DEFINE_INTRINSIC_FUNCTION1(env,requireAuth,requireAuth,none,i64,account) {
145
   wasm_interface::get().current_validate_context->require_authorization( Name(account) );
146
}
D
Daniel Larimer 已提交
147

148
DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) {
149
   wasm_interface::get().current_validate_context->require_recipient( account );
150 151
}

152 153 154 155 156 157 158
DEFINE_INTRINSIC_FUNCTION1(env,hasRecipient,hasRecipient,i32,i64,account) {
   return wasm_interface::get().current_validate_context->has_recipient( account );
}
DEFINE_INTRINSIC_FUNCTION1(env,hasAuth,hasAuth,i32,i64,account) {
   return wasm_interface::get().current_validate_context->has_authorization( account );
}

159
DEFINE_INTRINSIC_FUNCTION1(env,requireScope,requireScope,none,i64,scope) {
160
   wasm_interface::get().current_validate_context->require_scope( scope );
161 162
}

D
Daniel Larimer 已提交
163
DEFINE_INTRINSIC_FUNCTION4(env,store_i64,store_i64,i32,i64,scope,i64,table,i32,valueptr,i32,valuelen) 
164
{
D
Daniel Larimer 已提交
165 166
   auto& wasm  = wasm_interface::get();
   FC_ASSERT( wasm.current_apply_context, "no apply context found" );
D
Daniel Larimer 已提交
167
   FC_ASSERT( valuelen >= sizeof(uint64_t) );
D
Daniel Larimer 已提交
168 169

   auto  mem   = wasm.current_memory;
170
   char* value = memoryArrayPtr<char>( mem, valueptr, valuelen);
D
Daniel Larimer 已提交
171
   uint64_t* key = reinterpret_cast<uint64_t*>(value);
D
Daniel Larimer 已提交
172

173 174
   //idump((Name(scope))(Name(code))(Name(table))(Name(key))(valuelen) );

D
Daniel Larimer 已提交
175
   return wasm.current_apply_context->store_i64( scope, table, *key, value, valuelen );
176
}
177

D
Daniel Larimer 已提交
178
DEFINE_INTRINSIC_FUNCTION5(env,load_i64,load_i64,i32,i64,scope,i64,code,i64,table,i32,valueptr,i32,valuelen) 
179 180 181
{
   //idump((Name(scope))(Name(code))(Name(table))(Name(key))(valuelen) );

D
Daniel Larimer 已提交
182
   FC_ASSERT( valuelen >= sizeof(uint64_t) );
183 184 185 186 187 188

   auto& wasm  = wasm_interface::get();
   FC_ASSERT( wasm.current_validate_context, "no apply context found" );

   auto  mem   = wasm.current_memory;
   char* value = memoryArrayPtr<char>( mem, valueptr, valuelen);
D
Daniel Larimer 已提交
189
   uint64_t* key = reinterpret_cast<uint64_t*>(value);
190

D
Daniel Larimer 已提交
191
   return wasm.current_validate_context->load_i64( scope, code, table, *key, value, valuelen );
192
}
193

194
DEFINE_INTRINSIC_FUNCTION3(env,remove_i64,remove_i64,i32,i64,scope,i64,table,i64,key) {
195 196
   auto& wasm  = wasm_interface::get();
   FC_ASSERT( wasm.current_apply_context, "no apply context found" );
197
   return wasm.current_apply_context->remove_i64( scope, table, key );
198 199 200 201 202
}

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 已提交
203 204 205
   char* dst           = memoryArrayPtr<char>( mem, dstp, len);
   const char* src     = memoryArrayPtr<const char>( mem, srcp, len );
   FC_ASSERT( len > 0 );
206 207

   if( dst > src )
D
Daniel Larimer 已提交
208
      FC_ASSERT( dst >= (src + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
209
   else
D
Daniel Larimer 已提交
210 211
      FC_ASSERT( src >= (dst + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );

212 213 214 215 216
   memcpy( dst, src, uint32_t(len) );
   return dstp;
}


217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
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 );
   eos::chain::generated_transaction gtrx;
   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.
 **/

   wasm.current_apply_context->generated.emplace_back( std::move(gtrx) );
246

D
Daniel Larimer 已提交
247 248
   return 0;
}
249

250 251 252



253 254
DEFINE_INTRINSIC_FUNCTION2(env,readMessage,readMessage,i32,i32,destptr,i32,destsize) {
   FC_ASSERT( destsize > 0 );
255

256 257
   wasm_interface& wasm = wasm_interface::get();
   auto  mem   = wasm.current_memory;
258
   char* begin = memoryArrayPtr<char>( mem, destptr, uint32_t(destsize) );
259 260

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

D
Daniel Larimer 已提交
262
//   wdump((destsize)(wasm.current_validate_context->msg.data.size()));
263 264 265 266
   memcpy( begin, wasm.current_validate_context->msg.data.data(), minlen );
   return minlen;
}

267
DEFINE_INTRINSIC_FUNCTION2(env,assert,assert,none,i32,test,i32,msg) {
268 269
   const char* m = &Runtime::memoryRef<char>( wasm_interface::get().current_memory, msg );
  std::string message( m );
270
  if( !test ) edump((message));
271
  FC_ASSERT( test, "assertion failed: ${s}", ("s",message)("ptr",msg) );
272
}
273

274 275 276 277
DEFINE_INTRINSIC_FUNCTION0(env,messageSize,messageSize,i32) {
   return wasm_interface::get().current_validate_context->msg.data.size();
}

278
DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
279 280 281 282 283 284 285 286
   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;
}

287
DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i64,val) {
288 289 290 291 292 293
  std::cerr << uint64_t(val);
}

DEFINE_INTRINSIC_FUNCTION1(env,printi128,printi128,none,i32,val) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;
294 295 296
  auto& value = memoryRef<unsigned __int128>( mem, val );
  fc::uint128_t v(value>>64, uint64_t(value) );
  std::cerr << fc::variant(v).get_string();
297 298 299
}
DEFINE_INTRINSIC_FUNCTION1(env,printn,printn,none,i64,val) {
  std::cerr << Name(val).toString();
300
}
301

302
DEFINE_INTRINSIC_FUNCTION1(env,prints,prints,none,i32,charptr) {
303 304 305
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;

306
  const char* str = &memoryRef<const char>( mem, charptr );
307

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

311
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
312 313 314 315
}

   wasm_interface& wasm_interface::get() {
      static wasm_interface*  wasm = nullptr;
316
      if( !wasm )
317 318
      {
         wlog( "Runtime::init" );
319
         Runtime::init();
320 321 322 323 324 325 326 327 328 329 330 331 332
         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
     {
333 334 335 336
         // 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;
337 338 339 340 341
     }
   };


   char* wasm_interface::vm_allocate( int bytes ) {
342 343
      FunctionInstance* alloc_function = asFunctionNullable(getInstanceExport(current_module,"alloc"));
      const FunctionType* functionType = getFunctionType(alloc_function);
344
      FC_ASSERT( functionType->parameters.size() == 1 );
345
      std::vector<Value> invokeArgs(1);
346 347 348 349 350 351 352 353 354 355 356
      invokeArgs[0] = U32(bytes);

      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 已提交
357
   void  wasm_interface::vm_call( const char* name ) {
358
   try {
359
      try {
D
Daniel Larimer 已提交
360
         /*
361
         name += "_" + std::string( current_validate_context->msg.code ) + "_";
362
         name += std::string( current_validate_context->msg.type );
D
Daniel Larimer 已提交
363 364 365
         */
         /// TODO: cache this somehow
         FunctionInstance* call = asFunctionNullable(getInstanceExport(current_module,name) );
366 367 368 369
         if( !call ) {
            //wlog( "unable to find call ${name}", ("name",name));
            return;
         }
D
Daniel Larimer 已提交
370
         //FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name))  );
371

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

D
Daniel Larimer 已提交
374
  //       idump((current_validate_context->msg.code)(current_validate_context->msg.type)(current_validate_context->code));
D
Daniel Larimer 已提交
375 376
         std::vector<Value> args = { Value(uint64_t(current_validate_context->msg.code)),
                                     Value(uint64_t(current_validate_context->msg.type)) };
377 378 379 380 381 382

         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);

D
Daniel Larimer 已提交
383
         Runtime::invokeFunction(call,args);
384 385
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
386 387
          edump((e.callStack));
          throw;
388
      }
389 390
   } FC_CAPTURE_AND_RETHROW( (name)(current_validate_context->msg.type) ) }

D
Daniel Larimer 已提交
391 392 393
   void  wasm_interface::vm_precondition() { vm_call("precondition" ); } 
   void  wasm_interface::vm_apply()        { vm_call("apply" );        }
   void  wasm_interface::vm_validate()     { vm_call("validate");       }
394

395
   void  wasm_interface::vm_onInit()
396 397
   { try {
      try {
398
          wlog( "on_init" );
399 400
            FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init"));
            if( !apply ) {
401
               elog( "no onInit method found" );
402
               return; /// if not found then it is a no-op
403 404
         }

405 406
            const FunctionType* functionType = getFunctionType(apply);
            FC_ASSERT( functionType->parameters.size() == 0 );
407

408
            std::vector<Value> args(0);
409

410
            Runtime::invokeFunction(apply,args);
411 412
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
413 414
          edump((e.callStack));
          throw;
415
      }
416
   } FC_CAPTURE_AND_RETHROW() }
417

418 419 420 421 422 423
   void wasm_interface::validate( message_validate_context& c ) {

      current_validate_context       = &c;
      current_precondition_context   = nullptr;
      current_apply_context          = nullptr;

D
Daniel Larimer 已提交
424
      load( c.code, c.db );
425 426
      vm_validate();
   }
427 428 429 430 431 432
   void wasm_interface::precondition( precondition_validate_context& c ) {
   try {

      current_validate_context       = &c;
      current_precondition_context   = &c;

D
Daniel Larimer 已提交
433
      load( c.code, c.db );
434 435 436
      vm_precondition();

   } FC_CAPTURE_AND_RETHROW() }
437 438


439 440
   void wasm_interface::apply( 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 447 448 449 450 451
      vm_apply();

   } FC_CAPTURE_AND_RETHROW() }

   void wasm_interface::init( apply_context& c ) {
    try {
452 453 454 455
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
456
      load( c.code, c.db );
457
      vm_onInit();
458 459 460

   } FC_CAPTURE_AND_RETHROW() }

461

462

463 464
   void wasm_interface::load( const AccountName& name, const chainbase::database& db ) {
      const auto& recipient = db.get<account_object,by_name>( name );
465
  //    idump(("recipient")(Name(name))(recipient.code_version));
466 467 468 469 470 471 472 473

      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;
474
            state.code_version = fc::sha256();
475 476 477 478 479
         }
         state.module = new IR::Module();

        try
        {
480
          wlog( "LOADING CODE" );
481
          auto start = fc::time_point::now();
482 483 484 485 486 487 488
          Serialization::MemoryInputStream stream((const U8*)recipient.code.data(),recipient.code.size());
          WASM::serialize(stream,*state.module);

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

492 493 494
          current_memory = Runtime::getDefaultMemory(state.instance);

          char* memstart = &memoryRef<char>( current_memory, 0 );
495
         // state.init_memory.resize(1<<16); /// TODO: actually get memory size
496
          for( uint32_t i = 0; i < 10000; ++i )
497
              if( memstart[i] ) {
498
                   state.mem_end = i+1;
499
                   //std::cerr << (char)memstart[i];
500
              }
501
          ilog( "INIT MEMORY: ${size}", ("size", state.mem_end) );
502 503 504

          state.init_memory.resize(state.mem_end);
          memcpy( state.init_memory.data(), memstart, state.mem_end ); //state.init_memory.size() );
505 506
          std::cerr <<"\n";
          state.code_version = recipient.code_version;
507
          idump((state.code_version));
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
        }
        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 );
529
      current_state  = &state;
530
   }
531 532

} }