wasm_interface.cpp 20.3 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 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
DEFINE_INTRINSIC_FUNCTION2(env,multeq_i128,multeq_i128,none,i32,self,i32,other) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
   uint128_t& v = memoryRef<uint128_t>( mem, self );
   const uint128_t& o= memoryRef<const uint128_t>( mem, other );
   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;
   uint128_t& v       = memoryRef<uint128_t>( mem, self );
   const uint128_t& o = memoryRef<const uint128_t>( mem, other );
   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 69 70 71 72 73 74 75 76 77 78 79 80 81 82
}

DEFINE_INTRINSIC_FUNCTION3(env,remove_i128i128,remove_i128i128,i32,i64,scope,i64,table,i32,data) {
   FC_ASSERT( !"remove not implemented" );
   return 0;
}

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) {
83
   wlog( "back primary" );
84 85 86 87 88 89
   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) {
90
   wlog( "front primary" );
91 92 93
   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),
94 95
                                                                          (uint128_t*)v, (uint128_t*)(v+sizeof(uint128_t)), 
                                                                          v, datalen-(2*sizeof(uint128_t)) ) + 2*sizeof(uint128_t);
96 97 98
}

DEFINE_INTRINSIC_FUNCTION5(env,back_secondary_i128i128,back_secondary_i128i128,i32,i64,scope,i64,code,i64,table,i32,data,i32,datalen) {
99
   wlog( "back secondary" );
100
   auto& wasm  = wasm_interface::get();
101 102 103 104
   char* v     = memoryArrayPtr<char>( wasm.current_memory, data, datalen );



105 106 107 108
   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) {
109 110
   wlog( "front secondary" );
   FC_ASSERT( datalen >= 2*sizeof(uint128_t), "insufficient data passed" );
111
   auto& wasm  = wasm_interface::get();
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

   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;
129 130
}

131 132 133 134
DEFINE_INTRINSIC_FUNCTION0(env,currentCode,currentCode,i64) {
   auto& wasm  = wasm_interface::get();
   return wasm.current_validate_context->code.value;
}
135

136
DEFINE_INTRINSIC_FUNCTION1(env,requireAuth,requireAuth,none,i64,account) {
137
   wasm_interface::get().current_validate_context->require_authorization( Name(account) );
138
}
D
Daniel Larimer 已提交
139

140
DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) {
141
   wasm_interface::get().current_validate_context->require_recipient( account );
142 143 144
}

DEFINE_INTRINSIC_FUNCTION1(env,requireScope,requireScope,none,i64,scope) {
145
   wasm_interface::get().current_validate_context->require_scope( scope );
146 147 148 149
}

DEFINE_INTRINSIC_FUNCTION5(env,store_i64,store_i64,i32,i64,scope,i64,table,i64,key,i32,valueptr,i32,valuelen) 
{
D
Daniel Larimer 已提交
150 151 152 153
   auto& wasm  = wasm_interface::get();
   FC_ASSERT( wasm.current_apply_context, "no apply context found" );

   auto  mem   = wasm.current_memory;
154
   char* value = memoryArrayPtr<char>( mem, valueptr, valuelen);
D
Daniel Larimer 已提交
155

156 157
   //idump((Name(scope))(Name(code))(Name(table))(Name(key))(valuelen) );

158
   return wasm.current_apply_context->store_i64( scope, table, key, value, valuelen );
159
}
160

161 162 163 164 165 166 167 168 169 170 171 172
DEFINE_INTRINSIC_FUNCTION6(env,load_i64,load_i64,i32,i64,scope,i64,code,i64,table,i64,key,i32,valueptr,i32,valuelen) 
{
   //idump((Name(scope))(Name(code))(Name(table))(Name(key))(valuelen) );

   FC_ASSERT( valuelen >= 0 );

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

173
   return wasm.current_validate_context->load_i64( scope, code, table, key, value, valuelen );
174
}
175

176
DEFINE_INTRINSIC_FUNCTION3(env,remove_i64,remove_i64,i32,i64,scope,i64,table,i64,key) {
177 178
   auto& wasm  = wasm_interface::get();
   FC_ASSERT( wasm.current_apply_context, "no apply context found" );
179
   return wasm.current_apply_context->remove_i64( scope, table, key );
180 181 182 183 184 185 186
}

