Line data Source code
1 : // Copyright 2018 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/compiler/serializer-for-background-compilation.h"
6 :
7 : #include "src/compiler/js-heap-broker.h"
8 : #include "src/handles-inl.h"
9 : #include "src/interpreter/bytecode-array-iterator.h"
10 : #include "src/objects/code.h"
11 : #include "src/objects/shared-function-info-inl.h"
12 : #include "src/zone/zone.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 : namespace compiler {
17 :
18 : class SerializerForBackgroundCompilation::Environment : public ZoneObject {
19 : public:
20 : explicit Environment(Zone* zone, Isolate* isolate, int register_count,
21 : int parameter_count);
22 :
23 : Environment(SerializerForBackgroundCompilation* serializer, Isolate* isolate,
24 : int register_count, int parameter_count, Hints receiver,
25 : const HintsVector& arguments);
26 :
27 : int parameter_count() const { return parameter_count_; }
28 : int register_count() const { return register_count_; }
29 :
30 : // Remove all hints except those for the return value.
31 : void Clear();
32 :
33 : // Getters for the hints gathered until now (constants or maps).
34 : const Hints& LookupAccumulator();
35 : const Hints& LookupReturnValue();
36 : const Hints& LookupRegister(interpreter::Register the_register);
37 :
38 : // Setters for hints.
39 : void AddAccumulatorHints(const Hints& hints);
40 : void ReplaceAccumulatorHint(Handle<Object> hint);
41 : void SetAccumulatorHints(const Hints& hints);
42 : void ClearAccumulatorHints();
43 : void AddReturnValueHints(const Hints& hints);
44 : void SetRegisterHints(interpreter::Register the_register, const Hints& hints);
45 :
46 : private:
47 : explicit Environment(Zone* zone)
48 : : environment_hints_(zone),
49 : return_value_hints_(zone),
50 : register_count_(0),
51 : parameter_count_(0),
52 : empty_hints_(Hints(zone)) {}
53 : Zone* zone() const { return zone_; }
54 :
55 : int RegisterToLocalIndex(interpreter::Register the_register) const;
56 :
57 : Zone* zone_;
58 :
59 : // environment_hints_ contains best-effort guess for state of the registers,
60 : // the accumulator and the parameters. The structure is inspired by
61 : // BytecodeGraphBuilder::Environment and looks like:
62 : // hints: receiver | parameters | registers | accumulator
63 : // indices: 0 register_base() accumulator_base()
64 :
65 : HintsVector environment_hints_;
66 : Hints return_value_hints_;
67 : const int register_count_;
68 : const int parameter_count_;
69 0 : int register_base() const { return parameter_count_ + 1; }
70 0 : int accumulator_base() const { return register_base() + register_count_; }
71 : static const int kReceiverIndex = 0;
72 : static const int kParameterBase = 1;
73 : const Hints empty_hints_;
74 : };
75 :
76 0 : SerializerForBackgroundCompilation::Environment::Environment(
77 : Zone* zone, Isolate* isolate, int register_count, int parameter_count)
78 : : zone_(zone),
79 0 : environment_hints_(register_count + parameter_count + 2, Hints(zone),
80 : zone),
81 : return_value_hints_(zone),
82 : register_count_(register_count),
83 : parameter_count_(parameter_count),
84 0 : empty_hints_(Hints(zone)) {}
85 :
86 0 : SerializerForBackgroundCompilation::Environment::Environment(
87 0 : SerializerForBackgroundCompilation* serializer, Isolate* isolate,
88 : int register_count, int parameter_count, Hints receiver,
89 : const HintsVector& arguments)
90 : : Environment(serializer->zone(), isolate, register_count,
91 0 : parameter_count) {
92 0 : environment_hints_[kReceiverIndex] = receiver;
93 :
94 0 : size_t param_count = static_cast<size_t>(parameter_count);
95 :
96 : // Copy the hints for the actually passed arguments, at most up to
97 : // the parameter_count.
98 0 : for (size_t i = 0; i < std::min(arguments.size(), param_count); ++i) {
99 0 : environment_hints_[kParameterBase + i] = arguments[i];
100 : }
101 :
102 : Hints undefined_hint(serializer->zone());
103 : undefined_hint.push_back(
104 0 : serializer->broker()->isolate()->factory()->undefined_value());
105 : // Pad the rest with "undefined".
106 0 : for (size_t i = arguments.size(); i < param_count; ++i) {
107 0 : environment_hints_[kParameterBase + i] = undefined_hint;
108 : }
109 0 : }
110 :
111 0 : int SerializerForBackgroundCompilation::Environment::RegisterToLocalIndex(
112 0 : interpreter::Register the_register) const {
113 0 : if (the_register.is_parameter()) {
114 0 : return kParameterBase + the_register.ToParameterIndex(parameter_count());
115 : } else {
116 0 : return register_base() + the_register.index();
117 : }
118 : }
119 :
120 0 : void SerializerForBackgroundCompilation::Environment::Clear() {
121 0 : environment_hints_ =
122 : HintsVector(environment_hints_.size(), empty_hints_, zone());
123 0 : }
124 :
125 : const Hints&
126 0 : SerializerForBackgroundCompilation::Environment::LookupAccumulator() {
127 0 : return environment_hints_[accumulator_base()];
128 : }
129 :
130 : const Hints&
131 0 : SerializerForBackgroundCompilation::Environment::LookupReturnValue() {
132 0 : return return_value_hints_;
133 : }
134 :
135 0 : const Hints& SerializerForBackgroundCompilation::Environment::LookupRegister(
136 : interpreter::Register the_register) {
137 : // TODO(mslekova): We also want to gather hints for the context and
138 : // we already have data about the closure, so eventually more useful
139 : // info should be returned here instead of empty hints.
140 0 : if (the_register.is_current_context() || the_register.is_function_closure()) {
141 0 : return empty_hints_;
142 : }
143 0 : int local_index = RegisterToLocalIndex(the_register);
144 : DCHECK(static_cast<size_t>(local_index) < environment_hints_.size());
145 0 : return environment_hints_[local_index];
146 : }
147 :
148 0 : void SerializerForBackgroundCompilation::Environment::AddAccumulatorHints(
149 : const Hints& hints) {
150 0 : for (auto v : hints) {
151 0 : environment_hints_[accumulator_base()].push_back(v);
152 : }
153 0 : }
154 :
155 0 : void SerializerForBackgroundCompilation::Environment::ReplaceAccumulatorHint(
156 : Handle<Object> hint) {
157 : ClearAccumulatorHints();
158 0 : environment_hints_[accumulator_base()].push_back(hint);
159 0 : }
160 :
161 0 : void SerializerForBackgroundCompilation::Environment::ClearAccumulatorHints() {
162 0 : SetAccumulatorHints(empty_hints_);
163 0 : }
164 :
165 0 : void SerializerForBackgroundCompilation::Environment::SetAccumulatorHints(
166 : const Hints& hints) {
167 0 : environment_hints_[accumulator_base()] = hints;
168 0 : }
169 :
170 0 : void SerializerForBackgroundCompilation::Environment::AddReturnValueHints(
171 : const Hints& hints) {
172 0 : for (auto v : hints) {
173 0 : return_value_hints_.push_back(v);
174 : }
175 0 : }
176 :
177 0 : void SerializerForBackgroundCompilation::Environment::SetRegisterHints(
178 : interpreter::Register the_register, const Hints& hints) {
179 0 : int local_index = RegisterToLocalIndex(the_register);
180 : DCHECK(static_cast<size_t>(local_index) < environment_hints_.size());
181 0 : environment_hints_[local_index] = hints;
182 0 : }
183 :
184 0 : SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
185 : JSHeapBroker* broker, Zone* zone, Handle<JSFunction> closure)
186 : : broker_(broker),
187 : zone_(zone),
188 : environment_(new (zone) Environment(
189 0 : zone, broker_->isolate(),
190 0 : closure->shared()->GetBytecodeArray()->register_count(),
191 0 : closure->shared()->GetBytecodeArray()->parameter_count())),
192 0 : closure_(closure) {}
193 :
194 0 : SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
195 0 : JSHeapBroker* broker, Zone* zone, Handle<JSFunction> closure,
196 : const Hints& receiver, const HintsVector& arguments)
197 : : broker_(broker),
198 : zone_(zone),
199 : environment_(new (zone) Environment(
200 : this, broker->isolate(),
201 0 : closure->shared()->GetBytecodeArray()->register_count(),
202 0 : closure->shared()->GetBytecodeArray()->parameter_count(), receiver,
203 0 : arguments)),
204 0 : closure_(closure) {}
205 :
206 0 : Hints SerializerForBackgroundCompilation::Run() {
207 : JSFunctionRef closure_ref(broker(), closure_);
208 0 : if (closure_ref.serialized_for_compilation()) {
209 : return Hints(zone());
210 : }
211 0 : closure_ref.SetSerializedForCompilation();
212 :
213 : FeedbackVectorRef fv(
214 0 : broker(), handle(closure_->feedback_vector(), broker()->isolate()));
215 0 : fv.SerializeSlots();
216 :
217 : BytecodeArrayRef bytecode_array(
218 : broker(),
219 0 : handle(closure_->shared()->GetBytecodeArray(), broker()->isolate()));
220 :
221 0 : closure_ref.Serialize();
222 :
223 0 : TraverseBytecode();
224 :
225 : return environment()->LookupReturnValue();
226 : }
227 :
228 0 : void SerializerForBackgroundCompilation::TraverseBytecode() {
229 : interpreter::BytecodeArrayIterator iterator(
230 0 : handle(closure_->shared()->GetBytecodeArray(), broker()->isolate()));
231 :
232 0 : for (; !iterator.done(); iterator.Advance()) {
233 0 : switch (iterator.current_bytecode()) {
234 : #define DEFINE_BYTECODE_CASE(name) \
235 : case interpreter::Bytecode::k##name: \
236 : Visit##name(&iterator); \
237 : break;
238 0 : SUPPORTED_BYTECODE_LIST(DEFINE_BYTECODE_CASE)
239 : #undef DEFINE_BYTECODE_CASE
240 : default: {
241 0 : environment()->Clear();
242 0 : break;
243 : }
244 : }
245 : }
246 0 : }
247 :
248 0 : void SerializerForBackgroundCompilation::VisitIllegal(
249 : interpreter::BytecodeArrayIterator* iterator) {
250 0 : UNREACHABLE();
251 : }
252 :
253 0 : void SerializerForBackgroundCompilation::VisitWide(
254 : interpreter::BytecodeArrayIterator* iterator) {
255 0 : UNREACHABLE();
256 : }
257 :
258 0 : void SerializerForBackgroundCompilation::VisitExtraWide(
259 : interpreter::BytecodeArrayIterator* iterator) {
260 0 : UNREACHABLE();
261 : }
262 :
263 0 : void SerializerForBackgroundCompilation::VisitLdaUndefined(
264 0 : interpreter::BytecodeArrayIterator* iterator) {
265 : environment()->ReplaceAccumulatorHint(
266 0 : broker()->isolate()->factory()->undefined_value());
267 0 : }
268 :
269 0 : void SerializerForBackgroundCompilation::VisitLdaNull(
270 0 : interpreter::BytecodeArrayIterator* iterator) {
271 : environment()->ReplaceAccumulatorHint(
272 0 : broker()->isolate()->factory()->null_value());
273 0 : }
274 :
275 0 : void SerializerForBackgroundCompilation::VisitLdaZero(
276 0 : interpreter::BytecodeArrayIterator* iterator) {
277 0 : Handle<Object> zero(Smi::FromInt(0), broker()->isolate());
278 0 : environment()->ReplaceAccumulatorHint(zero);
279 0 : }
280 :
281 0 : void SerializerForBackgroundCompilation::VisitLdaSmi(
282 0 : interpreter::BytecodeArrayIterator* iterator) {
283 0 : Handle<Object> smi(Smi::FromInt(iterator->GetImmediateOperand(0)),
284 0 : broker()->isolate());
285 0 : environment()->ReplaceAccumulatorHint(smi);
286 0 : }
287 :
288 0 : void SerializerForBackgroundCompilation::VisitLdaConstant(
289 0 : interpreter::BytecodeArrayIterator* iterator) {
290 : Handle<Object> constant(iterator->GetConstantForIndexOperand(0),
291 0 : broker()->isolate());
292 0 : environment()->ReplaceAccumulatorHint(constant);
293 0 : }
294 :
295 0 : void SerializerForBackgroundCompilation::VisitLdar(
296 0 : interpreter::BytecodeArrayIterator* iterator) {
297 : const Hints& hints =
298 0 : environment()->LookupRegister(iterator->GetRegisterOperand(0));
299 0 : environment()->SetAccumulatorHints(hints);
300 0 : }
301 :
302 0 : void SerializerForBackgroundCompilation::VisitStar(
303 0 : interpreter::BytecodeArrayIterator* iterator) {
304 : const Hints& hints = environment()->LookupAccumulator();
305 0 : environment()->SetRegisterHints(iterator->GetRegisterOperand(0), hints);
306 0 : }
307 :
308 0 : void SerializerForBackgroundCompilation::VisitMov(
309 0 : interpreter::BytecodeArrayIterator* iterator) {
310 : const Hints& hints =
311 0 : environment()->LookupRegister(iterator->GetRegisterOperand(0));
312 0 : environment()->SetRegisterHints(iterator->GetRegisterOperand(1), hints);
313 0 : }
314 :
315 0 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver(
316 : interpreter::BytecodeArrayIterator* iterator) {
317 0 : ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
318 0 : }
319 :
320 0 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver0(
321 0 : interpreter::BytecodeArrayIterator* iterator) {
322 : Hints receiver(zone());
323 0 : receiver.push_back(broker()->isolate()->factory()->undefined_value());
324 :
325 : const Hints& callee =
326 0 : environment()->LookupRegister(iterator->GetRegisterOperand(0));
327 :
328 : HintsVector parameters(zone());
329 :
330 0 : ProcessCall(callee, receiver, parameters);
331 0 : }
332 :
333 0 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver1(
334 0 : interpreter::BytecodeArrayIterator* iterator) {
335 : Hints receiver(zone());
336 0 : receiver.push_back(broker()->isolate()->factory()->undefined_value());
337 :
338 : const Hints& callee =
339 0 : environment()->LookupRegister(iterator->GetRegisterOperand(0));
340 :
341 : const Hints& arg0 =
342 0 : environment()->LookupRegister(iterator->GetRegisterOperand(1));
343 :
344 : HintsVector parameters(zone());
345 0 : parameters.push_back(arg0);
346 :
347 0 : ProcessCall(callee, receiver, parameters);
348 0 : }
349 :
350 0 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver2(
351 0 : interpreter::BytecodeArrayIterator* iterator) {
352 : Hints receiver(zone());
353 0 : receiver.push_back(broker()->isolate()->factory()->undefined_value());
354 :
355 : const Hints& callee =
356 0 : environment()->LookupRegister(iterator->GetRegisterOperand(0));
357 :
358 : const Hints& arg0 =
359 0 : environment()->LookupRegister(iterator->GetRegisterOperand(1));
360 : const Hints& arg1 =
361 0 : environment()->LookupRegister(iterator->GetRegisterOperand(2));
362 :
363 : HintsVector parameters(zone());
364 0 : parameters.push_back(arg0);
365 0 : parameters.push_back(arg1);
366 :
367 0 : ProcessCall(callee, receiver, parameters);
368 0 : }
369 :
370 0 : void SerializerForBackgroundCompilation::VisitCallAnyReceiver(
371 : interpreter::BytecodeArrayIterator* iterator) {
372 0 : ProcessCallVarArgs(iterator, ConvertReceiverMode::kAny);
373 0 : }
374 :
375 0 : void SerializerForBackgroundCompilation::VisitCallNoFeedback(
376 : interpreter::BytecodeArrayIterator* iterator) {
377 0 : ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
378 0 : }
379 :
380 0 : void SerializerForBackgroundCompilation::VisitCallProperty(
381 : interpreter::BytecodeArrayIterator* iterator) {
382 0 : ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
383 0 : }
384 :
385 0 : void SerializerForBackgroundCompilation::VisitCallProperty0(
386 0 : interpreter::BytecodeArrayIterator* iterator) {
387 : const Hints& callee =
388 0 : environment()->LookupRegister(iterator->GetRegisterOperand(0));
389 : const Hints& receiver =
390 0 : environment()->LookupRegister(iterator->GetRegisterOperand(1));
391 :
392 : HintsVector parameters(zone());
393 :
394 0 : ProcessCall(callee, receiver, parameters);
395 0 : }
396 :
397 0 : void SerializerForBackgroundCompilation::VisitCallProperty1(
398 0 : interpreter::BytecodeArrayIterator* iterator) {
399 : const Hints& callee =
400 0 : environment()->LookupRegister(iterator->GetRegisterOperand(0));
401 : const Hints& receiver =
402 0 : environment()->LookupRegister(iterator->GetRegisterOperand(1));
403 : const Hints& arg0 =
404 0 : environment()->LookupRegister(iterator->GetRegisterOperand(2));
405 :
406 : HintsVector parameters(zone());
407 0 : parameters.push_back(arg0);
408 :
409 0 : ProcessCall(callee, receiver, parameters);
410 0 : }
411 :
412 0 : void SerializerForBackgroundCompilation::VisitCallProperty2(
413 0 : interpreter::BytecodeArrayIterator* iterator) {
414 : const Hints& callee =
415 0 : environment()->LookupRegister(iterator->GetRegisterOperand(0));
416 : const Hints& receiver =
417 0 : environment()->LookupRegister(iterator->GetRegisterOperand(1));
418 : const Hints& arg0 =
419 0 : environment()->LookupRegister(iterator->GetRegisterOperand(2));
420 : const Hints& arg1 =
421 0 : environment()->LookupRegister(iterator->GetRegisterOperand(3));
422 :
423 : HintsVector parameters(zone());
424 0 : parameters.push_back(arg0);
425 0 : parameters.push_back(arg1);
426 :
427 0 : ProcessCall(callee, receiver, parameters);
428 0 : }
429 :
430 0 : void SerializerForBackgroundCompilation::ProcessCall(
431 0 : const Hints& callee, const Hints& receiver, const HintsVector& arguments) {
432 : environment()->ClearAccumulatorHints();
433 :
434 0 : for (auto value : callee) {
435 0 : if (!value->IsJSFunction()) continue;
436 :
437 0 : Handle<JSFunction> callee(Handle<JSFunction>::cast(value));
438 0 : if (!callee->shared()->HasBytecodeArray() ||
439 0 : !callee->shared()->IsInlineable())
440 : continue;
441 :
442 : SerializerForBackgroundCompilation child_serializer(
443 0 : broker(), zone(), callee, receiver, arguments);
444 :
445 0 : environment()->AddAccumulatorHints(child_serializer.Run());
446 : }
447 0 : }
448 :
449 0 : void SerializerForBackgroundCompilation::ProcessCallVarArgs(
450 : interpreter::BytecodeArrayIterator* iterator,
451 0 : ConvertReceiverMode receiver_mode) {
452 : const Hints& callee =
453 0 : environment()->LookupRegister(iterator->GetRegisterOperand(0));
454 :
455 0 : interpreter::Register first_reg = iterator->GetRegisterOperand(1);
456 0 : size_t reg_count = iterator->GetRegisterCountOperand(2);
457 :
458 : Hints receiver(zone());
459 : interpreter::Register first_arg;
460 :
461 : int arg_count;
462 0 : if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
463 : // The receiver is implicit (and undefined), the arguments are in
464 : // consecutive registers.
465 0 : arg_count = static_cast<int>(reg_count);
466 0 : receiver.push_back(broker()->isolate()->factory()->undefined_value());
467 0 : first_arg = first_reg;
468 : } else {
469 : // The receiver is the first register, followed by the arguments in the
470 : // consecutive registers.
471 0 : arg_count = static_cast<int>(reg_count) - 1;
472 0 : receiver = environment()->LookupRegister(first_reg);
473 0 : first_arg = interpreter::Register(first_reg.index() + 1);
474 : }
475 :
476 : HintsVector arguments(zone());
477 :
478 : // The function arguments are in consecutive registers.
479 : int arg_base = first_arg.index();
480 0 : for (int i = 0; i < arg_count; ++i) {
481 : arguments.push_back(
482 0 : environment()->LookupRegister(interpreter::Register(arg_base + i)));
483 : }
484 :
485 0 : ProcessCall(callee, receiver, arguments);
486 0 : }
487 :
488 0 : void SerializerForBackgroundCompilation::VisitReturn(
489 0 : interpreter::BytecodeArrayIterator* iterator) {
490 0 : environment()->AddReturnValueHints(environment()->LookupAccumulator());
491 0 : environment()->Clear();
492 0 : }
493 :
494 : #define DEFINE_SKIPPED_JUMP(name, ...) \
495 : void SerializerForBackgroundCompilation::Visit##name( \
496 : interpreter::BytecodeArrayIterator* iterator) { \
497 : environment()->Clear(); \
498 : }
499 0 : CLEAR_ENVIRONMENT_LIST(DEFINE_SKIPPED_JUMP)
500 : #undef DEFINE_SKIPPED_JUMP
501 :
502 : #define DEFINE_CLEAR_ACCUMULATOR(name, ...) \
503 : void SerializerForBackgroundCompilation::Visit##name( \
504 : interpreter::BytecodeArrayIterator* iterator) { \
505 : environment()->ClearAccumulatorHints(); \
506 : }
507 0 : CLEAR_ACCUMULATOR_LIST(DEFINE_CLEAR_ACCUMULATOR)
508 : #undef DEFINE_CLEAR_ACCUMULATOR
509 :
510 : } // namespace compiler
511 : } // namespace internal
512 183867 : } // namespace v8
|