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

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

Issue 2696143006: [wasm] Refactor code specialization / patching (Closed)
Patch Set: Use IdentityMap 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
« no previous file with comments | « src/wasm/wasm-code-specialization.h ('k') | src/wasm/wasm-module.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 CodeSpecialization::CodeSpecialization(Isolate* isolate, Zone* zone)
44 : objects_to_relocate(isolate->heap(), zone) {}
45
46 CodeSpecialization::~CodeSpecialization() {}
47
48 void CodeSpecialization::RelocateMemoryReferences(Address old_start,
49 uint32_t old_size,
50 Address new_start,
51 uint32_t new_size) {
52 DCHECK(old_mem_start == 0 && new_mem_start == 0);
53 DCHECK(old_start != 0 || new_start != 0);
54 old_mem_start = old_start;
55 old_mem_size = old_size;
56 new_mem_start = new_start;
57 new_mem_size = new_size;
58 }
59
60 void CodeSpecialization::RelocateGlobals(Address old_start, Address new_start) {
61 DCHECK(old_globals_start == 0 && new_globals_start == 0);
62 DCHECK(old_start != 0 || new_start != 0);
63 old_globals_start = old_start;
64 new_globals_start = new_start;
65 }
66
67 void CodeSpecialization::PatchTableSize(uint32_t old_size, uint32_t new_size) {
68 DCHECK(old_function_table_size == 0 && new_function_table_size == 0);
69 DCHECK(old_size != 0 || new_size != 0);
70 old_function_table_size = old_size;
71 new_function_table_size = new_size;
72 }
73
74 void CodeSpecialization::RelocateDirectCalls(
75 Handle<WasmInstanceObject> instance) {
76 DCHECK(relocate_direct_calls_instance.is_null());
77 DCHECK(!instance.is_null());
78 relocate_direct_calls_instance = instance;
79 }
80
81 void CodeSpecialization::RelocateObject(Handle<Object> old_obj,
82 Handle<Object> new_obj) {
83 DCHECK(!old_obj.is_null() && !new_obj.is_null());
84 has_objects_to_relocate = true;
85 objects_to_relocate.Set(*old_obj, new_obj);
86 }
87
88 bool CodeSpecialization::ApplyToWholeInstance(
89 WasmInstanceObject* instance, ICacheFlushMode icache_flush_mode) {
90 DisallowHeapAllocation no_gc;
91 WasmCompiledModule* compiled_module = instance->compiled_module();
92 FixedArray* code_table = compiled_module->ptr_to_code_table();
93 WasmModule* module = compiled_module->module();
94 std::vector<WasmFunction>* wasm_functions =
95 &compiled_module->module()->functions;
96 DCHECK_EQ(wasm_functions->size() +
97 compiled_module->module()->num_exported_functions,
98 code_table->length());
99
100 bool changed = false;
101 int func_index = module->num_imported_functions;
102
103 // Patch all wasm functions.
104 for (int num_wasm_functions = static_cast<int>(wasm_functions->size());
105 func_index < num_wasm_functions; ++func_index) {
106 Code* wasm_function = Code::cast(code_table->get(func_index));
107 changed |= ApplyToWasmCode(wasm_function, icache_flush_mode);
108 }
109
110 // Patch all exported functions.
111 for (auto exp : module->export_table) {
112 if (exp.kind != kExternalFunction) continue;
113 Code* export_wrapper = Code::cast(code_table->get(func_index));
114 DCHECK_EQ(Code::JS_TO_WASM_FUNCTION, export_wrapper->kind());
115 // There must be exactly one call to WASM_FUNCTION or WASM_TO_JS_FUNCTION.
116 int num_wasm_calls = 0;
117 for (RelocIterator it(export_wrapper,
118 RelocInfo::ModeMask(RelocInfo::CODE_TARGET));
119 !it.done(); it.next()) {
120 DCHECK(RelocInfo::IsCodeTarget(it.rinfo()->rmode()));
121 Code* code = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
122 // Ignore calls to other builtins like ToNumber.
123 if (code->kind() != Code::WASM_FUNCTION &&
124 code->kind() != Code::WASM_TO_JS_FUNCTION &&
125 code->builtin_index() != Builtins::kIllegal)
126 continue;
127 ++num_wasm_calls;
128 Code* new_code = Code::cast(code_table->get(exp.index));
129 DCHECK(new_code->kind() == Code::WASM_FUNCTION ||
130 new_code->kind() == Code::WASM_TO_JS_FUNCTION);
131 it.rinfo()->set_target_address(new_code->instruction_start(),
132 UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
133 changed = true;
134 }
135 DCHECK_EQ(1, num_wasm_calls);
136 func_index++;
137 }
138 DCHECK_EQ(code_table->length(), func_index);
139 return changed;
140 }
141
142 bool CodeSpecialization::ApplyToWasmCode(Code* code,
143 ICacheFlushMode icache_flush_mode) {
144 DisallowHeapAllocation no_gc;
145 DCHECK_EQ(Code::WASM_FUNCTION, code->kind());
146
147 bool reloc_mem = old_mem_start || new_mem_start;
148 bool reloc_globals = old_globals_start || new_globals_start;
149 bool patch_table_size = old_function_table_size || new_function_table_size;
150 bool reloc_direct_calls = !relocate_direct_calls_instance.is_null();
151 bool reloc_objects = has_objects_to_relocate;
152
153 int reloc_mode = 0;
154 auto add_mode = [&reloc_mode](bool cond, RelocInfo::Mode mode) {
155 if (cond) reloc_mode |= RelocInfo::ModeMask(mode);
156 };
157 add_mode(reloc_mem, RelocInfo::WASM_MEMORY_REFERENCE);
158 add_mode(reloc_mem, RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
159 add_mode(reloc_globals, RelocInfo::WASM_GLOBAL_REFERENCE);
160 add_mode(patch_table_size, RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE);
161 add_mode(reloc_direct_calls, RelocInfo::CODE_TARGET);
162 add_mode(reloc_objects, RelocInfo::EMBEDDED_OBJECT);
163
164 // This is a poor man's replacement for c++17's std::optional. It's lazily
165 // initialized when needed.
166 union OptionalDirectCallSitePatchingUtils {
167 char __;
168 struct {
169 char initialized;
170 SourcePositionTableIterator source_pos_it;
titzer 2017/02/20 15:12:01 Can we heap allocate these instead of using this u
Clemens Hammacher 2017/02/20 15:32:57 Sure :) Done.
171 Decoder decoder;
172 const byte* func_bytes;
173 } data;
174 OptionalDirectCallSitePatchingUtils() : __(0) { data.initialized = false; }
175 ~OptionalDirectCallSitePatchingUtils() {
176 if (!data.initialized) return;
177 data.source_pos_it.~SourcePositionTableIterator();
178 data.decoder.~Decoder();
179 }
180 void Init(WasmInstanceObject* instance, Code* code) {
181 DCHECK(!data.initialized);
182 data.initialized = true;
183 new (&data.source_pos_it)
184 SourcePositionTableIterator(code->source_position_table());
185 new (&data.decoder) Decoder(nullptr, nullptr);
186 FixedArray* deopt_data = code->deoptimization_data();
187 DCHECK_EQ(2, deopt_data->length());
188 WasmCompiledModule* comp_mod = instance->compiled_module();
189 int func_index = Smi::cast(deopt_data->get(1))->value();
190 data.func_bytes =
191 comp_mod->module_bytes()->GetChars() +
192 comp_mod->module()->functions[func_index].code_start_offset;
193 }
194 } opt;
195
196 bool changed = false;
197
198 for (RelocIterator it(code, reloc_mode); !it.done(); it.next()) {
199 RelocInfo::Mode mode = it.rinfo()->rmode();
200 switch (mode) {
201 case RelocInfo::WASM_MEMORY_REFERENCE:
202 case RelocInfo::WASM_MEMORY_SIZE_REFERENCE:
203 DCHECK(reloc_mem);
204 it.rinfo()->update_wasm_memory_reference(old_mem_start, new_mem_start,
205 old_mem_size, new_mem_size,
206 icache_flush_mode);
207 changed = true;
208 break;
209 case RelocInfo::WASM_GLOBAL_REFERENCE:
210 DCHECK(reloc_globals);
211 it.rinfo()->update_wasm_global_reference(
212 old_globals_start, new_globals_start, icache_flush_mode);
213 changed = true;
214 break;
215 case RelocInfo::CODE_TARGET: {
216 DCHECK(reloc_direct_calls);
217 Code* old_code =
218 Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
219 // Skip everything which is not a wasm call (stack checks, traps, ...).
220 if (old_code->kind() != Code::WASM_FUNCTION &&
221 old_code->kind() != Code::WASM_TO_JS_FUNCTION &&
222 old_code->builtin_index() != Builtins::kIllegal)
223 continue;
224 // Iterate simultaneously over the relocation information and the source
225 // position table. For each call in the reloc info, move the source
226 // position iterator forward to that position to find the byte offset of
227 // the respective call. Then extract the call index from the module wire
228 // bytes to find the new compiled function.
229 size_t offset = it.rinfo()->pc() - code->instruction_start();
230 if (!opt.data.initialized)
231 opt.Init(*relocate_direct_calls_instance, code);
232 int byte_pos =
233 AdvanceSourcePositionTableIterator(opt.data.source_pos_it, offset);
234 int called_func_index = ExtractDirectCallIndex(
235 opt.data.decoder, opt.data.func_bytes + byte_pos);
236 FixedArray* code_table =
237 relocate_direct_calls_instance->compiled_module()
238 ->ptr_to_code_table();
239 Code* new_code = Code::cast(code_table->get(called_func_index));
240 it.rinfo()->set_target_address(new_code->instruction_start(),
241 UPDATE_WRITE_BARRIER, icache_flush_mode);
242 changed = true;
243 } break;
244 case RelocInfo::EMBEDDED_OBJECT: {
245 DCHECK(reloc_objects);
246 Object* old = it.rinfo()->target_object();
247 Handle<Object>* new_obj = objects_to_relocate.Find(old);
248 if (new_obj) {
249 it.rinfo()->set_target_object(**new_obj, UPDATE_WRITE_BARRIER,
250 icache_flush_mode);
251 changed = true;
252 }
253 } break;
254 case RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE:
255 DCHECK(patch_table_size);
256 it.rinfo()->update_wasm_function_table_size_reference(
257 old_function_table_size, new_function_table_size,
258 icache_flush_mode);
259 changed = true;
260 break;
261 default:
262 UNREACHABLE();
263 }
264 }
265
266 return changed;
267 }
OLDNEW
« no previous file with comments | « src/wasm/wasm-code-specialization.h ('k') | src/wasm/wasm-module.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698