wasm_interface.cpp 24.0 KB
Newer Older
1
#include <boost/function.hpp>
2
#include <boost/multiprecision/cpp_bin_float.hpp>
3
#include <eos/chain/wasm_interface.hpp>
4
#include <eos/chain/chain_controller.hpp>
5 6 7 8 9 10 11 12 13
#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>
14
#include <eos/chain/account_object.hpp>
15
#include <chrono>
16 17 18 19

namespace eos { namespace chain {
   using namespace IR;
   using namespace Runtime;
20
   typedef boost::multiprecision::cpp_bin_float_50 DOUBLE;
21

22 23 24
   wasm_interface::wasm_interface() {
   }

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

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

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

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

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

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
#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); \
80
   }
M
Matias Romeo 已提交
81

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
#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 已提交
104

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

108 109 110
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 已提交
111

112 113 114 115
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 已提交
116

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
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 );
}
140

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

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

M
Matias Romeo 已提交
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
DEFINE_INTRINSIC_FUNCTION2(env,double_add,double_add,i64,i64,a,i64,b) {
   DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a))
            + DOUBLE(*reinterpret_cast<double *>(&b));
   double res = c.convert_to<double>();
   return *reinterpret_cast<uint64_t *>(&res);
}

DEFINE_INTRINSIC_FUNCTION2(env,double_mult,double_mult,i64,i64,a,i64,b) {
   DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a))
            * DOUBLE(*reinterpret_cast<double *>(&b));
   double res = c.convert_to<double>();
   return *reinterpret_cast<uint64_t *>(&res);
}

DEFINE_INTRINSIC_FUNCTION2(env,double_div,double_div,i64,i64,a,i64,b) {
   auto divisor = DOUBLE(*reinterpret_cast<double *>(&b));
   FC_ASSERT( divisor != 0, "divide by zero" );

   DOUBLE c = DOUBLE(*reinterpret_cast<double *>(&a)) / divisor;
   double res = c.convert_to<double>();
   return *reinterpret_cast<uint64_t *>(&res);
}

DEFINE_INTRINSIC_FUNCTION2(env,double_lt,double_lt,i32,i64,a,i64,b) {
   return DOUBLE(*reinterpret_cast<double *>(&a))
        < DOUBLE(*reinterpret_cast<double *>(&b));
}

DEFINE_INTRINSIC_FUNCTION2(env,double_eq,double_eq,i32,i64,a,i64,b) {
   return DOUBLE(*reinterpret_cast<double *>(&a))
       == DOUBLE(*reinterpret_cast<double *>(&b));
}

DEFINE_INTRINSIC_FUNCTION2(env,double_gt,double_gt,i32,i64,a,i64,b) {
   return DOUBLE(*reinterpret_cast<double *>(&a))
        > DOUBLE(*reinterpret_cast<double *>(&b));
}

DEFINE_INTRINSIC_FUNCTION1(env,double_to_i64,double_to_i64,i64,i64,a) {
   return DOUBLE(*reinterpret_cast<double *>(&a))
          .convert_to<uint64_t>();
}

DEFINE_INTRINSIC_FUNCTION1(env,i64_to_double,i64_to_double,i64,i64,a) {
   double res = DOUBLE(a).convert_to<double>();
   return *reinterpret_cast<uint64_t *>(&res);
}

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

210 211 212 213 214 215
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) {
216
   wasm_interface::get().current_validate_context->require_authorization( Name(account) );
217
}
218

219
DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) {
220
   wasm_interface::get().current_apply_context->require_recipient( account );
221
}
222

223
DEFINE_INTRINSIC_FUNCTION1(env,requireScope,requireScope,none,i64,scope) {
224
   wasm_interface::get().current_validate_context->require_scope( scope );
225 226 227 228 229
}

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 已提交
230 231 232
   char* dst           = memoryArrayPtr<char>( mem, dstp, len);
   const char* src     = memoryArrayPtr<const char>( mem, srcp, len );
   FC_ASSERT( len > 0 );
233 234

   if( dst > src )
D
Daniel Larimer 已提交
235
      FC_ASSERT( dst >= (src + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );
236
   else
D
Daniel Larimer 已提交
237 238
      FC_ASSERT( src >= (dst + len), "overlap of memory range is undefined", ("d",dstp)("s",srcp)("l",len) );

239 240 241 242 243
   memcpy( dst, src, uint32_t(len) );
   return dstp;
}


244 245 246 247 248 249 250 251 252 253
/**
 * Transaction C API implementation
 * @{
 */ 

