LCOV - code coverage report
Current view: top level - src/wasm - wasm-code-specialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 96 97 99.0 %
Date: 2017-04-26 Functions: 13 13 100.0 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/wasm/wasm-code-specialization.h"
       6             : 
       7             : #include "src/assembler-inl.h"
       8             : #include "src/objects-inl.h"
       9             : #include "src/source-position-table.h"
      10             : #include "src/wasm/decoder.h"
      11             : #include "src/wasm/wasm-module.h"
      12             : #include "src/wasm/wasm-opcodes.h"
      13             : 
      14             : using namespace v8::internal;
      15             : using namespace v8::internal::wasm;
      16             : 
      17             : namespace {
      18             : 
      19       81819 : int ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc) {
      20             :   DCHECK_EQ(static_cast<int>(kExprCallFunction), static_cast<int>(*pc));
      21       81819 :   decoder.Reset(pc + 1, pc + 6);
      22             :   uint32_t call_idx = decoder.consume_u32v("call index");
      23             :   DCHECK(decoder.ok());
      24             :   DCHECK_GE(kMaxInt, call_idx);
      25       81819 :   return static_cast<int>(call_idx);
      26             : }
      27             : 
      28      330246 : int AdvanceSourcePositionTableIterator(SourcePositionTableIterator& iterator,
      29             :                                        size_t offset_l) {
      30             :   DCHECK_GE(kMaxInt, offset_l);
      31       81819 :   int offset = static_cast<int>(offset_l);
      32             :   DCHECK(!iterator.done());
      33             :   int byte_pos;
      34       82809 :   do {
      35             :     byte_pos = iterator.source_position().ScriptOffset();
      36       82809 :     iterator.Advance();
      37      165618 :   } while (!iterator.done() && iterator.code_offset() <= offset);
      38       81819 :   return byte_pos;
      39             : }
      40             : 
      41             : class PatchDirectCallsHelper {
      42             :  public:
      43       43745 :   PatchDirectCallsHelper(WasmInstanceObject* instance, Code* code)
      44       43745 :       : source_pos_it(code->SourcePositionTable()), decoder(nullptr, nullptr) {
      45             :     FixedArray* deopt_data = code->deoptimization_data();
      46             :     DCHECK_EQ(2, deopt_data->length());
      47       43745 :     WasmCompiledModule* comp_mod = instance->compiled_module();
      48             :     int func_index = Smi::cast(deopt_data->get(1))->value();
      49       43745 :     func_bytes = comp_mod->module_bytes()->GetChars() +
      50       87490 :                  comp_mod->module()->functions[func_index].code_start_offset;
      51       43745 :   }
      52             : 
      53             :   SourcePositionTableIterator source_pos_it;
      54             :   Decoder decoder;
      55             :   const byte* func_bytes;
      56             : };
      57             : 
      58      378258 : bool IsAtWasmDirectCallTarget(RelocIterator& it) {
      59             :   DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode()));
      60      378258 :   Code* code = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
      61      297063 :   return code->kind() == Code::WASM_FUNCTION ||
      62      260665 :          code->kind() == Code::WASM_TO_JS_FUNCTION ||
      63      259855 :          code->kind() == Code::WASM_INTERPRETER_ENTRY ||
      64      607885 :          code->builtin_index() == Builtins::kIllegal ||
      65      378258 :          code->builtin_index() == Builtins::kWasmCompileLazy;
      66             : }
      67             : 
      68             : }  // namespace
      69             : 
      70       67256 : CodeSpecialization::CodeSpecialization(Isolate* isolate, Zone* zone)
      71      201768 :     : objects_to_relocate(isolate->heap(), ZoneAllocationPolicy(zone)) {}
      72             : 
      73      134512 : CodeSpecialization::~CodeSpecialization() {}
      74             : 
      75       28355 : void CodeSpecialization::RelocateMemoryReferences(Address old_start,
      76             :                                                   uint32_t old_size,
      77             :                                                   Address new_start,
      78             :                                                   uint32_t new_size) {
      79             :   DCHECK(old_mem_start == nullptr && old_mem_size == 0 &&
      80             :          new_mem_start == nullptr && new_mem_size == 0);
      81             :   DCHECK(old_start != new_start || old_size != new_size);
      82       28355 :   old_mem_start = old_start;
      83       28355 :   old_mem_size = old_size;
      84       28355 :   new_mem_start = new_start;
      85       28355 :   new_mem_size = new_size;
      86       28355 : }
      87             : 
      88        7624 : void CodeSpecialization::RelocateGlobals(Address old_start, Address new_start) {
      89             :   DCHECK(old_globals_start == 0 && new_globals_start == 0);
      90             :   DCHECK(old_start != 0 || new_start != 0);
      91        7624 :   old_globals_start = old_start;
      92        7624 :   new_globals_start = new_start;
      93        7624 : }
      94             : 
      95         300 : void CodeSpecialization::PatchTableSize(uint32_t old_size, uint32_t new_size) {
      96             :   DCHECK(old_function_table_size == 0 && new_function_table_size == 0);
      97             :   DCHECK(old_size != 0 || new_size != 0);
      98         300 :   old_function_table_size = old_size;
      99         300 :   new_function_table_size = new_size;
     100         300 : }
     101             : 
     102       59782 : void CodeSpecialization::RelocateDirectCalls(
     103             :     Handle<WasmInstanceObject> instance) {
     104             :   DCHECK(relocate_direct_calls_instance.is_null());
     105             :   DCHECK(!instance.is_null());
     106       59782 :   relocate_direct_calls_instance = instance;
     107       59782 : }
     108             : 
     109        3527 : void CodeSpecialization::RelocateObject(Handle<Object> old_obj,
     110             :                                         Handle<Object> new_obj) {
     111             :   DCHECK(!old_obj.is_null() && !new_obj.is_null());
     112        3527 :   has_objects_to_relocate = true;
     113             :   objects_to_relocate.Set(*old_obj, new_obj);
     114        3527 : }
     115             : 
     116       52314 : bool CodeSpecialization::ApplyToWholeInstance(
     117             :     WasmInstanceObject* instance, ICacheFlushMode icache_flush_mode) {
     118             :   DisallowHeapAllocation no_gc;
     119       52314 :   WasmCompiledModule* compiled_module = instance->compiled_module();
     120             :   FixedArray* code_table = compiled_module->ptr_to_code_table();
     121       52314 :   WasmModule* module = compiled_module->module();
     122       52314 :   std::vector<WasmFunction>* wasm_functions =
     123       52314 :       &compiled_module->module()->functions;
     124             :   DCHECK_EQ(wasm_functions->size() +
     125             :                 compiled_module->module()->num_exported_functions,
     126             :             code_table->length());
     127             : 
     128             :   bool changed = false;
     129       52314 :   int func_index = module->num_imported_functions;
     130             : 
     131             :   // Patch all wasm functions.
     132      167623 :   for (int num_wasm_functions = static_cast<int>(wasm_functions->size());
     133             :        func_index < num_wasm_functions; ++func_index) {
     134             :     Code* wasm_function = Code::cast(code_table->get(func_index));
     135      115309 :     if (wasm_function->builtin_index() == Builtins::kWasmCompileLazy) continue;
     136       89930 :     changed |= ApplyToWasmCode(wasm_function, icache_flush_mode);
     137             :   }
     138             : 
     139             :   // Patch all exported functions (if we shall relocate direct calls).
     140       52314 :   if (!relocate_direct_calls_instance.is_null()) {
     141             :     // If we patch direct calls, the instance registered for that
     142             :     // (relocate_direct_calls_instance) should match the instance we currently
     143             :     // patch (instance).
     144             :     DCHECK_EQ(instance, *relocate_direct_calls_instance);
     145      175877 :     for (auto exp : module->export_table) {
     146       81305 :       if (exp.kind != kExternalFunction) continue;
     147             :       Code* export_wrapper = Code::cast(code_table->get(func_index));
     148             :       DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind());
     149             :       // There must be exactly one call to WASM_FUNCTION or WASM_TO_JS_FUNCTION.
     150             :       for (RelocIterator it(export_wrapper,
     151       79831 :                             RelocInfo::ModeMask(RelocInfo::CODE_TARGET));
     152       90958 :            ; it.next()) {
     153             :         DCHECK(!it.done());
     154             :         // Ignore calls to other builtins like ToNumber.
     155      170789 :         if (!IsAtWasmDirectCallTarget(it)) continue;
     156       79831 :         Code* new_code = Code::cast(code_table->get(exp.index));
     157             :         it.rinfo()->set_target_address(new_code->GetIsolate(),
     158             :                                        new_code->instruction_start(),
     159      159662 :                                        UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
     160             :         break;
     161       90958 :       }
     162             :       changed = true;
     163       79831 :       func_index++;
     164             :     }
     165             :     DCHECK_EQ(code_table->length(), func_index);
     166             :   }
     167       52314 :   return changed;
     168             : }
     169             : 
     170      107813 : bool CodeSpecialization::ApplyToWasmCode(Code* code,
     171             :                                          ICacheFlushMode icache_flush_mode) {
     172             :   DisallowHeapAllocation no_gc;
     173             :   DCHECK_EQ(Code::WASM_FUNCTION, code->kind());
     174             : 
     175      107813 :   bool reloc_mem_addr = old_mem_start != new_mem_start;
     176      107813 :   bool reloc_mem_size = old_mem_size != new_mem_size;
     177      107813 :   bool reloc_globals = old_globals_start || new_globals_start;
     178      107813 :   bool patch_table_size = old_function_table_size || new_function_table_size;
     179             :   bool reloc_direct_calls = !relocate_direct_calls_instance.is_null();
     180      107813 :   bool reloc_objects = has_objects_to_relocate;
     181             : 
     182      107813 :   int reloc_mode = 0;
     183             :   auto add_mode = [&reloc_mode](bool cond, RelocInfo::Mode mode) {
     184      107813 :     if (cond) reloc_mode |= RelocInfo::ModeMask(mode);
     185             :   };
     186             :   add_mode(reloc_mem_addr, RelocInfo::WASM_MEMORY_REFERENCE);
     187             :   add_mode(reloc_mem_size, RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
     188             :   add_mode(reloc_globals, RelocInfo::WASM_GLOBAL_REFERENCE);
     189             :   add_mode(patch_table_size, RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE);
     190             :   add_mode(reloc_direct_calls, RelocInfo::CODE_TARGET);
     191             :   add_mode(reloc_objects, RelocInfo::EMBEDDED_OBJECT);
     192             : 
     193             :   std::unique_ptr<PatchDirectCallsHelper> patch_direct_calls_helper;
     194             :   bool changed = false;
     195             : 
     196      693875 :   for (RelocIterator it(code, reloc_mode); !it.done(); it.next()) {
     197      586062 :     RelocInfo::Mode mode = it.rinfo()->rmode();
     198      586062 :     switch (mode) {
     199             :       case RelocInfo::WASM_MEMORY_REFERENCE:
     200             :         DCHECK(reloc_mem_addr);
     201             :         it.rinfo()->update_wasm_memory_reference(code->GetIsolate(),
     202             :                                                  old_mem_start, new_mem_start,
     203      128516 :                                                  icache_flush_mode);
     204             :         changed = true;
     205       64258 :         break;
     206             :       case RelocInfo::WASM_MEMORY_SIZE_REFERENCE:
     207             :         DCHECK(reloc_mem_size);
     208             :         it.rinfo()->update_wasm_memory_size(code->GetIsolate(), old_mem_size,
     209      547472 :                                             new_mem_size, icache_flush_mode);
     210             :         changed = true;
     211      273736 :         break;
     212             :       case RelocInfo::WASM_GLOBAL_REFERENCE:
     213             :         DCHECK(reloc_globals);
     214             :         it.rinfo()->update_wasm_global_reference(
     215             :             code->GetIsolate(), old_globals_start, new_globals_start,
     216       70706 :             icache_flush_mode);
     217             :         changed = true;
     218       35353 :         break;
     219             :       case RelocInfo::CODE_TARGET: {
     220             :         DCHECK(reloc_direct_calls);
     221             :         // Skip everything which is not a wasm call (stack checks, traps, ...).
     222      207469 :         if (!IsAtWasmDirectCallTarget(it)) continue;
     223             :         // Iterate simultaneously over the relocation information and the source
     224             :         // position table. For each call in the reloc info, move the source
     225             :         // position iterator forward to that position to find the byte offset of
     226             :         // the respective call. Then extract the call index from the module wire
     227             :         // bytes to find the new compiled function.
     228       81819 :         size_t offset = it.rinfo()->pc() - code->instruction_start();
     229       81819 :         if (!patch_direct_calls_helper) {
     230             :           patch_direct_calls_helper.reset(new PatchDirectCallsHelper(
     231       43745 :               *relocate_direct_calls_instance, code));
     232             :         }
     233             :         int byte_pos = AdvanceSourcePositionTableIterator(
     234       81819 :             patch_direct_calls_helper->source_pos_it, offset);
     235             :         int called_func_index = ExtractDirectCallIndex(
     236             :             patch_direct_calls_helper->decoder,
     237       81819 :             patch_direct_calls_helper->func_bytes + byte_pos);
     238             :         FixedArray* code_table =
     239             :             relocate_direct_calls_instance->compiled_module()
     240       81819 :                 ->ptr_to_code_table();
     241             :         Code* new_code = Code::cast(code_table->get(called_func_index));
     242             :         it.rinfo()->set_target_address(new_code->GetIsolate(),
     243             :                                        new_code->instruction_start(),
     244      163638 :                                        UPDATE_WRITE_BARRIER, icache_flush_mode);
     245             :         changed = true;
     246       81819 :       } break;
     247             :       case RelocInfo::EMBEDDED_OBJECT: {
     248             :         DCHECK(reloc_objects);
     249        5096 :         Object* old = it.rinfo()->target_object();
     250             :         Handle<Object>* new_obj = objects_to_relocate.Find(old);
     251        5096 :         if (new_obj) {
     252             :           it.rinfo()->set_target_object(HeapObject::cast(**new_obj),
     253             :                                         UPDATE_WRITE_BARRIER,
     254             :                                         icache_flush_mode);
     255             :           changed = true;
     256             :         }
     257             :       } break;
     258             :       case RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE:
     259             :         DCHECK(patch_table_size);
     260             :         it.rinfo()->update_wasm_function_table_size_reference(
     261             :             code->GetIsolate(), old_function_table_size,
     262         300 :             new_function_table_size, icache_flush_mode);
     263             :         changed = true;
     264         150 :         break;
     265             :       default:
     266           0 :         UNREACHABLE();
     267             :     }
     268             :   }
     269             : 
     270      107813 :   return changed;
     271             : }

Generated by: LCOV version 1.10