wasm_interface.cpp 11.9 KB
Newer Older
1
#include <eos/chain/wasm_interface.hpp>
D
Daniel Larimer 已提交
2 3 4 5 6
#include <eos/chain/apply_context.hpp>
#include <boost/core/ignore_unused.hpp>

#include <Runtime/Runtime.h>
#include "IR/Module.h"
7 8 9 10 11 12 13 14
#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"
D
Daniel Larimer 已提交
15

16

P
Pravin 已提交
17
namespace eosio { namespace chain {
D
Daniel Larimer 已提交
18

19 20
   using namespace IR;
   using namespace Runtime;
21

D
Daniel Larimer 已提交
22 23 24 25 26 27 28
   struct module_state {
      Runtime::ModuleInstance* instance     = nullptr;
      IR::Module*              module       = nullptr;
      int                      mem_start    = 0;
      int                      mem_end      = 1<<16;
      vector<char>             init_memory;
      fc::sha256               code_version;
B
Brian Johnson 已提交
29 30
   };

D
Daniel Larimer 已提交
31
   struct root_resolver : Runtime::Resolver
32
   {
D
Daniel Larimer 已提交
33 34 35 36
      bool resolve(const string& modname,
                   const string& exportname,
                   ObjectType type,
                   ObjectInstance*& out) override
37
      {
D
Daniel Larimer 已提交
38 39 40 41
          // Try to resolve an intrinsic first.
          if(IntrinsicResolver::singleton.resolve(modname,exportname,type,out)) { return true; }
          FC_ASSERT( !"unresolvable", "${module}.${export}", ("module",modname)("export",exportname) );
          return false;
42
      }
D
Daniel Larimer 已提交
43
   };
M
Matias Romeo 已提交
44 45 46



D
Daniel Larimer 已提交
47 48 49 50 51
   std::mutex                     global_load_mutex;
   struct wasm_interface_impl {
      map<digest_type, module_state> code_cache;
      module_state*                  current_state = nullptr;
   };
M
Matias Romeo 已提交
52

D
Daniel Larimer 已提交
53 54
   wasm_interface::wasm_interface()
   :my( new wasm_interface_impl() ) {
M
Matias Romeo 已提交
55

56 57
   }

D
Daniel Larimer 已提交
58 59 60
   wasm_interface& wasm_interface::get() {
      static bool init_once = [](){  Runtime::init(); return true; }();
      boost::ignore_unused(init_once);
M
Matias Romeo 已提交
61

D
Daniel Larimer 已提交
62 63 64 65 66
      thread_local wasm_interface* single = nullptr;
      if( !single ) {
         single = new wasm_interface();
      }
      return *single;
67
   }
M
Matias Romeo 已提交
68

69

D
Daniel Larimer 已提交
70 71 72
   void wasm_interface::load( digest_type codeid, const char* code, size_t codesize ) 
   {
      std::unique_lock<std::mutex> lock(global_load_mutex);
73

D
Daniel Larimer 已提交
74 75 76 77 78 79
      FC_ASSERT( codeid != digest_type() );
      auto& state = my->code_cache[codeid];
      if( state.code_version == codeid ) {
         my->current_state = &state;
         return; /// already cached
      }
80

D
Daniel Larimer 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
      state.module = new IR::Module();

     try {
       Serialization::MemoryInputStream stream((const U8*)code,codesize);
       WASM::serializeWithInjection(stream,*state.module);

       root_resolver resolver;
       LinkResult link_result = linkModule( *state.module, resolver );
       state.instance         = instantiateModule( *state.module, move(link_result.resolvedImports) );
       FC_ASSERT( state.instance );

       auto current_memory = Runtime::getDefaultMemory(state.instance);
         
       char* memstart = &memoryRef<char>( current_memory, 0 );
       const auto allocated_memory = Runtime::getDefaultMemorySize(state.instance);
       for( uint64_t i = 0; i < allocated_memory; ++i )
       {
          if( memstart[i] ) {
             state.mem_end = i+1;
          }
       }
102

D
Daniel Larimer 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
       state.init_memory.resize(state.mem_end);
       memcpy( state.init_memory.data(), memstart, state.mem_end ); 
       state.code_version = codeid;
     }
     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;
     }
     my->current_state = &state;
   } /// wasm_interface::load
126

D
Daniel Larimer 已提交
127 128 129 130 131
   void wasm_interface::init( apply_context& context ) 
   { try {
      try {
         FunctionInstance* init = asFunctionNullable(getInstanceExport(my->current_state->instance,"init"));
         if( !init ) return; /// if not found then it is a no-op
D
Daniel Larimer 已提交
132

D
Daniel Larimer 已提交
133
         //checktimeStart = fc::time_point::now();
134

D
Daniel Larimer 已提交
135 136
         const FunctionType* functype = getFunctionType(init);
         FC_ASSERT( functype->parameters.size() == 0 );
A
Andrianto Lie 已提交
137

D
Daniel Larimer 已提交
138
         std::vector<Value> args(0);
A
Andrianto Lie 已提交
139

D
Daniel Larimer 已提交
140
         Runtime::invokeFunction(init,args);
A
Andrianto Lie 已提交
141

D
Daniel Larimer 已提交
142 143 144 145 146 147
      } catch( const Runtime::Exception& e ) {
          edump((string(describeExceptionCause(e.cause))));
          edump((e.callStack));
          throw;
      }
   } FC_CAPTURE_AND_RETHROW() } /// wasm_interface::init
148

D
Daniel Larimer 已提交
149 150 151 152 153 154 155 156
   void wasm_interface::apply( apply_context& context ) 
   { try {
      try {
         FunctionInstance* call = asFunctionNullable(getInstanceExport(my->current_state->instance,"apply") );
         if( !call ) {
            return;
         }
         //FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name))  );
157

D
Daniel Larimer 已提交
158
         FC_ASSERT( getFunctionType(call)->parameters.size() == 2 );
B
Brian Johnson 已提交
159

D
Daniel Larimer 已提交
160 161 162
  //       idump((current_validate_context->msg.code)(current_validate_context->msg.type)(current_validate_context->code));
         vector<Value> args = { Value(uint64_t(context.act.scope)),
                                Value(uint64_t(context.act.name)) };
B
Brian Johnson 已提交
163

D
Daniel Larimer 已提交
164 165 166 167
         auto& state = *my->current_state;
         char* memstart = &memoryRef<char>( getDefaultMemory(my->current_state->instance), 0 );
         memset( memstart + state.mem_end, 0, ((1<<16) - state.mem_end) );
         memcpy( memstart, state.init_memory.data(), state.mem_end);
168

D
Daniel Larimer 已提交
169
         //checktimeStart = fc::time_point::now();
170

D
Daniel Larimer 已提交
171 172 173 174 175 176 177
         Runtime::invokeFunction(call,args);
      } catch( const Runtime::Exception& e ) {
          edump((std::string(describeExceptionCause(e.cause))));
          edump((e.callStack));
          throw;
      }
   } FC_CAPTURE_AND_RETHROW() } /// wasm_interface::apply
178

D
Daniel Larimer 已提交
179 180
   Runtime::MemoryInstance* wasm_interface::memory()const {
      return Runtime::getDefaultMemory( my->current_state->instance );
181
   }
D
Daniel Larimer 已提交
182 183
   uint32_t wasm_interface::memory_size()const {
      return Runtime::getDefaultMemorySize( my->current_state->instance );
184 185
   }

D
Daniel Larimer 已提交
186 187 188 189 190 191 192 193
   DEFINE_INTRINSIC_FUNCTION2(env,assert,assert,none,i32,test,i32,msg) {
      elog( "assert" );
      /*
      const char* m = &Runtime::memoryRef<char>( wasm_interface::get().current_memory, msg );
     std::string message( m );
     if( !test ) edump((message));
     FC_ASSERT( test, "assertion failed: ${s}", ("s",message)("ptr",msg) );
     */
194
   }
195

D
Daniel Larimer 已提交
196 197 198 199 200
   DEFINE_INTRINSIC_FUNCTION1(env,printi,printi,none,i64,val) {
     std::cerr << uint64_t(val);
   }
   DEFINE_INTRINSIC_FUNCTION1(env,printd,printd,none,i64,val) {
     //std::cerr << DOUBLE(*reinterpret_cast<double *>(&val));
201
   }
202

D
Daniel Larimer 已提交
203 204 205 206 207 208 209 210
   DEFINE_INTRINSIC_FUNCTION1(env,printi128,printi128,none,i32,val) {
     auto& wasm  = wasm_interface::get();
     auto  mem   = wasm.memory();
     auto& value = memoryRef<unsigned __int128>( mem, val );
     /*
     fc::uint128_t v(value>>64, uint64_t(value) );
     std::cerr << fc::variant(v).get_string();
     */
211

D
Daniel Larimer 已提交
212 213 214 215
   }
   DEFINE_INTRINSIC_FUNCTION1(env,printn,printn,none,i64,val) {
     std::cerr << name(val).to_string();
   }
216

D
Daniel Larimer 已提交
217 218 219
   DEFINE_INTRINSIC_FUNCTION1(env,prints,prints,none,i32,charptr) {
     auto& wasm  = wasm_interface::get();
     auto  mem   = wasm.memory();
220

D
Daniel Larimer 已提交
221 222
     const char* str = &memoryRef<const char>( mem, charptr );
     const auto allocated_memory = wasm.memory_size(); //Runtime::getDefaultMemorySize(state.instance);
223

D
Daniel Larimer 已提交
224 225
     std::cerr << std::string( str, strnlen(str, allocated_memory-charptr) );
   }
226

D
Daniel Larimer 已提交
227
DEFINE_INTRINSIC_FUNCTION2(env,readMessage,readMessage,i32,i32,destptr,i32,destsize) {
228
   FC_ASSERT( destsize > 0 );
229

D
Daniel Larimer 已提交
230
   /*
231 232
   wasm_interface& wasm = wasm_interface::get();
   auto  mem   = wasm.current_memory;
233
   char* begin = memoryArrayPtr<char>( mem, destptr, uint32_t(destsize) );
234 235

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

D
Daniel Larimer 已提交
237
//   wdump((destsize)(wasm.current_validate_context->msg.data.size()));
238
   memcpy( begin, wasm.current_validate_context->msg.data.data(), minlen );
D
Daniel Larimer 已提交
239 240
   */
   return 0;//minlen;
A
Andrianto Lie 已提交
241 242
}

243

244

D
Daniel Larimer 已提交
245 246 247 248 249 250 251 252 253 254
#define READ_RECORD(READFUNC, INDEX, SCOPE) \
   return 0;
   /*
   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);
   */
255

D
Daniel Larimer 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
#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); \
277 278
   }