DEFINE_INTRINSIC_FUNCTION3(env,memcpy,memcpy,i32,i32,dstp,i32,srcp,i32,len) {
   auto& wasm          = wasm_interface::get();
   auto  mem           = wasm.current_memory;
   char* dst           = &memoryRef<char>( mem, dstp);
   const char* src     = &memoryRef<const char>( mem, srcp );
187
   //char* dst_end       = &memoryRef<char>( mem, dstp+uint32_t(len));
188 189 190 191 192
   const char* src_end = &memoryRef<const char>( mem, srcp+uint32_t(len) );

#warning TODO: wasm memcpy has undefined behavior if memory ranges overlap
/*
   if( dst > src )
193
      FC_ASSERT( dst < src_end && src < dst_end, "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
194
   else
195
      FC_ASSERT( src < dst_end && dst < src_end, "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
196 197 198 199 200 201 202 203 204 205
*/
   memcpy( dst, src, uint32_t(len) );
   return dstp;
}


DEFINE_INTRINSIC_FUNCTION2(env,Varint_unpack,Varint_unpack,none,i32,streamptr,i32,valueptr) {
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;

206
   uint32_t* stream = memoryArrayPtr<uint32_t>( mem, streamptr, 3 );
207 208 209 210 211 212 213 214 215 216 217 218 219
   const char* pos = &memoryRef<const char>( mem, stream[1] );
   const char* end = &memoryRef<const char>( mem, stream[2] );
   uint32_t& value = memoryRef<uint32_t>( mem, valueptr );

   fc::unsigned_int vi;
   fc::datastream<const char*> ds(pos,end-pos);
   fc::raw::unpack( ds, vi );
   value = vi.value;

   stream[1] += ds.pos() - pos;
}


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 246 247 248
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) );
249

D
Daniel Larimer 已提交
250 251
   return 0;
}
252

253 254 255



256 257 258 259
DEFINE_INTRINSIC_FUNCTION2(env,readMessage,readMessage,i32,i32,destptr,i32,destsize) {
   FC_ASSERT( destsize > 0 );
   wasm_interface& wasm = wasm_interface::get();
   auto  mem   = wasm.current_memory;
260
   char* begin = memoryArrayPtr<char>( mem, destptr, destsize );
261 262 263 264 265 266

   int minlen = std::min<int>(wasm.current_validate_context->msg.data.size(), destsize);
   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 294 295 296 297 298
  std::cerr << uint64_t(val);
}

DEFINE_INTRINSIC_FUNCTION1(env,printi128,printi128,none,i32,val) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;
  fc::uint128_t& value = memoryRef<fc::uint128_t>( mem, val );
  std::cerr << fc::variant(value).get_string();
}
DEFINE_INTRINSIC_FUNCTION1(env,printn,printn,none,i64,val) {
  std::cerr << Name(val).toString();
299
}
300

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

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

307
  std::cerr << std::string( str, strlen(str) );
308 309
}

310
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
311 312
}

313
DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
314 315 316 317 318 319 320 321 322 323 324 325 326
   std::cerr << "TO UPPER CALLED\n";// << charptr << "\n";
//   std::cerr << "moduleInstance: " << moduleInstance << "\n";
  // /*U8* base = */Runtime::getMemoryBaseAddress( Runtime::getDefaultMemory(moduleInstance) );
   //std::cerr << "Base Address: " << (int64_t)base;
   //char* c = (char*)(base + charptr);
   char& c = Runtime::memoryRef<char>( Runtime::getDefaultMemory(wasm_interface::get().current_module), charptr );
