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 <sstream>
8 :
9 : #include "src/compiler/js-heap-broker.h"
10 : #include "src/handles-inl.h"
11 : #include "src/interpreter/bytecode-array-iterator.h"
12 : #include "src/objects/code.h"
13 : #include "src/objects/shared-function-info-inl.h"
14 : #include "src/vector-slot-pair.h"
15 : #include "src/zone/zone.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 : namespace compiler {
20 :
21 : using BytecodeArrayIterator = interpreter::BytecodeArrayIterator;
22 :
23 113 : CompilationSubject::CompilationSubject(Handle<JSFunction> closure,
24 : Isolate* isolate)
25 226 : : blueprint_{handle(closure->shared(), isolate),
26 226 : handle(closure->feedback_vector(), isolate)},
27 226 : closure_(closure) {
28 113 : CHECK(closure->has_feedback_vector());
29 113 : }
30 :
31 0 : Hints::Hints(Zone* zone)
32 0 : : constants_(zone), maps_(zone), function_blueprints_(zone) {}
33 :
34 0 : const ConstantsSet& Hints::constants() const { return constants_; }
35 :
36 0 : const MapsSet& Hints::maps() const { return maps_; }
37 :
38 0 : const BlueprintsSet& Hints::function_blueprints() const {
39 0 : return function_blueprints_;
40 : }
41 :
42 0 : void Hints::AddConstant(Handle<Object> constant) {
43 : constants_.insert(constant);
44 0 : }
45 :
46 0 : void Hints::AddMap(Handle<Map> map) { maps_.insert(map); }
47 :
48 0 : void Hints::AddFunctionBlueprint(FunctionBlueprint function_blueprint) {
49 : function_blueprints_.insert(function_blueprint);
50 0 : }
51 :
52 490 : void Hints::Add(const Hints& other) {
53 1200 : for (auto x : other.constants()) AddConstant(x);
54 980 : for (auto x : other.maps()) AddMap(x);
55 1041 : for (auto x : other.function_blueprints()) AddFunctionBlueprint(x);
56 490 : }
57 :
58 0 : bool Hints::IsEmpty() const {
59 0 : return constants().empty() && maps().empty() && function_blueprints().empty();
60 : }
61 :
62 0 : std::ostream& operator<<(std::ostream& out,
63 : const FunctionBlueprint& blueprint) {
64 0 : out << Brief(*blueprint.shared) << std::endl;
65 0 : out << Brief(*blueprint.feedback_vector) << std::endl;
66 0 : return out;
67 : }
68 :
69 0 : std::ostream& operator<<(std::ostream& out, const Hints& hints) {
70 : !hints.constants().empty() &&
71 0 : out << "\t\tConstants (" << hints.constants().size() << "):" << std::endl;
72 0 : for (auto x : hints.constants()) out << Brief(*x) << std::endl;
73 0 : !hints.maps().empty() && out << "\t\tMaps (" << hints.maps().size()
74 0 : << "):" << std::endl;
75 0 : for (auto x : hints.maps()) out << Brief(*x) << std::endl;
76 : !hints.function_blueprints().empty() &&
77 0 : out << "\t\tBlueprints (" << hints.function_blueprints().size()
78 0 : << "):" << std::endl;
79 0 : for (auto x : hints.function_blueprints()) out << x;
80 0 : return out;
81 : }
82 :
83 1336 : void Hints::Clear() {
84 : constants_.clear();
85 : maps_.clear();
86 : function_blueprints_.clear();
87 : DCHECK(IsEmpty());
88 1336 : }
89 :
90 30 : class SerializerForBackgroundCompilation::Environment : public ZoneObject {
91 : public:
92 : Environment(Zone* zone, CompilationSubject function);
93 : Environment(Zone* zone, Isolate* isolate, CompilationSubject function,
94 : base::Optional<Hints> new_target, const HintsVector& arguments);
95 :
96 : // When control flow bytecodes are encountered, e.g. a conditional jump,
97 : // the current environment needs to be stashed together with the target jump
98 : // address. Later, when this target bytecode is handled, the stashed
99 : // environment will be merged into the current one.
100 : void Merge(Environment* other);
101 :
102 : friend std::ostream& operator<<(std::ostream& out, const Environment& env);
103 :
104 : FunctionBlueprint function() const { return function_; }
105 :
106 878 : Hints& accumulator_hints() { return environment_hints_[accumulator_index()]; }
107 : Hints& register_hints(interpreter::Register reg) {
108 494 : int local_index = RegisterToLocalIndex(reg);
109 : DCHECK_LT(local_index, environment_hints_.size());
110 494 : return environment_hints_[local_index];
111 : }
112 : Hints& return_value_hints() { return return_value_hints_; }
113 :
114 : // Clears all hints except those for the return value and the closure.
115 152 : void ClearEphemeralHints() {
116 : DCHECK_EQ(environment_hints_.size(), function_closure_index() + 1);
117 1948 : for (int i = 0; i < function_closure_index(); ++i) {
118 1644 : environment_hints_[i].Clear();
119 : }
120 152 : }
121 :
122 : // Appends the hints for the given register range to {dst} (in order).
123 : void ExportRegisterHints(interpreter::Register first, size_t count,
124 : HintsVector& dst);
125 :
126 : private:
127 : int RegisterToLocalIndex(interpreter::Register reg) const;
128 :
129 : Zone* zone() const { return zone_; }
130 : int parameter_count() const { return parameter_count_; }
131 : int register_count() const { return register_count_; }
132 :
133 : Zone* const zone_;
134 : // Instead of storing the blueprint here, we could extract it from the
135 : // (closure) hints but that would be cumbersome.
136 : FunctionBlueprint const function_;
137 : int const parameter_count_;
138 : int const register_count_;
139 :
140 : // environment_hints_ contains hints for the contents of the registers,
141 : // the accumulator and the parameters. The layout is as follows:
142 : // [ parameters | registers | accumulator | context | closure ]
143 : // The first parameter is the receiver.
144 : HintsVector environment_hints_;
145 2148 : int accumulator_index() const { return parameter_count() + register_count(); }
146 0 : int current_context_index() const { return accumulator_index() + 1; }
147 1109 : int function_closure_index() const { return current_context_index() + 1; }
148 161 : int environment_hints_size() const { return function_closure_index() + 1; }
149 :
150 : Hints return_value_hints_;
151 : };
152 :
153 131 : SerializerForBackgroundCompilation::Environment::Environment(
154 : Zone* zone, CompilationSubject function)
155 : : zone_(zone),
156 : function_(function.blueprint()),
157 262 : parameter_count_(function_.shared->GetBytecodeArray()->parameter_count()),
158 262 : register_count_(function_.shared->GetBytecodeArray()->register_count()),
159 : environment_hints_(environment_hints_size(), Hints(zone), zone),
160 655 : return_value_hints_(zone) {
161 : Handle<JSFunction> closure;
162 131 : if (function.closure().ToHandle(&closure)) {
163 131 : environment_hints_[function_closure_index()].AddConstant(closure);
164 : } else {
165 18 : environment_hints_[function_closure_index()].AddFunctionBlueprint(
166 : function.blueprint());
167 : }
168 131 : }
169 :
170 72 : SerializerForBackgroundCompilation::Environment::Environment(
171 : Zone* zone, Isolate* isolate, CompilationSubject function,
172 72 : base::Optional<Hints> new_target, const HintsVector& arguments)
173 72 : : Environment(zone, function) {
174 : // Copy the hints for the actually passed arguments, at most up to
175 : // the parameter_count.
176 72 : size_t param_count = static_cast<size_t>(parameter_count());
177 630 : for (size_t i = 0; i < std::min(arguments.size(), param_count); ++i) {
178 700 : environment_hints_[i] = arguments[i];
179 : }
180 :
181 : // Pad the rest with "undefined".
182 : Hints undefined_hint(zone);
183 : undefined_hint.AddConstant(isolate->factory()->undefined_value());
184 76 : for (size_t i = arguments.size(); i < param_count; ++i) {
185 4 : environment_hints_[i] = undefined_hint;
186 : }
187 :
188 : interpreter::Register new_target_reg =
189 144 : function_.shared->GetBytecodeArray()
190 144 : ->incoming_new_target_or_generator_register();
191 72 : if (new_target_reg.is_valid()) {
192 : DCHECK(register_hints(new_target_reg).IsEmpty());
193 0 : if (new_target.has_value()) {
194 0 : register_hints(new_target_reg).Add(*new_target);
195 : }
196 72 : }
197 72 : }
198 :
199 15 : void SerializerForBackgroundCompilation::Environment::Merge(
200 30 : Environment* other) {
201 : // Presumably the source and the target would have the same layout
202 : // so this is enforced here.
203 15 : CHECK_EQ(parameter_count(), other->parameter_count());
204 15 : CHECK_EQ(register_count(), other->register_count());
205 15 : CHECK_EQ(environment_hints_size(), other->environment_hints_size());
206 :
207 215 : for (size_t i = 0; i < environment_hints_.size(); ++i) {
208 315 : environment_hints_[i].Add(other->environment_hints_[i]);
209 : }
210 15 : return_value_hints_.Add(other->return_value_hints_);
211 15 : }
212 :
213 0 : std::ostream& operator<<(
214 : std::ostream& out,
215 0 : const SerializerForBackgroundCompilation::Environment& env) {
216 0 : std::ostringstream output_stream;
217 0 : output_stream << "Function ";
218 0 : env.function_.shared->Name()->Print(output_stream);
219 0 : output_stream << "Parameter count: " << env.parameter_count() << std::endl;
220 0 : output_stream << "Register count: " << env.register_count() << std::endl;
221 :
222 0 : output_stream << "Hints (" << env.environment_hints_.size() << "):\n";
223 0 : for (size_t i = 0; i < env.environment_hints_.size(); ++i) {
224 0 : if (env.environment_hints_[i].IsEmpty()) continue;
225 :
226 0 : output_stream << "\tSlot " << i << std::endl;
227 0 : output_stream << env.environment_hints_[i];
228 : }
229 0 : output_stream << "Return value:\n";
230 0 : output_stream << env.return_value_hints_
231 0 : << "===========================================\n";
232 :
233 0 : out << output_stream.str();
234 0 : return out;
235 : }
236 :
237 494 : int SerializerForBackgroundCompilation::Environment::RegisterToLocalIndex(
238 490 : interpreter::Register reg) const {
239 : // TODO(mslekova): We also want to gather hints for the context.
240 494 : if (reg.is_current_context()) return current_context_index();
241 498 : if (reg.is_function_closure()) return function_closure_index();
242 490 : if (reg.is_parameter()) {
243 14 : return reg.ToParameterIndex(parameter_count());
244 : } else {
245 476 : return parameter_count() + reg.index();
246 : }
247 : }
248 :
249 59 : SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
250 : JSHeapBroker* broker, Zone* zone, Handle<JSFunction> closure)
251 : : broker_(broker),
252 : zone_(zone),
253 59 : environment_(new (zone) Environment(zone, {closure, broker_->isolate()})),
254 118 : stashed_environments_(zone) {
255 59 : JSFunctionRef(broker, closure).Serialize();
256 59 : }
257 :
258 72 : SerializerForBackgroundCompilation::SerializerForBackgroundCompilation(
259 : JSHeapBroker* broker, Zone* zone, CompilationSubject function,
260 : base::Optional<Hints> new_target, const HintsVector& arguments)
261 : : broker_(broker),
262 : zone_(zone),
263 72 : environment_(new (zone) Environment(zone, broker_->isolate(), function,
264 72 : new_target, arguments)),
265 288 : stashed_environments_(zone) {
266 : Handle<JSFunction> closure;
267 72 : if (function.closure().ToHandle(&closure)) {
268 54 : JSFunctionRef(broker, closure).Serialize();
269 : }
270 72 : }
271 :
272 393 : Hints SerializerForBackgroundCompilation::Run() {
273 : SharedFunctionInfoRef shared(broker(), environment()->function().shared);
274 : FeedbackVectorRef feedback_vector(broker(),
275 : environment()->function().feedback_vector);
276 131 : if (shared.IsSerializedForCompilation(feedback_vector)) {
277 : return Hints(zone());
278 : }
279 127 : shared.SetSerializedForCompilation(feedback_vector);
280 127 : feedback_vector.SerializeSlots();
281 127 : TraverseBytecode();
282 127 : return environment()->return_value_hints();
283 : }
284 :
285 393 : void SerializerForBackgroundCompilation::TraverseBytecode() {
286 : BytecodeArrayRef bytecode_array(
287 : broker(), handle(environment()->function().shared->GetBytecodeArray(),
288 381 : broker()->isolate()));
289 127 : BytecodeArrayIterator iterator(bytecode_array.object());
290 :
291 968 : for (; !iterator.done(); iterator.Advance()) {
292 841 : MergeAfterJump(&iterator);
293 841 : switch (iterator.current_bytecode()) {
294 : #define DEFINE_BYTECODE_CASE(name) \
295 : case interpreter::Bytecode::k##name: \
296 : Visit##name(&iterator); \
297 : break;
298 4 : SUPPORTED_BYTECODE_LIST(DEFINE_BYTECODE_CASE)
299 : #undef DEFINE_BYTECODE_CASE
300 : default: {
301 12 : environment()->ClearEphemeralHints();
302 12 : break;
303 : }
304 : }
305 : }
306 127 : }
307 :
308 0 : void SerializerForBackgroundCompilation::VisitIllegal(
309 : BytecodeArrayIterator* iterator) {
310 0 : UNREACHABLE();
311 : }
312 :
313 0 : void SerializerForBackgroundCompilation::VisitWide(
314 : BytecodeArrayIterator* iterator) {
315 0 : UNREACHABLE();
316 : }
317 :
318 0 : void SerializerForBackgroundCompilation::VisitExtraWide(
319 : BytecodeArrayIterator* iterator) {
320 0 : UNREACHABLE();
321 : }
322 :
323 0 : void SerializerForBackgroundCompilation::VisitStackCheck(
324 0 : BytecodeArrayIterator* iterator) {}
325 :
326 73 : void SerializerForBackgroundCompilation::VisitLdaUndefined(
327 219 : BytecodeArrayIterator* iterator) {
328 73 : environment()->accumulator_hints().Clear();
329 : environment()->accumulator_hints().AddConstant(
330 73 : broker()->isolate()->factory()->undefined_value());
331 73 : }
332 :
333 0 : void SerializerForBackgroundCompilation::VisitLdaNull(
334 0 : BytecodeArrayIterator* iterator) {
335 0 : environment()->accumulator_hints().Clear();
336 : environment()->accumulator_hints().AddConstant(
337 0 : broker()->isolate()->factory()->null_value());
338 0 : }
339 :
340 4 : void SerializerForBackgroundCompilation::VisitLdaZero(
341 12 : BytecodeArrayIterator* iterator) {
342 4 : environment()->accumulator_hints().Clear();
343 : environment()->accumulator_hints().AddConstant(
344 4 : handle(Smi::FromInt(0), broker()->isolate()));
345 4 : }
346 :
347 40 : void SerializerForBackgroundCompilation::VisitLdaSmi(
348 120 : BytecodeArrayIterator* iterator) {
349 40 : environment()->accumulator_hints().Clear();
350 : environment()->accumulator_hints().AddConstant(handle(
351 40 : Smi::FromInt(iterator->GetImmediateOperand(0)), broker()->isolate()));
352 40 : }
353 :
354 4 : void SerializerForBackgroundCompilation::VisitLdaConstant(
355 12 : BytecodeArrayIterator* iterator) {
356 4 : environment()->accumulator_hints().Clear();
357 : environment()->accumulator_hints().AddConstant(
358 4 : handle(iterator->GetConstantForIndexOperand(0), broker()->isolate()));
359 4 : }
360 :
361 22 : void SerializerForBackgroundCompilation::VisitLdar(
362 66 : BytecodeArrayIterator* iterator) {
363 22 : environment()->accumulator_hints().Clear();
364 : environment()->accumulator_hints().Add(
365 44 : environment()->register_hints(iterator->GetRegisterOperand(0)));
366 22 : }
367 :
368 150 : void SerializerForBackgroundCompilation::VisitStar(
369 300 : BytecodeArrayIterator* iterator) {
370 150 : interpreter::Register reg = iterator->GetRegisterOperand(0);
371 150 : environment()->register_hints(reg).Clear();
372 150 : environment()->register_hints(reg).Add(environment()->accumulator_hints());
373 150 : }
374 :
375 4 : void SerializerForBackgroundCompilation::VisitMov(
376 12 : BytecodeArrayIterator* iterator) {
377 4 : interpreter::Register src = iterator->GetRegisterOperand(0);
378 4 : interpreter::Register dst = iterator->GetRegisterOperand(1);
379 4 : environment()->register_hints(dst).Clear();
380 4 : environment()->register_hints(dst).Add(environment()->register_hints(src));
381 4 : }
382 :
383 23 : void SerializerForBackgroundCompilation::VisitCreateClosure(
384 110 : BytecodeArrayIterator* iterator) {
385 : Handle<SharedFunctionInfo> shared(
386 : SharedFunctionInfo::cast(iterator->GetConstantForIndexOperand(0)),
387 23 : broker()->isolate());
388 :
389 : FeedbackNexus nexus(environment()->function().feedback_vector,
390 46 : iterator->GetSlotOperand(1));
391 69 : Handle<Object> cell_value(nexus.GetFeedbackCell()->value(),
392 69 : broker()->isolate());
393 :
394 23 : environment()->accumulator_hints().Clear();
395 46 : if (cell_value->IsFeedbackVector()) {
396 : environment()->accumulator_hints().AddFunctionBlueprint(
397 18 : {shared, Handle<FeedbackVector>::cast(cell_value)});
398 : }
399 23 : }
400 :
401 4 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver(
402 : BytecodeArrayIterator* iterator) {
403 4 : ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
404 4 : }
405 :
406 22 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver0(
407 88 : BytecodeArrayIterator* iterator) {
408 : const Hints& callee =
409 22 : environment()->register_hints(iterator->GetRegisterOperand(0));
410 22 : FeedbackSlot slot = iterator->GetSlotOperand(1);
411 :
412 : Hints receiver(zone());
413 22 : receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
414 :
415 66 : HintsVector parameters({receiver}, zone());
416 66 : ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
417 22 : }
418 :
419 19 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver1(
420 95 : BytecodeArrayIterator* iterator) {
421 : const Hints& callee =
422 19 : environment()->register_hints(iterator->GetRegisterOperand(0));
423 : const Hints& arg0 =
424 19 : environment()->register_hints(iterator->GetRegisterOperand(1));
425 19 : FeedbackSlot slot = iterator->GetSlotOperand(2);
426 :
427 : Hints receiver(zone());
428 19 : receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
429 :
430 76 : HintsVector parameters({receiver, arg0}, zone());
431 57 : ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
432 19 : }
433 :
434 4 : void SerializerForBackgroundCompilation::VisitCallUndefinedReceiver2(
435 24 : BytecodeArrayIterator* iterator) {
436 : const Hints& callee =
437 4 : environment()->register_hints(iterator->GetRegisterOperand(0));
438 : const Hints& arg0 =
439 4 : environment()->register_hints(iterator->GetRegisterOperand(1));
440 : const Hints& arg1 =
441 4 : environment()->register_hints(iterator->GetRegisterOperand(2));
442 4 : FeedbackSlot slot = iterator->GetSlotOperand(3);
443 :
444 : Hints receiver(zone());
445 4 : receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
446 :
447 20 : HintsVector parameters({receiver, arg0, arg1}, zone());
448 12 : ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
449 4 : }
450 :
451 4 : void SerializerForBackgroundCompilation::VisitCallAnyReceiver(
452 : BytecodeArrayIterator* iterator) {
453 4 : ProcessCallVarArgs(iterator, ConvertReceiverMode::kAny);
454 4 : }
455 :
456 0 : void SerializerForBackgroundCompilation::VisitCallNoFeedback(
457 : BytecodeArrayIterator* iterator) {
458 0 : ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
459 0 : }
460 :
461 4 : void SerializerForBackgroundCompilation::VisitCallProperty(
462 : BytecodeArrayIterator* iterator) {
463 4 : ProcessCallVarArgs(iterator, ConvertReceiverMode::kNullOrUndefined);
464 4 : }
465 :
466 0 : void SerializerForBackgroundCompilation::VisitCallProperty0(
467 0 : BytecodeArrayIterator* iterator) {
468 : const Hints& callee =
469 0 : environment()->register_hints(iterator->GetRegisterOperand(0));
470 : const Hints& receiver =
471 0 : environment()->register_hints(iterator->GetRegisterOperand(1));
472 0 : FeedbackSlot slot = iterator->GetSlotOperand(2);
473 :
474 0 : HintsVector parameters({receiver}, zone());
475 0 : ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
476 0 : }
477 :
478 0 : void SerializerForBackgroundCompilation::VisitCallProperty1(
479 0 : BytecodeArrayIterator* iterator) {
480 : const Hints& callee =
481 0 : environment()->register_hints(iterator->GetRegisterOperand(0));
482 : const Hints& receiver =
483 0 : environment()->register_hints(iterator->GetRegisterOperand(1));
484 : const Hints& arg0 =
485 0 : environment()->register_hints(iterator->GetRegisterOperand(2));
486 0 : FeedbackSlot slot = iterator->GetSlotOperand(3);
487 :
488 0 : HintsVector parameters({receiver, arg0}, zone());
489 0 : ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
490 0 : }
491 :
492 4 : void SerializerForBackgroundCompilation::VisitCallProperty2(
493 20 : BytecodeArrayIterator* iterator) {
494 : const Hints& callee =
495 4 : environment()->register_hints(iterator->GetRegisterOperand(0));
496 : const Hints& receiver =
497 4 : environment()->register_hints(iterator->GetRegisterOperand(1));
498 : const Hints& arg0 =
499 4 : environment()->register_hints(iterator->GetRegisterOperand(2));
500 : const Hints& arg1 =
501 4 : environment()->register_hints(iterator->GetRegisterOperand(3));
502 4 : FeedbackSlot slot = iterator->GetSlotOperand(4);
503 :
504 20 : HintsVector parameters({receiver, arg0, arg1}, zone());
505 8 : ProcessCallOrConstruct(callee, base::nullopt, parameters, slot);
506 4 : }
507 :
508 4 : void SerializerForBackgroundCompilation::VisitCallWithSpread(
509 : BytecodeArrayIterator* iterator) {
510 4 : ProcessCallVarArgs(iterator, ConvertReceiverMode::kAny, true);
511 4 : }
512 :
513 76 : Hints SerializerForBackgroundCompilation::RunChildSerializer(
514 : CompilationSubject function, base::Optional<Hints> new_target,
515 76 : const HintsVector& arguments, bool with_spread) {
516 76 : if (with_spread) {
517 : DCHECK_LT(0, arguments.size());
518 : // Pad the missing arguments in case we were called with spread operator.
519 : // Drop the last actually passed argument, which contains the spread.
520 : // We don't know what the spread element produces. Therefore we pretend
521 : // that the function is called with the maximal number of parameters and
522 : // that we have no information about the parameters that were not
523 : // explicitly provided.
524 : HintsVector padded = arguments;
525 : padded.pop_back(); // Remove the spread element.
526 : // Fill the rest with empty hints.
527 : padded.resize(
528 8 : function.blueprint().shared->GetBytecodeArray()->parameter_count(),
529 8 : Hints(zone()));
530 8 : return RunChildSerializer(function, new_target, padded, false);
531 : }
532 :
533 72 : if (FLAG_trace_heap_broker) {
534 0 : std::ostream& out = broker()->Trace();
535 0 : out << "\nWill run child serializer with environment:\n"
536 0 : << "===========================================\n"
537 0 : << *environment();
538 : }
539 :
540 : SerializerForBackgroundCompilation child_serializer(
541 144 : broker(), zone(), function, new_target, arguments);
542 72 : return child_serializer.Run();
543 : }
544 :
545 : namespace {
546 73 : base::Optional<HeapObjectRef> GetHeapObjectFeedback(
547 68 : JSHeapBroker* broker, Handle<FeedbackVector> feedback_vector,
548 : FeedbackSlot slot) {
549 73 : if (slot.IsInvalid()) return base::nullopt;
550 73 : FeedbackNexus nexus(feedback_vector, slot);
551 73 : VectorSlotPair feedback(feedback_vector, slot, nexus.ic_state());
552 : DCHECK(feedback.IsValid());
553 73 : if (nexus.IsUninitialized()) return base::nullopt;
554 68 : HeapObject object;
555 68 : if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
556 68 : return HeapObjectRef(broker, handle(object, broker->isolate()));
557 : }
558 : } // namespace
559 :
560 73 : void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
561 54 : Hints callee, base::Optional<Hints> new_target,
562 345 : const HintsVector& arguments, FeedbackSlot slot, bool with_spread) {
563 : // Incorporate feedback into hints.
564 : base::Optional<HeapObjectRef> feedback = GetHeapObjectFeedback(
565 146 : broker(), environment()->function().feedback_vector, slot);
566 73 : if (feedback.has_value() && feedback->map().is_callable()) {
567 54 : if (new_target.has_value()) {
568 : // Construct; feedback is new_target, which often is also the callee.
569 8 : new_target->AddConstant(feedback->object());
570 8 : callee.AddConstant(feedback->object());
571 : } else {
572 : // Call; feedback is callee.
573 46 : callee.AddConstant(feedback->object());
574 : }
575 : }
576 :
577 73 : environment()->accumulator_hints().Clear();
578 :
579 200 : for (auto hint : callee.constants()) {
580 108 : if (!hint->IsJSFunction()) continue;
581 :
582 54 : Handle<JSFunction> function = Handle<JSFunction>::cast(hint);
583 108 : if (!function->shared()->IsInlineable() || !function->has_feedback_vector())
584 : continue;
585 :
586 : environment()->accumulator_hints().Add(RunChildSerializer(
587 216 : {function, broker()->isolate()}, new_target, arguments, with_spread));
588 : }
589 :
590 164 : for (auto hint : callee.function_blueprints()) {
591 18 : if (!hint.shared->IsInlineable()) continue;
592 : environment()->accumulator_hints().Add(RunChildSerializer(
593 72 : CompilationSubject(hint), new_target, arguments, with_spread));
594 : }
595 73 : }
596 :
597 16 : void SerializerForBackgroundCompilation::ProcessCallVarArgs(
598 : BytecodeArrayIterator* iterator, ConvertReceiverMode receiver_mode,
599 56 : bool with_spread) {
600 : const Hints& callee =
601 16 : environment()->register_hints(iterator->GetRegisterOperand(0));
602 16 : interpreter::Register first_reg = iterator->GetRegisterOperand(1);
603 16 : int reg_count = static_cast<int>(iterator->GetRegisterCountOperand(2));
604 : FeedbackSlot slot;
605 16 : if (iterator->current_bytecode() != interpreter::Bytecode::kCallNoFeedback) {
606 16 : slot = iterator->GetSlotOperand(3);
607 : }
608 :
609 : HintsVector arguments(zone());
610 : // The receiver is either given in the first register or it is implicitly
611 : // the {undefined} value.
612 16 : if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) {
613 : Hints receiver(zone());
614 8 : receiver.AddConstant(broker()->isolate()->factory()->undefined_value());
615 8 : arguments.push_back(receiver);
616 : }
617 32 : environment()->ExportRegisterHints(first_reg, reg_count, arguments);
618 :
619 32 : ProcessCallOrConstruct(callee, base::nullopt, arguments, slot);
620 16 : }
621 :
622 15 : void SerializerForBackgroundCompilation::ProcessJump(
623 15 : interpreter::BytecodeArrayIterator* iterator) {
624 15 : int jump_target = iterator->GetJumpTargetOffset();
625 : int current_offset = iterator->current_offset();
626 15 : if (current_offset >= jump_target) return;
627 :
628 30 : stashed_environments_[jump_target] = new (zone()) Environment(*environment());
629 : }
630 :
631 841 : void SerializerForBackgroundCompilation::MergeAfterJump(
632 15 : interpreter::BytecodeArrayIterator* iterator) {
633 841 : int current_offset = iterator->current_offset();
634 : auto stash = stashed_environments_.find(current_offset);
635 841 : if (stash != stashed_environments_.end()) {
636 30 : environment()->Merge(stash->second);
637 : stashed_environments_.erase(stash);
638 : }
639 841 : }
640 :
641 127 : void SerializerForBackgroundCompilation::VisitReturn(
642 254 : BytecodeArrayIterator* iterator) {
643 127 : environment()->return_value_hints().Add(environment()->accumulator_hints());
644 127 : environment()->ClearEphemeralHints();
645 127 : }
646 :
647 24 : void SerializerForBackgroundCompilation::Environment::ExportRegisterHints(
648 24 : interpreter::Register first, size_t count, HintsVector& dst) {
649 48 : dst.resize(dst.size() + count, Hints(zone()));
650 : int reg_base = first.index();
651 72 : for (int i = 0; i < static_cast<int>(count); ++i) {
652 96 : dst.push_back(register_hints(interpreter::Register(reg_base + i)));
653 : }
654 24 : }
655 :
656 4 : void SerializerForBackgroundCompilation::VisitConstruct(
657 12 : BytecodeArrayIterator* iterator) {
658 : const Hints& callee =
659 4 : environment()->register_hints(iterator->GetRegisterOperand(0));
660 4 : interpreter::Register first_reg = iterator->GetRegisterOperand(1);
661 4 : size_t reg_count = iterator->GetRegisterCountOperand(2);
662 4 : FeedbackSlot slot = iterator->GetSlotOperand(3);
663 : const Hints& new_target = environment()->accumulator_hints();
664 :
665 : HintsVector arguments(zone());
666 4 : environment()->ExportRegisterHints(first_reg, reg_count, arguments);
667 :
668 8 : ProcessCallOrConstruct(callee, new_target, arguments, slot);
669 4 : }
670 :
671 4 : void SerializerForBackgroundCompilation::VisitConstructWithSpread(
672 12 : BytecodeArrayIterator* iterator) {
673 : const Hints& callee =
674 4 : environment()->register_hints(iterator->GetRegisterOperand(0));
675 4 : interpreter::Register first_reg = iterator->GetRegisterOperand(1);
676 4 : size_t reg_count = iterator->GetRegisterCountOperand(2);
677 4 : FeedbackSlot slot = iterator->GetSlotOperand(3);
678 : const Hints& new_target = environment()->accumulator_hints();
679 :
680 : HintsVector arguments(zone());
681 4 : environment()->ExportRegisterHints(first_reg, reg_count, arguments);
682 :
683 8 : ProcessCallOrConstruct(callee, new_target, arguments, slot, true);
684 4 : }
685 :
686 : #define DEFINE_CLEAR_ENVIRONMENT(name, ...) \
687 : void SerializerForBackgroundCompilation::Visit##name( \
688 : BytecodeArrayIterator* iterator) { \
689 : environment()->ClearEphemeralHints(); \
690 : }
691 0 : CLEAR_ENVIRONMENT_LIST(DEFINE_CLEAR_ENVIRONMENT)
692 : #undef DEFINE_CLEAR_ENVIRONMENT
693 :
694 : #define DEFINE_CLEAR_ACCUMULATOR(name, ...) \
695 : void SerializerForBackgroundCompilation::Visit##name( \
696 : BytecodeArrayIterator* iterator) { \
697 : environment()->accumulator_hints().Clear(); \
698 : }
699 242 : CLEAR_ACCUMULATOR_LIST(DEFINE_CLEAR_ACCUMULATOR)
700 : #undef DEFINE_CLEAR_ACCUMULATOR
701 :
702 : #define DEFINE_CONDITIONAL_JUMP(name, ...) \
703 : void SerializerForBackgroundCompilation::Visit##name( \
704 : BytecodeArrayIterator* iterator) { \
705 : ProcessJump(iterator); \
706 : }
707 0 : CONDITIONAL_JUMPS_LIST(DEFINE_CONDITIONAL_JUMP)
708 : #undef DEFINE_CONDITIONAL_JUMP
709 :
710 : #define DEFINE_UNCONDITIONAL_JUMP(name, ...) \
711 : void SerializerForBackgroundCompilation::Visit##name( \
712 : BytecodeArrayIterator* iterator) { \
713 : ProcessJump(iterator); \
714 : environment()->ClearEphemeralHints(); \
715 : }
716 5 : UNCONDITIONAL_JUMPS_LIST(DEFINE_UNCONDITIONAL_JUMP)
717 : #undef DEFINE_UNCONDITIONAL_JUMP
718 :
719 : #define DEFINE_IGNORE(name, ...) \
720 : void SerializerForBackgroundCompilation::Visit##name( \
721 : BytecodeArrayIterator* iterator) {}
722 0 : INGORED_BYTECODE_LIST(DEFINE_IGNORE)
723 : #undef DEFINE_IGNORE
724 :
725 : } // namespace compiler
726 : } // namespace internal
727 178779 : } // namespace v8
|