D
Daniel Larimer 已提交
279 280
#define UPDATE_RECORD(UPDATEFUNC, INDEX, DATASIZE) \
   return 0;
281

D
Daniel Larimer 已提交
282 283 284 285 286 287
   /*
   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);
   */
288

D
Daniel Larimer 已提交
289 290 291 292 293 294 295 296 297
#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); \
B
Brian Johnson 已提交
298 299
   }

D
Daniel Larimer 已提交
300 301
DEFINE_RECORD_READ_FUNCTIONS(i64,,key_value_index, by_scope_primary);
DEFINE_RECORD_UPDATE_FUNCTIONS(i64, key_value_index);
B
Brian Johnson 已提交
302

D
Daniel Larimer 已提交
303 304 305
DEFINE_INTRINSIC_FUNCTION1(env,requireAuth,requireAuth,none,i64,account) {
   //wasm_interface::get().current_validate_context->require_authorization( Name(account) );
}
B
Brian Johnson 已提交
306

D
Daniel Larimer 已提交
307 308 309 310 311 312 313 314 315
DEFINE_INTRINSIC_FUNCTION1(env,requireNotice,requireNotice,none,i64,account) {
   //wasm_interface::get().current_validate_context->require_authorization( Name(account) );
}
DEFINE_INTRINSIC_FUNCTION0(env,checktime,checktime,none) {
   /*
   auto dur = wasm_interface::get().current_execution_time();
   if (dur > CHECKTIME_LIMIT) {
      wlog("checktime called ${d}", ("d", dur));
      throw checktime_exceeded();
B
Brian Johnson 已提交
316
   }
D
Daniel Larimer 已提交
317 318
   */
}
B
Brian Johnson 已提交
319 320


D
Daniel Larimer 已提交
321
} } /// eosio::chain