Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(322)

Side by Side Diff: src/wasm/wasm-code-specialization.cc

Issue 2696143006: [wasm] Refactor code specialization / patching (Closed)
Patch Set: Remove unused variables and add documentation Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 int ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc) {
20 DCHECK_EQ(static_cast<int>(kExprCallFunction), static_cast<int>(*pc));
21 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 return static_cast<int>(call_idx);
26 }
27
28 int AdvanceSourcePositionTableIterator(SourcePositionTableIterator& iterator,
29 size_t offset_l) {
30 DCHECK_GE(kMaxInt, offset_l);
31 int offset = static_cast<int>(offset_l);
32 DCHECK(!iterator.done());
33 int byte_pos;
34 do {
35 byte_pos = iterator.source_position().ScriptOffset();
36 iterator.Advance();
37 } while (!iterator.done() && iterator.code_offset() <= offset);
38 return byte_pos;
39 }
40
41 } // namespace
42
43 void CodeSpecialization::RelocateMemoryReferences(Address old_start,
44 uint32_t old_size,
45 Address new_start,
46 uint32_t new_size) {
47 DCHECK(old_mem_start == 0 && new_mem_start == 0);
48 DCHECK(old_start != 0 || new_start != 0);
49 old_mem_start = old_start;
50 old_mem_size = old_size;
51 new_mem_start = new_start;
52 new_mem_size = new_size;
53 }
54
55 void CodeSpecialization::RelocateGlobals(Address old_start, Address new_start) {
56 DCHECK(old_globals_start == 0 && new_globals_start == 0);
57 DCHECK(old_start != 0 || new_start != 0);
58 old_globals_start = old_start;
59 new_globals_start = new_start;
60 }
61
62 void CodeSpecialization::PatchTableSize(uint32_t old_size, uint32_t new_size) {
63 DCHECK(old_function_table_size == 0 && new_function_table_size == 0);
64 DCHECK(old_size != 0 || new_size != 0);
65 old_function_table_size = old_size;
66 new_function_table_size = new_size;
67 }
68
69 void CodeSpecialization::RelocateDirectCalls(WasmInstanceObject* instance) {
70 DCHECK_NULL(relocate_direct_calls_instance);
71 DCHECK_NOT_NULL(instance);
72 relocate_direct_calls_instance = instance;
73 }
74
75 void CodeSpecialization::RelocateObject(Object* old_obj, Object* new_obj) {
76 DCHECK(old_obj && new_obj);
77 objects_to_relocate.insert(std::make_pair(old_obj, new_obj));
78 }
79
80 bool CodeSpecialization::ApplyToWholeInstance(
81 WasmInstanceObject* instance, ICacheFlushMode icache_flush_mode) {
82 WasmCompiledModule* compiled_module = instance->compiled_module();
83 FixedArray* code_table = compiled_module->ptr_to_code_table();
84 WasmModule* module = compiled_module->module();
85 std::vector<WasmFunction>* wasm_functions =
86 &compiled_module->module()->functions;
87 DCHECK_EQ(wasm_functions->size() +
88 compiled_module->module()->num_exported_functions,
89 code_table->length());
90
91 bool changed = false;
92 int func_index = module->num_imported_functions;
93
94 // Patch all wasm functions.
95 for (int num_wasm_functions = static_cast<int>(wasm_functions->size());
96 func_index < num_wasm_functions; ++func_index) {
97 Code* wasm_function = Code::cast(code_table->get(func_index));
98 changed |= ApplyToWasmCode(wasm_function, icache_flush_mode);
99 }
100
101 // Patch all exported functions.
102 for (auto exp : module->export_table) {
103 if (exp.kind != kExternalFunction) continue;
104 Code* export_wrapper = Code::cast(code_table->get(func_index));
105 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind());
106 // There must be exactly one call to WASM_FUNCTION or WASM_TO_JS_FUNCTION.
107 int num_wasm_calls = 0;
108 for (RelocIterator it(export_wrapper,
109 RelocInfo::ModeMask(RelocInfo::CODE_TARGET));
110 !it.done(); it.next()) {
111 DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode()));
112 Code* code = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
113 // Ignore calls to other builtins like ToNumber.
114 if (code->kind() != Code::WASM_FUNCTION &&
115 code->kind() != Code::WASM_TO_JS_FUNCTION &&
116 code->builtin_index() != Builtins::kIllegal)
117 continue;
118 ++num_wasm_calls;
119 Code* new_code = Code::cast(code_table->get(exp.index));
120 DCHECK(new_code->kind() == Code::WASM_FUNCTION ||
121 new_code->kind() == Code::WASM_TO_JS_FUNCTION);
122 it.rinfo()->set_target_address(new_code->instruction_start(),
123 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
124 changed = true;
125 }
126 DCHECK_EQ(1, num_wasm_calls);
127 func_index++;
128 }
129 DCHECK_EQ(code_table->length(), func_index);
130 return changed;
131 }
132
133 bool CodeSpecialization::ApplyToWasmCode(Code* code,
134 ICacheFlushMode icache_flush_mode) {
135 DCHECK_EQ(Code::WASM_FUNCTION, code->kind());
136
137 bool reloc_mem = old_mem_start || new_mem_start;
138 bool reloc_globals = old_globals_start || new_globals_start;
139 bool patch_table_size = old_function_table_size || new_function_table_size;
140 bool reloc_direct_calls = relocate_direct_calls_instance != nullptr;
141 bool reloc_objects = !objects_to_relocate.empty();
142
143 int reloc_mode = 0;
144 auto add_mode = [&reloc_mode](bool cond, RelocInfo::Mode mode) {
145 if (cond) reloc_mode |= RelocInfo::ModeMask(mode);
146 };
147 add_mode(reloc_mem, RelocInfo::WASM_MEMORY_REFERENCE);
148 add_mode(reloc_mem, RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
149 add_mode(reloc_globals, RelocInfo::WASM_GLOBAL_REFERENCE);
150 add_mode(patch_table_size, RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE);
151 add_mode(reloc_direct_calls, RelocInfo::CODE_TARGET);
152 add_mode(reloc_objects, RelocInfo::EMBEDDED_OBJECT);
153
154 // This is a poor man's replacement for c++17's std::optional. It's lazily
155 // initialized when needed.
156 union OptionalDirectCallSitePatchingUtils {
157 char __;
158 struct {
159 char initialized;
160 SourcePositionTableIterator source_pos_it;
161 Decoder decoder;
162 const byte* func_bytes;
163 } data;
164 OptionalDirectCallSitePatchingUtils() : __(0) { data.initialized = false; }
165 ~OptionalDirectCallSitePatchingUtils() {
166 if (!data.initialized) return;
167 data.source_pos_it.~SourcePositionTableIterator();
168 data.decoder.~Decoder();
169 }
170 void Init(WasmInstanceObject* instance, Code* code) {
171 DCHECK(!data.initialized);
172 data.initialized = true;
173 new (&data.source_pos_it)
174 SourcePositionTableIterator(code->source_position_table());
175 new (&data.decoder) Decoder(nullptr, nullptr);
176 FixedArray* deopt_data = code->deoptimization_data();
177 DCHECK_EQ(2, deopt_data->length());
178 WasmCompiledModule* comp_mod = instance->compiled_module();
179 int func_index = Smi::cast(deopt_data->get(1))->value();
180 data.func_bytes =
181 comp_mod->module_bytes()->GetChars() +
182 comp_mod->module()->functions[func_index].code_start_offset;
183 }
184 } opt;
185
186 bool changed = false;
187
188 for (RelocIterator it(code, reloc_mode); !it.done(); it.next()) {
189 RelocInfo::Mode mode = it.rinfo()->rmode();
190 switch (mode) {
191 case RelocInfo::WASM_MEMORY_REFERENCE:
192 case RelocInfo::WASM_MEMORY_SIZE_REFERENCE:
193 DCHECK(reloc_mem);
194 it.rinfo()->update_wasm_memory_reference(old_mem_start, new_mem_start,
195 old_mem_size, new_mem_size,
196 icache_flush_mode);
197 changed = true;
198 break;
199 case RelocInfo::WASM_GLOBAL_REFERENCE:
200 DCHECK(reloc_globals);
201 it.rinfo()->update_wasm_global_reference(
202 old_globals_start, new_globals_start, icache_flush_mode);
203 changed = true;
204 break;
205 case RelocInfo::CODE_TARGET: {
206 DCHECK(reloc_direct_calls);
207 Code* old_code =
208 Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
209 // Skip everything which is not a wasm call (stack checks, traps, ...).
210 if (old_code->kind() != Code::WASM_FUNCTION &&
211 old_code->kind() != Code::WASM_TO_JS_FUNCTION &&
212 old_code->builtin_index() != Builtins::kIllegal)
213 continue;
214 // Iterate simultaneously over the relocation information and the source
215 // position table. For each call in the reloc info, move the source
216 // position iterator forward to that position to find the byte offset of
217 // the respective call. Then extract the call index from the module wire
218 // bytes to find the new compiled function.
219 size_t offset = it.rinfo()->pc() - code->instruction_start();
220 if (!opt.data.initialized)
221 opt.Init(relocate_direct_calls_instance, code);
222 int byte_pos =
223 AdvanceSourcePositionTableIterator(opt.data.source_pos_it, offset);
224 int called_func_index = ExtractDirectCallIndex(
225 opt.data.decoder, opt.data.func_bytes + byte_pos);
226 FixedArray* code_table =
227 relocate_direct_calls_instance->compiled_module()
228 ->ptr_to_code_table();
229 Code* new_code = Code::cast(code_table->get(called_func_index));
230 it.rinfo()->set_target_address(new_code->instruction_start(),
231 UPDATE_WRITE_BARRIER, icache_flush_mode);
232 changed = true;
233 } break;
234 case RelocInfo::EMBEDDED_OBJECT: {
235 DCHECK(reloc_objects);
236 Object* old = it.rinfo()->target_object();
237 auto rel = objects_to_relocate.find(old);
238 if (rel != objects_to_relocate.end()) {
239 it.rinfo()->set_target_object(rel->second, UPDATE_WRITE_BARRIER,
240 icache_flush_mode);
241 changed = true;
242 }
243 } break;
244 case RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE:
245 DCHECK(patch_table_size);
246 it.rinfo()->update_wasm_function_table_size_reference(
247 old_function_table_size, new_function_table_size,
248 icache_flush_mode);
249 changed = true;
250 break;
251 default:
252 UNREACHABLE();
253 }
254 }
255
256 return changed;
257 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698