DEFINE_INTRINSIC_FUNCTION0(env,transactionCreate,transactionCreate,i32) {
   auto& ptrx = wasm_interface::get().current_apply_context->create_pending_transaction();
   return ptrx.handle;
}

254 255 256 257 258 259 260
static void emplace_scope(const Name& scope, std::vector<Name>& scopes) {
   auto i = std::upper_bound( scopes.begin(), scopes.end(), scope);
   if (i == scopes.begin() || *(i - 1) != scope ) {
     scopes.insert(i, scope);
   }
}

261
DEFINE_INTRINSIC_FUNCTION3(env,transactionRequireScope,transactionRequireScope,none,i32,handle,i64,scope,i32,readOnly) {
262 263
   auto& ptrx = wasm_interface::get().current_apply_context->get_pending_transaction(handle);
   if(readOnly == 0) {
264
      emplace_scope(scope, ptrx.scope);
265
   } else {
266
      emplace_scope(scope, ptrx.readscope);
267 268 269 270 271
   }

   ptrx.check_size();
}

272 273 274 275 276 277 278
DEFINE_INTRINSIC_FUNCTION2(env,transactionAddMessage,transactionAddMessage,none,i32,handle,i32,msg_handle) {
   auto apply_context  = wasm_interface::get().current_apply_context;
   auto& ptrx = apply_context->get_pending_transaction(handle);
   auto& pmsg = apply_context->get_pending_message(msg_handle);
   ptrx.messages.emplace_back(pmsg);
   ptrx.check_size();
   apply_context->release_pending_message(msg_handle);
279 280
}

281 282 283 284 285 286 287 288 289 290 291 292 293
DEFINE_INTRINSIC_FUNCTION1(env,transactionSend,transactionSend,none,i32,handle) {
   auto apply_context  = wasm_interface::get().current_apply_context;
   auto& ptrx = apply_context->get_pending_transaction(handle);

   EOS_ASSERT(ptrx.messages.size() > 0, tx_unknown_argument,
      "Attempting to send a transaction with no messages");

   apply_context->deferred_transactions.emplace_back(ptrx);
   apply_context->release_pending_transaction(handle);
}

DEFINE_INTRINSIC_FUNCTION1(env,transactionDrop,transactionDrop,none,i32,handle) {
   wasm_interface::get().current_apply_context->release_pending_transaction(handle);
294 295
}

296
DEFINE_INTRINSIC_FUNCTION4(env,messageCreate,messageCreate,i32,i64,code,i64,type,i32,data,i32,length) {
297 298
   auto& wasm  = wasm_interface::get();
   auto  mem   = wasm.current_memory;
299
   
300 301
   EOS_ASSERT( length >= 0, tx_unknown_argument,
      "Pushing a message with a negative length" );
302

303
   Bytes payload;
304 305 306 307 308 309 310 311 312 313
   if (length > 0) {
      try {
         // memoryArrayPtr checks that the entire array of bytes is valid and
         // within the bounds of the memory segment so that transactions cannot pass
         // bad values in attempts to read improper memory
         const char* buffer = memoryArrayPtr<const char>( mem, uint32_t(data), uint32_t(length) );
         payload.insert(payload.end(), buffer, buffer + length);
      } catch( const Runtime::Exception& e ) {
         FC_THROW_EXCEPTION(tx_unknown_argument, "Message data is not a valid memory range");
      }
314
   }
315

316
   auto& pmsg = wasm.current_apply_context->create_pending_message(Name(code), Name(type), payload);
317
   return pmsg.handle;
318 319
}

320 321
DEFINE_INTRINSIC_FUNCTION3(env,messageRequirePermission,messageRequirePermission,none,i32,handle,i64,account,i64,permission) {
   auto apply_context  = wasm_interface::get().current_apply_context;
322 323 324 325 326
   // if this is not sent from the code account with the permission of "code" then we must
   // presently have the permission to add it, otherwise its a failure
   if (!(account == apply_context->code.value && Name(permission) == Name("code"))) {
      apply_context->require_authorization(Name(account), Name(permission));
   }
327 328
   auto& pmsg = apply_context->get_pending_message(handle);
   pmsg.authorization.emplace_back(Name(account), Name(permission));
D
Daniel Larimer 已提交
329
}
330

331
DEFINE_INTRINSIC_FUNCTION1(env,messageSend,messageSend,none,i32,handle) {
332
   auto apply_context  = wasm_interface::get().current_apply_context;
333
   auto& pmsg = apply_context->get_pending_message(handle);
334

335 336
   apply_context->inline_messages.emplace_back(pmsg);
   apply_context->release_pending_message(handle);
337 338
}