//   std::cerr << "char: " << c <<"\n";
//   if( c > 'Z' ) c -= 32;
//   return 0;
}

   wasm_interface& wasm_interface::get() {
      static wasm_interface*  wasm = nullptr;
327
      if( !wasm )
328 329
      {
         wlog( "Runtime::init" );
330
         Runtime::init();
331 332 333 334 335 336 337 338 339 340 341 342 343
         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
     {
344 345 346 347
         // 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;
348 349 350 351 352
     }
   };


   char* wasm_interface::vm_allocate( int bytes ) {
353 354
      FunctionInstance* alloc_function = asFunctionNullable(getInstanceExport(current_module,"alloc"));
      const FunctionType* functionType = getFunctionType(alloc_function);
355
      FC_ASSERT( functionType->parameters.size() == 1 );
356
      std::vector<Value> invokeArgs(1);
357 358 359 360 361 362 363 364 365 366 367
      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 已提交
368
   void  wasm_interface::vm_call( const char* name ) {
369
   try {
370
      try {
D
Daniel Larimer 已提交
371
         /*
372
         name += "_" + std::string( current_validate_context->msg.code ) + "_";
373
         name += std::string( current_validate_context->msg.type );
D
Daniel Larimer 已提交
374 375 376
         */
         /// TODO: cache this somehow
         FunctionInstance* call = asFunctionNullable(getInstanceExport(current_module,name) );
377 378 379 380
         if( !call ) {
            //wlog( "unable to find call ${name}", ("name",name));
            return;
         }
D
Daniel Larimer 已提交
381
         //FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name))  );
382

D
Daniel Larimer 已提交
383
         FC_ASSERT( getFunctionType(call)->parameters.size() == 2 );
384 385

         idump((current_validate_context->msg.code)(current_validate_context->msg.type)(current_validate_context->code));
D
Daniel Larimer 已提交
386 387
         std::vector<Value> args = { Value(uint64_t(current_validate_context->msg.code)),
                                     Value(uint64_t(current_validate_context->msg.type)) };
388 389 390 391 392 393

         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 已提交
394
         Runtime::invokeFunction(call,args);
395 396
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
397 398
          edump((e.callStack));
          throw;
399
      }
400 401
   } FC_CAPTURE_AND_RETHROW( (name)(current_validate_context->msg.type) ) }

D
Daniel Larimer 已提交
402 403 404
   void  wasm_interface::vm_precondition() { vm_call("precondition" ); } 
   void  wasm_interface::vm_apply()        { vm_call("apply" );        }
   void  wasm_interface::vm_validate()     { vm_call("validate");       }
405

406
   void  wasm_interface::vm_onInit()
407 408
   { try {
      try {
409
          wlog( "on_init" );
410 411
            FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init"));
            if( !apply ) {
412
               elog( "no onInit method found" );
413
               return; /// if not found then it is a no-op
414 415
         }

416 417
            const FunctionType* functionType = getFunctionType(apply);
            FC_ASSERT( functionType->parameters.size() == 0 );
418

419
            std::vector<Value> args(0);
420

421
            Runtime::invokeFunction(apply,args);
422 423
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
424 425
          edump((e.callStack));
          throw;
426
      }
427
   } FC_CAPTURE_AND_RETHROW() }
428

429 430 431 432 433 434
   void wasm_interface::validate( message_validate_context& c ) {

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

D
Daniel Larimer 已提交
435
      load( c.code, c.db );
436 437
      vm_validate();
   }
438 439 440 441 442 443
   void wasm_interface::precondition( precondition_validate_context& c ) {
   try {

      current_validate_context       = &c;
      current_precondition_context   = &c;

D
Daniel Larimer 已提交
444
      load( c.code, c.db );
445 446 447
      vm_precondition();

   } FC_CAPTURE_AND_RETHROW() }
448 449


450 451
   void wasm_interface::apply( 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 458 459 460 461 462
      vm_apply();

   } FC_CAPTURE_AND_RETHROW() }

   void wasm_interface::init( apply_context& c ) {
    try {
463 464 465 466
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
467
      load( c.code, c.db );
468
      vm_onInit();
469 470 471

   } FC_CAPTURE_AND_RETHROW() }

472

473

474 475
   void wasm_interface::load( const AccountName& name, const chainbase::database& db ) {
      const auto& recipient = db.get<account_object,by_name>( name );
476
  //    idump(("recipient")(Name(name))(recipient.code_version));
477 478 479 480 481 482 483 484

      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;
485
            state.code_version = fc::sha256();
486 487 488 489 490
         }
         state.module = new IR::Module();

        try
        {
491
          wlog( "LOADING CODE" );
492
          auto start = fc::time_point::now();
493 494 495 496 497 498 499
          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 );
500 501 502
          auto end = fc::time_point::now();
          idump(( (end-start).count()/1000000.0) );

503 504 505
          current_memory = Runtime::getDefaultMemory(state.instance);

          char* memstart = &memoryRef<char>( current_memory, 0 );
506
         // state.init_memory.resize(1<<16); /// TODO: actually get memory size
507
          for( uint32_t i = 0; i < 10000; ++i )
508
              if( memstart[i] ) {
509
                   state.mem_end = i+1;
510
                   //std::cerr << (char)memstart[i];
511
              }
512
          ilog( "INIT MEMORY: ${size}", ("size", state.mem_end) );
513 514 515

          state.init_memory.resize(state.mem_end);
          memcpy( state.init_memory.data(), memstart, state.mem_end ); //state.init_memory.size() );
516 517
          std::cerr <<"\n";
          state.code_version = recipient.code_version;
518
          idump((state.code_version));
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
        }
        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 );
540
      current_state  = &state;
541
   }
542 543

} }