339 340
DEFINE_INTRINSIC_FUNCTION1(env,messageDrop,messageDrop,none,i32,handle) {
   wasm_interface::get().current_apply_context->release_pending_message(handle);
341 342 343 344 345
}

/**
 * @} Transaction C API implementation
 */ 
346 347 348



349 350
DEFINE_INTRINSIC_FUNCTION2(env,readMessage,readMessage,i32,i32,destptr,i32,destsize) {
   FC_ASSERT( destsize > 0 );
351

352 353
   wasm_interface& wasm = wasm_interface::get();
   auto  mem   = wasm.current_memory;
354
   char* begin = memoryArrayPtr<char>( mem, destptr, uint32_t(destsize) );
355 356

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

D
Daniel Larimer 已提交
358
//   wdump((destsize)(wasm.current_validate_context->msg.data.size()));
359 360 361 362
   memcpy( begin, wasm.current_validate_context->msg.data.data(), minlen );
   return minlen;
}

363
DEFINE_INTRINSIC_FUNCTION2(env,assert,assert,none,i32,test,i32,msg) {
364 365
   const char* m = &Runtime::memoryRef<char>( wasm_interface::get().current_memory, msg );
  std::string message( m );
366
  if( !test ) edump((message));
367
  FC_ASSERT( test, "assertion failed: ${s}", ("s",message)("ptr",msg) );
368
}
369

370 371 372 373
DEFINE_INTRINSIC_FUNCTION0(env,messageSize,messageSize,i32) {
   return wasm_interface::get().current_validate_context->msg.data.size();
}

374
DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
375 376 377 378 379 380 381 382
   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;
}

383
DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i64,val) {
384
  std::cerr << uint64_t(val);
385
}
M
Matias Romeo 已提交
386 387 388
DEFINE_INTRINSIC_FUNCTION1(env,printd,printd,none,i64,val) {
  std::cerr << DOUBLE(*reinterpret_cast<double *>(&val));
}
389

390 391 392
DEFINE_INTRINSIC_FUNCTION1(env,printi128,printi128,none,i32,val) {
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;
393 394 395
  auto& value = memoryRef<unsigned __int128>( mem, val );
  fc::uint128_t v(value>>64, uint64_t(value) );
  std::cerr << fc::variant(v).get_string();
396 397 398
}
DEFINE_INTRINSIC_FUNCTION1(env,printn,printn,none,i64,val) {
  std::cerr << Name(val).toString();
399
}
400

401
DEFINE_INTRINSIC_FUNCTION1(env,prints,prints,none,i32,charptr) {
402 403 404
  auto& wasm  = wasm_interface::get();
  auto  mem   = wasm.current_memory;

405
  const char* str = &memoryRef<const char>( mem, charptr );
406

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

410
DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
411 412 413 414
}

   wasm_interface& wasm_interface::get() {
      static wasm_interface*  wasm = nullptr;
415
      if( !wasm )
416 417
      {
         wlog( "Runtime::init" );
418
         Runtime::init();
419 420 421 422 423 424 425 426 427 428 429 430 431
         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
     {
432 433 434 435
         // 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;
436 437 438
     }
   };

439 440 441 442 443
   int64_t wasm_interface::current_execution_time()
   {
      return (fc::time_point::now() - checktimeStart).count();
   }

444 445

   char* wasm_interface::vm_allocate( int bytes ) {
446 447
      FunctionInstance* alloc_function = asFunctionNullable(getInstanceExport(current_module,"alloc"));
      const FunctionType* functionType = getFunctionType(alloc_function);
448
      FC_ASSERT( functionType->parameters.size() == 1 );
449
      std::vector<Value> invokeArgs(1);
450 451
      invokeArgs[0] = U32(bytes);

452
      checktimeStart = fc::time_point::now();
453

454 455 456 457 458 459 460 461 462
      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 已提交
463
   void  wasm_interface::vm_call( const char* name ) {
464
   try {
465
      try {
D
Daniel Larimer 已提交
466
         /*
467
         name += "_" + std::string( current_validate_context->msg.code ) + "_";
468
         name += std::string( current_validate_context->msg.type );
D
Daniel Larimer 已提交
469 470 471
         */
         /// TODO: cache this somehow
         FunctionInstance* call = asFunctionNullable(getInstanceExport(current_module,name) );
472 473 474 475
         if( !call ) {
            //wlog( "unable to find call ${name}", ("name",name));
            return;
         }
D
Daniel Larimer 已提交
476
         //FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name))  );
477

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

D
Daniel Larimer 已提交
480
  //       idump((current_validate_context->msg.code)(current_validate_context->msg.type)(current_validate_context->code));
481
         std::vector<Value> args = { Value(uint64_t(current_validate_context->msg.code)),
D
Daniel Larimer 已提交
482
                                     Value(uint64_t(current_validate_context->msg.type)) };
483 484 485 486 487 488

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

489
         checktimeStart = fc::time_point::now();
490

D
Daniel Larimer 已提交
491
         Runtime::invokeFunction(call,args);
492 493
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
494 495
          edump((e.callStack));
          throw;
496
      }
497 498
   } FC_CAPTURE_AND_RETHROW( (name)(current_validate_context->msg.type) ) }

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

501
   void  wasm_interface::vm_onInit()
502 503
   { try {
      try {
504
          wlog( "on_init" );
505 506
            FunctionInstance* apply = asFunctionNullable(getInstanceExport(current_module,"init"));
            if( !apply ) {
507
               elog( "no onInit method found" );
508
               return; /// if not found then it is a no-op
509 510
         }

511
         checktimeStart = fc::time_point::now();
512

513 514
            const FunctionType* functionType = getFunctionType(apply);
            FC_ASSERT( functionType->parameters.size() == 0 );
515

516
            std::vector<Value> args(0);
517

518
            Runtime::invokeFunction(apply,args);
519 520
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
521 522
          edump((e.callStack));
          throw;
523
      }
524
   } FC_CAPTURE_AND_RETHROW() }
525

526
   void wasm_interface::validate( apply_context& c ) {
D
Daniel Larimer 已提交
527
      /*
528 529 530 531
      current_validate_context       = &c;
      current_precondition_context   = nullptr;
      current_apply_context          = nullptr;

D
Daniel Larimer 已提交
532
      load( c.code, c.db );
533
      vm_validate();
D
Daniel Larimer 已提交
534
      */
535
   }
536
   void wasm_interface::precondition( apply_context& c ) {
537 538
   try {

D
Daniel Larimer 已提交
539
      /*
540 541 542
      current_validate_context       = &c;
      current_precondition_context   = &c;

D
Daniel Larimer 已提交
543
      load( c.code, c.db );
544
      vm_precondition();
D
Daniel Larimer 已提交
545
      */
546 547

   } FC_CAPTURE_AND_RETHROW() }
548 549


550 551
   void wasm_interface::apply( apply_context& c ) {
    try {
552 553 554 555
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
556
      load( c.code, c.db );
557 558 559 560 561 562
      vm_apply();

   } FC_CAPTURE_AND_RETHROW() }

   void wasm_interface::init( apply_context& c ) {
    try {
563 564 565 566
      current_validate_context       = &c;
      current_precondition_context   = &c;
      current_apply_context          = &c;

D
Daniel Larimer 已提交
567
      load( c.code, c.db );
568
      vm_onInit();
569 570 571

   } FC_CAPTURE_AND_RETHROW() }

572

573

574 575
   void wasm_interface::load( const AccountName& name, const chainbase::database& db ) {
      const auto& recipient = db.get<account_object,by_name>( name );
576
  //    idump(("recipient")(Name(name))(recipient.code_version));
577 578 579 580 581 582 583 584

      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;
585
            state.code_version = fc::sha256();
586 587 588 589 590
         }
         state.module = new IR::Module();

        try
        {
591
          wlog( "LOADING CODE" );
592
          auto start = fc::time_point::now();
593
          Serialization::MemoryInputStream stream((const U8*)recipient.code.data(),recipient.code.size());
594
          WASM::serializeWithInjection(stream,*state.module);
595 596 597 598 599

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

603 604 605
          current_memory = Runtime::getDefaultMemory(state.instance);

          char* memstart = &memoryRef<char>( current_memory, 0 );
606
         // state.init_memory.resize(1<<16); /// TODO: actually get memory size
607
          for( uint32_t i = 0; i < 10000; ++i )
608
              if( memstart[i] ) {
609
                   state.mem_end = i+1;
610
                   //std::cerr << (char)memstart[i];
611
              }
612
          ilog( "INIT MEMORY: ${size}", ("size", state.mem_end) );
613 614 615

          state.init_memory.resize(state.mem_end);
          memcpy( state.init_memory.data(), memstart, state.mem_end ); //state.init_memory.size() );
616 617
          std::cerr <<"\n";
          state.code_version = recipient.code_version;
618
          idump((state.code_version));
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
        }
        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 );
640
      current_state  = &state;
641
   }
642 643

} }